summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-20 23:23:33 +0000
committerskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-20 23:23:33 +0000
commit983ecb1a0f93e427187ae41baa6cd686954754d6 (patch)
treec9b5e40060e87acce6277fe793ddeec8b6cc372c
parenta50ae535e1fbc14c1468376aad90908fccda9978 (diff)
downloadchromium_src-983ecb1a0f93e427187ae41baa6cd686954754d6.zip
chromium_src-983ecb1a0f93e427187ae41baa6cd686954754d6.tar.gz
chromium_src-983ecb1a0f93e427187ae41baa6cd686954754d6.tar.bz2
Adding new Launcher behavior
This is only an intermediate CL - trying to keep the CL's in a handle-able size. The new features of the Launcher behavior are: - Group running programs (V1, V2, Browsers) under existing launcher application icons. - When a V2 app gets started and it is not pinned to the launcher, it will be added for it's lifetime to the launcher (and disappear after the last incarnation goes away). - Each shown launcher entry can ... + .. show a context menu (right click) which can e.g. close all applications of that type. + .. activate or create such a type upon first click. + .. produce a list of running "apps" upon click when one of the applications has already a focus. [more to come] + .. [maybe] produce a fancy hover menu. (at the moment it produces the bubble help) - The list of apps (as described above) contains ... + .. The name of the app itself. + .. For each running instance the favicon & the title & (not yet implemented:) an icon for incognito. - The new features are behind a flag. The full specification can be seen here: https://docs.google.com/a/google.com/document/d/1i39rO8uERWwTvV0e0TDtelgGjzU9Wj5L6CldMl9y6lE/edit This is the second CL for these new features, however there are still several things missing which will be addressed in more CL's: - More unit tests (activation state tracking, V2 apps) - The "eye candy menus" (mocks are still missing) .. + .. including incognito marker + .. a definition how the menus get sorted + .. the open question about click or hover menus + .. touch integration - The browser icon should be movable as well - Rip out old classes and unused complexity - which can only be done after the flag gets removed: At the moment, the changes are trying to stay within the existing architecture to make it possible to switch with a flag. BUG=164438, 145410 Review URL: https://chromiumcodereview.appspot.com/11552028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@174270 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/launcher/launcher_delegate.h10
-rw-r--r--ash/launcher/launcher_model.h4
-rw-r--r--ash/launcher/launcher_model_unittest.cc28
-rw-r--r--ash/launcher/launcher_view.cc101
-rw-r--r--ash/launcher/launcher_view.h19
-rw-r--r--ash/launcher/launcher_view_unittest.cc4
-rw-r--r--ash/shell/launcher_delegate_impl.cc5
-rw-r--r--ash/shell/launcher_delegate_impl.h2
-rw-r--r--ash/test/test_launcher_delegate.cc5
-rw-r--r--ash/test/test_launcher_delegate.h2
-rw-r--r--chrome/app/generated_resources.grd3
-rw-r--r--chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc171
-rw-r--r--chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h55
-rw-r--r--chrome/browser/ui/ash/launcher/browser_launcher_item_controller.cc19
-rw-r--r--chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h1
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.cc21
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h37
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc49
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h41
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc40
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h35
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc29
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h45
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc4
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller.h16
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc4
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc441
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h46
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc253
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc18
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h11
-rw-r--r--chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc55
-rw-r--r--chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h38
-rw-r--r--chrome/browser/ui/ash/launcher/launcher_context_menu.cc9
-rw-r--r--chrome/browser/ui/ash/launcher/launcher_item_controller.h7
-rw-r--r--chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc181
-rw-r--r--chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h15
-rw-r--r--chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc189
-rw-r--r--chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h88
-rw-r--r--chrome/browser/ui/extensions/shell_window.cc16
-rw-r--r--chrome/browser/ui/extensions/shell_window.h5
-rw-r--r--chrome/browser/ui/views/frame/browser_view.h7
-rw-r--r--chrome/chrome_browser_ui.gypi14
-rw-r--r--chrome/test/base/browser_with_test_window_test.cc10
-rw-r--r--chrome/test/base/browser_with_test_window_test.h6
45 files changed, 1724 insertions, 435 deletions
diff --git a/ash/launcher/launcher_delegate.h b/ash/launcher/launcher_delegate.h
index e3eb140..1e3288f 100644
--- a/ash/launcher/launcher_delegate.h
+++ b/ash/launcher/launcher_delegate.h
@@ -47,6 +47,16 @@ class ASH_EXPORT LauncherDelegate {
virtual ui::MenuModel* CreateContextMenu(const LauncherItem& item,
aura::RootWindow* root_window) = 0;
+ // Returns the application menu model for the specified item. There are three
+ // possible return values:
+ // - A return of NULL indicates that no menu is wanted for this item.
+ // - A return of a menu with one item means that only the name of the
+ // application/item was added and there are no active applications.
+ // Note: This is useful for hover menus which also show context help.
+ // - A list containing the title and the active list of items.
+ // The caller takes ownership of the returned model.
+ virtual ui::MenuModel* CreateApplicationMenu(const LauncherItem& item) = 0;
+
// Returns the id of the item associated with the specified window, or 0 if
// there isn't one.
virtual LauncherID GetIDByWindow(aura::Window* window) = 0;
diff --git a/ash/launcher/launcher_model.h b/ash/launcher/launcher_model.h
index ce52126..3e2ba59 100644
--- a/ash/launcher/launcher_model.h
+++ b/ash/launcher/launcher_model.h
@@ -54,6 +54,9 @@ class ASH_EXPORT LauncherModel {
// Returns the id assigned to the next item added.
LauncherID next_id() const { return next_id_; }
+ // Returns a reserved id which will not be used by the |LauncherModel|.
+ LauncherID reserve_external_id() { return next_id_++; }
+
// Returns an iterator into items() for the item with the specified id, or
// items().end() if there is no item with the specified id.
LauncherItems::const_iterator ItemByID(LauncherID id) const;
@@ -75,6 +78,7 @@ class ASH_EXPORT LauncherModel {
// ID assigned to the next item.
LauncherID next_id_;
+
LauncherItems items_;
Status status_;
ObserverList<LauncherModelObserver> observers_;
diff --git a/ash/launcher/launcher_model_unittest.cc b/ash/launcher/launcher_model_unittest.cc
index 21aa3f1..fb29267 100644
--- a/ash/launcher/launcher_model_unittest.cc
+++ b/ash/launcher/launcher_model_unittest.cc
@@ -211,4 +211,32 @@ TEST(LauncherModel, AddIndices) {
EXPECT_EQ(TYPE_APP_LIST, model.items()[model.FirstPanelIndex() - 1].type);
}
+// Assertions around id generation and usage.
+TEST(LauncherModel, LauncherIDTests) {
+ TestLauncherModelObserver observer;
+ LauncherModel model;
+
+ EXPECT_EQ(2, model.item_count());
+
+ // Get the next to use ID counter.
+ LauncherID id = model.next_id();
+
+ // Calling this function multiple times does not change the returned ID.
+ EXPECT_EQ(model.next_id(), id);
+
+ // Check that when we reserve a value it will be the previously retrieved ID,
+ // but it will not change the item count and retrieving the next ID should
+ // produce something new.
+ EXPECT_EQ(model.reserve_external_id(), id);
+ EXPECT_EQ(2, model.item_count());
+ LauncherID id2 = model.next_id();
+ EXPECT_NE(id2, id);
+
+ // Adding another item to the list should also produce a new ID.
+ LauncherItem item;
+ item.type = TYPE_TABBED;
+ model.Add(item);
+ EXPECT_NE(model.next_id(), id2);
+}
+
} // namespace ash
diff --git a/ash/launcher/launcher_view.cc b/ash/launcher/launcher_view.cc
index b4f05ef..4b6bac82 100644
--- a/ash/launcher/launcher_view.cc
+++ b/ash/launcher/launcher_view.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "ash/ash_constants.h"
+#include "ash/ash_switches.h"
#include "ash/launcher/app_list_button.h"
#include "ash/launcher/launcher_button.h"
#include "ash/launcher/launcher_delegate.h"
@@ -19,6 +20,7 @@
#include "ash/shell_delegate.h"
#include "ash/wm/shelf_layout_manager.h"
#include "base/auto_reset.h"
+#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "grit/ash_strings.h"
#include "grit/ash_resources.h"
@@ -950,13 +952,21 @@ void LauncherView::LauncherItemChanged(int model_index,
ReflectItemStatus(item, button);
break;
}
-
+ case TYPE_BROWSER_SHORTCUT:
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ ash::switches::kAshEnablePerAppLauncher))
+ break;
+ // Fallthrough for the new Launcher since it needs to show the activation
+ // change as well.
case TYPE_APP_SHORTCUT:
case TYPE_PLATFORM_APP:
case TYPE_APP_PANEL: {
LauncherButton* button = static_cast<LauncherButton*>(view);
ReflectItemStatus(item, button);
- button->SetImage(item.image);
+ // The browser shortcut is currently not a "real" item and as such the
+ // the image is bogous as well. We therefore keep the image as is for it.
+ if (item.type != TYPE_BROWSER_SHORTCUT)
+ button->SetImage(item.image);
button->SchedulePaint();
break;
}
@@ -1100,38 +1110,89 @@ void LauncherView::ButtonPressed(views::Button* sender,
if (view_index == -1)
return;
- if (event.IsShiftDown())
- ui::LayerAnimator::set_slow_animation_mode(true);
tooltip_->Close();
- switch (model_->items()[view_index].type) {
- case TYPE_TABBED:
- case TYPE_APP_PANEL:
- delegate_->ItemClicked(model_->items()[view_index], event.flags());
- break;
+ // Collect usage statistics before we decide what to do with the click.
+ switch (model_->items()[view_index].type) {
case TYPE_APP_SHORTCUT:
case TYPE_PLATFORM_APP:
Shell::GetInstance()->delegate()->RecordUserMetricsAction(
UMA_LAUNCHER_CLICK_ON_APP);
- delegate_->ItemClicked(model_->items()[view_index], event.flags());
break;
case TYPE_APP_LIST:
Shell::GetInstance()->delegate()->RecordUserMetricsAction(
UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON);
- Shell::GetInstance()->ToggleAppList(GetWidget()->GetNativeView());
break;
case TYPE_BROWSER_SHORTCUT:
// Click on browser icon is counted in app clicks.
Shell::GetInstance()->delegate()->RecordUserMetricsAction(
UMA_LAUNCHER_CLICK_ON_APP);
+ break;
- delegate_->OnBrowserShortcutClicked(event.flags());
+ case TYPE_TABBED:
+ case TYPE_APP_PANEL:
break;
}
- if (event.IsShiftDown())
- ui::LayerAnimator::set_slow_animation_mode(false);
+
+ // If the item is already active we show a menu - otherwise we activate
+ // the item dependent on its type.
+ // Note that the old launcher has no menu and falls back automatically to
+ // the click action.
+ bool call_object_handler = model_->items()[view_index].type == TYPE_APP_LIST;
+ if (!call_object_handler) {
+ call_object_handler =
+ model_->items()[view_index].status != ash::STATUS_ACTIVE;
+ if (!call_object_handler) {
+ // ShowListMenuForView only returns true if the menu was shown.
+ if (ShowListMenuForView(model_->items()[view_index],
+ sender,
+ sender->GetBoundsInScreen().CenterPoint())) {
+ // When the menu was shown it is possible that this got deleted.
+ return;
+ }
+ call_object_handler = true;
+ }
+ }
+
+ if (call_object_handler) {
+ if (event.IsShiftDown())
+ ui::LayerAnimator::set_slow_animation_mode(true);
+ // The menu was not shown and the objects click handler should be called.
+ switch (model_->items()[view_index].type) {
+ case TYPE_TABBED:
+ case TYPE_APP_PANEL:
+ case TYPE_APP_SHORTCUT:
+ case TYPE_PLATFORM_APP:
+ delegate_->ItemClicked(model_->items()[view_index], event.flags());
+ break;
+ case TYPE_APP_LIST:
+ Shell::GetInstance()->ToggleAppList(GetWidget()->GetNativeView());
+ break;
+ case TYPE_BROWSER_SHORTCUT:
+ delegate_->OnBrowserShortcutClicked(event.flags());
+ break;
+ }
+ if (event.IsShiftDown())
+ ui::LayerAnimator::set_slow_animation_mode(false);
+ }
+
+}
+
+bool LauncherView::ShowListMenuForView(const LauncherItem& item,
+ views::View* source,
+ const gfx::Point& point) {
+ scoped_ptr<ui::MenuModel> menu_model;
+ menu_model.reset(delegate_->CreateApplicationMenu(item));
+
+ // Make sure we have a menu and it has at least one item in addition to the
+ // application title.
+ if (!menu_model.get() || menu_model->GetItemCount() <= 1)
+ return false;
+
+ ShowMenu(menu_model.get(), source, point);
+ return true;
}
void LauncherView::ShowContextMenuForView(views::View* source,
@@ -1141,7 +1202,7 @@ void LauncherView::ShowContextMenuForView(views::View* source,
model_->items()[view_index].type == TYPE_APP_LIST) {
view_index = -1;
}
-#if !defined(OS_MACOSX)
+
if (view_index == -1) {
Shell::GetInstance()->ShowContextMenu(point);
return;
@@ -1154,7 +1215,14 @@ void LauncherView::ShowContextMenuForView(views::View* source,
base::AutoReset<LauncherID> reseter(
&context_menu_id_,
view_index == -1 ? 0 : model_->items()[view_index].id);
- views::MenuModelAdapter menu_model_adapter(menu_model.get());
+
+ ShowMenu(menu_model.get(), source, point);
+}
+
+void LauncherView::ShowMenu(ui::MenuModel* menu_model,
+ views::View* source,
+ const gfx::Point& point) {
+ views::MenuModelAdapter menu_model_adapter(menu_model);
launcher_menu_runner_.reset(
new views::MenuRunner(menu_model_adapter.CreateMenu()));
// NOTE: if you convert to HAS_MNEMONICS be sure and update menu building
@@ -1166,7 +1234,6 @@ void LauncherView::ShowContextMenuForView(views::View* source,
return;
Shell::GetInstance()->UpdateShelfVisibility();
-#endif
}
void LauncherView::OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) {
diff --git a/ash/launcher/launcher_view.h b/ash/launcher/launcher_view.h
index 48c14c7..4c91ade 100644
--- a/ash/launcher/launcher_view.h
+++ b/ash/launcher/launcher_view.h
@@ -25,6 +25,10 @@ class MenuRunner;
class ViewModel;
}
+namespace ui {
+class MenuModel;
+}
+
namespace ash {
namespace test {
@@ -210,10 +214,25 @@ class ASH_EXPORT LauncherView : public views::View,
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
+ // Show the list of all running items for this |item|. It will return true
+ // when the menu was shown and false if there were no possible items to
+ // choose from. |source| specifies the view which is responsible for showing
+ // the menu and |point| is the origin for the point.
+ // TODO(skuhne): Depending on the menu type we use in the end (hover vs.
+ // click), |point| might become obsolete.
+ bool ShowListMenuForView(const LauncherItem& item,
+ views::View* source,
+ const gfx::Point& point);
+
// Overridden from views::ContextMenuController:
virtual void ShowContextMenuForView(views::View* source,
const gfx::Point& point) OVERRIDE;
+ // Show either a context or normal click menu of given |menu_model|.
+ void ShowMenu(ui::MenuModel* menu_model,
+ views::View*source,
+ const gfx::Point& point);
+
// Overridden from views::BoundsAnimatorObserver:
virtual void OnBoundsAnimatorProgressed(
views::BoundsAnimator* animator) OVERRIDE;
diff --git a/ash/launcher/launcher_view_unittest.cc b/ash/launcher/launcher_view_unittest.cc
index 61c247d..2c5ade8 100644
--- a/ash/launcher/launcher_view_unittest.cc
+++ b/ash/launcher/launcher_view_unittest.cc
@@ -159,6 +159,10 @@ class MockLauncherDelegate : public ash::LauncherDelegate {
aura::RootWindow* root_window) OVERRIDE {
return NULL;
}
+ virtual ui::MenuModel* CreateApplicationMenu(
+ const ash::LauncherItem&) OVERRIDE {
+ return NULL;
+ }
virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE {
NOTREACHED();
return -1;
diff --git a/ash/shell/launcher_delegate_impl.cc b/ash/shell/launcher_delegate_impl.cc
index 9cf4ca6..6caeb23 100644
--- a/ash/shell/launcher_delegate_impl.cc
+++ b/ash/shell/launcher_delegate_impl.cc
@@ -49,6 +49,11 @@ ui::MenuModel* LauncherDelegateImpl::CreateContextMenu(
return NULL;
}
+ui::MenuModel* LauncherDelegateImpl::CreateApplicationMenu(
+ const ash::LauncherItem& item) {
+ return NULL;
+}
+
ash::LauncherID LauncherDelegateImpl::GetIDByWindow(aura::Window* window) {
return watcher_->GetIDByWindow(window);
}
diff --git a/ash/shell/launcher_delegate_impl.h b/ash/shell/launcher_delegate_impl.h
index 978ddaf..6997360 100644
--- a/ash/shell/launcher_delegate_impl.h
+++ b/ash/shell/launcher_delegate_impl.h
@@ -33,6 +33,8 @@ class LauncherDelegateImpl : public ash::LauncherDelegate {
virtual ui::MenuModel* CreateContextMenu(
const ash::LauncherItem& item,
aura::RootWindow* root) OVERRIDE;
+ virtual ui::MenuModel* CreateApplicationMenu(
+ const ash::LauncherItem&) OVERRIDE;
virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE;
virtual bool IsDraggable(const ash::LauncherItem& item) OVERRIDE;
diff --git a/ash/test/test_launcher_delegate.cc b/ash/test/test_launcher_delegate.cc
index e708e49..52c1ff0d 100644
--- a/ash/test/test_launcher_delegate.cc
+++ b/ash/test/test_launcher_delegate.cc
@@ -83,6 +83,11 @@ ui::MenuModel* TestLauncherDelegate::CreateContextMenu(
return NULL;
}
+ui::MenuModel* TestLauncherDelegate::CreateApplicationMenu(
+ const ash::LauncherItem& item) {
+ return NULL;
+}
+
ash::LauncherID TestLauncherDelegate::GetIDByWindow(aura::Window* window) {
WindowToID::const_iterator found = window_to_id_.find(window);
if (found == window_to_id_.end())
diff --git a/ash/test/test_launcher_delegate.h b/ash/test/test_launcher_delegate.h
index 38140fa..417d3de 100644
--- a/ash/test/test_launcher_delegate.h
+++ b/ash/test/test_launcher_delegate.h
@@ -42,6 +42,8 @@ class TestLauncherDelegate : public LauncherDelegate,
virtual string16 GetTitle(const LauncherItem& item) OVERRIDE;
virtual ui::MenuModel* CreateContextMenu(const LauncherItem& item,
aura::RootWindow* root) OVERRIDE;
+ virtual ui::MenuModel* CreateApplicationMenu(
+ const LauncherItem& item) OVERRIDE;
virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE;
virtual bool IsDraggable(const ash::LauncherItem& item) OVERRIDE;
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index de9c165..b02d4f1 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3110,6 +3110,9 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY">$1<ex>(Ctrl+Shift+N)</ex></ph> may
Create Application Shortcuts
</message>
</if>
+ <message name="IDS_LAUNCHER_CHROME_BROWSER_NAME" desc="The name of the Chrome browser in the Launcher list.">
+ <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> browser
+ </message>
<message name="IDS_CREATE_SHORTCUTS_LABEL" desc="Contents of the main label in the create application shortcuts dialog explaining the dialog.">
Create application shortcuts in the following places:
</message>
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
new file mode 100644
index 0000000..2797dd8
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
@@ -0,0 +1,171 @@
+// Copyright (c) 2012 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/ash/launcher/app_shortcut_launcher_item_controller.h"
+
+#include "ash/wm/window_util.h"
+#include "chrome/browser/favicon/favicon_tab_helper.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/extensions/native_app_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "content/public/browser/web_contents.h"
+
+using extensions::Extension;
+
+// Item controller for an app shortcut. Shortcuts track app and launcher ids,
+// but do not have any associated windows (opening a shortcut will replace the
+// item with the appropriate LauncherItemController type).
+AppShortcutLauncherItemController::AppShortcutLauncherItemController(
+ const std::string& app_id,
+ ChromeLauncherControllerPerApp* controller)
+ : LauncherItemController(TYPE_SHORTCUT, app_id, controller),
+ app_controller_(controller) {
+ // To detect V1 applications we use their domain and match them against the
+ // used URL. This will also work with applications like Google Drive.
+ const Extension* extension =
+ launcher_controller()->GetExtensionForAppID(app_id);
+ refocus_url_ = GURL(extension->launch_web_url() + "*");
+}
+
+AppShortcutLauncherItemController::~AppShortcutLauncherItemController() {
+}
+
+string16 AppShortcutLauncherItemController::GetTitle() {
+ return GetAppTitle();
+}
+
+bool AppShortcutLauncherItemController::HasWindow(aura::Window* window) const {
+ std::vector<content::WebContents*> content =
+ app_controller_->GetV1ApplicationsFromAppId(app_id());
+ for (size_t i = 0; i < content.size(); i++) {
+ Browser* browser = chrome::FindBrowserWithWebContents(content[i]);
+ if (browser && browser->window()->GetNativeWindow() == window)
+ return true;
+ }
+ return false;
+}
+
+bool AppShortcutLauncherItemController::IsOpen() const {
+ return !app_controller_->GetV1ApplicationsFromAppId(app_id()).empty();
+}
+
+void AppShortcutLauncherItemController::Launch(int event_flags) {
+ app_controller_->LaunchApp(app_id(), event_flags);
+}
+
+void AppShortcutLauncherItemController::Activate() {
+ std::vector<content::WebContents*> content =
+ app_controller_->GetV1ApplicationsFromAppId(app_id());
+ if (content.empty()) {
+ Launch(ui::EF_NONE);
+ return;
+ }
+ Browser* browser = chrome::FindBrowserWithWebContents(content[0]);
+ TabStripModel* tab_strip = browser->tab_strip_model();
+ int index = tab_strip->GetIndexOfWebContents(content[0]);
+ DCHECK_NE(TabStripModel::kNoTab, index);
+ tab_strip->ActivateTabAt(index, false);
+ browser->window()->Show();
+ ash::wm::ActivateWindow(browser->window()->GetNativeWindow());
+}
+
+void AppShortcutLauncherItemController::Close() {
+ // Close all running 'programs' of this type.
+ std::vector<content::WebContents*> content =
+ app_controller_->GetV1ApplicationsFromAppId(app_id());
+ for (size_t i = 0; i < content.size(); i++) {
+ Browser* browser = chrome::FindBrowserWithWebContents(content[i]);
+ if (!browser)
+ continue;
+ TabStripModel* tab_strip = browser->tab_strip_model();
+ int index = tab_strip->GetIndexOfWebContents(content[i]);
+ DCHECK(index != TabStripModel::kNoTab);
+ tab_strip->CloseWebContentsAt(index, TabStripModel::CLOSE_NONE);
+ }
+}
+
+void AppShortcutLauncherItemController::Clicked() {
+ Activate();
+}
+
+void AppShortcutLauncherItemController::OnRemoved() {
+ // AppShortcutLauncherItemController is unowned; delete on removal.
+ delete this;
+}
+
+void AppShortcutLauncherItemController::LauncherItemChanged(
+ int model_index,
+ const ash::LauncherItem& old_item) {
+}
+
+ChromeLauncherAppMenuItems*
+AppShortcutLauncherItemController::GetApplicationList() {
+ ChromeLauncherAppMenuItems* items = new ChromeLauncherAppMenuItems;
+ // Add the application name to the menu.
+ items->push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL));
+
+ std::vector<content::WebContents*> content_list =
+ GetRunningApplications();
+
+ for (size_t i = 0; i < content_list.size(); i++) {
+ content::WebContents* web_contents = content_list[i];
+ // Get the icon.
+ FaviconTabHelper* favicon_tab_helper =
+ FaviconTabHelper::FromWebContents(web_contents);
+ gfx::Image app_icon = favicon_tab_helper->GetFavicon();
+ items->push_back(new ChromeLauncherAppMenuItemTab(
+ web_contents->GetTitle(),
+ app_icon.IsEmpty() ? NULL : &app_icon,
+ web_contents));
+ }
+ return items;
+}
+
+std::vector<content::WebContents*>
+AppShortcutLauncherItemController::GetRunningApplications() {
+ std::vector<content::WebContents*> items;
+
+ URLPattern refocus_pattern(URLPattern::SCHEME_ALL);
+ refocus_pattern.SetMatchAllURLs(true);
+
+ if (!refocus_url_.is_empty()) {
+ refocus_pattern.SetMatchAllURLs(false);
+ refocus_pattern.Parse(refocus_url_.spec());
+ }
+
+ for (BrowserList::const_reverse_iterator it =
+ BrowserList::begin_last_active();
+ it != BrowserList::end_last_active(); ++it) {
+ Browser* browser = *it;
+ TabStripModel* tab_strip = browser->tab_strip_model();
+ // We start to enumerate from the active index.
+ int active_index = tab_strip->active_index();
+ for (int index = 0; index < tab_strip->count(); index++) {
+ content::WebContents* web_contents = tab_strip->GetWebContentsAt(
+ (index + active_index) % tab_strip->count());
+ const GURL tab_url = web_contents->GetURL();
+ // The following cases are a successful application identification:
+ // a.) There is a refocus pattern given and it matches.
+ // or
+ // b.) The tab was launched as an app of the searched type AND
+ // either there is no refocus pattern or the url matches it.
+ // This is needed since a V1 applications can change the URL over
+ // time, and might therefore loose it's "app" status.
+ if (refocus_pattern.MatchesURL(tab_url) &&
+ (!refocus_pattern.match_all_urls() ||
+ launcher_controller()->GetPerAppInterface()->
+ IsWebContentHandledByApplication(web_contents, app_id())))
+ items.push_back(web_contents);
+ }
+ }
+ return items;
+}
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
new file mode 100644
index 0000000..82bdaed
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 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_ASH_LAUNCHER_APP_SHORTCUT_LAUNCHER_ITEM_CONTROLLER_H_
+#define CHROME_BROWSER_UI_ASH_LAUNCHER_APP_SHORTCUT_LAUNCHER_ITEM_CONTROLLER_H_
+
+#include <string>
+
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
+
+namespace aura {
+class Window;
+}
+
+class ChromeLauncherController;
+
+// Item controller for an app shortcut. Shortcuts track app and launcher ids,
+// but do not have any associated windows (opening a shortcut will replace the
+// item with the appropriate LauncherItemController type).
+class AppShortcutLauncherItemController : public LauncherItemController {
+ public:
+ AppShortcutLauncherItemController(const std::string& app_id,
+ ChromeLauncherControllerPerApp* controller);
+
+ virtual ~AppShortcutLauncherItemController();
+
+ // LauncherItemController overrides:
+ virtual string16 GetTitle() OVERRIDE;
+ virtual bool HasWindow(aura::Window* window) const OVERRIDE;
+ virtual bool IsOpen() const OVERRIDE;
+ virtual void Launch(int event_flags) OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void Clicked() OVERRIDE;
+ virtual void OnRemoved() OVERRIDE;
+ virtual void LauncherItemChanged(
+ int model_index,
+ const ash::LauncherItem& old_item) OVERRIDE;
+ virtual ChromeLauncherAppMenuItems* GetApplicationList() OVERRIDE;
+ std::vector<content::WebContents*> GetRunningApplications();
+
+ // Stores the optional refocus url pattern for this item.
+ const GURL& refocus_url() const { return refocus_url_; }
+ void set_refocus_url(const GURL& refocus_url) { refocus_url_ = refocus_url; }
+
+ private:
+ GURL refocus_url_;
+ ChromeLauncherControllerPerApp* app_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppShortcutLauncherItemController);
+};
+
+#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_APP_SHORTCUT_LAUNCHER_ITEM_CONTROLLER_H_
diff --git a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.cc
index 8e99060..67a4107 100644
--- a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/web_applications/web_app.h"
@@ -160,12 +161,19 @@ void BrowserLauncherItemController::OnRemoved() {
void BrowserLauncherItemController::LauncherItemChanged(
int index,
const ash::LauncherItem& old_item) {
- if (launcher_model()->items()[index].status == ash::STATUS_ACTIVE &&
+ if (!launcher_controller()->GetPerAppInterface() &&
+ launcher_model()->items()[index].status == ash::STATUS_ACTIVE &&
old_item.status == ash::STATUS_RUNNING) {
Activate();
}
}
+ChromeLauncherAppMenuItems*
+BrowserLauncherItemController::GetApplicationList() {
+ // This will never be called and the entire class will go away.
+ return new ChromeLauncherAppMenuItems;
+}
+
void BrowserLauncherItemController::ActiveTabChanged(
content::WebContents* old_contents,
content::WebContents* new_contents,
@@ -230,6 +238,9 @@ void BrowserLauncherItemController::OnWindowPropertyChanged(
}
void BrowserLauncherItemController::UpdateItemStatus() {
+ if (launcher_controller()->GetPerAppInterface())
+ return;
+
ash::LauncherItemStatus status;
if (ash::wm::IsActiveWindow(window_)) {
// Clear attention state if active.
@@ -245,6 +256,9 @@ void BrowserLauncherItemController::UpdateItemStatus() {
}
void BrowserLauncherItemController::UpdateLauncher(content::WebContents* tab) {
+ if (launcher_controller()->GetPerAppInterface())
+ return;
+
if (type() == TYPE_APP_PANEL)
return; // Maintained entirely by ChromeLauncherController.
@@ -292,7 +306,8 @@ void BrowserLauncherItemController::UpdateLauncher(content::WebContents* tab) {
void BrowserLauncherItemController::UpdateAppState(content::WebContents* tab) {
ChromeLauncherController::AppState app_state;
- if (tab_model_->GetIndexOfWebContents(tab) == TabStripModel::kNoTab) {
+ if (!launcher_controller()->GetPerAppInterface() &&
+ tab_model_->GetIndexOfWebContents(tab) == TabStripModel::kNoTab) {
app_state = ChromeLauncherController::APP_STATE_REMOVED;
} else if (tab_model_->GetActiveWebContents() == tab) {
if (ash::wm::IsActiveWindow(window_))
diff --git a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h
index 6c71283..dde726c 100644
--- a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h
@@ -80,6 +80,7 @@ class BrowserLauncherItemController : public LauncherItemController,
virtual void OnRemoved() OVERRIDE;
virtual void LauncherItemChanged(int index,
const ash::LauncherItem& old_item) OVERRIDE;
+ virtual ChromeLauncherAppMenuItems* GetApplicationList() OVERRIDE;
// TabStripModel overrides:
virtual void ActiveTabChanged(content::WebContents* old_contents,
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.cc
new file mode 100644
index 0000000..fed2925
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 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/ash/launcher/chrome_launcher_app_menu_item.h"
+
+ChromeLauncherAppMenuItem::ChromeLauncherAppMenuItem(const string16 title,
+ const gfx::Image* icon)
+ : title_(title),
+ icon_(icon ? gfx::Image(*icon) : gfx::Image()) {
+}
+
+ChromeLauncherAppMenuItem::~ChromeLauncherAppMenuItem() {
+}
+
+bool ChromeLauncherAppMenuItem::IsEnabled() const {
+ return false;
+}
+
+void ChromeLauncherAppMenuItem::Execute() {
+}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h
new file mode 100644
index 0000000..a488ad8
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 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_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_H_
+#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_H_
+
+#include "base/string16.h"
+#include "ui/gfx/image/image.h"
+
+// A description for a menu item. It contains the menu item description as well
+// as the function which gets executed upon menu item click.
+class ChromeLauncherAppMenuItem {
+ public:
+ ChromeLauncherAppMenuItem(const string16 title, const gfx::Image* icon);
+
+ virtual ~ChromeLauncherAppMenuItem();
+
+ // Retrieves the title for this menu option.
+ const string16& title() const { return title_; }
+
+ // Retrieves the icon for this menu option.
+ const gfx::Image& icon() const { return icon_; }
+
+ // Returns true if item is enabled.
+ virtual bool IsEnabled() const;
+
+ // Executes the option.
+ virtual void Execute();
+
+ private:
+ const string16 title_;
+ const gfx::Image icon_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeLauncherAppMenuItem);
+};
+#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
new file mode 100644
index 0000000..e59b9de
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 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/ash/launcher/chrome_launcher_app_menu_item_browser.h"
+
+#include "ash/wm/window_util.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/notification_service.h"
+
+ChromeLauncherAppMenuItemBrowser::ChromeLauncherAppMenuItemBrowser(
+ const string16 title,
+ const gfx::Image* icon,
+ Browser* browser)
+ : ChromeLauncherAppMenuItem(title, icon),
+ browser_(browser) {
+ registrar_.Add(this,
+ chrome::NOTIFICATION_BROWSER_CLOSING,
+ content::Source<Browser>(browser));
+}
+
+bool ChromeLauncherAppMenuItemBrowser::IsEnabled() const {
+ return true;
+}
+
+void ChromeLauncherAppMenuItemBrowser::Execute() {
+ if (browser_) {
+ browser_->window()->Show();
+ ash::wm::ActivateWindow(browser_->window()->GetNativeWindow());
+ }
+}
+
+void ChromeLauncherAppMenuItemBrowser::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case chrome::NOTIFICATION_BROWSER_CLOSING:
+ DCHECK_EQ(browser_, content::Source<Browser>(source).ptr());
+ browser_ = NULL;
+ break;
+
+ default:
+ NOTREACHED();
+ }
+}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h
new file mode 100644
index 0000000..274d728
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 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_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_BROWSER_H_
+#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_BROWSER_H_
+
+#include "base/values.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+class Browser;
+
+// A menu item controller for a running browser. It gets created when an
+// application list gets created. It's main purpose is to add the activation
+// method to the |ChromeLauncherAppMenuItem| class.
+class ChromeLauncherAppMenuItemBrowser : public content::NotificationObserver,
+ public ChromeLauncherAppMenuItem {
+ public:
+ ChromeLauncherAppMenuItemBrowser(const string16 title,
+ const gfx::Image* icon,
+ Browser* browser);
+ virtual bool IsEnabled() const OVERRIDE;
+ virtual void Execute() OVERRIDE;
+
+ private:
+ // content::NotificationObserver.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // The browser which is associated which this item.
+ Browser* browser_;
+
+ content::NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeLauncherAppMenuItemBrowser);
+};
+
+#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_BROWSER_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
new file mode 100644
index 0000000..dcdcf7b
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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/ash/launcher/chrome_launcher_app_menu_item_tab.h"
+
+#include "ash/wm/window_util.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+
+ChromeLauncherAppMenuItemTab::ChromeLauncherAppMenuItemTab(
+ const string16 title,
+ const gfx::Image* icon,
+ content::WebContents* content)
+ : ChromeLauncherAppMenuItem(title, icon),
+ content::WebContentsObserver(content) {
+}
+
+bool ChromeLauncherAppMenuItemTab::IsEnabled() const {
+ return true;
+}
+
+void ChromeLauncherAppMenuItemTab::Execute() {
+ if (!web_contents())
+ return;
+ Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
+ if (!browser)
+ return;
+ TabStripModel* tab_strip = browser->tab_strip_model();
+ int index = tab_strip->GetIndexOfWebContents(web_contents());
+ DCHECK(index != TabStripModel::kNoTab);
+ tab_strip->ActivateTabAt(index, false);
+ browser->window()->Show();
+ // Need this check to prevent unit tests from crashing.
+ if (browser->window()->GetNativeWindow())
+ ash::wm::ActivateWindow(browser->window()->GetNativeWindow());
+}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h
new file mode 100644
index 0000000..403a78c
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 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_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_TAB_H_
+#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_TAB_H_
+
+#include "base/string16.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content{
+class WebContents;
+}
+
+class TabStripModel;
+
+// A menu item controller for a running browser tab. It gets created when an
+// application/tab list gets created. It's main purpose is to add the
+// activation method to the |ChromeLauncherAppMenuItem| class.
+class ChromeLauncherAppMenuItemTab
+ : public ChromeLauncherAppMenuItem,
+ public content::WebContentsObserver {
+ public:
+ ChromeLauncherAppMenuItemTab(const string16 title,
+ const gfx::Image* icon,
+ content::WebContents* content);
+ virtual bool IsEnabled() const OVERRIDE;
+ virtual void Execute() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChromeLauncherAppMenuItemTab);
+};
+
+#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_TAB_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc
new file mode 100644
index 0000000..2cc5fc7
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 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/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
+
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+
+ChromeLauncherAppMenuItemV2App::ChromeLauncherAppMenuItemV2App(
+ const string16 title,
+ const gfx::Image* icon,
+ const std::string& app_id,
+ ChromeLauncherControllerPerApp* launcher_controller,
+ int app_index)
+ : ChromeLauncherAppMenuItem(title, icon),
+ launcher_controller_(launcher_controller),
+ app_id_(app_id),
+ app_index_(app_index) {
+}
+
+bool ChromeLauncherAppMenuItemV2App::IsEnabled() const {
+ return true;
+}
+
+void ChromeLauncherAppMenuItemV2App::Execute() {
+ // Note: If the application item did go away since the menu was created,
+ // The controller will take care of it.
+ launcher_controller_->ActivateShellApp(app_id_, app_index_);
+}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h
new file mode 100644
index 0000000..2c095a2
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 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_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_V2APP_H_
+#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_V2APP_H_
+
+#include <string>
+
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
+
+namespace gfx {
+class image;
+}
+
+class ChromeLauncherControllerPerApp;
+
+// A menu item controller for a running V2 application. It gets created when an
+// application list gets created. It's main purpose is to add the activation
+// method to the |ChromeLauncherAppMenuItem| class.
+class ChromeLauncherAppMenuItemV2App : public ChromeLauncherAppMenuItem {
+ public:
+ ChromeLauncherAppMenuItemV2App(
+ const string16 title,
+ const gfx::Image* icon,
+ const std::string& app_id,
+ ChromeLauncherControllerPerApp* launcher_controller,
+ int app_index);
+ virtual bool IsEnabled() const OVERRIDE;
+ virtual void Execute() OVERRIDE;
+
+ private:
+ // The owning class which can be used to validate the controller.
+ ChromeLauncherControllerPerApp* launcher_controller_;
+
+ // The application ID.
+ const std::string app_id_;
+
+ // The index for the given application.
+ const int app_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeLauncherAppMenuItemV2App);
+};
+
+#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_APP_MENU_ITEM_V2APP_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index da647f4..6a7ee2e 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -21,9 +21,9 @@ ChromeLauncherController* ChromeLauncherController::CreateInstance(
// can be re-created.
if (CommandLine::ForCurrentProcess()->HasSwitch(
ash::switches::kAshEnablePerAppLauncher))
- instance_ = new ChromeLauncherControllerPerBrowser(profile, model);
- else
instance_ = new ChromeLauncherControllerPerApp(profile, model);
+ else
+ instance_ = new ChromeLauncherControllerPerBrowser(profile, model);
return instance_;
}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index 39f4317..d54faa3 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -10,11 +10,14 @@
#include "ash/launcher/launcher_delegate.h"
#include "ash/launcher/launcher_types.h"
#include "ash/shelf_types.h"
+#include "base/memory/scoped_vector.h"
#include "chrome/browser/extensions/extension_prefs.h"
class BrowserLauncherItemControllerTest;
class LauncherItemController;
class Profile;
+class ChromeLauncherAppMenuItem;
+class ChromeLauncherControllerPerApp;
namespace ash {
class LauncherModel;
@@ -29,6 +32,9 @@ namespace content {
class WebContents;
}
+// A list of the elements which makes up a simple menu description.
+typedef ScopedVector<ChromeLauncherAppMenuItem> ChromeLauncherAppMenuItems;
+
// ChromeLauncherController manages the launcher items needed for content
// windows. Launcher items have a type, an optional app id, and a controller.
// ChromeLauncherController will furthermore create the particular
@@ -90,6 +96,11 @@ class ChromeLauncherController
// Initializes this ChromeLauncherController.
virtual void Init() = 0;
+ // Returns the new per application interface of the given launcher. If it is
+ // a per browser (old) controller, it will return NULL;
+ // TODO(skuhne): Remove when we rip out the old launcher.
+ virtual ChromeLauncherControllerPerApp* GetPerAppInterface() = 0;
+
// Creates an instance.
static ChromeLauncherController* CreateInstance(Profile* profile,
ash::LauncherModel* model);
@@ -242,7 +253,8 @@ class ChromeLauncherController
AppState app_state) = 0;
// Limits application refocusing to urls that match |url| for |id|.
- virtual void SetRefocusURLPattern(ash::LauncherID id, const GURL& url) = 0;
+ virtual void SetRefocusURLPatternForTest(ash::LauncherID id,
+ const GURL& url) = 0;
// Returns the extension identified by |app_id|.
virtual const extensions::Extension* GetExtensionForAppID(
@@ -256,6 +268,8 @@ class ChromeLauncherController
virtual string16 GetTitle(const ash::LauncherItem& item) OVERRIDE = 0;
virtual ui::MenuModel* CreateContextMenu(
const ash::LauncherItem& item, aura::RootWindow* root) OVERRIDE = 0;
+ virtual ui::MenuModel* CreateApplicationMenu(
+ const ash::LauncherItem& item) OVERRIDE = 0;
virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE = 0;
virtual bool IsDraggable(const ash::LauncherItem& item) OVERRIDE = 0;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index 6814fe4..6f6bf4d 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -676,7 +676,7 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, RefocusFilter) {
EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
WebContents* first_tab = tab_strip->GetActiveWebContents();
- controller->SetRefocusURLPattern(
+ controller->SetRefocusURLPatternForTest(
shortcut_id, GURL("http://www.example.com/path1/*"));
// Create new tab owned by app.
ui_test_utils::NavigateToURLWithDisposition(
@@ -711,7 +711,7 @@ IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, RefocusFilterLaunch) {
TabStripModel* tab_strip = browser()->tab_strip_model();
int tab_count = tab_strip->count();
ash::LauncherID shortcut_id = CreateShortcut("app1");
- controller->SetRefocusURLPattern(
+ controller->SetRefocusURLPatternForTest(
shortcut_id, GURL("http://www.example.com/path1/*"));
// Create new tab owned by app.
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc
index 3bd4f49..bd2cf58 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc
@@ -14,6 +14,7 @@
#include "base/values.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/favicon/favicon_tab_helper.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
@@ -22,14 +23,20 @@
#include "chrome/browser/ui/ash/app_sync_ui_state.h"
#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
#include "chrome/browser/ui/ash/extension_utils.h"
+#include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
#include "chrome/browser/ui/ash/launcher/launcher_app_icon_loader.h"
#include "chrome/browser/ui/ash/launcher/launcher_app_tab_helper.h"
+#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
#include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
+#include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -44,81 +51,20 @@
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "extensions/common/url_pattern.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/base/l10n/l10n_util.h"
-using content::WebContents;
-using extensions::Extension;
-
-namespace {
-
-// Item controller for an app shortcut. Shortcuts track app and launcher ids,
-// but do not have any associated windows (opening a shortcut will replace the
-// item with the appropriate LauncherItemController type).
-class AppShortcutLauncherItemController : public LauncherItemController {
- public:
- AppShortcutLauncherItemController(const std::string& app_id,
- ChromeLauncherControllerPerApp* controller)
- : LauncherItemController(TYPE_SHORTCUT, app_id, controller) {
- // Google Drive should just refocus to it's main app UI.
- // TODO(davemoore): Generalize this for other applications.
- if (app_id == "apdfllckaahabafndbhieahigkjlhalf") {
- const Extension* extension =
- launcher_controller()->GetExtensionForAppID(app_id);
- refocus_url_ = GURL(extension->launch_web_url() + "*");
- }
- }
-
- virtual ~AppShortcutLauncherItemController() {}
-
- // LauncherItemController overrides:
- virtual string16 GetTitle() OVERRIDE {
- return GetAppTitle();
- }
-
- virtual bool HasWindow(aura::Window* window) const OVERRIDE {
- return false;
- }
-
- virtual bool IsOpen() const OVERRIDE {
- return false;
- }
-
- virtual void Launch(int event_flags) OVERRIDE {
- launcher_controller()->LaunchApp(app_id(), event_flags);
- }
-
- virtual void Activate() OVERRIDE {
- launcher_controller()->ActivateApp(app_id(), ui::EF_NONE);
- }
-
- virtual void Close() OVERRIDE {
- // TODO: maybe should treat as unpin?
- }
- virtual void Clicked() OVERRIDE {
- Activate();
- }
-
- virtual void OnRemoved() OVERRIDE {
- // AppShortcutLauncherItemController is unowned; delete on removal.
- delete this;
- }
-
- virtual void LauncherItemChanged(
- int model_index,
- const ash::LauncherItem& old_item) OVERRIDE {
- }
+using extensions::Extension;
+using content::WebContents;
- // Stores the optional refocus url pattern for this item.
- const GURL& refocus_url() const { return refocus_url_; }
- void set_refocus_url(const GURL& refocus_url) { refocus_url_ = refocus_url; }
+// TODO(skuhne): Incognito markers need to be added with the advanced menu.
- private:
- GURL refocus_url_;
- DISALLOW_COPY_AND_ASSIGN(AppShortcutLauncherItemController);
-};
+namespace {
std::string GetPrefKeyForRootWindow(aura::RootWindow* root_window) {
gfx::Display display = gfx::Screen::GetScreenFor(
@@ -198,8 +144,6 @@ void MaybePropagatePrefToLocal(PrefService* pref_service,
} // namespace
-// ChromeLauncherControllerPerApp ---------------------------------------------
-
ChromeLauncherControllerPerApp::ChromeLauncherControllerPerApp(
Profile* profile,
ash::LauncherModel* model)
@@ -252,7 +196,14 @@ ChromeLauncherControllerPerApp::~ChromeLauncherControllerPerApp() {
for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
i != id_to_item_controller_map_.end(); ++i) {
i->second->OnRemoved();
- model_->RemoveItemAt(model_->ItemIndexByID(i->first));
+ // TODO(skuhne): After getting rid of the old launcher, get also rid of the
+ // BrowserLauncherItemController (since it is only used for activation
+ // tracking at that point.
+ int index = model_->ItemIndexByID(i->first);
+ // A "browser proxy" is not known to the model and this removal does
+ // therefore not need to be propagated to the model.
+ if (index != -1)
+ model_->RemoveItemAt(index);
}
if (ash::Shell::HasInstance())
@@ -283,21 +234,27 @@ void ChromeLauncherControllerPerApp::Init() {
}
}
+ChromeLauncherControllerPerApp*
+ChromeLauncherControllerPerApp::GetPerAppInterface() {
+ return NULL;
+}
+
ash::LauncherID ChromeLauncherControllerPerApp::CreateTabbedLauncherItem(
LauncherItemController* controller,
IncognitoState is_incognito,
ash::LauncherItemStatus status) {
- ash::LauncherID id = model_->next_id();
+ // We are using the launcher id only for addressing purposes to make the
+ // old launcher model happy. The |model_| does neither know anything about
+ // the browser proxy nor ever use it. As such the controller will only be
+ // used for event tracking.
+ ash::LauncherID id = model_->reserve_external_id();
DCHECK(!HasItemController(id));
+ // TODO(skuhne): We should get rid of this entire controller and make sure
+ // that we add only some general observers to make sure that we get the
+ // state changes.
DCHECK(controller);
id_to_item_controller_map_[id] = controller;
controller->set_launcher_id(id);
-
- ash::LauncherItem item;
- item.type = ash::TYPE_TABBED;
- item.is_incognito = (is_incognito == STATE_INCOGNITO);
- item.status = status;
- model_->Add(item);
return id;
}
@@ -318,6 +275,32 @@ void ChromeLauncherControllerPerApp::SetItemStatus(
ash::LauncherItem item = model_->items()[index];
item.status = status;
model_->Set(index, item);
+
+ if (model_->items()[index].type == ash::TYPE_BROWSER_SHORTCUT)
+ return;
+
+ // Determine the new browser's active state and change if necessary.
+ int browser_index = -1;
+ for (size_t index = 0; index < model_->items().size() && browser_index == -1;
+ index++) {
+ if (model_->items()[index].type == ash::TYPE_BROWSER_SHORTCUT)
+ browser_index = index;
+ }
+ DCHECK(browser_index >= 0);
+ ash::LauncherItem browser_item = model_->items()[browser_index];
+ ash::LauncherItemStatus browser_status = browser_item.status;
+ // See if the active window is a browser.
+ if (chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow())) {
+ browser_status = ash::STATUS_ACTIVE;
+ } else if (!BrowserList::empty()) {
+ browser_status = ash::STATUS_RUNNING;
+ } else {
+ browser_status = ash::STATUS_CLOSED;
+ }
+ if (browser_status != browser_item.status) {
+ browser_item.status = browser_status;
+ model_->Set(browser_index, browser_item);
+ }
}
void ChromeLauncherControllerPerApp::SetItemController(
@@ -345,22 +328,6 @@ void ChromeLauncherControllerPerApp::CloseLauncherItem(ash::LauncherID id) {
}
}
-void ChromeLauncherControllerPerApp::Unpin(ash::LauncherID id) {
- DCHECK(HasItemController(id));
-
- LauncherItemController* controller = id_to_item_controller_map_[id];
- if (controller->type() == LauncherItemController::TYPE_APP) {
- int index = model_->ItemIndexByID(id);
- ash::LauncherItem item = model_->items()[index];
- item.type = ash::TYPE_PLATFORM_APP;
- model_->Set(index, item);
- } else {
- LauncherItemClosed(id);
- }
- if (CanPin())
- PersistPinnedState();
-}
-
void ChromeLauncherControllerPerApp::Pin(ash::LauncherID id) {
DCHECK(HasItemController(id));
@@ -377,6 +344,22 @@ void ChromeLauncherControllerPerApp::Pin(ash::LauncherID id) {
PersistPinnedState();
}
+void ChromeLauncherControllerPerApp::Unpin(ash::LauncherID id) {
+ DCHECK(HasItemController(id));
+
+ LauncherItemController* controller = id_to_item_controller_map_[id];
+ if (controller->type() == LauncherItemController::TYPE_APP) {
+ int index = model_->ItemIndexByID(id);
+ ash::LauncherItem item = model_->items()[index];
+ item.type = ash::TYPE_PLATFORM_APP;
+ model_->Set(index, item);
+ } else {
+ LauncherItemClosed(id);
+ }
+ if (CanPin())
+ PersistPinnedState();
+}
+
bool ChromeLauncherControllerPerApp::IsPinned(ash::LauncherID id) {
int index = model_->ItemIndexByID(id);
ash::LauncherItemType type = model_->items()[index].type;
@@ -449,47 +432,13 @@ void ChromeLauncherControllerPerApp::ActivateApp(const std::string& app_id,
// If there is an existing non-shortcut controller for this app, open it.
ash::LauncherID id = GetLauncherIDForAppID(app_id);
- URLPattern refocus_pattern(URLPattern::SCHEME_ALL);
- refocus_pattern.SetMatchAllURLs(true);
-
- if (id > 0) {
- LauncherItemController* controller = id_to_item_controller_map_[id];
- if (controller->type() != LauncherItemController::TYPE_SHORTCUT) {
- controller->Activate();
- return;
- }
-
- AppShortcutLauncherItemController* app_controller =
- static_cast<AppShortcutLauncherItemController*>(controller);
- const GURL refocus_url = app_controller->refocus_url();
- if (!refocus_url.is_empty())
- refocus_pattern.Parse(refocus_url.spec());
- }
-
- // Check if there are any open tabs for this app.
- AppIDToWebContentsListMap::iterator app_i =
- app_id_to_web_contents_list_.find(app_id);
- if (app_i != app_id_to_web_contents_list_.end()) {
- for (WebContentsList::iterator tab_i = app_i->second.begin();
- tab_i != app_i->second.end();
- ++tab_i) {
- WebContents* tab = *tab_i;
- const GURL tab_url = tab->GetURL();
- if (refocus_pattern.MatchesURL(tab_url)) {
- Browser* browser = chrome::FindBrowserWithWebContents(tab);
- TabStripModel* tab_strip = browser->tab_strip_model();
- int index = tab_strip->GetIndexOfWebContents(tab);
- DCHECK_NE(TabStripModel::kNoTab, index);
- tab_strip->ActivateTabAt(index, false);
- browser->window()->Show();
- ash::wm::ActivateWindow(browser->window()->GetNativeWindow());
- return;
- }
- }
- }
+ // Only pinned applications will be handled.
+ if (!id)
+ return;
- LaunchApp(app_id, event_flags);
+ LauncherItemController* controller = id_to_item_controller_map_[id];
+ controller->Activate();
}
extensions::ExtensionPrefs::LaunchType
@@ -585,7 +534,7 @@ void ChromeLauncherControllerPerApp::SetLaunchType(
if (!HasItemController(id))
return;
- return profile_->GetExtensionService()->extension_prefs()->SetLaunchType(
+ profile_->GetExtensionService()->extension_prefs()->SetLaunchType(
id_to_item_controller_map_[id]->app_id(), launch_type);
}
@@ -616,6 +565,48 @@ bool ChromeLauncherControllerPerApp::CanPin() const {
return pref && pref->IsUserModifiable();
}
+void ChromeLauncherControllerPerApp::PersistPinnedState() {
+ // It is a coding error to call PersistPinnedState() if the pinned apps are
+ // not user-editable. The code should check earlier and not perform any
+ // modification actions that trigger persisting the state.
+ if (!CanPin()) {
+ NOTREACHED() << "Can't pin but pinned state being updated";
+ return;
+ }
+
+ // Mutating kPinnedLauncherApps is going to notify us and trigger us to
+ // process the change. We don't want that to happen so remove ourselves as a
+ // listener.
+ pref_change_registrar_.Remove(prefs::kPinnedLauncherApps);
+ {
+ ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
+ updater->Clear();
+ for (size_t i = 0; i < model_->items().size(); ++i) {
+ if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) {
+ ash::LauncherID id = model_->items()[i].id;
+ if (HasItemController(id) && IsPinned(id)) {
+ base::DictionaryValue* app_value = ash::CreateAppDict(
+ id_to_item_controller_map_[id]->app_id());
+ if (app_value)
+ updater->Append(app_value);
+ }
+ }
+ }
+ }
+ pref_change_registrar_.Add(
+ prefs::kPinnedLauncherApps,
+ base::Bind(&ChromeLauncherControllerPerApp::UpdateAppLaunchersFromPref,
+ base::Unretained(this)));
+}
+
+ash::LauncherModel* ChromeLauncherControllerPerApp::model() {
+ return model_;
+}
+
+Profile* ChromeLauncherControllerPerApp::profile() {
+ return profile_;
+}
+
ash::ShelfAutoHideBehavior
ChromeLauncherControllerPerApp::GetShelfAutoHideBehavior(
aura::RootWindow* root_window) const {
@@ -664,7 +655,7 @@ void ChromeLauncherControllerPerApp::RemoveTabFromRunningApp(
app_id_to_web_contents_list_.erase(i_app_id);
i_app_id = app_id_to_web_contents_list_.end();
ash::LauncherID id = GetLauncherIDForAppID(app_id);
- if (id > 0)
+ if (id)
SetItemStatus(id, ash::STATUS_CLOSED);
}
}
@@ -709,7 +700,7 @@ void ChromeLauncherControllerPerApp::UpdateAppState(
tab_list.push_front(contents);
}
ash::LauncherID id = GetLauncherIDForAppID(app_id);
- if (id > 0) {
+ if (id) {
// If the window is active, mark the app as active.
SetItemStatus(id, app_state == APP_STATE_WINDOW_ACTIVE ?
ash::STATUS_ACTIVE : ash::STATUS_RUNNING);
@@ -717,7 +708,7 @@ void ChromeLauncherControllerPerApp::UpdateAppState(
}
}
-void ChromeLauncherControllerPerApp::SetRefocusURLPattern(
+void ChromeLauncherControllerPerApp::SetRefocusURLPatternForTest(
ash::LauncherID id,
const GURL& url) {
DCHECK(HasItemController(id));
@@ -786,6 +777,11 @@ ui::MenuModel* ChromeLauncherControllerPerApp::CreateContextMenu(
return new LauncherContextMenu(this, &item, root_window);
}
+ui::MenuModel* ChromeLauncherControllerPerApp::CreateApplicationMenu(
+ const ash::LauncherItem& item) {
+ return new LauncherApplicationMenuItemModel(GetApplicationList(item));
+}
+
ash::LauncherID ChromeLauncherControllerPerApp::GetIDByWindow(
aura::Window* window) {
for (IDToItemControllerMap::const_iterator i =
@@ -822,6 +818,15 @@ void ChromeLauncherControllerPerApp::LauncherItemChanged(
int index,
const ash::LauncherItem& old_item) {
ash::LauncherID id = model_->items()[index].id;
+
+ // The browser item does not have a controller since it was created by the
+ // |LauncherModel|.
+ // TODO(skuhne): When removing the old launcher, this should get changed as
+ // well.
+ if (model_->items()[index].type == ash::TYPE_BROWSER_SHORTCUT)
+ return;
+
+ DCHECK(HasItemController(id));
id_to_item_controller_map_[id]->LauncherItemChanged(index, old_item);
}
@@ -892,46 +897,82 @@ void ChromeLauncherControllerPerApp::OnAppSyncUIStatusChanged() {
model_->SetStatus(ash::LauncherModel::STATUS_NORMAL);
}
-void ChromeLauncherControllerPerApp::PersistPinnedState() {
- // It is a coding error to call PersistPinnedState() if the pinned apps are
- // not user-editable. The code should check earlier and not perform any
- // modification actions that trigger persisting the state.
- if (!CanPin()) {
- NOTREACHED() << "Can't pin but pinned state being updated";
- return;
+ChromeLauncherAppMenuItems* ChromeLauncherControllerPerApp::GetApplicationList(
+ const ash::LauncherItem& item) {
+ if (item.type == ash::TYPE_BROWSER_SHORTCUT)
+ return GetBrowserApplicationList();
+
+ std::string app_id = id_to_item_controller_map_[item.id]->app_id();
+ ash::LauncherID id = GetLauncherIDForAppID(app_id);
+
+ // If there is no such an item pinned to the launcher, no menu gets created.
+ DCHECK(id);
+ DCHECK(id_to_item_controller_map_[id]);
+
+ return id_to_item_controller_map_[id]->GetApplicationList();
+}
+
+std::vector<content::WebContents*>
+ChromeLauncherControllerPerApp::GetV1ApplicationsFromAppId(
+ std::string app_id) {
+ ash::LauncherID id = GetLauncherIDForAppID(app_id);
+
+ // If there is no such an item pinned to the launcher, no menu gets created.
+ if (id) {
+ LauncherItemController* controller = id_to_item_controller_map_[id];
+ DCHECK(controller);
+ if (controller->type() == LauncherItemController::TYPE_SHORTCUT)
+ return GetV1ApplicationsFromController(controller);
}
+ return std::vector<content::WebContents*>();
+}
- // Mutating kPinnedLauncherApps is going to notify us and trigger us to
- // process the change. We don't want that to happen so remove ourselves as a
- // listener.
- pref_change_registrar_.Remove(prefs::kPinnedLauncherApps);
- {
- ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
- updater->Clear();
- for (size_t i = 0; i < model_->items().size(); ++i) {
- if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) {
- ash::LauncherID id = model_->items()[i].id;
- if (HasItemController(id) && IsPinned(id)) {
- base::DictionaryValue* app_value = ash::CreateAppDict(
- id_to_item_controller_map_[id]->app_id());
- if (app_value)
- updater->Append(app_value);
- }
- }
+void ChromeLauncherControllerPerApp::ActivateShellApp(
+ const std::string& app_id,
+ int index) {
+ ash::LauncherID id = GetLauncherIDForAppID(app_id);
+ if (id) {
+ LauncherItemController* controller = id_to_item_controller_map_[id];
+ if (controller->type() == LauncherItemController::TYPE_APP) {
+ ShellWindowLauncherItemController* shell_window_controller =
+ static_cast<ShellWindowLauncherItemController*>(controller);
+ shell_window_controller->ActivateIndexedApp(index);
}
}
- pref_change_registrar_.Add(
- prefs::kPinnedLauncherApps,
- base::Bind(&ChromeLauncherControllerPerApp::UpdateAppLaunchersFromPref,
- base::Unretained(this)));
}
-ash::LauncherModel* ChromeLauncherControllerPerApp::model() {
- return model_;
+bool ChromeLauncherControllerPerApp::IsWebContentHandledByApplication(
+ content::WebContents* web_contents,
+ const std::string& app_id) {
+ return ((web_contents_to_app_id_.find(web_contents) !=
+ web_contents_to_app_id_.end()) &&
+ (web_contents_to_app_id_[web_contents] == app_id));
}
-Profile* ChromeLauncherControllerPerApp::profile() {
- return profile_;
+ash::LauncherID ChromeLauncherControllerPerApp::CreateAppShortcutLauncherItem(
+ const std::string& app_id,
+ int index) {
+ AppShortcutLauncherItemController* controller =
+ new AppShortcutLauncherItemController(app_id, this);
+ ash::LauncherID launcher_id = InsertAppLauncherItem(
+ controller, app_id, ash::STATUS_CLOSED, index);
+ return launcher_id;
+}
+
+void ChromeLauncherControllerPerApp::SetAppTabHelperForTest(
+ AppTabHelper* helper) {
+ app_tab_helper_.reset(helper);
+}
+
+void ChromeLauncherControllerPerApp::SetAppIconLoaderForTest(
+ AppIconLoader* loader) {
+ app_icon_loader_.reset(loader);
+}
+
+const std::string&
+ChromeLauncherControllerPerApp::GetAppIdFromLauncherIdForTest(
+ ash::LauncherID id) {
+ return id_to_item_controller_map_[id]->app_id();
}
Profile* ChromeLauncherControllerPerApp::GetProfileForNewWindows() {
@@ -944,7 +985,11 @@ void ChromeLauncherControllerPerApp::LauncherItemClosed(ash::LauncherID id) {
app_icon_loader_->ClearImage(iter->second->app_id());
iter->second->OnRemoved();
id_to_item_controller_map_.erase(iter);
- model_->RemoveItemAt(model_->ItemIndexByID(id));
+ int index = model_->ItemIndexByID(id);
+ // A "browser proxy" is not known to the model and this removal does
+ // therefore not need to be propagated to the model.
+ if (index != -1)
+ model_->RemoveItemAt(index);
}
void ChromeLauncherControllerPerApp::DoPinAppWithID(
@@ -1160,28 +1205,36 @@ bool ChromeLauncherControllerPerApp::HasItemController(
id_to_item_controller_map_.end();
}
-ash::LauncherID ChromeLauncherControllerPerApp::CreateAppShortcutLauncherItem(
- const std::string& app_id,
- int index) {
- AppShortcutLauncherItemController* controller =
- new AppShortcutLauncherItemController(app_id, this);
- ash::LauncherID launcher_id = InsertAppLauncherItem(
- controller, app_id, ash::STATUS_CLOSED, index);
- return launcher_id;
-}
-
-void ChromeLauncherControllerPerApp::SetAppTabHelperForTest(
- AppTabHelper* helper) {
- app_tab_helper_.reset(helper);
-}
-
-void ChromeLauncherControllerPerApp::SetAppIconLoaderForTest(
- AppIconLoader* loader) {
- app_icon_loader_.reset(loader);
-}
-
-const std::string&
-ChromeLauncherControllerPerApp::GetAppIdFromLauncherIdForTest(
- ash::LauncherID id) {
- return id_to_item_controller_map_[id]->app_id();
+std::vector<content::WebContents*>
+ChromeLauncherControllerPerApp::GetV1ApplicationsFromController(
+ LauncherItemController* controller) {
+ DCHECK(controller->type() == LauncherItemController::TYPE_SHORTCUT);
+ AppShortcutLauncherItemController* app_controller =
+ static_cast<AppShortcutLauncherItemController*>(controller);
+ return app_controller->GetRunningApplications();
+}
+
+ChromeLauncherAppMenuItems*
+ChromeLauncherControllerPerApp::GetBrowserApplicationList() {
+ ChromeLauncherAppMenuItems* items = new ChromeLauncherAppMenuItems;
+ // Add the application name to the menu.
+ items->push_back(new ChromeLauncherAppMenuItem(
+ l10n_util::GetStringFUTF16(IDS_LAUNCHER_CHROME_BROWSER_NAME,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)), NULL));
+ int index = 1;
+ for (BrowserList::const_reverse_iterator it =
+ BrowserList::begin_last_active();
+ it != BrowserList::end_last_active(); ++it, ++index) {
+ Browser *browser = *it;
+ WebContents* web_contents = browser->tab_strip_model()->GetWebContentsAt(
+ browser->active_index());
+ FaviconTabHelper* favicon_tab_helper =
+ FaviconTabHelper::FromWebContents(web_contents);
+ gfx::Image app_icon = favicon_tab_helper->GetFavicon();
+ items->push_back(new ChromeLauncherAppMenuItemBrowser(
+ web_contents->GetTitle(),
+ app_icon.IsEmpty() ? NULL : &app_icon,
+ browser));
+ }
+ return items;
}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h
index 7288355..158d5a3 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h
@@ -8,6 +8,7 @@
#include <list>
#include <map>
#include <string>
+#include <vector>
#include "ash/launcher/launcher_model_observer.h"
#include "ash/launcher/launcher_types.h"
@@ -16,11 +17,14 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/prefs/public/pref_change_registrar.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/prefs/pref_service_observer.h"
#include "chrome/browser/ui/ash/app_sync_ui_state_observer.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
+#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "ui/aura/window_observer.h"
@@ -30,7 +34,7 @@ class Browser;
class BrowserLauncherItemControllerTest;
class LauncherItemController;
class Profile;
-class ShellWindowLauncherController;
+class TabContents;
namespace ash {
class LauncherModel;
@@ -69,6 +73,11 @@ class ChromeLauncherControllerPerApp
// Initializes this ChromeLauncherControllerPerApp.
virtual void Init() OVERRIDE;
+ // Returns the new per application interface of the given launcher. If it is
+ // a per browser (old) controller, it will return NULL;
+ // TODO(skuhne): Remove when we rip out the old launcher.
+ virtual ChromeLauncherControllerPerApp* GetPerAppInterface() OVERRIDE;
+
// Creates a new tabbed item on the launcher for |controller|.
virtual ash::LauncherID CreateTabbedLauncherItem(
LauncherItemController* controller,
@@ -81,7 +90,8 @@ class ChromeLauncherControllerPerApp
const std::string& app_id,
ash::LauncherItemStatus status) OVERRIDE;
- // Updates the running status of an item.
+ // Updates the running status of an item. It will also update the status of
+ // browsers launcher item if needed.
virtual void SetItemStatus(ash::LauncherID id,
ash::LauncherItemStatus status) OVERRIDE;
@@ -139,6 +149,7 @@ class ChromeLauncherControllerPerApp
// Returns the id of the app for the specified tab.
virtual std::string GetAppID(content::WebContents* tab) OVERRIDE;
+ // Returns the |LauncherModel|'s ID or 0 if the AppId was not found.
virtual ash::LauncherID GetLauncherIDForAppID(
const std::string& app_id) OVERRIDE;
virtual std::string GetAppIDForLauncherID(ash::LauncherID id) OVERRIDE;
@@ -216,8 +227,8 @@ class ChromeLauncherControllerPerApp
AppState app_state) OVERRIDE;
// Limits application refocusing to urls that match |url| for |id|.
- virtual void SetRefocusURLPattern(ash::LauncherID id,
- const GURL& url) OVERRIDE;
+ virtual void SetRefocusURLPatternForTest(ash::LauncherID id,
+ const GURL& url) OVERRIDE;
// Returns the extension identified by |app_id|.
virtual const extensions::Extension* GetExtensionForAppID(
@@ -231,6 +242,8 @@ class ChromeLauncherControllerPerApp
virtual string16 GetTitle(const ash::LauncherItem& item) OVERRIDE;
virtual ui::MenuModel* CreateContextMenu(
const ash::LauncherItem& item, aura::RootWindow* root) OVERRIDE;
+ virtual ui::MenuModel* CreateApplicationMenu(
+ const ash::LauncherItem& item) OVERRIDE;
virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE;
virtual bool IsDraggable(const ash::LauncherItem& item) OVERRIDE;
@@ -256,6 +269,22 @@ class ChromeLauncherControllerPerApp
// Overridden from AppSyncUIStateObserver
virtual void OnAppSyncUIStatusChanged() OVERRIDE;
+ // Get the list of all running incarnations of this item.
+ ChromeLauncherAppMenuItems* GetApplicationList(
+ const ash::LauncherItem& item);
+
+ // Get the list of all tabs which belong to a certain application type.
+ std::vector<content::WebContents*> GetV1ApplicationsFromAppId(
+ std::string app_id);
+
+ // Activates a specified shell application.
+ void ActivateShellApp(const std::string& app_id, int index);
+
+ // Checks if a given |web_contents| is known to be associated with an
+ // application of type |app_id|.
+ bool IsWebContentHandledByApplication(content::WebContents* web_contents,
+ const std::string& app_id);
+
protected:
// ChromeLauncherController overrides:
@@ -318,6 +347,15 @@ class ChromeLauncherControllerPerApp
bool HasItemController(ash::LauncherID id) const;
+ // Enumerate all Web contents which match a given shortcut |controller|.
+ std::vector<content::WebContents*> GetV1ApplicationsFromController(
+ LauncherItemController* controller);
+
+ // Returns the list of all browsers runing.
+ // TODO(skuhne): Move to wherever the BrowserLauncherItemController
+ // functionality moves to.
+ ChromeLauncherAppMenuItems* GetBrowserApplicationList();
+
ash::LauncherModel* model_;
// Profile used for prefs and loading extensions. This is NOT necessarily the
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc
index dc6b2e7..91f660f 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc
@@ -14,31 +14,40 @@
#include "base/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/test_extension_system.h"
#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/pref_names.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_pref_service.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/models/menu_model.h"
using extensions::Extension;
namespace {
const int kExpectedAppIndex = 1;
+const char* gmail_app_id = "pjkljhegncpnkpknbcohdijeoejaedia";
+const char* gmail_url = "https://mail.google.com/mail/u";
}
-class ChromeLauncherControllerPerAppTest : public testing::Test {
+class ChromeLauncherControllerPerAppTest : public BrowserWithTestWindowTest {
protected:
- ChromeLauncherControllerPerAppTest()
- : ui_thread_(content::BrowserThread::UI, &loop_),
- file_thread_(content::BrowserThread::FILE, &loop_),
- profile_(new TestingProfile()),
- extension_service_(NULL) {
+ ChromeLauncherControllerPerAppTest() : extension_service_(NULL) {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ BrowserWithTestWindowTest::SetUp();
+
DictionaryValue manifest;
manifest.SetString("name", "launcher controller test extension");
manifest.SetString("version", "1");
@@ -46,7 +55,7 @@ class ChromeLauncherControllerPerAppTest : public testing::Test {
extensions::TestExtensionSystem* extension_system(
static_cast<extensions::TestExtensionSystem*>(
- extensions::ExtensionSystem::Get(profile_.get())));
+ extensions::ExtensionSystem::Get(profile())));
extension_service_ = extension_system->CreateExtensionService(
CommandLine::ForCurrentProcess(), FilePath(), false);
@@ -62,8 +71,9 @@ class ChromeLauncherControllerPerAppTest : public testing::Test {
// Fake gmail extension.
extension3_ = Extension::Create(FilePath(), Extension::LOAD, manifest,
Extension::NO_FLAGS,
- "pjkljhegncpnkpknbcohdijeoejaedia",
+ gmail_app_id,
&error);
+
// Fake search extension.
extension4_ = Extension::Create(FilePath(), Extension::LOAD, manifest,
Extension::NO_FLAGS,
@@ -71,12 +81,6 @@ class ChromeLauncherControllerPerAppTest : public testing::Test {
&error);
}
- virtual void TearDown() OVERRIDE {
- profile_.reset();
- // Execute any pending deletion tasks.
- loop_.RunUntilIdle();
- }
-
void InsertPrefValue(base::ListValue* pref_value,
int index,
const std::string& extension_id) {
@@ -101,15 +105,10 @@ class ChromeLauncherControllerPerAppTest : public testing::Test {
}
// Needed for extension service & friends to work.
- MessageLoop loop_;
- content::TestBrowserThread ui_thread_;
- content::TestBrowserThread file_thread_;
-
scoped_refptr<Extension> extension1_;
scoped_refptr<Extension> extension2_;
scoped_refptr<Extension> extension3_;
scoped_refptr<Extension> extension4_;
- scoped_ptr<TestingProfile> profile_;
ash::LauncherModel model_;
ExtensionService* extension_service_;
@@ -118,7 +117,7 @@ class ChromeLauncherControllerPerAppTest : public testing::Test {
};
TEST_F(ChromeLauncherControllerPerAppTest, DefaultApps) {
- ChromeLauncherControllerPerApp launcher_controller(profile_.get(), &model_);
+ ChromeLauncherControllerPerApp launcher_controller(profile(), &model_);
launcher_controller.Init();
// Model should only contain the browser shortcut and app list items.
@@ -143,13 +142,13 @@ TEST_F(ChromeLauncherControllerPerAppTest, Policy) {
base::ListValue policy_value;
InsertPrefValue(&policy_value, 0, extension1_->id());
InsertPrefValue(&policy_value, 1, extension2_->id());
- profile_->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
- policy_value.DeepCopy());
+ profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
+ policy_value.DeepCopy());
// Only |extension1_| should get pinned. |extension2_| is specified but not
// installed, and |extension3_| is part of the default set, but that shouldn't
// take effect when the policy override is in place.
- ChromeLauncherControllerPerApp launcher_controller(profile_.get(), &model_);
+ ChromeLauncherControllerPerApp launcher_controller(profile(), &model_);
launcher_controller.Init();
EXPECT_EQ(3, model_.item_count());
EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_.items()[kExpectedAppIndex].type);
@@ -168,8 +167,8 @@ TEST_F(ChromeLauncherControllerPerAppTest, Policy) {
// Removing |extension1_| from the policy should be reflected in the launcher.
policy_value.Remove(0, NULL);
- profile_->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
- policy_value.DeepCopy());
+ profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
+ policy_value.DeepCopy());
EXPECT_EQ(3, model_.item_count());
EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_.items()[kExpectedAppIndex].type);
EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
@@ -181,7 +180,7 @@ TEST_F(ChromeLauncherControllerPerAppTest, UnpinWithUninstall) {
extension_service_->AddExtension(extension3_.get());
extension_service_->AddExtension(extension4_.get());
- ChromeLauncherControllerPerApp launcher_controller(profile_.get(), &model_);
+ ChromeLauncherControllerPerApp launcher_controller(profile(), &model_);
launcher_controller.Init();
EXPECT_TRUE(launcher_controller.IsAppPinned(extension3_->id()));
@@ -198,12 +197,12 @@ TEST_F(ChromeLauncherControllerPerAppTest, PrefUpdates) {
extension_service_->AddExtension(extension2_.get());
extension_service_->AddExtension(extension3_.get());
extension_service_->AddExtension(extension4_.get());
- ChromeLauncherControllerPerApp controller(profile_.get(), &model_);
+ ChromeLauncherControllerPerApp controller(profile(), &model_);
std::vector<std::string> expected_launchers;
std::vector<std::string> actual_launchers;
base::ListValue pref_value;
- profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+ profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
pref_value.DeepCopy());
GetAppLaunchers(&controller, &actual_launchers);
EXPECT_EQ(expected_launchers, actual_launchers);
@@ -212,7 +211,7 @@ TEST_F(ChromeLauncherControllerPerAppTest, PrefUpdates) {
InsertPrefValue(&pref_value, 0, extension1_->id());
InsertPrefValue(&pref_value, 1, extension2_->id());
InsertPrefValue(&pref_value, 2, extension4_->id());
- profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+ profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
pref_value.DeepCopy());
expected_launchers.push_back(extension2_->id());
expected_launchers.push_back(extension4_->id());
@@ -223,7 +222,7 @@ TEST_F(ChromeLauncherControllerPerAppTest, PrefUpdates) {
InsertPrefValue(&pref_value, 2, extension3_->id());
InsertPrefValue(&pref_value, 2, extension3_->id());
InsertPrefValue(&pref_value, 5, extension3_->id());
- profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+ profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
pref_value.DeepCopy());
expected_launchers.insert(expected_launchers.begin() + 1, extension3_->id());
GetAppLaunchers(&controller, &actual_launchers);
@@ -234,7 +233,7 @@ TEST_F(ChromeLauncherControllerPerAppTest, PrefUpdates) {
InsertPrefValue(&pref_value, 0, extension4_->id());
InsertPrefValue(&pref_value, 1, extension3_->id());
InsertPrefValue(&pref_value, 2, extension2_->id());
- profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+ profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
pref_value.DeepCopy());
std::reverse(expected_launchers.begin(), expected_launchers.end());
GetAppLaunchers(&controller, &actual_launchers);
@@ -242,7 +241,7 @@ TEST_F(ChromeLauncherControllerPerAppTest, PrefUpdates) {
// Clearing works.
pref_value.Clear();
- profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+ profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
pref_value.DeepCopy());
expected_launchers.clear();
GetAppLaunchers(&controller, &actual_launchers);
@@ -252,13 +251,13 @@ TEST_F(ChromeLauncherControllerPerAppTest, PrefUpdates) {
TEST_F(ChromeLauncherControllerPerAppTest, PendingInsertionOrder) {
extension_service_->AddExtension(extension1_.get());
extension_service_->AddExtension(extension3_.get());
- ChromeLauncherControllerPerApp controller(profile_.get(), &model_);
+ ChromeLauncherControllerPerApp controller(profile(), &model_);
base::ListValue pref_value;
InsertPrefValue(&pref_value, 0, extension1_->id());
InsertPrefValue(&pref_value, 1, extension2_->id());
InsertPrefValue(&pref_value, 2, extension3_->id());
- profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+ profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
pref_value.DeepCopy());
std::vector<std::string> expected_launchers;
@@ -275,3 +274,189 @@ TEST_F(ChromeLauncherControllerPerAppTest, PendingInsertionOrder) {
GetAppLaunchers(&controller, &actual_launchers);
EXPECT_EQ(expected_launchers, actual_launchers);
}
+
+// Checks the created menus and menu lists for correctness. It uses the given
+// |controller| to create the objects for the given |item| and checks the
+// found item count against the |expected_items|. The |title| list contains the
+// menu titles in the order of their appearance in the menu (not including the
+// application name).
+void CheckMenuCreation(ChromeLauncherControllerPerApp* controller,
+ const ash::LauncherItem& item,
+ size_t expected_items,
+ string16 title[]) {
+ ChromeLauncherAppMenuItems items(controller->GetApplicationList(item));
+ // There should be one item in there: The title.
+ EXPECT_EQ(expected_items + 1, items.size());
+ EXPECT_EQ(false, items[0]->IsEnabled());
+ for (size_t i = 0; i < expected_items; i++) {
+ EXPECT_EQ(title[i], items[1 + i]->title());
+ }
+
+ scoped_ptr<ui::MenuModel> menu(controller->CreateApplicationMenu(item));
+ // There should be one item in there.
+ int expected_menu_items = expected_items ? (expected_items + 2) : 1;
+ EXPECT_EQ(expected_menu_items, menu->GetItemCount());
+ EXPECT_EQ(false, menu->IsEnabledAt(0));
+ if (expected_items) {
+ EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR , menu->GetTypeAt(1));
+ }
+}
+
+// Check that browsers get reflected correctly in the launcher menu.
+TEST_F(ChromeLauncherControllerPerAppTest, BrowserMenuGeneration) {
+ EXPECT_EQ(1U, BrowserList::size());
+ chrome::NewTab(browser());
+
+ ChromeLauncherControllerPerApp launcher_controller(profile(), &model_);
+ launcher_controller.Init();
+
+ // Check that the browser list is empty at this time.
+ ash::LauncherItem item_browser;
+ item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
+ CheckMenuCreation(&launcher_controller, item_browser, 0, NULL);
+
+ // Now make the created browser() visible by adding it to the active browser
+ // list.
+ BrowserList::SetLastActive(browser());
+ string16 title1 = ASCIIToUTF16("Test1");
+ NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
+ string16 one_menu_item[] = {title1};
+ CheckMenuCreation(&launcher_controller, item_browser, 1, one_menu_item);
+
+ // Create one more browser/window and check that one more was added.
+ scoped_ptr<Browser> browser2(
+ chrome::CreateBrowserWithTestWindowForProfile(profile()));
+ chrome::NewTab(browser2.get());
+ BrowserList::SetLastActive(browser2.get());
+ string16 title2 = ASCIIToUTF16("Test2");
+ NavigateAndCommitActiveTabWithTitle(browser2.get(), GURL("http://test2"),
+ title2);
+
+ // Check that the list contains now two entries - make furthermore sure that
+ // the active item is the first entry.
+ string16 two_menu_items[] = {title2, title1};
+ CheckMenuCreation(&launcher_controller, item_browser, 2, two_menu_items);
+
+ // Apparently we have to close all tabs we have.
+ chrome::CloseTab(browser2.get());
+}
+
+// Check that V1 apps are correctly reflected in the launcher menu.
+TEST_F(ChromeLauncherControllerPerAppTest, V1AppMenuGeneration) {
+ EXPECT_EQ(1U, BrowserList::size());
+ EXPECT_EQ(0, browser()->tab_strip_model()->count());
+ chrome::NewTab(browser());
+ BrowserList::SetLastActive(browser());
+
+ ChromeLauncherControllerPerApp launcher_controller(profile(), &model_);
+ launcher_controller.Init();
+
+ // Model should only contain the browser shortcut and app list items.
+ EXPECT_EQ(2, model_.item_count());
+ EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
+
+ // Installing |extension3_| adds it to the launcher.
+ ash::LauncherID gmail_id = model_.next_id();
+ extension_service_->AddExtension(extension3_.get());
+ EXPECT_EQ(3, model_.item_count());
+ int gmail_index = model_.ItemIndexByID(gmail_id);
+ EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_.items()[gmail_index].type);
+ EXPECT_TRUE(launcher_controller.IsAppPinned(extension3_->id()));
+ launcher_controller.SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
+
+ // Check the menu content.
+ ash::LauncherItem item_browser;
+ item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
+
+ ash::LauncherItem item_gmail;
+ item_gmail.type = ash::TYPE_APP_SHORTCUT;
+ item_gmail.id = gmail_id;
+ CheckMenuCreation(&launcher_controller, item_gmail, 0, NULL);
+
+ // Set the gmail URL to a new tab.
+ string16 title1 = ASCIIToUTF16("Test1");
+ NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
+
+ string16 one_menu_item[] = {title1};
+ CheckMenuCreation(&launcher_controller, item_gmail, 1, one_menu_item);
+
+ // Create one empty tab.
+ chrome::NewTab(browser());
+ string16 title2 = ASCIIToUTF16("Test2");
+ NavigateAndCommitActiveTabWithTitle(
+ browser(),
+ GURL("https://bla"),
+ title2);
+
+ // and another one with another gmail instance.
+ chrome::NewTab(browser());
+ string16 title3 = ASCIIToUTF16("Test3");
+ NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title3);
+ string16 two_menu_items[] = {title3, title1};
+ CheckMenuCreation(&launcher_controller, item_gmail, 2, two_menu_items);
+
+ // Even though the item is in the V1 app list, it should also be in the
+ // browser list.
+ string16 browser_menu_item[] = {title3};
+ CheckMenuCreation(&launcher_controller, item_browser, 1, browser_menu_item);
+
+ // Test that closing of (all) the item(s) does work (and all menus get
+ // updated properly).
+ launcher_controller.Close(item_gmail.id);
+
+ CheckMenuCreation(&launcher_controller, item_gmail, 0, NULL);
+ string16 browser_menu_item2[] = {title2};
+ CheckMenuCreation(&launcher_controller, item_browser, 1, browser_menu_item2);
+}
+
+// Checks that the generated menu list properly activates items.
+TEST_F(ChromeLauncherControllerPerAppTest, V1AppMenuExecution) {
+ chrome::NewTab(browser());
+ BrowserList::SetLastActive(browser());
+
+ ChromeLauncherControllerPerApp launcher_controller(profile(), &model_);
+ launcher_controller.Init();
+
+ // Add |extension3_| to the launcher and add two items.
+ GURL gmail = GURL("https://mail.google.com/mail/u");
+ ash::LauncherID gmail_id = model_.next_id();
+ extension_service_->AddExtension(extension3_.get());
+ launcher_controller.SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
+ string16 title1 = ASCIIToUTF16("Test1");
+ NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
+ chrome::NewTab(browser());
+ string16 title2 = ASCIIToUTF16("Test2");
+ NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
+
+ // Check that the menu is properly set.
+ ash::LauncherItem item_gmail;
+ item_gmail.type = ash::TYPE_APP_SHORTCUT;
+ item_gmail.id = gmail_id;
+ string16 two_menu_items[] = {title2, title1};
+ CheckMenuCreation(&launcher_controller, item_gmail, 2, two_menu_items);
+ EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
+ // Execute the first item in the list (which shouldn't do anything since that
+ // item is per definition already the active tab).
+ {
+ scoped_ptr<ui::MenuModel> menu(
+ launcher_controller.CreateApplicationMenu(item_gmail));
+ menu->ActivatedAt(2);
+ }
+ EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
+
+ // Execute the second item.
+ {
+ scoped_ptr<ui::MenuModel> menu(
+ launcher_controller.CreateApplicationMenu(item_gmail));
+ menu->ActivatedAt(3);
+ }
+ // Now the active tab should be the second item.
+ EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
+}
+
+// TODO(skuhne) Add tests for:
+// - V2 apps: create through item in launcher or directly
+// - Tracking correct activation state (seems not to work from unit_test)
+// - Check that browser is always running or active when browser is active
+// - Check that v1 app active shows browser active and app.
+// ..
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc
index e900163..bc6da1c 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc
@@ -22,6 +22,7 @@
#include "chrome/browser/ui/ash/app_sync_ui_state.h"
#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
#include "chrome/browser/ui/ash/extension_utils.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
#include "chrome/browser/ui/ash/launcher/launcher_app_icon_loader.h"
#include "chrome/browser/ui/ash/launcher/launcher_app_tab_helper.h"
#include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
@@ -112,6 +113,10 @@ class AppShortcutLauncherItemController : public LauncherItemController {
const ash::LauncherItem& old_item) OVERRIDE {
}
+ virtual ChromeLauncherAppMenuItems* GetApplicationList() OVERRIDE {
+ return new ChromeLauncherAppMenuItems;
+ }
+
// Stores the optional refocus url pattern for this item.
const GURL& refocus_url() const { return refocus_url_; }
void set_refocus_url(const GURL& refocus_url) { refocus_url_ = refocus_url; }
@@ -287,6 +292,11 @@ void ChromeLauncherControllerPerBrowser::Init() {
}
}
+ChromeLauncherControllerPerApp*
+ChromeLauncherControllerPerBrowser::GetPerAppInterface() {
+ return NULL;
+}
+
ash::LauncherID ChromeLauncherControllerPerBrowser::CreateTabbedLauncherItem(
LauncherItemController* controller,
IncognitoState is_incognito,
@@ -724,7 +734,7 @@ void ChromeLauncherControllerPerBrowser::UpdateAppState(
}
}
-void ChromeLauncherControllerPerBrowser::SetRefocusURLPattern(
+void ChromeLauncherControllerPerBrowser::SetRefocusURLPatternForTest(
ash::LauncherID id,
const GURL& url) {
DCHECK(HasItemController(id));
@@ -794,6 +804,12 @@ ui::MenuModel* ChromeLauncherControllerPerBrowser::CreateContextMenu(
return new LauncherContextMenu(this, &item, root_window);
}
+ui::MenuModel* ChromeLauncherControllerPerBrowser::CreateApplicationMenu(
+ const ash::LauncherItem& item) {
+ // Not used by this launcher type.
+ return NULL;
+}
+
ash::LauncherID ChromeLauncherControllerPerBrowser::GetIDByWindow(
aura::Window* window) {
for (IDToItemControllerMap::const_iterator i =
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h
index e961afc..6c39f0b 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h
@@ -71,6 +71,11 @@ class ChromeLauncherControllerPerBrowser
// Initializes this ChromeLauncherControllerPerBrowser.
virtual void Init() OVERRIDE;
+ // Returns the new per application interface of the given launcher. If it is
+ // a per browser (old) controller, it will return NULL;
+ // TODO(skuhne): Remove when we rip out the old launcher.
+ virtual ChromeLauncherControllerPerApp* GetPerAppInterface() OVERRIDE;
+
// Creates a new tabbed item on the launcher for |controller|.
virtual ash::LauncherID CreateTabbedLauncherItem(
LauncherItemController* controller,
@@ -218,8 +223,8 @@ class ChromeLauncherControllerPerBrowser
AppState app_state) OVERRIDE;
// Limits application refocusing to urls that match |url| for |id|.
- virtual void SetRefocusURLPattern(ash::LauncherID id,
- const GURL& url) OVERRIDE;
+ virtual void SetRefocusURLPatternForTest(ash::LauncherID id,
+ const GURL& url) OVERRIDE;
// Returns the extension identified by |app_id|.
virtual const extensions::Extension* GetExtensionForAppID(
@@ -233,6 +238,8 @@ class ChromeLauncherControllerPerBrowser
virtual string16 GetTitle(const ash::LauncherItem& item) OVERRIDE;
virtual ui::MenuModel* CreateContextMenu(
const ash::LauncherItem& item, aura::RootWindow* root) OVERRIDE;
+ virtual ui::MenuModel* CreateApplicationMenu(
+ const ash::LauncherItem& item) OVERRIDE;
virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE;
virtual bool IsDraggable(const ash::LauncherItem& item) OVERRIDE;
diff --git a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc
new file mode 100644
index 0000000..9661be3
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 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/ash/launcher/launcher_application_menu_item_model.h"
+
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+
+LauncherApplicationMenuItemModel::LauncherApplicationMenuItemModel(
+ ChromeLauncherAppMenuItems* item_list)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)),
+ launcher_items_(item_list) {
+ Build();
+}
+
+LauncherApplicationMenuItemModel::~LauncherApplicationMenuItemModel() {
+}
+
+bool LauncherApplicationMenuItemModel::IsCommandIdChecked(
+ int command_id) const {
+ return false;
+}
+
+bool LauncherApplicationMenuItemModel::IsCommandIdEnabled(
+ int command_id) const {
+ DCHECK(command_id < static_cast<int>(launcher_items_.size()));
+ return launcher_items_[command_id]->IsEnabled();
+}
+
+bool LauncherApplicationMenuItemModel::GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) {
+ return false;
+}
+
+void LauncherApplicationMenuItemModel::ExecuteCommand(int command_id) {
+ DCHECK(command_id < static_cast<int>(launcher_items_.size()));
+ launcher_items_[command_id]->Execute();
+}
+
+void LauncherApplicationMenuItemModel::Build() {
+ for (size_t i = 0; i < launcher_items_.size(); i++) {
+ ChromeLauncherAppMenuItem* item = launcher_items_[i];
+ // The first item is the context menu, the others are the running apps.
+ AddItem(i, item->title());
+
+ if (!item->icon().IsEmpty())
+ SetIcon(GetIndexOfCommandId(i), item->icon());
+ // The first item is most likely the application name which should get
+ // separated from the rest.
+ if (!i && launcher_items_.size() > 1)
+ AddSeparator(ui::NORMAL_SEPARATOR);
+ }
+}
+
diff --git a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h
new file mode 100644
index 0000000..5053b23
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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_ASH_LAUNCHER_LAUNCHER_APPLICATION_MENU_ITEM_MODEL_H_
+#define CHROME_BROWSER_UI_ASH_LAUNCHER_LAUNCHER_APPLICATION_MENU_ITEM_MODEL_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "ui/base/models/simple_menu_model.h"
+
+// A menu model that builds the contents of a menu for a launcher item
+// containing a list of running applications.
+class LauncherApplicationMenuItemModel : public ui::SimpleMenuModel,
+ public ui::SimpleMenuModel::Delegate {
+ public:
+ explicit LauncherApplicationMenuItemModel(
+ ChromeLauncherAppMenuItems* item_list);
+ virtual ~LauncherApplicationMenuItemModel();
+
+ // Overridden from ui::SimpleMenuModel::Delegate:
+ virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) OVERRIDE;
+ virtual void ExecuteCommand(int command_id) OVERRIDE;
+
+ private:
+ void Build();
+
+ // The list of menu items as returned from the launcher controller.
+ ChromeLauncherAppMenuItems launcher_items_;
+
+ DISALLOW_COPY_AND_ASSIGN(LauncherApplicationMenuItemModel);
+};
+
+#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_LAUNCHER_APPLICATION_MENU_ITEM_MODEL_H_
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
index d505fde..4b7801f 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
@@ -66,8 +66,13 @@ void LauncherContextMenu::Init() {
if (is_valid_item()) {
if (item_.type == ash::TYPE_APP_SHORTCUT) {
DCHECK(controller_->IsPinned(item_.id));
- AddItem(MENU_OPEN_NEW, string16());
- AddSeparator(ui::NORMAL_SEPARATOR);
+ // Everything can be started as many times as needed through the menu,
+ // except for V2 apps - there should be only one instance of it.
+ if (!controller_->IsPlatformApp(item_.id) ||
+ !controller_->IsOpen(item_.id)) {
+ AddItem(MENU_OPEN_NEW, string16());
+ AddSeparator(ui::NORMAL_SEPARATOR);
+ }
AddItem(
MENU_PIN,
l10n_util::GetStringUTF16(IDS_LAUNCHER_CONTEXT_MENU_UNPIN));
diff --git a/chrome/browser/ui/ash/launcher/launcher_item_controller.h b/chrome/browser/ui/ash/launcher/launcher_item_controller.h
index af1cd5f..049e99d 100644
--- a/chrome/browser/ui/ash/launcher/launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/launcher_item_controller.h
@@ -8,9 +8,13 @@
#include "ash/launcher/launcher_types.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/scoped_vector.h"
#include "base/string16.h"
class ChromeLauncherController;
+class ChromeLauncherAppMenuItem;
+
+typedef ScopedVector<ChromeLauncherAppMenuItem> ChromeLauncherAppMenuItems;
namespace aura {
class Window;
@@ -77,6 +81,9 @@ class LauncherItemController {
// Called when the controlled item is removed from the launcher.
virtual void OnRemoved() = 0;
+ // Called to retrieve the list of running applications.
+ virtual ChromeLauncherAppMenuItems* GetApplicationList() = 0;
+
// Helper function to get the ash::LauncherItemType for the item type.
ash::LauncherItemType GetLauncherItemType() const;
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc
index 55e688c..9c33dad 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.cc
@@ -4,20 +4,13 @@
#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
-#include <algorithm>
-
#include "ash/shell.h"
#include "ash/wm/window_util.h"
#include "base/stl_util.h"
-#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
-#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
-#include "chrome/browser/ui/extensions/native_app_window.h"
+#include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h"
#include "chrome/browser/ui/extensions/shell_window.h"
-#include "chrome/common/extensions/extension.h"
#include "ui/aura/client/activation_client.h"
namespace {
@@ -28,160 +21,8 @@ std::string GetAppLauncherId(ShellWindow* shell_window) {
return shell_window->extension()->id();
}
-// Functor for std::find_if used in AppLauncherItemController.
-class ShellWindowHasWindow {
- public:
- explicit ShellWindowHasWindow(aura::Window* window) : window_(window) { }
-
- bool operator()(ShellWindow* shell_window) const {
- return shell_window->GetNativeWindow() == window_;
- }
-
- private:
- const aura::Window* window_;
-};
-
} // namespace
-// AppLauncherItemController ---------------------------------------------------
-
-// This is a LauncherItemController for shell windows. There is one instance
-// per app, per launcher id. [[[Currently, apps can not define multiple launcher
-// ids (see GatAppLauncherId() above) so there is one instance per app]]].
-// For apps with multiple windows, each item controller keeps track of all
-// windows associated with the app and their activation order.
-// Instances are owned by ShellWindowLauncherController.
-class ShellWindowLauncherController::AppLauncherItemController
- : public LauncherItemController {
- public:
- AppLauncherItemController(const std::string& app_launcher_id,
- const std::string& app_id,
- ChromeLauncherController* controller) :
- LauncherItemController(TYPE_APP, app_id, controller),
- app_launcher_id_(app_launcher_id) {
- }
- virtual ~AppLauncherItemController() {}
-
- void AddShellWindow(ShellWindow* shell_window,
- ash::LauncherItemStatus status) {
- if (status == ash::STATUS_ACTIVE)
- shell_windows_.push_front(shell_window);
- else
- shell_windows_.push_back(shell_window);
- }
-
- void RemoveShellWindowForWindow(aura::Window* window) {
- ShellWindowList::iterator iter =
- std::find_if(shell_windows_.begin(), shell_windows_.end(),
- ShellWindowHasWindow(window));
- if (iter != shell_windows_.end())
- shell_windows_.erase(iter);
- }
-
- void SetActiveWindow(aura::Window* window) {
- ShellWindowList::iterator iter =
- std::find_if(shell_windows_.begin(), shell_windows_.end(),
- ShellWindowHasWindow(window));
- if (iter != shell_windows_.end()) {
- ShellWindow* shell_window = *iter;
- shell_windows_.erase(iter);
- shell_windows_.push_front(shell_window);
- }
- }
-
- const std::string& app_launcher_id() const { return app_launcher_id_; }
-
- virtual string16 GetTitle() OVERRIDE {
- return GetAppTitle();
- }
-
- virtual bool HasWindow(aura::Window* window) const OVERRIDE {
- ShellWindowList::const_iterator iter =
- std::find_if(shell_windows_.begin(), shell_windows_.end(),
- ShellWindowHasWindow(window));
- return iter != shell_windows_.end();
- }
-
- virtual bool IsOpen() const OVERRIDE {
- return !shell_windows_.empty();
- }
-
- virtual void Launch(int event_flags) OVERRIDE {
- launcher_controller()->LaunchApp(app_id(), ui::EF_NONE);
- }
-
- virtual void Activate() OVERRIDE {
- DCHECK(!shell_windows_.empty());
- shell_windows_.front()->GetBaseWindow()->Activate();
- }
-
- virtual void Close() OVERRIDE {
- // Note: Closing windows may affect the contents of shell_windows_.
- ShellWindowList windows_to_close = shell_windows_;
- for (ShellWindowList::iterator iter = windows_to_close.begin();
- iter != windows_to_close.end(); ++iter) {
- (*iter)->GetBaseWindow()->Close();
- }
- }
-
- // Behavior for app windows:
- // * One window: Toggle minimization when clicked.
- // * Multiple windows:
- // ** If the first window is not active, activate it.
- // ** Otherwise activate the next window.
- virtual void Clicked() OVERRIDE {
- if (shell_windows_.empty())
- return;
- ShellWindow* first_window = shell_windows_.front();
- if (shell_windows_.size() == 1) {
- if (first_window->GetBaseWindow()->IsActive())
- first_window->GetBaseWindow()->Minimize();
- else
- RestoreOrShow(first_window);
- } else {
- if (!first_window->GetBaseWindow()->IsActive()) {
- RestoreOrShow(first_window);
- } else {
- shell_windows_.pop_front();
- shell_windows_.push_back(first_window);
- RestoreOrShow(shell_windows_.front());
- }
- }
- }
-
- virtual void OnRemoved() OVERRIDE {
- }
-
- virtual void LauncherItemChanged(int model_index,
- const ash::LauncherItem& old_item) OVERRIDE {
- }
-
- size_t shell_window_count() const { return shell_windows_.size(); }
-
- private:
- typedef std::list<ShellWindow*> ShellWindowList;
-
- void RestoreOrShow(ShellWindow* shell_window) {
- if (shell_window->GetBaseWindow()->IsMinimized())
- shell_window->GetBaseWindow()->Restore();
- else
- shell_window->GetBaseWindow()->Show();
- // Always activate windows when shown from the launcher.
- shell_window->GetBaseWindow()->Activate();
- }
-
- // List of associated shell windows in activation order.
- ShellWindowList shell_windows_;
-
- // The launcher id associated with this set of windows. There is one
- // AppLauncherItemController for each |app_launcher_id_|.
- const std::string app_launcher_id_;
-
- DISALLOW_COPY_AND_ASSIGN(AppLauncherItemController);
-};
-
-// ShellWindowLauncherController -----------------------------------------------
-
ShellWindowLauncherController::ShellWindowLauncherController(
ChromeLauncherController* owner)
: owner_(owner),
@@ -229,13 +70,13 @@ void ShellWindowLauncherController::OnShellWindowAdded(
AppControllerMap::iterator iter = app_controller_map_.find(app_launcher_id);
ash::LauncherID launcher_id = 0;
if (iter != app_controller_map_.end()) {
- AppLauncherItemController* controller = iter->second;
+ ShellWindowLauncherItemController* controller = iter->second;
DCHECK(controller->app_id() == app_id);
launcher_id = controller->launcher_id();
controller->AddShellWindow(shell_window, status);
} else {
- AppLauncherItemController* controller =
- new AppLauncherItemController(app_launcher_id, app_id, owner_);
+ ShellWindowLauncherItemController* controller =
+ new ShellWindowLauncherItemController(app_launcher_id, app_id, owner_);
controller->AddShellWindow(shell_window, status);
// If the app launcher id is not unique, and there is already a launcher
// item for this app id (e.g. pinned), use that launcher item.
@@ -257,7 +98,7 @@ void ShellWindowLauncherController::OnShellWindowIconChanged(
AppControllerMap::iterator iter = app_controller_map_.find(app_launcher_id);
if (iter == app_controller_map_.end())
return;
- AppLauncherItemController* controller = iter->second;
+ ShellWindowLauncherItemController* controller = iter->second;
owner_->SetLauncherItemImage(controller->launcher_id(),
shell_window->app_icon().AsImageSkia());
}
@@ -281,7 +122,7 @@ void ShellWindowLauncherController::OnWindowDestroying(aura::Window* window) {
AppControllerMap::iterator iter2 = app_controller_map_.find(app_launcher_id);
DCHECK(iter2 != app_controller_map_.end());
- AppLauncherItemController* controller = iter2->second;
+ ShellWindowLauncherItemController* controller = iter2->second;
controller->RemoveShellWindowForWindow(window);
if (controller->shell_window_count() == 0) {
// If this is the last window associated with the app launcher id, close the
@@ -296,22 +137,24 @@ void ShellWindowLauncherController::OnWindowDestroying(aura::Window* window) {
void ShellWindowLauncherController::OnWindowActivated(
aura::Window* new_active,
aura::Window* old_active) {
- // Make the newly active window the active (first) entry in the controlelr.
- AppLauncherItemController* new_controller = ControllerForWindow(new_active);
+ // Make the newly active window the active (first) entry in the controller.
+ ShellWindowLauncherItemController* new_controller =
+ ControllerForWindow(new_active);
if (new_controller) {
new_controller->SetActiveWindow(new_active);
owner_->SetItemStatus(new_controller->launcher_id(), ash::STATUS_ACTIVE);
}
// Mark the old active window's launcher item as running (if different).
- AppLauncherItemController* old_controller = ControllerForWindow(old_active);
+ ShellWindowLauncherItemController* old_controller =
+ ControllerForWindow(old_active);
if (old_controller && old_controller != new_controller)
owner_->SetItemStatus(old_controller->launcher_id(), ash::STATUS_RUNNING);
}
// Private Methods
-ShellWindowLauncherController::AppLauncherItemController*
+ShellWindowLauncherItemController*
ShellWindowLauncherController::ControllerForWindow(
aura::Window* window) {
WindowToAppLauncherIdMap::iterator iter1 =
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h
index 9dba82a..9c279f6 100644
--- a/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h
@@ -24,8 +24,8 @@ class ActivationClient;
}
class ChromeLauncherController;
-class LauncherItemController;
class ShellWindow;
+class ShellWindowLauncherItemController;
// ShellWindowLauncherController observes the Shell Window registry and the
// aura window manager. It handles adding and removing launcher items from
@@ -50,13 +50,18 @@ class ShellWindowLauncherController
virtual void OnWindowActivated(aura::Window* gained_active,
aura::Window* lost_active) OVERRIDE;
- private:
- class AppLauncherItemController;
+ // Returns the number of running applications.
+ int NumberOfAppsRunning();
+
+ // Activate the application with the given index.
+ void ActivateAppAt(int index);
- typedef std::map<std::string, AppLauncherItemController*> AppControllerMap;
+ private:
+ typedef std::map<std::string, ShellWindowLauncherItemController*>
+ AppControllerMap;
typedef std::map<aura::Window*, std::string> WindowToAppLauncherIdMap;
- AppLauncherItemController* ControllerForWindow(aura::Window* window);
+ ShellWindowLauncherItemController* ControllerForWindow(aura::Window* window);
ChromeLauncherController* owner_;
extensions::ShellWindowRegistry* registry_; // Unowned convenience pointer
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc
new file mode 100644
index 0000000..597e817
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.cc
@@ -0,0 +1,189 @@
+// Copyright (c) 2012 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/ash/launcher/shell_window_launcher_item_controller.h"
+
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
+#include "chrome/browser/ui/extensions/native_app_window.h"
+#include "chrome/browser/ui/extensions/shell_window.h"
+
+namespace {
+
+// Functor for std::find_if used in AppLauncherItemController.
+class ShellWindowHasWindow {
+ public:
+ explicit ShellWindowHasWindow(aura::Window* window) : window_(window) { }
+
+ bool operator()(ShellWindow* shell_window) const {
+ return shell_window->GetNativeWindow() == window_;
+ }
+
+ private:
+ const aura::Window* window_;
+};
+
+} // namespace
+
+ShellWindowLauncherItemController::ShellWindowLauncherItemController(
+ const std::string& app_launcher_id,
+ const std::string& app_id,
+ ChromeLauncherController* controller)
+ : LauncherItemController(TYPE_APP, app_id, controller),
+ app_launcher_id_(app_launcher_id) {
+}
+
+ShellWindowLauncherItemController::~ShellWindowLauncherItemController() {
+}
+
+void ShellWindowLauncherItemController::AddShellWindow(
+ ShellWindow* shell_window,
+ ash::LauncherItemStatus status) {
+ if (status == ash::STATUS_ACTIVE)
+ shell_windows_.push_front(shell_window);
+ else
+ shell_windows_.push_back(shell_window);
+}
+
+void ShellWindowLauncherItemController::RemoveShellWindowForWindow(
+ aura::Window* window) {
+ ShellWindowList::iterator iter =
+ std::find_if(shell_windows_.begin(), shell_windows_.end(),
+ ShellWindowHasWindow(window));
+ if (iter != shell_windows_.end())
+ shell_windows_.erase(iter);
+}
+
+void ShellWindowLauncherItemController::SetActiveWindow(
+ aura::Window* window) {
+ ShellWindowList::iterator iter =
+ std::find_if(shell_windows_.begin(), shell_windows_.end(),
+ ShellWindowHasWindow(window));
+ if (iter != shell_windows_.end()) {
+ ShellWindow* shell_window = *iter;
+ shell_windows_.erase(iter);
+ shell_windows_.push_front(shell_window);
+ }
+}
+
+string16 ShellWindowLauncherItemController::GetTitle() {
+ return GetAppTitle();
+}
+
+bool ShellWindowLauncherItemController::HasWindow(
+ aura::Window* window) const {
+ ShellWindowList::const_iterator iter =
+ std::find_if(shell_windows_.begin(), shell_windows_.end(),
+ ShellWindowHasWindow(window));
+ return iter != shell_windows_.end();
+}
+
+bool ShellWindowLauncherItemController::IsOpen() const {
+ return !shell_windows_.empty();
+}
+
+void ShellWindowLauncherItemController::Launch(
+ int event_flags) {
+ launcher_controller()->LaunchApp(app_id(), ui::EF_NONE);
+}
+
+void ShellWindowLauncherItemController::Activate() {
+ DCHECK(!shell_windows_.empty());
+ shell_windows_.front()->GetBaseWindow()->Activate();
+}
+
+void ShellWindowLauncherItemController::Close() {
+ // Note: Closing windows may affect the contents of shell_windows_.
+ ShellWindowList windows_to_close = shell_windows_;
+ for (ShellWindowList::iterator iter = windows_to_close.begin();
+ iter != windows_to_close.end(); ++iter) {
+ (*iter)->GetBaseWindow()->Close();
+ }
+}
+
+// Behavior for app windows:
+// * One window: Toggle minimization when clicked.
+// * Multiple windows:
+// ** If the first window is not active, activate it.
+// ** Otherwise activate the next window.
+void ShellWindowLauncherItemController::Clicked() {
+ if (shell_windows_.empty())
+ return;
+ ShellWindow* first_window = shell_windows_.front();
+ if (shell_windows_.size() == 1) {
+ if (first_window->GetBaseWindow()->IsActive())
+ first_window->GetBaseWindow()->Minimize();
+ else
+ RestoreOrShow(first_window);
+ } else {
+ if (!first_window->GetBaseWindow()->IsActive()) {
+ RestoreOrShow(first_window);
+ } else {
+ shell_windows_.pop_front();
+ shell_windows_.push_back(first_window);
+ RestoreOrShow(shell_windows_.front());
+ }
+ }
+}
+
+void ShellWindowLauncherItemController::ActivateIndexedApp(
+ size_t index) {
+ if (index < shell_windows_.size()) {
+ ShellWindowList::iterator it = shell_windows_.begin();
+ std::advance(it, index);
+ RestoreOrShow(*it);
+ }
+}
+
+string16 ShellWindowLauncherItemController::GetTitleOfIndexedApp(
+ size_t index) {
+ if (index < shell_windows_.size()) {
+ ShellWindowList::iterator it = shell_windows_.begin();
+ std::advance(it, index);
+ return (*it)->GetTitle();
+ }
+ return string16();
+}
+
+gfx::Image*
+ShellWindowLauncherItemController::GetIconOfIndexedApp(size_t index) {
+ if (index < shell_windows_.size()) {
+ ShellWindowList::iterator it = shell_windows_.begin();
+ std::advance(it, index);
+ return (*it)->GetAppListIcon();
+ }
+ return new gfx::Image();
+}
+
+ChromeLauncherAppMenuItems*
+ShellWindowLauncherItemController::GetApplicationList() {
+ ChromeLauncherAppMenuItems* items = new ChromeLauncherAppMenuItems;
+ if (!launcher_controller()->GetPerAppInterface()) {
+ items->push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL));
+ for (size_t i = 0; i < shell_window_count(); i++) {
+ gfx::Image* image = GetIconOfIndexedApp(i);
+ items->push_back(new ChromeLauncherAppMenuItemV2App(
+ GetTitleOfIndexedApp(i),
+ image,
+ app_id(),
+ launcher_controller()->GetPerAppInterface(),
+ i));
+ delete image;
+ }
+ }
+ return items;
+}
+
+void ShellWindowLauncherItemController::RestoreOrShow(
+ ShellWindow* shell_window) {
+ if (shell_window->GetBaseWindow()->IsMinimized())
+ shell_window->GetBaseWindow()->Restore();
+ else
+ shell_window->GetBaseWindow()->Show();
+ // Always activate windows when shown from the launcher.
+ shell_window->GetBaseWindow()->Activate();
+}
diff --git a/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h
new file mode 100644
index 0000000..a80ebb6
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2012 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_ASH_LAUNCHER_SHELL_WINDOW_LAUNCHER_ITEM_CONTROLLER_H_
+#define CHROME_BROWSER_UI_ASH_LAUNCHER_SHELL_WINDOW_LAUNCHER_ITEM_CONTROLLER_H_
+
+#include <list>
+#include <string>
+
+#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
+
+namespace aura {
+class Window;
+}
+
+namespace gfx {
+class Image;
+}
+
+class ChromeLauncherController;
+class ShellWindow;
+
+// This is a ShellWindowItemLauncherController for shell windows. There is one
+// instance per app, per launcher id.
+// For apps with multiple windows, each item controller keeps track of all
+// windows associated with the app and their activation order.
+// Instances are owned by ShellWindowLauncherController.
+class ShellWindowLauncherItemController : public LauncherItemController {
+ public:
+ ShellWindowLauncherItemController(const std::string& app_launcher_id,
+ const std::string& app_id,
+ ChromeLauncherController* controller);
+
+ virtual ~ShellWindowLauncherItemController();
+
+ void AddShellWindow(ShellWindow* shell_window,
+ ash::LauncherItemStatus status);
+
+ void RemoveShellWindowForWindow(aura::Window* window);
+
+ void SetActiveWindow(aura::Window* window);
+
+ const std::string& app_launcher_id() const { return app_launcher_id_; }
+
+ // LauncherItemController overrides.
+ virtual string16 GetTitle() OVERRIDE;
+ virtual bool HasWindow(aura::Window* window) const OVERRIDE;
+ virtual bool IsOpen() const OVERRIDE;
+ virtual void Launch(int event_flags) OVERRIDE;
+ virtual void Activate() OVERRIDE;
+ virtual void Close() OVERRIDE;
+ virtual void Clicked() OVERRIDE;
+ virtual void OnRemoved() OVERRIDE {}
+ virtual void LauncherItemChanged(
+ int model_index,
+ const ash::LauncherItem& old_item) OVERRIDE {}
+ virtual ChromeLauncherAppMenuItems* GetApplicationList() OVERRIDE;
+
+ // Get the number of running applications/incarnations of this.
+ size_t shell_window_count() const { return shell_windows_.size(); }
+
+ // Activates the window at position |index|.
+ void ActivateIndexedApp(size_t index);
+
+ private:
+ typedef std::list<ShellWindow*> ShellWindowList;
+
+ // Get the title of the running application with this |index|.
+ string16 GetTitleOfIndexedApp(size_t index);
+
+ // Get the title of the running application with this |index|.
+ // Note that the returned image needs to be released by the caller.
+ gfx::Image* GetIconOfIndexedApp(size_t index);
+
+ void RestoreOrShow(ShellWindow* shell_window);
+
+ // List of associated shell windows in activation order.
+ ShellWindowList shell_windows_;
+
+ // The launcher id associated with this set of windows. There is one
+ // AppLauncherItemController for each |app_launcher_id_|.
+ const std::string app_launcher_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellWindowLauncherItemController);
+};
+
+#endif // CHROME_BROWSER_UI_ASH_LAUNCHER_SHELL_WINDOW_LAUNCHER_ITEM_CONTROLLER_H_
diff --git a/chrome/browser/ui/extensions/shell_window.cc b/chrome/browser/ui/extensions/shell_window.cc
index c01b5d5..93752c0 100644
--- a/chrome/browser/ui/extensions/shell_window.cc
+++ b/chrome/browser/ui/extensions/shell_window.cc
@@ -48,6 +48,7 @@
#include "content/public/browser/web_intents_dispatcher.h"
#include "content/public/common/media_stream_request.h"
#include "content/public/common/renderer_preferences.h"
+#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkRegion.h"
#if defined(USE_ASH)
@@ -376,6 +377,21 @@ void ShellWindow::OnNativeWindowChanged() {
false));
}
+gfx::Image* ShellWindow::GetAppListIcon() {
+ // TODO(skuhne): We might want to use LoadImages in UpdateExtensionAppIcon
+ // instead to let the extension give us pre-defined icons in the launcher
+ // and the launcher list sizes. Since there is no mock yet, doing this now
+ // seems a bit premature and we scale for the time being.
+ if (app_icon_.IsEmpty())
+ return new gfx::Image();
+
+ SkBitmap bmp = skia::ImageOperations::Resize(
+ *app_icon_.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
+ extension_misc::EXTENSION_ICON_SMALLISH,
+ extension_misc::EXTENSION_ICON_SMALLISH);
+ return new gfx::Image(bmp);
+}
+
NativeAppWindow* ShellWindow::GetBaseWindow() {
return native_app_window_.get();
}
diff --git a/chrome/browser/ui/extensions/shell_window.h b/chrome/browser/ui/extensions/shell_window.h
index 929d485..692c824 100644
--- a/chrome/browser/ui/extensions/shell_window.h
+++ b/chrome/browser/ui/extensions/shell_window.h
@@ -100,6 +100,11 @@ class ShellWindow : public content::NotificationObserver,
NativeAppWindow* GetBaseWindow();
gfx::NativeWindow GetNativeWindow();
+ // This will return a slightly smaller icon then the app_icon to be used in
+ // application lists. It is the responsibility of the caller to delete the
+ // returned image after use.
+ gfx::Image* GetAppListIcon();
+
// NativeAppWindows should call this to determine what the window's title
// is on startup and from within UpdateWindowTitle().
virtual string16 GetTitle() const;
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 0590ca0..0b430f4 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -235,6 +235,10 @@ class BrowserView : public BrowserWindow,
#if defined(USE_ASH)
// Test support.
+ // Note: This is only needed to be BrowserLauncherItemController instead of
+ // LauncherItemController because of the "favicon_loader" member - to be more
+ // exact that member function is the only one being called.
+ // TODO(skuhne): Remove once per-app is default.
BrowserLauncherItemController* launcher_item_controller() const {
return launcher_item_controller_.get();
}
@@ -701,6 +705,9 @@ class BrowserView : public BrowserWindow,
#endif
#if defined(USE_ASH)
+ // Needs to be BrowserLauncerItemController for
+ // "BrowserActivationStateChanged" and "favicon_loader".
+ // TODO(skuhne): Remove once per-app is default.
scoped_ptr<BrowserLauncherItemController> launcher_item_controller_;
#endif
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 6c8e2d3..285da44 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -141,8 +141,18 @@
'browser/ui/ash/extension_utils.h',
'browser/ui/ash/ime_controller_chromeos.cc',
'browser/ui/ash/ime_controller_chromeos.h',
+ 'browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc',
+ 'browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h',
'browser/ui/ash/launcher/browser_launcher_item_controller.cc',
'browser/ui/ash/launcher/browser_launcher_item_controller.h',
+ 'browser/ui/ash/launcher/chrome_launcher_app_menu_item.cc',
+ 'browser/ui/ash/launcher/chrome_launcher_app_menu_item.h',
+ 'browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc',
+ 'browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h',
+ 'browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc',
+ 'browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h',
+ 'browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc',
+ 'browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h',
'browser/ui/ash/launcher/chrome_launcher_controller.cc',
'browser/ui/ash/launcher/chrome_launcher_controller.h',
'browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc',
@@ -159,6 +169,10 @@
'browser/ui/ash/launcher/launcher_favicon_loader.h',
'browser/ui/ash/launcher/launcher_item_controller.cc',
'browser/ui/ash/launcher/launcher_item_controller.h',
+ 'browser/ui/ash/launcher/launcher_application_menu_item_model.cc',
+ 'browser/ui/ash/launcher/launcher_application_menu_item_model.h',
+ 'browser/ui/ash/launcher/shell_window_launcher_item_controller.cc',
+ 'browser/ui/ash/launcher/shell_window_launcher_item_controller.h',
'browser/ui/ash/launcher/shell_window_launcher_controller.cc',
'browser/ui/ash/launcher/shell_window_launcher_controller.h',
'browser/ui/ash/screenshot_taker.cc',
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc
index 44dec85..0bac364 100644
--- a/chrome/test/base/browser_with_test_window_test.cc
+++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -146,6 +146,16 @@ void BrowserWithTestWindowTest::NavigateAndCommitActiveTab(const GURL& url) {
url);
}
+void BrowserWithTestWindowTest::NavigateAndCommitActiveTabWithTitle(
+ Browser* navigating_browser,
+ const GURL& url,
+ const string16& title) {
+ NavigationController* controller =
+ &chrome::GetActiveWebContents(navigating_browser)->GetController();
+ NavigateAndCommit(controller, url);
+ controller->GetActiveEntry()->SetTitle(title);
+}
+
void BrowserWithTestWindowTest::DestroyBrowserAndProfile() {
if (browser_.get()) {
// Make sure we close all tabs, otherwise Browser isn't happy in its
diff --git a/chrome/test/base/browser_with_test_window_test.h b/chrome/test/base/browser_with_test_window_test.h
index e2191f9a..76d7b4c 100644
--- a/chrome/test/base/browser_with_test_window_test.h
+++ b/chrome/test/base/browser_with_test_window_test.h
@@ -97,6 +97,12 @@ class BrowserWithTestWindowTest : public testing::Test {
// Navigates the current tab. This is a wrapper around NavigateAndCommit.
void NavigateAndCommitActiveTab(const GURL& url);
+ // Set the |title| of the current tab.
+ void NavigateAndCommitActiveTabWithTitle(
+ Browser* browser,
+ const GURL& url,
+ const string16& title);
+
protected:
// Destroys the browser, window, and profile created by this class. This is
// invoked from the destructor.