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/settings_window_manager.h"
27 #include "chrome/browser/ui/tabs/tab_strip_model.h"
28 #include "chrome/browser/web_applications/web_app.h"
29 #include "chrome/common/extensions/extension_constants.h"
30 #include "chrome/grit/chromium_strings.h"
31 #include "chrome/grit/generated_resources.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/common/url_constants.h"
34 #include "grit/ash_resources.h"
35 #include "ui/aura/window.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/base/resource/resource_bundle.h"
38 #include "ui/events/event.h"
39 #include "ui/gfx/image/image.h"
40 #include "ui/wm/core/window_animations.h"
42 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController(
43 ChromeLauncherController* launcher_controller)
44 : LauncherItemController(TYPE_SHORTCUT,
45 extension_misc::kChromeAppId,
46 launcher_controller) {
49 BrowserShortcutLauncherItemController::
50 ~BrowserShortcutLauncherItemController() {
53 void BrowserShortcutLauncherItemController::UpdateBrowserItemState() {
54 // The shell will not be available for win7_aura unittests like
55 // ChromeLauncherControllerTest.BrowserMenuGeneration.
56 if (!ash::Shell::HasInstance())
59 ash::ShelfModel* model = launcher_controller()->model();
61 // Determine the new browser's active state and change if necessary.
62 int browser_index = model->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT);
63 DCHECK_GE(browser_index, 0);
64 ash::ShelfItem browser_item = model->items()[browser_index];
65 ash::ShelfItemStatus browser_status = ash::STATUS_CLOSED;
67 aura::Window* window = ash::wm::GetActiveWindow();
69 // Check if the active browser / tab is a browser which is not an app,
70 // a windowed app, a popup or any other item which is not a browser of
72 Browser* browser = chrome::FindBrowserWithWindow(window);
73 if (IsBrowserRepresentedInBrowserList(browser)) {
74 browser_status = ash::STATUS_ACTIVE;
75 // If an app that has item is running in active WebContents, browser item
76 // status cannot be active.
77 content::WebContents* contents =
78 browser->tab_strip_model()->GetActiveWebContents();
80 (launcher_controller()->GetShelfIDForWebContents(contents) !=
82 browser_status = ash::STATUS_RUNNING;
86 if (browser_status == ash::STATUS_CLOSED) {
87 const BrowserList* ash_browser_list =
88 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
89 for (BrowserList::const_reverse_iterator it =
90 ash_browser_list->begin_last_active();
91 it != ash_browser_list->end_last_active() &&
92 browser_status == ash::STATUS_CLOSED; ++it) {
93 if (IsBrowserRepresentedInBrowserList(*it))
94 browser_status = ash::STATUS_RUNNING;
98 if (browser_status != browser_item.status) {
99 browser_item.status = browser_status;
100 model->Set(browser_index, browser_item);
104 void BrowserShortcutLauncherItemController::SetShelfIDForBrowserWindowContents(
106 content::WebContents* web_contents) {
107 // We need to call SetShelfIDForWindow for V1 applications since they are
108 // content which might change and as such change the application type.
110 !launcher_controller()->IsBrowserFromActiveUser(browser) ||
111 browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH ||
112 chrome::IsTrustedPopupWindowWithScheme(browser, content::kChromeUIScheme))
115 ash::SetShelfIDForWindow(
116 launcher_controller()->GetShelfIDForWebContents(web_contents),
117 browser->window()->GetNativeWindow());
120 bool BrowserShortcutLauncherItemController::IsOpen() const {
121 const BrowserList* ash_browser_list =
122 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
123 for (BrowserList::const_iterator it = ash_browser_list->begin();
124 it != ash_browser_list->end(); ++it) {
125 if (launcher_controller()->IsBrowserFromActiveUser(*it))
131 bool BrowserShortcutLauncherItemController::IsVisible() const {
132 Browser* last_browser = chrome::FindTabbedBrowser(
133 launcher_controller()->profile(),
135 chrome::HOST_DESKTOP_TYPE_ASH);
141 aura::Window* window = last_browser->window()->GetNativeWindow();
142 return ash::wm::IsActiveWindow(window);
145 void BrowserShortcutLauncherItemController::Launch(ash::LaunchSource source,
149 bool BrowserShortcutLauncherItemController::Activate(ash::LaunchSource source) {
150 Browser* last_browser = chrome::FindTabbedBrowser(
151 launcher_controller()->profile(),
153 chrome::HOST_DESKTOP_TYPE_ASH);
156 launcher_controller()->CreateNewWindow();
160 launcher_controller()->ActivateWindowOrMinimizeIfActive(
161 last_browser->window(), GetApplicationList(0).size() == 2);
165 void BrowserShortcutLauncherItemController::Close() {
168 ChromeLauncherAppMenuItems
169 BrowserShortcutLauncherItemController::GetApplicationList(int event_flags) {
170 ChromeLauncherAppMenuItems items;
171 bool found_tabbed_browser = false;
172 // Add the application name to the menu.
173 items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false));
174 const BrowserList* ash_browser_list =
175 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
176 for (BrowserList::const_iterator it = ash_browser_list->begin();
177 it != ash_browser_list->end(); ++it) {
178 Browser* browser = *it;
179 // Make sure that the browser was already shown, is from the current user
180 // and has a proper window.
181 if (!launcher_controller()->IsBrowserFromActiveUser(browser) ||
182 std::find(ash_browser_list->begin_last_active(),
183 ash_browser_list->end_last_active(),
184 browser) == ash_browser_list->end_last_active() ||
187 if (browser->is_type_tabbed())
188 found_tabbed_browser = true;
189 else if (!IsBrowserRepresentedInBrowserList(browser))
191 TabStripModel* tab_strip = browser->tab_strip_model();
192 if (tab_strip->active_index() == -1)
194 if (!(event_flags & ui::EF_SHIFT_DOWN)) {
195 content::WebContents* web_contents =
196 tab_strip->GetWebContentsAt(tab_strip->active_index());
197 gfx::Image app_icon = GetBrowserListIcon(web_contents);
198 base::string16 title = GetBrowserListTitle(web_contents);
199 items.push_back(new ChromeLauncherAppMenuItemBrowser(
200 title, &app_icon, browser, items.size() == 1));
202 for (int index = 0; index < tab_strip->count(); ++index) {
203 content::WebContents* web_contents =
204 tab_strip->GetWebContentsAt(index);
205 gfx::Image app_icon =
206 launcher_controller()->GetAppListIcon(web_contents);
207 base::string16 title =
208 launcher_controller()->GetAppListTitle(web_contents);
209 // Check if we need to insert a separator in front.
210 bool leading_separator = !index;
211 items.push_back(new ChromeLauncherAppMenuItemTab(
212 title, &app_icon, web_contents, leading_separator));
216 // If only windowed applications are open, we return an empty list to
217 // enforce the creation of a new browser.
218 if (!found_tabbed_browser)
223 bool BrowserShortcutLauncherItemController::ItemSelected(
224 const ui::Event& event) {
225 if (event.flags() & ui::EF_CONTROL_DOWN) {
226 launcher_controller()->CreateNewWindow();
230 // In case of a keyboard event, we were called by a hotkey. In that case we
231 // activate the next item in line if an item of our list is already active.
232 if (event.type() & ui::ET_KEY_RELEASED) {
233 ActivateOrAdvanceToNextBrowser();
237 return Activate(ash::LAUNCH_FROM_UNKNOWN);
240 base::string16 BrowserShortcutLauncherItemController::GetTitle() {
241 return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
244 ui::MenuModel* BrowserShortcutLauncherItemController::CreateContextMenu(
245 aura::Window* root_window) {
246 ash::ShelfItem item =
247 *(launcher_controller()->model()->ItemByID(shelf_id()));
248 return new LauncherContextMenu(launcher_controller(), &item, root_window);
252 BrowserShortcutLauncherItemController::CreateApplicationMenu(int event_flags) {
253 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags));
256 bool BrowserShortcutLauncherItemController::IsDraggable() {
257 return launcher_controller()->CanPin() ? true : false;
260 bool BrowserShortcutLauncherItemController::ShouldShowTooltip() {
264 gfx::Image BrowserShortcutLauncherItemController::GetBrowserListIcon(
265 content::WebContents* web_contents) const {
266 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
267 return rb.GetImageNamed(IsIncognito(web_contents) ?
268 IDR_ASH_SHELF_LIST_INCOGNITO_BROWSER :
269 IDR_ASH_SHELF_LIST_BROWSER);
272 base::string16 BrowserShortcutLauncherItemController::GetBrowserListTitle(
273 content::WebContents* web_contents) const {
274 base::string16 title = web_contents->GetTitle();
277 return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
280 bool BrowserShortcutLauncherItemController::IsIncognito(
281 content::WebContents* web_contents) const {
282 const Profile* profile =
283 Profile::FromBrowserContext(web_contents->GetBrowserContext());
284 return profile->IsOffTheRecord() && !profile->IsGuestSession();
287 void BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() {
288 // Create a list of all suitable running browsers.
289 std::vector<Browser*> items;
290 // We use the list in the order of how the browsers got created - not the LRU
292 const BrowserList* ash_browser_list =
293 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
294 for (BrowserList::const_iterator it =
295 ash_browser_list->begin();
296 it != ash_browser_list->end(); ++it) {
297 if (IsBrowserRepresentedInBrowserList(*it))
298 items.push_back(*it);
300 // If there are no suitable browsers we create a new one.
302 launcher_controller()->CreateNewWindow();
305 Browser* browser = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
306 if (items.size() == 1) {
307 // If there is only one suitable browser, we can either activate it, or
308 // bounce it (if it is already active).
309 if (browser == items[0]) {
310 AnimateWindow(browser->window()->GetNativeWindow(),
311 wm::WINDOW_ANIMATION_TYPE_BOUNCE);
316 // If there is more then one suitable browser, we advance to the next if
317 // |browser| is already active - or - check the last used browser if it can
319 std::vector<Browser*>::iterator i =
320 std::find(items.begin(), items.end(), browser);
321 if (i != items.end()) {
322 browser = (++i == items.end()) ? items[0] : *i;
324 browser = chrome::FindTabbedBrowser(launcher_controller()->profile(),
326 chrome::HOST_DESKTOP_TYPE_ASH);
328 !IsBrowserRepresentedInBrowserList(browser))
333 browser->window()->Show();
334 browser->window()->Activate();
337 bool BrowserShortcutLauncherItemController::IsBrowserRepresentedInBrowserList(
339 // Only Ash desktop browser windows for the active user are represented.
341 !launcher_controller()->IsBrowserFromActiveUser(browser) ||
342 browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
345 // v1 App popup windows with a valid app id have their own icon.
346 if (browser->is_app() &&
347 browser->is_type_popup() &&
348 launcher_controller()->GetShelfIDForAppID(
349 web_app::GetExtensionIdFromApplicationName(browser->app_name())) > 0)
352 // Stand-alone chrome:// windows (e.g. settings) have their own icon.
353 if (chrome::IsTrustedPopupWindowWithScheme(browser, content::kChromeUIScheme))
356 // Tabbed browser and other popup windows are all represented.