summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/shell/app_list.cc166
-rw-r--r--ash/shell/example_factory.h15
-rw-r--r--ash/shell/shell_main.cc43
-rw-r--r--chrome/app/generated_resources.grd6
-rw-r--r--chrome/app/theme/theme_resources.grd6
-rw-r--r--chrome/browser/chromeos/drop_shadow_label.cc68
-rw-r--r--chrome/browser/ui/views/aura/app_list/app_list_model_builder.cc122
-rw-r--r--chrome/browser/ui/views/aura/app_list/app_list_model_builder.h34
-rw-r--r--chrome/browser/ui/views/aura/app_list/app_list_model_builder_unittest.cc50
-rw-r--r--chrome/browser/ui/views/aura/app_list/app_list_view_delegate.cc19
-rw-r--r--chrome/browser/ui/views/aura/app_list/app_list_view_delegate.h26
-rw-r--r--chrome/browser/ui/views/aura/app_list/browser_command_item.cc29
-rw-r--r--chrome/browser/ui/views/aura/app_list/browser_command_item.h31
-rw-r--r--chrome/browser/ui/views/aura/app_list/chrome_app_list_item.h24
-rw-r--r--chrome/browser/ui/views/aura/app_list/extension_app_item.cc181
-rw-r--r--chrome/browser/ui/views/aura/app_list/extension_app_item.h64
-rw-r--r--chrome/browser/ui/views/aura/chrome_shell_delegate.cc14
-rw-r--r--chrome/browser/ui/views/aura/chrome_shell_delegate.h2
-rw-r--r--chrome/chrome_browser.gypi10
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/test/data/extensions/app_list/Extensions/dceacbkfkmllgmjmbhgkpjegnodmildf/1.0/manifest.json12
-rw-r--r--chrome/test/data/extensions/app_list/Extensions/ddljohincgifmhhihcegmecmeohlfngm/1.0/manifest.json6
-rw-r--r--chrome/test/data/extensions/app_list/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/main.html1
-rw-r--r--chrome/test/data/extensions/app_list/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/manifest.json11
-rw-r--r--chrome/test/data/extensions/app_list/Extensions/jlklkagmeajbjiobondfhiekepofmljl/1.0/main.html1
-rw-r--r--chrome/test/data/extensions/app_list/Extensions/jlklkagmeajbjiobondfhiekepofmljl/1.0/manifest.json11
-rw-r--r--chrome/test/data/extensions/app_list/Preferences72
-rw-r--r--ui/aura_shell/app_list/app_list.cc (renamed from ui/aura_shell/app_list.cc)30
-rw-r--r--ui/aura_shell/app_list/app_list.h (renamed from ui/aura_shell/app_list.h)6
-rw-r--r--ui/aura_shell/app_list/app_list_groups_view.cc243
-rw-r--r--ui/aura_shell/app_list/app_list_groups_view.h84
-rw-r--r--ui/aura_shell/app_list/app_list_item_group_model.cc25
-rw-r--r--ui/aura_shell/app_list/app_list_item_group_model.h46
-rw-r--r--ui/aura_shell/app_list/app_list_item_group_view.cc115
-rw-r--r--ui/aura_shell/app_list/app_list_item_group_view.h65
-rw-r--r--ui/aura_shell/app_list/app_list_item_model.cc37
-rw-r--r--ui/aura_shell/app_list/app_list_item_model.h54
-rw-r--r--ui/aura_shell/app_list/app_list_item_model_observer.h27
-rw-r--r--ui/aura_shell/app_list/app_list_item_view.cc162
-rw-r--r--ui/aura_shell/app_list/app_list_item_view.h72
-rw-r--r--ui/aura_shell/app_list/app_list_item_view_listener.h27
-rw-r--r--ui/aura_shell/app_list/app_list_model.cc32
-rw-r--r--ui/aura_shell/app_list/app_list_model.h41
-rw-r--r--ui/aura_shell/app_list/app_list_view.cc80
-rw-r--r--ui/aura_shell/app_list/app_list_view.h61
-rw-r--r--ui/aura_shell/app_list/app_list_view_delegate.h27
-rw-r--r--ui/aura_shell/app_list/drop_shadow_label.cc118
-rw-r--r--ui/aura_shell/app_list/drop_shadow_label.h (renamed from chrome/browser/chromeos/drop_shadow_label.h)10
-rw-r--r--ui/aura_shell/aura_shell.gyp24
-rw-r--r--ui/aura_shell/aura_shell_switches.cc3
-rw-r--r--ui/aura_shell/aura_shell_switches.h1
-rw-r--r--ui/aura_shell/shell.cc2
-rw-r--r--ui/aura_shell/shell_delegate.h11
-rw-r--r--ui/aura_shell/test/test_shell_delegate.cc7
-rw-r--r--ui/aura_shell/test/test_shell_delegate.h2
-rw-r--r--ui/base/models/list_model.h116
-rw-r--r--ui/base/models/list_model_observer.h31
-rw-r--r--ui/base/models/list_model_unittest.cc149
-rw-r--r--ui/base/ui_base_exports.cc1
-rw-r--r--ui/ui.gyp2
-rw-r--r--ui/ui_unittests.gypi1
61 files changed, 2622 insertions, 115 deletions
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
new file mode 100644
index 0000000..b8022ab
--- /dev/null
+++ b/ash/shell/app_list.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/shell/example_factory.h"
+#include "ash/shell/toplevel_window.h"
+#include "base/basictypes.h"
+#include "ui/aura_shell/app_list/app_list_item_group_model.h"
+#include "ui/aura_shell/app_list/app_list_item_model.h"
+#include "ui/aura_shell/app_list/app_list_item_view.h"
+#include "ui/aura_shell/app_list/app_list_model.h"
+#include "ui/aura_shell/app_list/app_list_view_delegate.h"
+#include "ui/aura_shell/app_list/app_list_view.h"
+#include "ui/views/examples/examples_window.h"
+
+namespace ash {
+namespace shell {
+
+namespace {
+
+class WindowTypeLauncherItem : public aura_shell::AppListItemModel {
+ public:
+ enum Type {
+ TOPLEVEL_WINDOW = 0,
+ NON_RESIZABLE_WINDOW,
+ LOCK_SCREEN,
+ WIDGETS_WINDOW,
+ EXAMPLES_WINDOW,
+ LAST_TYPE,
+ };
+
+ WindowTypeLauncherItem(Type type) : type_(type) {
+ SetIcon(GetIcon(type));
+ SetTitle(GetTitle(type));
+ }
+
+ static SkBitmap GetIcon(Type type) {
+ static const SkColor kColors[] = {
+ SkColorSetA(SK_ColorRED, 0x4F),
+ SkColorSetA(SK_ColorGREEN, 0x4F),
+ SkColorSetA(SK_ColorBLUE, 0x4F),
+ SkColorSetA(SK_ColorYELLOW, 0x4F),
+ SkColorSetA(SK_ColorCYAN, 0x4F),
+ };
+
+ SkBitmap icon;
+ icon.setConfig(SkBitmap::kARGB_8888_Config,
+ aura_shell::AppListItemView::kIconSize,
+ aura_shell::AppListItemView::kIconSize);
+ icon.allocPixels();
+ icon.eraseColor(kColors[static_cast<int>(type) % arraysize(kColors)]);
+ return icon;
+ }
+
+ static std::string GetTitle(Type type) {
+ switch (type) {
+ case TOPLEVEL_WINDOW:
+ return "Create Window";
+ case NON_RESIZABLE_WINDOW:
+ return "Create Non-Resizable Window";
+ case LOCK_SCREEN:
+ return "Lock Screen";
+ case WIDGETS_WINDOW:
+ return "Show Example Widgets";
+ case EXAMPLES_WINDOW:
+ return "Open Views Examples Window";
+ default:
+ return "Unknown window type.";
+ }
+ }
+
+ void Activate(int event_flags) {
+ switch (type_) {
+ case TOPLEVEL_WINDOW: {
+ ToplevelWindow::CreateParams params;
+ params.can_resize = true;
+ ToplevelWindow::CreateToplevelWindow(params);
+ break;
+ }
+ case NON_RESIZABLE_WINDOW: {
+ ToplevelWindow::CreateToplevelWindow(ToplevelWindow::CreateParams());
+ break;
+ }
+ case LOCK_SCREEN: {
+ CreateLockScreen();
+ break;
+ }
+ case WIDGETS_WINDOW: {
+ CreateWidgetsWindow();
+ break;
+ }
+ case EXAMPLES_WINDOW: {
+ views::examples::ShowExamplesWindow(false);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ private:
+ Type type_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTypeLauncherItem);
+};
+
+class ExampleAppListViewDelegate : public aura_shell::AppListViewDelegate {
+ public:
+ ExampleAppListViewDelegate() {}
+
+ private:
+ virtual void OnAppListItemActivated(aura_shell::AppListItemModel* item,
+ int event_flags) OVERRIDE {
+ static_cast<WindowTypeLauncherItem*>(item)->Activate(event_flags);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ExampleAppListViewDelegate);
+};
+
+aura_shell::AppListItemGroupModel* CreateGroup(
+ const std::string& title,
+ WindowTypeLauncherItem::Type start_type,
+ WindowTypeLauncherItem::Type end_type) {
+ aura_shell::AppListItemGroupModel* group =
+ new aura_shell::AppListItemGroupModel(title);
+ for (int i = static_cast<int>(start_type);
+ i < static_cast<int>(end_type);
+ ++i) {
+ WindowTypeLauncherItem::Type type =
+ static_cast<WindowTypeLauncherItem::Type>(i);
+ group->AddItem(new WindowTypeLauncherItem(type));
+ }
+ return group;
+}
+
+} // namespace
+
+void BuildAppListModel(aura_shell::AppListModel* model) {
+ model->AddGroup(CreateGroup("Windows",
+ WindowTypeLauncherItem::TOPLEVEL_WINDOW,
+ WindowTypeLauncherItem::WIDGETS_WINDOW));
+ model->AddGroup(CreateGroup("Samples",
+ WindowTypeLauncherItem::WIDGETS_WINDOW,
+ WindowTypeLauncherItem::LAST_TYPE));
+}
+
+aura_shell::AppListViewDelegate* CreateAppListViewDelegate() {
+ return new ExampleAppListViewDelegate;
+}
+
+// TODO(xiyuan): Remove this.
+void CreateAppList(
+ const gfx::Rect& bounds,
+ const aura_shell::ShellDelegate::SetWidgetCallback& callback) {
+ aura_shell::AppListModel* model = new aura_shell::AppListModel;
+ BuildAppListModel(model);
+
+ new aura_shell::AppListView(
+ model,
+ CreateAppListViewDelegate(),
+ bounds,
+ callback);
+}
+
+} // namespace shell
+} // namespace ash
diff --git a/ash/shell/example_factory.h b/ash/shell/example_factory.h
index 25491ac..76e1f6e 100644
--- a/ash/shell/example_factory.h
+++ b/ash/shell/example_factory.h
@@ -6,6 +6,13 @@
#define ASH_SHELL_EXAMPLE_FACTORY_H_
#pragma once
+#include "ui/aura_shell/shell_delegate.h"
+
+namespace aura_shell {
+class AppListModel;
+class AppListViewDelegate;
+}
+
namespace views {
class View;
}
@@ -20,6 +27,14 @@ void CreateLockScreen();
// Creates a window showing samples of commonly used widgets.
void CreateWidgetsWindow();
+void BuildAppListModel(aura_shell::AppListModel* model);
+
+aura_shell::AppListViewDelegate* CreateAppListViewDelegate();
+
+void CreateAppList(
+ const gfx::Rect& bounds,
+ const aura_shell::ShellDelegate::SetWidgetCallback& callback);
+
} // namespace shell
} // namespace ash
diff --git a/ash/shell/shell_main.cc b/ash/shell/shell_main.cc
index d63a9c7..0bde60d 100644
--- a/ash/shell/shell_main.cc
+++ b/ash/shell/shell_main.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ash/shell/example_factory.h"
#include "ash/shell/toplevel_window.h"
#include "base/at_exit.h"
#include "base/command_line.h"
@@ -24,34 +25,6 @@
namespace {
-class AppListWindow : public views::WidgetDelegateView {
- public:
- AppListWindow() {
- }
-
- // static
- static views::Widget* Create(const gfx::Rect& bounds) {
- AppListWindow* app_list = new AppListWindow;
-
- views::Widget::InitParams widget_params(
- views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- widget_params.bounds = bounds;
- widget_params.delegate = app_list;
- widget_params.keep_on_top = true;
- widget_params.transparent = true;
-
- views::Widget* widget = new views::Widget;
- widget->Init(widget_params);
- widget->SetContentsView(app_list);
- return widget;
- }
-
- // Overridden from views::View:
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
- canvas->FillRect(SkColorSetARGB(0x4F, 0xFF, 0, 0), bounds());
- }
-};
-
class ShellDelegateImpl : public aura_shell::ShellDelegate {
public:
ShellDelegateImpl() {
@@ -71,7 +44,19 @@ class ShellDelegateImpl : public aura_shell::ShellDelegate {
virtual void RequestAppListWidget(
const gfx::Rect& bounds,
const SetWidgetCallback& callback) OVERRIDE {
- callback.Run(AppListWindow::Create(bounds));
+ // TODO(xiyuan): Clean this up.
+ // The code below here is because we don't want to use
+ // --aura-views-applist. This function is deprecated and all code
+ // here will be removed when we clean it up.
+ ash::shell::CreateAppList(bounds, callback);
+ }
+
+ virtual void BuildAppListModel(aura_shell::AppListModel* model) {
+ ash::shell::BuildAppListModel(model);
+ }
+
+ virtual aura_shell::AppListViewDelegate* CreateAppListViewDelegate() {
+ return ash::shell::CreateAppListViewDelegate();
}
virtual void LauncherItemClicked(
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 4c4db72..0570436 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -14822,6 +14822,12 @@ Battery full
<message name="IDS_SEARCH_BOX_HINT" desc="Hint text for the search box in app list window.">
Search apps and more
</message>
+ <message name="IDS_APP_LIST_INCOGNITO" desc="Title text for an app list item that opens an incognito browser window.">
+ Incognito
+ </message>
+ <message name="IDS_APP_LIST_SETTINGS" desc="Title text for an app list item that opens settings page.">
+ Settings
+ </message>
</if>
</messages>
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index bbdac5f..d645f62 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -573,6 +573,12 @@
<include name="IDR_VOLUME_BUBBLE_DOWN_ICON" file="volume_down_icon.png" type="BINDATA" />
<include name="IDR_VOLUME_BUBBLE_MUTE_ICON" file="volume_mute_icon.png" type="BINDATA" />
</if>
+
+ <!-- Images only used by aura. -->
+ <if expr="pp_ifdef('use_aura')">
+ <include name="IDR_APP_LIST_INCOGNITO" file="app_list_incognito.png" type="BINDATA" />
+ <include name="IDR_APP_LIST_SETTINGS" file="app_list_settings.png" type="BINDATA" />
+ </if>
</includes>
</release>
</grit>
diff --git a/chrome/browser/chromeos/drop_shadow_label.cc b/chrome/browser/chromeos/drop_shadow_label.cc
deleted file mode 100644
index 54243ec..0000000
--- a/chrome/browser/chromeos/drop_shadow_label.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/drop_shadow_label.h"
-
-#include "base/utf_string_conversions.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/color_utils.h"
-
-using views::Label;
-
-namespace chromeos {
-
-static const int kDefaultDropShadowSize = 2;
-
-DropShadowLabel::DropShadowLabel() : drop_shadow_size_(kDefaultDropShadowSize) {
-}
-
-void DropShadowLabel::SetDropShadowSize(int drop_shadow_size) {
- if (drop_shadow_size != drop_shadow_size_) {
- drop_shadow_size_ = drop_shadow_size;
- invalidate_text_size();
- SchedulePaint();
- }
-}
-
-void DropShadowLabel::PaintText(gfx::Canvas* canvas,
- const string16& text,
- const gfx::Rect& text_bounds,
- int flags) {
- SkColor text_color = enabled() ? enabled_color() : disabled_color();
- if (drop_shadow_size_ > 0) {
- const float kShadowOpacity = 0.2;
- const SkColor shadow_color =
- SkColorSetA(SK_ColorBLACK, kShadowOpacity * SkColorGetA(text_color));
- for (int i = 0; i < drop_shadow_size_; i++) {
- canvas->DrawStringInt(text, font(), shadow_color,
- text_bounds.x() + i, text_bounds.y(),
- text_bounds.width(), text_bounds.height(), flags);
- canvas->DrawStringInt(text, font(), shadow_color,
- text_bounds.x() + i, text_bounds.y() + i,
- text_bounds.width(), text_bounds.height(), flags);
- canvas->DrawStringInt(text, font(), shadow_color,
- text_bounds.x(), text_bounds.y() + i,
- text_bounds.width(), text_bounds.height(), flags);
- }
- }
-
- canvas->DrawStringInt(text, font(), text_color, text_bounds.x(),
- text_bounds.y(), text_bounds.width(), text_bounds.height(), flags);
-
- if (HasFocus() || paint_as_focused()) {
- gfx::Rect focus_bounds = text_bounds;
- focus_bounds.Inset(-Label::kFocusBorderPadding,
- -Label::kFocusBorderPadding);
- canvas->DrawFocusRect(focus_bounds);
- }
-}
-
-gfx::Size DropShadowLabel::GetTextSize() const {
- gfx::Size text_size = Label::GetTextSize();
- text_size.SetSize(text_size.width() + drop_shadow_size_,
- text_size.height() + drop_shadow_size_);
- return text_size;
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/ui/views/aura/app_list/app_list_model_builder.cc b/chrome/browser/ui/views/aura/app_list/app_list_model_builder.cc
new file mode 100644
index 0000000..f35dbb9
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/app_list_model_builder.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/aura/app_list/app_list_model_builder.h"
+
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/views/aura/app_list/browser_command_item.h"
+#include "chrome/browser/ui/views/aura/app_list/extension_app_item.h"
+#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/aura_shell/app_list/app_list_item_group_model.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+// Gets or creates group for given |extension| in |model|. The created group
+// is added to |model| and owned by it.
+aura_shell::AppListItemGroupModel* GetOrCreateGroup(
+ int page_index,
+ const ListValue* app_page_names,
+ aura_shell::AppListModel* model) {
+ if (page_index >= model->group_count()) {
+ for (int i = model->group_count(); i <= page_index; ++i) {
+ std::string title;
+ if (!app_page_names->GetString(i, &title))
+ title = l10n_util::GetStringUTF8(IDS_APP_DEFAULT_PAGE_NAME);
+
+ aura_shell::AppListItemGroupModel* group =
+ new aura_shell::AppListItemGroupModel(title);
+ model->AddGroup(group);
+ }
+ }
+
+ return model->GetGroup(page_index);
+}
+
+// Binary predict to sort extension apps. Smaller launch ordinal takes
+// precedence.
+bool ExtensionAppPrecedes(const ExtensionAppItem* a,
+ const ExtensionAppItem* b) {
+ return a->launch_ordinal().LessThan(b->launch_ordinal());
+}
+
+} // namespace
+
+AppListModelBuilder::AppListModelBuilder(Profile* profile,
+ aura_shell::AppListModel* model)
+ : profile_(profile),
+ model_(model) {
+}
+
+AppListModelBuilder::~AppListModelBuilder() {
+}
+
+void AppListModelBuilder::Build() {
+ GetExtensionApps();
+ GetBrowserCommands();
+}
+
+void AppListModelBuilder::GetExtensionApps() {
+ DCHECK(profile_);
+ ExtensionService* service = profile_->GetExtensionService();
+ if (!service)
+ return;
+
+ // Get extension apps.
+ std::vector<ExtensionAppItem*> items;
+ const ExtensionSet* extensions = service->extensions();
+ for (ExtensionSet::const_iterator app = extensions->begin();
+ app != extensions->end(); ++app) {
+ if (AppLauncherHandler::IsAppExcludedFromList(*app))
+ continue;
+
+ items.push_back(new ExtensionAppItem(profile_, *app));
+ }
+
+ // Sort by launch ordinal.
+ std::sort(items.begin(), items.end(), &ExtensionAppPrecedes);
+
+ // Put all items into model and group them by page ordinal.
+ PrefService* prefs = profile_->GetPrefs();
+ const ListValue* app_page_names = prefs->GetList(prefs::kNTPAppPageNames);
+ for (size_t i = 0; i < items.size(); ++i) {
+ ExtensionAppItem* item = items[i];
+
+ aura_shell::AppListItemGroupModel* group = GetOrCreateGroup(
+ item->page_index(),
+ app_page_names,
+ model_);
+
+ group->AddItem(item);
+ }
+}
+
+void AppListModelBuilder::GetBrowserCommands() {
+ Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
+ if (!browser)
+ return;
+
+ // Uses the first group to put browser commands
+ if (model_->group_count() == 0)
+ model_->AddGroup(new aura_shell::AppListItemGroupModel(""));
+ aura_shell::AppListItemGroupModel* group = model_->GetGroup(0);
+
+ group->AddItem(new BrowserCommandItem(browser,
+ IDC_NEW_INCOGNITO_WINDOW,
+ IDS_APP_LIST_INCOGNITO,
+ IDR_APP_LIST_INCOGNITO));
+ group->AddItem(new BrowserCommandItem(browser,
+ IDC_OPTIONS,
+ IDS_APP_LIST_SETTINGS,
+ IDR_APP_LIST_SETTINGS));
+}
+
diff --git a/chrome/browser/ui/views/aura/app_list/app_list_model_builder.h b/chrome/browser/ui/views/aura/app_list/app_list_model_builder.h
new file mode 100644
index 0000000..b42182539
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/app_list_model_builder.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_APP_LIST_MODEL_BUILDER_H_
+#define CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_APP_LIST_MODEL_BUILDER_H_
+#pragma once
+
+#include "base/gtest_prod_util.h"
+#include "ui/aura_shell/app_list/app_list_model.h"
+
+class Profile;
+
+class AppListModelBuilder {
+ public:
+ AppListModelBuilder(Profile* profile, aura_shell::AppListModel* model);
+ virtual ~AppListModelBuilder();
+
+ // Populates the model.
+ void Build();
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(AppListModelBuilderTest, GetExtensionApps);
+
+ void GetExtensionApps();
+ void GetBrowserCommands();
+
+ Profile* profile_;
+ aura_shell::AppListModel* model_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListModelBuilder);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_APP_LIST_MODEL_BUILDER_H_
diff --git a/chrome/browser/ui/views/aura/app_list/app_list_model_builder_unittest.cc b/chrome/browser/ui/views/aura/app_list/app_list_model_builder_unittest.cc
new file mode 100644
index 0000000..4ff8338
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/app_list_model_builder_unittest.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/views/aura/app_list/app_list_model_builder.h"
+#include "chrome/browser/extensions/extension_service_unittest.h"
+#include "chrome/test/base/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura_shell/app_list/app_list_item_group_model.h"
+#include "ui/aura_shell/app_list/app_list_item_model.h"
+
+class AppListModelBuilderTest : public ExtensionServiceTestBase {
+ public:
+ AppListModelBuilderTest() {}
+ virtual ~AppListModelBuilderTest() {}
+};
+
+TEST_F(AppListModelBuilderTest, GetExtensionApps) {
+ // Load "app_list" extensions test profile. The test profile has 4 extensions:
+ // 1 dummy extension, 2 packaged extension apps and 1 hosted extension app.
+ FilePath source_install_dir = data_dir_
+ .AppendASCII("app_list")
+ .AppendASCII("Extensions");
+ FilePath pref_path = source_install_dir
+ .DirName()
+ .AppendASCII("Preferences");
+ InitializeInstalledExtensionService(pref_path, source_install_dir);
+ service_->Init();
+
+ // There should be 4 extensions in the test profile.
+ const ExtensionSet* extensions = service_->extensions();
+ ASSERT_EQ(static_cast<size_t>(4), extensions->size());
+
+ scoped_ptr<aura_shell::AppListModel> model(new aura_shell::AppListModel());
+ AppListModelBuilder builder(profile_.get(), model.get());
+ builder.GetExtensionApps();
+
+ // Expect to have two app groups.
+ EXPECT_EQ(2, model->group_count());
+
+ // Two packaged apps are on the first page and hosted app on the 2nd page.
+ aura_shell::AppListItemGroupModel* group1 = model->GetGroup(0);
+ EXPECT_EQ("Packaged App 1", group1->GetItem(0)->title());
+ EXPECT_EQ("Packaged App 2", group1->GetItem(1)->title());
+
+ aura_shell::AppListItemGroupModel* group2 = model->GetGroup(1);
+ EXPECT_EQ("Hosted App", group2->GetItem(0)->title());
+}
diff --git a/chrome/browser/ui/views/aura/app_list/app_list_view_delegate.cc b/chrome/browser/ui/views/aura/app_list/app_list_view_delegate.cc
new file mode 100644
index 0000000..c624778
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/app_list_view_delegate.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/aura/app_list/app_list_view_delegate.h"
+
+#include "chrome/browser/ui/views/aura/app_list/chrome_app_list_item.h"
+
+AppListViewDelegate::AppListViewDelegate() {
+}
+
+AppListViewDelegate::~AppListViewDelegate() {
+}
+
+void AppListViewDelegate::OnAppListItemActivated(
+ aura_shell::AppListItemModel* item,
+ int event_flags) {
+ static_cast<ChromeAppListItem*>(item)->Activate(event_flags);
+}
diff --git a/chrome/browser/ui/views/aura/app_list/app_list_view_delegate.h b/chrome/browser/ui/views/aura/app_list/app_list_view_delegate.h
new file mode 100644
index 0000000..1f185f3
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/app_list_view_delegate.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
+#define CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/aura_shell/app_list/app_list_view_delegate.h"
+
+class AppListViewDelegate : public aura_shell::AppListViewDelegate {
+ public:
+ AppListViewDelegate();
+ virtual ~AppListViewDelegate();
+
+ private:
+ // Overridden from aura_shell::AppListViewDelegate:
+ virtual void OnAppListItemActivated(aura_shell::AppListItemModel* item,
+ int event_flags) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListViewDelegate);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
diff --git a/chrome/browser/ui/views/aura/app_list/browser_command_item.cc b/chrome/browser/ui/views/aura/app_list/browser_command_item.cc
new file mode 100644
index 0000000..12c135e
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/browser_command_item.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/aura/app_list/browser_command_item.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image.h"
+
+BrowserCommandItem::BrowserCommandItem(Browser* browser,
+ int command_id,
+ int title_id,
+ int icon_id)
+ : browser_(browser),
+ command_id_(command_id) {
+ SetTitle(l10n_util::GetStringUTF8(title_id));
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ SetIcon(*rb.GetImageNamed(icon_id).ToSkBitmap());
+}
+
+BrowserCommandItem::~BrowserCommandItem() {
+}
+
+void BrowserCommandItem::Activate(int event_flags) {
+ browser_->ExecuteCommand(command_id_, event_flags);
+}
diff --git a/chrome/browser/ui/views/aura/app_list/browser_command_item.h b/chrome/browser/ui/views/aura/app_list/browser_command_item.h
new file mode 100644
index 0000000..26c896f
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/browser_command_item.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_BROWSER_COMMAND_ITEM_H_
+#define CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_BROWSER_COMMAND_ITEM_H_
+#pragma once
+
+#include "chrome/browser/ui/views/aura/app_list/chrome_app_list_item.h"
+
+class Browser;
+
+class BrowserCommandItem : public ChromeAppListItem {
+ public:
+ BrowserCommandItem(Browser* browser,
+ int command_id,
+ int title_id,
+ int icon_id);
+ virtual ~BrowserCommandItem();
+
+ private:
+ // Overridden from ChromeAppListItem:
+ virtual void Activate(int event_flags) OVERRIDE;
+
+ Browser* browser_;
+ int command_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserCommandItem);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_BROWSER_COMMAND_ITEM_H_
diff --git a/chrome/browser/ui/views/aura/app_list/chrome_app_list_item.h b/chrome/browser/ui/views/aura/app_list/chrome_app_list_item.h
new file mode 100644
index 0000000..ed676cc
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/chrome_app_list_item.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_CHROME_APP_LIST_ITEM_H_
+#define CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_CHROME_APP_LIST_ITEM_H_
+#pragma once
+
+#include "ui/aura_shell/app_list/app_list_item_model.h"
+
+// Base class of all chrome app list items. Chrome's AppListViewDelegate assumes
+// all items are derived from this class and calls Activate when an item is
+// activated.
+class ChromeAppListItem : public aura_shell::AppListItemModel {
+ public:
+ // Activates the item. |event_flags| holds flags of a mouse/keyboard event
+ // associated with this activation.
+ virtual void Activate(int event_flags) = 0;
+
+ protected:
+ virtual ~ChromeAppListItem() {}
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_CHROME_APP_LIST_ITEM_H_
diff --git a/chrome/browser/ui/views/aura/app_list/extension_app_item.cc b/chrome/browser/ui/views/aura/app_list/extension_app_item.cc
new file mode 100644
index 0000000..73a414a
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/extension_app_item.cc
@@ -0,0 +1,181 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/aura/app_list/extension_app_item.h"
+
+#include "chrome/browser/event_disposition.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "grit/component_extension_resources_map.h"
+#include "grit/theme_resources.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/aura_shell/app_list/app_list_item_view.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/image/image.h"
+
+namespace {
+
+const ExtensionPrefs* GetExtensionPrefs(Profile* profile) {
+ return profile->GetExtensionService()->extension_prefs();
+}
+
+// Gets page ordinal of given |extension| in its app launch page.
+StringOrdinal GetExtensionPageOrdinal(Profile* profile,
+ const Extension* extension) {
+ const ExtensionPrefs* prefs = GetExtensionPrefs(profile);
+ StringOrdinal page_ordinal = prefs->GetPageOrdinal(extension->id());
+ if (!page_ordinal.IsValid()) {
+ page_ordinal = extension->id() == extension_misc::kWebStoreAppId ?
+ prefs->CreateFirstAppPageOrdinal() : prefs->GetNaturalAppPageOrdinal();
+ }
+
+ return page_ordinal;
+}
+
+// Gets page index from page ordinal.
+int GetExtensionPageIndex(Profile* profile,
+ const Extension* extension) {
+ return std::max(0, GetExtensionPrefs(profile)->PageStringOrdinalAsInteger(
+ GetExtensionPageOrdinal(profile, extension)));
+}
+
+// Gets app launch ordinal of given extension.
+StringOrdinal GetExtensionLaunchOrdinal(Profile* profile,
+ const Extension* extension) {
+ const ExtensionPrefs* prefs = GetExtensionPrefs(profile);
+ StringOrdinal app_launch_ordinal =
+ prefs->GetAppLaunchOrdinal(extension->id());
+ if (!app_launch_ordinal.IsValid()) {
+ StringOrdinal page_ordinal = GetExtensionPageOrdinal(profile, extension);
+ app_launch_ordinal = extension->id() == extension_misc::kWebStoreAppId ?
+ prefs->CreateFirstAppLaunchOrdinal(page_ordinal) :
+ prefs->CreateNextAppLaunchOrdinal(page_ordinal);
+ }
+ return app_launch_ordinal;
+}
+
+}
+
+ExtensionAppItem::ExtensionAppItem(Profile* profile,
+ const Extension* extension)
+ : profile_(profile),
+ extension_id_(extension->id()),
+ page_index_(GetExtensionPageIndex(profile, extension)),
+ launch_ordinal_(GetExtensionLaunchOrdinal(profile, extension)) {
+ SetTitle(extension->name());
+ LoadImage(extension);
+}
+
+ExtensionAppItem::~ExtensionAppItem() {
+}
+
+const Extension* ExtensionAppItem::GetExtension() const {
+ const Extension* extension =
+ profile_->GetExtensionService()->GetInstalledExtension(extension_id_);
+ return extension;
+}
+
+void ExtensionAppItem::LoadImage(const Extension* extension) {
+ ExtensionResource icon = extension->GetIconResource(
+ aura_shell::AppListItemView::kIconSize,
+ ExtensionIconSet::MATCH_BIGGER);
+ if (icon.relative_path().empty()) {
+ LoadDefaultImage();
+ return;
+ }
+
+ if (extension->location() == Extension::COMPONENT) {
+ FilePath directory_path = extension->path();
+ FilePath relative_path = directory_path.BaseName().Append(
+ icon.relative_path());
+ for (size_t i = 0; i < kComponentExtensionResourcesSize; ++i) {
+ FilePath bm_resource_path =
+ FilePath().AppendASCII(kComponentExtensionResources[i].name);
+#if defined(OS_WIN)
+ bm_resource_path = bm_resource_path.NormalizeWindowsPathSeparators();
+#endif
+ if (relative_path == bm_resource_path) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ int resource = kComponentExtensionResources[i].value;
+
+ base::StringPiece contents = rb.GetRawDataResource(resource);
+ SkBitmap icon;
+ if (gfx::PNGCodec::Decode(
+ reinterpret_cast<const unsigned char*>(contents.data()),
+ contents.size(), &icon)) {
+ SetIcon(icon);
+ return;
+ } else {
+ NOTREACHED() << "Unable to decode image resource " << resource;
+ }
+ }
+ }
+ }
+
+ tracker_.reset(new ImageLoadingTracker(this));
+ tracker_->LoadImage(extension,
+ icon,
+ gfx::Size(aura_shell::AppListItemView::kIconSize,
+ aura_shell::AppListItemView::kIconSize),
+ ImageLoadingTracker::DONT_CACHE);
+}
+
+void ExtensionAppItem::LoadDefaultImage() {
+ const Extension* extension = GetExtension();
+ int resource = IDR_APP_DEFAULT_ICON;
+ if (extension && extension->id() == extension_misc::kWebStoreAppId)
+ resource = IDR_WEBSTORE_ICON;
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ SetIcon(*rb.GetImageNamed(resource).ToSkBitmap());
+}
+
+void ExtensionAppItem::OnImageLoaded(SkBitmap* image,
+ const ExtensionResource& resource,
+ int tracker_index) {
+ if (image && !image->empty())
+ SetIcon(*image);
+ else
+ LoadDefaultImage();
+}
+
+void ExtensionAppItem::Activate(int event_flags) {
+ const Extension* extension = GetExtension();
+ if (!extension)
+ return;
+
+ WindowOpenDisposition disposition =
+ browser::DispositionFromEventFlags(event_flags);
+
+ GURL url;
+ if (extension_id_ == extension_misc::kWebStoreAppId)
+ url = extension->GetFullLaunchURL();
+
+ if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) {
+ // Opens in a tab.
+ Browser::OpenApplication(
+ profile_, extension, extension_misc::LAUNCH_TAB, url, disposition);
+ } else if (disposition == NEW_WINDOW) {
+ // Force a new window open.
+ Browser::OpenApplication(
+ profile_, extension, extension_misc::LAUNCH_WINDOW, url,
+ disposition);
+ } else {
+ // Look at preference to find the right launch container. If no preference
+ // is set, launch as a regular tab.
+ extension_misc::LaunchContainer launch_container =
+ profile_->GetExtensionService()->extension_prefs()->GetLaunchContainer(
+ extension, ExtensionPrefs::LAUNCH_REGULAR);
+
+ Browser::OpenApplication(
+ profile_, extension, launch_container, GURL(url),
+ NEW_FOREGROUND_TAB);
+ }
+}
diff --git a/chrome/browser/ui/views/aura/app_list/extension_app_item.h b/chrome/browser/ui/views/aura/app_list/extension_app_item.h
new file mode 100644
index 0000000..7fbc463
--- /dev/null
+++ b/chrome/browser/ui/views/aura/app_list/extension_app_item.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_EXTENSION_APP_ITEM_H_
+#define CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_EXTENSION_APP_ITEM_H_
+#pragma once
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/browser/ui/views/aura/app_list/chrome_app_list_item.h"
+#include "chrome/common/string_ordinal.h"
+
+class Extension;
+class ExtensionResource;
+class Profile;
+class SkBitmap;
+
+// ExtensionAppItem represents an extension app in app list.
+class ExtensionAppItem : public ChromeAppListItem,
+ public ImageLoadingTracker::Observer {
+ public:
+ ExtensionAppItem(Profile* profile, const Extension* extension);
+ virtual ~ExtensionAppItem();
+
+ // Gets extension associated with this model. Returns NULL if extension
+ // no longer exists.
+ const Extension* GetExtension() const;
+
+ int page_index() const {
+ return page_index_;
+ }
+
+ const StringOrdinal& launch_ordinal() const {
+ return launch_ordinal_;
+ }
+
+ private:
+ // Loads extension icon.
+ void LoadImage(const Extension* extension);
+
+ // Loads default extension icon.
+ void LoadDefaultImage();
+
+ // Overridden from ImageLoadingTracker::Observer
+ virtual void OnImageLoaded(SkBitmap* image,
+ const ExtensionResource& resource,
+ int tracker_index) OVERRIDE;
+
+ // Overridden from ChromeAppListItem:
+ virtual void Activate(int event_flags) OVERRIDE;
+
+ Profile* profile_;
+ const std::string extension_id_;
+
+ const int page_index_;
+ const StringOrdinal launch_ordinal_;
+
+ scoped_ptr<ImageLoadingTracker> tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionAppItem);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_AURA_APP_LIST_EXTENSION_APP_ITEM_H_
diff --git a/chrome/browser/ui/views/aura/chrome_shell_delegate.cc b/chrome/browser/ui/views/aura/chrome_shell_delegate.cc
index 7750f8c..6774bb9 100644
--- a/chrome/browser/ui/views/aura/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/views/aura/chrome_shell_delegate.cc
@@ -7,6 +7,8 @@
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/views/aura/app_list_window.h"
+#include "chrome/browser/ui/views/aura/app_list/app_list_model_builder.h"
+#include "chrome/browser/ui/views/aura/app_list/app_list_view_delegate.h"
#include "chrome/browser/ui/views/aura/status_area_host_aura.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "ui/aura/window.h"
@@ -64,6 +66,18 @@ void ChromeShellDelegate::RequestAppListWidget(
new AppListWindow(bounds, callback);
}
+void ChromeShellDelegate::BuildAppListModel(aura_shell::AppListModel* model) {
+ AppListModelBuilder builder(ProfileManager::GetDefaultProfile(),
+ model);
+ builder.Build();
+}
+
+aura_shell::AppListViewDelegate*
+ChromeShellDelegate::CreateAppListViewDelegate() {
+ // Shell will own the created delegate.
+ return new AppListViewDelegate;
+}
+
void ChromeShellDelegate::LauncherItemClicked(
const aura_shell::LauncherItem& item) {
aura_shell::ActivateWindow(item.window);
diff --git a/chrome/browser/ui/views/aura/chrome_shell_delegate.h b/chrome/browser/ui/views/aura/chrome_shell_delegate.h
index a524f30..99046e0 100644
--- a/chrome/browser/ui/views/aura/chrome_shell_delegate.h
+++ b/chrome/browser/ui/views/aura/chrome_shell_delegate.h
@@ -41,6 +41,8 @@ class ChromeShellDelegate : public aura_shell::ShellDelegate {
virtual void RequestAppListWidget(
const gfx::Rect& bounds,
const SetWidgetCallback& callback) OVERRIDE;
+ virtual void BuildAppListModel(aura_shell::AppListModel* model) OVERRIDE;
+ virtual aura_shell::AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE;
virtual void LauncherItemClicked(
const aura_shell::LauncherItem& item) OVERRIDE;
virtual bool ConfigureLauncherItem(aura_shell::LauncherItem* item) OVERRIDE;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index edef9ff..ba43d24 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -472,7 +472,6 @@
'browser/chromeos/dbus/update_engine_client.h',
'browser/chromeos/disks/disk_mount_manager.cc',
'browser/chromeos/disks/disk_mount_manager.h',
- 'browser/chromeos/drop_shadow_label.cc',
'browser/chromeos/enterprise_extension_observer.cc',
'browser/chromeos/enterprise_extension_observer.h',
'browser/chromeos/extensions/file_browser_event_router.cc',
@@ -3352,6 +3351,15 @@
'browser/ui/views/appcache_info_view.h',
'browser/ui/views/aura/app_list_window.cc',
'browser/ui/views/aura/app_list_window.h',
+ 'browser/ui/views/aura/app_list/app_list_model_builder.cc',
+ 'browser/ui/views/aura/app_list/app_list_model_builder.h',
+ 'browser/ui/views/aura/app_list/app_list_view_delegate.cc',
+ 'browser/ui/views/aura/app_list/app_list_view_delegate.h',
+ 'browser/ui/views/aura/app_list/browser_command_item.cc',
+ 'browser/ui/views/aura/app_list/browser_command_item.h',
+ 'browser/ui/views/aura/app_list/chrome_app_list_item.h',
+ 'browser/ui/views/aura/app_list/extension_app_item.cc',
+ 'browser/ui/views/aura/app_list/extension_app_item.h',
'browser/ui/views/aura/chrome_shell_delegate.cc',
'browser/ui/views/aura/chrome_shell_delegate.h',
'browser/ui/views/aura/launcher_icon_updater.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 90bced0..fe296cc 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1917,6 +1917,7 @@
'browser/ui/toolbar/encoding_menu_controller_unittest.cc',
'browser/ui/toolbar/toolbar_model_unittest.cc',
'browser/ui/toolbar/wrench_menu_model_unittest.cc',
+ 'browser/ui/views/aura/app_list/app_list_model_builder_unittest.cc',
'browser/ui/views/accessibility_event_router_views_unittest.cc',
'browser/ui/views/bookmarks/bookmark_context_menu_test.cc',
'browser/ui/views/bookmarks/bookmark_editor_view_unittest.cc',
diff --git a/chrome/test/data/extensions/app_list/Extensions/dceacbkfkmllgmjmbhgkpjegnodmildf/1.0/manifest.json b/chrome/test/data/extensions/app_list/Extensions/dceacbkfkmllgmjmbhgkpjegnodmildf/1.0/manifest.json
new file mode 100644
index 0000000..8b2183c
--- /dev/null
+++ b/chrome/test/data/extensions/app_list/Extensions/dceacbkfkmllgmjmbhgkpjegnodmildf/1.0/manifest.json
@@ -0,0 +1,12 @@
+{
+ "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDbh1pj7Q+vZzotbfPfe1Q4AIeJc3gU1xhTSMtjB0UZH+G3ckScJYTnFCTkFAn/mEOtn7e+SZ9rhDf4k6X7Qf6BzK3PLNn3+2Hb/F0NC57hiWI2UyhXY2dl2ry6VENkuyo1QpEMGH5FB5tC2rcuivG8ipBbUWLoQLMbegUdOLXoNK4tGvKwlGa1B0QPAMIkEw3ZlerckC8e+tWC38WvHxy1EM5VeK8k4GcrDEltoVByprTe/8VTzvEsFFYljpIzbSTi6mKOhY2sdl0EfCpXT4dSCeSe81O8liMU1yYKBQCbzguASV7yzZMX08tb96MOpx0NYbYXt03Zyj3xlbep5n4l",
+ "version": "1.0",
+ "name": "Hosted App",
+ "manifest_version": 2,
+ "app": {
+ "urls": [ "*://www.google.com/" ],
+ "launch": {
+ "web_url": "http://www.google.com"
+ }
+ }
+}
diff --git a/chrome/test/data/extensions/app_list/Extensions/ddljohincgifmhhihcegmecmeohlfngm/1.0/manifest.json b/chrome/test/data/extensions/app_list/Extensions/ddljohincgifmhhihcegmecmeohlfngm/1.0/manifest.json
new file mode 100644
index 0000000..f777866
--- /dev/null
+++ b/chrome/test/data/extensions/app_list/Extensions/ddljohincgifmhhihcegmecmeohlfngm/1.0/manifest.json
@@ -0,0 +1,6 @@
+{
+ "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDUfs/dEfHkfc10Ud1qbzeBNPetmVRDyqDtMGE8tP7QrPBvqsmPHkT3F9QF6HGMd9doaWezO5KPCQIw0Sxck4/6U3VNme77rXvqexGYoYSuy+Q51J+TikJDngWIgUuY5AVg98PbAsyK8qzbVrQ/rPygP3NnZz1GTV6mHbihpRfz5t969i1f6tPtjs8rQYFfauknVaIDeSR3icUfeqrtoxnJWsaY5Tk0hrJJdvG/TF8pKseps+aVEpsJETzHUxFOa6ES9tNfLsZfBAZtmD58twKYsBV6eg/TXJveumNG0dfmt7KviwK8dOm333V6CT/++KGQ6uW5YHwrjhOYu+chLt5f",
+ "version": "1.0",
+ "name": "Dummy Extension 1",
+ "manifest_version": 2
+}
diff --git a/chrome/test/data/extensions/app_list/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/main.html b/chrome/test/data/extensions/app_list/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/main.html
new file mode 100644
index 0000000..18ecdcb
--- /dev/null
+++ b/chrome/test/data/extensions/app_list/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/main.html
@@ -0,0 +1 @@
+<html></html>
diff --git a/chrome/test/data/extensions/app_list/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/manifest.json b/chrome/test/data/extensions/app_list/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/manifest.json
new file mode 100644
index 0000000..bae4986
--- /dev/null
+++ b/chrome/test/data/extensions/app_list/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/manifest.json
@@ -0,0 +1,11 @@
+{
+ "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQCxUatX2sx1yjeTAnu8ydtVhdD/JPn2wrmK7rX1Qko7FY4BRA733YPuY7JTWdKDbNU4OKaJOjexkz3klsj0vvTwRJgNghSgYePTPHZfWtRzy7WVG3KOQX2IgNMuOMWE/r5Eyg84Zi+0vLIcTzaqdAOcFwGYhp0/jRvDWDRpoQLKld6p58c/kORJ4sZrZMnp22OSz0rrLZseDEH+4ZJt0GWPUwzlKKLAsC8WthW5ntNjzkjxJSpRrM+WF7nr/dmYUX3791rRia7rtJFNx66AZroZ3PT7H1uOkr7f5vQyZbQrtMfmoxUtuu0yGGJS3JPw9i+0Pg7iHUQkRYUG/dNVYh//",
+ "version": "1.0",
+ "name": "Packaged App 1",
+ "manifest_version": 2,
+ "app": {
+ "launch": {
+ "local_path": "main.html"
+ }
+ }
+}
diff --git a/chrome/test/data/extensions/app_list/Extensions/jlklkagmeajbjiobondfhiekepofmljl/1.0/main.html b/chrome/test/data/extensions/app_list/Extensions/jlklkagmeajbjiobondfhiekepofmljl/1.0/main.html
new file mode 100644
index 0000000..18ecdcb
--- /dev/null
+++ b/chrome/test/data/extensions/app_list/Extensions/jlklkagmeajbjiobondfhiekepofmljl/1.0/main.html
@@ -0,0 +1 @@
+<html></html>
diff --git a/chrome/test/data/extensions/app_list/Extensions/jlklkagmeajbjiobondfhiekepofmljl/1.0/manifest.json b/chrome/test/data/extensions/app_list/Extensions/jlklkagmeajbjiobondfhiekepofmljl/1.0/manifest.json
new file mode 100644
index 0000000..40293cf
--- /dev/null
+++ b/chrome/test/data/extensions/app_list/Extensions/jlklkagmeajbjiobondfhiekepofmljl/1.0/manifest.json
@@ -0,0 +1,11 @@
+{
+ "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDhZCj7XcmF9ADcbuJqDFsBaILQEMMkrdgAQVHh0LFKKNTVOtNRJWhodme3abYKDa4DqXup05Ao6bTntvj0XekcyY35xPTTH6//4FNfkv9Nc7UXBO2iN+c9fodgiR8j0c1sePmbxG2zog7tGfujBldqE+E6zix8arTvDme144WpLRVasszq6qIHRfsg0X8GSlRHG6cm+HVJ8ZcO4FrqX4eTmr0UrQf1JPUfZccKpmtjzKVR9HhOXE9XuSpWZuw4QatE/ENtjVBcb8JUhbUJw3g8Qi6xGjCIISsj/RSEUidVFUt65VnQ5d/DrXBjFk5k26bQscLKXHn2mRUgQau8OZDv",
+ "version": "1.0",
+ "name": "Packaged App 2",
+ "manifest_version": 2,
+ "app": {
+ "launch": {
+ "local_path": "main.html"
+ }
+ }
+}
diff --git a/chrome/test/data/extensions/app_list/Preferences b/chrome/test/data/extensions/app_list/Preferences
new file mode 100644
index 0000000..bb1de10
--- /dev/null
+++ b/chrome/test/data/extensions/app_list/Preferences
@@ -0,0 +1,72 @@
+{
+ "extensions": {
+ "settings": {
+ "dceacbkfkmllgmjmbhgkpjegnodmildf": {
+ "location": 1,
+ "path": "dceacbkfkmllgmjmbhgkpjegnodmildf/1.0",
+ "app_launcher_ordinal": "n",
+ "page_ordinal": "t",
+ "state": 1,
+ "install_time": "12968795380420751",
+ "manifest": {
+ "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDbh1pj7Q+vZzotbfPfe1Q4AIeJc3gU1xhTSMtjB0UZH+G3ckScJYTnFCTkFAn/mEOtn7e+SZ9rhDf4k6X7Qf6BzK3PLNn3+2Hb/F0NC57hiWI2UyhXY2dl2ry6VENkuyo1QpEMGH5FB5tC2rcuivG8ipBbUWLoQLMbegUdOLXoNK4tGvKwlGa1B0QPAMIkEw3ZlerckC8e+tWC38WvHxy1EM5VeK8k4GcrDEltoVByprTe/8VTzvEsFFYljpIzbSTi6mKOhY2sdl0EfCpXT4dSCeSe81O8liMU1yYKBQCbzguASV7yzZMX08tb96MOpx0NYbYXt03Zyj3xlbep5n4l",
+ "version": "1.0",
+ "name": "Hosted App",
+ "app": {
+ "urls": [ "*://www.google.com/" ],
+ "launch": {
+ "web_url": "http://www.google.com"
+ }
+ }
+ }
+ },
+ "ddljohincgifmhhihcegmecmeohlfngm": {
+ "location": 1,
+ "path": "ddljohincgifmhhihcegmecmeohlfngm/1.0",
+ "state": 1,
+ "install_time": "12968795380420751",
+ "manifest": {
+ "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDUfs/dEfHkfc10Ud1qbzeBNPetmVRDyqDtMGE8tP7QrPBvqsmPHkT3F9QF6HGMd9doaWezO5KPCQIw0Sxck4/6U3VNme77rXvqexGYoYSuy+Q51J+TikJDngWIgUuY5AVg98PbAsyK8qzbVrQ/rPygP3NnZz1GTV6mHbihpRfz5t969i1f6tPtjs8rQYFfauknVaIDeSR3icUfeqrtoxnJWsaY5Tk0hrJJdvG/TF8pKseps+aVEpsJETzHUxFOa6ES9tNfLsZfBAZtmD58twKYsBV6eg/TXJveumNG0dfmt7KviwK8dOm333V6CT/++KGQ6uW5YHwrjhOYu+chLt5f",
+ "version": "1.0",
+ "name": "Dummy Extension 1"
+ }
+ },
+ "emfkafnhnpcmabnnkckkchdilgeoekbo": {
+ "location": 1,
+ "path": "emfkafnhnpcmabnnkckkchdilgeoekbo/1.0",
+ "app_launcher_ordinal": "n",
+ "page_ordinal": "n",
+ "state": 1,
+ "install_time": "12968795380420751",
+ "manifest": {
+ "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQCxUatX2sx1yjeTAnu8ydtVhdD/JPn2wrmK7rX1Qko7FY4BRA733YPuY7JTWdKDbNU4OKaJOjexkz3klsj0vvTwRJgNghSgYePTPHZfWtRzy7WVG3KOQX2IgNMuOMWE/r5Eyg84Zi+0vLIcTzaqdAOcFwGYhp0/jRvDWDRpoQLKld6p58c/kORJ4sZrZMnp22OSz0rrLZseDEH+4ZJt0GWPUwzlKKLAsC8WthW5ntNjzkjxJSpRrM+WF7nr/dmYUX3791rRia7rtJFNx66AZroZ3PT7H1uOkr7f5vQyZbQrtMfmoxUtuu0yGGJS3JPw9i+0Pg7iHUQkRYUG/dNVYh//",
+ "version": "1.0",
+ "name": "Packaged App 1",
+ "app": {
+ "launch": {
+ "local_path": "main.html"
+ }
+ }
+ }
+ },
+ "jlklkagmeajbjiobondfhiekepofmljl": {
+ "location": 1,
+ "path": "jlklkagmeajbjiobondfhiekepofmljl/1.0",
+ "app_launcher_ordinal": "t",
+ "page_ordinal": "n",
+ "state": 1,
+ "install_time": "12968795380420751",
+ "manifest": {
+ "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDhZCj7XcmF9ADcbuJqDFsBaILQEMMkrdgAQVHh0LFKKNTVOtNRJWhodme3abYKDa4DqXup05Ao6bTntvj0XekcyY35xPTTH6//4FNfkv9Nc7UXBO2iN+c9fodgiR8j0c1sePmbxG2zog7tGfujBldqE+E6zix8arTvDme144WpLRVasszq6qIHRfsg0X8GSlRHG6cm+HVJ8ZcO4FrqX4eTmr0UrQf1JPUfZccKpmtjzKVR9HhOXE9XuSpWZuw4QatE/ENtjVBcb8JUhbUJw3g8Qi6xGjCIISsj/RSEUidVFUt65VnQ5d/DrXBjFk5k26bQscLKXHn2mRUgQau8OZDv",
+ "version": "1.0",
+ "name": "Packaged App 2",
+ "app": {
+ "launch": {
+ "local_path": "main.html"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ui/aura_shell/app_list.cc b/ui/aura_shell/app_list/app_list.cc
index 6e21601..b68acb9 100644
--- a/ui/aura_shell/app_list.cc
+++ b/ui/aura_shell/app_list/app_list.cc
@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/aura_shell/app_list.h"
+#include "ui/aura_shell/app_list/app_list.h"
#include "base/bind.h"
+#include "base/command_line.h"
#include "ui/aura/event.h"
#include "ui/aura/window.h"
-#include "ui/aura_shell/shell.h"
+#include "ui/aura_shell/app_list/app_list_model.h"
+#include "ui/aura_shell/app_list/app_list_view.h"
+#include "ui/aura_shell/aura_shell_switches.h"
#include "ui/aura_shell/shell_delegate.h"
+#include "ui/aura_shell/shell.h"
#include "ui/aura_shell/shell_window_ids.h"
#include "ui/gfx/screen.h"
@@ -25,7 +29,7 @@ gfx::Rect GetPreferredBounds(bool show) {
gfx::Point cursor = gfx::Screen::GetCursorScreenPoint();
gfx::Rect work_area = gfx::Screen::GetMonitorWorkAreaNearestPoint(cursor);
gfx::Rect widget_bounds(work_area);
- widget_bounds.Inset(150, 100);
+ widget_bounds.Inset(100, 100);
if (!show)
widget_bounds.Offset(0, kMoveUpAnimationOffset);
@@ -61,9 +65,23 @@ void AppList::SetVisible(bool visible) {
if (widget_) {
ScheduleAnimation();
} else if (is_visible_ && !set_widget_factory_.HasWeakPtrs()) {
- Shell::GetInstance()->delegate()->RequestAppListWidget(
- GetPreferredBounds(false),
- base::Bind(&AppList::SetWidget, set_widget_factory_.GetWeakPtr()));
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAuraViewsAppList)) {
+ scoped_ptr<AppListModel> model(new AppListModel);
+ Shell::GetInstance()->delegate()->BuildAppListModel(model.get());
+
+ // AppListModel and AppListViewDelegate are owned by AppListView. They
+ // will be released with AppListView on close.
+ new AppListView(
+ model.release(),
+ Shell::GetInstance()->delegate()->CreateAppListViewDelegate(),
+ GetPreferredBounds(false),
+ base::Bind(&AppList::SetWidget, set_widget_factory_.GetWeakPtr()));
+ } else {
+ Shell::GetInstance()->delegate()->RequestAppListWidget(
+ GetPreferredBounds(false),
+ base::Bind(&AppList::SetWidget, set_widget_factory_.GetWeakPtr()));
+ }
}
}
diff --git a/ui/aura_shell/app_list.h b/ui/aura_shell/app_list/app_list.h
index 398eea3..0802258 100644
--- a/ui/aura_shell/app_list.h
+++ b/ui/aura_shell/app_list/app_list.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_AURA_SHELL_APP_LIST_H_
-#define UI_AURA_SHELL_APP_LIST_H_
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_H_
#pragma once
#include "base/basictypes.h"
@@ -80,4 +80,4 @@ class AppList : public aura::EventFilter,
} // namespace internal
} // namespace aura_shell
-#endif // UI_AURA_SHELL_APP_LIST_H_
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_H_
diff --git a/ui/aura_shell/app_list/app_list_groups_view.cc b/ui/aura_shell/app_list/app_list_groups_view.cc
new file mode 100644
index 0000000..e448784
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_groups_view.cc
@@ -0,0 +1,243 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_shell/app_list/app_list_groups_view.h"
+
+#include "base/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/aura_shell/app_list/app_list_item_group_model.h"
+#include "ui/aura_shell/app_list/app_list_item_group_view.h"
+#include "ui/aura_shell/app_list/app_list_item_view.h"
+#include "ui/aura_shell/app_list/app_list_model.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/views/animation/bounds_animator.h"
+#include "ui/views/controls/button/text_button.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace aura_shell {
+
+namespace {
+
+const SkColor kPageHeaderColor = SkColorSetARGB(0xFF, 0xB2, 0xB2, 0xB2);
+const SkColor kSelectedPageHeaderColor = SK_ColorWHITE;
+
+// Creates page headers view that hosts page title buttons.
+views::View* CreatePageHeader() {
+ views::View* header = new views::View;
+ header->SetLayoutManager(
+ new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
+ return header;
+}
+
+// Creates page header button view that shows page title.
+views::View* CreatePageHeaderButton(views::ButtonListener* listener,
+ const std::string& title ) {
+ views::TextButton* button = new views::TextButton(listener,
+ UTF8ToUTF16(title));
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ button->SetFont(rb.GetFont(ResourceBundle::BaseFont).DeriveFont(
+ 2, gfx::Font::BOLD));
+ button->SetEnabledColor(kPageHeaderColor);
+ return button;
+}
+
+// Gets preferred bounds of buttons and page.
+void GetPageAndHeaderBounds(views::View* parent,
+ views::View* buttons,
+ views::View* page,
+ gfx::Rect* buttons_bounds,
+ gfx::Rect* page_bounds) {
+ gfx::Rect content_bounds = parent->GetContentsBounds();
+
+ if (buttons) {
+ gfx::Size buttons_size = buttons->GetPreferredSize();
+ if (buttons_bounds) {
+ buttons_bounds->SetRect(
+ (content_bounds.width() - buttons_size.width()) / 2,
+ content_bounds.bottom() - buttons_size.height(),
+ buttons_size.width(), buttons_size.height());
+ }
+
+ content_bounds.set_height(
+ std::max(0, content_bounds.height() - buttons_size.height()));
+ }
+
+ if (page_bounds) {
+ gfx::Size page_size = page->GetPreferredSize();
+ *page_bounds = content_bounds.Center(page_size);
+ }
+}
+
+} // namespace
+
+AppListGroupsView::AppListGroupsView(AppListModel* model,
+ AppListItemViewListener* listener)
+ : model_(model),
+ listener_(listener),
+ page_buttons_(NULL),
+ current_page_(0) {
+ animator_.reset(new views::BoundsAnimator(this));
+ model_->AddObserver(this);
+ Update();
+}
+
+AppListGroupsView::~AppListGroupsView() {
+ model_->RemoveObserver(this);
+}
+
+views::View* AppListGroupsView::GetFocusedTile() const {
+ AppListItemGroupView* page = GetCurrentPageView();
+ return page ? page->GetFocusedTile() : NULL;
+}
+
+void AppListGroupsView::Update() {
+ current_page_ = 0;
+ page_buttons_ = NULL;
+ RemoveAllChildViews(true);
+
+ int page_count = model_->group_count();
+ if (!page_count)
+ return;
+
+ if (page_count > 1)
+ AddChildView(page_buttons_ = CreatePageHeader());
+
+ for (int i = 0; i < page_count; ++i) {
+ AppListItemGroupModel* group = model_->GetGroup(i);
+ AddPage(group->title(), new AppListItemGroupView(group, listener_));
+ }
+
+ if (!size().IsEmpty())
+ Layout();
+ SetCurrentPage(0);
+}
+
+void AppListGroupsView::AddPage(const std::string& title,
+ AppListItemGroupView* page) {
+ pages_.push_back(page);
+ AddChildView(page);
+
+ if (page_buttons_)
+ page_buttons_->AddChildView(CreatePageHeaderButton(this, title));
+}
+
+int AppListGroupsView::GetPreferredTilesPerRow() const {
+ return std::max(1, width() / AppListItemView::kTileSize);
+}
+
+AppListItemGroupView* AppListGroupsView::GetCurrentPageView() const {
+ return static_cast<size_t>(current_page_) < pages_.size() ?
+ pages_[current_page_] : NULL;
+}
+
+void AppListGroupsView::SetCurrentPage(int page) {
+ int previous_page = current_page_;
+ current_page_ = page;
+
+ // Updates page buttons.
+ if (page_buttons_) {
+ for (int i = 0; i < page_buttons_->child_count(); ++i) {
+ views::TextButton* button = static_cast<views::TextButton*>(
+ page_buttons_->child_at(i));
+
+ button->SetEnabledColor(i == current_page_ ?
+ kSelectedPageHeaderColor : kPageHeaderColor);
+ }
+ page_buttons_->SchedulePaint();
+ }
+
+ // Gets sliding animation direction.
+ int dir = previous_page < current_page_ ? -1 :
+ previous_page > current_page_ ? 1 : 0;
+
+ // Skips animation if no sliding needed or no valid size.
+ if (dir == 0 || size().IsEmpty())
+ return;
+
+ animator_->Cancel();
+
+ // Makes sure new page has correct layout and focus to its focused tile.
+ AppListItemGroupView* current_view = GetCurrentPageView();
+ current_view->SetTilesPerRow(GetPreferredTilesPerRow());
+ views::View* tile = current_view->GetFocusedTile();
+ if (tile)
+ tile->RequestFocus();
+
+ // Prepares current page before animation.
+ gfx::Rect current_page_bounds;
+ GetPageAndHeaderBounds(this, page_buttons_, current_view,
+ NULL, &current_page_bounds);
+ current_page_bounds.Offset(- dir * width(), 0);
+ current_view->SetBoundsRect(current_page_bounds);
+
+ // Schedules animations to slide out previous page and slide in current page.
+ AppListItemGroupView* previous_view = pages_[previous_page];
+ gfx::Rect previous_page_bounds = previous_view->bounds();
+ previous_page_bounds.Offset(dir * width(), 0);
+ animator_->AnimateViewTo(previous_view, previous_page_bounds);
+
+ current_page_bounds.Offset(dir * width(), 0);
+ animator_->AnimateViewTo(current_view, current_page_bounds);
+}
+
+void AppListGroupsView::Layout() {
+ AppListItemGroupView* page = GetCurrentPageView();
+ if (!page)
+ return;
+
+ page->SetTilesPerRow(GetPreferredTilesPerRow());
+
+ gfx::Rect buttons_bounds;
+ gfx::Rect page_bounds;
+ GetPageAndHeaderBounds(this, page_buttons_, page,
+ &buttons_bounds, &page_bounds);
+
+ if (page_buttons_)
+ page_buttons_->SetBoundsRect(buttons_bounds);
+
+ page->SetBoundsRect(page_bounds);
+}
+
+bool AppListGroupsView::OnKeyPressed(const views::KeyEvent& event) {
+ if (event.IsControlDown()) {
+ switch (event.key_code()) {
+ case ui::VKEY_LEFT:
+ if (current_page_ > 0)
+ SetCurrentPage(current_page_ - 1);
+ return true;
+ case ui::VKEY_RIGHT:
+ if (static_cast<size_t>(current_page_ + 1) < pages_.size())
+ SetCurrentPage(current_page_ + 1);
+ return true;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
+void AppListGroupsView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ DCHECK(page_buttons_);
+ for (int i = 0; i < page_buttons_->child_count(); ++i) {
+ if (page_buttons_->child_at(i) == sender)
+ SetCurrentPage(i);
+ }
+}
+
+void AppListGroupsView::ListItemsAdded(int start, int count) {
+ Update();
+}
+
+void AppListGroupsView::ListItemsRemoved(int start, int count) {
+ Update();
+}
+
+void AppListGroupsView::ListItemsChanged(int start, int count) {
+ NOTREACHED();
+}
+
+} // namespace aura_shell
diff --git a/ui/aura_shell/app_list/app_list_groups_view.h b/ui/aura_shell/app_list/app_list_groups_view.h
new file mode 100644
index 0000000..bc2839d
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_groups_view.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_GROUPS_VIEW_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_GROUPS_VIEW_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/base/models/list_model_observer.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/view.h"
+
+namespace views {
+class BoundsAnimator;
+}
+
+namespace aura_shell {
+
+class AppListItemGroupView;
+class AppListItemViewListener;
+class AppListModel;
+
+// AppListGroupsView displays the UI for an AppListModel. If there are more than
+// one group in the model , a button strip is displayed to allow user to switch
+// between pages.
+class AURA_SHELL_EXPORT AppListGroupsView : public views::View,
+ public views::ButtonListener,
+ public ui::ListModelObserver {
+ public:
+ AppListGroupsView(AppListModel* model,
+ AppListItemViewListener* listener);
+ virtual ~AppListGroupsView();
+
+ // Gets current focused tile.
+ views::View* GetFocusedTile() const;
+
+ private:
+ // Updates from model.
+ void Update();
+
+ // Adds a result group page.
+ void AddPage(const std::string& title, AppListItemGroupView* page);
+
+ // Gets preferred number of tiles per row.
+ int GetPreferredTilesPerRow() const;
+
+ // Gets current result page.
+ AppListItemGroupView* GetCurrentPageView() const;
+
+ // Sets current result page.
+ void SetCurrentPage(int page);
+
+ // Overridden from views::View:
+ virtual void Layout() OVERRIDE;
+ virtual bool OnKeyPressed(const views::KeyEvent& event) OVERRIDE;
+
+ // Overridden from views::ButtonListener:
+ virtual void ButtonPressed(views::Button* sender,
+ const views::Event& event) OVERRIDE;
+
+ // Overridden from ListModelObserver:
+ virtual void ListItemsAdded(int start, int count) OVERRIDE;
+ virtual void ListItemsRemoved(int start, int count) OVERRIDE;
+ virtual void ListItemsChanged(int start, int count) OVERRIDE;
+
+ AppListModel* model_; // Owned by parent AppListView.
+ AppListItemViewListener* listener_;
+
+ std::vector<AppListItemGroupView*> pages_;
+ views::View* page_buttons_;
+ int current_page_;
+
+ scoped_ptr<views::BoundsAnimator> animator_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListGroupsView);
+};
+
+} // namespace aura_shell
+
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_GROUPS_VIEW_H_
diff --git a/ui/aura_shell/app_list/app_list_item_group_model.cc b/ui/aura_shell/app_list/app_list_item_group_model.cc
new file mode 100644
index 0000000..61e3b9e
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_group_model.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_shell/app_list/app_list_item_group_model.h"
+
+namespace aura_shell {
+
+AppListItemGroupModel::AppListItemGroupModel(const std::string& title)
+ : title_(title) {
+}
+
+AppListItemGroupModel::~AppListItemGroupModel() {
+}
+
+void AppListItemGroupModel::AddItem(AppListItemModel* item) {
+ items_.Add(item);
+}
+
+AppListItemModel* AppListItemGroupModel::GetItem(int index) {
+ DCHECK(index >= 0 && index < item_count());
+ return items_.item_at(index);
+}
+
+} // namespace aura_shell
diff --git a/ui/aura_shell/app_list/app_list_item_group_model.h b/ui/aura_shell/app_list/app_list_item_group_model.h
new file mode 100644
index 0000000..6476742
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_group_model.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_GROUP_MODEL_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_GROUP_MODEL_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "ui/aura_shell/app_list/app_list_item_model.h"
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/base/models/list_model.h"
+
+namespace aura_shell {
+
+// AppListItemGroupModel holds a list of AppListItemModels.
+class AURA_SHELL_EXPORT AppListItemGroupModel {
+ public:
+ typedef ui::ListModel<AppListItemModel> Items;
+
+ explicit AppListItemGroupModel(const std::string& title);
+ virtual ~AppListItemGroupModel();
+
+ void AddItem(AppListItemModel* item);
+ AppListItemModel* GetItem(int index);
+
+ const std::string& title() const {
+ return title_;
+ }
+
+ int item_count() const {
+ return items_.item_count();
+ }
+
+ private:
+ const std::string title_;
+ Items items_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListItemGroupModel);
+};
+
+} // namespace aura_shell
+
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_GROUP_MODEL_H_
diff --git a/ui/aura_shell/app_list/app_list_item_group_view.cc b/ui/aura_shell/app_list/app_list_item_group_view.cc
new file mode 100644
index 0000000..3a91672
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_group_view.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_shell/app_list/app_list_item_group_view.h"
+
+#include "ui/aura_shell/app_list/app_list_item_group_model.h"
+#include "ui/aura_shell/app_list/app_list_item_view.h"
+#include "ui/views/layout/grid_layout.h"
+
+namespace aura_shell {
+
+AppListItemGroupView::AppListItemGroupView(AppListItemGroupModel* model,
+ AppListItemViewListener* listener)
+ : model_(model),
+ listener_(listener),
+ tiles_per_row_(0),
+ focused_index_(0) {
+ Update();
+}
+
+AppListItemGroupView::~AppListItemGroupView() {
+}
+
+void AppListItemGroupView::SetTilesPerRow(int tiles_per_row) {
+ if (tiles_per_row_ == tiles_per_row)
+ return;
+
+ tiles_per_row_ = tiles_per_row;
+ Update();
+}
+
+void AppListItemGroupView::Update() {
+ RemoveAllChildViews(true);
+ if (model_->item_count() == 0 || tiles_per_row_ == 0)
+ return;
+
+ views::GridLayout* layout = new views::GridLayout(this);
+ SetLayoutManager(layout);
+
+ const int kTileColumnSetId = 0;
+ views::ColumnSet* column_set = layout->AddColumnSet(kTileColumnSetId);
+ for (int i = 0; i < tiles_per_row_; ++i) {
+ column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
+ views::GridLayout::USE_PREF, 0, 0);
+ }
+
+ for (int i = 0; i < model_->item_count(); ++i) {
+ if (i % tiles_per_row_ == 0)
+ layout->StartRow(0, kTileColumnSetId);
+
+ layout->AddView(new AppListItemView(model_->GetItem(i), listener_));
+ }
+}
+
+views::View* AppListItemGroupView::GetFocusedTile() {
+ return focused_index_ < child_count() ? child_at(focused_index_) : NULL;
+}
+
+void AppListItemGroupView::UpdateFocusedTile(views::View* tile) {
+ for (int i = 0; i < child_count(); ++i) {
+ if (child_at(i) == tile) {
+ focused_index_ = i;
+ break;
+ }
+ }
+}
+
+void AppListItemGroupView::SetFocusedTileByIndex(int index) {
+ index = std::max(0, std::min(child_count() - 1, index));
+ if (index != focused_index_)
+ child_at(index)->RequestFocus();
+}
+
+bool AppListItemGroupView::OnKeyPressed(const views::KeyEvent& event) {
+ if (!event.IsControlDown() && !event.IsShiftDown() && !event.IsAltDown()) {
+ // Arrow keys navigates in tile grid.
+ switch (event.key_code()) {
+ case ui::VKEY_LEFT:
+ if (focused_index_ > 0)
+ SetFocusedTileByIndex(focused_index_ - 1);
+ return true;
+ case ui::VKEY_RIGHT:
+ if (focused_index_ + 1 < child_count())
+ SetFocusedTileByIndex(focused_index_ + 1);
+ return true;
+ case ui::VKEY_UP:
+ if (focused_index_ - tiles_per_row_ >= 0)
+ SetFocusedTileByIndex(focused_index_ - tiles_per_row_);
+ return true;
+ case ui::VKEY_DOWN:
+ if (focused_index_ + tiles_per_row_ < child_count())
+ SetFocusedTileByIndex(focused_index_ + tiles_per_row_);
+ return true;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
+void AppListItemGroupView::ListItemsAdded(int start, int count) {
+ Update();
+}
+
+void AppListItemGroupView::ListItemsRemoved(int start, int count) {
+ Update();
+}
+
+void AppListItemGroupView::ListItemsChanged(int start, int count) {
+ NOTREACHED();
+}
+
+} // namespace aura_shell
diff --git a/ui/aura_shell/app_list/app_list_item_group_view.h b/ui/aura_shell/app_list/app_list_item_group_view.h
new file mode 100644
index 0000000..6718f9d
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_group_view.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_GROUP_VIEW_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_GROUP_VIEW_H_
+#pragma once
+
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/base/models/list_model_observer.h"
+#include "ui/views/view.h"
+
+namespace aura_shell {
+
+class AppListItemGroupModel;
+class AppListItemViewListener;
+
+// AppListItemGroupView displays its children tiles in a grid.
+class AURA_SHELL_EXPORT AppListItemGroupView
+ : public views::View,
+ public ui::ListModelObserver {
+ public:
+ AppListItemGroupView(AppListItemGroupModel* model,
+ AppListItemViewListener* listener);
+ virtual ~AppListItemGroupView();
+
+ // Sets tiles per row.
+ void SetTilesPerRow(int tiles_per_row);
+
+ // Gets currently focused tile.
+ views::View* GetFocusedTile();
+
+ // Updates tiles page when a tile gets focus.
+ void UpdateFocusedTile(views::View* tile);
+
+ private:
+ // Updates from model.
+ void Update();
+
+ // Sets focused tile by index.
+ void SetFocusedTileByIndex(int index);
+
+ // Overridden from views::View:
+ virtual bool OnKeyPressed(const views::KeyEvent& event) OVERRIDE;
+
+ // Overridden from ListModelObserver:
+ virtual void ListItemsAdded(int start, int count) OVERRIDE;
+ virtual void ListItemsRemoved(int start, int count) OVERRIDE;
+ virtual void ListItemsChanged(int start, int count) OVERRIDE;
+
+ AppListItemGroupModel* model_;
+ AppListItemViewListener* listener_;
+
+ // Tiles per row.
+ int tiles_per_row_;
+
+ // Index of focused tile view.
+ int focused_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListItemGroupView);
+};
+
+} // namespace aura_shell
+
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_GROUP_VIEW_H_
diff --git a/ui/aura_shell/app_list/app_list_item_model.cc b/ui/aura_shell/app_list/app_list_item_model.cc
new file mode 100644
index 0000000..a93bb8b
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_model.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_shell/app_list/app_list_item_model.h"
+
+#include "ui/aura_shell/app_list/app_list_item_model_observer.h"
+
+namespace aura_shell {
+
+AppListItemModel::AppListItemModel() {
+}
+
+AppListItemModel::~AppListItemModel() {
+}
+
+void AppListItemModel::SetIcon(const SkBitmap& icon) {
+ icon_ = icon;
+ FOR_EACH_OBSERVER(AppListItemModelObserver, observers_,
+ ItemIconChanged());
+}
+
+void AppListItemModel::SetTitle(const std::string& title) {
+ title_ = title;
+ FOR_EACH_OBSERVER(AppListItemModelObserver, observers_,
+ ItemTitleChanged());
+}
+
+void AppListItemModel::AddObserver(AppListItemModelObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void AppListItemModel::RemoveObserver(AppListItemModelObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+} // namespace aura_shell
diff --git a/ui/aura_shell/app_list/app_list_item_model.h b/ui/aura_shell/app_list/app_list_item_model.h
new file mode 100644
index 0000000..3d5c38c
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_model.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_MODEL_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_MODEL_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/observer_list.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/aura_shell/aura_shell_export.h"
+
+namespace aura_shell {
+
+class AppListItemModelObserver;
+
+// AppListItemModel provides icon and title to be shown in a TileView and
+// action to be executed when the TileView is activated (clicked or enter
+// key it hit).
+class AURA_SHELL_EXPORT AppListItemModel {
+ public:
+ AppListItemModel();
+ virtual ~AppListItemModel();
+
+ // Changes icon and title for the model.
+ void SetIcon(const SkBitmap& icon);
+ void SetTitle(const std::string& title);
+
+ void AddObserver(AppListItemModelObserver* observer);
+ void RemoveObserver(AppListItemModelObserver* observer);
+
+ const SkBitmap& icon() const {
+ return icon_;
+ }
+
+ const std::string& title() const {
+ return title_;
+ }
+
+ private:
+ SkBitmap icon_;
+ std::string title_;
+
+ ObserverList<AppListItemModelObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListItemModel);
+};
+
+} // namespace aura_shell
+
+#endif // #define UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_MODEL_H_
diff --git a/ui/aura_shell/app_list/app_list_item_model_observer.h b/ui/aura_shell/app_list/app_list_item_model_observer.h
new file mode 100644
index 0000000..f43d102
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_model_observer.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_MODEL_OBSERVER_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_MODEL_OBSERVER_H_
+#pragma once
+
+#include "ui/aura_shell/aura_shell_export.h"
+
+namespace aura_shell {
+
+class AURA_SHELL_EXPORT AppListItemModelObserver {
+ public:
+ // Invoked after app list item's icon is changed.
+ virtual void ItemIconChanged() = 0;
+
+ // Invoked after app list item's title is changed.
+ virtual void ItemTitleChanged() = 0;
+
+ protected:
+ virtual ~AppListItemModelObserver() {}
+};
+
+} // namespace aura_shell
+
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_MODEL_OBSERVER_H_
diff --git a/ui/aura_shell/app_list/app_list_item_view.cc b/ui/aura_shell/app_list/app_list_item_view.cc
new file mode 100644
index 0000000..afb080b
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_view.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_shell/app_list/app_list_item_view.h"
+
+#include "base/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/aura_shell/app_list/app_list_item_group_view.h"
+#include "ui/aura_shell/app_list/app_list_item_model.h"
+#include "ui/aura_shell/app_list/app_list_item_view_listener.h"
+#include "ui/aura_shell/app_list/drop_shadow_label.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/widget/widget.h"
+
+namespace aura_shell {
+
+namespace {
+
+const double kFocusedScale = 1.1;
+
+const SkColor kTitleColor = SK_ColorWHITE;
+
+gfx::Font GetTitleFont() {
+ static gfx::Font* font = NULL;
+ if (!font) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ font = new gfx::Font(rb.GetFont(ResourceBundle::BaseFont).DeriveFont(
+ 2, gfx::Font::BOLD));
+ }
+ return *font;
+}
+
+} // namespace
+
+AppListItemView::AppListItemView(AppListItemModel* model,
+ AppListItemViewListener* listener)
+ : model_(model),
+ listener_(listener),
+ icon_(new views::ImageView),
+ title_(new DropShadowLabel) {
+ set_focusable(true);
+
+ title_->SetFont(GetTitleFont());
+ title_->SetBackgroundColor(0);
+ title_->SetEnabledColor(kTitleColor);
+
+ AddChildView(icon_);
+ AddChildView(title_);
+
+ ItemIconChanged();
+ ItemTitleChanged();
+ model_->AddObserver(this);
+}
+
+AppListItemView::~AppListItemView() {
+ model_->RemoveObserver(this);
+}
+
+void AppListItemView::NotifyActivated(int event_flags) {
+ if (listener_)
+ listener_->AppListItemActivated(this, event_flags);
+}
+
+void AppListItemView::ItemIconChanged() {
+ icon_->SetImage(model_->icon());
+}
+
+void AppListItemView::ItemTitleChanged() {
+ title_->SetText(UTF8ToUTF16(model_->title()));
+}
+
+gfx::Size AppListItemView::GetPreferredSize() {
+ return gfx::Size(kTileSize, kTileSize);
+}
+
+void AppListItemView::Layout() {
+ gfx::Rect rect(GetContentsBounds());
+ gfx::Size title_size = title_->GetPreferredSize();
+
+ if (!HasFocus()) {
+ const int horiz_padding = (kTileSize - kIconSize) / 2;
+ const int vert_padding = (kTileSize - title_size.height() - kIconSize) / 2;
+ rect.Inset(horiz_padding, vert_padding);
+ }
+
+ icon_->SetBounds(rect.x(), rect.y(),
+ rect.width(), rect.height() - title_size.height());
+
+ title_->SetBounds(rect.x(), rect.bottom() - title_size.height(),
+ rect.width(), title_size.height());
+}
+
+void AppListItemView::OnFocus() {
+ View::OnFocus();
+
+ gfx::Size icon_size = icon_->GetPreferredSize();
+ icon_size.set_width(icon_size.width() * kFocusedScale);
+ icon_size.set_height(icon_size.height() * kFocusedScale);
+
+ gfx::Size max_size = GetPreferredSize();
+ if (icon_size.width() > max_size.width() ||
+ icon_size.height() > max_size.height()) {
+ double aspect =
+ static_cast<double>(icon_size.width()) / icon_size.height();
+
+ if (aspect > 1) {
+ icon_size.set_width(max_size.width());
+ icon_size.set_height(icon_size.width() / aspect);
+ } else {
+ icon_size.set_height(max_size.height());
+ icon_size.set_width(icon_size.height() * aspect);
+ }
+ }
+
+ icon_->SetImageSize(icon_size);
+ Layout();
+
+ AppListItemGroupView* group_view =
+ static_cast<AppListItemGroupView*>(parent());
+ group_view->UpdateFocusedTile(this);
+}
+
+void AppListItemView::OnBlur() {
+ icon_->ResetImageSize();
+ Layout();
+ SchedulePaint();
+}
+
+bool AppListItemView::OnKeyPressed(const views::KeyEvent& event) {
+ if (event.key_code() == ui::VKEY_RETURN) {
+ NotifyActivated(event.flags());
+ return true;
+ }
+
+ return false;
+}
+
+bool AppListItemView::OnMousePressed(const views::MouseEvent& event) {
+ views::View* hit_view = GetEventHandlerForPoint(event.location());
+ bool hit = hit_view != this;
+ if (hit)
+ RequestFocus();
+
+ return hit;
+}
+
+void AppListItemView::OnMouseReleased(const views::MouseEvent& event) {
+ views::View* hit_view = GetEventHandlerForPoint(event.location());
+ if (hit_view != this)
+ NotifyActivated(event.flags());
+}
+
+void AppListItemView::OnPaintFocusBorder(gfx::Canvas* canvas) {
+ // No focus border for AppListItemView.
+}
+
+} // namespace aura_shell
diff --git a/ui/aura_shell/app_list/app_list_item_view.h b/ui/aura_shell/app_list/app_list_item_view.h
new file mode 100644
index 0000000..3d8b6de
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_view.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_VIEW_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_VIEW_H_
+#pragma once
+
+#include "ui/aura_shell/app_list/app_list_item_model_observer.h"
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/views/view.h"
+
+class SkBitmap;
+
+namespace views {
+class ImageView;
+class Label;
+}
+
+namespace aura_shell {
+
+class AppListItemModel;
+class AppListItemViewListener;
+
+class AURA_SHELL_EXPORT AppListItemView : public views::View,
+ public AppListItemModelObserver {
+ public:
+ AppListItemView(AppListItemModel* model,
+ AppListItemViewListener* listener);
+ virtual ~AppListItemView();
+
+ AppListItemModel* model() const {
+ return model_;
+ }
+
+ // Tile size
+ static const int kTileSize = 180;
+
+ // Preferred icon size.
+ static const int kIconSize = 128;
+
+ protected:
+ // Notifies listener when activated.
+ void NotifyActivated(int event_flags);
+
+ // AppListItemModelObserver overrides:
+ virtual void ItemIconChanged() OVERRIDE;
+ virtual void ItemTitleChanged() OVERRIDE;
+
+ // views::View overrides:
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual void Layout() OVERRIDE;
+ virtual void OnFocus() OVERRIDE;
+ virtual void OnBlur() OVERRIDE;
+ virtual bool OnKeyPressed(const views::KeyEvent& event) OVERRIDE;
+ virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+ AppListItemModel* model_;
+ AppListItemViewListener* listener_;
+
+ views::ImageView* icon_;
+ views::Label* title_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListItemView);
+};
+
+} // namespace aura_shell
+
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_VIEW_H_
diff --git a/ui/aura_shell/app_list/app_list_item_view_listener.h b/ui/aura_shell/app_list/app_list_item_view_listener.h
new file mode 100644
index 0000000..dfa2084
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_item_view_listener.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_VIEW_LISTENER_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_VIEW_LISTENER_H_
+#pragma once
+
+#include "ui/aura_shell/aura_shell_export.h"
+
+namespace aura_shell {
+
+class AppListItemView;
+
+class AURA_SHELL_EXPORT AppListItemViewListener {
+ public:
+ // Invoked when an AppListeItemModelView is activated by click or enter key.
+ virtual void AppListItemActivated(AppListItemView* sender,
+ int event_flags) = 0;
+
+ protected:
+ virtual ~AppListItemViewListener() {}
+};
+
+} // namespace aura_shell
+
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_ITEM_VIEW_LISTENER_H_
diff --git a/ui/aura_shell/app_list/app_list_model.cc b/ui/aura_shell/app_list/app_list_model.cc
new file mode 100644
index 0000000..8cc531b
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_model.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_shell/app_list/app_list_model.h"
+
+namespace aura_shell {
+
+AppListModel::AppListModel() {
+}
+
+AppListModel::~AppListModel() {
+}
+
+void AppListModel::AddGroup(AppListItemGroupModel* group) {
+ groups_.Add(group);
+}
+
+AppListItemGroupModel* AppListModel::GetGroup(int index) {
+ DCHECK(index >= 0 && index < group_count());
+ return groups_.item_at(index);
+}
+
+void AppListModel::AddObserver(ui::ListModelObserver* observer) {
+ groups_.AddObserver(observer);
+}
+
+void AppListModel::RemoveObserver(ui::ListModelObserver* observer) {
+ groups_.RemoveObserver(observer);
+}
+
+} // namespace aura_shell
diff --git a/ui/aura_shell/app_list/app_list_model.h b/ui/aura_shell/app_list/app_list_model.h
new file mode 100644
index 0000000..f077d2c
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_model.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_MODEL_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_MODEL_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "ui/aura_shell/app_list/app_list_item_group_model.h"
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/base/models/list_model.h"
+
+namespace aura_shell {
+
+// Model for AppListView. It is consisted of a list of AppListItemGroupModels,
+// which in turn owns a list of AppListItemModels.
+class AURA_SHELL_EXPORT AppListModel {
+ public:
+ AppListModel();
+ virtual ~AppListModel();
+
+ void AddGroup(AppListItemGroupModel* group);
+ AppListItemGroupModel* GetGroup(int index);
+
+ void AddObserver(ui::ListModelObserver* observer);
+ void RemoveObserver(ui::ListModelObserver* observer);
+
+ int group_count() const {
+ return groups_.item_count();
+ }
+
+ private:
+ ui::ListModel<AppListItemGroupModel> groups_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListModel);
+};
+
+} // namespace aura_shell
+
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_MODEL_H_
diff --git a/ui/aura_shell/app_list/app_list_view.cc b/ui/aura_shell/app_list/app_list_view.cc
new file mode 100644
index 0000000..01eb658
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_view.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_shell/app_list/app_list_view.h"
+
+#include "ui/aura_shell/app_list/app_list_groups_view.h"
+#include "ui/aura_shell/app_list/app_list_item_view.h"
+#include "ui/aura_shell/app_list/app_list_model.h"
+#include "ui/aura_shell/app_list/app_list_view_delegate.h"
+#include "ui/aura_shell/shell.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/widget/widget.h"
+
+namespace aura_shell {
+
+AppListView::AppListView(
+ AppListModel* model,
+ AppListViewDelegate* delegate,
+ const gfx::Rect& bounds,
+ const aura_shell::ShellDelegate::SetWidgetCallback& callback)
+ : model_(model),
+ delegate_(delegate) {
+ Init(bounds, callback);
+}
+
+AppListView::~AppListView() {
+}
+
+void AppListView::Close() {
+ if (GetWidget()->IsVisible())
+ Shell::GetInstance()->ToggleAppList();
+}
+
+void AppListView::Init(const gfx::Rect& bounds,
+ const ShellDelegate::SetWidgetCallback& callback) {
+ SetLayoutManager(new views::FillLayout);
+ AppListGroupsView* groups_view = new AppListGroupsView(model_.get(), this);
+ AddChildView(groups_view);
+
+ views::Widget::InitParams widget_params(
+ views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ widget_params.bounds = bounds;
+ widget_params.delegate = this;
+ widget_params.keep_on_top = true;
+ widget_params.transparent = true;
+
+ views::Widget* widget = new views::Widget;
+ widget->Init(widget_params);
+ widget->SetContentsView(this);
+
+ callback.Run(widget);
+ if (groups_view->GetFocusedTile())
+ groups_view->GetFocusedTile()->RequestFocus();
+}
+
+bool AppListView::OnKeyPressed(const views::KeyEvent& event) {
+ if (event.key_code() == ui::VKEY_ESCAPE) {
+ Close();
+ return true;
+ }
+
+ return false;
+}
+
+bool AppListView::OnMousePressed(const views::MouseEvent& event) {
+ // If mouse click reaches us, this means user clicks on blank area. So close.
+ Close();
+
+ return true;
+}
+
+void AppListView::AppListItemActivated(AppListItemView* sender,
+ int event_flags) {
+ if (delegate_.get())
+ delegate_->OnAppListItemActivated(sender->model(), event_flags);
+ Close();
+}
+
+} // namespace aura_shell
diff --git a/ui/aura_shell/app_list/app_list_view.h b/ui/aura_shell/app_list/app_list_view.h
new file mode 100644
index 0000000..903d3a0
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_view.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_VIEW_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_VIEW_H_
+#pragma once
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura_shell/app_list/app_list_item_view_listener.h"
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/aura_shell/shell_delegate.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace views {
+class View;
+}
+
+namespace aura_shell {
+
+class AppListModel;
+class AppListViewDelegate;
+
+// AppListView is the top-level view and controller of app list UI. It creates
+// and hosts a AppListModelView and passes AppListModel to it for display.
+class AURA_SHELL_EXPORT AppListView : public views::WidgetDelegateView,
+ public AppListItemViewListener {
+ public:
+ // Takes ownership of |model| and |delegate|.
+ AppListView(AppListModel* model,
+ AppListViewDelegate* delegate,
+ const gfx::Rect& bounds,
+ const ShellDelegate::SetWidgetCallback& callback);
+ virtual ~AppListView();
+
+ // Closes app list.
+ void Close();
+
+ private:
+ // Initializes the window.
+ void Init(const gfx::Rect& bounds,
+ const ShellDelegate::SetWidgetCallback& callback);
+
+ // Overridden from views::View:
+ virtual bool OnKeyPressed(const views::KeyEvent& event) OVERRIDE;
+ virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE;
+
+ // Overridden from AppListItemModelViewListener:
+ virtual void AppListItemActivated(AppListItemView* sender,
+ int event_flags) OVERRIDE;
+
+ scoped_ptr<AppListModel> model_;
+
+ scoped_ptr<AppListViewDelegate> delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListView);
+};
+
+} // namespace aura_shell
+
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_VIEW_H_
diff --git a/ui/aura_shell/app_list/app_list_view_delegate.h b/ui/aura_shell/app_list/app_list_view_delegate.h
new file mode 100644
index 0000000..a73b783
--- /dev/null
+++ b/ui/aura_shell/app_list/app_list_view_delegate.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_SHELL_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
+#define UI_AURA_SHELL_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
+#pragma once
+
+#include "ui/aura_shell/aura_shell_export.h"
+
+namespace aura_shell {
+
+class AppListItemModel;
+
+class AURA_SHELL_EXPORT AppListViewDelegate {
+ public:
+ // AppListView owns the delegate.
+ virtual ~AppListViewDelegate() {}
+
+ // Invoked an AppListeItemModelView is activated by click or enter key.
+ virtual void OnAppListItemActivated(AppListItemModel* item,
+ int event_flags) = 0;
+};
+
+} // namespace aura_shell
+
+#endif // UI_AURA_SHELL_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
diff --git a/ui/aura_shell/app_list/drop_shadow_label.cc b/ui/aura_shell/app_list/drop_shadow_label.cc
new file mode 100644
index 0000000..5b85224
--- /dev/null
+++ b/ui/aura_shell/app_list/drop_shadow_label.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_shell/app_list/drop_shadow_label.h"
+
+#include "base/utf_string_conversions.h"
+#include "third_party/skia/include/effects/SkGradientShader.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/skbitmap_operations.h"
+
+using views::Label;
+
+namespace aura_shell {
+
+static const int kDefaultDropShadowSize = 2;
+
+DropShadowLabel::DropShadowLabel() : drop_shadow_size_(kDefaultDropShadowSize) {
+}
+
+void DropShadowLabel::SetDropShadowSize(int drop_shadow_size) {
+ if (drop_shadow_size != drop_shadow_size_) {
+ drop_shadow_size_ = drop_shadow_size;
+ invalidate_text_size();
+ SchedulePaint();
+ }
+}
+
+void DropShadowLabel::PaintText(gfx::Canvas* canvas,
+ const string16& text,
+ const gfx::Rect& text_bounds,
+ int flags) {
+ SkColor text_color = enabled() ? enabled_color() : disabled_color();
+ if (drop_shadow_size_ > 0) {
+ // To properly render shadow with elliding fade effect, text and shadow
+ // is rendered to this canvas first with elliding disable so that underlying
+ // code would not mix shadow color into text area because of elliding fade.
+ // When that is done and if we need elliding fade, an alpha mask is applied
+ // when transfering contents on this canvas to target canvas.
+ gfx::Size canvas_size(text_bounds.width() + drop_shadow_size_,
+ text_bounds.height() + drop_shadow_size_);
+ gfx::CanvasSkia text_canvas(canvas_size, false);
+
+ const double kShadowOpacity = 0.2;
+ const SkColor shadow_color =
+ SkColorSetA(SK_ColorBLACK, kShadowOpacity * SkColorGetA(text_color));
+ gfx::Size text_size = GetTextSize();
+ for (int i = 0; i < drop_shadow_size_; i++) {
+ text_canvas.DrawStringInt(text, font(), shadow_color, i, 0,
+ text_size.width(), text_size.height(),
+ flags | gfx::Canvas::NO_ELLIPSIS);
+ text_canvas.DrawStringInt(text, font(), shadow_color, i, i,
+ text_size.width(), text_size.height(),
+ flags | gfx::Canvas::NO_ELLIPSIS);
+ text_canvas.DrawStringInt(text, font(), shadow_color, 0, i,
+ text_size.width(), text_size.height(),
+ flags | gfx::Canvas::NO_ELLIPSIS);
+ }
+ text_canvas.DrawStringInt(text, font(), text_color, 0, 0,
+ text_size.width(), text_size.height(),
+ flags | gfx::Canvas::NO_ELLIPSIS);
+
+ const SkBitmap& text_bitmap = const_cast<SkBitmap&>(
+ skia::GetTopDevice(*text_canvas.sk_canvas())->accessBitmap(false));
+
+ if (text_size.width() > text_bounds.width() &&
+ !(flags & gfx::Canvas::NO_ELLIPSIS)) {
+ // Apply an gradient alpha mask for elliding fade effect.
+ const double kFadeWidthFactor = 1.5;
+ int fade_width = std::min(text_size.width() / 2,
+ static_cast<int>(text_size.height() * kFadeWidthFactor));
+
+ const SkColor kColors[] = { SK_ColorWHITE, 0 };
+ const SkScalar kPoints[] = { SkIntToScalar(0), SkIntToScalar(1) };
+ SkPoint p[2];
+ p[0].set(SkIntToScalar(text_bounds.width() - fade_width),
+ SkIntToScalar(0));
+ p[1].set(SkIntToScalar(text_bounds.width()),
+ SkIntToScalar(0));
+ SkShader* s = SkGradientShader::CreateLinear(
+ p, kColors, kPoints, 2, SkShader::kClamp_TileMode, NULL);
+
+ SkPaint paint;
+ paint.setShader(s)->unref();
+
+ gfx::CanvasSkia alpha_canvas(canvas_size, false);
+ alpha_canvas.DrawRect(gfx::Rect(canvas_size), paint);
+
+ const SkBitmap& alpha_bitmap = const_cast<SkBitmap&>(
+ skia::GetTopDevice(*alpha_canvas.sk_canvas())->accessBitmap(false));
+ SkBitmap blended = SkBitmapOperations::CreateMaskedBitmap(text_bitmap,
+ alpha_bitmap);
+ canvas->DrawBitmapInt(blended, text_bounds.x(), text_bounds.y());
+ } else {
+ canvas->DrawBitmapInt(text_bitmap, text_bounds.x(), text_bounds.y());
+ }
+ } else {
+ canvas->DrawStringInt(text, font(), text_color, text_bounds.x(),
+ text_bounds.y(), text_bounds.width(), text_bounds.height(), flags);
+ }
+
+ if (HasFocus() || paint_as_focused()) {
+ gfx::Rect focus_bounds = text_bounds;
+ focus_bounds.Inset(-Label::kFocusBorderPadding,
+ -Label::kFocusBorderPadding);
+ canvas->DrawFocusRect(focus_bounds);
+ }
+}
+
+gfx::Size DropShadowLabel::GetTextSize() const {
+ gfx::Size text_size = Label::GetTextSize();
+ text_size.SetSize(text_size.width() + drop_shadow_size_,
+ text_size.height() + drop_shadow_size_);
+ return text_size;
+}
+
+} // namespace aura_shell
diff --git a/chrome/browser/chromeos/drop_shadow_label.h b/ui/aura_shell/app_list/drop_shadow_label.h
index e64f12d..ded5e31 100644
--- a/chrome/browser/chromeos/drop_shadow_label.h
+++ b/ui/aura_shell/app_list/drop_shadow_label.h
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_CHROMEOS_DROP_SHADOW_LABEL_H_
-#define CHROME_BROWSER_CHROMEOS_DROP_SHADOW_LABEL_H_
+#ifndef UI_AURA_SHELL_APP_LIST_DROP_SHADOW_LABEL_H_
+#define UI_AURA_SHELL_APP_LIST_DROP_SHADOW_LABEL_H_
#pragma once
#include "ui/gfx/font.h"
#include "ui/views/controls/label.h"
-namespace chromeos {
+namespace aura_shell {
/////////////////////////////////////////////////////////////////////////////
//
@@ -49,6 +49,6 @@ class DropShadowLabel : public views::Label {
DISALLOW_COPY_AND_ASSIGN(DropShadowLabel);
};
-} // namespace chromeos
+} // namespace aura_shell
-#endif // CHROME_BROWSER_CHROMEOS_DROP_SHADOW_LABEL_H_
+#endif // UI_AURA_SHELL_APP_LIST_DROP_SHADOW_LABEL_H_
diff --git a/ui/aura_shell/aura_shell.gyp b/ui/aura_shell/aura_shell.gyp
index ddfc949..1e1d9a1 100644
--- a/ui/aura_shell/aura_shell.gyp
+++ b/ui/aura_shell/aura_shell.gyp
@@ -33,10 +33,29 @@
],
'sources': [
# All .cc, .h under views, except unittests
- 'app_list.cc',
- 'app_list.h',
'aura_shell_switches.cc',
'aura_shell_switches.h',
+ 'app_list/app_list.cc',
+ 'app_list/app_list.h',
+ 'app_list/app_list_groups_view.cc',
+ 'app_list/app_list_groups_view.h',
+ 'app_list/app_list_item_group_model.cc',
+ 'app_list/app_list_item_group_model.h',
+ 'app_list/app_list_item_group_view.cc',
+ 'app_list/app_list_item_group_view.h',
+ 'app_list/app_list_item_model.cc',
+ 'app_list/app_list_item_model.h',
+ 'app_list/app_list_item_model_observer.h',
+ 'app_list/app_list_item_view.cc',
+ 'app_list/app_list_item_view.h',
+ 'app_list/app_list_item_view_listener.h',
+ 'app_list/app_list_model.cc',
+ 'app_list/app_list_model.h',
+ 'app_list/app_list_view.cc',
+ 'app_list/app_list_view.h',
+ 'app_list/app_list_view_delegate.h',
+ 'app_list/drop_shadow_label.cc',
+ 'app_list/drop_shadow_label.h',
'compact_layout_manager.cc',
'compact_layout_manager.h',
'compact_status_area_layout_manager.cc',
@@ -222,6 +241,7 @@
'aura_shell',
],
'sources': [
+ '../../ash/shell/app_list.cc',
'../../ash/shell/bubble.cc',
'../../ash/shell/example_factory.h',
'../../ash/shell/lock_view.cc',
diff --git a/ui/aura_shell/aura_shell_switches.cc b/ui/aura_shell/aura_shell_switches.cc
index aee6bf3..6c6e728 100644
--- a/ui/aura_shell/aura_shell_switches.cc
+++ b/ui/aura_shell/aura_shell_switches.cc
@@ -17,6 +17,9 @@ const char kAuraNoShadows[] = "aura-no-shadows";
// Use Aura-style translucent window frame.
const char kAuraTranslucentFrames[] = "aura-translucent-frames";
+// Use views-based app list.
+const char kAuraViewsAppList[] = "aura-views-applist";
+
// Use a custom window style, e.g. --aura-window-mode=compact.
// When this flag is not passed we default to "normal" mode.
const char kAuraWindowMode[] = "aura-window-mode";
diff --git a/ui/aura_shell/aura_shell_switches.h b/ui/aura_shell/aura_shell_switches.h
index 95adef5..fd6ffcb3 100644
--- a/ui/aura_shell/aura_shell_switches.h
+++ b/ui/aura_shell/aura_shell_switches.h
@@ -14,6 +14,7 @@ namespace switches {
// Please keep alphabetized.
AURA_SHELL_EXPORT extern const char kAuraNoShadows[];
AURA_SHELL_EXPORT extern const char kAuraTranslucentFrames[];
+AURA_SHELL_EXPORT extern const char kAuraViewsAppList[];
AURA_SHELL_EXPORT extern const char kAuraWindowMode[];
AURA_SHELL_EXPORT extern const char kAuraWindowModeCompact[];
AURA_SHELL_EXPORT extern const char kAuraWindowModeNormal[];
diff --git a/ui/aura_shell/shell.cc b/ui/aura_shell/shell.cc
index bfa233e..f73c39e 100644
--- a/ui/aura_shell/shell.cc
+++ b/ui/aura_shell/shell.cc
@@ -15,7 +15,7 @@
#include "ui/aura/root_window.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
-#include "ui/aura_shell/app_list.h"
+#include "ui/aura_shell/app_list/app_list.h"
#include "ui/aura_shell/aura_shell_switches.h"
#include "ui/aura_shell/compact_layout_manager.h"
#include "ui/aura_shell/compact_status_area_layout_manager.h"
diff --git a/ui/aura_shell/shell_delegate.h b/ui/aura_shell/shell_delegate.h
index 982ef8d..7912919 100644
--- a/ui/aura_shell/shell_delegate.h
+++ b/ui/aura_shell/shell_delegate.h
@@ -19,6 +19,8 @@ class Widget;
namespace aura_shell {
+class AppListModel;
+class AppListViewDelegate;
struct LauncherItem;
// Delegate of the Shell.
@@ -39,10 +41,19 @@ class AURA_SHELL_EXPORT ShellDelegate {
// Invoked to create app list widget. The Delegate calls the callback
// when the widget is ready to show.
+ // Deprecated.
+ // TODO(xiyuan): Clean this up when switching to views app list.
virtual void RequestAppListWidget(
const gfx::Rect& bounds,
const SetWidgetCallback& callback) = 0;
+ // Invoked to ask the delegate to populate the |model|.
+ virtual void BuildAppListModel(AppListModel* model) = 0;
+
+ // Invoked to create an AppListViewDelegate. Shell takes the ownership of
+ // the created delegate.
+ virtual AppListViewDelegate* CreateAppListViewDelegate() = 0;
+
// Invoked when the user clicks on a window entry in the launcher.
virtual void LauncherItemClicked(const LauncherItem& item) = 0;
diff --git a/ui/aura_shell/test/test_shell_delegate.cc b/ui/aura_shell/test/test_shell_delegate.cc
index 42414b7..0a58e7c 100644
--- a/ui/aura_shell/test/test_shell_delegate.cc
+++ b/ui/aura_shell/test/test_shell_delegate.cc
@@ -25,6 +25,13 @@ void TestShellDelegate::RequestAppListWidget(
const SetWidgetCallback& callback) {
}
+void TestShellDelegate::BuildAppListModel(AppListModel* model) {
+}
+
+AppListViewDelegate* TestShellDelegate::CreateAppListViewDelegate() {
+ return NULL;
+}
+
void TestShellDelegate::LauncherItemClicked(const LauncherItem& item) {
}
diff --git a/ui/aura_shell/test/test_shell_delegate.h b/ui/aura_shell/test/test_shell_delegate.h
index 6811d45..a300b00 100644
--- a/ui/aura_shell/test/test_shell_delegate.h
+++ b/ui/aura_shell/test/test_shell_delegate.h
@@ -23,6 +23,8 @@ class TestShellDelegate : public ShellDelegate {
virtual void RequestAppListWidget(
const gfx::Rect& bounds,
const SetWidgetCallback& callback) OVERRIDE;
+ virtual void BuildAppListModel(AppListModel* model) OVERRIDE;
+ virtual AppListViewDelegate* CreateAppListViewDelegate() OVERRIDE;
virtual void LauncherItemClicked(const LauncherItem& item) OVERRIDE;
virtual bool ConfigureLauncherItem(LauncherItem* item) OVERRIDE;
};
diff --git a/ui/base/models/list_model.h b/ui/base/models/list_model.h
new file mode 100644
index 0000000..3634ed1
--- /dev/null
+++ b/ui/base/models/list_model.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_MODELS_LIST_MODEL_H_
+#define UI_BASE_MODELS_LIST_MODEL_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/observer_list.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/base/models/list_model_observer.h"
+
+namespace ui {
+
+// A list model that manages a list of ItemType pointers. Items added to the
+// model are owned by the model. An item can be taken out of the model by
+// RemoveAt.
+template <class ItemType>
+class ListModel {
+ public:
+ typedef std::vector<ItemType*> Items;
+
+ ListModel() {}
+ virtual ~ListModel() {}
+
+ // Adds |item| to the model at given |index|.
+ virtual void AddAt(int index, ItemType* item) {
+ DCHECK(index >= 0 && index <= item_count());
+ items_->insert(items_.begin() + index, item);
+ NotifyItemsAdded(index, 1);
+ }
+
+ // Removes an item at given |index| from the model. Note the removed item
+ // is NOT deleted and it's up to the caller to delete it.
+ virtual ItemType* RemoveAt(int index) {
+ DCHECK(index >= 0 && index < item_count());
+ ItemType* item = items_[index];
+ items_->erase(items_.begin() + index);
+ NotifyItemsRemoved(index, 1);
+ return item;
+ }
+
+ // Removes all items from the model. This does NOT delete the items.
+ virtual void RemoveAll() {
+ int count = item_count();
+ items_->clear();
+ NotifyItemsRemoved(0, count);
+ }
+
+ // Removes an item at given |index| from the model and deletes it.
+ virtual void DeleteAt(int index) {
+ delete RemoveAt(index);
+ }
+
+ // Removes and deletes all items from the model.
+ virtual void DeleteAll() {
+ int count = item_count();
+ items_.reset();
+ NotifyItemsRemoved(0, count);
+ }
+
+ // Convenience function to append an item to the model.
+ void Add(ItemType* item) {
+ AddAt(item_count(), item);
+ }
+
+ void AddObserver(ListModelObserver* observer) {
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(ListModelObserver* observer) {
+ observers_.RemoveObserver(observer);
+ }
+
+ void NotifyItemsAdded(int start, int count) {
+ FOR_EACH_OBSERVER(ListModelObserver,
+ observers_,
+ ListItemsAdded(start, count));
+ }
+
+ void NotifyItemsRemoved(int start, int count) {
+ FOR_EACH_OBSERVER(ListModelObserver,
+ observers_,
+ ListItemsRemoved(start, count));
+ }
+
+ void NotifyItemsChanged(int start, int count) {
+ FOR_EACH_OBSERVER(ListModelObserver,
+ observers_,
+ ListItemsChanged(start, count));
+ }
+
+ int item_count() const { return static_cast<int>(items_.size()); }
+ const Items& items() const { return items_.get(); }
+
+ const ItemType* item_at(int index) const {
+ DCHECK(index >= 0 && index < item_count());
+ return items_[index];
+ }
+ ItemType* item_at(int index) {
+ return const_cast<ItemType*>(
+ const_cast<const ListModel<ItemType>*>(this)->item_at(index));
+ }
+
+ private:
+ ScopedVector<ItemType> items_;
+ ObserverList<ListModelObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ListModel<ItemType>);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_MODELS_LIST_MODEL_H_
diff --git a/ui/base/models/list_model_observer.h b/ui/base/models/list_model_observer.h
new file mode 100644
index 0000000..65b22a8
--- /dev/null
+++ b/ui/base/models/list_model_observer.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_MODELS_LIST_MODEL_OBSERVER_H_
+#define UI_BASE_MODELS_LIST_MODEL_OBSERVER_H_
+#pragma once
+
+#include "ui/base/ui_export.h"
+
+namespace ui {
+
+class UI_EXPORT ListModelObserver {
+ public:
+ // Invoked after items has been added to the model.
+ virtual void ListItemsAdded(int start, int count) = 0;
+
+ // Invoked after items has been removed. |start| is the index before the
+ // removal.
+ virtual void ListItemsRemoved(int start, int count) = 0;
+
+ // Invoked after items has been changed.
+ virtual void ListItemsChanged(int start, int count) = 0;
+
+ protected:
+ virtual ~ListModelObserver() {}
+};
+
+} // namespace ui
+
+#endif // UI_BASE_MODELS_LIST_MODEL_OBSERVER_H_
diff --git a/ui/base/models/list_model_unittest.cc b/ui/base/models/list_model_unittest.cc
new file mode 100644
index 0000000..1718431
--- /dev/null
+++ b/ui/base/models/list_model_unittest.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/models/list_model.h"
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+
+class FooItem {
+ public:
+ explicit FooItem(int id) : id_(id) {}
+
+ int id() const { return id_; }
+
+ private:
+ int id_;
+ DISALLOW_COPY_AND_ASSIGN(FooItem);
+};
+
+class ListModelTest : public testing::Test,
+ public ListModelObserver {
+ public:
+ ListModelTest()
+ : added_count_(0),
+ removed_count_(0),
+ changed_count_(0) {
+ }
+
+ void ExpectCountsEqual(int added_count,
+ int removed_count,
+ int changed_count) {
+ EXPECT_EQ(added_count, added_count_);
+ EXPECT_EQ(removed_count, removed_count_);
+ EXPECT_EQ(changed_count, changed_count_);
+ }
+
+ void ClearCounts() {
+ added_count_ = removed_count_ = changed_count_ = 0;
+ }
+
+ // ListModelObserver implementation:
+ virtual void ListItemsAdded(int start, int count) OVERRIDE {
+ added_count_ += count;
+ }
+ virtual void ListItemsRemoved(int start, int count) OVERRIDE {
+ removed_count_ += count;
+ }
+ virtual void ListItemsChanged(int start, int count) OVERRIDE {
+ changed_count_ += count;
+ }
+
+ private:
+ int added_count_;
+ int removed_count_;
+ int changed_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ListModelTest);
+};
+
+TEST_F(ListModelTest, Add) {
+ ListModel<FooItem> model;
+ model.AddObserver(this);
+
+ // Append FooItem(0)
+ model.Add(new FooItem(0));
+ ExpectCountsEqual(1, 0, 0);
+
+ // Append FooItem(1)
+ model.Add(new FooItem(1));
+ ExpectCountsEqual(2, 0, 0);
+
+ // Insert FooItem(2) at position 0
+ model.AddAt(0, new FooItem(2));
+ ExpectCountsEqual(3, 0, 0);
+
+ // Total 3 items in mode.
+ EXPECT_EQ(3, model.item_count());
+
+ // First one should be FooItem(2), followed by FooItem(0) and FooItem(1)
+ EXPECT_EQ(2, model.item_at(0)->id());
+ EXPECT_EQ(0, model.item_at(1)->id());
+ EXPECT_EQ(1, model.item_at(2)->id());
+}
+
+TEST_F(ListModelTest, Remove) {
+ ListModel<FooItem> model;
+ model.AddObserver(this);
+
+ model.Add(new FooItem(0));
+ model.Add(new FooItem(1));
+ model.Add(new FooItem(2));
+
+ ClearCounts();
+
+ // Remove item at index 1 from model and release memory.
+ model.DeleteAt(1);
+ ExpectCountsEqual(0, 1, 0);
+
+ EXPECT_EQ(2, model.item_count());
+ EXPECT_EQ(0, model.item_at(0)->id());
+ EXPECT_EQ(2, model.item_at(1)->id());
+
+ // Remove all items from model and delete them.
+ model.DeleteAll();
+ ExpectCountsEqual(0, 3, 0);
+}
+
+TEST_F(ListModelTest, RemoveAll) {
+ ListModel<FooItem> model;
+ model.AddObserver(this);
+
+ scoped_ptr<FooItem> foo0(new FooItem(0));
+ scoped_ptr<FooItem> foo1(new FooItem(1));
+ scoped_ptr<FooItem> foo2(new FooItem(2));
+
+ model.Add(foo0.get());
+ model.Add(foo1.get());
+ model.Add(foo2.get());
+
+ ClearCounts();
+
+ // Remove all items and scoped_ptr above would release memory.
+ model.RemoveAll();
+ ExpectCountsEqual(0, 3, 0);
+}
+
+TEST_F(ListModelTest, FakeUpdate) {
+ ListModel<FooItem> model;
+ model.AddObserver(this);
+
+ model.Add(new FooItem(0));
+ model.Add(new FooItem(1));
+ model.Add(new FooItem(2));
+
+ ClearCounts();
+
+ model.NotifyItemsChanged(0, 1);
+ ExpectCountsEqual(0, 0, 1);
+
+ model.NotifyItemsChanged(1, 2);
+ ExpectCountsEqual(0, 0, 3);
+}
+
+} // namespace ui
diff --git a/ui/base/ui_base_exports.cc b/ui/base/ui_base_exports.cc
index 5759e9b..5d7f51d 100644
--- a/ui/base/ui_base_exports.cc
+++ b/ui/base/ui_base_exports.cc
@@ -8,4 +8,5 @@
// resulting dynamic library (ui.dll).
#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/models/list_model_observer.h"
#include "ui/base/models/table_model_observer.h"
diff --git a/ui/ui.gyp b/ui/ui.gyp
index d49d141..4b50684 100644
--- a/ui/ui.gyp
+++ b/ui/ui.gyp
@@ -174,6 +174,8 @@
'base/models/button_menu_item_model.cc',
'base/models/button_menu_item_model.h',
'base/models/combobox_model.h',
+ 'base/models/list_model.h',
+ 'base/models/list_model_observer.h',
'base/models/menu_model.cc',
'base/models/menu_model.h',
'base/models/menu_model_delegate.h',
diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi
index ced2aa3..6130da5 100644
--- a/ui/ui_unittests.gypi
+++ b/ui/ui_unittests.gypi
@@ -57,6 +57,7 @@
'base/ime/character_composer_unittest.cc',
'base/l10n/l10n_util_mac_unittest.mm',
'base/l10n/l10n_util_unittest.cc',
+ 'base/models/list_model_unittest.cc',
'base/models/tree_node_iterator_unittest.cc',
'base/models/tree_node_model_unittest.cc',
'base/range/range_unittest.cc',