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#ifndef CHROME_BROWSER_UI_PANELS_PANEL_H_
6#define CHROME_BROWSER_UI_PANELS_PANEL_H_
7
8#include <string>
9
10#include "base/gtest_prod_util.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/memory/weak_ptr.h"
13#include "base/strings/string16.h"
14#include "chrome/browser/command_updater.h"
15#include "chrome/browser/command_updater_delegate.h"
16#include "chrome/browser/ui/panels/panel_constants.h"
17#include "components/sessions/session_id.h"
18#include "content/public/browser/notification_observer.h"
19#include "content/public/browser/notification_registrar.h"
20#include "extensions/browser/extension_registry_observer.h"
21#include "ui/base/base_window.h"
22#include "ui/gfx/image/image.h"
23#include "ui/gfx/rect.h"
24
25class GURL;
26class NativePanel;
27class PanelCollection;
28class PanelHost;
29class PanelManager;
30class Profile;
31class StackedPanelCollection;
32
33namespace content {
34class WebContents;
35struct NativeWebKeyboardEvent;
36}
37
38namespace extensions {
39class Extension;
40class ExtensionRegistry;
41class WindowController;
42}
43
44// A platform independent implementation of ui::BaseWindow for Panels.
45// This class gets the first crack at all the ui::BaseWindow calls for Panels
46// and does one or more of the following:
47// - Do nothing.  The function is not relevant to Panels.
48// - Do Panel specific platform independent processing and then invoke the
49//   function on the platform specific member. For example, restrict panel
50//   size to certain limits.
51// - Invoke an appropriate PanelManager function to do stuff that might affect
52//   other Panels. For example deleting a panel would rearrange other panels.
53class Panel : public ui::BaseWindow,
54              public CommandUpdaterDelegate,
55              public content::NotificationObserver,
56              public extensions::ExtensionRegistryObserver {
57 public:
58  enum ExpansionState {
59    // The panel is fully expanded with both title-bar and the client-area.
60    EXPANDED,
61    // The panel is shown with the title-bar only.
62    TITLE_ONLY,
63    // The panel is shown with 3-pixel line.
64    MINIMIZED
65  };
66
67  // Controls how the attention should be drawn.
68  enum AttentionMode {
69    // Uses the panel attention. The panel's titlebar would be painted
70    // differently to attract the user's attention. This is the default mode.
71    USE_PANEL_ATTENTION = 0x01,
72    // Uses the system attention. On Windows or Linux (depending on Window
73    // Manager), the app icon on taskbar will be flashed. On MacOS, the dock
74    // icon will jump once.
75    USE_SYSTEM_ATTENTION = 0x02
76  };
77
78  virtual ~Panel();
79
80  // Returns the PanelManager associated with this panel.
81  PanelManager* manager() const;
82
83  const std::string& app_name() const { return app_name_; }
84  const gfx::Image& app_icon() const { return app_icon_; }
85  const SessionID& session_id() const { return session_id_; }
86  extensions::WindowController* extension_window_controller() const {
87    return extension_window_controller_.get();
88  }
89  const std::string extension_id() const;
90
91  CommandUpdater* command_updater();
92  Profile* profile() const;
93
94  const extensions::Extension* GetExtension() const;
95
96  // Returns web contents of the panel, if any. There may be none if web
97  // contents have not been added to the panel yet.
98  content::WebContents* GetWebContents() const;
99
100  void SetExpansionState(ExpansionState new_expansion_state);
101
102  bool IsDrawingAttention() const;
103
104  // This function will only get called by PanelManager when full screen mode
105  // changes i.e it gets called when an app goes into full screen mode or when
106  // an app exits full screen mode. Panel should respond by making sure
107  // a) it does not go on top when some app enters full screen mode.
108  // b) it remains on top when an app exits full screen mode.
109  void FullScreenModeChanged(bool is_full_screen);
110
111  int TitleOnlyHeight() const;
112
113  // Returns true if the panel can show minimize or restore button in its
114  // titlebar, depending on its state.
115  bool CanShowMinimizeButton() const;
116  bool CanShowRestoreButton() const;
117
118  // ui::BaseWindow overrides.
119  virtual bool IsActive() const OVERRIDE;
120  virtual bool IsMaximized() const OVERRIDE;
121  virtual bool IsMinimized() const OVERRIDE;
122  virtual bool IsFullscreen() const OVERRIDE;
123  virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
124  virtual gfx::Rect GetRestoredBounds() const OVERRIDE;
125  virtual ui::WindowShowState GetRestoredState() const OVERRIDE;
126  virtual gfx::Rect GetBounds() const OVERRIDE;
127  virtual void Show() OVERRIDE;
128  virtual void Hide() OVERRIDE;
129  virtual void ShowInactive() OVERRIDE;
130  virtual void Close() OVERRIDE;
131  virtual void Activate() OVERRIDE;
132  virtual void Deactivate() OVERRIDE;
133  virtual void Maximize() OVERRIDE;
134  virtual void Minimize() OVERRIDE;
135  virtual void Restore() OVERRIDE;
136  virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
137  virtual void FlashFrame(bool flash) OVERRIDE;
138  virtual bool IsAlwaysOnTop() const OVERRIDE;
139  virtual void SetAlwaysOnTop(bool on_top) OVERRIDE;
140
141  // Overridden from CommandUpdaterDelegate:
142  virtual void ExecuteCommandWithDisposition(
143      int id,
144      WindowOpenDisposition disposition) OVERRIDE;
145
146  // content::NotificationObserver overrides.
147  virtual void Observe(int type,
148                       const content::NotificationSource& source,
149                       const content::NotificationDetails& details) OVERRIDE;
150
151  //  extensions::ExtensionRegistryObserver.
152  virtual void OnExtensionUnloaded(
153      content::BrowserContext* browser_context,
154      const extensions::Extension* extension,
155      extensions::UnloadedExtensionInfo::Reason reason) OVERRIDE;
156
157  // Construct a native panel implementation.
158  static NativePanel* CreateNativePanel(Panel* panel,
159                                        const gfx::Rect& bounds,
160                                        bool always_on_top);
161
162  NativePanel* native_panel() const { return native_panel_; }
163
164  // Invoked when the native panel has detected a mouse click on the
165  // panel's titlebar, minimize or restore buttons. Behavior of the
166  // click may be modified as indicated by |modifier|.
167  void OnTitlebarClicked(panel::ClickModifier modifier);
168  void OnMinimizeButtonClicked(panel::ClickModifier modifier);
169  void OnRestoreButtonClicked(panel::ClickModifier modifier);
170
171  // Used on platforms where the panel cannot determine its window size
172  // until the window has been created. (e.g. GTK)
173  void OnWindowSizeAvailable();
174
175  // Asynchronous completion of panel close request.
176  void OnNativePanelClosed();
177
178  // May be NULL if:
179  // * panel is newly created and has not been positioned yet.
180  // * panel is being closed asynchronously.
181  // Please use it with caution.
182  PanelCollection* collection() const { return collection_; }
183
184  // Sets the current panel collection that contains this panel.
185  void set_collection(PanelCollection* new_collection) {
186    collection_ = new_collection;
187  }
188
189  StackedPanelCollection* stack() const;
190
191  ExpansionState expansion_state() const { return expansion_state_; }
192  const gfx::Size& min_size() const { return min_size_; }
193  const gfx::Size& max_size() const { return max_size_; }
194  bool auto_resizable() const { return auto_resizable_; }
195
196  bool in_preview_mode() const { return in_preview_mode_; }
197
198  panel::Resizability CanResizeByMouse() const;
199
200  AttentionMode attention_mode() const { return attention_mode_; }
201  void set_attention_mode(AttentionMode attention_mode) {
202    attention_mode_ = attention_mode;
203  }
204
205  // The full size is the size of the panel when it is detached or expanded
206  // in the docked collection and squeezing mode is not on.
207  gfx::Size full_size() const { return full_size_; }
208  void set_full_size(const gfx::Size& size) { full_size_ = size; }
209
210  // Panel must be initialized to be "fully created" and ready for use.
211  // Only called by PanelManager.
212  bool initialized() const { return initialized_; }
213  void Initialize(const GURL& url, const gfx::Rect& bounds, bool always_on_top);
214
215  // This is different from BaseWindow::SetBounds():
216  // * SetPanelBounds() is only called by PanelManager to manage its position.
217  // * SetBounds() is called by the API to try to change the bounds, which may
218  //   only change the size for Panel.
219  void SetPanelBounds(const gfx::Rect& bounds);
220
221  // Updates the panel bounds instantly without any animation.
222  void SetPanelBoundsInstantly(const gfx::Rect& bounds);
223
224  // Ensures that the panel's size does not exceed the work area by updating
225  // maximum and full size of the panel. This is called each time when display
226  // settings are changed. Note that bounds are not updated here and the call
227  // of setting bounds or refreshing layout should be called after this.
228  void LimitSizeToWorkArea(const gfx::Rect& work_area);
229
230  // Sets whether the panel will auto resize according to its content.
231  void SetAutoResizable(bool resizable);
232
233  // Configures the web contents for auto resize, including configurations
234  // on the renderer and detecting renderer changes.
235  void EnableWebContentsAutoResize(content::WebContents* web_contents);
236
237  // Invoked when the preferred window size of the given panel might need to
238  // get changed due to the contents being auto-resized.
239  void OnContentsAutoResized(const gfx::Size& new_content_size);
240
241  // Resizes the panel and sets the origin. Invoked when the panel is resized
242  // via the mouse.
243  void OnWindowResizedByMouse(const gfx::Rect& new_bounds);
244
245  // Sets minimum and maximum size for the panel.
246  void SetSizeRange(const gfx::Size& min_size, const gfx::Size& max_size);
247
248  // Updates the maximum size of the panel so that it's never smaller than the
249  // panel's desired size. Note that even if the user resizes the panel smaller
250  // later, the increased maximum size will still be in effect. Since it's not
251  // possible currently to switch the panel back to autosizing from
252  // user-resizable, it should not be a problem.
253  void IncreaseMaxSize(const gfx::Size& desired_panel_size);
254
255  // Handles keyboard events coming back from the renderer.
256  void HandleKeyboardEvent(const content::NativeWebKeyboardEvent& event);
257
258  // Sets whether the panel is shown in preview mode. When the panel is
259  // being dragged, it is in preview mode.
260  void SetPreviewMode(bool in_preview_mode);
261
262  // Sets whether the minimize or restore button, if any, are visible.
263  void UpdateMinimizeRestoreButtonVisibility();
264
265  // Changes the preferred size to acceptable based on min_size() and max_size()
266  gfx::Size ClampSize(const gfx::Size& size) const;
267
268  // Called when the panel's active state changes.
269  // |active| is true if panel became active.
270  void OnActiveStateChanged(bool active);
271
272  // Called when the panel starts/ends the user resizing.
273  void OnPanelStartUserResizing();
274  void OnPanelEndUserResizing();
275
276  // Gives beforeunload handlers the chance to cancel the close.
277  bool ShouldCloseWindow();
278
279  // Invoked when the window containing us is closing. Performs the necessary
280  // cleanup.
281  void OnWindowClosing();
282
283  // Executes a command if it's enabled.
284  // Returns true if the command is executed.
285  bool ExecuteCommandIfEnabled(int id);
286
287  // Gets the title of the window from the web contents.
288  base::string16 GetWindowTitle() const;
289
290  // Gets the Favicon of the web contents.
291  gfx::Image GetCurrentPageIcon() const;
292
293  // Updates the title bar to display the current title and icon.
294  void UpdateTitleBar();
295
296  // Updates UI to reflect change in loading state.
297  void LoadingStateChanged(bool is_loading);
298
299  // Updates UI to reflect that the web cotents receives the focus.
300  void WebContentsFocused(content::WebContents* contents);
301
302  // Moves the panel by delta instantly.
303  void MoveByInstantly(const gfx::Vector2d& delta_origin);
304
305  // Applies |corner_style| to the panel window.
306  void SetWindowCornerStyle(panel::CornerStyle corner_style);
307
308  // Performs the system minimize for the panel, i.e. becoming iconic.
309  void MinimizeBySystem();
310
311  bool IsMinimizedBySystem() const;
312
313  // Returns true if the panel is shown in the active desktop. The user could
314  // create or use multiple desktops or workspaces.
315  bool IsShownOnActiveDesktop() const;
316
317  // Turns on/off the shadow effect around the window shape.
318  void ShowShadow(bool show);
319
320 protected:
321  // Panel can only be created using PanelManager::CreatePanel() or subclass.
322  // |app_name| is the default title for Panels when the page content does not
323  // provide a title. For extensions, this is usually the application name
324  // generated from the extension id.
325  Panel(Profile* profile, const std::string& app_name,
326        const gfx::Size& min_size, const gfx::Size& max_size);
327
328 private:
329  friend class PanelManager;
330  friend class PanelBrowserTest;
331
332  enum MaxSizePolicy {
333    // Default maximum size is proportional to the work area.
334    DEFAULT_MAX_SIZE,
335    // Custom maximum size is used when the panel is resized by the user.
336    CUSTOM_MAX_SIZE
337  };
338
339  void OnImageLoaded(const gfx::Image& image);
340
341  // Initialize state for all supported commands.
342  void InitCommandState();
343
344  // Configures the renderer for auto resize (if auto resize is enabled).
345  void ConfigureAutoResize(content::WebContents* web_contents);
346
347  // Load the app's image, firing a load state change when loaded.
348  void UpdateAppIcon();
349
350  // Prepares a title string for display (removes embedded newlines, etc).
351  static void FormatTitleForDisplay(base::string16* title);
352
353  // The application name that is also the name of the window when the
354  // page content does not provide a title.
355  // This name should be set when the panel is created.
356  const std::string app_name_;
357
358  Profile* profile_;
359
360  // Current collection of panels to which this panel belongs. This determines
361  // the panel's screen layout.
362  PanelCollection* collection_;  // Owned by PanelManager.
363
364  bool initialized_;
365
366  // Stores the full size of the panel so we can restore it after it's
367  // been minimized or squeezed due to lack of space in the collection.
368  gfx::Size full_size_;
369
370  // This is the minimum size that the panel can shrink to.
371  gfx::Size min_size_;
372
373  // This is the size beyond which the panel is not going to grow to accomodate
374  // the growing content and WebKit would add the scrollbars in such case.
375  gfx::Size max_size_;
376
377  MaxSizePolicy max_size_policy_;
378
379  // True if this panel auto resizes based on content.
380  bool auto_resizable_;
381
382  // True if this panel is in preview mode. When in preview mode, panel bounds
383  // should not be affected by layout refresh. This is currently used by drag
384  // controller to add a panel to the collection without causing its bounds to
385  // change.
386  bool in_preview_mode_;
387
388  // Platform specifc implementation for panels.  It'd be one of
389  // PanelGtk/PanelView/PanelCocoa.
390  NativePanel* native_panel_;  // Weak, owns us.
391
392  AttentionMode attention_mode_;
393
394  ExpansionState expansion_state_;
395
396  // The CommandUpdater manages the window commands.
397  CommandUpdater command_updater_;
398
399  content::NotificationRegistrar registrar_;
400  extensions::ExtensionRegistry* extension_registry_;
401  const SessionID session_id_;
402  scoped_ptr<extensions::WindowController> extension_window_controller_;
403  scoped_ptr<PanelHost> panel_host_;
404
405  // Icon showed in the task bar.
406  gfx::Image app_icon_;
407
408  base::WeakPtrFactory<Panel> image_loader_ptr_factory_;
409
410  DISALLOW_COPY_AND_ASSIGN(Panel);
411};
412
413#endif  // CHROME_BROWSER_UI_PANELS_PANEL_H_
414