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