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_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_CONTROLLER_H_ 6 #define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_CONTROLLER_H_ 7 #pragma once 8 9 #import <Cocoa/Cocoa.h> 10 11 #include "base/memory/scoped_nsobject.h" 12 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" 13 #import "chrome/browser/ui/cocoa/tracking_area.h" 14 15 @class BookmarkBarController; 16 @class BookmarkBarFolderView; 17 @class BookmarkFolderTarget; 18 @class BookmarkBarFolderHoverState; 19 @class BookmarkBarFolderWindow; 20 @class BookmarkBarFolderWindowContentView; 21 22 // A controller for the pop-up windows from bookmark folder buttons 23 // which look sort of like menus. 24 @interface BookmarkBarFolderController : 25 NSWindowController<BookmarkButtonDelegate, 26 BookmarkButtonControllerProtocol, 27 NSUserInterfaceValidations> { 28 @private 29 // The button whose click opened us. 30 scoped_nsobject<BookmarkButton> parentButton_; 31 32 // Bookmark bar folder controller chains are torn down in two ways: 33 // 1. Clicking "outside" the folder (see use of 34 // CrApplicationEventHookProtocol in the bookmark bar controller). 35 // 2. Engaging a different folder (via hover over or explicit click). 36 // 37 // In either case, the BookmarkButtonControllerProtocol method 38 // closeAllBookmarkFolders gets called. For bookmark bar folder 39 // controllers, this is passed up the chain so we begin with a top 40 // level "close". 41 // When any bookmark folder window closes, it necessarily tells 42 // subcontroller windows to close (down the chain), and autoreleases 43 // the controller. (Must autorelease since the controller can still 44 // get delegate events such as windowDidClose). 45 // 46 // Bookmark bar folder controllers own their buttons. When doing 47 // drag and drop of a button from one sub-sub-folder to a different 48 // sub-sub-folder, we need to make sure the button's pointers stay 49 // valid until we've dropped (or cancelled). Note that such a drag 50 // causes the source sub-sub-folder (previous parent window) to go 51 // away (windows close, controllers autoreleased) since you're 52 // hovering over a different folder chain for dropping. To keep 53 // things valid (like the button's target, its delegate, the parent 54 // cotroller that we have a pointer to below [below], etc), we heep 55 // strong pointers to our owning controller, so the entire chain 56 // stays owned. 57 58 // Our parent controller, if we are a nested folder, otherwise nil. 59 // Strong to insure the object lives as long as we need it. 60 scoped_nsobject<BookmarkBarFolderController> parentController_; 61 62 // The main bar controller from whence we or a parent sprang. 63 BookmarkBarController* barController_; // WEAK: It owns us. 64 65 // Our buttons. We do not have buttons for nested folders. 66 scoped_nsobject<NSMutableArray> buttons_; 67 68 // The scroll view that contains our main button view (below). 69 IBOutlet NSScrollView* scrollView_; 70 71 // The view defining the visible area in which we draw our content. 72 IBOutlet BookmarkBarFolderWindowContentView* visibleView_; 73 74 // The main view of this window (where the buttons go) within the scroller. 75 IBOutlet BookmarkBarFolderView* folderView_; 76 77 // A window used to show the shadow behind the main window when it is 78 // scrollable. (A 'shadow' window is needed because the main window, when 79 // scrollable in either or both directions, will reach completely to the 80 // top and/or bottom edge of the screen in order to support mouse tracking 81 // during scrolling operations. In that case, though, the 'visible' 82 // window must be inset a bit from the edge of the screen for aesthetics; 83 // it will also be inset much more from the bottom of the screen when the 84 // Dock is showing. When scrollable, the main window would show a shadow 85 // incorrectly positioned, hence the 'shadow' window.) 86 IBOutlet BookmarkBarFolderWindow* shadowWindow_; 87 88 // The up and down scroll arrow views. These arrows are hidden and shown 89 // as necessary (when scrolling is possible) and are contained in the nib 90 // as siblings to the scroll view. 91 IBOutlet NSView* scrollDownArrowView_; // Positioned at the top. 92 IBOutlet NSView* scrollUpArrowView_; // Positioned at the bottom. 93 94 // YES if subfolders should grow to the right (the default). 95 // Direction switches if we'd grow off the screen. 96 BOOL subFolderGrowthToRight_; 97 98 // Weak; we keep track to work around a 99 // setShowsBorderOnlyWhileMouseInside bug. 100 BookmarkButton* buttonThatMouseIsIn_; 101 102 // The context menu for a bookmark button which represents an URL. 103 IBOutlet NSMenu* buttonMenu_; 104 105 // The context menu for a bookmark button which represents a folder. 106 IBOutlet NSMenu* folderMenu_; 107 108 // We model hover state as a state machine with specific allowable 109 // transitions. |hoverState_| is the state of this machine at any 110 // given time. 111 scoped_nsobject<BookmarkBarFolderHoverState> hoverState_; 112 113 // Logic for dealing with a click on a bookmark folder button. 114 scoped_nsobject<BookmarkFolderTarget> folderTarget_; 115 116 // A controller for a pop-up bookmark folder window (custom menu). 117 // We (self) are the parentController_ for our folderController_. 118 // This is not a scoped_nsobject because it owns itself (when its 119 // window closes the controller gets autoreleased). 120 BookmarkBarFolderController* folderController_; 121 122 // Implement basic menu scrolling through this tracking area. 123 ScopedCrTrackingArea scrollTrackingArea_; 124 125 // Timer to continue scrolling as needed. We own the timer but 126 // don't release it when done (we invalidate it). 127 NSTimer* scrollTimer_; 128 129 // Precalculated sum of left and right edge padding of buttons in a 130 // folder menu window. This is calculated from the widths of the main 131 // folder menu window and the scroll view within. 132 CGFloat padding_; 133 134 // Amount to scroll by on each timer fire. Can be + or -. 135 CGFloat verticalScrollDelta_; 136 137 // We need to know the size of the vertical scrolling arrows so we 138 // can obscure/unobscure them. 139 CGFloat verticalScrollArrowHeight_; 140 141 // Set to YES to prevent any node animations. Useful for unit testing so that 142 // incomplete animations do not cause valgrind complaints. 143 BOOL ignoreAnimations_; 144 145 int selectedIndex_; 146 NSString* typedPrefix_; 147 } 148 149 // Designated initializer. 150 - (id)initWithParentButton:(BookmarkButton*)button 151 parentController:(BookmarkBarFolderController*)parentController 152 barController:(BookmarkBarController*)barController; 153 154 // Return the parent button that owns the bookmark folder we represent. 155 - (BookmarkButton*)parentButton; 156 157 // Text typed by user, for type-select and arrow key support. 158 // Returns YES if the menu should be closed now. 159 - (BOOL)handleInputText:(NSString*)newText; 160 161 // If you wanted to clear the type-select buffer. Currently only used 162 // internally. 163 - (void)clearInputText; 164 165 // Gets notified when a fav icon asynchronously loads, so we can now use the 166 // real icon instead of a generic placeholder. 167 - (void)faviconLoadedForNode:(const BookmarkNode*)node; 168 169 - (void)setSelectedButtonByIndex:(int)index; 170 171 // Offset our folder menu window. This is usually needed in response to a 172 // parent folder menu window or the bookmark bar changing position due to 173 // the dragging of a bookmark node from the parent into this folder menu. 174 - (void)offsetFolderMenuWindow:(NSSize)offset; 175 176 // Re-layout the window menu in case some buttons were added or removed, 177 // specifically as a result of the bookmark bar changing configuration 178 // and altering the contents of the off-the-side folder. 179 - (void)reconfigureMenu; 180 181 // Actions from a context menu over a button or folder. 182 - (IBAction)cutBookmark:(id)sender; 183 - (IBAction)copyBookmark:(id)sender; 184 - (IBAction)pasteBookmark:(id)sender; 185 - (IBAction)deleteBookmark:(id)sender; 186 187 // Passed up by a child view to tell us of a desire to scroll. 188 - (void)scrollWheel:(NSEvent *)theEvent; 189 190 - (void)mouseDragged:(NSEvent*)theEvent; 191 192 193 // Forwarded to the associated BookmarkBarController. 194 - (IBAction)addFolder:(id)sender; 195 - (IBAction)addPage:(id)sender; 196 - (IBAction)editBookmark:(id)sender; 197 - (IBAction)openBookmark:(id)sender; 198 - (IBAction)openAllBookmarks:(id)sender; 199 - (IBAction)openAllBookmarksIncognitoWindow:(id)sender; 200 - (IBAction)openAllBookmarksNewWindow:(id)sender; 201 - (IBAction)openBookmarkInIncognitoWindow:(id)sender; 202 - (IBAction)openBookmarkInNewForegroundTab:(id)sender; 203 - (IBAction)openBookmarkInNewWindow:(id)sender; 204 205 @property(assign, nonatomic) BOOL subFolderGrowthToRight; 206 207 @end 208 209 @interface BookmarkBarFolderController(TestingAPI) 210 - (NSPoint)windowTopLeftForWidth:(int)windowWidth 211 height:(int)windowHeight; 212 - (NSArray*)buttons; 213 - (BookmarkBarFolderController*)folderController; 214 - (id)folderTarget; 215 - (void)configureWindowLevel; 216 - (void)performOneScroll:(CGFloat)delta; 217 - (BookmarkButton*)buttonThatMouseIsIn; 218 // Set to YES in order to prevent animations. 219 - (void)setIgnoreAnimations:(BOOL)ignore; 220 221 // Return YES if the scroll-up or scroll-down arrows are showing. 222 - (BOOL)canScrollUp; 223 - (BOOL)canScrollDown; 224 - (CGFloat)verticalScrollArrowHeight; 225 - (NSView*)visibleView; 226 - (NSScrollView*)scrollView; 227 - (NSView*)folderView; 228 229 - (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point; 230 @end 231 232 #endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_CONTROLLER_H_ 233