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 "ash/shell/window_type_launcher.h"
6
7#include "ash/root_window_controller.h"
8#include "ash/screensaver/screensaver_view.h"
9#include "ash/session/session_state_delegate.h"
10#include "ash/shelf/shelf_widget.h"
11#include "ash/shell.h"
12#include "ash/shell/example_factory.h"
13#include "ash/shell/panel_window.h"
14#include "ash/shell/toplevel_window.h"
15#include "ash/shell_delegate.h"
16#include "ash/shell_window_ids.h"
17#include "ash/system/status_area_widget.h"
18#include "ash/system/web_notification/web_notification_tray.h"
19#include "ash/test/child_modal_window.h"
20#include "base/bind.h"
21#include "base/strings/utf_string_conversions.h"
22#include "base/time/time.h"
23#include "content/public/browser/browser_thread.h"
24#include "ui/aura/window.h"
25#include "ui/aura/window_event_dispatcher.h"
26#include "ui/compositor/layer.h"
27#include "ui/gfx/canvas.h"
28#include "ui/message_center/message_center.h"
29#include "ui/message_center/notification_types.h"
30#include "ui/views/controls/button/label_button.h"
31#include "ui/views/controls/menu/menu_item_view.h"
32#include "ui/views/controls/menu/menu_runner.h"
33#include "ui/views/examples/examples_window_with_content.h"
34#include "ui/views/layout/grid_layout.h"
35#include "ui/views/widget/widget.h"
36#include "ui/wm/core/shadow_types.h"
37
38using views::MenuItemView;
39using views::MenuRunner;
40
41namespace ash {
42namespace shell {
43
44namespace {
45
46SkColor g_colors[] = { SK_ColorRED,
47                       SK_ColorYELLOW,
48                       SK_ColorBLUE,
49                       SK_ColorGREEN };
50int g_color_index = 0;
51
52class ModalWindow : public views::WidgetDelegateView,
53                    public views::ButtonListener {
54 public:
55  explicit ModalWindow(ui::ModalType modal_type)
56      : modal_type_(modal_type),
57        color_(g_colors[g_color_index]),
58        open_button_(new views::LabelButton(this,
59                                            base::ASCIIToUTF16("Moar!"))) {
60    ++g_color_index %= arraysize(g_colors);
61    open_button_->SetStyle(views::Button::STYLE_BUTTON);
62    AddChildView(open_button_);
63  }
64  virtual ~ModalWindow() {
65  }
66
67  static void OpenModalWindow(aura::Window* parent, ui::ModalType modal_type) {
68    views::Widget* widget =
69        views::Widget::CreateWindowWithParent(new ModalWindow(modal_type),
70                                              parent);
71    widget->GetNativeView()->SetName("ModalWindow");
72    widget->Show();
73  }
74
75  // Overridden from views::View:
76  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
77    canvas->FillRect(GetLocalBounds(), color_);
78  }
79  virtual gfx::Size GetPreferredSize() const OVERRIDE {
80    return gfx::Size(200, 200);
81  }
82  virtual void Layout() OVERRIDE {
83    gfx::Size open_ps = open_button_->GetPreferredSize();
84    gfx::Rect local_bounds = GetLocalBounds();
85    open_button_->SetBounds(
86        5, local_bounds.bottom() - open_ps.height() - 5,
87        open_ps.width(), open_ps.height());
88  }
89
90  // Overridden from views::WidgetDelegate:
91  virtual views::View* GetContentsView() OVERRIDE {
92    return this;
93  }
94  virtual bool CanResize() const OVERRIDE {
95    return true;
96  }
97  virtual base::string16 GetWindowTitle() const OVERRIDE {
98    return base::ASCIIToUTF16("Modal Window");
99  }
100  virtual ui::ModalType GetModalType() const OVERRIDE {
101    return modal_type_;
102  }
103
104  // Overridden from views::ButtonListener:
105  virtual void ButtonPressed(views::Button* sender,
106                             const ui::Event& event) OVERRIDE {
107    DCHECK(sender == open_button_);
108    OpenModalWindow(GetWidget()->GetNativeView(), modal_type_);
109  }
110
111 private:
112  ui::ModalType modal_type_;
113  SkColor color_;
114  views::LabelButton* open_button_;
115
116  DISALLOW_COPY_AND_ASSIGN(ModalWindow);
117};
118
119class NonModalTransient : public views::WidgetDelegateView {
120 public:
121  NonModalTransient()
122      : color_(g_colors[g_color_index]) {
123    ++g_color_index %= arraysize(g_colors);
124  }
125  virtual ~NonModalTransient() {
126  }
127
128  static void OpenNonModalTransient(aura::Window* parent) {
129    views::Widget* widget =
130        views::Widget::CreateWindowWithParent(new NonModalTransient, parent);
131    widget->GetNativeView()->SetName("NonModalTransient");
132    widget->Show();
133  }
134
135  static void ToggleNonModalTransient(aura::Window* parent) {
136    if (!non_modal_transient_) {
137      non_modal_transient_ =
138          views::Widget::CreateWindowWithParent(new NonModalTransient, parent);
139      non_modal_transient_->GetNativeView()->SetName("NonModalTransient");
140    }
141    if (non_modal_transient_->IsVisible())
142      non_modal_transient_->Hide();
143    else
144      non_modal_transient_->Show();
145  }
146
147  // Overridden from views::View:
148  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
149    canvas->FillRect(GetLocalBounds(), color_);
150  }
151  virtual gfx::Size GetPreferredSize() const OVERRIDE {
152    return gfx::Size(250, 250);
153  }
154
155  // Overridden from views::WidgetDelegate:
156  virtual views::View* GetContentsView() OVERRIDE {
157    return this;
158  }
159  virtual bool CanResize() const OVERRIDE {
160    return true;
161  }
162  virtual base::string16 GetWindowTitle() const OVERRIDE {
163    return base::ASCIIToUTF16("Non-Modal Transient");
164  }
165  virtual void DeleteDelegate() OVERRIDE {
166    if (GetWidget() == non_modal_transient_)
167      non_modal_transient_ = NULL;
168
169    delete this;
170  }
171
172 private:
173  SkColor color_;
174
175  static views::Widget* non_modal_transient_;
176
177  DISALLOW_COPY_AND_ASSIGN(NonModalTransient);
178};
179
180// static
181views::Widget* NonModalTransient::non_modal_transient_ = NULL;
182
183void AddViewToLayout(views::GridLayout* layout, views::View* view) {
184  layout->StartRow(0, 0);
185  layout->AddView(view);
186  layout->AddPaddingRow(0, 5);
187}
188
189}  // namespace
190
191void InitWindowTypeLauncher() {
192  views::Widget* widget =
193      views::Widget::CreateWindowWithContextAndBounds(
194          new WindowTypeLauncher,
195          Shell::GetPrimaryRootWindow(),
196          gfx::Rect(120, 150, 300, 410));
197  widget->GetNativeView()->SetName("WindowTypeLauncher");
198  wm::SetShadowType(widget->GetNativeView(),
199                               wm::SHADOW_TYPE_RECTANGULAR);
200  widget->Show();
201}
202
203WindowTypeLauncher::WindowTypeLauncher()
204    : create_button_(new views::LabelButton(
205          this, base::ASCIIToUTF16("Create Window"))),
206      panel_button_(new views::LabelButton(
207          this, base::ASCIIToUTF16("Create Panel"))),
208      create_nonresizable_button_(new views::LabelButton(
209          this, base::ASCIIToUTF16("Create Non-Resizable Window"))),
210      bubble_button_(new views::LabelButton(
211          this, base::ASCIIToUTF16("Create Pointy Bubble"))),
212      lock_button_(new views::LabelButton(
213          this, base::ASCIIToUTF16("Lock Screen"))),
214      widgets_button_(new views::LabelButton(
215          this, base::ASCIIToUTF16("Show Example Widgets"))),
216      system_modal_button_(new views::LabelButton(
217          this, base::ASCIIToUTF16("Open System Modal Window"))),
218      window_modal_button_(new views::LabelButton(
219          this, base::ASCIIToUTF16("Open Window Modal Window"))),
220      child_modal_button_(new views::LabelButton(
221          this, base::ASCIIToUTF16("Open Child Modal Window"))),
222      transient_button_(new views::LabelButton(
223          this, base::ASCIIToUTF16("Open Non-Modal Transient Window"))),
224      examples_button_(new views::LabelButton(
225          this, base::ASCIIToUTF16("Open Views Examples Window"))),
226      show_hide_window_button_(new views::LabelButton(
227          this, base::ASCIIToUTF16("Show/Hide a Window"))),
228      show_screensaver_(new views::LabelButton(
229          this, base::ASCIIToUTF16("Show the Screensaver [for 5 seconds]"))),
230      show_web_notification_(new views::LabelButton(
231          this, base::ASCIIToUTF16("Show a web/app notification"))) {
232  create_button_->SetStyle(views::Button::STYLE_BUTTON);
233  panel_button_->SetStyle(views::Button::STYLE_BUTTON);
234  create_nonresizable_button_->SetStyle(views::Button::STYLE_BUTTON);
235  bubble_button_->SetStyle(views::Button::STYLE_BUTTON);
236  lock_button_->SetStyle(views::Button::STYLE_BUTTON);
237  widgets_button_->SetStyle(views::Button::STYLE_BUTTON);
238  system_modal_button_->SetStyle(views::Button::STYLE_BUTTON);
239  window_modal_button_->SetStyle(views::Button::STYLE_BUTTON);
240  child_modal_button_->SetStyle(views::Button::STYLE_BUTTON);
241  transient_button_->SetStyle(views::Button::STYLE_BUTTON);
242  examples_button_->SetStyle(views::Button::STYLE_BUTTON);
243  show_hide_window_button_->SetStyle(views::Button::STYLE_BUTTON);
244  show_screensaver_->SetStyle(views::Button::STYLE_BUTTON);
245  show_web_notification_->SetStyle(views::Button::STYLE_BUTTON);
246
247  views::GridLayout* layout = new views::GridLayout(this);
248  layout->SetInsets(5, 5, 5, 5);
249  SetLayoutManager(layout);
250  views::ColumnSet* column_set = layout->AddColumnSet(0);
251  column_set->AddColumn(views::GridLayout::LEADING,
252                        views::GridLayout::CENTER,
253                        0,
254                        views::GridLayout::USE_PREF,
255                        0,
256                        0);
257  AddViewToLayout(layout, create_button_);
258  AddViewToLayout(layout, panel_button_);
259  AddViewToLayout(layout, create_nonresizable_button_);
260  AddViewToLayout(layout, bubble_button_);
261  AddViewToLayout(layout, lock_button_);
262  AddViewToLayout(layout, widgets_button_);
263  AddViewToLayout(layout, system_modal_button_);
264  AddViewToLayout(layout, window_modal_button_);
265  AddViewToLayout(layout, child_modal_button_);
266  AddViewToLayout(layout, transient_button_);
267  AddViewToLayout(layout, examples_button_);
268  AddViewToLayout(layout, show_hide_window_button_);
269  AddViewToLayout(layout, show_screensaver_);
270  AddViewToLayout(layout, show_web_notification_);
271  set_context_menu_controller(this);
272}
273
274WindowTypeLauncher::~WindowTypeLauncher() {
275}
276
277void WindowTypeLauncher::OnPaint(gfx::Canvas* canvas) {
278  canvas->FillRect(GetLocalBounds(), SK_ColorWHITE);
279}
280
281bool WindowTypeLauncher::OnMousePressed(const ui::MouseEvent& event) {
282  // Overridden so we get OnMouseReleased and can show the context menu.
283  return true;
284}
285
286views::View* WindowTypeLauncher::GetContentsView() {
287  return this;
288}
289
290bool WindowTypeLauncher::CanResize() const {
291  return true;
292}
293
294base::string16 WindowTypeLauncher::GetWindowTitle() const {
295  return base::ASCIIToUTF16("Examples: Window Builder");
296}
297
298bool WindowTypeLauncher::CanMaximize() const {
299  return true;
300}
301
302bool WindowTypeLauncher::CanMinimize() const {
303  return true;
304}
305
306void WindowTypeLauncher::ButtonPressed(views::Button* sender,
307                                       const ui::Event& event) {
308  if (sender == create_button_) {
309    ToplevelWindow::CreateParams params;
310    params.can_resize = true;
311    params.can_maximize = true;
312    ToplevelWindow::CreateToplevelWindow(params);
313  } else if (sender == panel_button_) {
314    PanelWindow::CreatePanelWindow(gfx::Rect());
315  } else if (sender == create_nonresizable_button_) {
316    ToplevelWindow::CreateToplevelWindow(ToplevelWindow::CreateParams());
317  } else if (sender == bubble_button_) {
318    CreatePointyBubble(sender);
319  } else if (sender == lock_button_) {
320    Shell::GetInstance()->session_state_delegate()->LockScreen();
321  } else if (sender == widgets_button_) {
322    CreateWidgetsWindow();
323  } else if (sender == system_modal_button_) {
324    ModalWindow::OpenModalWindow(GetWidget()->GetNativeView(),
325                                 ui::MODAL_TYPE_SYSTEM);
326  } else if (sender == window_modal_button_) {
327    ModalWindow::OpenModalWindow(GetWidget()->GetNativeView(),
328                                 ui::MODAL_TYPE_WINDOW);
329  } else if (sender == child_modal_button_) {
330    ash::test::CreateChildModalParent(
331        GetWidget()->GetNativeView()->GetRootWindow());
332  } else if (sender == transient_button_) {
333    NonModalTransient::OpenNonModalTransient(GetWidget()->GetNativeView());
334  } else if (sender == show_hide_window_button_) {
335    NonModalTransient::ToggleNonModalTransient(GetWidget()->GetNativeView());
336  } else if (sender == show_screensaver_) {
337    ash::ShowScreensaver(GURL("http://www.google.com"));
338    content::BrowserThread::PostDelayedTask(content::BrowserThread::UI,
339                                            FROM_HERE,
340                                            base::Bind(&ash::CloseScreensaver),
341                                            base::TimeDelta::FromSeconds(5));
342
343  } else if (sender == show_web_notification_) {
344    scoped_ptr<message_center::Notification> notification;
345    notification.reset(new message_center::Notification(
346        message_center::NOTIFICATION_TYPE_SIMPLE,
347        "id0",
348        base::ASCIIToUTF16("Test Shell Web Notification"),
349        base::ASCIIToUTF16("Notification message body."),
350        gfx::Image(),
351        base::ASCIIToUTF16("www.testshell.org"),
352        message_center::NotifierId(
353            message_center::NotifierId::APPLICATION, "test-id"),
354        message_center::RichNotificationData(),
355        NULL /* delegate */));
356
357    ash::Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget()
358        ->web_notification_tray()->message_center()
359        ->AddNotification(notification.Pass());
360  } else if (sender == examples_button_) {
361    views::examples::ShowExamplesWindowWithContent(
362        views::examples::DO_NOTHING_ON_CLOSE,
363        Shell::GetInstance()->delegate()->GetActiveBrowserContext(),
364        NULL);
365  }
366}
367
368void WindowTypeLauncher::ExecuteCommand(int id, int event_flags) {
369  switch (id) {
370    case COMMAND_NEW_WINDOW:
371      InitWindowTypeLauncher();
372      break;
373    case COMMAND_TOGGLE_FULLSCREEN:
374      GetWidget()->SetFullscreen(!GetWidget()->IsFullscreen());
375      break;
376    default:
377      break;
378  }
379}
380
381void WindowTypeLauncher::ShowContextMenuForView(
382    views::View* source,
383    const gfx::Point& point,
384    ui::MenuSourceType source_type) {
385  MenuItemView* root = new MenuItemView(this);
386  root->AppendMenuItem(COMMAND_NEW_WINDOW,
387                       base::ASCIIToUTF16("New Window"),
388                       MenuItemView::NORMAL);
389  root->AppendMenuItem(COMMAND_TOGGLE_FULLSCREEN,
390                       base::ASCIIToUTF16("Toggle FullScreen"),
391                       MenuItemView::NORMAL);
392  // MenuRunner takes ownership of root.
393  menu_runner_.reset(new MenuRunner(
394      root, MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
395  if (menu_runner_->RunMenuAt(GetWidget(),
396                              NULL,
397                              gfx::Rect(point, gfx::Size()),
398                              views::MENU_ANCHOR_TOPLEFT,
399                              source_type) == MenuRunner::MENU_DELETED) {
400    return;
401  }
402}
403
404}  // namespace shell
405}  // namespace ash
406