Upstream version 10.39.225.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/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"
41
42 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController(
43     ChromeLauncherController* launcher_controller)
44     : LauncherItemController(TYPE_SHORTCUT,
45                              extension_misc::kChromeAppId,
46                              launcher_controller) {
47 }
48
49 BrowserShortcutLauncherItemController::
50     ~BrowserShortcutLauncherItemController() {
51 }
52
53 void BrowserShortcutLauncherItemController::UpdateBrowserItemState() {
54   // The shell will not be available for win7_aura unittests like
55   // ChromeLauncherControllerTest.BrowserMenuGeneration.
56   if (!ash::Shell::HasInstance())
57     return;
58
59   ash::ShelfModel* model = launcher_controller()->model();
60
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;
66
67   aura::Window* window = ash::wm::GetActiveWindow();
68   if (window) {
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
71     // interest.
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();
79       if (contents &&
80           (launcher_controller()->GetShelfIDForWebContents(contents) !=
81               browser_item.id))
82         browser_status = ash::STATUS_RUNNING;
83     }
84   }
85
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;
95     }
96   }
97
98   if (browser_status != browser_item.status) {
99     browser_item.status = browser_status;
100     model->Set(browser_index, browser_item);
101   }
102 }
103
104 void BrowserShortcutLauncherItemController::SetShelfIDForBrowserWindowContents(
105     Browser* browser,
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.
109   if (!browser ||
110       !launcher_controller()->IsBrowserFromActiveUser(browser) ||
111       browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH ||
112       chrome::IsTrustedPopupWindowWithScheme(browser, content::kChromeUIScheme))
113     return;
114
115   ash::SetShelfIDForWindow(
116       launcher_controller()->GetShelfIDForWebContents(web_contents),
117       browser->window()->GetNativeWindow());
118 }
119
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))
126       return true;
127   }
128   return false;
129 }
130
131 bool BrowserShortcutLauncherItemController::IsVisible() const {
132   Browser* last_browser = chrome::FindTabbedBrowser(
133       launcher_controller()->profile(),
134       true,
135       chrome::HOST_DESKTOP_TYPE_ASH);
136
137   if (!last_browser) {
138     return false;
139   }
140
141   aura::Window* window = last_browser->window()->GetNativeWindow();
142   return ash::wm::IsActiveWindow(window);
143 }
144
145 void BrowserShortcutLauncherItemController::Launch(ash::LaunchSource source,
146                                                    int event_flags) {
147 }
148
149 bool BrowserShortcutLauncherItemController::Activate(ash::LaunchSource source) {
150   Browser* last_browser = chrome::FindTabbedBrowser(
151       launcher_controller()->profile(),
152       true,
153       chrome::HOST_DESKTOP_TYPE_ASH);
154
155   if (!last_browser) {
156     launcher_controller()->CreateNewWindow();
157     return true;
158   }
159
160   launcher_controller()->ActivateWindowOrMinimizeIfActive(
161       last_browser->window(), GetApplicationList(0).size() == 2);
162   return false;
163 }
164
165 void BrowserShortcutLauncherItemController::Close() {
166 }
167
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() ||
185         !browser->window())
186       continue;
187     if (browser->is_type_tabbed())
188       found_tabbed_browser = true;
189     else if (!IsBrowserRepresentedInBrowserList(browser))
190       continue;
191     TabStripModel* tab_strip = browser->tab_strip_model();
192     if (tab_strip->active_index() == -1)
193       continue;
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));
201     } else {
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));
213       }
214     }
215   }
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)
219     items.clear();
220   return items.Pass();
221 }
222
223 bool BrowserShortcutLauncherItemController::ItemSelected(
224     const ui::Event& event) {
225   if (event.flags() & ui::EF_CONTROL_DOWN) {
226     launcher_controller()->CreateNewWindow();
227     return true;
228   }
229
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();
234     return false;
235   }
236
237   return Activate(ash::LAUNCH_FROM_UNKNOWN);
238 }
239
240 base::string16 BrowserShortcutLauncherItemController::GetTitle() {
241   return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
242 }
243
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);
249 }
250
251 ash::ShelfMenuModel*
252 BrowserShortcutLauncherItemController::CreateApplicationMenu(int event_flags) {
253   return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags));
254 }
255
256 bool BrowserShortcutLauncherItemController::IsDraggable() {
257   return launcher_controller()->CanPin() ? true : false;
258 }
259
260 bool BrowserShortcutLauncherItemController::ShouldShowTooltip() {
261   return true;
262 }
263
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);
270 }
271
272 base::string16 BrowserShortcutLauncherItemController::GetBrowserListTitle(
273     content::WebContents* web_contents) const {
274   base::string16 title = web_contents->GetTitle();
275   if (!title.empty())
276     return title;
277   return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
278 }
279
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();
285 }
286
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
291   // order.
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);
299   }
300   // If there are no suitable browsers we create a new one.
301   if (items.empty()) {
302     launcher_controller()->CreateNewWindow();
303     return;
304   }
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);
312       return;
313     }
314     browser = items[0];
315   } else {
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
318     // be used.
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;
323     } else {
324       browser = chrome::FindTabbedBrowser(launcher_controller()->profile(),
325                                           true,
326                                           chrome::HOST_DESKTOP_TYPE_ASH);
327       if (!browser ||
328           !IsBrowserRepresentedInBrowserList(browser))
329         browser = items[0];
330     }
331   }
332   DCHECK(browser);
333   browser->window()->Show();
334   browser->window()->Activate();
335 }
336
337 bool BrowserShortcutLauncherItemController::IsBrowserRepresentedInBrowserList(
338     Browser* browser) {
339   // Only Ash desktop browser windows for the active user are represented.
340   if (!browser ||
341       !launcher_controller()->IsBrowserFromActiveUser(browser) ||
342       browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
343     return false;
344
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)
350     return false;
351
352   // Stand-alone chrome:// windows (e.g. settings) have their own icon.
353   if (chrome::IsTrustedPopupWindowWithScheme(browser, content::kChromeUIScheme))
354     return false;
355
356   // Tabbed browser and other popup windows are all represented.
357   return true;
358 }