Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / ash / launcher / app_window_launcher_item_controller.cc
blobc2fb1a5b689bafebb4c4843f2d1217f14dfe8728
1 // Copyright 2014 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.
5 #include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h"
7 #include "ash/shelf/shelf_model.h"
8 #include "ash/wm/window_state.h"
9 #include "ash/wm/window_util.h"
10 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
11 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
12 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
13 #include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
14 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
15 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
16 #include "components/favicon/content/content_favicon_driver.h"
17 #include "content/public/browser/web_contents.h"
18 #include "extensions/browser/app_window/app_window.h"
19 #include "extensions/browser/app_window/native_app_window.h"
20 #include "skia/ext/image_operations.h"
21 #include "ui/aura/client/aura_constants.h"
22 #include "ui/aura/window.h"
23 #include "ui/events/event.h"
24 #include "ui/gfx/image/image_skia.h"
25 #include "ui/wm/core/window_animations.h"
27 using extensions::AppWindow;
29 namespace {
31 // Size of the icon in the shelf launcher in display-independent pixels.
32 const int kAppListIconSize = 24;
34 // This will return a slightly smaller icon than the app icon to be used in
35 // the application list menu.
36 gfx::Image GetAppListIcon(AppWindow* app_window) {
37 // TODO(skuhne): We instead might want to use LoadImages in
38 // AppWindow::UpdateExtensionAppIcon() to let the extension give us
39 // pre-defined icons in the launcher and the launcher list sizes. Since there
40 // is no mock yet, doing this now seems a bit premature and we scale for the
41 // time being.
42 if (app_window->app_icon().IsEmpty())
43 return gfx::Image();
45 SkBitmap bmp =
46 skia::ImageOperations::Resize(*app_window->app_icon().ToSkBitmap(),
47 skia::ImageOperations::RESIZE_BEST,
48 kAppListIconSize,
49 kAppListIconSize);
50 return gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp));
53 // Functor for std::find_if used in AppLauncherItemController.
54 class AppWindowHasWindow {
55 public:
56 explicit AppWindowHasWindow(aura::Window* window) : window_(window) {}
58 bool operator()(AppWindow* app_window) const {
59 return app_window->GetNativeWindow() == window_;
62 private:
63 const aura::Window* window_;
66 } // namespace
68 AppWindowLauncherItemController::AppWindowLauncherItemController(
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) {}
78 AppWindowLauncherItemController::~AppWindowLauncherItemController() {}
80 void AppWindowLauncherItemController::AddAppWindow(
81 AppWindow* app_window,
82 ash::ShelfItemStatus status) {
83 if (app_window->window_type_is_panel() && type() != TYPE_APP_PANEL)
84 LOG(ERROR) << "AppWindow of type Panel added to non-panel launcher item";
85 app_windows_.push_front(app_window);
86 observed_windows_.Add(app_window->GetNativeWindow());
89 void AppWindowLauncherItemController::RemoveAppWindowForWindow(
90 aura::Window* window) {
91 AppWindowList::iterator iter = std::find_if(
92 app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window));
93 if (iter != app_windows_.end()) {
94 if (*iter == last_active_app_window_)
95 last_active_app_window_ = NULL;
96 app_windows_.erase(iter);
98 observed_windows_.Remove(window);
101 void AppWindowLauncherItemController::SetActiveWindow(aura::Window* window) {
102 AppWindowList::iterator iter = std::find_if(
103 app_windows_.begin(), app_windows_.end(), AppWindowHasWindow(window));
104 if (iter != app_windows_.end())
105 last_active_app_window_ = *iter;
108 bool AppWindowLauncherItemController::IsOpen() const {
109 return !app_windows_.empty();
112 bool AppWindowLauncherItemController::IsVisible() const {
113 // Return true if any windows are visible.
114 for (AppWindowList::const_iterator iter = app_windows_.begin();
115 iter != app_windows_.end();
116 ++iter) {
117 if ((*iter)->GetNativeWindow()->IsVisible())
118 return true;
120 return false;
123 void AppWindowLauncherItemController::Launch(ash::LaunchSource source,
124 int event_flags) {
125 launcher_controller()->LaunchApp(app_id(), source, ui::EF_NONE);
128 ash::ShelfItemDelegate::PerformedAction
129 AppWindowLauncherItemController::Activate(ash::LaunchSource source) {
130 DCHECK(!app_windows_.empty());
131 AppWindow* window_to_activate =
132 last_active_app_window_ ? last_active_app_window_ : app_windows_.back();
133 window_to_activate->GetBaseWindow()->Activate();
134 return kExistingWindowActivated;
137 void AppWindowLauncherItemController::Close() {
138 // Note: Closing windows may affect the contents of app_windows_.
139 AppWindowList windows_to_close = app_windows_;
140 for (AppWindowList::iterator iter = windows_to_close.begin();
141 iter != windows_to_close.end();
142 ++iter) {
143 (*iter)->GetBaseWindow()->Close();
147 void AppWindowLauncherItemController::ActivateIndexedApp(size_t index) {
148 if (index >= app_windows_.size())
149 return;
150 AppWindowList::iterator it = app_windows_.begin();
151 std::advance(it, index);
152 ShowAndActivateOrMinimize(*it);
155 ChromeLauncherAppMenuItems AppWindowLauncherItemController::GetApplicationList(
156 int event_flags) {
157 ChromeLauncherAppMenuItems items;
158 items.push_back(new ChromeLauncherAppMenuItem(GetTitle(), NULL, false));
159 int index = 0;
160 for (AppWindowList::iterator iter = app_windows_.begin();
161 iter != app_windows_.end();
162 ++iter) {
163 AppWindow* app_window = *iter;
165 // If the app's web contents provides a favicon, use it. Otherwise, use a
166 // scaled down app icon.
167 favicon::FaviconDriver* favicon_driver =
168 favicon::ContentFaviconDriver::FromWebContents(
169 app_window->web_contents());
170 gfx::Image result = favicon_driver->GetFavicon();
171 if (result.IsEmpty())
172 result = GetAppListIcon(app_window);
174 items.push_back(new ChromeLauncherAppMenuItemV2App(
175 app_window->GetTitle(),
176 &result, // Will be copied
177 app_id(),
178 launcher_controller(),
179 index,
180 index == 0 /* has_leading_separator */));
181 ++index;
183 return items.Pass();
186 ash::ShelfItemDelegate::PerformedAction
187 AppWindowLauncherItemController::ItemSelected(const ui::Event& event) {
188 if (app_windows_.empty())
189 return kNoAction;
190 if (type() == TYPE_APP_PANEL) {
191 DCHECK_EQ(app_windows_.size(), 1u);
192 AppWindow* panel = app_windows_.front();
193 aura::Window* panel_window = panel->GetNativeWindow();
194 // If the panel is attached on another display, move it to the current
195 // display and activate it.
196 if (ash::wm::GetWindowState(panel_window)->panel_attached() &&
197 ash::wm::MoveWindowToEventRoot(panel_window, event)) {
198 if (!panel->GetBaseWindow()->IsActive())
199 return ShowAndActivateOrMinimize(panel);
200 } else {
201 return ShowAndActivateOrMinimize(panel);
203 } else {
204 AppWindow* window_to_show = last_active_app_window_
205 ? last_active_app_window_
206 : app_windows_.front();
207 // If the event was triggered by a keystroke, we try to advance to the next
208 // item if the window we are trying to activate is already active.
209 if (app_windows_.size() >= 1 &&
210 window_to_show->GetBaseWindow()->IsActive() &&
211 event.type() == ui::ET_KEY_RELEASED) {
212 return ActivateOrAdvanceToNextAppWindow(window_to_show);
213 } else {
214 return ShowAndActivateOrMinimize(window_to_show);
217 return kNoAction;
220 base::string16 AppWindowLauncherItemController::GetTitle() {
221 // For panels return the title of the contents if set.
222 // Otherwise return the title of the app.
223 if (type() == TYPE_APP_PANEL && !app_windows_.empty()) {
224 AppWindow* app_window = app_windows_.front();
225 if (app_window->web_contents()) {
226 base::string16 title = app_window->web_contents()->GetTitle();
227 if (!title.empty())
228 return title;
231 return GetAppTitle();
234 ui::MenuModel* AppWindowLauncherItemController::CreateContextMenu(
235 aura::Window* root_window) {
236 ash::ShelfItem item = *(launcher_controller()->model()->ItemByID(shelf_id()));
237 return new LauncherContextMenu(launcher_controller(), &item, root_window);
240 ash::ShelfMenuModel* AppWindowLauncherItemController::CreateApplicationMenu(
241 int event_flags) {
242 return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags));
245 bool AppWindowLauncherItemController::IsDraggable() {
246 if (type() == TYPE_APP_PANEL)
247 return true;
248 return launcher_controller()->CanPin() ? true : false;
251 bool AppWindowLauncherItemController::ShouldShowTooltip() {
252 if (type() == TYPE_APP_PANEL && IsVisible())
253 return false;
254 return true;
257 void AppWindowLauncherItemController::OnWindowPropertyChanged(
258 aura::Window* window,
259 const void* key,
260 intptr_t old) {
261 if (key == aura::client::kDrawAttentionKey) {
262 ash::ShelfItemStatus status;
263 if (ash::wm::IsActiveWindow(window)) {
264 status = ash::STATUS_ACTIVE;
265 } else if (window->GetProperty(aura::client::kDrawAttentionKey)) {
266 status = ash::STATUS_ATTENTION;
267 } else {
268 status = ash::STATUS_RUNNING;
270 launcher_controller()->SetItemStatus(shelf_id(), status);
274 ash::ShelfItemDelegate::PerformedAction
275 AppWindowLauncherItemController::ShowAndActivateOrMinimize(
276 AppWindow* app_window) {
277 // Either show or minimize windows when shown from the launcher.
278 return launcher_controller()->ActivateWindowOrMinimizeIfActive(
279 app_window->GetBaseWindow(), GetApplicationList(0).size() == 2);
282 ash::ShelfItemDelegate::PerformedAction
283 AppWindowLauncherItemController::ActivateOrAdvanceToNextAppWindow(
284 AppWindow* window_to_show) {
285 AppWindowList::iterator i(
286 std::find(app_windows_.begin(), app_windows_.end(), window_to_show));
287 if (i != app_windows_.end()) {
288 if (++i != app_windows_.end())
289 window_to_show = *i;
290 else
291 window_to_show = app_windows_.front();
293 if (window_to_show->GetBaseWindow()->IsActive()) {
294 // Coming here, only a single window is active. For keyboard activations
295 // the window gets animated.
296 AnimateWindow(window_to_show->GetNativeWindow(),
297 wm::WINDOW_ANIMATION_TYPE_BOUNCE);
298 } else {
299 return ShowAndActivateOrMinimize(window_to_show);
301 return kNoAction;