1// Copyright (c) 2011 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_GTK_BROWSER_ACTIONS_TOOLBAR_GTK_H_
6#define CHROME_BROWSER_UI_GTK_BROWSER_ACTIONS_TOOLBAR_GTK_H_
7#pragma once
8
9#include <map>
10#include <string>
11
12#include "base/memory/linked_ptr.h"
13#include "base/task.h"
14#include "chrome/browser/extensions/extension_toolbar_model.h"
15#include "chrome/browser/ui/gtk/custom_button.h"
16#include "chrome/browser/ui/gtk/menu_gtk.h"
17#include "chrome/browser/ui/gtk/overflow_button.h"
18#include "chrome/browser/ui/gtk/owned_widget_gtk.h"
19#include "content/common/notification_observer.h"
20#include "content/common/notification_registrar.h"
21#include "ui/base/animation/animation_delegate.h"
22#include "ui/base/animation/slide_animation.h"
23#include "ui/base/gtk/gtk_signal.h"
24#include "ui/base/gtk/gtk_signal_registrar.h"
25#include "ui/base/models/simple_menu_model.h"
26
27class Browser;
28class BrowserActionButton;
29class Extension;
30class GtkThemeService;
31class Profile;
32
33typedef struct _GdkDragContext GdkDragContext;
34typedef struct _GtkWidget GtkWidget;
35
36class BrowserActionsToolbarGtk : public ExtensionToolbarModel::Observer,
37                                 public ui::AnimationDelegate,
38                                 public MenuGtk::Delegate,
39                                 public ui::SimpleMenuModel::Delegate,
40                                 public NotificationObserver {
41 public:
42  explicit BrowserActionsToolbarGtk(Browser* browser);
43  virtual ~BrowserActionsToolbarGtk();
44
45  GtkWidget* widget() { return hbox_.get(); }
46  GtkWidget* chevron() { return overflow_button_->widget(); }
47
48  // Returns the widget in use by the BrowserActionButton corresponding to
49  // |extension|. Used in positioning the ExtensionInstalledBubble for
50  // BrowserActions.
51  GtkWidget* GetBrowserActionWidget(const Extension* extension);
52
53  int button_count() { return extension_button_map_.size(); }
54
55  Browser* browser() { return browser_; }
56
57  // Returns the currently selected tab ID, or -1 if there is none.
58  int GetCurrentTabId();
59
60  // Update the display of all buttons.
61  void Update();
62
63  // NotificationObserver implementation.
64  virtual void Observe(NotificationType type,
65                       const NotificationSource& source,
66                       const NotificationDetails& details);
67
68  bool animating() {
69    return resize_animation_.is_animating();
70  }
71
72 private:
73  friend class BrowserActionButton;
74
75  // Initialize drag and drop.
76  void SetupDrags();
77
78  // Query the extensions service for all extensions with browser actions,
79  // and create the UI for them.
80  void CreateAllButtons();
81
82  // Sets the width of the container and overflow state according to the model.
83  void SetContainerWidth();
84
85  // Create the UI for a single browser action. This will stick the button
86  // at the end of the toolbar.
87  void CreateButtonForExtension(const Extension* extension, int index);
88
89  // Delete resources associated with UI for a browser action.
90  void RemoveButtonForExtension(const Extension* extension);
91
92  // Change the visibility of widget() based on whether we have any buttons
93  // to show.
94  void UpdateVisibility();
95
96  // Hide the extension popup, if any.
97  void HidePopup();
98
99  // Animate the toolbar to show the given number of icons. This assumes the
100  // visibility of the overflow button will not change.
101  void AnimateToShowNIcons(int count);
102
103  // Returns true if this extension should be shown in this toolbar. This can
104  // return false if we are in an incognito window and the extension is disabled
105  // for incognito.
106  bool ShouldDisplayBrowserAction(const Extension* extension);
107
108  // ExtensionToolbarModel::Observer implementation.
109  virtual void BrowserActionAdded(const Extension* extension, int index);
110  virtual void BrowserActionRemoved(const Extension* extension);
111  virtual void BrowserActionMoved(const Extension* extension, int index);
112  virtual void ModelLoaded();
113
114  // ui::AnimationDelegate implementation.
115  virtual void AnimationProgressed(const ui::Animation* animation);
116  virtual void AnimationEnded(const ui::Animation* animation);
117
118  // SimpleMenuModel::Delegate implementation.
119  // In our case, |command_id| is be the index into the model's extension list.
120  virtual bool IsCommandIdChecked(int command_id) const;
121  virtual bool IsCommandIdEnabled(int command_id) const;
122  virtual bool GetAcceleratorForCommandId(
123      int command_id,
124      ui::Accelerator* accelerator);
125  virtual void ExecuteCommand(int command_id);
126
127  // MenuGtk::Delegate implementation.
128  virtual void StoppedShowing();
129  virtual bool AlwaysShowIconForCmd(int command_id) const;
130
131  // Called by the BrowserActionButton in response to drag-begin.
132  void DragStarted(BrowserActionButton* button, GdkDragContext* drag_context);
133
134  // Sets the width of the button area of the toolbar to |new_width|, clamping
135  // it to appropriate values.
136  void SetButtonHBoxWidth(int new_width);
137
138  // Shows or hides the chevron as appropriate.
139  void UpdateChevronVisibility();
140
141  CHROMEGTK_CALLBACK_4(BrowserActionsToolbarGtk, gboolean, OnDragMotion,
142                       GdkDragContext*, gint, gint, guint);
143  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, void, OnDragEnd,
144                       GdkDragContext*);
145  CHROMEGTK_CALLBACK_2(BrowserActionsToolbarGtk, gboolean, OnDragFailed,
146                       GdkDragContext*, GtkDragResult);
147  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, void, OnHierarchyChanged,
148                       GtkWidget*);
149  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, void, OnSetFocus, GtkWidget*);
150  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, gboolean,
151                       OnGripperMotionNotify, GdkEventMotion*);
152  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, gboolean, OnGripperExpose,
153                       GdkEventExpose*);
154  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, gboolean,
155                       OnGripperEnterNotify, GdkEventCrossing*);
156  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, gboolean,
157                       OnGripperLeaveNotify, GdkEventCrossing*);
158  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, gboolean,
159                       OnGripperButtonRelease, GdkEventButton*);
160  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, gboolean,
161                       OnGripperButtonPress, GdkEventButton*);
162  // The overflow button is pressed.
163  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, gboolean,
164                       OnOverflowButtonPress, GdkEventButton*);
165  // The user presses a mouse button over the popped up overflow menu.
166  CHROMEGTK_CALLBACK_1(BrowserActionsToolbarGtk, gboolean,
167                       OnOverflowMenuButtonPress, GdkEventButton*);
168  CHROMEGTK_CALLBACK_0(BrowserActionsToolbarGtk, void, OnButtonShowOrHide);
169
170  Browser* browser_;
171
172  Profile* profile_;
173  GtkThemeService* theme_service_;
174
175  ExtensionToolbarModel* model_;
176
177  // Contains the drag gripper, browser action buttons, and overflow chevron.
178  OwnedWidgetGtk hbox_;
179
180  // Contains the browser action buttons.
181  OwnedWidgetGtk button_hbox_;
182
183  // The overflow button for chrome theme mode.
184  scoped_ptr<CustomDrawButton> overflow_button_;
185  // The separator just next to the overflow button. Only shown in GTK+ theme
186  // mode. In Chrome theme mode, the overflow button has a separator built in.
187  GtkWidget* separator_;
188  scoped_ptr<MenuGtk> overflow_menu_;
189  scoped_ptr<ui::SimpleMenuModel> overflow_menu_model_;
190  GtkWidget* overflow_area_;
191  // A widget for adding extra padding to the left of the overflow button.
192  GtkWidget* overflow_alignment_;
193
194  // The button that is currently being dragged, or NULL.
195  BrowserActionButton* drag_button_;
196
197  // The new position of the button in the drag, or -1.
198  int drop_index_;
199
200  // Map from extension ID to BrowserActionButton, which is a wrapper for
201  // a chrome button and related functionality. There should be one entry
202  // for every extension that has a browser action.
203  typedef std::map<std::string, linked_ptr<BrowserActionButton> >
204      ExtensionButtonMap;
205  ExtensionButtonMap extension_button_map_;
206
207  // We use this animation for the smart resizing of the toolbar.
208  ui::SlideAnimation resize_animation_;
209  // This is the final width we are animating towards.
210  int desired_width_;
211  // This is the width we were at when we started animating.
212  int start_width_;
213
214  ui::GtkSignalRegistrar signals_;
215
216  NotificationRegistrar registrar_;
217
218  ScopedRunnableMethodFactory<BrowserActionsToolbarGtk> method_factory_;
219
220  DISALLOW_COPY_AND_ASSIGN(BrowserActionsToolbarGtk);
221};
222
223#endif  // CHROME_BROWSER_UI_GTK_BROWSER_ACTIONS_TOOLBAR_GTK_H_
224