- add sources.
[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/shell_window.h"
8 #include "apps/ui/native_app_window.h"
9 #include "ash/launcher/launcher_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::ShellWindow;
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(ShellWindow* shell_window) {
36   // TODO(skuhne): We instead might want to use LoadImages in
37   // ShellWindow::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 (shell_window->app_icon().IsEmpty())
42     return make_scoped_ptr(new gfx::Image());
43
44   SkBitmap bmp =
45       skia::ImageOperations::Resize(*shell_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 ShellWindowHasWindow {
55  public:
56   explicit ShellWindowHasWindow(aura::Window* window) : window_(window) { }
57
58   bool operator()(ShellWindow* shell_window) const {
59     return shell_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_launcher_id,
71     const std::string& app_id,
72     ChromeLauncherController* controller)
73     : LauncherItemController(type, app_id, controller),
74       last_active_shell_window_(NULL),
75       app_launcher_id_(app_launcher_id),
76       observed_windows_(this) {
77 }
78
79 ShellWindowLauncherItemController::~ShellWindowLauncherItemController() {
80 }
81
82 void ShellWindowLauncherItemController::AddShellWindow(
83     ShellWindow* shell_window,
84     ash::LauncherItemStatus status) {
85   if (shell_window->window_type_is_panel() && type() != TYPE_APP_PANEL)
86     LOG(ERROR) << "ShellWindow of type Panel added to non-panel launcher item";
87   shell_windows_.push_front(shell_window);
88   observed_windows_.Add(shell_window->GetNativeWindow());
89 }
90
91 void ShellWindowLauncherItemController::RemoveShellWindowForWindow(
92     aura::Window* window) {
93   ShellWindowList::iterator iter =
94       std::find_if(shell_windows_.begin(), shell_windows_.end(),
95                    ShellWindowHasWindow(window));
96   if (iter != shell_windows_.end()) {
97     if (*iter == last_active_shell_window_)
98       last_active_shell_window_ = NULL;
99     shell_windows_.erase(iter);
100   }
101   observed_windows_.Remove(window);
102 }
103
104 void ShellWindowLauncherItemController::SetActiveWindow(aura::Window* window) {
105   ShellWindowList::iterator iter =
106       std::find_if(shell_windows_.begin(), shell_windows_.end(),
107                    ShellWindowHasWindow(window));
108   if (iter != shell_windows_.end())
109     last_active_shell_window_ = *iter;
110 }
111
112 bool ShellWindowLauncherItemController::IsCurrentlyShownInWindow(
113     aura::Window* window) const {
114   ShellWindowList::const_iterator iter =
115       std::find_if(shell_windows_.begin(), shell_windows_.end(),
116                    ShellWindowHasWindow(window));
117   return iter != shell_windows_.end();
118 }
119
120 bool ShellWindowLauncherItemController::IsOpen() const {
121   return !shell_windows_.empty();
122 }
123
124 bool ShellWindowLauncherItemController::IsVisible() const {
125   // Return true if any windows are visible.
126   for (ShellWindowList::const_iterator iter = shell_windows_.begin();
127        iter != shell_windows_.end(); ++iter) {
128     if ((*iter)->GetNativeWindow()->IsVisible())
129       return true;
130   }
131   return false;
132 }
133
134 void ShellWindowLauncherItemController::Launch(ash::LaunchSource source,
135                                                int event_flags) {
136   launcher_controller()->LaunchApp(app_id(),
137                                    source,
138                                    ui::EF_NONE);
139 }
140
141 void ShellWindowLauncherItemController::Activate(ash::LaunchSource source) {
142   DCHECK(!shell_windows_.empty());
143   ShellWindow* window_to_activate = last_active_shell_window_ ?
144       last_active_shell_window_ : shell_windows_.back();
145   window_to_activate->GetBaseWindow()->Activate();
146 }
147
148 void ShellWindowLauncherItemController::Close() {
149   // Note: Closing windows may affect the contents of shell_windows_.
150   ShellWindowList windows_to_close = shell_windows_;
151   for (ShellWindowList::iterator iter = windows_to_close.begin();
152        iter != windows_to_close.end(); ++iter) {
153     (*iter)->GetBaseWindow()->Close();
154   }
155 }
156
157 void ShellWindowLauncherItemController::ActivateIndexedApp(size_t index) {
158   if (index >= shell_windows_.size())
159     return;
160   ShellWindowList::iterator it = shell_windows_.begin();
161   std::advance(it, index);
162   ShowAndActivateOrMinimize(*it);
163 }
164
165 ChromeLauncherAppMenuItems
166 ShellWindowLauncherItemController::GetApplicationList(int event_flags) {
167   ChromeLauncherAppMenuItems items;
168   items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false));
169   int index = 0;
170   for (ShellWindowList::iterator iter = shell_windows_.begin();
171        iter != shell_windows_.end(); ++iter) {
172     ShellWindow* shell_window = *iter;
173     scoped_ptr<gfx::Image> image(GetAppListIcon(shell_window));
174     items.push_back(new ChromeLauncherAppMenuItemV2App(
175         shell_window->GetTitle(),
176         image.get(),  // Will be copied
177         app_id(),
178         launcher_controller(),
179         index,
180         index == 0 /* has_leading_separator */));
181     ++index;
182   }
183   return items.Pass();
184 }
185
186 void ShellWindowLauncherItemController::ItemSelected(const ui::Event& event) {
187   if (shell_windows_.empty())
188     return;
189   if (type() == TYPE_APP_PANEL) {
190     DCHECK(shell_windows_.size() == 1);
191     ShellWindow* panel = shell_windows_.front();
192     aura::Window* panel_window = panel->GetNativeWindow();
193     // If the panel is attached on another display, move it to the current
194     // display and activate it.
195     if (ash::wm::GetWindowState(panel_window)->panel_attached() &&
196         ash::wm::MoveWindowToEventRoot(panel_window, event)) {
197       if (!panel->GetBaseWindow()->IsActive())
198         ShowAndActivateOrMinimize(panel);
199     } else {
200       ShowAndActivateOrMinimize(panel);
201     }
202   } else {
203     ShellWindow* window_to_show = last_active_shell_window_ ?
204         last_active_shell_window_ : shell_windows_.front();
205     // If the event was triggered by a keystroke, we try to advance to the next
206     // item if the window we are trying to activate is already active.
207     if (shell_windows_.size() >= 1 &&
208         window_to_show->GetBaseWindow()->IsActive() &&
209         event.type() == ui::ET_KEY_RELEASED) {
210       ActivateOrAdvanceToNextShellWindow(window_to_show);
211     } else {
212       ShowAndActivateOrMinimize(window_to_show);
213     }
214   }
215 }
216
217 base::string16 ShellWindowLauncherItemController::GetTitle() {
218   // For panels return the title of the contents if set.
219   // Otherwise return the title of the app.
220   if (type() == TYPE_APP_PANEL && !shell_windows_.empty()) {
221     ShellWindow* shell_window = shell_windows_.front();
222     if (shell_window->web_contents()) {
223       string16 title = shell_window->web_contents()->GetTitle();
224       if (!title.empty())
225         return title;
226     }
227   }
228   return GetAppTitle();
229 }
230
231 ui::MenuModel* ShellWindowLauncherItemController::CreateContextMenu(
232     aura::Window* root_window) {
233   ash::LauncherItem item =
234       *(launcher_controller()->model()->ItemByID(launcher_id()));
235   return new LauncherContextMenu(launcher_controller(), &item, root_window);
236 }
237
238 ash::LauncherMenuModel*
239 ShellWindowLauncherItemController::CreateApplicationMenu(int event_flags) {
240   return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags));
241 }
242
243 bool ShellWindowLauncherItemController::IsDraggable() {
244   if (type() == TYPE_APP_PANEL)
245     return true;
246   return launcher_controller()->CanPin() ? true : false;
247 }
248
249 bool ShellWindowLauncherItemController::ShouldShowTooltip() {
250   if (type() == TYPE_APP_PANEL && IsVisible())
251     return false;
252   return true;
253 }
254
255 void ShellWindowLauncherItemController::OnWindowPropertyChanged(
256     aura::Window* window,
257     const void* key,
258     intptr_t old) {
259   if (key == aura::client::kDrawAttentionKey) {
260     ash::LauncherItemStatus status;
261     if (ash::wm::IsActiveWindow(window)) {
262       status = ash::STATUS_ACTIVE;
263     } else if (window->GetProperty(aura::client::kDrawAttentionKey)) {
264       status = ash::STATUS_ATTENTION;
265     } else {
266       status = ash::STATUS_RUNNING;
267     }
268     launcher_controller()->SetItemStatus(launcher_id(), status);
269   }
270 }
271
272 void ShellWindowLauncherItemController::ShowAndActivateOrMinimize(
273     ShellWindow* shell_window) {
274   // Either show or minimize windows when shown from the launcher.
275   launcher_controller()->ActivateWindowOrMinimizeIfActive(
276       shell_window->GetBaseWindow(),
277       GetApplicationList(0).size() == 2);
278 }
279
280 void ShellWindowLauncherItemController::ActivateOrAdvanceToNextShellWindow(
281     ShellWindow* window_to_show) {
282   ShellWindowList::iterator i(
283       std::find(shell_windows_.begin(),
284                 shell_windows_.end(),
285                 window_to_show));
286   if (i != shell_windows_.end()) {
287     if (++i != shell_windows_.end())
288       window_to_show = *i;
289     else
290       window_to_show = shell_windows_.front();
291   }
292   if (window_to_show->GetBaseWindow()->IsActive()) {
293     // Coming here, only a single window is active. For keyboard activations
294     // the window gets animated.
295     AnimateWindow(window_to_show->GetNativeWindow(),
296                   views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE);
297   } else {
298     ShowAndActivateOrMinimize(window_to_show);
299   }
300 }