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:
211 virtual void BookmarkModelLoaded(BookmarkModel
* model
,
212 bool ids_reassigned
) OVERRIDE
;
213 virtual void BookmarkModelBeingDeleted(BookmarkModel
* model
) OVERRIDE
;
214 virtual void BookmarkNodeMoved(BookmarkModel
* model
,
215 const BookmarkNode
* old_parent
,
217 const BookmarkNode
* new_parent
,
218 int new_index
) OVERRIDE
;
219 virtual void BookmarkNodeAdded(BookmarkModel
* model
,
220 const BookmarkNode
* parent
,
222 virtual void BookmarkNodeRemoved(BookmarkModel
* model
,
223 const BookmarkNode
* parent
,
225 const BookmarkNode
* node
) OVERRIDE
;
226 virtual void BookmarkAllNodesRemoved(BookmarkModel
* model
) OVERRIDE
;
227 virtual void BookmarkNodeChanged(BookmarkModel
* model
,
228 const BookmarkNode
* node
) OVERRIDE
;
229 virtual void BookmarkNodeFaviconChanged(BookmarkModel
* model
,
230 const BookmarkNode
* node
) OVERRIDE
;
231 virtual void BookmarkNodeChildrenReordered(BookmarkModel
* model
,
232 const BookmarkNode
* node
) OVERRIDE
;
234 // Overridden from content::NotificationObserver:
235 virtual void Observe(int type
,
236 const content::NotificationSource
& source
,
237 const content::NotificationDetails
& details
) OVERRIDE
;
239 GtkWidget
* CreateBookmarkButton(const BookmarkNode
* node
);
240 GtkToolItem
* CreateBookmarkToolItem(const BookmarkNode
* node
);
242 void ConnectFolderButtonEvents(GtkWidget
* widget
, bool is_tool_item
);
244 // Finds the BookmarkNode from the model associated with |button|.
245 const BookmarkNode
* GetNodeForToolButton(GtkWidget
* button
);
247 // Creates and displays a popup menu for BookmarkNode |node|.
248 void PopupMenuForNode(GtkWidget
* sender
, const BookmarkNode
* node
,
249 GdkEventButton
* event
);
251 // GtkButton callbacks.
252 CHROMEGTK_CALLBACK_1(BookmarkBarGtk
, gboolean
, OnButtonPressed
,
254 CHROMEGTK_CALLBACK_0(BookmarkBarGtk
, void, OnClicked
);
255 CHROMEGTK_CALLBACK_1(BookmarkBarGtk
, void, OnButtonDragBegin
,
257 CHROMEGTK_CALLBACK_1(BookmarkBarGtk
, void, OnButtonDragEnd
, GdkDragContext
*);
258 CHROMEGTK_CALLBACK_4(BookmarkBarGtk
, void, OnButtonDragGet
,
259 GdkDragContext
*, GtkSelectionData
*, guint
, guint
);
261 // GtkButton callbacks for folder buttons.
262 CHROMEGTK_CALLBACK_0(BookmarkBarGtk
, void, OnFolderClicked
);
264 // GtkButton callback for apps button.
265 CHROMEGTK_CALLBACK_0(BookmarkBarGtk
, void, OnAppsButtonClicked
);
267 // GtkToolbar callbacks.
268 CHROMEGTK_CALLBACK_4(BookmarkBarGtk
, gboolean
, OnToolbarDragMotion
,
269 GdkDragContext
*, gint
, gint
, guint
);
270 CHROMEGTK_CALLBACK_1(BookmarkBarGtk
, void, OnToolbarSizeAllocate
,
273 // Used for both folder buttons and the toolbar.
274 CHROMEGTK_CALLBACK_6(BookmarkBarGtk
, void, OnDragReceived
,
275 GdkDragContext
*, gint
, gint
, GtkSelectionData
*,
277 CHROMEGTK_CALLBACK_2(BookmarkBarGtk
, void, OnDragLeave
,
278 GdkDragContext
*, guint
);
280 // Used for folder buttons.
281 CHROMEGTK_CALLBACK_4(BookmarkBarGtk
, gboolean
, OnFolderDragMotion
,
282 GdkDragContext
*, gint
, gint
, guint
);
284 // GtkEventBox callbacks.
285 CHROMEGTK_CALLBACK_1(BookmarkBarGtk
, gboolean
, OnEventBoxExpose
,
287 CHROMEGTK_CALLBACK_0(BookmarkBarGtk
, void, OnEventBoxDestroy
);
289 // Callbacks on our parent widget.
290 CHROMEGTK_CALLBACK_1(BookmarkBarGtk
, void, OnParentSizeAllocate
,
293 // |throbbing_widget_| callback.
294 CHROMEGTK_CALLBACK_0(BookmarkBarGtk
, void, OnThrobbingWidgetDestroy
);
296 // Overriden from BookmarkBarInstructionsDelegate:
297 virtual void ShowImportDialog() OVERRIDE
;
299 // Updates the visibility of the apps shortcut button |apps_shortcut_visible_|
301 void OnAppsPageShortcutVisibilityChanged();
303 // Updates the drag&drop state when |edit_bookmarks_enabled_| changes.
304 void OnEditBookmarksEnabledChanged();
306 // Used for opening urls.
307 content::PageNavigator
* page_navigator_
;
310 BrowserWindowGtk
* window_
;
312 // Provides us with the offset into the background theme image.
313 TabstripOriginProvider
* tabstrip_origin_provider_
;
315 // Model providing details as to the starred entries/folders that should be
316 // shown. This is owned by the Profile.
317 BookmarkModel
* model_
;
319 // Contains |bookmark_hbox_|. Event box exists to prevent leakage of
320 // background color from the toplevel application window's GDK window.
321 ui::OwnedWidgetGtk event_box_
;
323 // Used to detached the bookmark bar when on the NTP.
324 GtkWidget
* ntp_padding_box_
;
326 // Used to paint the background of the bookmark bar when in detached mode.
327 GtkWidget
* paint_box_
;
329 // Used to position all children.
330 GtkWidget
* bookmark_hbox_
;
332 // Alignment widget that is visible if there are no bookmarks on
334 GtkWidget
* instructions_
;
336 // BookmarkBarInstructionsGtk that holds the label and the link for importing
337 // bookmarks when there are no bookmarks on the bookmark bar.
338 scoped_ptr
<BookmarkBarInstructionsGtk
> instructions_gtk_
;
340 // The apps page shortcut button.
341 GtkWidget
* apps_shortcut_button_
;
343 // GtkToolbar which contains all the bookmark buttons.
344 ui::OwnedWidgetGtk bookmark_toolbar_
;
346 // The button that shows extra bookmarks that don't fit on the bookmark
348 GtkWidget
* overflow_button_
;
350 // A separator between the main bookmark bar area and
351 // |other_bookmarks_button_|.
352 GtkWidget
* other_bookmarks_separator_
;
354 // The other bookmarks button.
355 GtkWidget
* other_bookmarks_button_
;
357 // Padding for the other bookmarks button.
358 GtkWidget
* other_padding_
;
360 // The BookmarkNode from the model being dragged. NULL when we aren't
362 const BookmarkNode
* dragged_node_
;
364 // The visual representation that follows the cursor during drags.
365 GtkWidget
* drag_icon_
;
367 // We create a GtkToolbarItem from |dragged_node_| ;or display.
368 GtkToolItem
* toolbar_drop_item_
;
370 // Theme provider for building buttons.
371 GtkThemeService
* theme_service_
;
373 // Whether we should show the instructional text in the bookmark bar.
374 bool show_instructions_
;
376 MenuBarHelper menu_bar_helper_
;
378 // The last displayed right click menu, or NULL if no menus have been
381 scoped_ptr
<BookmarkContextMenuController
> current_context_menu_controller_
;
383 scoped_ptr
<MenuGtk
> current_context_menu_
;
385 // The last displayed left click menu, or NULL if no menus have been
387 scoped_ptr
<BookmarkMenuController
> current_menu_
;
389 gfx::SlideAnimation slide_animation_
;
391 // Used to optimize out |bookmark_toolbar_| size-allocate events we don't
392 // need to respond to.
393 int last_allocation_width_
;
395 content::NotificationRegistrar registrar_
;
397 // The size of the web contents last time we forced a paint. We keep track
398 // of this so we don't force too many paints.
399 gfx::Size last_web_contents_size_
;
401 // The last coordinates recorded by OnButtonPress; used to line up the
402 // drag icon during bookmark drags.
403 gfx::Point last_pressed_coordinates_
;
405 // The currently throbbing widget. This is NULL if no widget is throbbing.
406 // We track it because we only want to allow one widget to throb at a time.
407 GtkWidget
* throbbing_widget_
;
409 // Tracks whether the apps shortcut button should be shown.
410 BooleanPrefMember apps_shortcut_visible_
;
412 // Tracks whether bookmarks can be modified.
413 BooleanPrefMember edit_bookmarks_enabled_
;
415 BookmarkBar::State bookmark_bar_state_
;
417 // Maximum height of the bookmark bar.
420 base::WeakPtrFactory
<BookmarkBarGtk
> weak_factory_
;
422 DISALLOW_COPY_AND_ASSIGN(BookmarkBarGtk
);
425 #endif // CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_BAR_GTK_H_