browser_shortcut_launcher_item_controller.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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. 4 5#include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h" 6 7#include <vector> 8 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" 40 41BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController( 42 ChromeLauncherController* launcher_controller) 43 : LauncherItemController(TYPE_SHORTCUT, 44 extension_misc::kChromeAppId, 45 launcher_controller) { 46} 47 48BrowserShortcutLauncherItemController:: 49 ~BrowserShortcutLauncherItemController() { 50} 51 52void BrowserShortcutLauncherItemController::UpdateBrowserItemState() { 53 // The shell will not be available for win7_aura unittests like 54 // ChromeLauncherControllerTest.BrowserMenuGeneration. 55 if (!ash::Shell::HasInstance()) 56 return; 57 58 ash::ShelfModel* model = launcher_controller()->model(); 59 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; 65 66 aura::Window* window = ash::wm::GetActiveWindow(); 67 if (window) { 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 70 // interest. 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(); 78 if (contents && 79 (launcher_controller()->GetShelfIDForWebContents(contents) != 80 browser_item.id)) 81 browser_status = ash::STATUS_RUNNING; 82 } 83 } 84 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; 94 } 95 } 96 97 if (browser_status != browser_item.status) { 98 browser_item.status = browser_status; 99 model->Set(browser_index, browser_item); 100 } 101} 102 103void BrowserShortcutLauncherItemController::SetShelfIDForBrowserWindowContents( 104 Browser* browser, 105 content::WebContents* web_contents) { 106 if (!IsBrowserRepresentedInBrowserList(browser)) 107 return; 108 ash::SetShelfIDForWindow( 109 launcher_controller()->GetShelfIDForWebContents(web_contents), 110 browser->window()->GetNativeWindow()); 111} 112 113bool 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)) 119 return true; 120 } 121 return false; 122} 123 124bool BrowserShortcutLauncherItemController::IsVisible() const { 125 Browser* last_browser = chrome::FindTabbedBrowser( 126 launcher_controller()->profile(), 127 true, 128 chrome::HOST_DESKTOP_TYPE_ASH); 129 130 if (!last_browser) { 131 return false; 132 } 133 134 aura::Window* window = last_browser->window()->GetNativeWindow(); 135 return ash::wm::IsActiveWindow(window); 136} 137 138void BrowserShortcutLauncherItemController::Launch(ash::LaunchSource source, 139 int event_flags) { 140} 141 142bool BrowserShortcutLauncherItemController::Activate(ash::LaunchSource source) { 143 Browser* last_browser = chrome::FindTabbedBrowser( 144 launcher_controller()->profile(), 145 true, 146 chrome::HOST_DESKTOP_TYPE_ASH); 147 148 if (!last_browser) { 149 launcher_controller()->CreateNewWindow(); 150 return true; 151 } 152 153 launcher_controller()->ActivateWindowOrMinimizeIfActive( 154 last_browser->window(), GetApplicationList(0).size() == 2); 155 return false; 156} 157 158void BrowserShortcutLauncherItemController::Close() { 159} 160 161ChromeLauncherAppMenuItems 162BrowserShortcutLauncherItemController::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() || 178 !browser->window()) 179 continue; 180 if (browser->is_type_tabbed()) 181 found_tabbed_browser = true; 182 else if (!IsBrowserRepresentedInBrowserList(browser)) 183 continue; 184 TabStripModel* tab_strip = browser->tab_strip_model(); 185 if (tab_strip->active_index() == -1) 186 continue; 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)); 194 } else { 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)); 206 } 207 } 208 } 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) 212 items.clear(); 213 return items.Pass(); 214} 215 216bool BrowserShortcutLauncherItemController::ItemSelected( 217 const ui::Event& event) { 218 if (event.flags() & ui::EF_CONTROL_DOWN) { 219 launcher_controller()->CreateNewWindow(); 220 return true; 221 } 222 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(); 227 return false; 228 } 229 230 return Activate(ash::LAUNCH_FROM_UNKNOWN); 231} 232 233base::string16 BrowserShortcutLauncherItemController::GetTitle() { 234 return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); 235} 236 237ui::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); 242} 243 244ash::ShelfMenuModel* 245BrowserShortcutLauncherItemController::CreateApplicationMenu(int event_flags) { 246 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); 247} 248 249bool BrowserShortcutLauncherItemController::IsDraggable() { 250 return launcher_controller()->CanPin() ? true : false; 251} 252 253bool BrowserShortcutLauncherItemController::ShouldShowTooltip() { 254 return true; 255} 256 257gfx::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); 263} 264 265base::string16 BrowserShortcutLauncherItemController::GetBrowserListTitle( 266 content::WebContents* web_contents) const { 267 base::string16 title = web_contents->GetTitle(); 268 if (!title.empty()) 269 return title; 270 return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE); 271} 272 273bool BrowserShortcutLauncherItemController::IsIncognito( 274 content::WebContents* web_contents) const { 275 const Profile* profile = 276 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 277 return profile->IsOffTheRecord() && !profile->IsGuestSession(); 278} 279 280void 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 284 // order. 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); 292 } 293 // If there are no suitable browsers we create a new one. 294 if (items.empty()) { 295 launcher_controller()->CreateNewWindow(); 296 return; 297 } 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); 305 return; 306 } 307 browser = items[0]; 308 } else { 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 311 // be used. 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; 316 } else { 317 browser = chrome::FindTabbedBrowser(launcher_controller()->profile(), 318 true, 319 chrome::HOST_DESKTOP_TYPE_ASH); 320 if (!browser || 321 !IsBrowserRepresentedInBrowserList(browser)) 322 browser = items[0]; 323 } 324 } 325 DCHECK(browser); 326 browser->window()->Show(); 327 browser->window()->Activate(); 328} 329 330bool BrowserShortcutLauncherItemController::IsBrowserRepresentedInBrowserList( 331 Browser* browser) { 332 // Only Ash desktop browser windows for the active user are represented. 333 if (!browser || 334 !launcher_controller()->IsBrowserFromActiveUser(browser) || 335 browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH) 336 return false; 337 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) 343 return false; 344 345 // Stand-alone chrome:// windows (e.g. settings) have their own icon. 346 if (chrome::IsTrustedPopupWindowWithScheme(browser, content::kChromeUIScheme)) 347 return false; 348 349 // Tabbed browser and other popup windows are all represented. 350 return true; 351} 352