Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / views / app_list_view.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 "ui/app_list/views/app_list_view.h"
6
7 #include <algorithm>
8
9 #include "base/command_line.h"
10 #include "base/strings/string_util.h"
11 #include "base/win/windows_version.h"
12 #include "ui/app_list/app_list_constants.h"
13 #include "ui/app_list/app_list_model.h"
14 #include "ui/app_list/app_list_view_delegate.h"
15 #include "ui/app_list/pagination_model.h"
16 #include "ui/app_list/signin_delegate.h"
17 #include "ui/app_list/speech_ui_model.h"
18 #include "ui/app_list/views/app_list_background.h"
19 #include "ui/app_list/views/app_list_folder_view.h"
20 #include "ui/app_list/views/app_list_main_view.h"
21 #include "ui/app_list/views/app_list_view_observer.h"
22 #include "ui/app_list/views/apps_container_view.h"
23 #include "ui/app_list/views/contents_view.h"
24 #include "ui/app_list/views/search_box_view.h"
25 #include "ui/app_list/views/signin_view.h"
26 #include "ui/app_list/views/speech_view.h"
27 #include "ui/base/ui_base_switches.h"
28 #include "ui/compositor/layer.h"
29 #include "ui/compositor/layer_animation_observer.h"
30 #include "ui/compositor/scoped_layer_animation_settings.h"
31 #include "ui/gfx/image/image_skia.h"
32 #include "ui/gfx/insets.h"
33 #include "ui/gfx/path.h"
34 #include "ui/gfx/skia_util.h"
35 #include "ui/views/bubble/bubble_frame_view.h"
36 #include "ui/views/bubble/bubble_window_targeter.h"
37 #include "ui/views/controls/textfield/textfield.h"
38 #include "ui/views/layout/fill_layout.h"
39 #include "ui/views/widget/widget.h"
40
41 #if defined(USE_AURA)
42 #include "ui/aura/window.h"
43 #include "ui/aura/window_tree_host.h"
44 #if defined(OS_WIN)
45 #include "ui/base/win/shell.h"
46 #endif
47 #if !defined(OS_CHROMEOS)
48 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
49 #endif
50 #endif  // defined(USE_AURA)
51
52 namespace app_list {
53
54 namespace {
55
56 void (*g_next_paint_callback)();
57
58 // The margin from the edge to the speech UI.
59 const int kSpeechUIMargin = 12;
60
61 // The vertical position for the appearing animation of the speech UI.
62 const float kSpeechUIAppearingPosition = 12;
63
64 // The distance between the arrow tip and edge of the anchor view.
65 const int kArrowOffset = 10;
66
67 // Determines whether the current environment supports shadows bubble borders.
68 bool SupportsShadow() {
69 #if defined(OS_WIN)
70   // Shadows are not supported on Windows without Aero Glass.
71   if (!ui::win::IsAeroGlassEnabled() ||
72       CommandLine::ForCurrentProcess()->HasSwitch(
73           switches::kDisableDwmComposition)) {
74     return false;
75   }
76 #elif defined(OS_LINUX) && !defined(USE_ASH)
77   // Shadows are not supported on (non-ChromeOS) Linux.
78   return false;
79 #endif
80   return true;
81 }
82
83 }  // namespace
84
85 // An animation observer to hide the view at the end of the animation.
86 class HideViewAnimationObserver : public ui::ImplicitAnimationObserver {
87  public:
88   HideViewAnimationObserver()
89       : frame_(NULL),
90         target_(NULL) {
91   }
92
93   virtual ~HideViewAnimationObserver() {
94     if (target_)
95       StopObservingImplicitAnimations();
96   }
97
98   void SetTarget(views::View* target) {
99     if (!target_)
100       StopObservingImplicitAnimations();
101     target_ = target;
102   }
103
104   void set_frame(views::BubbleFrameView* frame) { frame_ = frame; }
105
106  private:
107   // Overridden from ui::ImplicitAnimationObserver:
108   virtual void OnImplicitAnimationsCompleted() OVERRIDE {
109     if (target_) {
110       target_->SetVisible(false);
111       target_ = NULL;
112
113       // Should update the background by invoking SchedulePaint().
114       frame_->SchedulePaint();
115     }
116   }
117
118   views::BubbleFrameView* frame_;
119   views::View* target_;
120
121   DISALLOW_COPY_AND_ASSIGN(HideViewAnimationObserver);
122 };
123
124 ////////////////////////////////////////////////////////////////////////////////
125 // AppListView:
126
127 AppListView::AppListView(AppListViewDelegate* delegate)
128     : delegate_(delegate),
129       app_list_main_view_(NULL),
130       signin_view_(NULL),
131       speech_view_(NULL),
132       animation_observer_(new HideViewAnimationObserver()) {
133   CHECK(delegate);
134
135   delegate_->AddObserver(this);
136   delegate_->GetSpeechUI()->AddObserver(this);
137 }
138
139 AppListView::~AppListView() {
140   delegate_->GetSpeechUI()->RemoveObserver(this);
141   delegate_->RemoveObserver(this);
142   animation_observer_.reset();
143   // Remove child views first to ensure no remaining dependencies on delegate_.
144   RemoveAllChildViews(true);
145 }
146
147 void AppListView::InitAsBubbleAttachedToAnchor(
148     gfx::NativeView parent,
149     PaginationModel* pagination_model,
150     views::View* anchor,
151     const gfx::Vector2d& anchor_offset,
152     views::BubbleBorder::Arrow arrow,
153     bool border_accepts_events) {
154   SetAnchorView(anchor);
155   InitAsBubbleInternal(
156       parent, pagination_model, arrow, border_accepts_events, anchor_offset);
157 }
158
159 void AppListView::InitAsBubbleAtFixedLocation(
160     gfx::NativeView parent,
161     PaginationModel* pagination_model,
162     const gfx::Point& anchor_point_in_screen,
163     views::BubbleBorder::Arrow arrow,
164     bool border_accepts_events) {
165   SetAnchorView(NULL);
166   SetAnchorRect(gfx::Rect(anchor_point_in_screen, gfx::Size()));
167   InitAsBubbleInternal(
168       parent, pagination_model, arrow, border_accepts_events, gfx::Vector2d());
169 }
170
171 void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
172   GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
173   SizeToContents();  // Recalcuates with new border.
174   GetBubbleFrameView()->SchedulePaint();
175 }
176
177 void AppListView::SetAnchorPoint(const gfx::Point& anchor_point) {
178   SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
179 }
180
181 void AppListView::SetDragAndDropHostOfCurrentAppList(
182     ApplicationDragAndDropHost* drag_and_drop_host) {
183   app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
184 }
185
186 void AppListView::ShowWhenReady() {
187   app_list_main_view_->ShowAppListWhenReady();
188 }
189
190 void AppListView::Close() {
191   app_list_main_view_->Close();
192   delegate_->Dismiss();
193 }
194
195 void AppListView::UpdateBounds() {
196   SizeToContents();
197 }
198
199 bool AppListView::ShouldCenterWindow() const {
200   return delegate_->ShouldCenterWindow();
201 }
202
203 gfx::Size AppListView::GetPreferredSize() {
204   return app_list_main_view_->GetPreferredSize();
205 }
206
207 void AppListView::Paint(gfx::Canvas* canvas) {
208   views::BubbleDelegateView::Paint(canvas);
209   if (g_next_paint_callback) {
210     g_next_paint_callback();
211     g_next_paint_callback = NULL;
212   }
213 }
214
215 void AppListView::OnThemeChanged() {
216 #if defined(OS_WIN)
217   GetWidget()->Close();
218 #endif
219 }
220
221 bool AppListView::ShouldHandleSystemCommands() const {
222   return true;
223 }
224
225 void AppListView::Prerender() {
226   app_list_main_view_->Prerender();
227 }
228
229 void AppListView::OnProfilesChanged() {
230   SigninDelegate* signin_delegate =
231       delegate_ ? delegate_->GetSigninDelegate() : NULL;
232   bool show_signin_view = signin_delegate && signin_delegate->NeedSignin();
233
234   signin_view_->SetVisible(show_signin_view);
235   app_list_main_view_->SetVisible(!show_signin_view);
236   app_list_main_view_->search_box_view()->InvalidateMenu();
237 }
238
239 void AppListView::SetProfileByPath(const base::FilePath& profile_path) {
240   delegate_->SetProfileByPath(profile_path);
241   app_list_main_view_->ModelChanged();
242 }
243
244 void AppListView::AddObserver(AppListViewObserver* observer) {
245   observers_.AddObserver(observer);
246 }
247
248 void AppListView::RemoveObserver(AppListViewObserver* observer) {
249   observers_.RemoveObserver(observer);
250 }
251
252 // static
253 void AppListView::SetNextPaintCallback(void (*callback)()) {
254   g_next_paint_callback = callback;
255 }
256
257 #if defined(OS_WIN)
258 HWND AppListView::GetHWND() const {
259 #if defined(USE_AURA)
260   gfx::NativeWindow window =
261       GetWidget()->GetTopLevelWidget()->GetNativeWindow();
262   return window->GetHost()->GetAcceleratedWidget();
263 #else
264   return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
265 #endif
266 }
267 #endif
268
269 void AppListView::InitAsBubbleInternal(gfx::NativeView parent,
270                                        PaginationModel* pagination_model,
271                                        views::BubbleBorder::Arrow arrow,
272                                        bool border_accepts_events,
273                                        const gfx::Vector2d& anchor_offset) {
274   app_list_main_view_ = new AppListMainView(delegate_.get(),
275                                             pagination_model,
276                                             parent);
277   AddChildView(app_list_main_view_);
278 #if defined(USE_AURA)
279   app_list_main_view_->SetPaintToLayer(true);
280   app_list_main_view_->SetFillsBoundsOpaquely(false);
281   app_list_main_view_->layer()->SetMasksToBounds(true);
282 #endif
283
284   signin_view_ =
285       new SigninView(delegate_->GetSigninDelegate(),
286                      app_list_main_view_->GetPreferredSize().width());
287   AddChildView(signin_view_);
288
289   // Speech recognition is available only when the start page exists.
290   if (delegate_ && delegate_->GetSpeechRecognitionContents()) {
291     speech_view_ = new SpeechView(delegate_.get());
292     speech_view_->SetVisible(false);
293 #if defined(USE_AURA)
294     speech_view_->SetPaintToLayer(true);
295     speech_view_->SetFillsBoundsOpaquely(false);
296     speech_view_->layer()->SetOpacity(0.0f);
297 #endif
298     AddChildView(speech_view_);
299   }
300
301   OnProfilesChanged();
302   set_color(kContentsBackgroundColor);
303   set_margins(gfx::Insets());
304   set_parent_window(parent);
305   set_close_on_deactivate(false);
306   set_close_on_esc(false);
307   set_anchor_view_insets(gfx::Insets(kArrowOffset + anchor_offset.y(),
308                                      kArrowOffset + anchor_offset.x(),
309                                      kArrowOffset - anchor_offset.y(),
310                                      kArrowOffset - anchor_offset.x()));
311   set_border_accepts_events(border_accepts_events);
312   set_shadow(SupportsShadow() ? views::BubbleBorder::BIG_SHADOW
313                               : views::BubbleBorder::NO_SHADOW_OPAQUE_BORDER);
314   views::BubbleDelegateView::CreateBubble(this);
315   SetBubbleArrow(arrow);
316
317 #if defined(USE_AURA)
318   aura::Window* window = GetWidget()->GetNativeWindow();
319   window->layer()->SetMasksToBounds(true);
320   GetBubbleFrameView()->set_background(new AppListBackground(
321       GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
322       app_list_main_view_));
323   set_background(NULL);
324   window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
325       new views::BubbleWindowTargeter(this)));
326 #else
327   set_background(new AppListBackground(
328       GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(),
329       app_list_main_view_));
330
331   // On non-aura the bubble has two widgets, and it's possible for the border
332   // to be shown independently in odd situations. Explicitly hide the bubble
333   // widget to ensure that any WM_WINDOWPOSCHANGED messages triggered by the
334   // window manager do not have the SWP_SHOWWINDOW flag set which would cause
335   // the border to be shown. See http://crbug.com/231687 .
336   GetWidget()->Hide();
337 #endif
338
339   if (delegate_)
340     delegate_->ViewInitialized();
341 }
342
343 void AppListView::OnBeforeBubbleWidgetInit(
344     views::Widget::InitParams* params,
345     views::Widget* widget) const {
346 #if defined(USE_AURA) && !defined(OS_CHROMEOS)
347   if (delegate_ && delegate_->ForceNativeDesktop())
348     params->native_widget = new views::DesktopNativeWidgetAura(widget);
349 #endif
350 #if defined(OS_WIN)
351   // Windows 7 and higher offer pinning to the taskbar, but we need presence
352   // on the taskbar for the user to be able to pin us. So, show the window on
353   // the taskbar for these versions of Windows.
354   if (base::win::GetVersion() >= base::win::VERSION_WIN7)
355     params->force_show_in_taskbar = true;
356 #elif defined(OS_LINUX)
357   // Set up a custom WM_CLASS for the app launcher window. This allows task
358   // switchers in X11 environments to distinguish it from main browser windows.
359   params->wm_class_name = kAppListWMClass;
360   // Show the window in the taskbar, even though it is a bubble, which would not
361   // normally be shown.
362   params->force_show_in_taskbar = true;
363 #endif
364 }
365
366 views::View* AppListView::GetInitiallyFocusedView() {
367   return app_list_main_view_->search_box_view()->search_box();
368 }
369
370 gfx::ImageSkia AppListView::GetWindowIcon() {
371   if (delegate_)
372     return delegate_->GetWindowIcon();
373
374   return gfx::ImageSkia();
375 }
376
377 bool AppListView::WidgetHasHitTestMask() const {
378   return true;
379 }
380
381 void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const {
382   DCHECK(mask);
383   mask->addRect(gfx::RectToSkRect(
384       GetBubbleFrameView()->GetContentsBounds()));
385 }
386
387 bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) {
388   // The accelerator is added by BubbleDelegateView.
389   if (accelerator.key_code() == ui::VKEY_ESCAPE) {
390     if (app_list_main_view_->search_box_view()->HasSearch()) {
391       app_list_main_view_->search_box_view()->ClearSearch();
392     } else if (app_list_main_view_->contents_view()
393                    ->apps_container_view()
394                    ->IsInFolderView()) {
395       app_list_main_view_->contents_view()
396           ->apps_container_view()
397           ->app_list_folder_view()
398           ->CloseFolderPage();
399       return true;
400     } else {
401       GetWidget()->Deactivate();
402       Close();
403     }
404     return true;
405   }
406
407   return false;
408 }
409
410 void AppListView::Layout() {
411   const gfx::Rect contents_bounds = GetContentsBounds();
412   app_list_main_view_->SetBoundsRect(contents_bounds);
413   signin_view_->SetBoundsRect(contents_bounds);
414
415   if (speech_view_) {
416     gfx::Rect speech_bounds = contents_bounds;
417     int preferred_height = speech_view_->GetPreferredSize().height();
418     speech_bounds.Inset(kSpeechUIMargin, kSpeechUIMargin);
419     speech_bounds.set_height(std::min(speech_bounds.height(),
420                                       preferred_height));
421     speech_bounds.Inset(-speech_view_->GetInsets());
422     speech_view_->SetBoundsRect(speech_bounds);
423   }
424 }
425
426 void AppListView::SchedulePaintInRect(const gfx::Rect& rect) {
427   BubbleDelegateView::SchedulePaintInRect(rect);
428   if (GetBubbleFrameView())
429     GetBubbleFrameView()->SchedulePaint();
430 }
431
432 void AppListView::OnWidgetDestroying(views::Widget* widget) {
433   BubbleDelegateView::OnWidgetDestroying(widget);
434   if (delegate_ && widget == GetWidget())
435     delegate_->ViewClosing();
436 }
437
438 void AppListView::OnWidgetActivationChanged(views::Widget* widget,
439                                             bool active) {
440   // Do not called inherited function as the bubble delegate auto close
441   // functionality is not used.
442   if (widget == GetWidget())
443     FOR_EACH_OBSERVER(AppListViewObserver, observers_,
444                       OnActivationChanged(widget, active));
445 }
446
447 void AppListView::OnWidgetVisibilityChanged(views::Widget* widget,
448                                             bool visible) {
449   BubbleDelegateView::OnWidgetVisibilityChanged(widget, visible);
450
451   if (widget != GetWidget())
452     return;
453
454   if (!visible)
455     app_list_main_view_->ResetForShow();
456
457   // Whether we need to signin or not may have changed since last time we were
458   // shown.
459   Layout();
460 }
461
462 void AppListView::OnSpeechRecognitionStateChanged(
463     SpeechRecognitionState new_state) {
464   if (signin_view_->visible() || !speech_view_)
465     return;
466
467   bool recognizing = (new_state == SPEECH_RECOGNITION_RECOGNIZING ||
468                       new_state == SPEECH_RECOGNITION_IN_SPEECH);
469   // No change for this class.
470   if (speech_view_->visible() == recognizing)
471     return;
472
473   if (recognizing)
474     speech_view_->Reset();
475
476 #if defined(USE_AURA)
477   animation_observer_->set_frame(GetBubbleFrameView());
478   gfx::Transform speech_transform;
479   speech_transform.Translate(
480       0, SkFloatToMScalar(kSpeechUIAppearingPosition));
481   if (recognizing)
482     speech_view_->layer()->SetTransform(speech_transform);
483
484   {
485     ui::ScopedLayerAnimationSettings main_settings(
486         app_list_main_view_->layer()->GetAnimator());
487     if (recognizing) {
488       animation_observer_->SetTarget(app_list_main_view_);
489       main_settings.AddObserver(animation_observer_.get());
490     }
491     app_list_main_view_->layer()->SetOpacity(recognizing ? 0.0f : 1.0f);
492   }
493
494   {
495     ui::ScopedLayerAnimationSettings speech_settings(
496         speech_view_->layer()->GetAnimator());
497     if (!recognizing) {
498       animation_observer_->SetTarget(speech_view_);
499       speech_settings.AddObserver(animation_observer_.get());
500     }
501
502     speech_view_->layer()->SetOpacity(recognizing ? 1.0f : 0.0f);
503     if (recognizing)
504       speech_view_->layer()->SetTransform(gfx::Transform());
505     else
506       speech_view_->layer()->SetTransform(speech_transform);
507   }
508
509   if (recognizing)
510     speech_view_->SetVisible(true);
511   else
512     app_list_main_view_->SetVisible(true);
513 #else
514   speech_view_->SetVisible(recognizing);
515   app_list_main_view_->SetVisible(!recognizing);
516
517   // Needs to schedule paint of AppListView itself, to repaint the background.
518   GetBubbleFrameView()->SchedulePaint();
519 #endif
520 }
521
522 }  // namespace app_list