- add sources.
[platform/framework/web/crosswalk.git] / src / ash / wm / panels / panel_window_resizer_unittest.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 "ash/wm/panels/panel_window_resizer.h"
6
7 #include "ash/launcher/launcher.h"
8 #include "ash/launcher/launcher_model.h"
9 #include "ash/root_window_controller.h"
10 #include "ash/shelf/shelf_layout_manager.h"
11 #include "ash/shelf/shelf_types.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.h"
14 #include "ash/shell_window_ids.h"
15 #include "ash/test/ash_test_base.h"
16 #include "ash/test/cursor_manager_test_api.h"
17 #include "ash/test/shell_test_api.h"
18 #include "ash/test/test_launcher_delegate.h"
19 #include "ash/wm/drag_window_resizer.h"
20 #include "ash/wm/panels/panel_layout_manager.h"
21 #include "ash/wm/window_state.h"
22 #include "base/win/windows_version.h"
23 #include "ui/aura/client/aura_constants.h"
24 #include "ui/aura/root_window.h"
25 #include "ui/base/hit_test.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/ui_base_types.h"
28 #include "ui/views/widget/widget.h"
29
30 namespace ash {
31 namespace internal {
32
33 class PanelWindowResizerTest : public test::AshTestBase {
34  public:
35   PanelWindowResizerTest() {}
36   virtual ~PanelWindowResizerTest() {}
37
38   virtual void SetUp() OVERRIDE {
39     AshTestBase::SetUp();
40     UpdateDisplay("600x400");
41     test::ShellTestApi test_api(Shell::GetInstance());
42     model_ = test_api.launcher_model();
43     launcher_delegate_ = test::TestLauncherDelegate::instance();
44   }
45
46   virtual void TearDown() OVERRIDE {
47     AshTestBase::TearDown();
48   }
49
50  protected:
51   gfx::Point CalculateDragPoint(const WindowResizer& resizer,
52                                 int delta_x,
53                                 int delta_y) const {
54     gfx::Point location = resizer.GetInitialLocation();
55     location.set_x(location.x() + delta_x);
56     location.set_y(location.y() + delta_y);
57     return location;
58   }
59
60   aura::Window* CreatePanelWindow(const gfx::Point& origin) {
61     gfx::Rect bounds(origin, gfx::Size(101, 101));
62     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
63         NULL,
64         aura::client::WINDOW_TYPE_PANEL,
65         0,
66         bounds);
67     launcher_delegate_->AddLauncherItem(window);
68     PanelLayoutManager* manager =
69         static_cast<PanelLayoutManager*>(
70             Shell::GetContainer(window->GetRootWindow(),
71                                 internal::kShellWindowId_PanelContainer)->
72                 layout_manager());
73     manager->Relayout();
74     return window;
75   }
76
77   void DragStart(aura::Window* window) {
78     resizer_.reset(CreateWindowResizer(
79         window,
80         window->bounds().origin(),
81         HTCAPTION,
82         aura::client::WINDOW_MOVE_SOURCE_MOUSE).release());
83     ASSERT_TRUE(resizer_.get());
84   }
85
86   void DragMove(int dx, int dy) {
87     resizer_->Drag(CalculateDragPoint(*resizer_, dx, dy), 0);
88   }
89
90   void DragEnd() {
91     resizer_->CompleteDrag(0);
92     resizer_.reset();
93   }
94
95   void DragRevert() {
96     resizer_->RevertDrag();
97     resizer_.reset();
98   }
99
100   // Test dragging the panel slightly, then detaching, and then reattaching
101   // dragging out by the vector (dx, dy).
102   void DetachReattachTest(aura::Window* window, int dx, int dy) {
103     wm::WindowState* window_state = wm::GetWindowState(window);
104     EXPECT_TRUE(window_state->panel_attached());
105     aura::Window* root_window = window->GetRootWindow();
106     EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
107     DragStart(window);
108     gfx::Rect initial_bounds = window->GetBoundsInScreen();
109
110     // Drag the panel slightly. The window should still be snapped to the
111     // launcher.
112     DragMove(dx * 5, dy * 5);
113     EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
114     EXPECT_EQ(initial_bounds.y(), window->GetBoundsInScreen().y());
115
116     // Drag further out and the window should now move to the cursor.
117     DragMove(dx * 100, dy * 100);
118     EXPECT_EQ(initial_bounds.x() + dx * 100, window->GetBoundsInScreen().x());
119     EXPECT_EQ(initial_bounds.y() + dy * 100, window->GetBoundsInScreen().y());
120
121     // The panel should be detached when the drag completes.
122     DragEnd();
123
124     EXPECT_FALSE(window_state->panel_attached());
125     EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
126               window->parent()->id());
127     EXPECT_EQ(root_window, window->GetRootWindow());
128
129     DragStart(window);
130     // Drag the panel down.
131     DragMove(dx * -95, dy * -95);
132     // Release the mouse and the panel should be reattached.
133     DragEnd();
134
135     // The panel should be reattached and have snapped to the launcher.
136     EXPECT_TRUE(window_state->panel_attached());
137     EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
138     EXPECT_EQ(initial_bounds.y(), window->GetBoundsInScreen().y());
139     EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
140   }
141
142   void TestWindowOrder(const std::vector<aura::Window*>& window_order) {
143     int panel_index = model_->FirstPanelIndex();
144     EXPECT_EQ((int)(panel_index + window_order.size()), model_->item_count());
145     for (std::vector<aura::Window*>::const_iterator iter =
146          window_order.begin(); iter != window_order.end();
147          ++iter, ++panel_index) {
148       LauncherID id = launcher_delegate_->GetIDByWindow(*iter);
149       EXPECT_EQ(id, model_->items()[panel_index].id);
150     }
151   }
152
153   // Test dragging panel window along the shelf and verify that panel icons
154   // are reordered appropriately.
155   void DragAlongShelfReorder(int dx, int dy) {
156     gfx::Point origin(0, 0);
157     scoped_ptr<aura::Window> w1(CreatePanelWindow(origin));
158     scoped_ptr<aura::Window> w2(CreatePanelWindow(origin));
159     std::vector<aura::Window*> window_order_original;
160     std::vector<aura::Window*> window_order_swapped;
161     window_order_original.push_back(w1.get());
162     window_order_original.push_back(w2.get());
163     window_order_swapped.push_back(w2.get());
164     window_order_swapped.push_back(w1.get());
165     TestWindowOrder(window_order_original);
166
167     // Drag window #2 to the beginning of the shelf.
168     DragStart(w2.get());
169     DragMove(400 * dx, 400 * dy);
170     TestWindowOrder(window_order_swapped);
171     DragEnd();
172
173     // Expect swapped window order.
174     TestWindowOrder(window_order_swapped);
175
176     // Drag window #2 back to the end.
177     DragStart(w2.get());
178     DragMove(-400 * dx, -400 * dy);
179     TestWindowOrder(window_order_original);
180     DragEnd();
181
182     // Expect original order.
183     TestWindowOrder(window_order_original);
184   }
185
186  private:
187   scoped_ptr<WindowResizer> resizer_;
188   internal::PanelLayoutManager* panel_layout_manager_;
189   LauncherModel* model_;
190   test::TestLauncherDelegate* launcher_delegate_;
191
192   DISALLOW_COPY_AND_ASSIGN(PanelWindowResizerTest);
193 };
194
195 class PanelWindowResizerTextDirectionTest
196     : public PanelWindowResizerTest,
197       public testing::WithParamInterface<bool> {
198  public:
199   PanelWindowResizerTextDirectionTest() : is_rtl_(GetParam()) {}
200   virtual ~PanelWindowResizerTextDirectionTest() {}
201
202   virtual void SetUp() OVERRIDE {
203     original_locale = l10n_util::GetApplicationLocale(std::string());
204     if (is_rtl_)
205       base::i18n::SetICUDefaultLocale("he");
206     PanelWindowResizerTest::SetUp();
207     ASSERT_EQ(is_rtl_, base::i18n::IsRTL());
208   }
209
210   virtual void TearDown() OVERRIDE {
211     if (is_rtl_)
212       base::i18n::SetICUDefaultLocale(original_locale);
213     PanelWindowResizerTest::TearDown();
214   }
215
216  private:
217   bool is_rtl_;
218   std::string original_locale;
219
220   DISALLOW_COPY_AND_ASSIGN(PanelWindowResizerTextDirectionTest);
221 };
222
223 // PanelLayoutManager and PanelWindowResizer should work if panels have
224 // transient children of supported types.
225 class PanelWindowResizerTransientTest
226     : public PanelWindowResizerTest,
227       public testing::WithParamInterface<aura::client::WindowType> {
228  public:
229   PanelWindowResizerTransientTest() : transient_window_type_(GetParam()) {}
230   virtual ~PanelWindowResizerTransientTest() {}
231
232  protected:
233   aura::client::WindowType transient_window_type_;
234
235  private:
236   DISALLOW_COPY_AND_ASSIGN(PanelWindowResizerTransientTest);
237 };
238
239 // Verifies a window can be dragged from the panel and detached and then
240 // reattached.
241 TEST_F(PanelWindowResizerTest, PanelDetachReattachBottom) {
242  if (!SupportsHostWindowResize())
243     return;
244
245   scoped_ptr<aura::Window> window(
246       CreatePanelWindow(gfx::Point(0, 0)));
247   DetachReattachTest(window.get(), 0, -1);
248 }
249
250 TEST_F(PanelWindowResizerTest, PanelDetachReattachLeft) {
251  if (!SupportsHostWindowResize())
252     return;
253
254   ash::Shell* shell = ash::Shell::GetInstance();
255   shell->SetShelfAlignment(SHELF_ALIGNMENT_LEFT, shell->GetPrimaryRootWindow());
256   scoped_ptr<aura::Window> window(
257       CreatePanelWindow(gfx::Point(0, 0)));
258   DetachReattachTest(window.get(), 1, 0);
259 }
260
261 TEST_F(PanelWindowResizerTest, PanelDetachReattachRight) {
262   if (!SupportsHostWindowResize())
263     return;
264
265   ash::Shell* shell = ash::Shell::GetInstance();
266   shell->SetShelfAlignment(SHELF_ALIGNMENT_RIGHT,
267                            shell->GetPrimaryRootWindow());
268   scoped_ptr<aura::Window> window(
269       CreatePanelWindow(gfx::Point(0, 0)));
270   DetachReattachTest(window.get(), -1, 0);
271 }
272
273 TEST_F(PanelWindowResizerTest, PanelDetachReattachTop) {
274  if (!SupportsHostWindowResize())
275     return;
276
277   ash::Shell* shell = ash::Shell::GetInstance();
278   shell->SetShelfAlignment(SHELF_ALIGNMENT_TOP, shell->GetPrimaryRootWindow());
279   scoped_ptr<aura::Window> window(
280       CreatePanelWindow(gfx::Point(0, 0)));
281   DetachReattachTest(window.get(), 0, 1);
282 }
283
284 TEST_F(PanelWindowResizerTest, PanelDetachReattachMultipleDisplays) {
285   if (!SupportsMultipleDisplays())
286     return;
287
288   UpdateDisplay("600x400,600x400");
289   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
290   scoped_ptr<aura::Window> window(
291       CreatePanelWindow(gfx::Point(600, 0)));
292   EXPECT_EQ(root_windows[1], window->GetRootWindow());
293   DetachReattachTest(window.get(), 0, -1);
294 }
295
296 TEST_F(PanelWindowResizerTest, DetachThenDragAcrossDisplays) {
297   if (!SupportsMultipleDisplays())
298     return;
299
300   UpdateDisplay("600x400,600x400");
301   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
302   scoped_ptr<aura::Window> window(
303       CreatePanelWindow(gfx::Point(0, 0)));
304   gfx::Rect initial_bounds = window->GetBoundsInScreen();
305   EXPECT_EQ(root_windows[0], window->GetRootWindow());
306   DragStart(window.get());
307   DragMove(0, -100);
308   DragEnd();
309   EXPECT_EQ(root_windows[0], window->GetRootWindow());
310   EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
311   EXPECT_EQ(initial_bounds.y() - 100, window->GetBoundsInScreen().y());
312   EXPECT_FALSE(wm::GetWindowState(window.get())->panel_attached());
313   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, window->parent()->id());
314
315   DragStart(window.get());
316   DragMove(500, 0);
317   DragEnd();
318   EXPECT_EQ(root_windows[1], window->GetRootWindow());
319   EXPECT_EQ(initial_bounds.x() + 500, window->GetBoundsInScreen().x());
320   EXPECT_EQ(initial_bounds.y() - 100, window->GetBoundsInScreen().y());
321   EXPECT_FALSE(wm::GetWindowState(window.get())->panel_attached());
322   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, window->parent()->id());
323 }
324
325 TEST_F(PanelWindowResizerTest, DetachAcrossDisplays) {
326   if (!SupportsMultipleDisplays())
327     return;
328
329   UpdateDisplay("600x400,600x400");
330   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
331   scoped_ptr<aura::Window> window(
332       CreatePanelWindow(gfx::Point(0, 0)));
333   gfx::Rect initial_bounds = window->GetBoundsInScreen();
334   EXPECT_EQ(root_windows[0], window->GetRootWindow());
335   DragStart(window.get());
336   DragMove(500, -100);
337   DragEnd();
338   EXPECT_EQ(root_windows[1], window->GetRootWindow());
339   EXPECT_EQ(initial_bounds.x() + 500, window->GetBoundsInScreen().x());
340   EXPECT_EQ(initial_bounds.y() - 100, window->GetBoundsInScreen().y());
341   EXPECT_FALSE(wm::GetWindowState(window.get())->panel_attached());
342   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, window->parent()->id());
343 }
344
345 TEST_F(PanelWindowResizerTest, DetachThenAttachToSecondDisplay) {
346   if (!SupportsMultipleDisplays())
347     return;
348
349   UpdateDisplay("600x400,600x600");
350   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
351   scoped_ptr<aura::Window> window(
352       CreatePanelWindow(gfx::Point(0, 0)));
353   gfx::Rect initial_bounds = window->GetBoundsInScreen();
354   EXPECT_EQ(root_windows[0], window->GetRootWindow());
355
356   // Detach the window.
357   DragStart(window.get());
358   DragMove(0, -100);
359   DragEnd();
360   EXPECT_EQ(root_windows[0], window->GetRootWindow());
361   EXPECT_FALSE(wm::GetWindowState(window.get())->panel_attached());
362
363   // Drag the window just above the other display's launcher.
364   DragStart(window.get());
365   DragMove(500, 295);
366   EXPECT_EQ(initial_bounds.x() + 500, window->GetBoundsInScreen().x());
367
368   // Should stick to other launcher.
369   EXPECT_EQ(initial_bounds.y() + 200, window->GetBoundsInScreen().y());
370   DragEnd();
371
372   // When dropped should move to second display's panel container.
373   EXPECT_EQ(root_windows[1], window->GetRootWindow());
374   EXPECT_TRUE(wm::GetWindowState(window.get())->panel_attached());
375   EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
376 }
377
378 TEST_F(PanelWindowResizerTest, AttachToSecondDisplay) {
379   if (!SupportsMultipleDisplays())
380     return;
381
382   UpdateDisplay("600x400,600x600");
383   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
384   scoped_ptr<aura::Window> window(
385       CreatePanelWindow(gfx::Point(0, 0)));
386   gfx::Rect initial_bounds = window->GetBoundsInScreen();
387   EXPECT_EQ(root_windows[0], window->GetRootWindow());
388
389   // Drag the window just above the other display's launcher.
390   DragStart(window.get());
391   DragMove(500, 195);
392   EXPECT_EQ(initial_bounds.x() + 500, window->GetBoundsInScreen().x());
393
394   // Should stick to other launcher.
395   EXPECT_EQ(initial_bounds.y() + 200, window->GetBoundsInScreen().y());
396   DragEnd();
397
398   // When dropped should move to second display's panel container.
399   EXPECT_EQ(root_windows[1], window->GetRootWindow());
400   EXPECT_TRUE(wm::GetWindowState(window.get())->panel_attached());
401   EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
402 }
403
404 TEST_F(PanelWindowResizerTest, RevertDragRestoresAttachment) {
405   scoped_ptr<aura::Window> window(
406       CreatePanelWindow(gfx::Point(0, 0)));
407   EXPECT_TRUE(wm::GetWindowState(window.get())->panel_attached());
408   EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
409   DragStart(window.get());
410   DragMove(0, -100);
411   DragRevert();
412   EXPECT_TRUE(wm::GetWindowState(window.get())->panel_attached());
413   EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
414
415   // Detach panel.
416   DragStart(window.get());
417   DragMove(0, -100);
418   DragEnd();
419   EXPECT_FALSE(wm::GetWindowState(window.get())->panel_attached());
420   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, window->parent()->id());
421
422   // Drag back to launcher.
423   DragStart(window.get());
424   DragMove(0, 100);
425
426   // When the drag is reverted it should remain detached.
427   DragRevert();
428   EXPECT_FALSE(wm::GetWindowState(window.get())->panel_attached());
429   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, window->parent()->id());
430 }
431
432 TEST_F(PanelWindowResizerTest, DragMovesToPanelLayer) {
433   scoped_ptr<aura::Window> window(CreatePanelWindow(gfx::Point(0, 0)));
434   DragStart(window.get());
435   DragMove(0, -100);
436   DragEnd();
437   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, window->parent()->id());
438
439   // While moving the panel window should be moved to the panel container.
440   DragStart(window.get());
441   DragMove(20, 0);
442   EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
443   DragEnd();
444
445   // When dropped it should return to the default container.
446   EXPECT_EQ(internal::kShellWindowId_DefaultContainer,
447             window->parent()->id());
448 }
449
450 TEST_P(PanelWindowResizerTextDirectionTest, DragReordersPanelsHorizontal) {
451   if (!SupportsHostWindowResize())
452     return;
453
454   DragAlongShelfReorder(base::i18n::IsRTL() ? 1 : -1, 0);
455 }
456
457 TEST_F(PanelWindowResizerTest, DragReordersPanelsVertical) {
458   if (!SupportsHostWindowResize())
459     return;
460
461   ash::Shell* shell = ash::Shell::GetInstance();
462   shell->SetShelfAlignment(SHELF_ALIGNMENT_LEFT, shell->GetPrimaryRootWindow());
463   DragAlongShelfReorder(0, -1);
464 }
465
466 // Tests that panels can have transient children of different types.
467 // The transient children should be reparented in sync with the panel.
468 TEST_P(PanelWindowResizerTransientTest, PanelWithTransientChild) {
469   if (!SupportsHostWindowResize())
470     return;
471
472   scoped_ptr<aura::Window> window(CreatePanelWindow(gfx::Point(0, 0)));
473   scoped_ptr<aura::Window> child(CreateTestWindowInShellWithDelegateAndType(
474       NULL, transient_window_type_, 0, gfx::Rect(20, 20, 150, 40)));
475   window->AddTransientChild(child.get());
476   if (window->parent() != child->parent())
477     window->parent()->AddChild(child.get());
478   EXPECT_EQ(window.get(), child->transient_parent());
479
480   // Drag the child to the shelf. Its new position should not be overridden.
481   const gfx::Rect attached_bounds(window->GetBoundsInScreen());
482   const int dy = window->GetBoundsInScreen().bottom() -
483       child->GetBoundsInScreen().bottom();
484   DragStart(child.get());
485   DragMove(50, dy);
486   // While moving the transient child window should be in the panel container.
487   EXPECT_EQ(internal::kShellWindowId_PanelContainer, child->parent()->id());
488   DragEnd();
489   // Child should move, |window| should not.
490   EXPECT_EQ(gfx::Point(20 + 50, 20 + dy).ToString(),
491             child->GetBoundsInScreen().origin().ToString());
492   EXPECT_EQ(attached_bounds.ToString(), window->GetBoundsInScreen().ToString());
493
494   // Drag the child along the the shelf past the |window|.
495   // Its new position should not be overridden.
496   DragStart(child.get());
497   DragMove(350, 0);
498   // While moving the transient child window should be in the panel container.
499   EXPECT_EQ(internal::kShellWindowId_PanelContainer, child->parent()->id());
500   DragEnd();
501   // |child| should move, |window| should not.
502   EXPECT_EQ(gfx::Point(20 + 50 + 350, 20 + dy).ToString(),
503             child->GetBoundsInScreen().origin().ToString());
504   EXPECT_EQ(attached_bounds.ToString(), window->GetBoundsInScreen().ToString());
505
506   DragStart(window.get());
507   DragMove(0, -100);
508   // While moving the windows should be in the panel container.
509   EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
510   EXPECT_EQ(internal::kShellWindowId_PanelContainer, child->parent()->id());
511   DragEnd();
512   // When dropped they should return to the default container.
513   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, window->parent()->id());
514   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, child->parent()->id());
515
516   // While moving the window and child should be moved to the panel container.
517   DragStart(window.get());
518   DragMove(20, 0);
519   EXPECT_EQ(internal::kShellWindowId_PanelContainer, window->parent()->id());
520   EXPECT_EQ(internal::kShellWindowId_PanelContainer, child->parent()->id());
521   DragEnd();
522
523   // When dropped they should return to the default container.
524   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, window->parent()->id());
525   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, child->parent()->id());
526 }
527
528 INSTANTIATE_TEST_CASE_P(LtrRtl, PanelWindowResizerTextDirectionTest,
529                         testing::Bool());
530 INSTANTIATE_TEST_CASE_P(NormalPanelPopup, PanelWindowResizerTransientTest,
531                         testing::Values(aura::client::WINDOW_TYPE_NORMAL,
532                                         aura::client::WINDOW_TYPE_PANEL,
533                                         aura::client::WINDOW_TYPE_POPUP));
534
535 }  // namespace internal
536 }  // namespace ash