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.
5 #ifndef CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_BAR_GTK_H_
6 #define CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_BAR_GTK_H_
12 #include "base/compiler_specific.h"
13 #include "base/gtest_prod_util.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/prefs/pref_member.h"
17 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
18 #include "chrome/browser/bookmarks/bookmark_stats.h"
19 #include "chrome/browser/ui/bookmarks/bookmark_bar.h"
20 #include "chrome/browser/ui/bookmarks/bookmark_bar_instructions_delegate.h"
21 #include "chrome/browser/ui/bookmarks/bookmark_context_menu_controller.h"
22 #include "chrome/browser/ui/gtk/menu_bar_helper.h"
23 #include "content/public/browser/notification_observer.h"
24 #include "content/public/browser/notification_registrar.h"
25 #include "ui/base/gtk/gtk_signal.h"
26 #include "ui/base/gtk/owned_widget_gtk.h"
27 #include "ui/gfx/animation/animation.h"
28 #include "ui/gfx/animation/animation_delegate.h"
29 #include "ui/gfx/animation/slide_animation.h"
30 #include "ui/gfx/point.h"
31 #include "ui/gfx/size.h"
33 class BookmarkBarInstructionsGtk;
34 class BookmarkMenuController;
36 class BrowserWindowGtk;
37 class GtkThemeService;
39 class TabstripOriginProvider;
45 class BookmarkBarGtk : public gfx::AnimationDelegate,
46 public BookmarkModelObserver,
47 public MenuBarHelper::Delegate,
48 public content::NotificationObserver,
49 public BookmarkBarInstructionsDelegate,
50 public BookmarkContextMenuControllerDelegate {
52 BookmarkBarGtk(BrowserWindowGtk* window,
54 TabstripOriginProvider* tabstrip_origin_provider);
55 virtual ~BookmarkBarGtk();
57 // Returns the current browser.
58 Browser* browser() const { return browser_; }
60 // Returns the top level widget.
61 GtkWidget* widget() const { return event_box_.get(); }
63 // Sets the PageNavigator that is used when the user selects an entry on
65 void SetPageNavigator(content::PageNavigator* navigator);
67 // Create the contents of the bookmark bar.
70 // Changes the state of the bookmark bar.
71 void SetBookmarkBarState(BookmarkBar::State state,
72 BookmarkBar::AnimateChangeType animate_type);
74 // Get the current height of the bookmark bar.
77 // Returns true if the bookmark bar is showing an animation.
80 // gfx::AnimationDelegate implementation -------------------------------------
81 virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE;
82 virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE;
84 // MenuBarHelper::Delegate implementation ------------------------------------
85 virtual void PopupForButton(GtkWidget* button) OVERRIDE;
86 virtual void PopupForButtonNextTo(GtkWidget* button,
87 GtkMenuDirectionType dir) OVERRIDE;
89 // BookmarkContextMenuController::Delegate implementation --------------------
90 virtual void CloseMenu() OVERRIDE;
92 const gfx::Animation* animation() { return &slide_animation_; }
94 int max_height() const { return max_height_; }
97 FRIEND_TEST_ALL_PREFIXES(BookmarkBarGtkUnittest, DisplaysHelpMessageOnEmpty);
98 FRIEND_TEST_ALL_PREFIXES(BookmarkBarGtkUnittest,
99 HidesHelpMessageWithBookmark);
100 FRIEND_TEST_ALL_PREFIXES(BookmarkBarGtkUnittest, BuildsButtons);
102 // Change the visibility of the bookmarks bar. (Starts out hidden, per GTK's
103 // default behaviour). There are three visiblity states:
105 // Showing - bookmark bar is fully visible.
106 // Hidden - bookmark bar is hidden except for a few pixels that give
107 // extra padding to the bottom of the toolbar. Buttons are not
109 // Fullscreen - bookmark bar is fully hidden.
110 void Show(BookmarkBar::State old_state,
111 BookmarkBar::AnimateChangeType animate_type);
112 void Hide(BookmarkBar::State old_state,
113 BookmarkBar::AnimateChangeType animate_type);
115 // Calculate maximum height of bookmark bar.
116 void CalculateMaxHeight();
118 // Helper function which generates GtkToolItems for |bookmark_toolbar_|.
119 void CreateAllBookmarkButtons();
121 // Sets the visibility of the instructional text based on whether there are
122 // any bookmarks in the bookmark bar node.
123 void SetInstructionState();
125 // Sets the visibility of the overflow chevron.
126 void SetChevronState();
128 // Shows or hides the other bookmarks button depending on whether there are
130 void UpdateOtherBookmarksVisibility();
132 // Destroys all the bookmark buttons in the GtkToolbar.
133 void RemoveAllButtons();
135 // Adds the "other bookmarks" and overflow buttons.
136 void AddCoreButtons();
138 // Removes and recreates all buttons in the bar.
141 // Returns the number of buttons corresponding to starred urls/folders. This
142 // is equivalent to the number of children the bookmark bar node from the
143 // bookmark bar model has.
144 int GetBookmarkButtonCount();
146 // Returns BOOKMARK_LAUNCH_LOCATION_DETACHED_BAR or
147 // BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR based on detached state.
148 BookmarkLaunchLocation GetBookmarkLaunchLocation() const;
150 // Set the appearance of the overflow button appropriately (either chromium
151 // style or GTK style).
152 void SetOverflowButtonAppearance();
154 // Returns the index of the first bookmark that is not visible on the bar.
155 // Returns -1 if they are all visible.
156 // |extra_space| is how much extra space to give the toolbar during the
157 // calculation (for the purposes of determining if ditching the chevron
158 // would be a good idea).
159 // If non-NULL, |showing_folders| will be packed with all the folders that are
160 // showing on the bar.
161 int GetFirstHiddenBookmark(int extra_space,
162 std::vector<GtkWidget*>* showing_folders);
164 // Update the detached state (either enable or disable it, or do nothing).
165 void UpdateDetachedState(BookmarkBar::State old_state);
167 // Turns on or off the app_paintable flag on |event_box_|, depending on our
169 void UpdateEventBoxPaintability();
171 // Queue a paint on the event box.
172 void PaintEventBox();
174 // Finds the size of the current web contents, if it exists and sets |size|
175 // to the correct value. Returns false if there isn't a WebContents, a
176 // condition that can happen during testing.
177 bool GetWebContentsSize(gfx::Size* size);
179 // Connects to the "size-allocate" signal on the given widget, and causes it
180 // to throb after allocation. This is called when a new item is added to the
181 // bar. We can't call StartThrobbing directly because we don't know if it's
182 // visible or not until after the widget is allocated.
183 void StartThrobbingAfterAllocation(GtkWidget* item);
185 // Used by StartThrobbingAfterAllocation.
186 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnItemAllocate, GtkAllocation*);
188 // Makes the appropriate widget on the bookmark bar stop throbbing
189 // (a folder, the overflow chevron, or nothing).
190 void StartThrobbing(const BookmarkNode* node);
192 // Set |throbbing_widget_| to |widget|. Also makes sure that
193 // |throbbing_widget_| doesn't become stale.
194 void SetThrobbingWidget(GtkWidget* widget);
196 // An item has been dragged over the toolbar, update the drag context
197 // and toolbar UI appropriately.
198 gboolean ItemDraggedOverToolbar(
199 GdkDragContext* context, int index, guint time);
201 // When dragging in the middle of a folder, assume the user wants to drop
202 // on the folder. Towards the edges, assume the user wants to drop on the
203 // toolbar. This makes it possible to drop between two folders. This function
204 // returns the index on the toolbar the drag should target, or -1 if the
205 // drag should hit the folder.
206 int GetToolbarIndexForDragOverFolder(GtkWidget* button, gint x);
208 void ClearToolbarDropHighlighting();
210 // Overridden from BookmarkModelObserver:
212 // Invoked when the bookmark model has finished loading. Creates a button
213 // for each of the children of the root node from the model.
214 virtual void Loaded(BookmarkModel* model, bool ids_reassigned) OVERRIDE;
216 // Invoked when the model is being deleted.
217 virtual void BookmarkModelBeingDeleted(BookmarkModel* model) OVERRIDE;
219 // Invoked when a node has moved.
220 virtual void BookmarkNodeMoved(BookmarkModel* model,
221 const BookmarkNode* old_parent,
223 const BookmarkNode* new_parent,
224 int new_index) OVERRIDE;
225 virtual void BookmarkNodeAdded(BookmarkModel* model,
226 const BookmarkNode* parent,
228 virtual void BookmarkNodeRemoved(BookmarkModel* model,
229 const BookmarkNode* parent,
231 const BookmarkNode* node) OVERRIDE;
232 virtual void BookmarkAllNodesRemoved(BookmarkModel* model) OVERRIDE;
233 virtual void BookmarkNodeChanged(BookmarkModel* model,
234 const BookmarkNode* node) OVERRIDE;
235 // Invoked when a favicon has finished loading.
236 virtual void BookmarkNodeFaviconChanged(BookmarkModel* model,
237 const BookmarkNode* node) OVERRIDE;
238 virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
239 const BookmarkNode* node) OVERRIDE;
241 // Overridden from content::NotificationObserver:
242 virtual void Observe(int type,
243 const content::NotificationSource& source,
244 const content::NotificationDetails& details) OVERRIDE;
246 GtkWidget* CreateBookmarkButton(const BookmarkNode* node);
247 GtkToolItem* CreateBookmarkToolItem(const BookmarkNode* node);
249 void ConnectFolderButtonEvents(GtkWidget* widget, bool is_tool_item);
251 // Finds the BookmarkNode from the model associated with |button|.
252 const BookmarkNode* GetNodeForToolButton(GtkWidget* button);
254 // Creates and displays a popup menu for BookmarkNode |node|.
255 void PopupMenuForNode(GtkWidget* sender, const BookmarkNode* node,
256 GdkEventButton* event);
258 // GtkButton callbacks.
259 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, gboolean, OnButtonPressed,
261 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnClicked);
262 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnButtonDragBegin,
264 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnButtonDragEnd, GdkDragContext*);
265 CHROMEGTK_CALLBACK_4(BookmarkBarGtk, void, OnButtonDragGet,
266 GdkDragContext*, GtkSelectionData*, guint, guint);
268 // GtkButton callbacks for folder buttons.
269 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnFolderClicked);
271 // GtkButton callback for apps button.
272 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnAppsButtonClicked);
274 // GtkToolbar callbacks.
275 CHROMEGTK_CALLBACK_4(BookmarkBarGtk, gboolean, OnToolbarDragMotion,
276 GdkDragContext*, gint, gint, guint);
277 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnToolbarSizeAllocate,
280 // Used for both folder buttons and the toolbar.
281 CHROMEGTK_CALLBACK_6(BookmarkBarGtk, void, OnDragReceived,
282 GdkDragContext*, gint, gint, GtkSelectionData*,
284 CHROMEGTK_CALLBACK_2(BookmarkBarGtk, void, OnDragLeave,
285 GdkDragContext*, guint);
287 // Used for folder buttons.
288 CHROMEGTK_CALLBACK_4(BookmarkBarGtk, gboolean, OnFolderDragMotion,
289 GdkDragContext*, gint, gint, guint);
291 // GtkEventBox callbacks.
292 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, gboolean, OnEventBoxExpose,
294 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnEventBoxDestroy);
296 // Callbacks on our parent widget.
297 CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnParentSizeAllocate,
300 // |throbbing_widget_| callback.
301 CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnThrobbingWidgetDestroy);
303 // Overriden from BookmarkBarInstructionsDelegate:
304 virtual void ShowImportDialog() OVERRIDE;
306 // Updates the visibility of the apps shortcut button |apps_shortcut_visible_|
308 void OnAppsPageShortcutVisibilityChanged();
310 // Updates the drag&drop state when |edit_bookmarks_enabled_| changes.
311 void OnEditBookmarksEnabledChanged();
313 // Used for opening urls.
314 content::PageNavigator* page_navigator_;
317 BrowserWindowGtk* window_;
319 // Provides us with the offset into the background theme image.
320 TabstripOriginProvider* tabstrip_origin_provider_;
322 // Model providing details as to the starred entries/folders that should be
323 // shown. This is owned by the Profile.
324 BookmarkModel* model_;
326 // Contains |bookmark_hbox_|. Event box exists to prevent leakage of
327 // background color from the toplevel application window's GDK window.
328 ui::OwnedWidgetGtk event_box_;
330 // Used to detached the bookmark bar when on the NTP.
331 GtkWidget* ntp_padding_box_;
333 // Used to paint the background of the bookmark bar when in detached mode.
334 GtkWidget* paint_box_;
336 // Used to position all children.
337 GtkWidget* bookmark_hbox_;
339 // Alignment widget that is visible if there are no bookmarks on
341 GtkWidget* instructions_;
343 // BookmarkBarInstructionsGtk that holds the label and the link for importing
344 // bookmarks when there are no bookmarks on the bookmark bar.
345 scoped_ptr<BookmarkBarInstructionsGtk> instructions_gtk_;
347 // The apps page shortcut button.
348 GtkWidget* apps_shortcut_button_;
350 // GtkToolbar which contains all the bookmark buttons.
351 ui::OwnedWidgetGtk bookmark_toolbar_;
353 // The button that shows extra bookmarks that don't fit on the bookmark
355 GtkWidget* overflow_button_;
357 // A separator between the main bookmark bar area and
358 // |other_bookmarks_button_|.
359 GtkWidget* other_bookmarks_separator_;
361 // The other bookmarks button.
362 GtkWidget* other_bookmarks_button_;
364 // Padding for the other bookmarks button.
365 GtkWidget* other_padding_;
367 // The BookmarkNode from the model being dragged. NULL when we aren't
369 const BookmarkNode* dragged_node_;
371 // The visual representation that follows the cursor during drags.
372 GtkWidget* drag_icon_;
374 // We create a GtkToolbarItem from |dragged_node_| ;or display.
375 GtkToolItem* toolbar_drop_item_;
377 // Theme provider for building buttons.
378 GtkThemeService* theme_service_;
380 // Whether we should show the instructional text in the bookmark bar.
381 bool show_instructions_;
383 MenuBarHelper menu_bar_helper_;
385 // The last displayed right click menu, or NULL if no menus have been
388 scoped_ptr<BookmarkContextMenuController> current_context_menu_controller_;
390 scoped_ptr<MenuGtk> current_context_menu_;
392 // The last displayed left click menu, or NULL if no menus have been
394 scoped_ptr<BookmarkMenuController> current_menu_;
396 gfx::SlideAnimation slide_animation_;
398 // Used to optimize out |bookmark_toolbar_| size-allocate events we don't
399 // need to respond to.
400 int last_allocation_width_;
402 content::NotificationRegistrar registrar_;
404 // The size of the web contents last time we forced a paint. We keep track
405 // of this so we don't force too many paints.
406 gfx::Size last_web_contents_size_;
408 // The last coordinates recorded by OnButtonPress; used to line up the
409 // drag icon during bookmark drags.
410 gfx::Point last_pressed_coordinates_;
412 // The currently throbbing widget. This is NULL if no widget is throbbing.
413 // We track it because we only want to allow one widget to throb at a time.
414 GtkWidget* throbbing_widget_;
416 // Tracks whether the apps shortcut button should be shown.
417 BooleanPrefMember apps_shortcut_visible_;
419 // Tracks whether bookmarks can be modified.
420 BooleanPrefMember edit_bookmarks_enabled_;
422 BookmarkBar::State bookmark_bar_state_;
424 // Maximum height of the bookmark bar.
427 base::WeakPtrFactory<BookmarkBarGtk> weak_factory_;
429 DISALLOW_COPY_AND_ASSIGN(BookmarkBarGtk);
432 #endif // CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_BAR_GTK_H_