browser_shortcut_launcher_item_controller.cc revision bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3
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/launcher/launcher.h"
10#include "ash/shell.h"
11#include "ash/wm/window_util.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
14#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
15#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
16#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
17#include "chrome/browser/ui/browser.h"
18#include "chrome/browser/ui/browser_finder.h"
19#include "chrome/browser/ui/browser_list.h"
20#include "chrome/browser/ui/browser_window.h"
21#include "chrome/browser/ui/tabs/tab_strip_model.h"
22#include "chrome/common/extensions/extension_constants.h"
23#include "content/public/browser/web_contents.h"
24#include "grit/ash_resources.h"
25#include "grit/chromium_strings.h"
26#include "grit/generated_resources.h"
27#include "ui/aura/window.h"
28#include "ui/base/events/event.h"
29#include "ui/base/l10n/l10n_util.h"
30#include "ui/base/resource/resource_bundle.h"
31#include "ui/gfx/image/image.h"
32#include "ui/views/corewm/window_animations.h"
33
34#if defined(OS_CHROMEOS)
35#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h"
36#endif
37
38BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController(
39    ChromeLauncherControllerPerApp* launcher_controller,
40    Profile* profile)
41    : LauncherItemController(TYPE_SHORTCUT,
42                             extension_misc::kChromeAppId,
43                             launcher_controller),
44      app_controller_(launcher_controller),
45      profile_(profile) {
46}
47
48string16 BrowserShortcutLauncherItemController::GetTitle() {
49  return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
50}
51
52bool BrowserShortcutLauncherItemController::HasWindow(
53    aura::Window* window) const {
54  const BrowserList* ash_browser_list =
55      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
56  for (BrowserList::const_iterator it = ash_browser_list->begin();
57       it != ash_browser_list->end(); ++it) {
58    // During browser creation it is possible that this function is called
59    // before a browser got a window (see crbug.com/263563).
60    if ((*it)->window() &&
61        (*it)->window()->GetNativeWindow() == window)
62      return true;
63  }
64  return false;
65}
66
67bool BrowserShortcutLauncherItemController::IsOpen() const {
68  const BrowserList* ash_browser_list =
69      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
70  return ash_browser_list->empty() ? false : true;
71}
72
73bool BrowserShortcutLauncherItemController::IsVisible() const {
74  Browser* last_browser = chrome::FindTabbedBrowser(
75      profile_,
76      true,
77      chrome::HOST_DESKTOP_TYPE_ASH);
78
79  if (!last_browser) {
80    return false;
81  }
82
83  aura::Window* window = last_browser->window()->GetNativeWindow();
84  return ash::wm::IsActiveWindow(window);
85}
86
87void BrowserShortcutLauncherItemController::Launch(int event_flags) {
88}
89
90void BrowserShortcutLauncherItemController::Activate() {
91  Browser* last_browser = chrome::FindTabbedBrowser(
92      profile_,
93      true,
94      chrome::HOST_DESKTOP_TYPE_ASH);
95
96  if (!last_browser) {
97    launcher_controller()->CreateNewWindow();
98    return;
99  }
100
101  launcher_controller()->ActivateWindowOrMinimizeIfActive(
102      last_browser->window(), GetApplicationList(0).size() == 2);
103}
104
105void BrowserShortcutLauncherItemController::Close() {
106}
107
108void BrowserShortcutLauncherItemController::LauncherItemChanged(
109    int model_index,
110    const ash::LauncherItem& old_item) {
111}
112
113void BrowserShortcutLauncherItemController::Clicked(const ui::Event& event) {
114  #if defined(OS_CHROMEOS)
115    chromeos::default_pinned_apps_field_trial::RecordShelfClick(
116        chromeos::default_pinned_apps_field_trial::CHROME);
117  #endif
118
119  if (event.flags() & ui::EF_CONTROL_DOWN) {
120    launcher_controller()->CreateNewWindow();
121    return;
122  }
123
124  // In case of a keyboard event, we were called by a hotkey. In that case we
125  // activate the next item in line if an item of our list is already active.
126  if (event.type() & ui::ET_KEY_RELEASED) {
127    ActivateOrAdvanceToNextBrowser();
128    return;
129  }
130
131  Activate();
132}
133
134void BrowserShortcutLauncherItemController::OnRemoved() {
135  // BrowserShortcutLauncherItemController is owned by ChromeLauncherController.
136}
137
138ChromeLauncherAppMenuItems
139BrowserShortcutLauncherItemController::GetApplicationList(int event_flags) {
140  ChromeLauncherAppMenuItems items;
141  bool found_tabbed_browser = false;
142  // Add the application name to the menu.
143  items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false));
144  const BrowserList* ash_browser_list =
145      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
146  for (BrowserList::const_iterator it = ash_browser_list->begin();
147       it != ash_browser_list->end(); ++it) {
148    Browser* browser = *it;
149    // Make sure that the browser was already shown and it has a proper window.
150    if (std::find(ash_browser_list->begin_last_active(),
151                  ash_browser_list->end_last_active(),
152                  browser) == ash_browser_list->end_last_active() ||
153        !browser->window())
154      continue;
155    if (browser->is_type_tabbed())
156      found_tabbed_browser = true;
157    else if (!app_controller_->IsBrowserRepresentedInBrowserList(browser))
158      continue;
159    TabStripModel* tab_strip = browser->tab_strip_model();
160    if (tab_strip->active_index() == -1)
161      continue;
162    if (!(event_flags & ui::EF_SHIFT_DOWN)) {
163      content::WebContents* web_contents =
164          tab_strip->GetWebContentsAt(tab_strip->active_index());
165      gfx::Image app_icon = GetBrowserListIcon(web_contents);
166      string16 title = GetBrowserListTitle(web_contents);
167      items.push_back(new ChromeLauncherAppMenuItemBrowser(
168          title, &app_icon, browser, items.size() == 1));
169    } else {
170      for (int index = 0; index  < tab_strip->count(); ++index) {
171        content::WebContents* web_contents =
172            tab_strip->GetWebContentsAt(index);
173        gfx::Image app_icon = app_controller_->GetAppListIcon(web_contents);
174        string16 title = app_controller_->GetAppListTitle(web_contents);
175        // Check if we need to insert a separator in front.
176        bool leading_separator = !index;
177        items.push_back(new ChromeLauncherAppMenuItemTab(
178            title, &app_icon, web_contents, leading_separator));
179      }
180    }
181  }
182  // If only windowed applications are open, we return an empty list to
183  // enforce the creation of a new browser.
184  if (!found_tabbed_browser)
185    items.clear();
186  return items.Pass();
187}
188
189gfx::Image BrowserShortcutLauncherItemController::GetBrowserListIcon(
190    content::WebContents* web_contents) const {
191  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
192  return rb.GetImageNamed(IsIncognito(web_contents) ?
193      IDR_AURA_LAUNCHER_LIST_INCOGNITO_BROWSER :
194      IDR_AURA_LAUNCHER_LIST_BROWSER);
195}
196
197string16 BrowserShortcutLauncherItemController::GetBrowserListTitle(
198    content::WebContents* web_contents) const {
199  string16 title = web_contents->GetTitle();
200  if (!title.empty())
201    return title;
202  return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
203}
204
205bool BrowserShortcutLauncherItemController::IsIncognito(
206    content::WebContents* web_contents) const {
207  const Profile* profile =
208      Profile::FromBrowserContext(web_contents->GetBrowserContext());
209  return profile->IsOffTheRecord() && !profile->IsGuestSession();
210}
211
212void BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() {
213  // Create a list of all suitable running browsers.
214  std::vector<Browser*> items;
215  // We use the list in the order of how the browsers got created - not the LRU
216  // order.
217  const BrowserList* ash_browser_list =
218      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
219  for (BrowserList::const_iterator it =
220           ash_browser_list->begin();
221       it != ash_browser_list->end(); ++it) {
222    if (app_controller_->IsBrowserRepresentedInBrowserList(*it))
223      items.push_back(*it);
224  }
225  // If there are no suitable browsers we create a new one.
226  if (!items.size()) {
227    launcher_controller()->CreateNewWindow();
228    return;
229  }
230  Browser* browser = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
231  if (items.size() == 1) {
232    // If there is only one suitable browser, we can either activate it, or
233    // bounce it (if it is already active).
234    if (browser == items[0]) {
235      AnimateWindow(browser->window()->GetNativeWindow(),
236                    views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE);
237      return;
238    }
239    browser = items[0];
240  } else {
241    // If there is more then one suitable browser, we advance to the next if
242    // |current_browser| is already active - or - check the last used browser
243    // if it can be used.
244    std::vector<Browser*>::iterator i =
245        std::find(items.begin(), items.end(), browser);
246    if (i != items.end()) {
247      browser = (++i == items.end()) ? items[0] : *i;
248    } else {
249      browser = chrome::FindTabbedBrowser(profile_,
250                                          true,
251                                          chrome::HOST_DESKTOP_TYPE_ASH);
252      if (!browser ||
253          !app_controller_->IsBrowserRepresentedInBrowserList(browser))
254        browser = items[0];
255    }
256  }
257  DCHECK(browser);
258  browser->window()->Show();
259  browser->window()->Activate();
260}
261