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/chrome_pages.h"
26 #include "chrome/browser/ui/tabs/tab_strip_model.h"
27 #include "chrome/browser/web_applications/web_app.h"
28 #include "chrome/common/extensions/extension_constants.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/url_constants.h"
31 #include "grit/ash_resources.h"
32 #include "grit/chromium_strings.h"
33 #include "grit/generated_resources.h"
34 #include "ui/aura/window.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "ui/base/resource/resource_bundle.h"
37 #include "ui/events/event.h"
38 #include "ui/gfx/image/image.h"
39 #include "ui/wm/core/window_animations.h"
41 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController(
42 ChromeLauncherController
* launcher_controller
)
43 : LauncherItemController(TYPE_SHORTCUT
,
44 extension_misc::kChromeAppId
,
45 launcher_controller
) {
48 BrowserShortcutLauncherItemController::
49 ~BrowserShortcutLauncherItemController() {
52 void BrowserShortcutLauncherItemController::UpdateBrowserItemState() {
53 // The shell will not be available for win7_aura unittests like
54 // ChromeLauncherControllerTest.BrowserMenuGeneration.
55 if (!ash::Shell::HasInstance())
58 ash::ShelfModel
* model
= launcher_controller()->model();
60 // Determine the new browser's active state and change if necessary.
61 int browser_index
= model
->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT
);
62 DCHECK_GE(browser_index
, 0);
63 ash::ShelfItem browser_item
= model
->items()[browser_index
];
64 ash::ShelfItemStatus browser_status
= ash::STATUS_CLOSED
;
66 aura::Window
* window
= ash::wm::GetActiveWindow();
68 // Check if the active browser / tab is a browser which is not an app,
69 // a windowed app, a popup or any other item which is not a browser of
71 Browser
* browser
= chrome::FindBrowserWithWindow(window
);
72 if (IsBrowserRepresentedInBrowserList(browser
)) {
73 browser_status
= ash::STATUS_ACTIVE
;
74 // If an app that has item is running in active WebContents, browser item
75 // status cannot be active.
76 content::WebContents
* contents
=
77 browser
->tab_strip_model()->GetActiveWebContents();
79 (launcher_controller()->GetShelfIDForWebContents(contents
) !=
81 browser_status
= ash::STATUS_RUNNING
;
85 if (browser_status
== ash::STATUS_CLOSED
) {
86 const BrowserList
* ash_browser_list
=
87 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH
);
88 for (BrowserList::const_reverse_iterator it
=
89 ash_browser_list
->begin_last_active();
90 it
!= ash_browser_list
->end_last_active() &&
91 browser_status
== ash::STATUS_CLOSED
; ++it
) {
92 if (IsBrowserRepresentedInBrowserList(*it
))
93 browser_status
= ash::STATUS_RUNNING
;
97 if (browser_status
!= browser_item
.status
) {
98 browser_item
.status
= browser_status
;
99 model
->Set(browser_index
, browser_item
);
103 void BrowserShortcutLauncherItemController::SetShelfIDForBrowserWindowContents(
105 content::WebContents
* web_contents
) {
106 if (!IsBrowserRepresentedInBrowserList(browser
))
108 ash::SetShelfIDForWindow(
109 launcher_controller()->GetShelfIDForWebContents(web_contents
),
110 browser
->window()->GetNativeWindow());
113 bool BrowserShortcutLauncherItemController::IsOpen() const {
114 const BrowserList
* ash_browser_list
=
115 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH
);
116 for (BrowserList::const_iterator it
= ash_browser_list
->begin();
117 it
!= ash_browser_list
->end(); ++it
) {
118 if (launcher_controller()->IsBrowserFromActiveUser(*it
))
124 bool BrowserShortcutLauncherItemController::IsVisible() const {
125 Browser
* last_browser
= chrome::FindTabbedBrowser(
126 launcher_controller()->profile(),
128 chrome::HOST_DESKTOP_TYPE_ASH
);
134 aura::Window
* window
= last_browser
->window()->GetNativeWindow();
135 return ash::wm::IsActiveWindow(window
);
138 void BrowserShortcutLauncherItemController::Launch(ash::LaunchSource source
,
142 bool BrowserShortcutLauncherItemController::Activate(ash::LaunchSource source
) {
143 Browser
* last_browser
= chrome::FindTabbedBrowser(
144 launcher_controller()->profile(),
146 chrome::HOST_DESKTOP_TYPE_ASH
);
149 launcher_controller()->CreateNewWindow();
153 launcher_controller()->ActivateWindowOrMinimizeIfActive(
154 last_browser
->window(), GetApplicationList(0).size() == 2);
158 void BrowserShortcutLauncherItemController::Close() {
161 ChromeLauncherAppMenuItems
162 BrowserShortcutLauncherItemController::GetApplicationList(int event_flags
) {
163 ChromeLauncherAppMenuItems items
;
164 bool found_tabbed_browser
= false;
165 // Add the application name to the menu.
166 items
.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL
, false));
167 const BrowserList
* ash_browser_list
=
168 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH
);
169 for (BrowserList::const_iterator it
= ash_browser_list
->begin();
170 it
!= ash_browser_list
->end(); ++it
) {
171 Browser
* browser
= *it
;
172 // Make sure that the browser was already shown, is from the current user
173 // and has a proper window.
174 if (!launcher_controller()->IsBrowserFromActiveUser(browser
) ||
175 std::find(ash_browser_list
->begin_last_active(),
176 ash_browser_list
->end_last_active(),
177 browser
) == ash_browser_list
->end_last_active() ||
180 if (browser
->is_type_tabbed())
181 found_tabbed_browser
= true;
182 else if (!IsBrowserRepresentedInBrowserList(browser
))
184 TabStripModel
* tab_strip
= browser
->tab_strip_model();
185 if (tab_strip
->active_index() == -1)
187 if (!(event_flags
& ui::EF_SHIFT_DOWN
)) {
188 content::WebContents
* web_contents
=
189 tab_strip
->GetWebContentsAt(tab_strip
->active_index());
190 gfx::Image app_icon
= GetBrowserListIcon(web_contents
);
191 base::string16 title
= GetBrowserListTitle(web_contents
);
192 items
.push_back(new ChromeLauncherAppMenuItemBrowser(
193 title
, &app_icon
, browser
, items
.size() == 1));
195 for (int index
= 0; index
< tab_strip
->count(); ++index
) {
196 content::WebContents
* web_contents
=
197 tab_strip
->GetWebContentsAt(index
);
198 gfx::Image app_icon
=
199 launcher_controller()->GetAppListIcon(web_contents
);
200 base::string16 title
=
201 launcher_controller()->GetAppListTitle(web_contents
);
202 // Check if we need to insert a separator in front.
203 bool leading_separator
= !index
;
204 items
.push_back(new ChromeLauncherAppMenuItemTab(
205 title
, &app_icon
, web_contents
, leading_separator
));
209 // If only windowed applications are open, we return an empty list to
210 // enforce the creation of a new browser.
211 if (!found_tabbed_browser
)
216 bool BrowserShortcutLauncherItemController::ItemSelected(
217 const ui::Event
& event
) {
218 if (event
.flags() & ui::EF_CONTROL_DOWN
) {
219 launcher_controller()->CreateNewWindow();
223 // In case of a keyboard event, we were called by a hotkey. In that case we
224 // activate the next item in line if an item of our list is already active.
225 if (event
.type() & ui::ET_KEY_RELEASED
) {
226 ActivateOrAdvanceToNextBrowser();
230 return Activate(ash::LAUNCH_FROM_UNKNOWN
);
233 base::string16
BrowserShortcutLauncherItemController::GetTitle() {
234 return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME
);
237 ui::MenuModel
* BrowserShortcutLauncherItemController::CreateContextMenu(
238 aura::Window
* root_window
) {
239 ash::ShelfItem item
=
240 *(launcher_controller()->model()->ItemByID(shelf_id()));
241 return new LauncherContextMenu(launcher_controller(), &item
, root_window
);
245 BrowserShortcutLauncherItemController::CreateApplicationMenu(int event_flags
) {
246 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags
));
249 bool BrowserShortcutLauncherItemController::IsDraggable() {
250 return launcher_controller()->CanPin() ? true : false;
253 bool BrowserShortcutLauncherItemController::ShouldShowTooltip() {
257 gfx::Image
BrowserShortcutLauncherItemController::GetBrowserListIcon(
258 content::WebContents
* web_contents
) const {
259 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
260 return rb
.GetImageNamed(IsIncognito(web_contents
) ?
261 IDR_ASH_SHELF_LIST_INCOGNITO_BROWSER
:
262 IDR_ASH_SHELF_LIST_BROWSER
);
265 base::string16
BrowserShortcutLauncherItemController::GetBrowserListTitle(
266 content::WebContents
* web_contents
) const {
267 base::string16 title
= web_contents
->GetTitle();
270 return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE
);
273 bool BrowserShortcutLauncherItemController::IsIncognito(
274 content::WebContents
* web_contents
) const {
275 const Profile
* profile
=
276 Profile::FromBrowserContext(web_contents
->GetBrowserContext());
277 return profile
->IsOffTheRecord() && !profile
->IsGuestSession();
280 void BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() {
281 // Create a list of all suitable running browsers.
282 std::vector
<Browser
*> items
;
283 // We use the list in the order of how the browsers got created - not the LRU
285 const BrowserList
* ash_browser_list
=
286 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH
);
287 for (BrowserList::const_iterator it
=
288 ash_browser_list
->begin();
289 it
!= ash_browser_list
->end(); ++it
) {
290 if (IsBrowserRepresentedInBrowserList(*it
))
291 items
.push_back(*it
);
293 // If there are no suitable browsers we create a new one.
295 launcher_controller()->CreateNewWindow();
298 Browser
* browser
= chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
299 if (items
.size() == 1) {
300 // If there is only one suitable browser, we can either activate it, or
301 // bounce it (if it is already active).
302 if (browser
== items
[0]) {
303 AnimateWindow(browser
->window()->GetNativeWindow(),
304 wm::WINDOW_ANIMATION_TYPE_BOUNCE
);
309 // If there is more then one suitable browser, we advance to the next if
310 // |browser| is already active - or - check the last used browser if it can
312 std::vector
<Browser
*>::iterator i
=
313 std::find(items
.begin(), items
.end(), browser
);
314 if (i
!= items
.end()) {
315 browser
= (++i
== items
.end()) ? items
[0] : *i
;
317 browser
= chrome::FindTabbedBrowser(launcher_controller()->profile(),
319 chrome::HOST_DESKTOP_TYPE_ASH
);
321 !IsBrowserRepresentedInBrowserList(browser
))
326 browser
->window()->Show();
327 browser
->window()->Activate();
330 bool BrowserShortcutLauncherItemController::IsBrowserRepresentedInBrowserList(
332 // Only Ash desktop browser windows for the active user are represented.
334 !launcher_controller()->IsBrowserFromActiveUser(browser
) ||
335 browser
->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH
)
338 // v1 App popup windows with a valid app id have their own icon.
339 if (browser
->is_app() &&
340 browser
->is_type_popup() &&
341 launcher_controller()->GetShelfIDForAppID(
342 web_app::GetExtensionIdFromApplicationName(browser
->app_name())) > 0)
345 // Stand-alone chrome:// windows (e.g. settings) have their own icon.
346 if (chrome::IsTrustedPopupWindowWithScheme(browser
, content::kChromeUIScheme
))
349 // Tabbed browser and other popup windows are all represented.