Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / ash / launcher / browser_shortcut_launcher_item_controller.cc
blob83668d1f98196362f0588ef0fe4e24c28b871c4c
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"
7 #include <vector>
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 namespace {
44 bool IsSettingsBrowser(Browser* browser) {
45 // Normally this test is sufficient. TODO(stevenjb): Replace this with a
46 // better mechanism (Settings WebUI or Browser type).
47 if (chrome::IsTrustedPopupWindowWithScheme(browser, content::kChromeUIScheme))
48 return true;
49 // If a settings window navigates away from a kChromeUIScheme (e.g. after a
50 // crash), the above may not be true, so also test against the known list
51 // of settings browsers (which will not be valid during chrome::Navigate
52 // which is why we still need the above test).
53 if (chrome::SettingsWindowManager::GetInstance()->IsSettingsBrowser(browser))
54 return true;
55 return false;
58 } // namespace
60 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController(
61 ChromeLauncherController* launcher_controller)
62 : LauncherItemController(TYPE_SHORTCUT,
63 extension_misc::kChromeAppId,
64 launcher_controller) {
67 BrowserShortcutLauncherItemController::
68 ~BrowserShortcutLauncherItemController() {
71 void BrowserShortcutLauncherItemController::UpdateBrowserItemState() {
72 // The shell will not be available for win7_aura unittests like
73 // ChromeLauncherControllerTest.BrowserMenuGeneration.
74 if (!ash::Shell::HasInstance())
75 return;
77 ash::ShelfModel* model = launcher_controller()->model();
79 // Determine the new browser's active state and change if necessary.
80 int browser_index = model->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT);
81 DCHECK_GE(browser_index, 0);
82 ash::ShelfItem browser_item = model->items()[browser_index];
83 ash::ShelfItemStatus browser_status = ash::STATUS_CLOSED;
85 aura::Window* window = ash::wm::GetActiveWindow();
86 if (window) {
87 // Check if the active browser / tab is a browser which is not an app,
88 // a windowed app, a popup or any other item which is not a browser of
89 // interest.
90 Browser* browser = chrome::FindBrowserWithWindow(window);
91 if (IsBrowserRepresentedInBrowserList(browser)) {
92 browser_status = ash::STATUS_ACTIVE;
93 // If an app that has item is running in active WebContents, browser item
94 // status cannot be active.
95 content::WebContents* contents =
96 browser->tab_strip_model()->GetActiveWebContents();
97 if (contents &&
98 (launcher_controller()->GetShelfIDForWebContents(contents) !=
99 browser_item.id))
100 browser_status = ash::STATUS_RUNNING;
104 if (browser_status == ash::STATUS_CLOSED) {
105 const BrowserList* ash_browser_list =
106 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
107 for (BrowserList::const_reverse_iterator it =
108 ash_browser_list->begin_last_active();
109 it != ash_browser_list->end_last_active() &&
110 browser_status == ash::STATUS_CLOSED; ++it) {
111 if (IsBrowserRepresentedInBrowserList(*it))
112 browser_status = ash::STATUS_RUNNING;
116 if (browser_status != browser_item.status) {
117 browser_item.status = browser_status;
118 model->Set(browser_index, browser_item);
122 void BrowserShortcutLauncherItemController::SetShelfIDForBrowserWindowContents(
123 Browser* browser,
124 content::WebContents* web_contents) {
125 // We need to call SetShelfIDForWindow for V1 applications since they are
126 // content which might change and as such change the application type.
127 if (!browser ||
128 !launcher_controller()->IsBrowserFromActiveUser(browser) ||
129 browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH ||
130 IsSettingsBrowser(browser))
131 return;
133 ash::SetShelfIDForWindow(
134 launcher_controller()->GetShelfIDForWebContents(web_contents),
135 browser->window()->GetNativeWindow());
138 bool BrowserShortcutLauncherItemController::IsOpen() const {
139 const BrowserList* ash_browser_list =
140 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
141 for (BrowserList::const_iterator it = ash_browser_list->begin();
142 it != ash_browser_list->end(); ++it) {
143 if (launcher_controller()->IsBrowserFromActiveUser(*it))
144 return true;
146 return false;
149 bool BrowserShortcutLauncherItemController::IsVisible() const {
150 Browser* last_browser = chrome::FindTabbedBrowser(
151 launcher_controller()->profile(),
152 true,
153 chrome::HOST_DESKTOP_TYPE_ASH);
155 if (!last_browser) {
156 return false;
159 aura::Window* window = last_browser->window()->GetNativeWindow();
160 return ash::wm::IsActiveWindow(window);
163 void BrowserShortcutLauncherItemController::Launch(ash::LaunchSource source,
164 int event_flags) {
167 ash::ShelfItemDelegate::PerformedAction
168 BrowserShortcutLauncherItemController::Activate(ash::LaunchSource source) {
169 Browser* last_browser = chrome::FindTabbedBrowser(
170 launcher_controller()->profile(),
171 true,
172 chrome::HOST_DESKTOP_TYPE_ASH);
174 if (!last_browser) {
175 launcher_controller()->CreateNewWindow();
176 return kNewWindowCreated;
179 return launcher_controller()->ActivateWindowOrMinimizeIfActive(
180 last_browser->window(), GetApplicationList(0).size() == 2);
183 void BrowserShortcutLauncherItemController::Close() {
186 ChromeLauncherAppMenuItems
187 BrowserShortcutLauncherItemController::GetApplicationList(int event_flags) {
188 ChromeLauncherAppMenuItems items;
189 bool found_tabbed_browser = false;
190 // Add the application name to the menu.
191 items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false));
192 const BrowserList* ash_browser_list =
193 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
194 for (BrowserList::const_iterator it = ash_browser_list->begin();
195 it != ash_browser_list->end(); ++it) {
196 Browser* browser = *it;
197 // Make sure that the browser is from the current user, has a proper window,
198 // and the window was already shown.
199 if (!launcher_controller()->IsBrowserFromActiveUser(browser))
200 continue;
201 if (!(browser->window() && browser->window()->GetNativeWindow()))
202 continue;
203 if (!(browser->window()->GetNativeWindow()->IsVisible() ||
204 browser->window()->IsMinimized())) {
205 continue;
207 if (browser->is_type_tabbed())
208 found_tabbed_browser = true;
209 else if (!IsBrowserRepresentedInBrowserList(browser))
210 continue;
211 TabStripModel* tab_strip = browser->tab_strip_model();
212 if (tab_strip->active_index() == -1)
213 continue;
214 if (!(event_flags & ui::EF_SHIFT_DOWN)) {
215 content::WebContents* web_contents =
216 tab_strip->GetWebContentsAt(tab_strip->active_index());
217 gfx::Image app_icon = GetBrowserListIcon(web_contents);
218 base::string16 title = GetBrowserListTitle(web_contents);
219 items.push_back(new ChromeLauncherAppMenuItemBrowser(
220 title, &app_icon, browser, items.size() == 1));
221 } else {
222 for (int index = 0; index < tab_strip->count(); ++index) {
223 content::WebContents* web_contents =
224 tab_strip->GetWebContentsAt(index);
225 gfx::Image app_icon =
226 launcher_controller()->GetAppListIcon(web_contents);
227 base::string16 title =
228 launcher_controller()->GetAppListTitle(web_contents);
229 // Check if we need to insert a separator in front.
230 bool leading_separator = !index;
231 items.push_back(new ChromeLauncherAppMenuItemTab(
232 title, &app_icon, web_contents, leading_separator));
236 // If only windowed applications are open, we return an empty list to
237 // enforce the creation of a new browser.
238 if (!found_tabbed_browser)
239 items.clear();
240 return items.Pass();
243 ash::ShelfItemDelegate::PerformedAction
244 BrowserShortcutLauncherItemController::ItemSelected(const ui::Event& event) {
245 if (event.flags() & ui::EF_CONTROL_DOWN) {
246 launcher_controller()->CreateNewWindow();
247 return kNewWindowCreated;
250 // In case of a keyboard event, we were called by a hotkey. In that case we
251 // activate the next item in line if an item of our list is already active.
252 if (event.type() & ui::ET_KEY_RELEASED) {
253 return ActivateOrAdvanceToNextBrowser();
256 return Activate(ash::LAUNCH_FROM_UNKNOWN);
259 base::string16 BrowserShortcutLauncherItemController::GetTitle() {
260 return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
263 ui::MenuModel* BrowserShortcutLauncherItemController::CreateContextMenu(
264 aura::Window* root_window) {
265 ash::ShelfItem item =
266 *(launcher_controller()->model()->ItemByID(shelf_id()));
267 return new LauncherContextMenu(launcher_controller(), &item, root_window);
270 ash::ShelfMenuModel*
271 BrowserShortcutLauncherItemController::CreateApplicationMenu(int event_flags) {
272 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags));
275 bool BrowserShortcutLauncherItemController::IsDraggable() {
276 return launcher_controller()->CanPin() ? true : false;
279 bool BrowserShortcutLauncherItemController::ShouldShowTooltip() {
280 return true;
283 gfx::Image BrowserShortcutLauncherItemController::GetBrowserListIcon(
284 content::WebContents* web_contents) const {
285 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
286 return rb.GetImageNamed(IsIncognito(web_contents) ?
287 IDR_ASH_SHELF_LIST_INCOGNITO_BROWSER :
288 IDR_ASH_SHELF_LIST_BROWSER);
291 base::string16 BrowserShortcutLauncherItemController::GetBrowserListTitle(
292 content::WebContents* web_contents) const {
293 base::string16 title = web_contents->GetTitle();
294 if (!title.empty())
295 return title;
296 return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
299 bool BrowserShortcutLauncherItemController::IsIncognito(
300 content::WebContents* web_contents) const {
301 const Profile* profile =
302 Profile::FromBrowserContext(web_contents->GetBrowserContext());
303 return profile->IsOffTheRecord() && !profile->IsGuestSession();
306 ash::ShelfItemDelegate::PerformedAction
307 BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() {
308 // Create a list of all suitable running browsers.
309 std::vector<Browser*> items;
310 // We use the list in the order of how the browsers got created - not the LRU
311 // order.
312 const BrowserList* ash_browser_list =
313 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
314 for (BrowserList::const_iterator it =
315 ash_browser_list->begin();
316 it != ash_browser_list->end(); ++it) {
317 if (IsBrowserRepresentedInBrowserList(*it))
318 items.push_back(*it);
320 // If there are no suitable browsers we create a new one.
321 if (items.empty()) {
322 launcher_controller()->CreateNewWindow();
323 return kNewWindowCreated;
325 Browser* browser = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
326 if (items.size() == 1) {
327 // If there is only one suitable browser, we can either activate it, or
328 // bounce it (if it is already active).
329 if (browser == items[0]) {
330 AnimateWindow(browser->window()->GetNativeWindow(),
331 wm::WINDOW_ANIMATION_TYPE_BOUNCE);
332 return kNoAction;
334 browser = items[0];
335 } else {
336 // If there is more then one suitable browser, we advance to the next if
337 // |browser| is already active - or - check the last used browser if it can
338 // be used.
339 std::vector<Browser*>::iterator i =
340 std::find(items.begin(), items.end(), browser);
341 if (i != items.end()) {
342 browser = (++i == items.end()) ? items[0] : *i;
343 } else {
344 browser = chrome::FindTabbedBrowser(launcher_controller()->profile(),
345 true,
346 chrome::HOST_DESKTOP_TYPE_ASH);
347 if (!browser ||
348 !IsBrowserRepresentedInBrowserList(browser))
349 browser = items[0];
352 DCHECK(browser);
353 browser->window()->Show();
354 browser->window()->Activate();
355 return kExistingWindowActivated;
358 bool BrowserShortcutLauncherItemController::IsBrowserRepresentedInBrowserList(
359 Browser* browser) {
360 // Only Ash desktop browser windows for the active user are represented.
361 if (!browser ||
362 !launcher_controller()->IsBrowserFromActiveUser(browser) ||
363 browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
364 return false;
366 // v1 App popup windows with a valid app id have their own icon.
367 if (browser->is_app() &&
368 browser->is_type_popup() &&
369 launcher_controller()->GetShelfIDForAppID(
370 web_app::GetExtensionIdFromApplicationName(browser->app_name())) > 0)
371 return false;
373 // Settings browsers have their own icon.
374 if (IsSettingsBrowser(browser))
375 return false;
377 // Tabbed browser and other popup windows are all represented.
378 return true;