Added a pref to hide the Managed Bookmarks.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / bookmarks / bookmark_bar_controller.h
blob9dad4b87a26a0ede906bfcb68d843db66e85b29b
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_COCOA_BOOKMARKS_BOOKMARK_BAR_CONTROLLER_H_
6 #define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_CONTROLLER_H_
8 #import <Cocoa/Cocoa.h>
9 #include <map>
11 #import "base/mac/cocoa_protocols.h"
12 #include "base/mac/scoped_nsobject.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h"
15 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
16 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_state.h"
17 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
18 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
19 #include "chrome/browser/ui/cocoa/tabs/tab_strip_model_observer_bridge.h"
20 #include "ui/base/window_open_disposition.h"
22 @class BookmarkBarController;
23 @class BookmarkBarFolderController;
24 @class BookmarkBarView;
25 @class BookmarkButtonCell;
26 @class BookmarkFolderTarget;
27 @class BookmarkContextMenuCocoaController;
28 class BookmarkModel;
29 class BookmarkNode;
30 class Browser;
31 class ChromeBookmarkClient;
32 class GURL;
33 namespace ui {
34 class ThemeProvider;
37 namespace bookmarks {
39 // Magic numbers from Cole
40 // TODO(jrg): create an objc-friendly version of bookmark_bar_constants.h?
42 // Used as a maximum width for buttons on the bar.
43 const CGFloat kDefaultBookmarkWidth = 150.0;
45 // Horizontal frame inset for buttons in the bookmark bar.
46 const CGFloat kBookmarkHorizontalPadding = 1.0;
48 // Vertical frame inset for buttons in the bookmark bar.
49 const CGFloat kBookmarkVerticalPadding = 2.0;
51 // Left margin before the first button in the bookmark bar.
52 const CGFloat kBookmarkLeftMargin = 2.0;
54 // Right margin before the last button in the bookmark bar.
55 const CGFloat kBookmarkRightMargin = 2.0;
57 // Used as a min/max width for buttons on menus (not on the bar).
58 const CGFloat kBookmarkMenuButtonMinimumWidth = 100.0;
59 const CGFloat kBookmarkMenuButtonMaximumWidth = 485.0;
61 // The minimum separation between a folder menu and the edge of the screen.
62 // If the menu gets closer to the edge of the screen (either right or left)
63 // then it is pops up in the opposite direction.
64 // (See -[BookmarkBarFolderController childFolderWindowLeftForWidth:]).
65 const CGFloat kBookmarkHorizontalScreenPadding = 8.0;
67 // Our NSScrollView is supposed to be just barely big enough to fit its
68 // contentView. It is actually a hair too small.
69 // This turns on horizontal scrolling which, although slight, is awkward.
70 // Make sure our window (and NSScrollView) are wider than its documentView
71 // by at least this much.
72 const CGFloat kScrollViewContentWidthMargin = 2;
74 // Make subfolder menus overlap their parent menu a bit to give a better
75 // perception of a menuing system.
76 const CGFloat kBookmarkMenuOverlap = 2.0;
78 // When constraining a scrolling bookmark bar folder window to the
79 // screen, shrink the "constrain" by this much vertically. Currently
80 // this is 0.0 to avoid a problem with tracking areas leaving the
81 // window, but should probably be 8.0 or something.
82 const CGFloat kScrollWindowVerticalMargin = 6.0;
84 // How far to offset a folder menu from the top of the bookmark bar. This
85 // is set just above the bar so that it become distinctive when drawn.
86 const CGFloat kBookmarkBarMenuOffset = 2.0;
88 // How far to offset a folder menu's left edge horizontally in relation to
89 // the left edge of the button from which it springs. Because of drawing
90 // differences, simply aligning the |frame| of each does not render the
91 // pproper result, so we have to offset.
92 const CGFloat kBookmarkBarButtonOffset = 2.0;
94 // Delay before opening a subfolder (and closing the previous one)
95 // when hovering over a folder button.
96 const NSTimeInterval kHoverOpenDelay = 0.3;
98 // Delay on hover before a submenu opens when dragging.
99 // Experimentally a drag hover open delay needs to be bigger than a
100 // normal (non-drag) menu hover open such as used in the bookmark folder.
101 // TODO(jrg): confirm feel of this constant with ui-team.
102 // http://crbug.com/36276
103 const NSTimeInterval kDragHoverOpenDelay = 0.7;
105 // Notes on use of kDragHoverCloseDelay in
106 // -[BookmarkBarFolderController draggingEntered:].
108 // We have an implicit delay on stop-hover-open before a submenu
109 // closes. This cannot be zero since it's nice to move the mouse in a
110 // direct line from "current position" to "position of item in
111 // submenu". However, by doing so, it's possible to overlap a
112 // different button on the current menu. Example:
114 // Folder1
115 // Folder2 ---> Sub1
116 // Folder3 Sub2
117 // Sub3
119 // If you hover over the F in Folder2 to open the sub, and then want to
120 // select Sub3, a direct line movement of the mouse may cross over
121 // Folder3. Without this delay, that'll cause Sub to be closed before
122 // you get there, since a "hover over" of Folder3 gets activated.
123 // It's subtle but without the delay it feels broken.
125 // This is only really a problem with vertical menu --> vertical menu
126 // movement; the bookmark bar (horizontal menu, sort of) seems fine,
127 // perhaps because mouse move direction is purely vertical so there is
128 // no opportunity for overlap.
129 const NSTimeInterval kDragHoverCloseDelay = 0.4;
131 } // namespace bookmarks
133 // The interface for the bookmark bar controller's delegate. Currently, the
134 // delegate is the BWC and is responsible for ensuring that the toolbar is
135 // displayed correctly (as specified by |-getDesiredToolbarHeightCompression|
136 // and |-toolbarDividerOpacity|) at the beginning and at the end of an animation
137 // (or after a state change).
138 @protocol BookmarkBarControllerDelegate
140 // Sent when the state has changed (after any animation), but before the final
141 // display update.
142 - (void)bookmarkBar:(BookmarkBarController*)controller
143 didChangeFromState:(BookmarkBar::State)oldState
144 toState:(BookmarkBar::State)newState;
146 // Sent before the animation begins.
147 - (void)bookmarkBar:(BookmarkBarController*)controller
148 willAnimateFromState:(BookmarkBar::State)oldState
149 toState:(BookmarkBar::State)newState;
151 @end
153 // A controller for the bookmark bar in the browser window. Handles showing
154 // and hiding based on the preference in the given profile.
155 @interface BookmarkBarController :
156 NSViewController<BookmarkBarState,
157 BookmarkBarToolbarViewController,
158 BookmarkButtonDelegate,
159 BookmarkButtonControllerProtocol,
160 NSDraggingDestination> {
161 @private
162 // The state of the bookmark bar. If an animation is running, this is set to
163 // the "destination" and |lastState_| is set to the "original" state.
164 BookmarkBar::State currentState_;
166 // The "original" state of the bookmark bar if an animation is running.
167 BookmarkBar::State lastState_;
169 // YES if an animation is running.
170 BOOL isAnimationRunning_;
172 Browser* browser_; // weak; owned by its window
173 BookmarkModel* bookmarkModel_; // weak; part of the profile owned by the
174 // top-level Browser object.
175 ChromeBookmarkClient* bookmarkClient_;
177 // Our initial view width, which is applied in awakeFromNib.
178 CGFloat initialWidth_;
180 // BookmarkNodes have a 64bit id. NSMenuItems have a 32bit tag used
181 // to represent the bookmark node they refer to. This map provides
182 // a mapping from one to the other, so we can properly identify the
183 // node from the item. When adding items in, we start with seedId_.
184 int32 seedId_;
185 std::map<int32,int64> menuTagMap_;
187 // Our bookmark buttons, ordered from L-->R.
188 base::scoped_nsobject<NSMutableArray> buttons_;
190 // The folder image so we can use one copy for all buttons
191 base::scoped_nsobject<NSImage> folderImage_;
193 // The default image, so we can use one copy for all buttons.
194 base::scoped_nsobject<NSImage> defaultImage_;
196 // If the bar is disabled, we hide it and ignore show/hide commands.
197 // Set when using fullscreen mode.
198 BOOL barIsEnabled_;
200 // Bridge from Chrome-style C++ notifications (e.g. derived from
201 // BookmarkModelObserver)
202 scoped_ptr<BookmarkBarBridge> bridge_;
204 // Delegate that is informed about state changes in the bookmark bar.
205 id<BookmarkBarControllerDelegate> delegate_; // weak
207 // Delegate that can resize us.
208 id<ViewResizer> resizeDelegate_; // weak
210 // Logic for dealing with a click on a bookmark folder button.
211 base::scoped_nsobject<BookmarkFolderTarget> folderTarget_;
213 // A controller for a pop-up bookmark folder window (custom menu).
214 // This is not a scoped_nsobject because it owns itself (when its
215 // window closes the controller gets autoreleased).
216 BookmarkBarFolderController* folderController_;
218 // The event tap that allows monitoring of all events, to properly close with
219 // a click outside the bounds of the window.
220 id exitEventTap_;
222 IBOutlet BookmarkBarView* buttonView_; // Contains 'no items' text fields.
223 IBOutlet BookmarkButton* offTheSideButton_; // aka the chevron.
225 NSRect originalNoItemsRect_; // Original, pre-resized field rect.
226 NSRect originalImportBookmarksRect_; // Original, pre-resized field rect.
228 // "Apps" button on the left side.
229 base::scoped_nsobject<BookmarkButton> appsPageShortcutButton_;
231 // "Managed bookmarks" button on the left side, next to the apps button.
232 base::scoped_nsobject<BookmarkButton> managedBookmarksButton_;
234 // "Other bookmarks" button on the right side.
235 base::scoped_nsobject<BookmarkButton> otherBookmarksButton_;
237 // When doing a drag, this is folder button "hovered over" which we
238 // may want to open after a short delay. There are cases where a
239 // mouse-enter can open a folder (e.g. if the menus are "active")
240 // but that doesn't use this variable or need a delay so "hover" is
241 // the wrong term.
242 base::scoped_nsobject<BookmarkButton> hoverButton_;
244 // We save the view width when we add bookmark buttons. This lets
245 // us avoid a rebuild until we've grown the window bigger than our
246 // initial build.
247 CGFloat savedFrameWidth_;
249 // The number of buttons we display in the bookmark bar. This does
250 // not include the "off the side" chevron or the "Other Bookmarks"
251 // button. We use this number to determine if we need to display
252 // the chevron, and to know what to place in the chevron's menu.
253 // Since we create everything before doing layout we can't be sure
254 // that all bookmark buttons we create will be visible. Thus,
255 // [buttons_ count] isn't a definitive check.
256 int displayedButtonCount_;
258 // A state flag which tracks when the bar's folder menus should be shown.
259 // An initial click in any of the folder buttons turns this on and
260 // one of the following will turn it off: another click in the button,
261 // the window losing focus, a click somewhere other than in the bar
262 // or a folder menu.
263 BOOL showFolderMenus_;
265 // If YES then state changes (for example, from hidden to shown) are animated.
266 // This is turned off for unit tests.
267 BOOL stateAnimationsEnabled_;
269 // If YES then changes inside the bookmark bar (for example, removing a
270 // bookmark) are animated. This is turned off for unit tests.
271 BOOL innerContentAnimationsEnabled_;
273 // YES if there is a possible drop about to happen in the bar.
274 BOOL hasInsertionPos_;
276 // The x point on the bar where the left edge of the new item will end
277 // up if it is dropped.
278 CGFloat insertionPos_;
280 // Controller responsible for all bookmark context menus.
281 base::scoped_nsobject<BookmarkContextMenuCocoaController>
282 contextMenuController_;
285 @property(readonly, nonatomic) BookmarkBar::State currentState;
286 @property(readonly, nonatomic) BookmarkBar::State lastState;
287 @property(readonly, nonatomic) BOOL isAnimationRunning;
288 @property(assign, nonatomic) id<BookmarkBarControllerDelegate> delegate;
289 @property(assign, nonatomic) BOOL stateAnimationsEnabled;
290 @property(assign, nonatomic) BOOL innerContentAnimationsEnabled;
292 // Initializes the bookmark bar controller with the given browser
293 // profile and delegates.
294 - (id)initWithBrowser:(Browser*)browser
295 initialWidth:(CGFloat)initialWidth
296 delegate:(id<BookmarkBarControllerDelegate>)delegate
297 resizeDelegate:(id<ViewResizer>)resizeDelegate;
299 // The Browser corresponding to this BookmarkBarController.
300 - (Browser*)browser;
302 // The controller for all bookmark bar context menus.
303 - (BookmarkContextMenuCocoaController*)menuController;
305 // Updates the bookmark bar (from its current, possibly in-transition) state to
306 // the new state.
307 - (void)updateState:(BookmarkBar::State)newState
308 changeType:(BookmarkBar::AnimateChangeType)changeType;
310 // Update the visible state of the bookmark bar.
311 - (void)updateVisibility;
313 // Update the visible state of the extra butons on the bookmark bar: the
314 // apps shortcut and the managed bookmarks folder.
315 - (void)updateExtraButtonsVisibility;
317 // Hides or shows the bookmark bar depending on the current state.
318 - (void)updateHiddenState;
320 // Turn on or off the bookmark bar and prevent or reallow its appearance. On
321 // disable, toggle off if shown. On enable, show only if needed. App and popup
322 // windows do not show a bookmark bar.
323 - (void)setBookmarkBarEnabled:(BOOL)enabled;
325 // Returns the amount by which the toolbar above should be compressed.
326 - (CGFloat)getDesiredToolbarHeightCompression;
328 // Gets the appropriate opacity for the toolbar's divider; 0 means that it
329 // shouldn't be shown.
330 - (CGFloat)toolbarDividerOpacity;
332 // Updates the sizes and positions of the subviews.
333 // TODO(viettrungluu): I'm not convinced this should be public, but I currently
334 // need it for animations. Try not to propagate its use.
335 - (void)layoutSubviews;
337 // Called by our view when it is moved to a window.
338 - (void)viewDidMoveToWindow;
340 // Provide a favicon for a bookmark node. May return nil.
341 - (NSImage*)faviconForNode:(const BookmarkNode*)node;
343 // Used for situations where the bookmark bar folder menus should no longer
344 // be actively popping up. Called when the window loses focus, a click has
345 // occured outside the menus or a bookmark has been activated. (Note that this
346 // differs from the behavior of the -[BookmarkButtonControllerProtocol
347 // closeAllBookmarkFolders] method in that the latter does not terminate menu
348 // tracking since it may be being called in response to actions (such as
349 // dragging) where a 'stale' menu presentation should first be collapsed before
350 // presenting a new menu.)
351 - (void)closeFolderAndStopTrackingMenus;
353 // Checks if operations such as edit or delete are allowed.
354 - (BOOL)canEditBookmark:(const BookmarkNode*)node;
356 // Checks if bookmark editing is enabled at all.
357 - (BOOL)canEditBookmarks;
359 // Actions for manipulating bookmarks.
360 // Open a normal bookmark or folder from a button, ...
361 - (IBAction)openBookmark:(id)sender;
362 - (IBAction)openBookmarkFolderFromButton:(id)sender;
363 // From the "off the side" button, ...
364 - (IBAction)openOffTheSideFolderFromButton:(id)sender;
365 // Import bookmarks from another browser.
366 - (IBAction)importBookmarks:(id)sender;
367 @end
369 // Redirects from BookmarkBarBridge, the C++ object which glues us to
370 // the rest of Chromium. Internal to BookmarkBarController.
371 @interface BookmarkBarController(BridgeRedirect)
372 - (void)loaded:(BookmarkModel*)model;
373 - (void)beingDeleted:(BookmarkModel*)model;
374 - (void)nodeAdded:(BookmarkModel*)model
375 parent:(const BookmarkNode*)oldParent index:(int)index;
376 - (void)nodeChanged:(BookmarkModel*)model
377 node:(const BookmarkNode*)node;
378 - (void)nodeMoved:(BookmarkModel*)model
379 oldParent:(const BookmarkNode*)oldParent oldIndex:(int)oldIndex
380 newParent:(const BookmarkNode*)newParent newIndex:(int)newIndex;
381 - (void)nodeRemoved:(BookmarkModel*)model
382 parent:(const BookmarkNode*)oldParent index:(int)index;
383 - (void)nodeFaviconLoaded:(BookmarkModel*)model
384 node:(const BookmarkNode*)node;
385 - (void)nodeChildrenReordered:(BookmarkModel*)model
386 node:(const BookmarkNode*)node;
387 @end
389 // These APIs should only be used by unit tests (or used internally).
390 @interface BookmarkBarController(InternalOrTestingAPI)
391 - (void)openBookmarkFolder:(id)sender;
392 - (BookmarkBarView*)buttonView;
393 - (NSMutableArray*)buttons;
394 - (NSButton*)offTheSideButton;
395 - (NSButton*)appsPageShortcutButton;
396 - (BOOL)offTheSideButtonIsHidden;
397 - (BOOL)appsPageShortcutButtonIsHidden;
398 - (BookmarkButton*)otherBookmarksButton;
399 - (BookmarkBarFolderController*)folderController;
400 - (id)folderTarget;
401 - (int)displayedButtonCount;
402 - (void)openURL:(GURL)url disposition:(WindowOpenDisposition)disposition;
403 - (void)clearBookmarkBar;
404 - (BookmarkButtonCell*)cellForBookmarkNode:(const BookmarkNode*)node;
405 - (BookmarkButtonCell*)cellForCustomButtonWithText:(NSString*)text
406 image:(NSImage*)image;
407 - (NSRect)frameForBookmarkButtonFromCell:(NSCell*)cell xOffset:(int*)xOffset;
408 - (void)checkForBookmarkButtonGrowth:(NSButton*)button;
409 - (void)frameDidChange;
410 - (int64)nodeIdFromMenuTag:(int32)tag;
411 - (int32)menuTagFromNodeId:(int64)menuid;
412 - (void)updateTheme:(ui::ThemeProvider*)themeProvider;
413 - (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point;
414 - (BOOL)isEventAnExitEvent:(NSEvent*)event;
415 - (BOOL)shrinkOrHideView:(NSView*)view forMaxX:(CGFloat)maxViewX;
416 - (void)unhighlightBookmark:(const BookmarkNode*)node;
418 // The following are for testing purposes only and are not used internally.
419 - (NSMenu *)menuForFolderNode:(const BookmarkNode*)node;
420 @end
422 #endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_CONTROLLER_H_