OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" | 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #import "base/mac/bundle_locations.h" | 9 #import "base/mac/bundle_locations.h" |
10 #import "base/mac/foundation_util.h" | 10 #import "base/mac/foundation_util.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa.h" | 36 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa.h" |
37 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" | 37 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" |
38 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h" | 38 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h" |
39 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controlle
r.h" | 39 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controlle
r.h" |
40 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h" | 40 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h" |
41 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" | 41 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" |
42 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h" | 42 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h" |
43 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h" | 43 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h" |
44 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h" | 44 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h" |
45 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | 45 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
46 #import "chrome/browser/ui/cocoa/l10n_util.h" | |
47 #import "chrome/browser/ui/cocoa/menu_button.h" | 46 #import "chrome/browser/ui/cocoa/menu_button.h" |
48 #import "chrome/browser/ui/cocoa/themed_window.h" | 47 #import "chrome/browser/ui/cocoa/themed_window.h" |
49 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" | 48 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" |
50 #import "chrome/browser/ui/cocoa/view_id_util.h" | 49 #import "chrome/browser/ui/cocoa/view_id_util.h" |
51 #import "chrome/browser/ui/cocoa/view_resizer.h" | 50 #import "chrome/browser/ui/cocoa/view_resizer.h" |
52 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 51 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
53 #include "chrome/common/extensions/extension_constants.h" | 52 #include "chrome/common/extensions/extension_constants.h" |
54 #include "chrome/common/extensions/extension_metrics.h" | 53 #include "chrome/common/extensions/extension_metrics.h" |
55 #include "chrome/common/url_constants.h" | 54 #include "chrome/common/url_constants.h" |
56 #include "chrome/grit/generated_resources.h" | 55 #include "chrome/grit/generated_resources.h" |
(...skipping 15 matching lines...) Expand all Loading... |
72 #include "ui/base/l10n/l10n_util_mac.h" | 71 #include "ui/base/l10n/l10n_util_mac.h" |
73 #include "ui/base/material_design/material_design_controller.h" | 72 #include "ui/base/material_design/material_design_controller.h" |
74 #include "ui/base/resource/resource_bundle.h" | 73 #include "ui/base/resource/resource_bundle.h" |
75 #include "ui/gfx/color_palette.h" | 74 #include "ui/gfx/color_palette.h" |
76 #include "ui/gfx/image/image.h" | 75 #include "ui/gfx/image/image.h" |
77 #include "ui/gfx/image/image_skia_util_mac.h" | 76 #include "ui/gfx/image/image_skia_util_mac.h" |
78 #include "ui/gfx/paint_vector_icon.h" | 77 #include "ui/gfx/paint_vector_icon.h" |
79 #include "ui/resources/grit/ui_resources.h" | 78 #include "ui/resources/grit/ui_resources.h" |
80 | 79 |
81 using base::UserMetricsAction; | 80 using base::UserMetricsAction; |
82 using bookmarks::BookmarkBarLayout; | |
83 using bookmarks::BookmarkModel; | 81 using bookmarks::BookmarkModel; |
84 using bookmarks::BookmarkNode; | 82 using bookmarks::BookmarkNode; |
85 using bookmarks::BookmarkNodeData; | 83 using bookmarks::BookmarkNodeData; |
86 using content::OpenURLParams; | 84 using content::OpenURLParams; |
87 using content::Referrer; | 85 using content::Referrer; |
88 using content::WebContents; | 86 using content::WebContents; |
89 | 87 |
90 // Bookmark bar state changing and animations | 88 // Bookmark bar state changing and animations |
91 // | 89 // |
92 // The bookmark bar has three real states: "showing" (a normal bar attached to | 90 // The bookmark bar has three real states: "showing" (a normal bar attached to |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 // Pointers to animation logic: | 137 // Pointers to animation logic: |
140 // - |-moveToState:withAnimation:| starts animations, deciding which ones we | 138 // - |-moveToState:withAnimation:| starts animations, deciding which ones we |
141 // know how to handle. | 139 // know how to handle. |
142 // - |-doBookmarkBarAnimation| has most of the actual logic. | 140 // - |-doBookmarkBarAnimation| has most of the actual logic. |
143 // - |-getDesiredToolbarHeightCompression| and |-toolbarDividerOpacity| contain | 141 // - |-getDesiredToolbarHeightCompression| and |-toolbarDividerOpacity| contain |
144 // related logic. | 142 // related logic. |
145 // - The BWC's |-layoutSubviews| needs to know how to position things. | 143 // - The BWC's |-layoutSubviews| needs to know how to position things. |
146 // - The BWC should implement |-bookmarkBar:didChangeFromState:toState:| and | 144 // - The BWC should implement |-bookmarkBar:didChangeFromState:toState:| and |
147 // |-bookmarkBar:willAnimateFromState:toState:| in order to inform the | 145 // |-bookmarkBar:willAnimateFromState:toState:| in order to inform the |
148 // toolbar of required changes. | 146 // toolbar of required changes. |
149 // | |
150 // Layout: | |
151 // | |
152 // Several events (initial load, changes to the bookmark model etc.) can | |
153 // require the bar layout to change. In most cases, this is accomplished | |
154 // by building a BookmarkBarLayout from the current state of the view, | |
155 // the bookmark model, and the managed bookmark service. If the calculated | |
156 // layout differs from the previous one, it's applied to the view | |
157 // via |applyLayout:animated:|. This is a cheap way to "coalesce" multiple | |
158 // potentially layout-changing events, since in practice, these events come | |
159 // in bursts and don't require a change. | |
160 // | |
161 // Temporary changes in layout during dragging are an exception to this, | |
162 // since the layout temporarily adjusts to the drag (for example, adding | |
163 // a placeholder space for a mid-drag button or removing the space previously | |
164 // taken up by a button which is being dragged off the bar). In this case, | |
165 // the original stored layout is maintained as the source of truth, and | |
166 // elements are laid out from a combination of the stored layout and the | |
167 // drag state. See |setDropInsertionPos:| for details. | |
168 | 147 |
169 namespace { | 148 namespace { |
170 | 149 |
171 // Duration of the bookmark bar animations. | 150 // Duration of the bookmark bar animations. |
172 const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; | 151 const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; |
173 const NSTimeInterval kDragAndDropAnimationDuration = 0.25; | 152 const NSTimeInterval kDragAndDropAnimationDuration = 0.25; |
174 | 153 |
175 const int kMaxReusePoolSize = 10; | |
176 | |
177 // Min width for no item text field and import bookmarks button. | |
178 const CGFloat kNoItemElementMinWidth = 30; | |
179 | |
180 void RecordAppLaunch(Profile* profile, GURL url) { | 154 void RecordAppLaunch(Profile* profile, GURL url) { |
181 const extensions::Extension* extension = | 155 const extensions::Extension* extension = |
182 extensions::ExtensionRegistry::Get(profile)-> | 156 extensions::ExtensionRegistry::Get(profile)-> |
183 enabled_extensions().GetAppByURL(url); | 157 enabled_extensions().GetAppByURL(url); |
184 if (!extension) | 158 if (!extension) |
185 return; | 159 return; |
186 | 160 |
187 extensions::RecordAppLaunchType(extension_misc::APP_LAUNCH_BOOKMARK_BAR, | 161 extensions::RecordAppLaunchType(extension_misc::APP_LAUNCH_BOOKMARK_BAR, |
188 extension->GetType()); | 162 extension->GetType()); |
189 } | 163 } |
190 | 164 |
191 const CGFloat kBookmarkButtonHeightMinusPadding = | |
192 bookmarks::kBookmarkButtonHeight - bookmarks::kBookmarkVerticalPadding * 2; | |
193 | |
194 } // namespace | 165 } // namespace |
195 | 166 |
196 namespace bookmarks { | 167 @interface BookmarkBarController () |
197 | 168 |
198 BookmarkBarLayout::BookmarkBarLayout() | 169 // Updates the sizes and positions of the subviews. |
199 : visible_elements(0), | 170 - (void)layoutSubviews; |
200 apps_button_offset(0), | |
201 managed_bookmarks_button_offset(0), | |
202 supervised_bookmarks_button_offset(0), | |
203 off_the_side_button_offset(0), | |
204 other_bookmarks_button_offset(0), | |
205 no_item_textfield_offset(0), | |
206 no_item_textfield_width(0), | |
207 import_bookmarks_button_offset(0), | |
208 import_bookmarks_button_width(0), | |
209 max_x(0){}; | |
210 BookmarkBarLayout::~BookmarkBarLayout(){}; | |
211 BookmarkBarLayout::BookmarkBarLayout(BookmarkBarLayout&& other) = default; | |
212 BookmarkBarLayout& BookmarkBarLayout::operator=(BookmarkBarLayout&& other) = | |
213 default; | |
214 | 171 |
215 bool operator==(const BookmarkBarLayout& lhs, const BookmarkBarLayout& rhs) { | 172 // Moves to the given next state (from the current state), possibly animating. |
216 return std::tie(lhs.visible_elements, lhs.apps_button_offset, | 173 // If |animate| is NO, it will stop any running animation and jump to the given |
217 lhs.managed_bookmarks_button_offset, | 174 // state. If YES, it may either (depending on implementation) jump to the end of |
218 lhs.supervised_bookmarks_button_offset, | 175 // the current animation and begin the next one, or stop the current animation |
219 lhs.off_the_side_button_offset, | 176 // mid-flight and animate to the next state. |
220 lhs.other_bookmarks_button_offset, | 177 - (void)moveToState:(BookmarkBar::State)nextState |
221 lhs.no_item_textfield_offset, lhs.no_item_textfield_width, | 178 withAnimation:(BOOL)animate; |
222 lhs.import_bookmarks_button_offset, | |
223 lhs.import_bookmarks_button_width, lhs.button_offsets, | |
224 lhs.max_x) == | |
225 std::tie( | |
226 rhs.visible_elements, rhs.apps_button_offset, | |
227 rhs.managed_bookmarks_button_offset, | |
228 rhs.supervised_bookmarks_button_offset, | |
229 rhs.off_the_side_button_offset, rhs.other_bookmarks_button_offset, | |
230 rhs.no_item_textfield_offset, rhs.no_item_textfield_width, | |
231 rhs.import_bookmarks_button_offset, | |
232 rhs.import_bookmarks_button_width, rhs.button_offsets, rhs.max_x); | |
233 } | |
234 | 179 |
235 bool operator!=(const BookmarkBarLayout& lhs, const BookmarkBarLayout& rhs) { | 180 // Create buttons for all items in the given bookmark node tree. |
236 return !(lhs == rhs); | 181 // Modifies self->buttons_. Do not add more buttons than will fit on the view. |
237 } | 182 - (void)addNodesToButtonList:(const BookmarkNode*)node; |
238 | 183 |
239 } // namespace bookmarks | 184 // Create an autoreleased button appropriate for insertion into the bookmark |
| 185 // bar. Update |xOffset| with the offset appropriate for the subsequent button. |
| 186 - (BookmarkButton*)buttonForNode:(const BookmarkNode*)node |
| 187 xOffset:(int*)xOffset; |
240 | 188 |
241 @implementation BookmarkBarController { | 189 // Find a parent whose button is visible on the bookmark bar. |
242 BookmarkBarLayout layout_; | 190 - (BookmarkButton*)bookmarkButtonToPulseForNode:(const BookmarkNode*)node; |
243 CGFloat originalNoItemTextFieldWidth_; | |
244 CGFloat originalImportBookmarksButtonWidth_; | |
245 CGFloat originalNoItemInterelementPadding_; | |
246 BOOL didCreateExtraButtons_; | |
247 | 191 |
248 // Maps bookmark node IDs to instantiated buttons for ease of lookup. | 192 // Puts stuff into the final state without animating, stopping a running |
249 std::unordered_map<int64_t, base::scoped_nsobject<BookmarkButton>> | 193 // animation if necessary. |
250 nodeIdToButtonMap_; | 194 - (void)finalizeState; |
251 | 195 |
252 // A place to stash bookmark buttons that have been removed from the bar | 196 // Stops any current animation in its tracks (midway). |
253 // so that they can be reused instead of creating new ones. | 197 - (void)stopCurrentAnimation; |
254 base::scoped_nsobject<NSMutableArray> unusedButtonPool_; | 198 |
255 } | 199 // Show/hide the bookmark bar. |
| 200 // if |animate| is YES, the changes are made using the animator; otherwise they |
| 201 // are made immediately. |
| 202 - (void)showBookmarkBarWithAnimation:(BOOL)animate; |
| 203 |
| 204 // Handles animating the resize of the content view. Returns YES if it handled |
| 205 // the animation, NO if not (and hence it should be done instantly). |
| 206 - (BOOL)doBookmarkBarAnimation; |
| 207 |
| 208 // |point| is in the base coordinate system of the destination window; |
| 209 // it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be |
| 210 // made and inserted into the new location while leaving the bookmark in |
| 211 // the old location, otherwise move the bookmark by removing from its old |
| 212 // location and inserting into the new location. |
| 213 - (BOOL)dragBookmark:(const BookmarkNode*)sourceNode |
| 214 to:(NSPoint)point |
| 215 copy:(BOOL)copy; |
| 216 |
| 217 // Returns the index in the model for a drag to the location given by |
| 218 // |point|. This is determined by finding the first button before the center |
| 219 // of which |point| falls, scanning left to right. Note that, currently, only |
| 220 // the x-coordinate of |point| is considered. Though not currently implemented, |
| 221 // we may check for errors, in which case this would return negative value; |
| 222 // callers should check for this. |
| 223 - (int)indexForDragToPoint:(NSPoint)point; |
| 224 |
| 225 // Add or remove buttons to/from the bar until it is filled but not overflowed. |
| 226 - (void)redistributeButtonsOnBarAsNeeded; |
| 227 |
| 228 // Determine the nature of the bookmark bar contents based on the number of |
| 229 // buttons showing. If too many then show the off-the-side list, if none |
| 230 // then show the no items label. |
| 231 - (void)reconfigureBookmarkBar; |
| 232 |
| 233 - (int)preferredHeight; |
| 234 - (void)addButtonsToView; |
| 235 - (BOOL)setManagedBookmarksButtonVisibility; |
| 236 - (BOOL)setSupervisedBookmarksButtonVisibility; |
| 237 - (BOOL)setOtherBookmarksButtonVisibility; |
| 238 - (BOOL)setAppsPageShortcutButtonVisibility; |
| 239 - (BookmarkButton*)createCustomBookmarkButtonForCell:(NSCell*)cell; |
| 240 - (void)createManagedBookmarksButton; |
| 241 - (void)createSupervisedBookmarksButton; |
| 242 - (void)createOtherBookmarksButton; |
| 243 - (void)createAppsPageShortcutButton; |
| 244 - (void)openAppsPage:(id)sender; |
| 245 - (void)centerNoItemsLabel; |
| 246 - (void)positionRightSideButtons; |
| 247 - (void)watchForExitEvent:(BOOL)watch; |
| 248 - (void)resetAllButtonPositionsWithAnimation:(BOOL)animate; |
| 249 |
| 250 @end |
| 251 |
| 252 @implementation BookmarkBarController |
256 | 253 |
257 @synthesize currentState = currentState_; | 254 @synthesize currentState = currentState_; |
258 @synthesize lastState = lastState_; | 255 @synthesize lastState = lastState_; |
259 @synthesize isAnimationRunning = isAnimationRunning_; | 256 @synthesize isAnimationRunning = isAnimationRunning_; |
260 @synthesize delegate = delegate_; | 257 @synthesize delegate = delegate_; |
261 @synthesize stateAnimationsEnabled = stateAnimationsEnabled_; | 258 @synthesize stateAnimationsEnabled = stateAnimationsEnabled_; |
262 @synthesize innerContentAnimationsEnabled = innerContentAnimationsEnabled_; | 259 @synthesize innerContentAnimationsEnabled = innerContentAnimationsEnabled_; |
263 | 260 |
264 - (id)initWithBrowser:(Browser*)browser | 261 - (id)initWithBrowser:(Browser*)browser |
265 initialWidth:(CGFloat)initialWidth | 262 initialWidth:(CGFloat)initialWidth |
266 delegate:(id<BookmarkBarControllerDelegate>)delegate { | 263 delegate:(id<BookmarkBarControllerDelegate>)delegate { |
267 if ((self = [super initWithNibName:nil bundle:nil])) { | 264 if ((self = [super initWithNibName:@"BookmarkBar" |
| 265 bundle:base::mac::FrameworkBundle()])) { |
268 currentState_ = BookmarkBar::HIDDEN; | 266 currentState_ = BookmarkBar::HIDDEN; |
269 lastState_ = BookmarkBar::HIDDEN; | 267 lastState_ = BookmarkBar::HIDDEN; |
270 | 268 |
271 browser_ = browser; | 269 browser_ = browser; |
272 initialWidth_ = initialWidth; | 270 initialWidth_ = initialWidth; |
273 bookmarkModel_ = | 271 bookmarkModel_ = |
274 BookmarkModelFactory::GetForBrowserContext(browser_->profile()); | 272 BookmarkModelFactory::GetForBrowserContext(browser_->profile()); |
275 managedBookmarkService_ = | 273 managedBookmarkService_ = |
276 ManagedBookmarkServiceFactory::GetForProfile(browser_->profile()); | 274 ManagedBookmarkServiceFactory::GetForProfile(browser_->profile()); |
277 buttons_.reset([[NSMutableArray alloc] init]); | 275 buttons_.reset([[NSMutableArray alloc] init]); |
278 unusedButtonPool_.reset([[NSMutableArray alloc] init]); | |
279 delegate_ = delegate; | 276 delegate_ = delegate; |
280 folderTarget_.reset( | 277 folderTarget_.reset( |
281 [[BookmarkFolderTarget alloc] initWithController:self | 278 [[BookmarkFolderTarget alloc] initWithController:self |
282 profile:browser_->profile()]); | 279 profile:browser_->profile()]); |
283 didCreateExtraButtons_ = NO; | |
284 | 280 |
285 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 281 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
286 folderImage_.reset( | 282 folderImage_.reset( |
287 rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER).CopyNSImage()); | 283 rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER).CopyNSImage()); |
288 folderImageWhite_.reset( | 284 folderImageWhite_.reset( |
289 rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER_WHITE).CopyNSImage()); | 285 rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER_WHITE).CopyNSImage()); |
290 | 286 |
291 const int kIconSize = 16; | 287 const int kIconSize = 16; |
292 defaultImage_.reset([NSImageFromImageSkia(gfx::CreateVectorIcon( | 288 defaultImage_.reset([NSImageFromImageSkia(gfx::CreateVectorIcon( |
293 omnibox::kHttpIcon, kIconSize, gfx::kChromeIconGrey)) retain]); | 289 omnibox::kHttpIcon, kIconSize, gfx::kChromeIconGrey)) retain]); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 initWithFrame:NSMakeRect(0, 0, initialWidth_, 0)] | 326 initWithFrame:NSMakeRect(0, 0, initialWidth_, 0)] |
331 autorelease]]; | 327 autorelease]]; |
332 [[self view] setHidden:YES]; | 328 [[self view] setHidden:YES]; |
333 [[self view] setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; | 329 [[self view] setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; |
334 [[self controlledView] setController:self]; | 330 [[self controlledView] setController:self]; |
335 [[self controlledView] setDelegate:self]; | 331 [[self controlledView] setDelegate:self]; |
336 | 332 |
337 buttonView_.reset([[BookmarkBarView alloc] | 333 buttonView_.reset([[BookmarkBarView alloc] |
338 initWithController:self | 334 initWithController:self |
339 frame:NSMakeRect(0, -2, 584, 144)]); | 335 frame:NSMakeRect(0, -2, 584, 144)]); |
340 [buttonView_ setAutoresizingMask:NSViewWidthSizable | NSViewMaxXMargin]; | 336 [buttonView_ setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin | |
| 337 NSViewMaxXMargin]; |
341 [[buttonView_ importBookmarksButton] setTarget:self]; | 338 [[buttonView_ importBookmarksButton] setTarget:self]; |
342 [[buttonView_ importBookmarksButton] setAction:@selector(importBookmarks:)]; | 339 [[buttonView_ importBookmarksButton] setAction:@selector(importBookmarks:)]; |
343 | 340 |
| 341 [self createOffTheSideButton]; |
| 342 [buttonView_ addSubview:offTheSideButton_]; |
| 343 |
344 [self.view addSubview:buttonView_]; | 344 [self.view addSubview:buttonView_]; |
345 | 345 // viewDidLoad became part of the API in 10.10 |
346 // viewDidLoad became part of the API in 10.10. | |
347 if (!base::mac::IsAtLeastOS10_10()) | 346 if (!base::mac::IsAtLeastOS10_10()) |
348 [self viewDidLoad]; | 347 [self viewDidLoad]; |
349 } | 348 } |
350 | 349 |
351 - (BookmarkButton*)findAncestorButtonOnBarForNode:(const BookmarkNode*)node { | 350 - (BookmarkButton*)bookmarkButtonToPulseForNode:(const BookmarkNode*)node { |
352 // Find the closest parent that is visible on the bar. | 351 // Find the closest parent that is visible on the bar. |
353 while (node) { | 352 while (node) { |
354 // Check if we've reached one of the special buttons. Otherwise, if the next | 353 // Check if we've reached one of the special buttons. Otherwise, if the next |
355 // parent is the boomark bar, find the corresponding button. | 354 // parent is the boomark bar, find the corresponding button. |
356 if ([managedBookmarksButton_ bookmarkNode] == node) | 355 if ([managedBookmarksButton_ bookmarkNode] == node) |
357 return managedBookmarksButton_; | 356 return managedBookmarksButton_; |
358 | 357 |
359 if ([supervisedBookmarksButton_ bookmarkNode] == node) | 358 if ([supervisedBookmarksButton_ bookmarkNode] == node) |
360 return supervisedBookmarksButton_; | 359 return supervisedBookmarksButton_; |
361 | 360 |
(...skipping 14 matching lines...) Expand all Loading... |
376 | 375 |
377 node = node->parent(); | 376 node = node->parent(); |
378 } | 377 } |
379 NOTREACHED(); | 378 NOTREACHED(); |
380 return nil; | 379 return nil; |
381 } | 380 } |
382 | 381 |
383 - (void)startPulsingBookmarkNode:(const BookmarkNode*)node { | 382 - (void)startPulsingBookmarkNode:(const BookmarkNode*)node { |
384 [self stopPulsingBookmarkNode]; | 383 [self stopPulsingBookmarkNode]; |
385 | 384 |
386 pulsingButton_.reset([self findAncestorButtonOnBarForNode:node], | 385 pulsingButton_.reset([self bookmarkButtonToPulseForNode:node], |
387 base::scoped_policy::RETAIN); | 386 base::scoped_policy::RETAIN); |
388 if (!pulsingButton_) | 387 if (!pulsingButton_) |
389 return; | 388 return; |
390 | 389 |
391 [pulsingButton_ setPulseIsStuckOn:YES]; | 390 [pulsingButton_ setPulseIsStuckOn:YES]; |
392 pulsingBookmarkObserver_.reset( | 391 pulsingBookmarkObserver_.reset( |
393 new BookmarkModelObserverForCocoa(bookmarkModel_, ^() { | 392 new BookmarkModelObserverForCocoa(bookmarkModel_, ^() { |
394 // Stop pulsing if anything happened to the node. | 393 // Stop pulsing if anything happened to the node. |
395 [self stopPulsingBookmarkNode]; | 394 [self stopPulsingBookmarkNode]; |
396 })); | 395 })); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 // Remove our view from its superview so it doesn't attempt to reference | 431 // Remove our view from its superview so it doesn't attempt to reference |
433 // it when the controller is gone. | 432 // it when the controller is gone. |
434 //TODO(dmaclach): Remove -- http://crbug.com/25845 | 433 //TODO(dmaclach): Remove -- http://crbug.com/25845 |
435 [view removeFromSuperview]; | 434 [view removeFromSuperview]; |
436 | 435 |
437 // Be sure there is no dangling pointer. | 436 // Be sure there is no dangling pointer. |
438 if ([view respondsToSelector:@selector(setController:)]) | 437 if ([view respondsToSelector:@selector(setController:)]) |
439 [view performSelector:@selector(setController:) withObject:nil]; | 438 [view performSelector:@selector(setController:) withObject:nil]; |
440 | 439 |
441 // For safety, make sure the buttons can no longer call us. | 440 // For safety, make sure the buttons can no longer call us. |
442 base::scoped_nsobject<NSMutableArray> buttons([buttons_ mutableCopy]); | 441 for (BookmarkButton* button in buttons_.get()) { |
443 [buttons addObjectsFromArray:unusedButtonPool_]; | |
444 if (didCreateExtraButtons_) { | |
445 [buttons addObjectsFromArray:@[ | |
446 appsPageShortcutButton_, managedBookmarksButton_, | |
447 supervisedBookmarksButton_, otherBookmarksButton_, offTheSideButton_ | |
448 ]]; | |
449 } | |
450 | |
451 for (BookmarkButton* button in buttons.get()) { | |
452 [button setDelegate:nil]; | 442 [button setDelegate:nil]; |
453 [button setTarget:nil]; | 443 [button setTarget:nil]; |
454 [button setAction:nil]; | 444 [button setAction:nil]; |
455 } | 445 } |
| 446 |
456 bridge_.reset(NULL); | 447 bridge_.reset(NULL); |
457 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 448 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
458 [self watchForExitEvent:NO]; | 449 [self watchForExitEvent:NO]; |
459 browser_ = nullptr; | 450 browser_ = nullptr; |
460 } | 451 } |
461 | 452 |
462 - (void)viewDidLoad { | 453 - (void)viewDidLoad { |
463 // We are enabled by default. | 454 // We are enabled by default. |
464 barIsEnabled_ = YES; | 455 barIsEnabled_ = YES; |
465 | 456 |
466 // Remember the original sizes of the 'no items' and 'import bookmarks' | 457 // Remember the original sizes of the 'no items' and 'import bookmarks' |
467 // fields to aid in resizing when the window frame changes. | 458 // fields to aid in resizing when the window frame changes. |
468 NSRect noItemTextFieldFrame = [[buttonView_ noItemTextField] frame]; | 459 originalNoItemsRect_ = [[buttonView_ noItemTextfield] frame]; |
469 NSRect noItemButtonFrame = [[buttonView_ importBookmarksButton] frame]; | 460 originalImportBookmarksRect_ = [[buttonView_ importBookmarksButton] frame]; |
470 originalNoItemTextFieldWidth_ = NSWidth(noItemTextFieldFrame); | |
471 originalImportBookmarksButtonWidth_ = NSWidth(noItemButtonFrame); | |
472 originalNoItemInterelementPadding_ = | |
473 NSMinX(noItemButtonFrame) - NSMaxX(noItemTextFieldFrame); | |
474 | 461 |
| 462 // Bookmark buttons start farther from the bookmark bar's left edge so |
| 463 // adjust the positions of the noItems and importBookmarks textfields. |
| 464 const CGFloat kBookmarksTextfieldOffsetX = 14; |
| 465 originalNoItemsRect_.origin.x += kBookmarksTextfieldOffsetX; |
| 466 [[buttonView_ noItemTextfield] setFrame:originalNoItemsRect_]; |
| 467 |
| 468 originalImportBookmarksRect_.origin.x += kBookmarksTextfieldOffsetX; |
| 469 [[buttonView_ importBookmarksButton] setFrame:originalImportBookmarksRect_]; |
| 470 |
| 471 // When resized we may need to add new buttons, or remove them (if |
| 472 // no longer visible), or add/remove the "off the side" menu. |
475 [[self view] setPostsFrameChangedNotifications:YES]; | 473 [[self view] setPostsFrameChangedNotifications:YES]; |
476 [[NSNotificationCenter defaultCenter] | 474 [[NSNotificationCenter defaultCenter] |
477 addObserver:self | 475 addObserver:self |
478 selector:@selector(frameDidChange) | 476 selector:@selector(frameDidChange) |
479 name:NSViewFrameDidChangeNotification | 477 name:NSViewFrameDidChangeNotification |
480 object:[self view]]; | 478 object:[self view]]; |
481 | 479 |
482 // Watch for things going to or from fullscreen. | 480 // Watch for things going to or from fullscreen. |
483 [[NSNotificationCenter defaultCenter] | 481 [[NSNotificationCenter defaultCenter] |
484 addObserver:self | 482 addObserver:self |
485 selector:@selector(willEnterOrLeaveFullscreen:) | 483 selector:@selector(willEnterOrLeaveFullscreen:) |
486 name:NSWindowWillEnterFullScreenNotification | 484 name:NSWindowWillEnterFullScreenNotification |
487 object:nil]; | 485 object:nil]; |
488 [[NSNotificationCenter defaultCenter] | 486 [[NSNotificationCenter defaultCenter] |
489 addObserver:self | 487 addObserver:self |
490 selector:@selector(willEnterOrLeaveFullscreen:) | 488 selector:@selector(willEnterOrLeaveFullscreen:) |
491 name:NSWindowWillExitFullScreenNotification | 489 name:NSWindowWillExitFullScreenNotification |
492 object:nil]; | 490 object:nil]; |
493 [self layoutSubviews]; | |
494 | 491 |
495 // Don't pass ourself along (as 'self') until our init is completely | 492 // Don't pass ourself along (as 'self') until our init is completely |
496 // done. Thus, this call is (almost) last. | 493 // done. Thus, this call is (almost) last. |
497 bridge_.reset(new BookmarkBarBridge(browser_->profile(), self, | 494 bridge_.reset(new BookmarkBarBridge(browser_->profile(), self, |
498 bookmarkModel_)); | 495 bookmarkModel_)); |
499 } | 496 } |
500 | 497 |
501 // Called by our main view (a BookmarkBarView) when it gets moved to a | 498 // Called by our main view (a BookmarkBarView) when it gets moved to a |
502 // window. We perform operations which need to know the relevant | 499 // window. We perform operations which need to know the relevant |
503 // window (e.g. watch for a window close) so they can't be performed | 500 // window (e.g. watch for a window close) so they can't be performed |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
549 - (void)parentWindowDidResignMain:(NSNotification*)notification { | 546 - (void)parentWindowDidResignMain:(NSNotification*)notification { |
550 [self closeFolderAndStopTrackingMenus]; | 547 [self closeFolderAndStopTrackingMenus]; |
551 } | 548 } |
552 | 549 |
553 - (void)layoutToFrame:(NSRect)frame { | 550 - (void)layoutToFrame:(NSRect)frame { |
554 // The view should be pinned to the top of the window with a flexible width. | 551 // The view should be pinned to the top of the window with a flexible width. |
555 DCHECK_EQ(NSViewWidthSizable | NSViewMinYMargin, | 552 DCHECK_EQ(NSViewWidthSizable | NSViewMinYMargin, |
556 [[self view] autoresizingMask]); | 553 [[self view] autoresizingMask]); |
557 [[self view] setFrame:frame]; | 554 [[self view] setFrame:frame]; |
558 [self layoutSubviews]; | 555 [self layoutSubviews]; |
559 [self frameDidChange]; | |
560 } | 556 } |
561 | 557 |
562 // Change the layout of the bookmark bar's subviews in response to a visibility | 558 // Change the layout of the bookmark bar's subviews in response to a visibility |
563 // change (e.g., show or hide the bar) or style change (attached or floating). | 559 // change (e.g., show or hide the bar) or style change (attached or floating). |
564 - (void)layoutSubviews { | 560 - (void)layoutSubviews { |
565 NSRect frame = [[self view] frame]; | 561 NSRect frame = [[self view] frame]; |
566 NSRect buttonViewFrame = NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame)); | 562 NSRect buttonViewFrame = NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame)); |
567 | 563 |
568 // Add padding to the detached bookmark bar. | 564 // Add padding to the detached bookmark bar. |
569 // The state of our morph (if any); 1 is total bubble, 0 is the regular bar. | 565 // The state of our morph (if any); 1 is total bubble, 0 is the regular bar. |
570 CGFloat morph = [self detachedMorphProgress]; | 566 CGFloat morph = [self detachedMorphProgress]; |
571 CGFloat padding = 0; | 567 CGFloat padding = 0; |
572 padding = bookmarks::kNTPBookmarkBarPadding; | 568 padding = bookmarks::kNTPBookmarkBarPadding; |
573 buttonViewFrame = | 569 buttonViewFrame = |
574 NSInsetRect(buttonViewFrame, morph * padding, morph * padding); | 570 NSInsetRect(buttonViewFrame, morph * padding, morph * padding); |
| 571 |
575 [buttonView_ setFrame:buttonViewFrame]; | 572 [buttonView_ setFrame:buttonViewFrame]; |
576 | 573 |
577 // Update bookmark button backgrounds. | 574 // Update bookmark button backgrounds. |
578 if ([self isAnimationRunning]) { | 575 if ([self isAnimationRunning]) { |
579 for (NSButton* button in buttons_.get()) | 576 for (NSButton* button in buttons_.get()) |
580 [button setNeedsDisplay:YES]; | 577 [button setNeedsDisplay:YES]; |
581 // Update the apps and other buttons explicitly, since they are not in the | 578 // Update the apps and other buttons explicitly, since they are not in the |
582 // buttons_ array. | 579 // buttons_ array. |
583 [appsPageShortcutButton_ setNeedsDisplay:YES]; | 580 [appsPageShortcutButton_ setNeedsDisplay:YES]; |
584 [managedBookmarksButton_ setNeedsDisplay:YES]; | 581 [managedBookmarksButton_ setNeedsDisplay:YES]; |
585 [supervisedBookmarksButton_ setNeedsDisplay:YES]; | 582 [supervisedBookmarksButton_ setNeedsDisplay:YES]; |
586 [otherBookmarksButton_ setNeedsDisplay:YES]; | 583 [otherBookmarksButton_ setNeedsDisplay:YES]; |
587 } | 584 } |
588 } | 585 } |
589 | 586 |
590 // We don't change a preference; we only change visibility. Preference changing | 587 // We don't change a preference; we only change visibility. Preference changing |
591 // (global state) is handled in |chrome::ToggleBookmarkBarWhenVisible()|. We | 588 // (global state) is handled in |chrome::ToggleBookmarkBarWhenVisible()|. We |
592 // simply update based on what we're told. | 589 // simply update based on what we're told. |
593 - (void)updateVisibility { | 590 - (void)updateVisibility { |
594 [self showBookmarkBarWithAnimation:NO]; | 591 [self showBookmarkBarWithAnimation:NO]; |
595 } | 592 } |
596 | 593 |
| 594 - (void)updateExtraButtonsVisibility { |
| 595 if (!appsPageShortcutButton_.get() || |
| 596 !managedBookmarksButton_.get() || |
| 597 !supervisedBookmarksButton_.get()) { |
| 598 return; |
| 599 } |
| 600 [self setAppsPageShortcutButtonVisibility]; |
| 601 [self setManagedBookmarksButtonVisibility]; |
| 602 [self setSupervisedBookmarksButtonVisibility]; |
| 603 [self resetAllButtonPositionsWithAnimation:NO]; |
| 604 [self reconfigureBookmarkBar]; |
| 605 } |
| 606 |
597 - (void)updateHiddenState { | 607 - (void)updateHiddenState { |
598 BOOL oldHidden = [[self view] isHidden]; | 608 BOOL oldHidden = [[self view] isHidden]; |
599 BOOL newHidden = ![self isVisible]; | 609 BOOL newHidden = ![self isVisible]; |
600 if (oldHidden != newHidden) | 610 if (oldHidden != newHidden) |
601 [[self view] setHidden:newHidden]; | 611 [[self view] setHidden:newHidden]; |
602 } | 612 } |
603 | 613 |
604 - (void)setBookmarkBarEnabled:(BOOL)enabled { | 614 - (void)setBookmarkBarEnabled:(BOOL)enabled { |
605 if (enabled != barIsEnabled_) { | 615 if (enabled != barIsEnabled_) { |
606 barIsEnabled_ = enabled; | 616 barIsEnabled_ = enabled; |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
811 DCHECK([[sender cell] isKindOfClass:[BookmarkButtonCell class]]); | 821 DCHECK([[sender cell] isKindOfClass:[BookmarkButtonCell class]]); |
812 | 822 |
813 // Only record the action if it's the initial folder being opened. | 823 // Only record the action if it's the initial folder being opened. |
814 if (!showFolderMenus_) | 824 if (!showFolderMenus_) |
815 RecordBookmarkFolderOpen([self bookmarkLaunchLocation]); | 825 RecordBookmarkFolderOpen([self bookmarkLaunchLocation]); |
816 showFolderMenus_ = !showFolderMenus_; | 826 showFolderMenus_ = !showFolderMenus_; |
817 | 827 |
818 // Middle click on chevron should not open bookmarks under it, instead just | 828 // Middle click on chevron should not open bookmarks under it, instead just |
819 // open its folder menu. | 829 // open its folder menu. |
820 if (sender == offTheSideButton_.get()) { | 830 if (sender == offTheSideButton_.get()) { |
821 [[sender cell] setStartingChildIndex:layout_.VisibleButtonCount()]; | 831 [[sender cell] setStartingChildIndex:displayedButtonCount_]; |
822 NSEvent* event = [NSApp currentEvent]; | 832 NSEvent* event = [NSApp currentEvent]; |
823 if ([event type] == NSOtherMouseUp) { | 833 if ([event type] == NSOtherMouseUp) { |
824 [self openOrCloseBookmarkFolderForOffTheSideButton]; | 834 [self openOrCloseBookmarkFolderForOffTheSideButton]; |
825 return; | 835 return; |
826 } | 836 } |
827 } | 837 } |
828 // Toggle presentation of bar folder menus. | 838 // Toggle presentation of bar folder menus. |
829 [folderTarget_ openBookmarkFolderFromButton:sender]; | 839 [folderTarget_ openBookmarkFolderFromButton:sender]; |
830 } | 840 } |
831 | 841 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
874 - (void)themeDidChangeNotification:(NSNotification*)notification { | 884 - (void)themeDidChangeNotification:(NSNotification*)notification { |
875 [self updateTheme:[[[self view] window] themeProvider]]; | 885 [self updateTheme:[[[self view] window] themeProvider]]; |
876 } | 886 } |
877 | 887 |
878 - (BookmarkLaunchLocation)bookmarkLaunchLocation { | 888 - (BookmarkLaunchLocation)bookmarkLaunchLocation { |
879 return currentState_ == BookmarkBar::DETACHED ? | 889 return currentState_ == BookmarkBar::DETACHED ? |
880 BOOKMARK_LAUNCH_LOCATION_DETACHED_BAR : | 890 BOOKMARK_LAUNCH_LOCATION_DETACHED_BAR : |
881 BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR; | 891 BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR; |
882 } | 892 } |
883 | 893 |
| 894 // Position the right-side buttons including the off-the-side chevron. |
| 895 - (void)positionRightSideButtons { |
| 896 int maxX = NSMaxX([[self buttonView] bounds]) - |
| 897 bookmarks::kBookmarkHorizontalPadding; |
| 898 int right = maxX; |
| 899 |
| 900 int ignored = 0; |
| 901 NSRect frame = [self frameForBookmarkButtonFromCell: |
| 902 [otherBookmarksButton_ cell] xOffset:&ignored]; |
| 903 if (![otherBookmarksButton_ isHidden]) { |
| 904 right -= NSWidth(frame); |
| 905 frame.origin.x = right; |
| 906 } else { |
| 907 frame.origin.x = maxX - NSWidth(frame); |
| 908 } |
| 909 [otherBookmarksButton_ setFrame:frame]; |
| 910 |
| 911 frame = [offTheSideButton_ frame]; |
| 912 frame.size.height = bookmarks::kBookmarkFolderButtonHeight; |
| 913 right -= frame.size.width; |
| 914 frame.origin.x = right; |
| 915 [offTheSideButton_ setFrame:frame]; |
| 916 } |
| 917 |
| 918 // Configure the off-the-side button (e.g. specify the node range, |
| 919 // check if we should enable or disable it, etc). |
| 920 - (void)configureOffTheSideButtonContentsAndVisibility { |
| 921 [[offTheSideButton_ cell] setStartingChildIndex:displayedButtonCount_]; |
| 922 [[offTheSideButton_ cell] |
| 923 setBookmarkNode:bookmarkModel_->bookmark_bar_node()]; |
| 924 int bookmarkChildren = bookmarkModel_->bookmark_bar_node()->child_count(); |
| 925 if (bookmarkChildren > displayedButtonCount_) { |
| 926 [offTheSideButton_ setHidden:NO]; |
| 927 // Set the off the side button as needing re-display. This is needed to |
| 928 // avoid the button being shown with a black background the first time |
| 929 // it's displayed. See https://codereview.chromium.org/1630453002/ for |
| 930 // more context. |
| 931 [offTheSideButton_ setNeedsDisplay:YES]; |
| 932 } else { |
| 933 // If we just deleted the last item in an off-the-side menu so the |
| 934 // button will be going away, make sure the menu goes away. |
| 935 if (folderController_ && |
| 936 ([folderController_ parentButton] == offTheSideButton_)) |
| 937 [self closeAllBookmarkFolders]; |
| 938 // (And hide the button, too.) |
| 939 [offTheSideButton_ setHidden:YES]; |
| 940 } |
| 941 } |
| 942 |
884 // Main menubar observation code, so we can know to close our fake menus if the | 943 // Main menubar observation code, so we can know to close our fake menus if the |
885 // user clicks on the actual menubar, as multiple unconnected menus sharing | 944 // user clicks on the actual menubar, as multiple unconnected menus sharing |
886 // the screen looks weird. | 945 // the screen looks weird. |
887 // Needed because the local event monitor doesn't see the click on the menubar. | 946 // Needed because the local event monitor doesn't see the click on the menubar. |
888 | 947 |
889 // Gets called when the menubar is clicked. | 948 // Gets called when the menubar is clicked. |
890 - (void)begunTracking:(NSNotification *)notification { | 949 - (void)begunTracking:(NSNotification *)notification { |
891 [self closeFolderAndStopTrackingMenus]; | 950 [self closeFolderAndStopTrackingMenus]; |
892 } | 951 } |
893 | 952 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
930 } | 989 } |
931 } else { | 990 } else { |
932 if (exitEventTap_) { | 991 if (exitEventTap_) { |
933 [NSEvent removeMonitor:exitEventTap_]; | 992 [NSEvent removeMonitor:exitEventTap_]; |
934 exitEventTap_ = nil; | 993 exitEventTap_ = nil; |
935 [self stopObservingMenubar]; | 994 [self stopObservingMenubar]; |
936 } | 995 } |
937 } | 996 } |
938 } | 997 } |
939 | 998 |
940 // Show/hide the bookmark bar. | 999 // Keep the "no items" label centered in response to a frame size change. |
941 // If |animate| is YES, the changes are made using the animator; otherwise they | 1000 - (void)centerNoItemsLabel { |
942 // are made immediately. | 1001 // Note that this computation is done in the parent's coordinate system, |
| 1002 // which is unflipped. Also, we want the label to be a fixed distance from |
| 1003 // the bottom, so that it slides up properly (on animating to hidden). |
| 1004 // The textfield sits in the itemcontainer, so to center it we maintain |
| 1005 // equal vertical padding on the top and bottom. |
| 1006 int yoffset = (NSHeight([[buttonView_ noItemTextfield] frame]) - |
| 1007 NSHeight([[buttonView_ noItemContainer] frame])) / 2; |
| 1008 [[buttonView_ noItemContainer] setFrameOrigin:NSMakePoint(0, yoffset)]; |
| 1009 } |
| 1010 |
| 1011 // (Private) |
943 - (void)showBookmarkBarWithAnimation:(BOOL)animate { | 1012 - (void)showBookmarkBarWithAnimation:(BOOL)animate { |
944 if (animate && stateAnimationsEnabled_) { | 1013 if (animate && stateAnimationsEnabled_) { |
945 // If |-doBookmarkBarAnimation| does the animation, we're done. | 1014 // If |-doBookmarkBarAnimation| does the animation, we're done. |
946 if ([self doBookmarkBarAnimation]) | 1015 if ([self doBookmarkBarAnimation]) |
947 return; | 1016 return; |
948 | 1017 |
949 // Else fall through and do the change instantly. | 1018 // Else fall through and do the change instantly. |
950 } | 1019 } |
951 | 1020 |
952 BookmarkBarToolbarView* view = [self controlledView]; | 1021 BookmarkBarToolbarView* view = [self controlledView]; |
953 | 1022 |
954 // Set our height immediately via -[AnimatableView setHeight:]. | 1023 // Set our height immediately via -[AnimatableView setHeight:]. |
955 [view setHeight:[self preferredHeight]]; | 1024 [view setHeight:[self preferredHeight]]; |
956 | 1025 |
957 // Only show the divider if showing the normal bookmark bar. | 1026 // Only show the divider if showing the normal bookmark bar. |
958 BOOL showsDivider = [self isInState:BookmarkBar::SHOW]; | 1027 BOOL showsDivider = [self isInState:BookmarkBar::SHOW]; |
959 [view setShowsDivider:showsDivider]; | 1028 [view setShowsDivider:showsDivider]; |
960 | 1029 |
961 // Make sure we're shown. | 1030 // Make sure we're shown. |
962 [view setHidden:![self isVisible]]; | 1031 [view setHidden:![self isVisible]]; |
963 | 1032 |
964 // Update everything else. | 1033 // Update everything else. |
965 [self layoutSubviews]; | 1034 [self layoutSubviews]; |
966 [self frameDidChange]; | 1035 [self frameDidChange]; |
967 } | 1036 } |
968 | 1037 |
969 // Handles animating the resize of the content view. Returns YES if it handled | 1038 // (Private) |
970 // the animation, NO if not (and hence it should be done instantly). | |
971 - (BOOL)doBookmarkBarAnimation { | 1039 - (BOOL)doBookmarkBarAnimation { |
972 BookmarkBarToolbarView* view = [self controlledView]; | 1040 BookmarkBarToolbarView* view = [self controlledView]; |
973 if ([self isAnimatingFromState:BookmarkBar::HIDDEN | 1041 if ([self isAnimatingFromState:BookmarkBar::HIDDEN |
974 toState:BookmarkBar::SHOW]) { | 1042 toState:BookmarkBar::SHOW]) { |
975 [view setShowsDivider:YES]; | 1043 [view setShowsDivider:YES]; |
976 [view setHidden:NO]; | 1044 [view setHidden:NO]; |
977 // Height takes into account the extra height we have since the toolbar | 1045 // Height takes into account the extra height we have since the toolbar |
978 // only compresses when we're done. | 1046 // only compresses when we're done. |
979 [view animateToNewHeight:(chrome::kMinimumBookmarkBarHeight - | 1047 [view animateToNewHeight:(chrome::kMinimumBookmarkBarHeight - |
980 bookmarks::kBookmarkBarOverlap) | 1048 bookmarks::kBookmarkBarOverlap) |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1031 case BookmarkBar::HIDDEN: | 1099 case BookmarkBar::HIDDEN: |
1032 return 0; | 1100 return 0; |
1033 } | 1101 } |
1034 } | 1102 } |
1035 | 1103 |
1036 // Return an appropriate width for the given bookmark button cell. | 1104 // Return an appropriate width for the given bookmark button cell. |
1037 - (CGFloat)widthForBookmarkButtonCell:(NSCell*)cell { | 1105 - (CGFloat)widthForBookmarkButtonCell:(NSCell*)cell { |
1038 return std::min([cell cellSize].width, bookmarks::kDefaultBookmarkWidth); | 1106 return std::min([cell cellSize].width, bookmarks::kDefaultBookmarkWidth); |
1039 } | 1107 } |
1040 | 1108 |
1041 - (BookmarkButton*)buttonForNode:(const BookmarkNode*)node { | 1109 // For the given root node of the bookmark bar, show or hide (as |
1042 BookmarkButton* button = nil; | 1110 // appropriate) the "no items" container (text which says "bookmarks |
1043 int64_t nodeId = node->id(); | 1111 // go here"). |
1044 auto buttonIt = nodeIdToButtonMap_.find(nodeId); | 1112 - (void)showOrHideNoItemContainerForNode:(const BookmarkNode*)node { |
1045 if (buttonIt != nodeIdToButtonMap_.end()) { | 1113 BOOL hideNoItemWarning = !node->empty(); |
1046 button = (*buttonIt).second.get(); | 1114 [[buttonView_ noItemContainer] setHidden:hideNoItemWarning]; |
1047 [self updateTitleAndTooltipForButton:button]; | 1115 } |
1048 } else if ([unusedButtonPool_ count] > 0) { | 1116 |
1049 button = [[[unusedButtonPool_ firstObject] retain] autorelease]; | 1117 // TODO(jrg): write a "build bar" so there is a nice spot for things |
1050 [unusedButtonPool_ removeObjectAtIndex:0]; | 1118 // like the contextual menu which is invoked when not over a |
1051 BOOL darkTheme = [[[self view] window] hasDarkTheme]; | 1119 // bookmark. On Safari that menu has a "new folder" option. |
1052 [[button cell] | 1120 - (void)addNodesToButtonList:(const BookmarkNode*)node { |
1053 setBookmarkNode:node | 1121 [self showOrHideNoItemContainerForNode:node]; |
1054 image:[self faviconForNode:node forADarkTheme:darkTheme]]; | 1122 |
1055 } else { | 1123 CGFloat maxViewX = NSMaxX([[self view] bounds]); |
1056 BookmarkButtonCell* cell = [self cellForBookmarkNode:node]; | 1124 int xOffset = |
1057 NSRect frame = NSMakeRect(0, bookmarks::kBookmarkVerticalPadding, 0, | 1125 bookmarks::kBookmarkLeftMargin - bookmarks::kBookmarkHorizontalPadding; |
1058 kBookmarkButtonHeightMinusPadding); | 1126 |
1059 button = [[[BookmarkButton alloc] initWithFrame:frame] autorelease]; | 1127 // Draw the apps bookmark if needed. |
1060 [button setCell:cell]; | 1128 if (![appsPageShortcutButton_ isHidden]) { |
1061 [buttonView_ addSubview:button]; | 1129 NSRect frame = |
1062 [button setDelegate:self]; | 1130 [self frameForBookmarkButtonFromCell:[appsPageShortcutButton_ cell] |
| 1131 xOffset:&xOffset]; |
| 1132 [appsPageShortcutButton_ setFrame:frame]; |
1063 } | 1133 } |
1064 DCHECK(button); | |
1065 | 1134 |
1066 // Do setup. | 1135 // Draw the managed bookmark folder if needed. |
1067 nodeIdToButtonMap_.insert( | 1136 if (![managedBookmarksButton_ isHidden]) { |
1068 {nodeId, base::scoped_nsobject<BookmarkButton>([button retain])}); | 1137 xOffset += bookmarks::kBookmarkHorizontalPadding; |
| 1138 NSRect frame = |
| 1139 [self frameForBookmarkButtonFromCell:[managedBookmarksButton_ cell] |
| 1140 xOffset:&xOffset]; |
| 1141 [managedBookmarksButton_ setFrame:frame]; |
| 1142 } |
| 1143 |
| 1144 // Draw the supervised bookmark folder if needed. |
| 1145 if (![supervisedBookmarksButton_ isHidden]) { |
| 1146 xOffset += bookmarks::kBookmarkHorizontalPadding; |
| 1147 NSRect frame = |
| 1148 [self frameForBookmarkButtonFromCell:[supervisedBookmarksButton_ cell] |
| 1149 xOffset:&xOffset]; |
| 1150 [supervisedBookmarksButton_ setFrame:frame]; |
| 1151 } |
| 1152 |
| 1153 for (int i = 0; i < node->child_count(); i++) { |
| 1154 const BookmarkNode* child = node->GetChild(i); |
| 1155 BookmarkButton* button = [self buttonForNode:child xOffset:&xOffset]; |
| 1156 if (NSMinX([button frame]) >= maxViewX) { |
| 1157 [button setDelegate:nil]; |
| 1158 break; |
| 1159 } |
| 1160 [buttons_ addObject:button]; |
| 1161 } |
| 1162 } |
| 1163 |
| 1164 - (BookmarkButton*)buttonForNode:(const BookmarkNode*)node |
| 1165 xOffset:(int*)xOffset { |
| 1166 BookmarkButtonCell* cell = [self cellForBookmarkNode:node]; |
| 1167 NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:xOffset]; |
| 1168 |
| 1169 base::scoped_nsobject<BookmarkButton> button( |
| 1170 [[BookmarkButton alloc] initWithFrame:frame]); |
| 1171 DCHECK(button.get()); |
| 1172 |
| 1173 // [NSButton setCell:] warns to NOT use setCell: other than in the |
| 1174 // initializer of a control. However, we are using a basic |
| 1175 // NSButton whose initializer does not take an NSCell as an |
| 1176 // object. To honor the assumed semantics, we do nothing with |
| 1177 // NSButton between alloc/init and setCell:. |
| 1178 [button setCell:cell]; |
| 1179 [button setDelegate:self]; |
| 1180 |
| 1181 // We cannot set the button cell's text color until it is placed in |
| 1182 // the button (e.g. the [button setCell:cell] call right above). We |
| 1183 // also cannot set the cell's text color until the view is added to |
| 1184 // the hierarchy. If that second part is now true, set the color. |
| 1185 // (If not we'll set the color on the 1st themeChanged: |
| 1186 // notification.) |
| 1187 const ui::ThemeProvider* themeProvider = [[[self view] window] themeProvider]; |
| 1188 if (themeProvider) { |
| 1189 NSColor* color = |
| 1190 themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT); |
| 1191 [cell setTextColor:color]; |
| 1192 } |
| 1193 |
1069 if (node->is_folder()) { | 1194 if (node->is_folder()) { |
1070 [button setTarget:self]; | 1195 [button setTarget:self]; |
1071 [button setAction:@selector(openBookmarkFolderFromButton:)]; | 1196 [button setAction:@selector(openBookmarkFolderFromButton:)]; |
1072 [[button draggableButton] setActsOnMouseDown:YES]; | 1197 [[button draggableButton] setActsOnMouseDown:YES]; |
| 1198 // If it has a title, and it will be truncated, show full title in |
| 1199 // tooltip. |
| 1200 NSString* title = base::SysUTF16ToNSString(node->GetTitle()); |
| 1201 if ([title length] && |
| 1202 [[button cell] cellSize].width > bookmarks::kDefaultBookmarkWidth) { |
| 1203 [button setToolTip:title]; |
| 1204 } |
1073 } else { | 1205 } else { |
1074 // Make the button do something. | 1206 // Make the button do something |
1075 [button setTarget:self]; | 1207 [button setTarget:self]; |
1076 [button setAction:@selector(openBookmark:)]; | 1208 [button setAction:@selector(openBookmark:)]; |
1077 [[button draggableButton] setActsOnMouseDown:NO]; | 1209 if (node->is_url()) |
| 1210 [button setToolTip:[BookmarkMenuCocoaController tooltipForNode:node]]; |
1078 } | 1211 } |
1079 [self updateTitleAndTooltipForButton:button]; | 1212 return [[button.get() retain] autorelease]; |
1080 return button; | |
1081 } | 1213 } |
1082 | 1214 |
1083 - (void)updateTitleAndTooltipForButton:(BookmarkButton*)button { | 1215 // Add bookmark buttons to the view only if they are completely |
1084 const BookmarkNode* node = [button bookmarkNode]; | 1216 // visible and don't overlap the "other bookmarks". Remove buttons |
1085 CGFloat buttonWidth = [self widthOfButtonForNode:node]; | 1217 // which are clipped. Called when building the bookmark bar the first time. |
1086 NSString* buttonTitle = base::SysUTF16ToNSString(node->GetTitle()); | 1218 - (void)addButtonsToView { |
| 1219 displayedButtonCount_ = 0; |
| 1220 NSMutableArray* buttons = [self buttons]; |
| 1221 for (NSButton* button in buttons) { |
| 1222 if (NSMaxX([button frame]) > (NSMinX([offTheSideButton_ frame]) - |
| 1223 bookmarks::kBookmarkHorizontalPadding)) |
| 1224 break; |
| 1225 [buttonView_ addSubview:button]; |
| 1226 ++displayedButtonCount_; |
| 1227 } |
| 1228 NSUInteger removalCount = |
| 1229 [buttons count] - (NSUInteger)displayedButtonCount_; |
| 1230 if (removalCount > 0) { |
| 1231 NSRange removalRange = NSMakeRange(displayedButtonCount_, removalCount); |
| 1232 [buttons removeObjectsInRange:removalRange]; |
| 1233 } |
| 1234 } |
1087 | 1235 |
1088 if (NSWidth([button frame]) == buttonWidth && | 1236 // Shows or hides the Managed, Supervised, or Other Bookmarks button as |
1089 [[button title] isEqualToString:buttonTitle]) | 1237 // appropriate, and returns whether it ended up visible. |
1090 return; | 1238 - (BOOL)setBookmarkButtonVisibility:(BookmarkButton*)button |
| 1239 canShow:(BOOL)show |
| 1240 resetAllButtonPositions:(BOOL)resetButtons { |
| 1241 if (!button) |
| 1242 return NO; |
1091 | 1243 |
1092 CGRect frame = [button frame]; | 1244 BOOL visible = ![button bookmarkNode]->empty() && show; |
1093 frame.size.width = buttonWidth; | 1245 BOOL currentVisibility = ![button isHidden]; |
1094 [button setFrame:frame]; | 1246 if (currentVisibility != visible) { |
1095 [[button cell] setTitle:buttonTitle]; | 1247 [button setHidden:!visible]; |
1096 NSString* tooltip = nil; | 1248 if (resetButtons) |
| 1249 [self resetAllButtonPositionsWithAnimation:NO]; |
| 1250 } |
| 1251 return visible; |
| 1252 } |
1097 | 1253 |
1098 // Folders show a tooltip iff the title is truncated. | 1254 // Shows or hides the Managed Bookmarks button as appropriate, and returns |
1099 if (node->is_folder() && [buttonTitle length] > 0 && | 1255 // whether it ended up visible. |
1100 [[button cell] cellSize].width < buttonWidth) { | 1256 - (BOOL)setManagedBookmarksButtonVisibility { |
1101 tooltip = buttonTitle; | 1257 PrefService* prefs = browser_->profile()->GetPrefs(); |
1102 } else if (node->is_url()) { | 1258 BOOL prefIsSet = |
1103 tooltip = [BookmarkMenuCocoaController tooltipForNode:node]; | 1259 prefs->GetBoolean(bookmarks::prefs::kShowManagedBookmarksInBookmarkBar); |
1104 } | 1260 return [self setBookmarkButtonVisibility:managedBookmarksButton_.get() |
| 1261 canShow:prefIsSet |
| 1262 resetAllButtonPositions:YES]; |
| 1263 } |
1105 | 1264 |
1106 [button setToolTip:tooltip]; | 1265 // Shows or hides the Supervised Bookmarks button as appropriate, and returns |
| 1266 // whether it ended up visible. |
| 1267 - (BOOL)setSupervisedBookmarksButtonVisibility { |
| 1268 return [self setBookmarkButtonVisibility:supervisedBookmarksButton_.get() |
| 1269 canShow:YES |
| 1270 resetAllButtonPositions:YES]; |
| 1271 } |
| 1272 |
| 1273 // Shows or hides the Other Bookmarks button as appropriate, and returns |
| 1274 // whether it ended up visible. |
| 1275 - (BOOL)setOtherBookmarksButtonVisibility { |
| 1276 return [self setBookmarkButtonVisibility:otherBookmarksButton_.get() |
| 1277 canShow:YES |
| 1278 resetAllButtonPositions:NO]; |
| 1279 } |
| 1280 |
| 1281 // Shows or hides the Apps button as appropriate, and returns whether it ended |
| 1282 // up visible. |
| 1283 - (BOOL)setAppsPageShortcutButtonVisibility { |
| 1284 if (!appsPageShortcutButton_.get()) |
| 1285 return NO; |
| 1286 |
| 1287 BOOL visible = |
| 1288 bookmarkModel_->loaded() && |
| 1289 chrome::ShouldShowAppsShortcutInBookmarkBar(browser_->profile()); |
| 1290 [appsPageShortcutButton_ setHidden:!visible]; |
| 1291 return visible; |
1107 } | 1292 } |
1108 | 1293 |
1109 // Creates a bookmark bar button that does not correspond to a regular bookmark | 1294 // Creates a bookmark bar button that does not correspond to a regular bookmark |
1110 // or folder. It is used by the "Other Bookmarks" and the "Apps" buttons. | 1295 // or folder. It is used by the "Other Bookmarks" and the "Apps" buttons. |
1111 - (BookmarkButton*)createCustomBookmarkButtonForCell:(NSCell*)cell { | 1296 - (BookmarkButton*)createCustomBookmarkButtonForCell:(NSCell*)cell { |
1112 BookmarkButton* button = [[BookmarkButton alloc] init]; | 1297 BookmarkButton* button = [[BookmarkButton alloc] init]; |
1113 [[button draggableButton] setDraggable:NO]; | 1298 [[button draggableButton] setDraggable:NO]; |
1114 [[button draggableButton] setActsOnMouseDown:YES]; | 1299 [[button draggableButton] setActsOnMouseDown:YES]; |
1115 [button setCell:cell]; | 1300 [button setCell:cell]; |
1116 [button setDelegate:self]; | 1301 [button setDelegate:self]; |
1117 [button setTarget:self]; | 1302 [button setTarget:self]; |
1118 // Make sure this button, like all other BookmarkButtons, lives | 1303 // Make sure this button, like all other BookmarkButtons, lives |
1119 // until the end of the current event loop. | 1304 // until the end of the current event loop. |
1120 [[button retain] autorelease]; | 1305 [[button retain] autorelease]; |
1121 return button; | 1306 return button; |
1122 } | 1307 } |
1123 | 1308 |
1124 // Creates the button for "Managed Bookmarks", but does not position it. | 1309 // Creates the button for "Managed Bookmarks", but does not position it. |
1125 - (void)createManagedBookmarksButton { | 1310 - (void)createManagedBookmarksButton { |
1126 if (managedBookmarksButton_.get()) { | 1311 if (managedBookmarksButton_.get()) { |
1127 // The node's title might have changed if the user signed in or out. | 1312 // The node's title might have changed if the user signed in or out. |
1128 // Make sure it's up to date now. | 1313 // Make sure it's up to date now. |
1129 const BookmarkNode* node = managedBookmarkService_->managed_node(); | 1314 const BookmarkNode* node = managedBookmarkService_->managed_node(); |
1130 NSString* title = base::SysUTF16ToNSString(node->GetTitle()); | 1315 NSString* title = base::SysUTF16ToNSString(node->GetTitle()); |
1131 NSCell* cell = [managedBookmarksButton_ cell]; | 1316 NSCell* cell = [managedBookmarksButton_ cell]; |
1132 [cell setTitle:title]; | 1317 [cell setTitle:title]; |
1133 | 1318 |
| 1319 // Its visibility may have changed too. |
| 1320 [self setManagedBookmarksButtonVisibility]; |
| 1321 |
1134 return; | 1322 return; |
1135 } | 1323 } |
1136 | 1324 |
1137 NSCell* cell = | 1325 NSCell* cell = |
1138 [self cellForBookmarkNode:managedBookmarkService_->managed_node()]; | 1326 [self cellForBookmarkNode:managedBookmarkService_->managed_node()]; |
1139 managedBookmarksButton_.reset([self createCustomBookmarkButtonForCell:cell]); | 1327 managedBookmarksButton_.reset([self createCustomBookmarkButtonForCell:cell]); |
1140 [managedBookmarksButton_ setAction:@selector(openBookmarkFolderFromButton:)]; | 1328 [managedBookmarksButton_ setAction:@selector(openBookmarkFolderFromButton:)]; |
1141 view_id_util::SetID(managedBookmarksButton_.get(), VIEW_ID_MANAGED_BOOKMARKS); | 1329 view_id_util::SetID(managedBookmarksButton_.get(), VIEW_ID_MANAGED_BOOKMARKS); |
1142 NSRect frame = NSMakeRect(0, bookmarks::kBookmarkVerticalPadding, | |
1143 [self widthForBookmarkButtonCell:cell], | |
1144 kBookmarkButtonHeightMinusPadding); | |
1145 [managedBookmarksButton_ setFrame:frame]; | |
1146 [buttonView_ addSubview:managedBookmarksButton_.get()]; | 1330 [buttonView_ addSubview:managedBookmarksButton_.get()]; |
1147 | 1331 |
| 1332 [self setManagedBookmarksButtonVisibility]; |
1148 } | 1333 } |
1149 | 1334 |
1150 // Creates the button for "Supervised Bookmarks", but does not position it. | 1335 // Creates the button for "Supervised Bookmarks", but does not position it. |
1151 - (void)createSupervisedBookmarksButton { | 1336 - (void)createSupervisedBookmarksButton { |
1152 if (supervisedBookmarksButton_.get()) { | 1337 if (supervisedBookmarksButton_.get()) { |
| 1338 // The button's already there, but its visibility may have changed. |
| 1339 [self setSupervisedBookmarksButtonVisibility]; |
1153 return; | 1340 return; |
1154 } | 1341 } |
1155 | 1342 |
1156 NSCell* cell = | 1343 NSCell* cell = |
1157 [self cellForBookmarkNode:managedBookmarkService_->supervised_node()]; | 1344 [self cellForBookmarkNode:managedBookmarkService_->supervised_node()]; |
1158 supervisedBookmarksButton_.reset( | 1345 supervisedBookmarksButton_.reset( |
1159 [self createCustomBookmarkButtonForCell:cell]); | 1346 [self createCustomBookmarkButtonForCell:cell]); |
1160 [supervisedBookmarksButton_ | 1347 [supervisedBookmarksButton_ |
1161 setAction:@selector(openBookmarkFolderFromButton:)]; | 1348 setAction:@selector(openBookmarkFolderFromButton:)]; |
1162 view_id_util::SetID(supervisedBookmarksButton_.get(), | 1349 view_id_util::SetID(supervisedBookmarksButton_.get(), |
1163 VIEW_ID_SUPERVISED_BOOKMARKS); | 1350 VIEW_ID_SUPERVISED_BOOKMARKS); |
1164 NSRect frame = NSMakeRect(0, bookmarks::kBookmarkVerticalPadding, | |
1165 [self widthForBookmarkButtonCell:cell], | |
1166 kBookmarkButtonHeightMinusPadding); | |
1167 [supervisedBookmarksButton_ setFrame:frame]; | |
1168 [buttonView_ addSubview:supervisedBookmarksButton_.get()]; | 1351 [buttonView_ addSubview:supervisedBookmarksButton_.get()]; |
| 1352 |
| 1353 [self setSupervisedBookmarksButtonVisibility]; |
1169 } | 1354 } |
1170 | 1355 |
1171 // Creates the button for "Other Bookmarks", but does not position it. | 1356 // Creates the button for "Other Bookmarks", but does not position it. |
1172 - (void)createOtherBookmarksButton { | 1357 - (void)createOtherBookmarksButton { |
1173 // Can't create this until the model is loaded, but only need to | 1358 // Can't create this until the model is loaded, but only need to |
1174 // create it once. | 1359 // create it once. |
1175 if (otherBookmarksButton_.get()) { | 1360 if (otherBookmarksButton_.get()) { |
| 1361 [self setOtherBookmarksButtonVisibility]; |
1176 return; | 1362 return; |
1177 } | 1363 } |
1178 | 1364 |
1179 NSCell* cell = [self cellForBookmarkNode:bookmarkModel_->other_node()]; | 1365 NSCell* cell = [self cellForBookmarkNode:bookmarkModel_->other_node()]; |
1180 otherBookmarksButton_.reset([self createCustomBookmarkButtonForCell:cell]); | 1366 otherBookmarksButton_.reset([self createCustomBookmarkButtonForCell:cell]); |
| 1367 // Peg at right; keep same height as bar. |
| 1368 [otherBookmarksButton_ setAutoresizingMask:(NSViewMinXMargin)]; |
1181 [otherBookmarksButton_ setAction:@selector(openBookmarkFolderFromButton:)]; | 1369 [otherBookmarksButton_ setAction:@selector(openBookmarkFolderFromButton:)]; |
1182 NSRect frame = NSMakeRect(0, bookmarks::kBookmarkVerticalPadding, | |
1183 [self widthForBookmarkButtonCell:cell], | |
1184 kBookmarkButtonHeightMinusPadding); | |
1185 [otherBookmarksButton_ setFrame:frame]; | |
1186 view_id_util::SetID(otherBookmarksButton_.get(), VIEW_ID_OTHER_BOOKMARKS); | 1370 view_id_util::SetID(otherBookmarksButton_.get(), VIEW_ID_OTHER_BOOKMARKS); |
1187 [buttonView_ addSubview:otherBookmarksButton_.get()]; | 1371 [buttonView_ addSubview:otherBookmarksButton_.get()]; |
| 1372 |
| 1373 [self setOtherBookmarksButtonVisibility]; |
1188 } | 1374 } |
1189 | 1375 |
1190 // Creates the button for "Apps", but does not position it. | 1376 // Creates the button for "Apps", but does not position it. |
1191 - (void)createAppsPageShortcutButton { | 1377 - (void)createAppsPageShortcutButton { |
| 1378 // Can't create this until the model is loaded, but only need to |
| 1379 // create it once. |
1192 if (appsPageShortcutButton_.get()) { | 1380 if (appsPageShortcutButton_.get()) { |
| 1381 [self setAppsPageShortcutButtonVisibility]; |
1193 return; | 1382 return; |
1194 } | 1383 } |
1195 | 1384 |
1196 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 1385 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
1197 NSString* text = l10n_util::GetNSString(IDS_BOOKMARK_BAR_APPS_SHORTCUT_NAME); | 1386 NSString* text = l10n_util::GetNSString(IDS_BOOKMARK_BAR_APPS_SHORTCUT_NAME); |
1198 NSImage* image = rb.GetNativeImageNamed( | 1387 NSImage* image = rb.GetNativeImageNamed( |
1199 IDR_BOOKMARK_BAR_APPS_SHORTCUT).ToNSImage(); | 1388 IDR_BOOKMARK_BAR_APPS_SHORTCUT).ToNSImage(); |
1200 NSCell* cell = [self cellForCustomButtonWithText:text | 1389 NSCell* cell = [self cellForCustomButtonWithText:text |
1201 image:image]; | 1390 image:image]; |
1202 NSRect frame; | |
1203 frame.origin.y = bookmarks::kBookmarkVerticalPadding; | |
1204 frame.size = NSMakeSize([self widthForBookmarkButtonCell:cell], | |
1205 kBookmarkButtonHeightMinusPadding); | |
1206 appsPageShortcutButton_.reset([self createCustomBookmarkButtonForCell:cell]); | 1391 appsPageShortcutButton_.reset([self createCustomBookmarkButtonForCell:cell]); |
1207 [appsPageShortcutButton_ setFrame:frame]; | |
1208 [[appsPageShortcutButton_ draggableButton] setActsOnMouseDown:NO]; | 1392 [[appsPageShortcutButton_ draggableButton] setActsOnMouseDown:NO]; |
1209 [appsPageShortcutButton_ setAction:@selector(openAppsPage:)]; | 1393 [appsPageShortcutButton_ setAction:@selector(openAppsPage:)]; |
1210 NSString* tooltip = | 1394 NSString* tooltip = |
1211 l10n_util::GetNSString(IDS_BOOKMARK_BAR_APPS_SHORTCUT_TOOLTIP); | 1395 l10n_util::GetNSString(IDS_BOOKMARK_BAR_APPS_SHORTCUT_TOOLTIP); |
1212 [appsPageShortcutButton_ setToolTip:tooltip]; | 1396 [appsPageShortcutButton_ setToolTip:tooltip]; |
1213 [buttonView_ addSubview:appsPageShortcutButton_.get()]; | 1397 [buttonView_ addSubview:appsPageShortcutButton_.get()]; |
| 1398 |
| 1399 [self setAppsPageShortcutButtonVisibility]; |
1214 } | 1400 } |
1215 | 1401 |
1216 // Creates the "off-the-side" (chevron/overflow) button but | |
1217 // does not position it. | |
1218 - (void)createOffTheSideButton { | 1402 - (void)createOffTheSideButton { |
1219 if (offTheSideButton_.get()) { | |
1220 return; | |
1221 } | |
1222 DCHECK(bookmarkModel_->loaded()); | |
1223 offTheSideButton_.reset( | 1403 offTheSideButton_.reset( |
1224 [[BookmarkButton alloc] initWithFrame:NSMakeRect(0, 0, 20, 24)]); | 1404 [[BookmarkButton alloc] initWithFrame:NSMakeRect(586, 0, 20, 24)]); |
1225 id offTheSideCell = [BookmarkButtonCell offTheSideButtonCell]; | 1405 id offTheSideCell = [BookmarkButtonCell offTheSideButtonCell]; |
1226 [offTheSideCell setTag:kMaterialStandardButtonTypeWithLimitedClickFeedback]; | 1406 [offTheSideCell setTag:kMaterialStandardButtonTypeWithLimitedClickFeedback]; |
1227 [offTheSideCell setImagePosition:NSImageOnly]; | 1407 [offTheSideCell setImagePosition:NSImageOnly]; |
1228 | 1408 |
1229 [offTheSideCell setHighlightsBy:NSNoCellMask]; | 1409 [offTheSideCell setHighlightsBy:NSNoCellMask]; |
1230 [offTheSideCell setShowsBorderOnlyWhileMouseInside:YES]; | 1410 [offTheSideCell setShowsBorderOnlyWhileMouseInside:YES]; |
1231 [offTheSideCell setBezelStyle:NSShadowlessSquareBezelStyle]; | 1411 [offTheSideCell setBezelStyle:NSShadowlessSquareBezelStyle]; |
1232 [offTheSideCell setBookmarkNode:bookmarkModel_->bookmark_bar_node()]; | |
1233 | |
1234 [offTheSideButton_ setCell:offTheSideCell]; | 1412 [offTheSideButton_ setCell:offTheSideCell]; |
1235 [offTheSideButton_ setImage:[self offTheSideButtonImage:NO]]; | 1413 [offTheSideButton_ setImage:[self offTheSideButtonImage:NO]]; |
1236 [offTheSideButton_ setButtonType:NSMomentaryLightButton]; | 1414 [offTheSideButton_ setButtonType:NSMomentaryLightButton]; |
1237 | 1415 |
1238 [offTheSideButton_ setTarget:self]; | 1416 [offTheSideButton_ setTarget:self]; |
1239 [offTheSideButton_ setAction:@selector(openOffTheSideFolderFromButton:)]; | 1417 [offTheSideButton_ setAction:@selector(openOffTheSideFolderFromButton:)]; |
1240 [offTheSideButton_ setDelegate:self]; | 1418 [offTheSideButton_ setDelegate:self]; |
1241 [[offTheSideButton_ draggableButton] setDraggable:NO]; | 1419 [[offTheSideButton_ draggableButton] setDraggable:NO]; |
1242 [[offTheSideButton_ draggableButton] setActsOnMouseDown:YES]; | 1420 [[offTheSideButton_ draggableButton] setActsOnMouseDown:YES]; |
1243 [offTheSideButton_ setHidden:YES]; | |
1244 [buttonView_ addSubview:offTheSideButton_]; | |
1245 } | |
1246 | |
1247 - (void)updateExtraButtonsVisibility { | |
1248 [self rebuildLayoutWithAnimated:NO]; | |
1249 } | |
1250 | |
1251 - (void)createExtraButtons { | |
1252 DCHECK(!didCreateExtraButtons_); | |
1253 [self createSupervisedBookmarksButton]; | |
1254 [self createManagedBookmarksButton]; | |
1255 [self createOtherBookmarksButton]; | |
1256 [self createAppsPageShortcutButton]; | |
1257 [self createOffTheSideButton]; | |
1258 didCreateExtraButtons_ = YES; | |
1259 } | 1421 } |
1260 | 1422 |
1261 - (void)openAppsPage:(id)sender { | 1423 - (void)openAppsPage:(id)sender { |
1262 WindowOpenDisposition disposition = | 1424 WindowOpenDisposition disposition = |
1263 ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); | 1425 ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); |
1264 [self openURL:GURL(chrome::kChromeUIAppsURL) disposition:disposition]; | 1426 [self openURL:GURL(chrome::kChromeUIAppsURL) disposition:disposition]; |
1265 RecordBookmarkAppsPageOpen([self bookmarkLaunchLocation]); | 1427 RecordBookmarkAppsPageOpen([self bookmarkLaunchLocation]); |
1266 } | 1428 } |
1267 | 1429 |
1268 // To avoid problems with sync, changes that may impact the current | 1430 // To avoid problems with sync, changes that may impact the current |
1269 // bookmark (e.g. deletion) make sure context menus are closed. This | 1431 // bookmark (e.g. deletion) make sure context menus are closed. This |
1270 // prevents deleting a node which no longer exists. | 1432 // prevents deleting a node which no longer exists. |
1271 - (void)cancelMenuTracking { | 1433 - (void)cancelMenuTracking { |
1272 [contextMenuController_ cancelTracking]; | 1434 [contextMenuController_ cancelTracking]; |
1273 } | 1435 } |
1274 | 1436 |
1275 // Moves to the given next state (from the current state), possibly animating. | |
1276 // If |animate| is NO, it will stop any running animation and jump to the given | |
1277 // state. If YES, it may either (depending on implementation) jump to the end of | |
1278 // the current animation and begin the next one, or stop the current animation | |
1279 // mid-flight and animate to the next state. | |
1280 - (void)moveToState:(BookmarkBar::State)nextState | 1437 - (void)moveToState:(BookmarkBar::State)nextState |
1281 withAnimation:(BOOL)animate { | 1438 withAnimation:(BOOL)animate { |
1282 BOOL isAnimationRunning = [self isAnimationRunning]; | 1439 BOOL isAnimationRunning = [self isAnimationRunning]; |
1283 | 1440 |
1284 // No-op if the next state is the same as the "current" one, subject to the | 1441 // No-op if the next state is the same as the "current" one, subject to the |
1285 // following conditions: | 1442 // following conditions: |
1286 // - no animation is running; or | 1443 // - no animation is running; or |
1287 // - an animation is running and |animate| is YES ([*] if it's NO, we'd want | 1444 // - an animation is running and |animate| is YES ([*] if it's NO, we'd want |
1288 // to cancel the animation and jump to the final state). | 1445 // to cancel the animation and jump to the final state). |
1289 if ((nextState == currentState_) && (!isAnimationRunning || animate)) | 1446 if ((nextState == currentState_) && (!isAnimationRunning || animate)) |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1336 } | 1493 } |
1337 | 1494 |
1338 // N.B.: |-moveToState:...| will check if this should be a no-op or not. | 1495 // N.B.: |-moveToState:...| will check if this should be a no-op or not. |
1339 - (void)updateState:(BookmarkBar::State)newState | 1496 - (void)updateState:(BookmarkBar::State)newState |
1340 changeType:(BookmarkBar::AnimateChangeType)changeType { | 1497 changeType:(BookmarkBar::AnimateChangeType)changeType { |
1341 BOOL animate = changeType == BookmarkBar::ANIMATE_STATE_CHANGE && | 1498 BOOL animate = changeType == BookmarkBar::ANIMATE_STATE_CHANGE && |
1342 stateAnimationsEnabled_; | 1499 stateAnimationsEnabled_; |
1343 [self moveToState:newState withAnimation:animate]; | 1500 [self moveToState:newState withAnimation:animate]; |
1344 } | 1501 } |
1345 | 1502 |
1346 // Jump to final state (detached, attached, hidden, etc.) without animating, | 1503 // (Private) |
1347 // stopping a running animation if necessary. | |
1348 - (void)finalizeState { | 1504 - (void)finalizeState { |
1349 // We promise that our delegate that the variables will be finalized before | 1505 // We promise that our delegate that the variables will be finalized before |
1350 // the call to |-bookmarkBar:didChangeFromState:toState:|. | 1506 // the call to |-bookmarkBar:didChangeFromState:toState:|. |
1351 BookmarkBar::State oldState = lastState_; | 1507 BookmarkBar::State oldState = lastState_; |
1352 lastState_ = currentState_; | 1508 lastState_ = currentState_; |
1353 isAnimationRunning_ = NO; | 1509 isAnimationRunning_ = NO; |
1354 | 1510 |
1355 // Notify our delegate. | 1511 // Notify our delegate. |
1356 [delegate_ bookmarkBar:self | 1512 [delegate_ bookmarkBar:self |
1357 didChangeFromState:oldState | 1513 didChangeFromState:oldState |
1358 toState:currentState_]; | 1514 toState:currentState_]; |
1359 | 1515 |
1360 // Update ourselves visually. | 1516 // Update ourselves visually. |
1361 [self updateVisibility]; | 1517 [self updateVisibility]; |
1362 } | 1518 } |
1363 | 1519 |
1364 // Stops any current animation in its tracks (midway). | 1520 // (Private) |
1365 - (void)stopCurrentAnimation { | 1521 - (void)stopCurrentAnimation { |
1366 [[self controlledView] stopAnimation]; | 1522 [[self controlledView] stopAnimation]; |
1367 } | 1523 } |
1368 | 1524 |
1369 // Delegate method for |AnimatableView| (a superclass of | 1525 // Delegate method for |AnimatableView| (a superclass of |
1370 // |BookmarkBarToolbarView|). | 1526 // |BookmarkBarToolbarView|). |
1371 - (void)animationDidEnd:(NSAnimation*)animation { | 1527 - (void)animationDidEnd:(NSAnimation*)animation { |
1372 [self finalizeState]; | 1528 [self finalizeState]; |
1373 } | 1529 } |
1374 | 1530 |
| 1531 - (void)reconfigureBookmarkBar { |
| 1532 [self setManagedBookmarksButtonVisibility]; |
| 1533 [self setSupervisedBookmarksButtonVisibility]; |
| 1534 [self redistributeButtonsOnBarAsNeeded]; |
| 1535 [self positionRightSideButtons]; |
| 1536 [self configureOffTheSideButtonContentsAndVisibility]; |
| 1537 [self centerNoItemsLabel]; |
| 1538 } |
| 1539 |
| 1540 // Determine if the given |view| can completely fit within the constraint of |
| 1541 // maximum x, given by |maxViewX|, and, if not, narrow the view up to a minimum |
| 1542 // width. If the minimum width is not achievable then hide the view. Return YES |
| 1543 // if the view was hidden. |
| 1544 - (BOOL)shrinkOrHideView:(NSView*)view forMaxX:(CGFloat)maxViewX { |
| 1545 BOOL wasHidden = NO; |
| 1546 // See if the view needs to be narrowed. |
| 1547 NSRect frame = [view frame]; |
| 1548 if (NSMaxX(frame) > maxViewX) { |
| 1549 // Resize if more than 30 pixels are showing, otherwise hide. |
| 1550 if (NSMinX(frame) + 30.0 < maxViewX) { |
| 1551 frame.size.width = maxViewX - NSMinX(frame); |
| 1552 [view setFrame:frame]; |
| 1553 } else { |
| 1554 [view setHidden:YES]; |
| 1555 wasHidden = YES; |
| 1556 } |
| 1557 } |
| 1558 return wasHidden; |
| 1559 } |
| 1560 |
1375 // Bookmark button menu items that open a new window (e.g., open in new window, | 1561 // Bookmark button menu items that open a new window (e.g., open in new window, |
1376 // open in incognito, edit, etc.) cause us to lose a mouse-exited event | 1562 // open in incognito, edit, etc.) cause us to lose a mouse-exited event |
1377 // on the button, which leaves it in a hover state. | 1563 // on the button, which leaves it in a hover state. |
1378 // Since the showsBorderOnlyWhileMouseInside uses a tracking area, simple | 1564 // Since the showsBorderOnlyWhileMouseInside uses a tracking area, simple |
1379 // tricks (e.g. sending an extra mouseExited: to the button) don't | 1565 // tricks (e.g. sending an extra mouseExited: to the button) don't |
1380 // fix the problem. | 1566 // fix the problem. |
1381 // http://crbug.com/129338 | 1567 // http://crbug.com/129338 |
1382 - (void)unhighlightBookmark:(const BookmarkNode*)node { | 1568 - (void)unhighlightBookmark:(const BookmarkNode*)node { |
1383 // Only relevant if context menu was opened from a button on the | 1569 // Only relevant if context menu was opened from a button on the |
1384 // bookmark bar. | 1570 // bookmark bar. |
1385 const BookmarkNode* parent = node->parent(); | 1571 const BookmarkNode* parent = node->parent(); |
1386 BookmarkNode::Type parentType = parent->type(); | 1572 BookmarkNode::Type parentType = parent->type(); |
1387 if (parentType == BookmarkNode::BOOKMARK_BAR) { | 1573 if (parentType == BookmarkNode::BOOKMARK_BAR) { |
1388 int index = parent->GetIndexOf(node); | 1574 int index = parent->GetIndexOf(node); |
1389 if ((index >= 0) && (static_cast<NSUInteger>(index) < [buttons_ count])) { | 1575 if ((index >= 0) && (static_cast<NSUInteger>(index) < [buttons_ count])) { |
1390 NSButton* button = | 1576 NSButton* button = |
1391 [buttons_ objectAtIndex:static_cast<NSUInteger>(index)]; | 1577 [buttons_ objectAtIndex:static_cast<NSUInteger>(index)]; |
1392 if ([button showsBorderOnlyWhileMouseInside]) { | 1578 if ([button showsBorderOnlyWhileMouseInside]) { |
1393 [button setShowsBorderOnlyWhileMouseInside:NO]; | 1579 [button setShowsBorderOnlyWhileMouseInside:NO]; |
1394 [button setShowsBorderOnlyWhileMouseInside:YES]; | 1580 [button setShowsBorderOnlyWhileMouseInside:YES]; |
1395 } | 1581 } |
1396 } | 1582 } |
1397 } | 1583 } |
1398 } | 1584 } |
1399 | 1585 |
1400 - (void)addButtonForNode:(const bookmarks::BookmarkNode*)node | 1586 |
1401 atIndex:(NSInteger)buttonIndex { | 1587 // Adjust the horizontal width, x position and the visibility of the "For quick |
1402 [self rebuildLayoutWithAnimated:NO]; | 1588 // access" text field and "Import bookmarks..." button based on the current |
| 1589 // width of the containing |buttonView_| (which is affected by window width). |
| 1590 - (void)adjustNoItemContainerForMaxX:(CGFloat)maxViewX { |
| 1591 if (![[buttonView_ noItemContainer] isHidden]) { |
| 1592 // Reset initial frames for the two items, then adjust as necessary. |
| 1593 NSTextField* noItemTextfield = [buttonView_ noItemTextfield]; |
| 1594 NSRect noItemsRect = originalNoItemsRect_; |
| 1595 NSRect importBookmarksRect = originalImportBookmarksRect_; |
| 1596 if (![appsPageShortcutButton_ isHidden]) { |
| 1597 float width = NSWidth([appsPageShortcutButton_ frame]); |
| 1598 noItemsRect.origin.x += width; |
| 1599 importBookmarksRect.origin.x += width; |
| 1600 } |
| 1601 if (![managedBookmarksButton_ isHidden]) { |
| 1602 float width = NSWidth([managedBookmarksButton_ frame]); |
| 1603 noItemsRect.origin.x += width; |
| 1604 importBookmarksRect.origin.x += width; |
| 1605 } |
| 1606 if (![supervisedBookmarksButton_ isHidden]) { |
| 1607 float width = NSWidth([supervisedBookmarksButton_ frame]); |
| 1608 noItemsRect.origin.x += width; |
| 1609 importBookmarksRect.origin.x += width; |
| 1610 } |
| 1611 [noItemTextfield setFrame:noItemsRect]; |
| 1612 [noItemTextfield setHidden:NO]; |
| 1613 NSButton* importBookmarksButton = [buttonView_ importBookmarksButton]; |
| 1614 [importBookmarksButton setFrame:importBookmarksRect]; |
| 1615 [importBookmarksButton setHidden:NO]; |
| 1616 // Check each to see if they need to be shrunk or hidden. |
| 1617 if ([self shrinkOrHideView:importBookmarksButton forMaxX:maxViewX]) |
| 1618 [self shrinkOrHideView:noItemTextfield forMaxX:maxViewX]; |
| 1619 } |
| 1620 } |
| 1621 |
| 1622 // Scans through all buttons from left to right, calculating from scratch where |
| 1623 // they should be based on the preceding widths, until it finds the one |
| 1624 // requested. |
| 1625 // Returns NSZeroRect if there is no such button in the bookmark bar. |
| 1626 // Enables you to work out where a button will end up when it is done animating. |
| 1627 - (NSRect)finalRectOfButton:(BookmarkButton*)wantedButton { |
| 1628 CGFloat left = bookmarks::kBookmarkLeftMargin; |
| 1629 NSRect buttonFrame = NSZeroRect; |
| 1630 |
| 1631 // Draw the apps bookmark if needed. |
| 1632 if (![appsPageShortcutButton_ isHidden]) { |
| 1633 left = NSMaxX([appsPageShortcutButton_ frame]) + |
| 1634 bookmarks::kBookmarkHorizontalPadding; |
| 1635 } |
| 1636 |
| 1637 // Draw the managed bookmarks folder if needed. |
| 1638 if (![managedBookmarksButton_ isHidden]) { |
| 1639 left = NSMaxX([managedBookmarksButton_ frame]) + |
| 1640 bookmarks::kBookmarkHorizontalPadding; |
| 1641 } |
| 1642 |
| 1643 // Draw the supervised bookmarks folder if needed. |
| 1644 if (![supervisedBookmarksButton_ isHidden]) { |
| 1645 left = NSMaxX([supervisedBookmarksButton_ frame]) + |
| 1646 bookmarks::kBookmarkHorizontalPadding; |
| 1647 } |
| 1648 |
| 1649 for (NSButton* button in buttons_.get()) { |
| 1650 // Hidden buttons get no space. |
| 1651 if ([button isHidden]) |
| 1652 continue; |
| 1653 buttonFrame = [button frame]; |
| 1654 buttonFrame.origin.x = left; |
| 1655 left += buttonFrame.size.width + bookmarks::kBookmarkHorizontalPadding; |
| 1656 if (button == wantedButton) |
| 1657 return buttonFrame; |
| 1658 } |
| 1659 return NSZeroRect; |
| 1660 } |
| 1661 |
| 1662 // Calculates the final position of the last button in the bar. |
| 1663 // We can't just use [[self buttons] lastObject] frame] because the button |
| 1664 // may be animating currently. |
| 1665 - (NSRect)finalRectOfLastButton { |
| 1666 return [self finalRectOfButton:[[self buttons] lastObject]]; |
| 1667 } |
| 1668 |
| 1669 - (CGFloat)buttonViewMaxXWithOffTheSideButtonIsVisible:(BOOL)visible { |
| 1670 CGFloat maxViewX = NSMaxX([buttonView_ bounds]); |
| 1671 // If necessary, pull in the width to account for the Other Bookmarks button. |
| 1672 if ([self setOtherBookmarksButtonVisibility]) { |
| 1673 maxViewX = [otherBookmarksButton_ frame].origin.x - |
| 1674 bookmarks::kBookmarkRightMargin; |
| 1675 } |
| 1676 |
| 1677 [self positionRightSideButtons]; |
| 1678 // If we're already overflowing, then we need to account for the chevron. |
| 1679 if (visible) { |
| 1680 maxViewX = |
| 1681 [offTheSideButton_ frame].origin.x - bookmarks::kBookmarkRightMargin; |
| 1682 } |
| 1683 |
| 1684 return maxViewX; |
| 1685 } |
| 1686 |
| 1687 - (void)redistributeButtonsOnBarAsNeeded { |
| 1688 const BookmarkNode* node = bookmarkModel_->bookmark_bar_node(); |
| 1689 NSInteger barCount = node->child_count(); |
| 1690 |
| 1691 // Determine the current maximum extent of the visible buttons. |
| 1692 [self positionRightSideButtons]; |
| 1693 BOOL offTheSideButtonVisible = (barCount > displayedButtonCount_); |
| 1694 CGFloat maxViewX = [self buttonViewMaxXWithOffTheSideButtonIsVisible: |
| 1695 offTheSideButtonVisible]; |
| 1696 |
| 1697 // As a result of pasting or dragging, the bar may now have more buttons |
| 1698 // than will fit so remove any which overflow. They will be shown in |
| 1699 // the off-the-side folder. |
| 1700 while (displayedButtonCount_ > 0) { |
| 1701 BookmarkButton* button = [buttons_ lastObject]; |
| 1702 if (NSMaxX([self finalRectOfLastButton]) < maxViewX) |
| 1703 break; |
| 1704 [buttons_ removeLastObject]; |
| 1705 [button setDelegate:nil]; |
| 1706 [button removeFromSuperview]; |
| 1707 --displayedButtonCount_; |
| 1708 // Account for the fact that the chevron might now be visible. |
| 1709 if (!offTheSideButtonVisible) { |
| 1710 offTheSideButtonVisible = YES; |
| 1711 maxViewX = [self buttonViewMaxXWithOffTheSideButtonIsVisible:YES]; |
| 1712 } |
| 1713 } |
| 1714 |
| 1715 // As a result of cutting, deleting and dragging, the bar may now have room |
| 1716 // for more buttons. |
| 1717 int xOffset; |
| 1718 if (displayedButtonCount_ > 0) { |
| 1719 xOffset = NSMaxX([self finalRectOfLastButton]); |
| 1720 } else if (![managedBookmarksButton_ isHidden]) { |
| 1721 xOffset = NSMaxX([managedBookmarksButton_ frame]) + |
| 1722 bookmarks::kBookmarkHorizontalPadding; |
| 1723 } else if (![supervisedBookmarksButton_ isHidden]) { |
| 1724 xOffset = NSMaxX([supervisedBookmarksButton_ frame]) + |
| 1725 bookmarks::kBookmarkHorizontalPadding; |
| 1726 } else if (![appsPageShortcutButton_ isHidden]) { |
| 1727 xOffset = NSMaxX([appsPageShortcutButton_ frame]) + |
| 1728 bookmarks::kBookmarkHorizontalPadding; |
| 1729 } else { |
| 1730 xOffset = bookmarks::kBookmarkLeftMargin - |
| 1731 bookmarks::kBookmarkHorizontalPadding; |
| 1732 } |
| 1733 for (int i = displayedButtonCount_; i < barCount; ++i) { |
| 1734 const BookmarkNode* child = node->GetChild(i); |
| 1735 BookmarkButton* button = [self buttonForNode:child xOffset:&xOffset]; |
| 1736 // If we're testing against the last possible button then account |
| 1737 // for the chevron no longer needing to be shown. |
| 1738 if (i == barCount - 1) |
| 1739 maxViewX = [self buttonViewMaxXWithOffTheSideButtonIsVisible:NO]; |
| 1740 if (NSMaxX([button frame]) > maxViewX) { |
| 1741 [button setDelegate:nil]; |
| 1742 break; |
| 1743 } |
| 1744 ++displayedButtonCount_; |
| 1745 [buttons_ addObject:button]; |
| 1746 [buttonView_ addSubview:button]; |
| 1747 } |
| 1748 |
| 1749 // While we're here, adjust the horizontal width and the visibility |
| 1750 // of the "For quick access" and "Import bookmarks..." text fields. |
| 1751 if (![buttons_ count]) |
| 1752 [self adjustNoItemContainerForMaxX:maxViewX]; |
1403 } | 1753 } |
1404 | 1754 |
1405 #pragma mark Private Methods Exposed for Testing | 1755 #pragma mark Private Methods Exposed for Testing |
1406 | 1756 |
1407 - (BookmarkBarView*)buttonView { | 1757 - (BookmarkBarView*)buttonView { |
1408 return buttonView_; | 1758 return buttonView_; |
1409 } | 1759 } |
1410 | 1760 |
1411 - (NSMutableArray*)buttons { | 1761 - (NSMutableArray*)buttons { |
1412 return buttons_.get(); | 1762 return buttons_.get(); |
1413 } | 1763 } |
1414 | 1764 |
| 1765 - (BOOL)offTheSideButtonIsHidden { |
| 1766 return [offTheSideButton_ isHidden]; |
| 1767 } |
| 1768 |
| 1769 - (BOOL)appsPageShortcutButtonIsHidden { |
| 1770 return [appsPageShortcutButton_ isHidden]; |
| 1771 } |
| 1772 |
1415 - (BookmarkButton*)otherBookmarksButton { | 1773 - (BookmarkButton*)otherBookmarksButton { |
1416 return otherBookmarksButton_.get(); | 1774 return otherBookmarksButton_.get(); |
1417 } | 1775 } |
1418 | 1776 |
1419 - (BookmarkButton*)managedBookmarksButton { | |
1420 return managedBookmarksButton_.get(); | |
1421 } | |
1422 | |
1423 - (BookmarkButton*)supervisedBookmarksButton { | |
1424 return supervisedBookmarksButton_.get(); | |
1425 } | |
1426 | |
1427 - (BookmarkBarFolderController*)folderController { | 1777 - (BookmarkBarFolderController*)folderController { |
1428 return folderController_; | 1778 return folderController_; |
1429 } | 1779 } |
1430 | 1780 |
1431 - (id)folderTarget { | 1781 - (id)folderTarget { |
1432 return folderTarget_.get(); | 1782 return folderTarget_.get(); |
1433 } | 1783 } |
1434 | 1784 |
| 1785 - (int)displayedButtonCount { |
| 1786 return displayedButtonCount_; |
| 1787 } |
| 1788 |
| 1789 // Delete all buttons (bookmarks, chevron, "other bookmarks") from the |
| 1790 // bookmark bar; reset knowledge of bookmarks. |
| 1791 - (void)clearBookmarkBar { |
| 1792 [self stopPulsingBookmarkNode]; |
| 1793 for (BookmarkButton* button in buttons_.get()) { |
| 1794 [button setDelegate:nil]; |
| 1795 [button removeFromSuperview]; |
| 1796 } |
| 1797 [buttons_ removeAllObjects]; |
| 1798 displayedButtonCount_ = 0; |
| 1799 |
| 1800 // Make sure there are no stale pointers in the pasteboard. This |
| 1801 // can be important if a bookmark is deleted (via bookmark sync) |
| 1802 // while in the middle of a drag. The "drag completed" code |
| 1803 // (e.g. [BookmarkBarView performDragOperationForBookmarkButton:]) is |
| 1804 // careful enough to bail if there is no data found at "drop" time. |
| 1805 [[NSPasteboard pasteboardWithName:NSDragPboard] clearContents]; |
| 1806 } |
| 1807 |
1435 // Return an autoreleased NSCell suitable for a bookmark button. | 1808 // Return an autoreleased NSCell suitable for a bookmark button. |
1436 // TODO(jrg): move much of the cell config into the BookmarkButtonCell class. | 1809 // TODO(jrg): move much of the cell config into the BookmarkButtonCell class. |
1437 - (BookmarkButtonCell*)cellForBookmarkNode:(const BookmarkNode*)node { | 1810 - (BookmarkButtonCell*)cellForBookmarkNode:(const BookmarkNode*)node { |
1438 BOOL darkTheme = [[[self view] window] hasDarkTheme]; | 1811 BOOL darkTheme = [[[self view] window] hasDarkTheme]; |
1439 NSImage* image = node ? [self faviconForNode:node forADarkTheme:darkTheme] | 1812 NSImage* image = node ? [self faviconForNode:node forADarkTheme:darkTheme] |
1440 : nil; | 1813 : nil; |
1441 BookmarkButtonCell* cell = | 1814 BookmarkButtonCell* cell = |
1442 [BookmarkButtonCell buttonCellForNode:node | 1815 [BookmarkButtonCell buttonCellForNode:node |
1443 text:nil | 1816 text:nil |
1444 image:image | 1817 image:image |
(...skipping 17 matching lines...) Expand all Loading... |
1462 menuController:contextMenuController_]; | 1835 menuController:contextMenuController_]; |
1463 [cell setTag:kMaterialStandardButtonTypeWithLimitedClickFeedback]; | 1836 [cell setTag:kMaterialStandardButtonTypeWithLimitedClickFeedback]; |
1464 [cell setHighlightsBy:NSNoCellMask]; | 1837 [cell setHighlightsBy:NSNoCellMask]; |
1465 | 1838 |
1466 // Note: a quirk of setting a cell's text color is that it won't work | 1839 // Note: a quirk of setting a cell's text color is that it won't work |
1467 // until the cell is associated with a button, so we can't theme the cell yet. | 1840 // until the cell is associated with a button, so we can't theme the cell yet. |
1468 | 1841 |
1469 return cell; | 1842 return cell; |
1470 } | 1843 } |
1471 | 1844 |
| 1845 // Returns a frame appropriate for the given bookmark cell, suitable |
| 1846 // for creating an NSButton that will contain it. |xOffset| is the X |
| 1847 // offset for the frame; it is increased to be an appropriate X offset |
| 1848 // for the next button. |
| 1849 - (NSRect)frameForBookmarkButtonFromCell:(NSCell*)cell |
| 1850 xOffset:(int*)xOffset { |
| 1851 DCHECK(xOffset); |
| 1852 NSRect bounds = [buttonView_ bounds]; |
| 1853 bounds.size.height = bookmarks::kBookmarkButtonHeight; |
| 1854 |
| 1855 NSRect frame = NSInsetRect(bounds, |
| 1856 bookmarks::kBookmarkHorizontalPadding, |
| 1857 bookmarks::kBookmarkVerticalPadding); |
| 1858 frame.size.width = [self widthForBookmarkButtonCell:cell]; |
| 1859 |
| 1860 // Add an X offset based on what we've already done |
| 1861 frame.origin.x += *xOffset; |
| 1862 |
| 1863 // And up the X offset for next time. |
| 1864 *xOffset = NSMaxX(frame); |
| 1865 |
| 1866 return frame; |
| 1867 } |
| 1868 |
| 1869 // A bookmark button's contents changed. Check for growth |
| 1870 // (e.g. increase the width up to the maximum). If we grew, move |
| 1871 // other bookmark buttons over. |
| 1872 - (void)checkForBookmarkButtonGrowth:(NSButton*)changedButton { |
| 1873 NSRect frame = [changedButton frame]; |
| 1874 CGFloat desiredSize = [self widthForBookmarkButtonCell:[changedButton cell]]; |
| 1875 CGFloat delta = desiredSize - frame.size.width; |
| 1876 if (delta) { |
| 1877 frame.size.width = desiredSize; |
| 1878 [changedButton setFrame:frame]; |
| 1879 for (NSButton* button in buttons_.get()) { |
| 1880 NSRect buttonFrame = [button frame]; |
| 1881 if (buttonFrame.origin.x > frame.origin.x) { |
| 1882 buttonFrame.origin.x += delta; |
| 1883 [button setFrame:buttonFrame]; |
| 1884 } |
| 1885 } |
| 1886 } |
| 1887 // We may have just crossed a threshold to enable the off-the-side |
| 1888 // button. |
| 1889 [self configureOffTheSideButtonContentsAndVisibility]; |
| 1890 } |
| 1891 |
1472 // Called when our controlled frame has changed size. | 1892 // Called when our controlled frame has changed size. |
1473 - (void)frameDidChange { | 1893 - (void)frameDidChange { |
1474 [self rebuildLayoutWithAnimated:NO]; | 1894 if (!bookmarkModel_->loaded()) |
| 1895 return; |
| 1896 [self updateTheme:[[[self view] window] themeProvider]]; |
| 1897 [self reconfigureBookmarkBar]; |
1475 } | 1898 } |
1476 | 1899 |
1477 // Adapt appearance of buttons to the current theme. Called after | 1900 // Adapt appearance of buttons to the current theme. Called after |
1478 // theme changes, or when our view is added to the view hierarchy. | 1901 // theme changes, or when our view is added to the view hierarchy. |
1479 // Oddly, the view pings us instead of us pinging our view. This is | 1902 // Oddly, the view pings us instead of us pinging our view. This is |
1480 // because our trigger is an [NSView viewWillMoveToWindow:], which the | 1903 // because our trigger is an [NSView viewWillMoveToWindow:], which the |
1481 // controller doesn't normally know about. Otherwise we don't have | 1904 // controller doesn't normally know about. Otherwise we don't have |
1482 // access to the theme before we know what window we will be on. | 1905 // access to the theme before we know what window we will be on. |
1483 - (void)updateTheme:(const ui::ThemeProvider*)themeProvider { | 1906 - (void)updateTheme:(const ui::ThemeProvider*)themeProvider { |
1484 if (!themeProvider) | 1907 if (!themeProvider) |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1559 | 1982 |
1560 // Find something like std::is_between<T>? I can't believe one doesn't exist. | 1983 // Find something like std::is_between<T>? I can't believe one doesn't exist. |
1561 static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { | 1984 static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) { |
1562 return ((value >= low) && (value <= high)); | 1985 return ((value >= low) && (value <= high)); |
1563 } | 1986 } |
1564 | 1987 |
1565 // Return the proposed drop target for a hover open button from the | 1988 // Return the proposed drop target for a hover open button from the |
1566 // given array, or nil if none. We use this for distinguishing | 1989 // given array, or nil if none. We use this for distinguishing |
1567 // between a hover-open candidate or drop-indicator draw. | 1990 // between a hover-open candidate or drop-indicator draw. |
1568 // Helper for buttonForDroppingOnAtPoint:. | 1991 // Helper for buttonForDroppingOnAtPoint:. |
| 1992 // Get UI review on "middle half" ness. |
| 1993 // http://crbug.com/36276 |
1569 - (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point | 1994 - (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point |
1570 fromArray:(NSArray*)array { | 1995 fromArray:(NSArray*)array { |
1571 // Ensure buttons are scanned left to right. | 1996 for (BookmarkButton* button in array) { |
1572 id<NSFastEnumeration> buttonsToCheck = | |
1573 cocoa_l10n_util::ShouldDoExperimentalRTLLayout() | |
1574 ? [array reverseObjectEnumerator] | |
1575 : [array objectEnumerator]; | |
1576 for (BookmarkButton* button in buttonsToCheck) { | |
1577 // Hidden buttons can overlap valid visible buttons, just ignore. | 1997 // Hidden buttons can overlap valid visible buttons, just ignore. |
1578 if ([button isHidden]) | 1998 if ([button isHidden]) |
1579 continue; | 1999 continue; |
1580 // Break early if we've gone too far. | 2000 // Break early if we've gone too far. |
1581 if ((NSMinX([button frame]) > point.x) || (![button superview])) | 2001 if ((NSMinX([button frame]) > point.x) || (![button superview])) |
1582 return nil; | 2002 return nil; |
1583 // Careful -- this only applies to the bar with horiz buttons. | 2003 // Careful -- this only applies to the bar with horiz buttons. |
1584 // Intentionally NOT using NSPointInRect() so that scrolling into | 2004 // Intentionally NOT using NSPointInRect() so that scrolling into |
1585 // a submenu doesn't cause it to be closed. | 2005 // a submenu doesn't cause it to be closed. |
1586 if (ValueInRangeInclusive(NSMinX([button frame]), | 2006 if (ValueInRangeInclusive(NSMinX([button frame]), |
(...skipping 27 matching lines...) Expand all Loading... |
1614 - (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point { | 2034 - (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point { |
1615 point = [[self view] convertPoint:point | 2035 point = [[self view] convertPoint:point |
1616 fromView:[[[self view] window] contentView]]; | 2036 fromView:[[[self view] window] contentView]]; |
1617 | 2037 |
1618 // If there's a hover button, return it if the point is within its bounds. | 2038 // If there's a hover button, return it if the point is within its bounds. |
1619 // Since the logic in -buttonForDroppingOnAtPoint:fromArray: only matches a | 2039 // Since the logic in -buttonForDroppingOnAtPoint:fromArray: only matches a |
1620 // button when the point is over the middle half, this is needed to prevent | 2040 // button when the point is over the middle half, this is needed to prevent |
1621 // the button's folder being closed if the mouse temporarily leaves the | 2041 // the button's folder being closed if the mouse temporarily leaves the |
1622 // middle half but is still within the button bounds. | 2042 // middle half but is still within the button bounds. |
1623 if (hoverButton_ && NSPointInRect(point, [hoverButton_ frame])) | 2043 if (hoverButton_ && NSPointInRect(point, [hoverButton_ frame])) |
1624 return hoverButton_.get(); | 2044 return hoverButton_.get(); |
1625 | 2045 |
1626 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point | 2046 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point |
1627 fromArray:buttons_.get()]; | 2047 fromArray:buttons_.get()]; |
1628 // One more chance -- try "Other Bookmarks" and "off the side" (if visible). | 2048 // One more chance -- try "Other Bookmarks" and "off the side" (if visible). |
1629 // This is different than BookmarkBarFolderController. | 2049 // This is different than BookmarkBarFolderController. |
1630 if (!button) { | 2050 if (!button) { |
1631 NSMutableArray* array = [NSMutableArray array]; | 2051 NSMutableArray* array = [NSMutableArray array]; |
1632 if (layout_.IsOffTheSideButtonVisible()) | 2052 if (![self offTheSideButtonIsHidden]) |
1633 [array addObject:offTheSideButton_]; | 2053 [array addObject:offTheSideButton_]; |
1634 [array addObject:otherBookmarksButton_]; | 2054 [array addObject:otherBookmarksButton_]; |
1635 button = [self buttonForDroppingOnAtPoint:point | 2055 button = [self buttonForDroppingOnAtPoint:point |
1636 fromArray:array]; | 2056 fromArray:array]; |
1637 } | 2057 } |
1638 return button; | 2058 return button; |
1639 } | 2059 } |
1640 | 2060 |
1641 // Returns the index in the model for a drag to the location given by | |
1642 // |point|. This is determined by finding the first button before the center | |
1643 // of which |point| falls, scanning front to back. Note that, currently, only | |
1644 // the x-coordinate of |point| is considered. Though not currently implemented, | |
1645 // we may check for errors, in which case this would return negative value; | |
1646 // callers should check for this. | |
1647 - (int)indexForDragToPoint:(NSPoint)point { | 2061 - (int)indexForDragToPoint:(NSPoint)point { |
| 2062 // TODO(jrg): revisit position info based on UI team feedback. |
| 2063 // dropLocation is in bar local coordinates. |
1648 NSPoint dropLocation = | 2064 NSPoint dropLocation = |
1649 [[self view] convertPoint:point | 2065 [[self view] convertPoint:point |
1650 fromView:[[[self view] window] contentView]]; | 2066 fromView:[[[self view] window] contentView]]; |
1651 | 2067 BookmarkButton* buttonToTheRightOfDraggedButton = nil; |
1652 BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); | 2068 for (BookmarkButton* button in buttons_.get()) { |
1653 for (size_t i = 0; i < layout_.VisibleButtonCount(); i++) { | |
1654 BookmarkButton* button = [buttons_ objectAtIndex:i]; | |
1655 CGFloat midpoint = NSMidX([button frame]); | 2069 CGFloat midpoint = NSMidX([button frame]); |
1656 if (isRTL ? dropLocation.x >= midpoint : dropLocation.x <= midpoint) { | 2070 if (dropLocation.x <= midpoint) { |
1657 return i; | 2071 buttonToTheRightOfDraggedButton = button; |
| 2072 break; |
1658 } | 2073 } |
1659 } | 2074 } |
1660 // No buttons left to insert the dragged button before, so it | 2075 if (buttonToTheRightOfDraggedButton) { |
1661 // goes at the end. | 2076 const BookmarkNode* afterNode = |
1662 return layout_.VisibleButtonCount(); | 2077 [buttonToTheRightOfDraggedButton bookmarkNode]; |
| 2078 DCHECK(afterNode); |
| 2079 int index = afterNode->parent()->GetIndexOf(afterNode); |
| 2080 // Make sure we don't get confused by buttons which aren't visible. |
| 2081 return std::min(index, displayedButtonCount_); |
| 2082 } |
| 2083 |
| 2084 // If nothing is to my right I am at the end! |
| 2085 return displayedButtonCount_; |
1663 } | 2086 } |
1664 | 2087 |
1665 // Informs the bar that something representing the bookmark at | |
1666 // |sourceNode| was dragged into the bar. | |
1667 // |point| is in the base coordinate system of the destination window; | |
1668 // it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be | |
1669 // made and inserted into the new location while leaving the bookmark in | |
1670 // the old location, otherwise move the bookmark by removing from its old | |
1671 // location and inserting into the new location. | |
1672 // Returns whether the drag was allowed. | |
1673 // TODO(mrossetti,jrg): Yet more duplicated code. | 2088 // TODO(mrossetti,jrg): Yet more duplicated code. |
1674 // http://crbug.com/35966 | 2089 // http://crbug.com/35966 |
1675 - (BOOL)dragBookmark:(const BookmarkNode*)sourceNode | 2090 - (BOOL)dragBookmark:(const BookmarkNode*)sourceNode |
1676 to:(NSPoint)point | 2091 to:(NSPoint)point |
1677 copy:(BOOL)copy { | 2092 copy:(BOOL)copy { |
1678 DCHECK(sourceNode); | 2093 DCHECK(sourceNode); |
1679 // Drop destination. | 2094 // Drop destination. |
1680 const BookmarkNode* destParent = NULL; | 2095 const BookmarkNode* destParent = NULL; |
1681 int destIndex = 0; | 2096 int destIndex = 0; |
1682 | 2097 |
(...skipping 26 matching lines...) Expand all Loading... |
1709 [self closeFolderAndStopTrackingMenus]; | 2124 [self closeFolderAndStopTrackingMenus]; |
1710 | 2125 |
1711 // Movement of a node triggers observers (like us) to rebuild the | 2126 // Movement of a node triggers observers (like us) to rebuild the |
1712 // bar so we don't have to do so explicitly. | 2127 // bar so we don't have to do so explicitly. |
1713 | 2128 |
1714 return YES; | 2129 return YES; |
1715 } | 2130 } |
1716 | 2131 |
1717 - (void)draggingEnded:(id<NSDraggingInfo>)info { | 2132 - (void)draggingEnded:(id<NSDraggingInfo>)info { |
1718 [self closeFolderAndStopTrackingMenus]; | 2133 [self closeFolderAndStopTrackingMenus]; |
1719 layout_ = {}; // Force layout. | 2134 [[BookmarkButton draggedButton] setHidden:NO]; |
1720 [self rebuildLayoutWithAnimated:YES]; | 2135 [self resetAllButtonPositionsWithAnimation:YES]; |
1721 } | 2136 } |
1722 | 2137 |
1723 // Set insertionPos_ and hasInsertionPos_, and make insertion space for a | 2138 // Set insertionPos_ and hasInsertionPos_, and make insertion space for a |
1724 // hypothetical drop with the new button having a left edge of |where|. | 2139 // hypothetical drop with the new button having a left edge of |where|. |
| 2140 // Gets called only by our view. |
1725 - (void)setDropInsertionPos:(CGFloat)where { | 2141 - (void)setDropInsertionPos:(CGFloat)where { |
1726 if (hasInsertionPos_ && where == insertionPos_) { | 2142 if (!hasInsertionPos_ || where != insertionPos_) { |
1727 return; | 2143 insertionPos_ = where; |
1728 } | 2144 hasInsertionPos_ = YES; |
1729 insertionPos_ = where; | 2145 CGFloat left; |
1730 hasInsertionPos_ = YES; | 2146 if (![supervisedBookmarksButton_ isHidden]) { |
1731 CGFloat paddingWidth = bookmarks::kDefaultBookmarkWidth; | 2147 left = NSMaxX([supervisedBookmarksButton_ frame]) + |
1732 BookmarkButton* draggedButton = [BookmarkButton draggedButton]; | 2148 bookmarks::kBookmarkHorizontalPadding; |
1733 BOOL draggedButtonIsOnBar = NO; | 2149 } else if (![managedBookmarksButton_ isHidden]) { |
1734 int64_t draggedButtonNodeId; | 2150 left = NSMaxX([managedBookmarksButton_ frame]) + |
1735 CGFloat draggedButtonOffset; | 2151 bookmarks::kBookmarkHorizontalPadding; |
1736 if (draggedButton) { | 2152 } else if (![appsPageShortcutButton_ isHidden]) { |
1737 paddingWidth = std::min(bookmarks::kDefaultBookmarkWidth, | 2153 left = NSMaxX([appsPageShortcutButton_ frame]) + |
1738 NSWidth([draggedButton frame])); | 2154 bookmarks::kBookmarkHorizontalPadding; |
1739 draggedButtonNodeId = [draggedButton bookmarkNode]->id(); | 2155 } else { |
1740 auto offsetIt = layout_.button_offsets.find(draggedButtonNodeId); | 2156 left = bookmarks::kBookmarkLeftMargin; |
1741 if (offsetIt != layout_.button_offsets.end()) { | |
1742 draggedButtonIsOnBar = YES; | |
1743 draggedButtonOffset = (*offsetIt).second; | |
1744 } | 2157 } |
1745 } | 2158 CGFloat paddingWidth = bookmarks::kDefaultBookmarkWidth; |
1746 paddingWidth += bookmarks::kBookmarkHorizontalPadding; | 2159 BookmarkButton* draggedButton = [BookmarkButton draggedButton]; |
1747 BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); | 2160 if (draggedButton) { |
1748 | 2161 paddingWidth = std::min(bookmarks::kDefaultBookmarkWidth, |
1749 // If the button being dragged is not currently on the bar | 2162 NSWidth([draggedButton frame])); |
1750 // (for example, a drag from the URL bar, a link on the desktop, | 2163 } |
1751 // a button inside a menu, etc.), buttons in front of the drag position | 2164 // Put all the buttons where they belong, with all buttons to the right |
1752 // (to the right in LTR, to the left in RTL), should make room for it. | 2165 // of the insertion point shuffling right to make space for it. |
1753 // Otherwise: | 2166 [NSAnimationContext beginGrouping]; |
1754 // If a given button was to the left of the dragged button's original | 2167 [[NSAnimationContext currentContext] |
1755 // position, but is to the right of the drag position, or | 2168 setDuration:kDragAndDropAnimationDuration]; |
1756 // if it was to the right of the dragged button's original position and | 2169 for (NSButton* button in buttons_.get()) { |
1757 // is to the left of the drag position, make room. | 2170 // Hidden buttons get no space. |
1758 // TODO(lgrey): Extract ScopedNSAnimationContextGroup | 2171 if ([button isHidden]) |
1759 // from the tab strip controller and use it on all of these. | |
1760 [NSAnimationContext beginGrouping]; | |
1761 [[NSAnimationContext currentContext] | |
1762 setDuration:kDragAndDropAnimationDuration]; | |
1763 | |
1764 for (BookmarkButton* button in buttons_.get()) { | |
1765 CGRect buttonFrame = [button frame]; | |
1766 int64_t nodeId = [button bookmarkNode]->id(); | |
1767 CGFloat offset = layout_.button_offsets[nodeId]; | |
1768 CGFloat buttonEdge = isRTL ? NSWidth([buttonView_ frame]) - offset : offset; | |
1769 | |
1770 if (draggedButtonIsOnBar) { | |
1771 if (nodeId == draggedButtonNodeId) | |
1772 continue; | 2172 continue; |
1773 BOOL wasBefore = offset < draggedButtonOffset; | 2173 NSRect buttonFrame = [button frame]; |
1774 BOOL isBefore = isRTL ? buttonEdge > where : buttonEdge < where; | 2174 buttonFrame.origin.x = left; |
1775 if (isBefore && !wasBefore) { | 2175 // Update "left" for next time around. |
1776 offset -= paddingWidth; | 2176 left += buttonFrame.size.width; |
1777 } else if (!isBefore && wasBefore) { | 2177 if (left > insertionPos_) |
1778 offset += paddingWidth; | 2178 buttonFrame.origin.x += paddingWidth; |
1779 } | 2179 left += bookmarks::kBookmarkHorizontalPadding; |
1780 } else { | 2180 if (innerContentAnimationsEnabled_) |
1781 if (isRTL ? (where > buttonEdge) | 2181 [[button animator] setFrame:buttonFrame]; |
1782 : (where < offset + NSWidth(buttonFrame))) { | 2182 else |
1783 offset += paddingWidth; | 2183 [button setFrame:buttonFrame]; |
1784 } | |
1785 } | 2184 } |
1786 | 2185 [NSAnimationContext endGrouping]; |
1787 [self applyXOffset:offset | |
1788 toButton:button | |
1789 animated:innerContentAnimationsEnabled_]; | |
1790 } | |
1791 | |
1792 [NSAnimationContext endGrouping]; | |
1793 } | |
1794 | |
1795 - (BookmarkBarLayout)layoutFromCurrentState { | |
1796 BookmarkBarLayout layout = {}; | |
1797 | |
1798 const BookmarkNode* node = bookmarkModel_->bookmark_bar_node(); | |
1799 CGFloat viewWidth = NSWidth([buttonView_ frame]); | |
1800 CGFloat xOffset = bookmarks::kBookmarkLeftMargin; | |
1801 CGFloat maxX = viewWidth - bookmarks::kBookmarkHorizontalPadding; | |
1802 | |
1803 layout.visible_elements = bookmarks::kVisibleElementsMaskNone; | |
1804 layout.max_x = maxX; | |
1805 | |
1806 // Lay out "extra" buttons (apps, managed, supervised, "Other"). | |
1807 if (chrome::ShouldShowAppsShortcutInBookmarkBar(browser_->profile())) { | |
1808 layout.visible_elements |= bookmarks::kVisibleElementsMaskAppsButton; | |
1809 layout.apps_button_offset = xOffset; | |
1810 xOffset += NSWidth([appsPageShortcutButton_ frame]) + | |
1811 bookmarks::kBookmarkHorizontalPadding; | |
1812 } | |
1813 if (!managedBookmarkService_->managed_node()->empty()) { | |
1814 layout.visible_elements |= | |
1815 bookmarks::kVisibleElementsMaskManagedBookmarksButton; | |
1816 layout.managed_bookmarks_button_offset = xOffset; | |
1817 xOffset += NSWidth([managedBookmarksButton_ frame]) + | |
1818 bookmarks::kBookmarkHorizontalPadding; | |
1819 } | |
1820 if (!managedBookmarkService_->supervised_node()->empty()) { | |
1821 layout.visible_elements |= | |
1822 bookmarks::kVisibleElementsMaskSupervisedBookmarksButton; | |
1823 layout.supervised_bookmarks_button_offset = xOffset; | |
1824 xOffset += NSWidth([supervisedBookmarksButton_ frame]) + | |
1825 bookmarks::kBookmarkHorizontalPadding; | |
1826 } | |
1827 if (!bookmarkModel_->other_node()->empty()) { | |
1828 layout.visible_elements |= | |
1829 bookmarks::kVisibleElementsMaskOtherBookmarksButton; | |
1830 maxX -= NSWidth([otherBookmarksButton_ frame]); | |
1831 layout.other_bookmarks_button_offset = maxX; | |
1832 } | |
1833 | |
1834 // Lay out empty state ("no items" label, import bookmarks button.) | |
1835 if (node->empty()) { | |
1836 CGFloat roomForTextField = | |
1837 maxX - xOffset + bookmarks::kInitialNoItemTextFieldXOrigin; | |
1838 if (roomForTextField >= kNoItemElementMinWidth) { | |
1839 layout.visible_elements |= bookmarks::kVisibleElementsMaskNoItemTextField; | |
1840 xOffset += bookmarks::kInitialNoItemTextFieldXOrigin; | |
1841 layout.no_item_textfield_offset = xOffset; | |
1842 layout.no_item_textfield_width = | |
1843 std::min(maxX - xOffset, originalNoItemTextFieldWidth_); | |
1844 xOffset += | |
1845 layout.no_item_textfield_width + originalNoItemInterelementPadding_; | |
1846 | |
1847 // Does the "import bookmarks" button fit? | |
1848 if (maxX - xOffset >= kNoItemElementMinWidth) { | |
1849 layout.visible_elements |= | |
1850 bookmarks::kVisibleElementsMaskImportBookmarksButton; | |
1851 layout.import_bookmarks_button_offset = xOffset; | |
1852 layout.import_bookmarks_button_width = | |
1853 std::min(maxX - xOffset, originalImportBookmarksButtonWidth_); | |
1854 } | |
1855 } | |
1856 } else { | |
1857 // Lay out bookmark buttons and "off-the-side" chevron. | |
1858 CGFloat offTheSideButtonWidth = NSWidth([offTheSideButton_ frame]); | |
1859 int buttonCount = node->child_count(); | |
1860 for (int i = 0; i < buttonCount; i++) { | |
1861 const BookmarkNode* buttonNode = node->GetChild(i); | |
1862 CGFloat widthOfButton = [self widthOfButtonForNode:buttonNode]; | |
1863 // If it's the last button, we just need to ensure that it can fit. | |
1864 // If not, we need to be able to fit both it and the chevron. | |
1865 CGFloat widthToCheck = i == buttonCount - 1 | |
1866 ? widthOfButton | |
1867 : widthOfButton + offTheSideButtonWidth; | |
1868 if (xOffset + widthToCheck > maxX) { | |
1869 layout.visible_elements |= | |
1870 bookmarks::kVisibleElementsMaskOffTheSideButton; | |
1871 layout.off_the_side_button_offset = maxX - offTheSideButtonWidth; | |
1872 break; | |
1873 } | |
1874 layout.button_offsets.insert({buttonNode->id(), xOffset}); | |
1875 xOffset += widthOfButton + bookmarks::kBookmarkHorizontalPadding; | |
1876 } | |
1877 } | |
1878 return layout; | |
1879 } | |
1880 | |
1881 - (void)rebuildLayoutWithAnimated:(BOOL)animated { | |
1882 if (!bookmarkModel_->loaded()) | |
1883 return; | |
1884 | |
1885 BookmarkBarLayout layout = [self layoutFromCurrentState]; | |
1886 if (layout_ != layout) { | |
1887 layout_ = std::move(layout); | |
1888 [self applyLayout:layout_ animated:animated]; | |
1889 } | 2186 } |
1890 } | 2187 } |
1891 | 2188 |
1892 - (void)applyLayout:(const BookmarkBarLayout&)layout animated:(BOOL)animated { | 2189 // Put all visible bookmark bar buttons in their normal locations, either with |
1893 if (!bookmarkModel_->loaded()) | 2190 // or without animation according to the |animate| flag. |
1894 return; | 2191 // This is generally useful, so is called from various places internally. |
| 2192 - (void)resetAllButtonPositionsWithAnimation:(BOOL)animate { |
1895 | 2193 |
1896 if (folderController_) | 2194 // Position the apps bookmark if needed. |
1897 [self closeAllBookmarkFolders]; | 2195 CGFloat left = bookmarks::kBookmarkLeftMargin; |
1898 [self stopPulsingBookmarkNode]; | 2196 if (![appsPageShortcutButton_ isHidden]) { |
1899 | 2197 int xOffset = bookmarks::kBookmarkLeftMargin - |
1900 // Hide or show "extra" buttons and position if necessary. | 2198 bookmarks::kBookmarkHorizontalPadding; |
1901 [self applyXOffset:layout.apps_button_offset | 2199 NSRect frame = |
1902 toButton:appsPageShortcutButton_ | 2200 [self frameForBookmarkButtonFromCell:[appsPageShortcutButton_ cell] |
1903 animated:NO]; | 2201 xOffset:&xOffset]; |
1904 [appsPageShortcutButton_ setHidden:!layout.IsAppsButtonVisible()]; | 2202 [appsPageShortcutButton_ setFrame:frame]; |
1905 | 2203 left = xOffset + bookmarks::kBookmarkHorizontalPadding; |
1906 [self applyXOffset:layout.managed_bookmarks_button_offset | |
1907 toButton:managedBookmarksButton_ | |
1908 animated:NO]; | |
1909 [managedBookmarksButton_ setHidden:!layout.IsManagedBookmarksButtonVisible()]; | |
1910 | |
1911 [self applyXOffset:layout.supervised_bookmarks_button_offset | |
1912 toButton:supervisedBookmarksButton_ | |
1913 animated:NO]; | |
1914 [supervisedBookmarksButton_ | |
1915 setHidden:!layout.IsSupervisedBookmarksButtonVisible()]; | |
1916 | |
1917 [self applyXOffset:layout.other_bookmarks_button_offset | |
1918 toButton:otherBookmarksButton_ | |
1919 animated:NO]; | |
1920 [otherBookmarksButton_ setHidden:!layout.IsOtherBookmarksButtonVisible()]; | |
1921 | |
1922 [self applyXOffset:layout.off_the_side_button_offset | |
1923 toButton:offTheSideButton_ | |
1924 animated:NO]; | |
1925 [offTheSideButton_ setHidden:!layout.IsOffTheSideButtonVisible()]; | |
1926 if (layout.IsOffTheSideButtonVisible()) { | |
1927 [[offTheSideButton_ cell] | |
1928 setStartingChildIndex:layout_.VisibleButtonCount()]; | |
1929 } | 2204 } |
1930 | 2205 |
1931 // Hide or show empty state and position if necessary. | 2206 // Position the managed bookmarks folder if needed. |
1932 [[buttonView_ noItemTextField] setHidden:!layout.IsNoItemTextFieldVisible()]; | 2207 if (![managedBookmarksButton_ isHidden]) { |
1933 [[buttonView_ importBookmarksButton] | 2208 int xOffset = left; |
1934 setHidden:!layout.IsImportBookmarksButtonVisible()]; | 2209 NSRect frame = |
1935 | 2210 [self frameForBookmarkButtonFromCell:[managedBookmarksButton_ cell] |
1936 if (layout.IsNoItemTextFieldVisible()) { | 2211 xOffset:&xOffset]; |
1937 NSTextField* noItemTextField = [buttonView_ noItemTextField]; | 2212 [managedBookmarksButton_ setFrame:frame]; |
1938 [noItemTextField setHidden:NO]; | 2213 left = xOffset + bookmarks::kBookmarkHorizontalPadding; |
1939 NSRect textFieldFrame = [noItemTextField frame]; | |
1940 textFieldFrame.size.width = layout.no_item_textfield_width; | |
1941 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) { | |
1942 textFieldFrame.origin.x = NSWidth([buttonView_ frame]) - | |
1943 layout.no_item_textfield_offset - | |
1944 layout.no_item_textfield_width; | |
1945 } else { | |
1946 textFieldFrame.origin.x = layout.no_item_textfield_offset; | |
1947 } | |
1948 [noItemTextField setFrame:textFieldFrame]; | |
1949 | |
1950 if (layout.IsImportBookmarksButtonVisible()) { | |
1951 NSButton* importBookmarksButton = [buttonView_ importBookmarksButton]; | |
1952 NSRect buttonFrame = [importBookmarksButton frame]; | |
1953 buttonFrame.size.width = layout.import_bookmarks_button_width; | |
1954 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) { | |
1955 buttonFrame.origin.x = NSWidth([buttonView_ frame]) - | |
1956 layout.import_bookmarks_button_offset - | |
1957 layout.import_bookmarks_button_width; | |
1958 } else { | |
1959 buttonFrame.origin.x = layout.import_bookmarks_button_offset; | |
1960 } | |
1961 [importBookmarksButton setFrame:buttonFrame]; | |
1962 } | |
1963 } | |
1964 // 1) Hide all buttons initially. | |
1965 // 2) Show all buttons in the layout. | |
1966 // 3) Remove any buttons that are still hidden (so: not in the layout) | |
1967 // from the node ID -> button map and add them to the reuse pool if | |
1968 // there's room. | |
1969 for (BookmarkButton* button in buttons_.get()) { | |
1970 [button setHidden:YES]; | |
1971 } | |
1972 [buttons_ removeAllObjects]; | |
1973 | |
1974 const BookmarkNode* parentNode = bookmarkModel_->bookmark_bar_node(); | |
1975 for (size_t i = 0; i < layout.VisibleButtonCount(); i++) { | |
1976 const BookmarkNode* node = parentNode->GetChild(i); | |
1977 DCHECK(node); | |
1978 BookmarkButton* button = [self buttonForNode:node]; | |
1979 CGFloat offset = layout.button_offsets.at(node->id()); | |
1980 [self applyXOffset:offset | |
1981 toButton:button | |
1982 animated:animated && innerContentAnimationsEnabled_]; | |
1983 [buttons_ addObject:button]; | |
1984 [button setHidden:NO]; | |
1985 } | 2214 } |
1986 | 2215 |
1987 for (auto& item : nodeIdToButtonMap_) { | 2216 // Position the supervised bookmarks folder if needed. |
1988 if ([item.second isHidden]) { | 2217 if (![supervisedBookmarksButton_ isHidden]) { |
1989 if ([unusedButtonPool_ count] < kMaxReusePoolSize) { | 2218 int xOffset = left; |
1990 BookmarkButton* button = item.second.get(); | 2219 NSRect frame = |
1991 // Dragged buttons unhide themselves, so position it off-screen | 2220 [self frameForBookmarkButtonFromCell:[supervisedBookmarksButton_ cell] |
1992 // while it's in the reuse pool. | 2221 xOffset:&xOffset]; |
1993 CGRect buttonFrame = [button frame]; | 2222 [supervisedBookmarksButton_ setFrame:frame]; |
1994 buttonFrame.origin.x = -10000; | 2223 left = xOffset + bookmarks::kBookmarkHorizontalPadding; |
1995 [button setFrame:buttonFrame]; | |
1996 [unusedButtonPool_ addObject:button]; | |
1997 } else { | |
1998 [item.second setDelegate:nil]; | |
1999 [item.second removeFromSuperview]; | |
2000 } | |
2001 | |
2002 nodeIdToButtonMap_.erase(item.first); | |
2003 } | |
2004 } | |
2005 const ui::ThemeProvider* themeProvider = [[[self view] window] themeProvider]; | |
2006 [self updateTheme:themeProvider]; | |
2007 } | |
2008 | |
2009 - (void)applyXOffset:(CGFloat)offset | |
2010 toButton:(BookmarkButton*)button | |
2011 animated:(BOOL)animated { | |
2012 CGRect frame = [button frame]; | |
2013 BOOL wasOffscreen = frame.origin.x < -200; | |
2014 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) { | |
2015 frame.origin.x = NSWidth([buttonView_ frame]) - offset - NSWidth(frame); | |
2016 } else { | |
2017 frame.origin.x = offset; | |
2018 } | 2224 } |
2019 | 2225 |
2020 // Buttons fresh from the reuse pool are kept offscreen. Animation should | 2226 animate &= innerContentAnimationsEnabled_; |
2021 // be disabled for them so they don't slide in. | 2227 |
2022 if (animated && !wasOffscreen) { | 2228 for (NSButton* button in buttons_.get()) { |
2023 [[button animator] setFrame:frame]; | 2229 // Hidden buttons get no space. |
2024 } else { | 2230 if ([button isHidden]) |
2025 [button setFrame:frame]; | 2231 continue; |
| 2232 NSRect buttonFrame = [button frame]; |
| 2233 buttonFrame.origin.x = left; |
| 2234 left += buttonFrame.size.width + bookmarks::kBookmarkHorizontalPadding; |
| 2235 if (animate) |
| 2236 [[button animator] setFrame:buttonFrame]; |
| 2237 else |
| 2238 [button setFrame:buttonFrame]; |
2026 } | 2239 } |
2027 } | 2240 } |
2028 | 2241 |
2029 - (CGFloat)widthOfButtonForNode:(const BookmarkNode*)node { | |
2030 // TODO(lgrey): Can we get this information without an actual image? | |
2031 NSImage* image = [self faviconForNode:node forADarkTheme:NO]; | |
2032 CGFloat width = [BookmarkButtonCell cellWidthForNode:node image:image]; | |
2033 return std::min(width, bookmarks::kDefaultBookmarkWidth); | |
2034 } | |
2035 | |
2036 // Clear insertion flag, remove insertion space and put all visible bookmark | 2242 // Clear insertion flag, remove insertion space and put all visible bookmark |
2037 // bar buttons in their normal locations. | 2243 // bar buttons in their normal locations. |
2038 // Gets called only by our view. | 2244 // Gets called only by our view. |
2039 // TODO(lgrey): Is there a sane way to dedupe this with |setDropInsertionPos:|? | |
2040 - (void)clearDropInsertionPos { | 2245 - (void)clearDropInsertionPos { |
2041 if (!hasInsertionPos_) { | 2246 if (hasInsertionPos_) { |
2042 return; | 2247 hasInsertionPos_ = NO; |
| 2248 [self resetAllButtonPositionsWithAnimation:YES]; |
2043 } | 2249 } |
2044 hasInsertionPos_ = NO; | |
2045 BookmarkButton* draggedButton = [BookmarkButton draggedButton]; | |
2046 if (!draggedButton) { | |
2047 [self applyLayout:layout_ animated:YES]; | |
2048 return; | |
2049 } | |
2050 int64_t draggedButtonNodeId = [draggedButton bookmarkNode]->id(); | |
2051 if (layout_.button_offsets.find(draggedButtonNodeId) == | |
2052 layout_.button_offsets.end()) { | |
2053 [self applyLayout:layout_ animated:YES]; | |
2054 return; | |
2055 } | |
2056 // The dragged button came from the bar, but is being dragged outside | |
2057 // of it now, so the rest of the buttons should be laid out as if it | |
2058 // were removed. | |
2059 CGFloat draggedButtonOffset = layout_.button_offsets[draggedButtonNodeId]; | |
2060 CGFloat spaceForDraggedButton = | |
2061 NSWidth([draggedButton frame]) + bookmarks::kBookmarkHorizontalPadding; | |
2062 [NSAnimationContext beginGrouping]; | |
2063 [[NSAnimationContext currentContext] | |
2064 setDuration:kDragAndDropAnimationDuration]; | |
2065 | |
2066 for (BookmarkButton* button in buttons_.get()) { | |
2067 int64_t nodeId = [button bookmarkNode]->id(); | |
2068 CGFloat offset = layout_.button_offsets[nodeId]; | |
2069 | |
2070 if (nodeId == draggedButtonNodeId) | |
2071 continue; | |
2072 | |
2073 if (offset > draggedButtonOffset) { | |
2074 offset -= spaceForDraggedButton; | |
2075 [self applyXOffset:offset | |
2076 toButton:button | |
2077 animated:innerContentAnimationsEnabled_]; | |
2078 } | |
2079 } | |
2080 | |
2081 [NSAnimationContext endGrouping]; | |
2082 } | 2250 } |
2083 | 2251 |
2084 #pragma mark Bridge Notification Handlers | 2252 #pragma mark Bridge Notification Handlers |
2085 | 2253 |
| 2254 // TODO(jrg): for now this is brute force. |
2086 - (void)loaded:(BookmarkModel*)model { | 2255 - (void)loaded:(BookmarkModel*)model { |
2087 DCHECK(model == bookmarkModel_); | 2256 DCHECK(model == bookmarkModel_); |
2088 if (!model->loaded()) | 2257 if (!model->loaded()) |
2089 return; | 2258 return; |
2090 // Make sure there are no stale pointers in the pasteboard. This | |
2091 // can be important if a bookmark is deleted (via bookmark sync) | |
2092 // while in the middle of a drag. The "drag completed" code | |
2093 // (e.g. [BookmarkBarView performDragOperationForBookmarkButton:]) is | |
2094 // careful enough to bail if there is no data found at "drop" time. | |
2095 [[NSPasteboard pasteboardWithName:NSDragPboard] clearContents]; | |
2096 | |
2097 if (!didCreateExtraButtons_) { | |
2098 [self createExtraButtons]; | |
2099 } | |
2100 | 2259 |
2101 // If this is a rebuild request while we have a folder open, close it. | 2260 // If this is a rebuild request while we have a folder open, close it. |
| 2261 // TODO(mrossetti): Eliminate the need for this because it causes the folder |
| 2262 // menu to disappear after a cut/copy/paste/delete change. |
| 2263 // See: http://crbug.com/36614 |
2102 if (folderController_) | 2264 if (folderController_) |
2103 [self closeAllBookmarkFolders]; | 2265 [self closeAllBookmarkFolders]; |
2104 [self rebuildLayoutWithAnimated:NO]; | 2266 |
| 2267 // Brute force nuke and build. |
| 2268 savedFrameWidth_ = NSWidth([[self view] frame]); |
| 2269 const BookmarkNode* node = model->bookmark_bar_node(); |
| 2270 [self clearBookmarkBar]; |
| 2271 [self createAppsPageShortcutButton]; |
| 2272 [self createManagedBookmarksButton]; |
| 2273 [self createSupervisedBookmarksButton]; |
| 2274 [self addNodesToButtonList:node]; |
| 2275 [self createOtherBookmarksButton]; |
| 2276 [self updateTheme:[[[self view] window] themeProvider]]; |
| 2277 [self positionRightSideButtons]; |
| 2278 [self addButtonsToView]; |
| 2279 [self configureOffTheSideButtonContentsAndVisibility]; |
| 2280 [self reconfigureBookmarkBar]; |
2105 } | 2281 } |
| 2282 |
2106 - (void)nodeAdded:(BookmarkModel*)model | 2283 - (void)nodeAdded:(BookmarkModel*)model |
2107 parent:(const BookmarkNode*)newParent index:(int)newIndex { | 2284 parent:(const BookmarkNode*)newParent index:(int)newIndex { |
2108 // If a context menu is open, close it. | 2285 // If a context menu is open, close it. |
2109 [self cancelMenuTracking]; | 2286 [self cancelMenuTracking]; |
2110 | 2287 |
2111 const BookmarkNode* newNode = newParent->GetChild(newIndex); | 2288 const BookmarkNode* newNode = newParent->GetChild(newIndex); |
2112 id<BookmarkButtonControllerProtocol> newController = | 2289 id<BookmarkButtonControllerProtocol> newController = |
2113 [self controllerForNode:newParent]; | 2290 [self controllerForNode:newParent]; |
2114 [newController addButtonForNode:newNode atIndex:newIndex]; | 2291 [newController addButtonForNode:newNode atIndex:newIndex]; |
2115 [self rebuildLayoutWithAnimated:NO]; | 2292 // If we go from 0 --> 1 bookmarks we may need to hide the |
| 2293 // "bookmarks go here" text container. |
| 2294 [self showOrHideNoItemContainerForNode:model->bookmark_bar_node()]; |
| 2295 // Cope with chevron or "Other Bookmarks" buttons possibly changing state. |
| 2296 [self reconfigureBookmarkBar]; |
2116 } | 2297 } |
2117 | 2298 |
2118 // TODO(jrg): for now this is brute force. | 2299 // TODO(jrg): for now this is brute force. |
2119 - (void)nodeChanged:(BookmarkModel*)model | 2300 - (void)nodeChanged:(BookmarkModel*)model |
2120 node:(const BookmarkNode*)node { | 2301 node:(const BookmarkNode*)node { |
2121 [self loaded:model]; | 2302 [self loaded:model]; |
2122 } | 2303 } |
2123 | 2304 |
2124 - (void)nodeMoved:(BookmarkModel*)model | 2305 - (void)nodeMoved:(BookmarkModel*)model |
2125 oldParent:(const BookmarkNode*)oldParent oldIndex:(int)oldIndex | 2306 oldParent:(const BookmarkNode*)oldParent oldIndex:(int)oldIndex |
2126 newParent:(const BookmarkNode*)newParent newIndex:(int)newIndex { | 2307 newParent:(const BookmarkNode*)newParent newIndex:(int)newIndex { |
2127 const BookmarkNode* movedNode = newParent->GetChild(newIndex); | 2308 const BookmarkNode* movedNode = newParent->GetChild(newIndex); |
2128 id<BookmarkButtonControllerProtocol> oldController = | 2309 id<BookmarkButtonControllerProtocol> oldController = |
2129 [self controllerForNode:oldParent]; | 2310 [self controllerForNode:oldParent]; |
2130 id<BookmarkButtonControllerProtocol> newController = | 2311 id<BookmarkButtonControllerProtocol> newController = |
2131 [self controllerForNode:newParent]; | 2312 [self controllerForNode:newParent]; |
2132 if (newController == oldController) { | 2313 if (newController == oldController) { |
2133 [oldController moveButtonFromIndex:oldIndex toIndex:newIndex]; | 2314 [oldController moveButtonFromIndex:oldIndex toIndex:newIndex]; |
2134 } else { | 2315 } else { |
2135 [oldController removeButton:oldIndex animate:NO]; | 2316 [oldController removeButton:oldIndex animate:NO]; |
2136 [newController addButtonForNode:movedNode atIndex:newIndex]; | 2317 [newController addButtonForNode:movedNode atIndex:newIndex]; |
2137 } | 2318 } |
2138 [self rebuildLayoutWithAnimated:NO]; | 2319 // If the bar is one of the parents we may need to update the visibility |
| 2320 // of the "bookmarks go here" presentation. |
| 2321 [self showOrHideNoItemContainerForNode:model->bookmark_bar_node()]; |
| 2322 // Cope with chevron or "Other Bookmarks" buttons possibly changing state. |
| 2323 [self reconfigureBookmarkBar]; |
2139 } | 2324 } |
2140 | 2325 |
2141 - (void)nodeRemoved:(BookmarkModel*)model | 2326 - (void)nodeRemoved:(BookmarkModel*)model |
2142 parent:(const BookmarkNode*)oldParent index:(int)index { | 2327 parent:(const BookmarkNode*)oldParent index:(int)index { |
2143 // If a context menu is open, close it. | 2328 // If a context menu is open, close it. |
2144 [self cancelMenuTracking]; | 2329 [self cancelMenuTracking]; |
2145 | 2330 |
2146 // Locate the parent node. The parent may not be showing, in which case | 2331 // Locate the parent node. The parent may not be showing, in which case |
2147 // we do nothing. | 2332 // we do nothing. |
2148 id<BookmarkButtonControllerProtocol> parentController = | 2333 id<BookmarkButtonControllerProtocol> parentController = |
2149 [self controllerForNode:oldParent]; | 2334 [self controllerForNode:oldParent]; |
2150 [parentController removeButton:index animate:YES]; | 2335 [parentController removeButton:index animate:YES]; |
2151 [self rebuildLayoutWithAnimated:NO]; | 2336 // If we go from 1 --> 0 bookmarks we may need to show the |
| 2337 // "bookmarks go here" text container. |
| 2338 [self showOrHideNoItemContainerForNode:model->bookmark_bar_node()]; |
| 2339 // If we deleted the only item on the "off the side" menu we no |
| 2340 // longer need to show it. |
| 2341 [self reconfigureBookmarkBar]; |
2152 } | 2342 } |
2153 | 2343 |
| 2344 // TODO(jrg): linear searching is bad. |
| 2345 // Need a BookmarkNode-->NSCell mapping. |
| 2346 // |
2154 // TODO(jrg): if the bookmark bar is open on launch, we see the | 2347 // TODO(jrg): if the bookmark bar is open on launch, we see the |
2155 // buttons all placed, then "scooted over" as the favicons load. If | 2348 // buttons all placed, then "scooted over" as the favicons load. If |
2156 // this looks bad I may need to change widthForBookmarkButtonCell to | 2349 // this looks bad I may need to change widthForBookmarkButtonCell to |
2157 // add space for an image even if not there on the assumption that | 2350 // add space for an image even if not there on the assumption that |
2158 // favicons will eventually load. | 2351 // favicons will eventually load. |
2159 - (void)nodeFaviconLoaded:(BookmarkModel*)model | 2352 - (void)nodeFaviconLoaded:(BookmarkModel*)model |
2160 node:(const BookmarkNode*)node { | 2353 node:(const BookmarkNode*)node { |
2161 auto buttonIt = nodeIdToButtonMap_.find(node->id()); | 2354 for (BookmarkButton* button in buttons_.get()) { |
2162 if (buttonIt != nodeIdToButtonMap_.end()) { | 2355 const BookmarkNode* cellnode = [button bookmarkNode]; |
2163 BookmarkButton* button = (*buttonIt).second; | 2356 if (cellnode == node) { |
2164 BOOL darkTheme = [[[self view] window] hasDarkTheme]; | 2357 BOOL darkTheme = [[[self view] window] hasDarkTheme]; |
2165 NSImage* theImage = [self faviconForNode:node forADarkTheme:darkTheme]; | 2358 NSImage* theImage = [self faviconForNode:node forADarkTheme:darkTheme]; |
2166 [[button cell] setBookmarkCellText:[button title] image:theImage]; | 2359 [[button cell] setBookmarkCellText:[button title] |
| 2360 image:theImage]; |
| 2361 // Adding an image means we might need more room for the |
| 2362 // bookmark. Test for it by growing the button (if needed) |
| 2363 // and shifting everything else over. |
| 2364 [self checkForBookmarkButtonGrowth:button]; |
| 2365 return; |
| 2366 } |
2167 } | 2367 } |
2168 [self rebuildLayoutWithAnimated:NO]; | 2368 |
2169 if (folderController_) | 2369 if (folderController_) |
2170 [folderController_ faviconLoadedForNode:node]; | 2370 [folderController_ faviconLoadedForNode:node]; |
2171 } | 2371 } |
2172 | 2372 |
2173 // TODO(jrg): for now this is brute force. | 2373 // TODO(jrg): for now this is brute force. |
2174 - (void)nodeChildrenReordered:(BookmarkModel*)model | 2374 - (void)nodeChildrenReordered:(BookmarkModel*)model |
2175 node:(const BookmarkNode*)node { | 2375 node:(const BookmarkNode*)node { |
2176 [self loaded:model]; | 2376 [self loaded:model]; |
2177 } | 2377 } |
2178 | 2378 |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2302 - (void)didDragBookmarkToTrash:(BookmarkButton*)button { | 2502 - (void)didDragBookmarkToTrash:(BookmarkButton*)button { |
2303 if ([self canDragBookmarkButtonToTrash:button]) { | 2503 if ([self canDragBookmarkButtonToTrash:button]) { |
2304 const BookmarkNode* node = [button bookmarkNode]; | 2504 const BookmarkNode* node = [button bookmarkNode]; |
2305 if (node) | 2505 if (node) |
2306 bookmarkModel_->Remove(node); | 2506 bookmarkModel_->Remove(node); |
2307 } | 2507 } |
2308 } | 2508 } |
2309 | 2509 |
2310 - (void)bookmarkDragDidEnd:(BookmarkButton*)button | 2510 - (void)bookmarkDragDidEnd:(BookmarkButton*)button |
2311 operation:(NSDragOperation)operation { | 2511 operation:(NSDragOperation)operation { |
2312 [self rebuildLayoutWithAnimated:YES]; | 2512 [button setHidden:NO]; |
| 2513 [self resetAllButtonPositionsWithAnimation:YES]; |
2313 } | 2514 } |
2314 | 2515 |
2315 | 2516 |
2316 #pragma mark BookmarkButtonControllerProtocol | 2517 #pragma mark BookmarkButtonControllerProtocol |
2317 | 2518 |
2318 // Close all bookmark folders. "Folder" here is the fake menu for | 2519 // Close all bookmark folders. "Folder" here is the fake menu for |
2319 // bookmark folders, not a button context menu. | 2520 // bookmark folders, not a button context menu. |
2320 - (void)closeAllBookmarkFolders { | 2521 - (void)closeAllBookmarkFolders { |
2321 [self watchForExitEvent:NO]; | 2522 [self watchForExitEvent:NO]; |
2322 | 2523 |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2462 // Return YES if we should show the drop indicator, else NO. | 2663 // Return YES if we should show the drop indicator, else NO. |
2463 - (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point { | 2664 - (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point { |
2464 return ![self buttonForDroppingOnAtPoint:point]; | 2665 return ![self buttonForDroppingOnAtPoint:point]; |
2465 } | 2666 } |
2466 | 2667 |
2467 // Return the x position for a drop indicator. | 2668 // Return the x position for a drop indicator. |
2468 - (CGFloat)indicatorPosForDragToPoint:(NSPoint)point { | 2669 - (CGFloat)indicatorPosForDragToPoint:(NSPoint)point { |
2469 CGFloat x = 0; | 2670 CGFloat x = 0; |
2470 CGFloat halfHorizontalPadding = 0.5 * bookmarks::kBookmarkHorizontalPadding; | 2671 CGFloat halfHorizontalPadding = 0.5 * bookmarks::kBookmarkHorizontalPadding; |
2471 int destIndex = [self indexForDragToPoint:point]; | 2672 int destIndex = [self indexForDragToPoint:point]; |
2472 int numButtons = layout_.VisibleButtonCount(); | 2673 int numButtons = displayedButtonCount_; |
2473 | 2674 |
2474 CGFloat leadingOffset; | 2675 CGFloat leftmostX; |
2475 if (layout_.IsSupervisedBookmarksButtonVisible()) { | 2676 if (![supervisedBookmarksButton_ isHidden]) { |
2476 leadingOffset = | 2677 leftmostX = |
2477 layout_.supervised_bookmarks_button_offset + halfHorizontalPadding; | 2678 NSMaxX([supervisedBookmarksButton_ frame]) + halfHorizontalPadding; |
2478 } else if (layout_.IsManagedBookmarksButtonVisible()) { | 2679 } else if (![managedBookmarksButton_ isHidden]) { |
2479 leadingOffset = | 2680 leftmostX = NSMaxX([managedBookmarksButton_ frame]) + halfHorizontalPadding; |
2480 layout_.managed_bookmarks_button_offset + halfHorizontalPadding; | 2681 } else if (![appsPageShortcutButton_ isHidden]) { |
2481 } else if (layout_.IsAppsButtonVisible()) { | 2682 leftmostX = NSMaxX([appsPageShortcutButton_ frame]) + halfHorizontalPadding; |
2482 leadingOffset = layout_.apps_button_offset + halfHorizontalPadding; | |
2483 } else { | 2683 } else { |
2484 leadingOffset = bookmarks::kBookmarkLeftMargin - halfHorizontalPadding; | 2684 leftmostX = bookmarks::kBookmarkLeftMargin - halfHorizontalPadding; |
2485 } | 2685 } |
2486 | 2686 |
2487 // If it's a drop strictly between existing buttons ... | 2687 // If it's a drop strictly between existing buttons ... |
2488 if (destIndex == 0) { | 2688 if (destIndex == 0) { |
2489 x = leadingOffset; | 2689 x = leftmostX; |
2490 } else if (destIndex > 0 && destIndex < numButtons) { | 2690 } else if (destIndex > 0 && destIndex < numButtons) { |
2491 // ... put the indicator right between the buttons. | 2691 // ... put the indicator right between the buttons. |
2492 int64_t nodeId = | 2692 BookmarkButton* button = |
2493 bookmarkModel_->bookmark_bar_node()->GetChild(destIndex)->id(); | 2693 [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex-1)]; |
2494 x = layout_.button_offsets[nodeId] - halfHorizontalPadding; | 2694 DCHECK(button); |
| 2695 NSRect buttonFrame = [button frame]; |
| 2696 x = NSMaxX(buttonFrame) + halfHorizontalPadding; |
| 2697 |
2495 // If it's a drop at the end (past the last button, if there are any) ... | 2698 // If it's a drop at the end (past the last button, if there are any) ... |
2496 } else if (destIndex == numButtons) { | 2699 } else if (destIndex == numButtons) { |
2497 // and if it's past the last button ... | 2700 // and if it's past the last button ... |
2498 if (numButtons > 0) { | 2701 if (numButtons > 0) { |
2499 // ... find the last button, and put the indicator after it. | 2702 // ... find the last button, and put the indicator to its right. |
2500 const BookmarkNode* node = | 2703 BookmarkButton* button = |
2501 bookmarkModel_->bookmark_bar_node()->GetChild(destIndex - 1); | 2704 [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex - 1)]; |
2502 int64_t nodeId = node->id(); | 2705 DCHECK(button); |
2503 x = layout_.button_offsets[nodeId] + [self widthOfButtonForNode:node] + | 2706 x = NSMaxX([button frame]) + halfHorizontalPadding; |
2504 halfHorizontalPadding; | 2707 |
2505 // Otherwise, put it right at the beginning. | 2708 // Otherwise, put it right at the beginning. |
2506 } else { | 2709 } else { |
2507 x = leadingOffset; | 2710 x = leftmostX; |
2508 } | 2711 } |
2509 } else { | 2712 } else { |
2510 NOTREACHED(); | 2713 NOTREACHED(); |
2511 } | 2714 } |
2512 | 2715 |
2513 return cocoa_l10n_util::ShouldDoExperimentalRTLLayout() | 2716 return x; |
2514 ? NSWidth([buttonView_ frame]) - x | |
2515 : x; | |
2516 } | 2717 } |
2517 | 2718 |
2518 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child { | 2719 - (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child { |
2519 // If the bookmarkbar is not in detached mode, lock bar visibility, forcing | 2720 // If the bookmarkbar is not in detached mode, lock bar visibility, forcing |
2520 // the overlay to stay open when in fullscreen mode. | 2721 // the overlay to stay open when in fullscreen mode. |
2521 if (![self isInState:BookmarkBar::DETACHED] && | 2722 if (![self isInState:BookmarkBar::DETACHED] && |
2522 ![self isAnimatingToState:BookmarkBar::DETACHED]) { | 2723 ![self isAnimatingToState:BookmarkBar::DETACHED]) { |
2523 BrowserWindowController* browserController = | 2724 BrowserWindowController* browserController = |
2524 [BrowserWindowController browserWindowControllerForView:[self view]]; | 2725 [BrowserWindowController browserWindowControllerForView:[self view]]; |
2525 [browserController lockToolbarVisibilityForOwner:child withAnimation:NO]; | 2726 [browserController lockToolbarVisibilityForOwner:child withAnimation:NO]; |
2526 } | 2727 } |
2527 } | 2728 } |
2528 | 2729 |
2529 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child { | 2730 - (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child { |
2530 // Release bar visibility, allowing the overlay to close if in fullscreen | 2731 // Release bar visibility, allowing the overlay to close if in fullscreen |
2531 // mode. | 2732 // mode. |
2532 BrowserWindowController* browserController = | 2733 BrowserWindowController* browserController = |
2533 [BrowserWindowController browserWindowControllerForView:[self view]]; | 2734 [BrowserWindowController browserWindowControllerForView:[self view]]; |
2534 [browserController releaseToolbarVisibilityForOwner:child withAnimation:NO]; | 2735 [browserController releaseToolbarVisibilityForOwner:child withAnimation:NO]; |
2535 } | 2736 } |
2536 | 2737 |
2537 // Add a new folder controller as triggered by the given folder button. | 2738 // Add a new folder controller as triggered by the given folder button. |
2538 - (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton { | 2739 - (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton { |
| 2740 |
2539 // If doing a close/open, make sure the fullscreen chrome doesn't | 2741 // If doing a close/open, make sure the fullscreen chrome doesn't |
2540 // have a chance to begin animating away in the middle of things. | 2742 // have a chance to begin animating away in the middle of things. |
2541 BrowserWindowController* browserController = | 2743 BrowserWindowController* browserController = |
2542 [BrowserWindowController browserWindowControllerForView:[self view]]; | 2744 [BrowserWindowController browserWindowControllerForView:[self view]]; |
2543 // Confirm we're not re-locking with ourself as an owner before locking. | 2745 // Confirm we're not re-locking with ourself as an owner before locking. |
2544 DCHECK([browserController isToolbarVisibilityLockedForOwner:self] == NO); | 2746 DCHECK([browserController isToolbarVisibilityLockedForOwner:self] == NO); |
2545 [browserController lockToolbarVisibilityForOwner:self withAnimation:NO]; | 2747 [browserController lockToolbarVisibilityForOwner:self withAnimation:NO]; |
2546 | 2748 |
2547 if (folderController_) | 2749 if (folderController_) |
2548 [self closeAllBookmarkFolders]; | 2750 [self closeAllBookmarkFolders]; |
(...skipping 15 matching lines...) Expand all Loading... |
2564 [browserController releaseToolbarVisibilityForOwner:self withAnimation:NO]; | 2766 [browserController releaseToolbarVisibilityForOwner:self withAnimation:NO]; |
2565 } | 2767 } |
2566 | 2768 |
2567 - (void)openAll:(const BookmarkNode*)node | 2769 - (void)openAll:(const BookmarkNode*)node |
2568 disposition:(WindowOpenDisposition)disposition { | 2770 disposition:(WindowOpenDisposition)disposition { |
2569 [self closeFolderAndStopTrackingMenus]; | 2771 [self closeFolderAndStopTrackingMenus]; |
2570 chrome::OpenAll([[self view] window], browser_, node, disposition, | 2772 chrome::OpenAll([[self view] window], browser_, node, disposition, |
2571 browser_->profile()); | 2773 browser_->profile()); |
2572 } | 2774 } |
2573 | 2775 |
| 2776 - (void)addButtonForNode:(const BookmarkNode*)node |
| 2777 atIndex:(NSInteger)buttonIndex { |
| 2778 int newOffset = |
| 2779 bookmarks::kBookmarkLeftMargin - bookmarks::kBookmarkHorizontalPadding; |
| 2780 if (buttonIndex == -1) |
| 2781 buttonIndex = [buttons_ count]; // New button goes at the end. |
| 2782 if (buttonIndex <= (NSInteger)[buttons_ count]) { |
| 2783 if (buttonIndex) { |
| 2784 BookmarkButton* targetButton = [buttons_ objectAtIndex:buttonIndex - 1]; |
| 2785 NSRect targetFrame = [targetButton frame]; |
| 2786 newOffset = targetFrame.origin.x + NSWidth(targetFrame) + |
| 2787 bookmarks::kBookmarkHorizontalPadding; |
| 2788 } |
| 2789 BookmarkButton* newButton = [self buttonForNode:node xOffset:&newOffset]; |
| 2790 ++displayedButtonCount_; |
| 2791 [buttons_ insertObject:newButton atIndex:buttonIndex]; |
| 2792 [buttonView_ addSubview:newButton]; |
| 2793 [self resetAllButtonPositionsWithAnimation:NO]; |
| 2794 // See if any buttons need to be pushed off to or brought in from the side. |
| 2795 [self reconfigureBookmarkBar]; |
| 2796 } else { |
| 2797 // A button from somewhere else (not the bar) is being moved to the |
| 2798 // off-the-side so insure it gets redrawn if its showing. |
| 2799 [self reconfigureBookmarkBar]; |
| 2800 [folderController_ reconfigureMenu]; |
| 2801 } |
| 2802 } |
| 2803 |
2574 // TODO(mrossetti): Duplicate code with BookmarkBarFolderController. | 2804 // TODO(mrossetti): Duplicate code with BookmarkBarFolderController. |
2575 // http://crbug.com/35966 | 2805 // http://crbug.com/35966 |
2576 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { | 2806 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { |
2577 DCHECK([urls count] == [titles count]); | 2807 DCHECK([urls count] == [titles count]); |
2578 BOOL nodesWereAdded = NO; | 2808 BOOL nodesWereAdded = NO; |
2579 // Figure out where these new bookmarks nodes are to be added. | 2809 // Figure out where these new bookmarks nodes are to be added. |
2580 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point]; | 2810 BookmarkButton* button = [self buttonForDroppingOnAtPoint:point]; |
2581 const BookmarkNode* destParent = NULL; | 2811 const BookmarkNode* destParent = NULL; |
2582 int destIndex = 0; | 2812 int destIndex = 0; |
2583 if ([button isFolder]) { | 2813 if ([button isFolder]) { |
(...skipping 27 matching lines...) Expand all Loading... |
2611 [titles objectAtIndex:i]), | 2841 [titles objectAtIndex:i]), |
2612 gurl); | 2842 gurl); |
2613 nodesWereAdded = YES; | 2843 nodesWereAdded = YES; |
2614 } | 2844 } |
2615 } | 2845 } |
2616 } | 2846 } |
2617 return nodesWereAdded; | 2847 return nodesWereAdded; |
2618 } | 2848 } |
2619 | 2849 |
2620 - (void)moveButtonFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex { | 2850 - (void)moveButtonFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex { |
2621 int buttonCount = layout_.VisibleButtonCount(); | 2851 if (fromIndex != toIndex) { |
2622 BOOL isMoveWithinOffTheSideMenu = | 2852 NSInteger buttonCount = (NSInteger)[buttons_ count]; |
2623 (toIndex >= buttonCount) && (fromIndex >= buttonCount); | 2853 if (toIndex == -1) |
2624 if (isMoveWithinOffTheSideMenu) { | 2854 toIndex = buttonCount; |
2625 fromIndex -= buttonCount; | 2855 // See if we have a simple move within the bar, which will be the case if |
2626 toIndex -= buttonCount; | 2856 // both button indexes are in the visible space. |
2627 [folderController_ moveButtonFromIndex:fromIndex toIndex:toIndex]; | 2857 if (fromIndex < buttonCount && toIndex < buttonCount) { |
2628 } else { | 2858 BookmarkButton* movedButton = [buttons_ objectAtIndex:fromIndex]; |
2629 [self rebuildLayoutWithAnimated:NO]; | 2859 [buttons_ removeObjectAtIndex:fromIndex]; |
| 2860 [buttons_ insertObject:movedButton atIndex:toIndex]; |
| 2861 [movedButton setHidden:NO]; |
| 2862 [self resetAllButtonPositionsWithAnimation:NO]; |
| 2863 } else if (fromIndex < buttonCount) { |
| 2864 // A button is being removed from the bar and added to off-the-side. |
| 2865 // By now the node has already been inserted into the model so the |
| 2866 // button to be added is represented by |toIndex|. Things get |
| 2867 // complicated because the off-the-side is showing and must be redrawn |
| 2868 // while possibly re-laying out the bookmark bar. |
| 2869 [self removeButton:fromIndex animate:NO]; |
| 2870 [self reconfigureBookmarkBar]; |
| 2871 [folderController_ reconfigureMenu]; |
| 2872 } else if (toIndex < buttonCount) { |
| 2873 // A button is being added to the bar and removed from off-the-side. |
| 2874 // By now the node has already been inserted into the model so the |
| 2875 // button to be added is represented by |toIndex|. |
| 2876 const BookmarkNode* node = bookmarkModel_->bookmark_bar_node(); |
| 2877 const BookmarkNode* movedNode = node->GetChild(toIndex); |
| 2878 DCHECK(movedNode); |
| 2879 [self addButtonForNode:movedNode atIndex:toIndex]; |
| 2880 [self reconfigureBookmarkBar]; |
| 2881 } else { |
| 2882 // A button is being moved within the off-the-side. |
| 2883 fromIndex -= buttonCount; |
| 2884 toIndex -= buttonCount; |
| 2885 [folderController_ moveButtonFromIndex:fromIndex toIndex:toIndex]; |
| 2886 } |
2630 } | 2887 } |
2631 } | 2888 } |
2632 | 2889 |
2633 - (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate { | 2890 - (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate { |
2634 if ((size_t)buttonIndex < layout_.VisibleButtonCount()) { | 2891 if (buttonIndex < (NSInteger)[buttons_ count]) { |
2635 // The button being removed is showing in the bar. | 2892 // The button being removed is showing in the bar. |
2636 BookmarkButton* oldButton = buttons_[buttonIndex]; | 2893 BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex]; |
2637 if (oldButton == [folderController_ parentButton]) { | 2894 if (oldButton == [folderController_ parentButton]) { |
2638 // If we are deleting a button whose folder is currently open, close it! | 2895 // If we are deleting a button whose folder is currently open, close it! |
2639 [self closeAllBookmarkFolders]; | 2896 [self closeAllBookmarkFolders]; |
2640 } | 2897 } |
2641 if (animate && innerContentAnimationsEnabled_ && [self isVisible] && | 2898 if (animate && innerContentAnimationsEnabled_ && [self isVisible] && |
2642 [[self browserWindow] isMainWindow]) { | 2899 [[self browserWindow] isMainWindow]) { |
2643 NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation]; | 2900 NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation]; |
2644 NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint, | 2901 NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint, |
2645 NSZeroSize, nil, nil, nil); | 2902 NSZeroSize, nil, nil, nil); |
2646 } | 2903 } |
2647 [self rebuildLayoutWithAnimated:YES]; | 2904 [oldButton setDelegate:nil]; |
| 2905 [oldButton removeFromSuperview]; |
| 2906 [buttons_ removeObjectAtIndex:buttonIndex]; |
| 2907 --displayedButtonCount_; |
| 2908 [self resetAllButtonPositionsWithAnimation:YES]; |
| 2909 [self reconfigureBookmarkBar]; |
2648 } else if (folderController_ && | 2910 } else if (folderController_ && |
2649 [folderController_ parentButton] == offTheSideButton_) { | 2911 [folderController_ parentButton] == offTheSideButton_) { |
2650 // The button being removed is in the OTS (off-the-side) and the OTS | 2912 // The button being removed is in the OTS (off-the-side) and the OTS |
2651 // menu is showing so we need to remove the button. | 2913 // menu is showing so we need to remove the button. |
2652 NSInteger index = buttonIndex - layout_.VisibleButtonCount(); | 2914 NSInteger index = buttonIndex - displayedButtonCount_; |
2653 [folderController_ removeButton:index animate:animate]; | 2915 [folderController_ removeButton:index animate:animate]; |
2654 } | 2916 } |
2655 } | 2917 } |
2656 | 2918 |
2657 - (id<BookmarkButtonControllerProtocol>)controllerForNode: | 2919 - (id<BookmarkButtonControllerProtocol>)controllerForNode: |
2658 (const BookmarkNode*)node { | 2920 (const BookmarkNode*)node { |
2659 // See if it's in the bar, then if it is in the hierarchy of visible | 2921 // See if it's in the bar, then if it is in the hierarchy of visible |
2660 // folder menus. | 2922 // folder menus. |
2661 if (bookmarkModel_->bookmark_bar_node() == node) | 2923 if (bookmarkModel_->bookmark_bar_node() == node) |
2662 return self; | 2924 return self; |
2663 return [folderController_ controllerForNode:node]; | 2925 return [folderController_ controllerForNode:node]; |
2664 } | 2926 } |
2665 | 2927 |
2666 // For testing. | |
2667 - (const BookmarkBarLayout&)currentLayout { | |
2668 return layout_; | |
2669 } | |
2670 | |
2671 @end | 2928 @end |
OLD | NEW |