Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / ash / launcher / shell_window_launcher_item_controller.cc
1 // Copyright (c) 2012 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/shell_window_launcher_item_controller.h"
6
7 #include "apps/app_window.h"
8 #include "apps/ui/native_app_window.h"
9 #include "ash/shelf/shelf_model.h"
10 #include "ash/wm/window_state.h"
11 #include "ash/wm/window_util.h"
12 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
13 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
14 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
15 #include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
16 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
17 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
18 #include "content/public/browser/web_contents.h"
19 #include "skia/ext/image_operations.h"
20 #include "ui/aura/client/aura_constants.h"
21 #include "ui/aura/window.h"
22 #include "ui/events/event.h"
23 #include "ui/gfx/image/image_skia.h"
24 #include "ui/views/corewm/window_animations.h"
25
26 using apps::AppWindow;
27
28 namespace {
29
30 // Size of the icon in the shelf launcher in display-independent pixels.
31 const int kAppListIconSize = 24;
32
33 // This will return a slightly smaller icon than the app icon to be used in
34 // the application list menu.
35 scoped_ptr<gfx::Image> GetAppListIcon(AppWindow* app_window) {
36   // TODO(skuhne): We instead might want to use LoadImages in
37   // AppWindow::UpdateExtensionAppIcon() to let the extension give us
38   // pre-defined icons in the launcher and the launcher list sizes. Since there
39   // is no mock yet, doing this now seems a bit premature and we scale for the
40   // time being.
41   if (app_window->app_icon().IsEmpty())
42     return make_scoped_ptr(new gfx::Image());
43
44   SkBitmap bmp =
45       skia::ImageOperations::Resize(*app_window->app_icon().ToSkBitmap(),
46                                     skia::ImageOperations::RESIZE_BEST,
47                                     kAppListIconSize,
48                                     kAppListIconSize);
49   return make_scoped_ptr(
50       new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp)));
51 }
52
53 // Functor for std::find_if used in AppLauncherItemController.
54 class AppWindowHasWindow {
55  public:
56   explicit AppWindowHasWindow(aura::Window* window) : window_(window) {}
57
58   bool operator()(AppWindow* app_window) const {
59     return app_window->GetNativeWindow() == window_;
60   }
61
62  private:
63   const aura::Window* window_;
64 };
65
66 }  // namespace
67
68 ShellWindowLauncherItemController::ShellWindowLauncherItemController(
69     Type type,
70     const std::string& app_shelf_id,
71     const std::string& app_id,
72     ChromeLauncherController* controller)
73     : LauncherItemController(type, app_id, controller),
74       last_active_app_window_(NULL),
75       app_shelf_id_(app_shelf_id),
76       observed_windows_(this) {}
77
78 ShellWindowLauncherItemController::~ShellWindowLauncherItemController() {
79 }
80
81 void ShellWindowLauncherItemController::AddAppWindow(
82     AppWindow* app_window,
83     ash::ShelfItemStatus status) {
84   if (app_window->window_type_is_panel() && type() != TYPE_APP_PANEL)
85     LOG(ERROR) << "AppWindow of type Panel added to non-panel launcher item";
86   app_windows_.push_front(app_window);
87   observed_windows_.Add(app_window->GetNativeWindow());
88 }
89
90 void ShellWindowLauncherItemController::RemoveShellWindowForWindow(
91     aura::Window* window) {
92   AppWindowList::iterator iter = std::find_if(
93       app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window));
94   if (iter != app_windows_.end()) {
95     if (*iter == last_active_app_window_)
96       last_active_app_window_ = NULL;
97     app_windows_.erase(iter);
98   }
99   observed_windows_.Remove(window);
100 }
101
102 void ShellWindowLauncherItemController::SetActiveWindow(aura::Window* window) {
103   AppWindowList::iterator iter = std::find_if(
104       app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window));
105   if (iter != app_windows_.end())
106     last_active_app_window_ = *iter;
107 }
108
109 bool ShellWindowLauncherItemController::IsOpen() const {
110   return !app_windows_.empty();
111 }
112
113 bool ShellWindowLauncherItemController::IsVisible() const {
114   // Return true if any windows are visible.
115   for (AppWindowList::const_iterator iter = app_windows_.begin();
116        iter != app_windows_.end();
117        ++iter) {
118     if ((*iter)->GetNativeWindow()->IsVisible())
119       return true;
120   }
121   return false;
122 }
123
124 void ShellWindowLauncherItemController::Launch(ash::LaunchSource source,
125                                                int event_flags) {
126   launcher_controller()->LaunchApp(app_id(),
127                                    source,
128                                    ui::EF_NONE);
129 }
130
131 bool ShellWindowLauncherItemController::Activate(ash::LaunchSource source) {
132   DCHECK(!app_windows_.empty());
133   AppWindow* window_to_activate =
134       last_active_app_window_ ? last_active_app_window_ : app_windows_.back();
135   window_to_activate->GetBaseWindow()->Activate();
136   return false;
137 }
138
139 void ShellWindowLauncherItemController::Close() {
140   // Note: Closing windows may affect the contents of app_windows_.
141   AppWindowList windows_to_close = app_windows_;
142   for (AppWindowList::iterator iter = windows_to_close.begin();
143        iter != windows_to_close.end();
144        ++iter) {
145     (*iter)->GetBaseWindow()->Close();
146   }
147 }
148
149 void ShellWindowLauncherItemController::ActivateIndexedApp(size_t index) {
150   if (index >= app_windows_.size())
151     return;
152   AppWindowList::iterator it = app_windows_.begin();
153   std::advance(it, index);
154   ShowAndActivateOrMinimize(*it);
155 }
156
157 ChromeLauncherAppMenuItems
158 ShellWindowLauncherItemController::GetApplicationList(int event_flags) {
159   ChromeLauncherAppMenuItems items;
160   items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false));
161   int index = 0;
162   for (AppWindowList::iterator iter = app_windows_.begin();
163        iter != app_windows_.end();
164        ++iter) {
165     AppWindow* app_window = *iter;
166     scoped_ptr<gfx::Image> image(GetAppListIcon(app_window));
167     items.push_back(new ChromeLauncherAppMenuItemV2App(
168         app_window->GetTitle(),
169         image.get(),  // Will be copied
170         app_id(),
171         launcher_controller(),
172         index,
173         index == 0 /* has_leading_separator */));
174     ++index;
175   }
176   return items.Pass();
177 }
178
179 bool ShellWindowLauncherItemController::ItemSelected(const ui::Event& event) {
180   if (app_windows_.empty())
181     return false;
182   if (type() == TYPE_APP_PANEL) {
183     DCHECK(app_windows_.size() == 1);
184     AppWindow* panel = app_windows_.front();
185     aura::Window* panel_window = panel->GetNativeWindow();
186     // If the panel is attached on another display, move it to the current
187     // display and activate it.
188     if (ash::wm::GetWindowState(panel_window)->panel_attached() &&
189         ash::wm::MoveWindowToEventRoot(panel_window, event)) {
190       if (!panel->GetBaseWindow()->IsActive())
191         ShowAndActivateOrMinimize(panel);
192     } else {
193       ShowAndActivateOrMinimize(panel);
194     }
195   } else {
196     AppWindow* window_to_show = last_active_app_window_
197                                     ? last_active_app_window_
198                                     : app_windows_.front();
199     // If the event was triggered by a keystroke, we try to advance to the next
200     // item if the window we are trying to activate is already active.
201     if (app_windows_.size() >= 1 &&
202         window_to_show->GetBaseWindow()->IsActive() &&
203         event.type() == ui::ET_KEY_RELEASED) {
204       ActivateOrAdvanceToNextShellWindow(window_to_show);
205     } else {
206       ShowAndActivateOrMinimize(window_to_show);
207     }
208   }
209   return false;
210 }
211
212 base::string16 ShellWindowLauncherItemController::GetTitle() {
213   // For panels return the title of the contents if set.
214   // Otherwise return the title of the app.
215   if (type() == TYPE_APP_PANEL && !app_windows_.empty()) {
216     AppWindow* app_window = app_windows_.front();
217     if (app_window->web_contents()) {
218       base::string16 title = app_window->web_contents()->GetTitle();
219       if (!title.empty())
220         return title;
221     }
222   }
223   return GetAppTitle();
224 }
225
226 ui::MenuModel* ShellWindowLauncherItemController::CreateContextMenu(
227     aura::Window* root_window) {
228   ash::ShelfItem item =
229       *(launcher_controller()->model()->ItemByID(shelf_id()));
230   return new LauncherContextMenu(launcher_controller(), &item, root_window);
231 }
232
233 ash::ShelfMenuModel* ShellWindowLauncherItemController::CreateApplicationMenu(
234     int event_flags) {
235   return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags));
236 }
237
238 bool ShellWindowLauncherItemController::IsDraggable() {
239   if (type() == TYPE_APP_PANEL)
240     return true;
241   return launcher_controller()->CanPin() ? true : false;
242 }
243
244 bool ShellWindowLauncherItemController::ShouldShowTooltip() {
245   if (type() == TYPE_APP_PANEL && IsVisible())
246     return false;
247   return true;
248 }
249
250 void ShellWindowLauncherItemController::OnWindowPropertyChanged(
251     aura::Window* window,
252     const void* key,
253     intptr_t old) {
254   if (key == aura::client::kDrawAttentionKey) {
255     ash::ShelfItemStatus status;
256     if (ash::wm::IsActiveWindow(window)) {
257       status = ash::STATUS_ACTIVE;
258     } else if (window->GetProperty(aura::client::kDrawAttentionKey)) {
259       status = ash::STATUS_ATTENTION;
260     } else {
261       status = ash::STATUS_RUNNING;
262     }
263     launcher_controller()->SetItemStatus(shelf_id(), status);
264   }
265 }
266
267 void ShellWindowLauncherItemController::ShowAndActivateOrMinimize(
268     AppWindow* app_window) {
269   // Either show or minimize windows when shown from the launcher.
270   launcher_controller()->ActivateWindowOrMinimizeIfActive(
271       app_window->GetBaseWindow(), GetApplicationList(0).size() == 2);
272 }
273
274 void ShellWindowLauncherItemController::ActivateOrAdvanceToNextShellWindow(
275     AppWindow* window_to_show) {
276   AppWindowList::iterator i(
277       std::find(app_windows_.begin(), app_windows_.end(), window_to_show));
278   if (i != app_windows_.end()) {
279     if (++i != app_windows_.end())
280       window_to_show = *i;
281     else
282       window_to_show = app_windows_.front();
283   }
284   if (window_to_show->GetBaseWindow()->IsActive()) {
285     // Coming here, only a single window is active. For keyboard activations
286     // the window gets animated.
287     AnimateWindow(window_to_show->GetNativeWindow(),
288                   views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE);
289   } else {
290     ShowAndActivateOrMinimize(window_to_show);
291   }
292 }