Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / ash / launcher / browser_shortcut_launcher_item_controller.cc
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/tabs/tab_strip_model.h"
26 #include "chrome/browser/web_applications/web_app.h"
27 #include "chrome/common/extensions/extension_constants.h"
28 #include "content/public/browser/web_contents.h"
29 #include "grit/ash_resources.h"
30 #include "grit/chromium_strings.h"
31 #include "grit/generated_resources.h"
32 #include "ui/aura/window.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/base/resource/resource_bundle.h"
35 #include "ui/events/event.h"
36 #include "ui/gfx/image/image.h"
37 #include "ui/views/corewm/window_animations.h"
38
39 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController(
40     ChromeLauncherController* launcher_controller)
41     : LauncherItemController(TYPE_SHORTCUT,
42                              extension_misc::kChromeAppId,
43                              launcher_controller) {
44 }
45
46 BrowserShortcutLauncherItemController::
47     ~BrowserShortcutLauncherItemController() {
48 }
49
50 void BrowserShortcutLauncherItemController::UpdateBrowserItemState() {
51   // The shell will not be available for win7_aura unittests like
52   // ChromeLauncherControllerTest.BrowserMenuGeneration.
53   if (!ash::Shell::HasInstance())
54     return;
55
56   ash::ShelfModel* model = launcher_controller()->model();
57
58   // Determine the new browser's active state and change if necessary.
59   int browser_index = model->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT);
60   DCHECK_GE(browser_index, 0);
61   ash::ShelfItem browser_item = model->items()[browser_index];
62   ash::ShelfItemStatus browser_status = ash::STATUS_CLOSED;
63
64   aura::Window* window = ash::wm::GetActiveWindow();
65   if (window) {
66     // Check if the active browser / tab is a browser which is not an app,
67     // a windowed app, a popup or any other item which is not a browser of
68     // interest.
69     Browser* browser = chrome::FindBrowserWithWindow(window);
70     if (IsBrowserRepresentedInBrowserList(browser)) {
71       browser_status = ash::STATUS_ACTIVE;
72       // If an app that has item is running in active WebContents, browser item
73       // status cannot be active.
74       content::WebContents* contents =
75           browser->tab_strip_model()->GetActiveWebContents();
76       if (contents &&
77           (launcher_controller()->GetShelfIDForWebContents(contents) !=
78               browser_item.id))
79         browser_status = ash::STATUS_RUNNING;
80     }
81   }
82
83   if (browser_status == ash::STATUS_CLOSED) {
84     const BrowserList* ash_browser_list =
85         BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
86     for (BrowserList::const_reverse_iterator it =
87              ash_browser_list->begin_last_active();
88          it != ash_browser_list->end_last_active() &&
89          browser_status == ash::STATUS_CLOSED; ++it) {
90       if (IsBrowserRepresentedInBrowserList(*it))
91         browser_status = ash::STATUS_RUNNING;
92     }
93   }
94
95   if (browser_status != browser_item.status) {
96     browser_item.status = browser_status;
97     model->Set(browser_index, browser_item);
98   }
99 }
100
101 bool BrowserShortcutLauncherItemController::IsOpen() const {
102   const BrowserList* ash_browser_list =
103       BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
104   for (BrowserList::const_iterator it = ash_browser_list->begin();
105        it != ash_browser_list->end(); ++it) {
106     if (launcher_controller()->IsBrowserFromActiveUser(*it))
107       return true;
108   }
109   return false;
110 }
111
112 bool BrowserShortcutLauncherItemController::IsVisible() const {
113   Browser* last_browser = chrome::FindTabbedBrowser(
114       launcher_controller()->profile(),
115       true,
116       chrome::HOST_DESKTOP_TYPE_ASH);
117
118   if (!last_browser) {
119     return false;
120   }
121
122   aura::Window* window = last_browser->window()->GetNativeWindow();
123   return ash::wm::IsActiveWindow(window);
124 }
125
126 void BrowserShortcutLauncherItemController::Launch(ash::LaunchSource source,
127                                                    int event_flags) {
128 }
129
130 bool BrowserShortcutLauncherItemController::Activate(ash::LaunchSource source) {
131   Browser* last_browser = chrome::FindTabbedBrowser(
132       launcher_controller()->profile(),
133       true,
134       chrome::HOST_DESKTOP_TYPE_ASH);
135
136   if (!last_browser) {
137     launcher_controller()->CreateNewWindow();
138     return true;
139   }
140
141   launcher_controller()->ActivateWindowOrMinimizeIfActive(
142       last_browser->window(), GetApplicationList(0).size() == 2);
143   return false;
144 }
145
146 void BrowserShortcutLauncherItemController::Close() {
147 }
148
149 ChromeLauncherAppMenuItems
150 BrowserShortcutLauncherItemController::GetApplicationList(int event_flags) {
151   ChromeLauncherAppMenuItems items;
152   bool found_tabbed_browser = false;
153   // Add the application name to the menu.
154   items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false));
155   const BrowserList* ash_browser_list =
156       BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
157   for (BrowserList::const_iterator it = ash_browser_list->begin();
158        it != ash_browser_list->end(); ++it) {
159     Browser* browser = *it;
160     // Make sure that the browser was already shown, is from the current user
161     // and has a proper window.
162     if (!launcher_controller()->IsBrowserFromActiveUser(browser) ||
163         std::find(ash_browser_list->begin_last_active(),
164                   ash_browser_list->end_last_active(),
165                   browser) == ash_browser_list->end_last_active() ||
166         !browser->window())
167       continue;
168     if (browser->is_type_tabbed())
169       found_tabbed_browser = true;
170     else if (!IsBrowserRepresentedInBrowserList(browser))
171       continue;
172     TabStripModel* tab_strip = browser->tab_strip_model();
173     if (tab_strip->active_index() == -1)
174       continue;
175     if (!(event_flags & ui::EF_SHIFT_DOWN)) {
176       content::WebContents* web_contents =
177           tab_strip->GetWebContentsAt(tab_strip->active_index());
178       gfx::Image app_icon = GetBrowserListIcon(web_contents);
179       base::string16 title = GetBrowserListTitle(web_contents);
180       items.push_back(new ChromeLauncherAppMenuItemBrowser(
181           title, &app_icon, browser, items.size() == 1));
182     } else {
183       for (int index = 0; index  < tab_strip->count(); ++index) {
184         content::WebContents* web_contents =
185             tab_strip->GetWebContentsAt(index);
186         gfx::Image app_icon =
187             launcher_controller()->GetAppListIcon(web_contents);
188         base::string16 title =
189             launcher_controller()->GetAppListTitle(web_contents);
190         // Check if we need to insert a separator in front.
191         bool leading_separator = !index;
192         items.push_back(new ChromeLauncherAppMenuItemTab(
193             title, &app_icon, web_contents, leading_separator));
194       }
195     }
196   }
197   // If only windowed applications are open, we return an empty list to
198   // enforce the creation of a new browser.
199   if (!found_tabbed_browser)
200     items.clear();
201   return items.Pass();
202 }
203
204 bool BrowserShortcutLauncherItemController::ItemSelected(
205     const ui::Event& event) {
206   if (event.flags() & ui::EF_CONTROL_DOWN) {
207     launcher_controller()->CreateNewWindow();
208     return true;
209   }
210
211   // In case of a keyboard event, we were called by a hotkey. In that case we
212   // activate the next item in line if an item of our list is already active.
213   if (event.type() & ui::ET_KEY_RELEASED) {
214     ActivateOrAdvanceToNextBrowser();
215     return false;
216   }
217
218   return Activate(ash::LAUNCH_FROM_UNKNOWN);
219 }
220
221 base::string16 BrowserShortcutLauncherItemController::GetTitle() {
222   return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
223 }
224
225 ui::MenuModel* BrowserShortcutLauncherItemController::CreateContextMenu(
226     aura::Window* root_window) {
227   ash::ShelfItem item =
228       *(launcher_controller()->model()->ItemByID(shelf_id()));
229   return new LauncherContextMenu(launcher_controller(), &item, root_window);
230 }
231
232 ash::ShelfMenuModel*
233 BrowserShortcutLauncherItemController::CreateApplicationMenu(int event_flags) {
234   return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags));
235 }
236
237 bool BrowserShortcutLauncherItemController::IsDraggable() {
238   return launcher_controller()->CanPin() ? true : false;
239 }
240
241 bool BrowserShortcutLauncherItemController::ShouldShowTooltip() {
242   return true;
243 }
244
245 gfx::Image BrowserShortcutLauncherItemController::GetBrowserListIcon(
246     content::WebContents* web_contents) const {
247   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
248   return rb.GetImageNamed(IsIncognito(web_contents) ?
249       IDR_AURA_LAUNCHER_LIST_INCOGNITO_BROWSER :
250       IDR_AURA_LAUNCHER_LIST_BROWSER);
251 }
252
253 base::string16 BrowserShortcutLauncherItemController::GetBrowserListTitle(
254     content::WebContents* web_contents) const {
255   base::string16 title = web_contents->GetTitle();
256   if (!title.empty())
257     return title;
258   return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
259 }
260
261 bool BrowserShortcutLauncherItemController::IsIncognito(
262     content::WebContents* web_contents) const {
263   const Profile* profile =
264       Profile::FromBrowserContext(web_contents->GetBrowserContext());
265   return profile->IsOffTheRecord() && !profile->IsGuestSession();
266 }
267
268 void BrowserShortcutLauncherItemController::ActivateOrAdvanceToNextBrowser() {
269   // Create a list of all suitable running browsers.
270   std::vector<Browser*> items;
271   // We use the list in the order of how the browsers got created - not the LRU
272   // order.
273   const BrowserList* ash_browser_list =
274       BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
275   for (BrowserList::const_iterator it =
276            ash_browser_list->begin();
277        it != ash_browser_list->end(); ++it) {
278     if (IsBrowserRepresentedInBrowserList(*it))
279       items.push_back(*it);
280   }
281   // If there are no suitable browsers we create a new one.
282   if (items.empty()) {
283     launcher_controller()->CreateNewWindow();
284     return;
285   }
286   Browser* browser = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
287   if (items.size() == 1) {
288     // If there is only one suitable browser, we can either activate it, or
289     // bounce it (if it is already active).
290     if (browser == items[0]) {
291       AnimateWindow(browser->window()->GetNativeWindow(),
292                     views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE);
293       return;
294     }
295     browser = items[0];
296   } else {
297     // If there is more then one suitable browser, we advance to the next if
298     // |browser| is already active - or - check the last used browser if it can
299     // be used.
300     std::vector<Browser*>::iterator i =
301         std::find(items.begin(), items.end(), browser);
302     if (i != items.end()) {
303       browser = (++i == items.end()) ? items[0] : *i;
304     } else {
305       browser = chrome::FindTabbedBrowser(launcher_controller()->profile(),
306                                           true,
307                                           chrome::HOST_DESKTOP_TYPE_ASH);
308       if (!browser ||
309           !IsBrowserRepresentedInBrowserList(browser))
310         browser = items[0];
311     }
312   }
313   DCHECK(browser);
314   browser->window()->Show();
315   browser->window()->Activate();
316 }
317
318 bool BrowserShortcutLauncherItemController::IsBrowserRepresentedInBrowserList(
319     Browser* browser) {
320   return (browser &&
321           launcher_controller()->IsBrowserFromActiveUser(browser) &&
322           browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH &&
323           (browser->is_type_tabbed() ||
324            !browser->is_app() ||
325            !browser->is_type_popup() ||
326            launcher_controller()->
327                GetShelfIDForAppID(web_app::GetExtensionIdFromApplicationName(
328                    browser->app_name())) <= 0));
329 }