• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_BOOKMARKS_BOOKMARK_BAR_GTK_H_
6 #define CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_BAR_GTK_H_
7 #pragma once
8 
9 #include <gtk/gtk.h>
10 
11 #include <vector>
12 
13 #include "base/gtest_prod_util.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "chrome/browser/bookmarks/bookmark_context_menu_controller.h"
16 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
17 #include "chrome/browser/prefs/pref_member.h"
18 #include "chrome/browser/sync/profile_sync_service.h"
19 #include "chrome/browser/ui/gtk/bookmarks/bookmark_bar_instructions_gtk.h"
20 #include "chrome/browser/ui/gtk/menu_bar_helper.h"
21 #include "chrome/browser/ui/gtk/owned_widget_gtk.h"
22 #include "chrome/browser/ui/gtk/view_id_util.h"
23 #include "content/common/notification_observer.h"
24 #include "content/common/notification_registrar.h"
25 #include "ui/base/animation/animation.h"
26 #include "ui/base/animation/animation_delegate.h"
27 #include "ui/base/animation/slide_animation.h"
28 #include "ui/base/gtk/gtk_signal.h"
29 #include "ui/gfx/point.h"
30 #include "ui/gfx/size.h"
31 
32 class BookmarkMenuController;
33 class Browser;
34 class BrowserWindowGtk;
35 class CustomContainerButton;
36 class GtkThemeService;
37 class MenuGtk;
38 class PageNavigator;
39 class Profile;
40 class TabstripOriginProvider;
41 
42 class BookmarkBarGtk : public ui::AnimationDelegate,
43                        public ProfileSyncServiceObserver,
44                        public BookmarkModelObserver,
45                        public MenuBarHelper::Delegate,
46                        public NotificationObserver,
47                        public BookmarkBarInstructionsGtk::Delegate,
48                        public BookmarkContextMenuControllerDelegate {
49  public:
50   BookmarkBarGtk(BrowserWindowGtk* window,
51                  Profile* profile,
52                  Browser* browser,
53                  TabstripOriginProvider* tabstrip_origin_provider);
54   virtual ~BookmarkBarGtk();
55 
56   // Resets the profile. This removes any buttons for the current profile and
57   // recreates the models.
58   void SetProfile(Profile* profile);
59 
60   // Returns the current profile.
GetProfile()61   Profile* GetProfile() { return profile_; }
62 
63   // Returns the current browser.
browser()64   Browser* browser() const { return browser_; }
65 
66   // Returns the top level widget.
widget()67   GtkWidget* widget() const { return event_box_.get(); }
68 
69   // Sets the PageNavigator that is used when the user selects an entry on
70   // the bookmark bar.
71   void SetPageNavigator(PageNavigator* navigator);
72 
73   // Create the contents of the bookmark bar.
74   void Init(Profile* profile);
75 
76   // Whether the current page is the New Tag Page (which requires different
77   // rendering).
78   bool OnNewTabPage();
79 
80   // Change the visibility of the bookmarks bar. (Starts out hidden, per GTK's
81   // default behaviour). There are three visiblity states:
82   //
83   //   Showing    - bookmark bar is fully visible.
84   //   Hidden     - bookmark bar is hidden except for a few pixels that give
85   //                extra padding to the bottom of the toolbar. Buttons are not
86   //                clickable.
87   //   Fullscreen - bookmark bar is fully hidden.
88   void Show(bool animate);
89   void Hide(bool animate);
90   void EnterFullscreen();
91 
92   // Get the current height of the bookmark bar.
93   int GetHeight();
94 
95   // Returns true if the bookmark bar is showing an animation.
96   bool IsAnimating();
97 
98   // Returns true if the bookmarks bar preference is set to 'always show'.
99   bool IsAlwaysShown();
100 
101   // ui::AnimationDelegate implementation --------------------------------------
102   virtual void AnimationProgressed(const ui::Animation* animation);
103   virtual void AnimationEnded(const ui::Animation* animation);
104 
105   // MenuBarHelper::Delegate implementation ------------------------------------
106   virtual void PopupForButton(GtkWidget* button);
107   virtual void PopupForButtonNextTo(GtkWidget* button,
108                                     GtkMenuDirectionType dir);
109 
110   // The NTP needs to have access to this.
111   static const int kBookmarkBarNTPHeight;
112 
113   // BookmarkContextMenuController::Delegate implementation --------------------
114   virtual void CloseMenu();
115 
animation()116   const ui::Animation* animation() { return &slide_animation_; }
117 
118  private:
119   FRIEND_TEST_ALL_PREFIXES(BookmarkBarGtkUnittest, DisplaysHelpMessageOnEmpty);
120   FRIEND_TEST_ALL_PREFIXES(BookmarkBarGtkUnittest,
121                            HidesHelpMessageWithBookmark);
122   FRIEND_TEST_ALL_PREFIXES(BookmarkBarGtkUnittest, BuildsButtons);
123 
124   // Helper function which generates GtkToolItems for |bookmark_toolbar_|.
125   void CreateAllBookmarkButtons();
126 
127   // Sets the visibility of the instructional text based on whether there are
128   // any bookmarks in the bookmark bar node.
129   void SetInstructionState();
130 
131   // Sets the visibility of the overflow chevron.
132   void SetChevronState();
133 
134   // Helper function which destroys all the bookmark buttons in the GtkToolbar.
135   void RemoveAllBookmarkButtons();
136 
137   // Returns the number of buttons corresponding to starred urls/folders. This
138   // is equivalent to the number of children the bookmark bar node from the
139   // bookmark bar model has.
140   int GetBookmarkButtonCount();
141 
142   // Set the appearance of the overflow button appropriately (either chromium
143   // style or GTK style).
144   void SetOverflowButtonAppearance();
145 
146   // Returns the index of the first bookmark that is not visible on the bar.
147   // Returns -1 if they are all visible.
148   // |extra_space| is how much extra space to give the toolbar during the
149   // calculation (for the purposes of determining if ditching the chevron
150   // would be a good idea).
151   // If non-NULL, |showing_folders| will be packed with all the folders that are
152   // showing on the bar.
153   int GetFirstHiddenBookmark(int extra_space,
154                              std::vector<GtkWidget*>* showing_folders);
155 
156   // Returns true if the bookmark bar should be floating on the page (for
157   // NTP).
158   bool ShouldBeFloating();
159   // Update the floating state (either enable or disable it, or do nothing).
160   void UpdateFloatingState();
161 
162   // Turns on or off the app_paintable flag on |event_box_|, depending on our
163   // state.
164   void UpdateEventBoxPaintability();
165 
166   // Queue a paint on the event box.
167   void PaintEventBox();
168 
169   // Finds the size of the current tab contents, if it exists and sets |size|
170   // to the correct value. Returns false if there isn't a TabContents, a
171   // condition that can happen during testing.
172   bool GetTabContentsSize(gfx::Size* size);
173 
174   // Connects to the "size-allocate" signal on the given widget, and causes it
175   // to throb after allocation. This is called when a new item is added to the
176   // bar. We can't call StartThrobbing directly because we don't know if it's
177   // visible or not until after the widget is allocated.
178   void StartThrobbingAfterAllocation(GtkWidget* item);
179 
180   // Used by StartThrobbingAfterAllocation.
181   CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnItemAllocate, GtkAllocation*);
182 
183   // Makes the appropriate widget on the bookmark bar stop throbbing
184   // (a folder, the overflow chevron, or nothing).
185   void StartThrobbing(const BookmarkNode* node);
186 
187   // Set |throbbing_widget_| to |widget|. Also makes sure that
188   // |throbbing_widget_| doesn't become stale.
189   void SetThrobbingWidget(GtkWidget* widget);
190 
191   // An item has been dragged over the toolbar, update the drag context
192   // and toolbar UI appropriately.
193   gboolean ItemDraggedOverToolbar(
194       GdkDragContext* context, int index, guint time);
195 
196   // When dragging in the middle of a folder, assume the user wants to drop
197   // on the folder. Towards the edges, assume the user wants to drop on the
198   // toolbar. This makes it possible to drop between two folders. This function
199   // returns the index on the toolbar the drag should target, or -1 if the
200   // drag should hit the folder.
201   int GetToolbarIndexForDragOverFolder(GtkWidget* button, gint x);
202 
203   void ClearToolbarDropHighlighting();
204 
205   // Overridden from BookmarkModelObserver:
206 
207   // Invoked when the bookmark model has finished loading. Creates a button
208   // for each of the children of the root node from the model.
209   virtual void Loaded(BookmarkModel* model);
210 
211   // Invoked when the model is being deleted.
212   virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
213 
214   // Invoked when a node has moved.
215   virtual void BookmarkNodeMoved(BookmarkModel* model,
216                                  const BookmarkNode* old_parent,
217                                  int old_index,
218                                  const BookmarkNode* new_parent,
219                                  int new_index);
220   virtual void BookmarkNodeAdded(BookmarkModel* model,
221                                  const BookmarkNode* parent,
222                                  int index);
223   virtual void BookmarkNodeRemoved(BookmarkModel* model,
224                                    const BookmarkNode* parent,
225                                    int old_index,
226                                    const BookmarkNode* node);
227   virtual void BookmarkNodeChanged(BookmarkModel* model,
228                                    const BookmarkNode* node);
229   // Invoked when a favicon has finished loading.
230   virtual void BookmarkNodeFaviconLoaded(BookmarkModel* model,
231                                          const BookmarkNode* node);
232   virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
233                                              const BookmarkNode* node);
234 
235   // Overridden from NotificationObserver:
236   virtual void Observe(NotificationType type,
237                        const NotificationSource& source,
238                        const NotificationDetails& details);
239 
240   GtkWidget* CreateBookmarkButton(const BookmarkNode* node);
241   GtkToolItem* CreateBookmarkToolItem(const BookmarkNode* node);
242 
243   void ConnectFolderButtonEvents(GtkWidget* widget, bool is_tool_item);
244 
245   // Finds the BookmarkNode from the model associated with |button|.
246   const BookmarkNode* GetNodeForToolButton(GtkWidget* button);
247 
248   // Creates and displays a popup menu for BookmarkNode |node|.
249   void PopupMenuForNode(GtkWidget* sender, const BookmarkNode* node,
250                         GdkEventButton* event);
251 
252   // GtkButton callbacks.
253   CHROMEGTK_CALLBACK_1(BookmarkBarGtk, gboolean, OnButtonPressed,
254                        GdkEventButton*);
255   CHROMEGTK_CALLBACK_1(BookmarkBarGtk, gboolean, OnSyncErrorButtonPressed,
256                        GdkEventButton*);
257   CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnClicked);
258   CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnButtonDragBegin,
259                        GdkDragContext*);
260   CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnButtonDragEnd, GdkDragContext*);
261   CHROMEGTK_CALLBACK_4(BookmarkBarGtk, void, OnButtonDragGet,
262                        GdkDragContext*, GtkSelectionData*, guint, guint);
263 
264   // GtkButton callbacks for folder buttons.
265   CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnFolderClicked);
266 
267   // GtkToolbar callbacks.
268   CHROMEGTK_CALLBACK_4(BookmarkBarGtk, gboolean, OnToolbarDragMotion,
269                        GdkDragContext*, gint, gint, guint);
270   CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnToolbarSizeAllocate,
271                        GtkAllocation*);
272 
273   // Used for both folder buttons and the toolbar.
274   CHROMEGTK_CALLBACK_6(BookmarkBarGtk, void, OnDragReceived,
275                        GdkDragContext*, gint, gint, GtkSelectionData*,
276                        guint, guint);
277   CHROMEGTK_CALLBACK_2(BookmarkBarGtk, void, OnDragLeave,
278                        GdkDragContext*, guint);
279 
280   // Used for folder buttons.
281   CHROMEGTK_CALLBACK_4(BookmarkBarGtk, gboolean, OnFolderDragMotion,
282                        GdkDragContext*, gint, gint, guint);
283 
284   // GtkEventBox callbacks.
285   CHROMEGTK_CALLBACK_1(BookmarkBarGtk, gboolean, OnEventBoxExpose,
286                        GdkEventExpose*);
287   CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnEventBoxDestroy);
288 
289   // Callbacks on our parent widget.
290   CHROMEGTK_CALLBACK_1(BookmarkBarGtk, void, OnParentSizeAllocate,
291                        GtkAllocation*);
292 
293   // |throbbing_widget_| callback.
294   CHROMEGTK_CALLBACK_0(BookmarkBarGtk, void, OnThrobbingWidgetDestroy);
295 
296   // ProfileSyncServiceObserver method.
297   virtual void OnStateChanged();
298 
299   // Overriden from BookmarkBarInstructionsGtk::Delegate.
300   virtual void ShowImportDialog();
301 
302   // Updates the drag&drop state when |edit_bookmarks_enabled_| changes.
303   void OnEditBookmarksEnabledChanged();
304 
305   Profile* profile_;
306 
307   // Used for opening urls.
308   PageNavigator* page_navigator_;
309 
310   Browser* browser_;
311   BrowserWindowGtk* window_;
312 
313   // Provides us with the offset into the background theme image.
314   TabstripOriginProvider* tabstrip_origin_provider_;
315 
316   // Model providing details as to the starred entries/folders that should be
317   // shown. This is owned by the Profile.
318   BookmarkModel* model_;
319 
320   // Contains |bookmark_hbox_|. Event box exists to prevent leakage of
321   // background color from the toplevel application window's GDK window.
322   OwnedWidgetGtk event_box_;
323 
324   // Used to float the bookmark bar when on the NTP.
325   GtkWidget* ntp_padding_box_;
326 
327   // Used to paint the background of the bookmark bar when in floating mode.
328   GtkWidget* paint_box_;
329 
330   // Used to position all children.
331   GtkWidget* bookmark_hbox_;
332 
333   // Alignment widget that is visible if there are no bookmarks on
334   // the bookmar bar.
335   GtkWidget* instructions_;
336 
337   // BookmarkBarInstructionsGtk that holds the label and the link for importing
338   // bookmarks when there are no bookmarks on the bookmark bar.
339   scoped_ptr<BookmarkBarInstructionsGtk> instructions_gtk_;
340 
341   // GtkToolbar which contains all the bookmark buttons.
342   OwnedWidgetGtk bookmark_toolbar_;
343 
344   // The button that shows extra bookmarks that don't fit on the bookmark
345   // bar.
346   GtkWidget* overflow_button_;
347 
348   // The other bookmarks button.
349   GtkWidget* other_bookmarks_button_;
350 
351   // The sync error button.
352   GtkWidget* sync_error_button_;
353 
354   // A pointer to the ProfileSyncService instance if one exists.
355   ProfileSyncService* sync_service_;
356 
357   // The BookmarkNode from the model being dragged. NULL when we aren't
358   // dragging.
359   const BookmarkNode* dragged_node_;
360 
361   // The visual representation that follows the cursor during drags.
362   GtkWidget* drag_icon_;
363 
364   // We create a GtkToolbarItem from |dragged_node_| ;or display.
365   GtkToolItem* toolbar_drop_item_;
366 
367   // Theme provider for building buttons.
368   GtkThemeService* theme_service_;
369 
370   // Whether we should show the instructional text in the bookmark bar.
371   bool show_instructions_;
372 
373   MenuBarHelper menu_bar_helper_;
374 
375   // The last displayed right click menu, or NULL if no menus have been
376   // displayed yet.
377   // The controller.
378   scoped_ptr<BookmarkContextMenuController> current_context_menu_controller_;
379   // The view.
380   scoped_ptr<MenuGtk> current_context_menu_;
381 
382   // The last displayed left click menu, or NULL if no menus have been
383   // displayed yet.
384   scoped_ptr<BookmarkMenuController> current_menu_;
385 
386   ui::SlideAnimation slide_animation_;
387 
388   // Whether we are currently configured as floating (detached from the
389   // toolbar). This reflects our actual state, and can be out of sync with
390   // what ShouldShowFloating() returns.
391   bool floating_;
392 
393   // Used to optimize out |bookmark_toolbar_| size-allocate events we don't
394   // need to respond to.
395   int last_allocation_width_;
396 
397   NotificationRegistrar registrar_;
398 
399   // The size of the tab contents last time we forced a paint. We keep track
400   // of this so we don't force too many paints.
401   gfx::Size last_tab_contents_size_;
402 
403   // The last coordinates recorded by OnButtonPress; used to line up the
404   // drag icon during bookmark drags.
405   gfx::Point last_pressed_coordinates_;
406 
407   // The currently throbbing widget. This is NULL if no widget is throbbing.
408   // We track it because we only want to allow one widget to throb at a time.
409   GtkWidget* throbbing_widget_;
410 
411   // Tracks whether bookmarks can be modified.
412   BooleanPrefMember edit_bookmarks_enabled_;
413 
414   ScopedRunnableMethodFactory<BookmarkBarGtk> method_factory_;
415 };
416 
417 #endif  // CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_BAR_GTK_H_
418