Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Side by Side Diff: chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm

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

Powered by Google App Engine
This is Rietveld 408576698