1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
9 #include "ash/shelf/shelf.h"
10 #include "ash/shelf/shelf_model.h"
11 #include "ash/shelf/shelf_util.h"
12 #include "ash/shell.h"
13 #include "ash/wm/window_util.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
16 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
17 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
18 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
19 #include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
20 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_finder.h"
23 #include "chrome/browser/ui/browser_list.h"
24 #include "chrome/browser/ui/browser_window.h"
25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/browser/web_applications/web_app.h"
27 #include "chrome/common/extensions/extension_constants.h"
28 #include "content/public/browser/web_contents.h"
29 #include "grit/ash_resources.h"
30 #include "grit/chromium_strings.h"
31 #include "grit/generated_resources.h"
32 #include "ui/aura/window.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/base/resource/resource_bundle.h"
35 #include "ui/events/event.h"
36 #include "ui/gfx/image/image.h"
37 #include "ui/views/corewm/window_animations.h"
39 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController(
40 ChromeLauncherController
* launcher_controller
)
41 : LauncherItemController(TYPE_SHORTCUT
,
42 extension_misc::kChromeAppId
,
43 launcher_controller
) {
46 BrowserShortcutLauncherItemController::
47 ~BrowserShortcutLauncherItemController() {
50 void BrowserShortcutLauncherItemController::UpdateBrowserItemState() {
51 // The shell will not be available for win7_aura unittests like
52 // ChromeLauncherControllerTest.BrowserMenuGeneration.
53 if (!ash::Shell::HasInstance())
56 ash::ShelfModel
* model
= launcher_controller()->model();
58 // Determine the new browser's active state and change if necessary.
59 int browser_index
= model
->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT
);
60 DCHECK_GE(browser_index
, 0);
61 ash::LauncherItem browser_item
= model
->items()[browser_index
];
62 ash::LauncherItemStatus browser_status
= ash::STATUS_CLOSED
;
64 aura::Window
* window
= ash::wm::GetActiveWindow();
66 // Check if the active browser / tab is a browser which is not an app,
67 // a windowed app, a popup or any other item which is not a browser of
69 Browser
* browser
= chrome::FindBrowserWithWindow(window
);
70 if (IsBrowserRepresentedInBrowserList(browser
)) {
71 browser_status
= ash::STATUS_ACTIVE
;
72 // If an app that has item is running in active WebContents, browser item
73 // status cannot be active.
74 content::WebContents
* contents
=
75 browser
->tab_strip_model()->GetActiveWebContents();
77 (launcher_controller()->GetLauncherIDForWebContents(contents
) !=
79 browser_status
= ash::STATUS_RUNNING
;
83 if (browser_status
== ash::STATUS_CLOSED
) {
84 const BrowserList
* ash_browser_list
=
85 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH
);
86 for (BrowserList::const_reverse_iterator it
=
87 ash_browser_list
->begin_last_active();
88 it
!= ash_browser_list
->end_last_active() &&
89 browser_status
== ash::STATUS_CLOSED
; ++it
) {
90 if (IsBrowserRepresentedInBrowserList(*it
))
91 browser_status
= ash::STATUS_RUNNING
;
95 if (browser_status
!= browser_item
.status
) {
96 browser_item
.status
= browser_status
;
97 model
->Set(browser_index
, browser_item
);
101 bool BrowserShortcutLauncherItemController::IsOpen() const {
102 const BrowserList
* ash_browser_list
=
103 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH
);
104 for (BrowserList::const_iterator it
= ash_browser_list
->begin();
105 it
!= ash_browser_list
->end(); ++it
) {
106 if (launcher_controller()->IsBrowserFromActiveUser(*it
))
112 bool BrowserShortcutLauncherItemController::IsVisible() const {
113 Browser
* last_browser
= chrome::FindTabbedBrowser(
114 launcher_controller()->profile(),
116 chrome::HOST_DESKTOP_TYPE_ASH
);
122 aura::Window
* window
= last_browser
->window()->GetNativeWindow();
123 return ash::wm::IsActiveWindow(window
);
126 void BrowserShortcutLauncherItemController::Launch(ash::LaunchSource source
,
130 bool BrowserShortcutLauncherItemController::Activate(ash::LaunchSource source
) {
131 Browser
* last_browser
= chrome::FindTabbedBrowser(
132 launcher_controller()->profile(),
134 chrome::HOST_DESKTOP_TYPE_ASH
);
137 launcher_controller()->CreateNewWindow();
141 launcher_controller()->ActivateWindowOrMinimizeIfActive(
142 last_browser
->window(), GetApplicationList(0).size() == 2);
146 void BrowserShortcutLauncherItemController::Close() {
149 ChromeLauncherAppMenuItems
150 BrowserShortcutLauncherItemController::GetApplicationList(int event_flags
) {
151 ChromeLauncherAppMenuItems items
;
152 bool found_tabbed_browser
= false;
153 // Add the application name to the menu.
154 items
.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL
, false));
155 const BrowserList
* ash_browser_list
=
156 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH
);
157 for (BrowserList::const_iterator it
= ash_browser_list
->begin();
158 it
!= ash_browser_list
->end(); ++it
) {
159 Browser
* browser
= *it
;
160 // Make sure that the browser was already shown, is from the current user
161 // and has a proper window.
162 if (!launcher_controller()->IsBrowserFromActiveUser(browser
) ||
163 std::find(ash_browser_list
->begin_last_active(),
164 ash_browser_list
->end_last_active(),
165 browser
) == ash_browser_list
->end_last_active() ||
168 if (browser
->is_type_tabbed())
169 found_tabbed_browser
= true;
170 else if (!IsBrowserRepresentedInBrowserList(browser
))
172 TabStripModel
* tab_strip
= browser
->tab_strip_model();
173 if (tab_strip
->active_index() == -1)
175 if (!(event_flags
& ui::EF_SHIFT_DOWN
)) {
176 content::WebContents
* web_contents
=
177 tab_strip
->GetWebContentsAt(tab_strip
->active_index());
178 gfx::Image app_icon
= GetBrowserListIcon(web_contents
);
179 base::string16 title
= GetBrowserListTitle(web_contents
);
180 items
.push_back(new ChromeLauncherAppMenuItemBrowser(
181 title
, &app_icon
, browser
, items
.size() == 1));
183 for (int index
= 0; index
< tab_strip
->count(); ++index
) {
184 content::WebContents
* web_contents
=
185 tab_strip
->GetWebContentsAt(index
);
186 gfx::Image app_icon
=
187 launcher_controller()->GetAppListIcon(web_contents
);
188 base::string16 title
=
189 launcher_controller()->GetAppListTitle(web_contents
);
190 // Check if we need to insert a separator in front.
191 bool leading_separator
= !index
;
192 items
.push_back(new ChromeLauncherAppMenuItemTab(
193 title
, &app_icon
, web_contents
, leading_separator
));
197 // If only windowed applications are open, we return an empty list to
198 // enforce the creation of a new browser.
199 if (!found_tabbed_browser
)
204 bool BrowserShortcutLauncherItemController::ItemSelected(
205 const ui::Event
& event
) {
206 if (event
.flags() & ui::EF_CONTROL_DOWN
) {
207 launcher_controller()->CreateNewWindow();
211 // In case of a keyboard event, we were called by a hotkey. In that case we
212 // activate the next item in line if an item of our list is already active.
213 if (event
.type() & ui::ET_KEY_RELEASED
) {
214 ActivateOrAdvanceToNextBrowser();
218 return Activate(ash::LAUNCH_FROM_UNKNOWN
);
221 base::string16
BrowserShortcutLauncherItemController::GetTitle() {
222 return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME
);
225 ui::MenuModel
* BrowserShortcutLauncherItemController::CreateContextMenu(
226 aura::Window
* root_window
) {
227 ash::LauncherItem item
=
228 *(launcher_controller()->model()->ItemByID(launcher_id()));
229 return new LauncherContextMenu(launcher_controller(), &item
, root_window
);
233 BrowserShortcutLauncherItemController::CreateApplicationMenu(int event_flags
) {
234 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags
));
237 bool BrowserShortcutLauncherItemController::IsDraggable() {
238 return launcher_controller()->CanPin() ? true : false;
241 bool BrowserShortcutLauncherItemController::ShouldShowTooltip() {
245 gfx::Image
BrowserShortcutLauncherItemController::GetBrowserListIcon(
246 content::WebContents
* web_contents
) const {
247 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
248 return rb
.GetImageNamed(IsIncognito(web_contents
) ?
249 IDR_AURA_LAUNCHER_LIST_INCOGNITO_BROWSER
:
250 IDR_AURA_LAUNCHER_LIST_BROWSER
);
253 base::string16
BrowserShortcutLauncherItemController::GetBrowserListTitle(
254 content::WebContents
* web_contents
) const {
255 base::string16 title
= web_contents
->GetTitle();
258 return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE
);
261 bool BrowserShortcutLauncherItemController::IsIncognito(
262 content::WebContents
* web_contents
) const {
263 const Profile
* profile
=
264 Profile::FromBrowserContext(web_contents
->GetBrowserContext());
265 return profile
->IsOffTheRecord() && !profile
->IsGuestSession();
268 void BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() {
269 // Create a list of all suitable running browsers.
270 std::vector
<Browser
*> items
;
271 // We use the list in the order of how the browsers got created - not the LRU
273 const BrowserList
* ash_browser_list
=
274 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH
);
275 for (BrowserList::const_iterator it
=
276 ash_browser_list
->begin();
277 it
!= ash_browser_list
->end(); ++it
) {
278 if (IsBrowserRepresentedInBrowserList(*it
))
279 items
.push_back(*it
);
281 // If there are no suitable browsers we create a new one.
283 launcher_controller()->CreateNewWindow();
286 Browser
* browser
= chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
287 if (items
.size() == 1) {
288 // If there is only one suitable browser, we can either activate it, or
289 // bounce it (if it is already active).
290 if (browser
== items
[0]) {
291 AnimateWindow(browser
->window()->GetNativeWindow(),
292 views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE
);
297 // If there is more then one suitable browser, we advance to the next if
298 // |browser| is already active - or - check the last used browser if it can
300 std::vector
<Browser
*>::iterator i
=
301 std::find(items
.begin(), items
.end(), browser
);
302 if (i
!= items
.end()) {
303 browser
= (++i
== items
.end()) ? items
[0] : *i
;
305 browser
= chrome::FindTabbedBrowser(launcher_controller()->profile(),
307 chrome::HOST_DESKTOP_TYPE_ASH
);
309 !IsBrowserRepresentedInBrowserList(browser
))
314 browser
->window()->Show();
315 browser
->window()->Activate();
318 bool BrowserShortcutLauncherItemController::IsBrowserRepresentedInBrowserList(
321 launcher_controller()->IsBrowserFromActiveUser(browser
) &&
322 browser
->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH
&&
323 (browser
->is_type_tabbed() ||
324 !browser
->is_app() ||
325 !browser
->is_type_popup() ||
326 launcher_controller()->
327 GetLauncherIDForAppID(web_app::GetExtensionIdFromApplicationName(
328 browser
->app_name())) <= 0));