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