| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 #include "app/l10n_util_mac.h" | 5 #include "app/l10n_util_mac.h" |
| 6 #include "app/resource_bundle.h" | 6 #include "app/resource_bundle.h" |
| 7 #include "base/mac_util.h" | 7 #include "base/mac_util.h" |
| 8 #include "base/sys_string_conversions.h" | 8 #include "base/sys_string_conversions.h" |
| 9 #include "chrome/browser/bookmarks/bookmark_editor.h" | 9 #include "chrome/browser/bookmarks/bookmark_editor.h" |
| 10 #include "chrome/browser/bookmarks/bookmark_model.h" | 10 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 11 #include "chrome/browser/browser.h" | 11 #include "chrome/browser/browser.h" |
| 12 #include "chrome/browser/browser_list.h" | 12 #include "chrome/browser/browser_list.h" |
| 13 #import "chrome/browser/cocoa/background_gradient_view.h" |
| 13 #import "chrome/browser/cocoa/bookmark_bar_bridge.h" | 14 #import "chrome/browser/cocoa/bookmark_bar_bridge.h" |
| 14 #import "chrome/browser/cocoa/bookmark_bar_constants.h" | 15 #import "chrome/browser/cocoa/bookmark_bar_constants.h" |
| 15 #import "chrome/browser/cocoa/bookmark_bar_controller.h" | 16 #import "chrome/browser/cocoa/bookmark_bar_controller.h" |
| 16 #import "chrome/browser/cocoa/bookmark_bar_toolbar_view.h" | 17 #import "chrome/browser/cocoa/bookmark_bar_toolbar_view.h" |
| 17 #import "chrome/browser/cocoa/bookmark_bar_view.h" | 18 #import "chrome/browser/cocoa/bookmark_bar_view.h" |
| 18 #import "chrome/browser/cocoa/bookmark_button_cell.h" | 19 #import "chrome/browser/cocoa/bookmark_button_cell.h" |
| 19 #import "chrome/browser/cocoa/bookmark_editor_controller.h" | 20 #import "chrome/browser/cocoa/bookmark_editor_controller.h" |
| 20 #import "chrome/browser/cocoa/bookmark_name_folder_controller.h" | 21 #import "chrome/browser/cocoa/bookmark_name_folder_controller.h" |
| 21 #import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h" | 22 #import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h" |
| 22 #import "chrome/browser/cocoa/event_utils.h" | 23 #import "chrome/browser/cocoa/event_utils.h" |
| 23 #import "chrome/browser/cocoa/menu_button.h" | 24 #import "chrome/browser/cocoa/menu_button.h" |
| 24 #import "chrome/browser/cocoa/toolbar_controller.h" | 25 #import "chrome/browser/cocoa/toolbar_controller.h" |
| 25 #import "chrome/browser/cocoa/view_resizer.h" | 26 #import "chrome/browser/cocoa/view_resizer.h" |
| 26 #include "chrome/browser/metrics/user_metrics.h" | 27 #include "chrome/browser/metrics/user_metrics.h" |
| 27 #include "chrome/browser/profile.h" | 28 #include "chrome/browser/profile.h" |
| 28 #include "chrome/browser/tab_contents/tab_contents.h" | 29 #include "chrome/browser/tab_contents/tab_contents.h" |
| 29 #include "chrome/browser/tab_contents/tab_contents_view.h" | 30 #include "chrome/browser/tab_contents/tab_contents_view.h" |
| 30 #include "chrome/common/pref_names.h" | 31 #include "chrome/common/pref_names.h" |
| 31 #include "chrome/common/pref_service.h" | 32 #include "chrome/common/pref_service.h" |
| 32 #include "grit/app_resources.h" | 33 #include "grit/app_resources.h" |
| 33 #include "grit/generated_resources.h" | 34 #include "grit/generated_resources.h" |
| 34 #include "grit/theme_resources.h" | 35 #include "grit/theme_resources.h" |
| 35 #include "skia/ext/skia_utils_mac.h" | 36 #include "skia/ext/skia_utils_mac.h" |
| 36 #import "third_party/mozilla/include/NSPasteboard+Utils.h" | 37 #import "third_party/mozilla/include/NSPasteboard+Utils.h" |
| 37 | 38 |
| 39 // Bookmark bar state changing and animations |
| 40 // |
| 41 // The bookmark bar has three real states: "showing" (a normal bar attached to |
| 42 // the toolbar), "hidden", and "detached" (pretending to be part of the web |
| 43 // content on the NTP). It can, or at least should be able to, animate between |
| 44 // these states. There are several complications even without animation: |
| 45 // - The placement of the bookmark bar is done by the BWC, and it needs to know |
| 46 // the state in order to place the bookmark bar correctly (immediately below |
| 47 // the toolbar when showing, below the infobar when detached). |
| 48 // - The "divider" (a black line) needs to be drawn by either the toolbar (when |
| 49 // the bookmark bar is hidden or detached) or by the bookmark bar (when it is |
| 50 // showing). It should not be drawn by both. |
| 51 // - The toolbar needs to vertically "compress" when the bookmark bar is |
| 52 // showing. This ensures the proper display of both the bookmark bar and the |
| 53 // toolbar, and gives a padded area around the bookmark bar items for right |
| 54 // clicks, etc. |
| 55 // |
| 56 // Our model is that the BWC controls us and also the toolbar. We try not to |
| 57 // talk to the browser nor the toolbar directly, instead centralizing control in |
| 58 // the BWC. The key method by which the BWC controls us is |
| 59 // |-updateAndShowNormalBar:showDetachedBar:withAnimation:|. This invokes state |
| 60 // changes, and at appropriate times we request that the BWC do things for us |
| 61 // via either the resize delegate or our general delegate. If the BWC needs any |
| 62 // information about what it should do, or tell the toolbar to do, it can then |
| 63 // query us back (e.g., |-isShownAs...|, |-getDesiredToolbarHeightCompression|, |
| 64 // |-shouldToolbarShowDivider|, etc.). |
| 65 // |
| 66 // Animation-related complications: |
| 67 // - Compression of the toolbar is touchy during animation. It must not be |
| 68 // compressed while the bookmark bar is animating to/from showing (from/to |
| 69 // hidden), otherwise it would look like the bookmark bar's contents are |
| 70 // sliding out of the controls inside the toolbar. As such, we have to make |
| 71 // sure that the bookmark bar is shown at the right location and at the |
| 72 // right height (at various points in time). |
| 73 // - Showing the divider is also complicated during animation between hidden |
| 74 // and showing. We have to make sure that the toolbar does not show the |
| 75 // divider despite the fact that it's not compressed. The exception to this |
| 76 // is at the beginning/end of the animation when the toolbar is still |
| 77 // uncompressed but the bookmark bar has height 0. If we're not careful, we |
| 78 // get a flicker at this point. |
| 79 // - We have to ensure that we do the right thing if we're told to change state |
| 80 // while we're running an animation. The generic/easy thing to do is to jump |
| 81 // to the end state of our current animation, and (if the new state change |
| 82 // again involves an animation) begin the new animation. We can do better |
| 83 // than that, however, and sometimes just change the current animation to go |
| 84 // to the new end state (e.g., by "reversing" the animation in the showing -> |
| 85 // hidden -> showing case). We also have to ensure that demands to |
| 86 // immediately change state are always honoured. |
| 87 // |
| 88 // Pointers to animation logic: |
| 89 // - |-moveToVisualState:withAnimation:| starts animations, deciding which ones |
| 90 // we know how to handle. |
| 91 // - |showBookmarkBarWithAnimation:| has most of the actual logic. |
| 92 // - |-getDesiredToolbarHeightCompression| and |-shouldToolbarShowDivider| |
| 93 // contain related logic. |
| 94 // - The BWC's |-layoutSubviews| needs to know how to position things. |
| 95 // - The BWC should implement |-bookmarkBar:didChangeFromState:toState:| and |
| 96 // |-bookmarkBar:willAnimateFromState:toState:| in order to inform the |
| 97 // toolbar of required changes. |
| 98 |
| 99 namespace { |
| 100 |
| 101 // Overlap (in pixels) between the toolbar and the bookmark bar (when showing in |
| 102 // normal mode). |
| 103 const CGFloat kBookmarkBarOverlap = 6.0; |
| 104 |
| 105 // Duration of the bookmark bar animations. |
| 106 const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; |
| 107 |
| 108 } // namespace |
| 109 |
| 38 // Specialization of NSButton that responds to middle-clicks. By default, | 110 // Specialization of NSButton that responds to middle-clicks. By default, |
| 39 // NSButton ignores them. | 111 // NSButton ignores them. |
| 40 @interface BookmarkButton : NSButton | 112 @interface BookmarkButton : NSButton |
| 41 @end | 113 @end |
| 42 | 114 |
| 43 @implementation BookmarkButton | 115 @implementation BookmarkButton |
| 44 - (void)otherMouseUp:(NSEvent*) event { | 116 - (void)otherMouseUp:(NSEvent*) event { |
| 45 [self performClick:self]; | 117 [self performClick:self]; |
| 46 } | 118 } |
| 47 @end | 119 @end |
| 48 | 120 |
| 49 @interface BookmarkBarController(Private) | 121 @interface BookmarkBarController(Private) |
| 50 - (void)showBookmarkBar:(BOOL)enable immediately:(BOOL)immediately; | 122 // Determines the appropriate state for the given situation. |
| 123 + (bookmarks::VisualState)visualStateToShowNormalBar:(BOOL)showNormalBar |
| 124 showDetachedBar:(BOOL)showDetachedBar; |
| 125 |
| 126 // Moves to the given next state (from the current state), possibly animating. |
| 127 // If |animate| is NO, it will stop any running animation and jump to the given |
| 128 // state. If YES, it may either (depending on implementation) jump to the end of |
| 129 // the current animation and begin the next one, or stop the current animation |
| 130 // mid-flight and animate to the next state. |
| 131 - (void)moveToVisualState:(bookmarks::VisualState)nextVisualState |
| 132 withAnimation:(BOOL)animate; |
| 133 |
| 134 // Return the backdrop to the bookmark bar as various types. |
| 135 - (BackgroundGradientView*)backgroundGradientView; |
| 136 - (AnimatableView*)animatableView; |
| 137 |
| 138 // Puts stuff into the final visual state without animating, stopping a running |
| 139 // animation if necessary. |
| 140 - (void)finalizeVisualState; |
| 141 |
| 142 // Stops any current animation in its tracks (midway). |
| 143 - (void)stopCurrentAnimation; |
| 144 |
| 145 // Show/hide the bookmark bar. Handles animating the resize of the content view. |
| 146 // if |animate| is YES, the changes are made using the animator; otherwise they |
| 147 // are made immediately. |
| 148 - (void)showBookmarkBarWithAnimation:(BOOL)animate; |
| 149 |
| 51 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu; | 150 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu; |
| 52 - (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu; | 151 - (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu; |
| 53 - (void)tagEmptyMenu:(NSMenu*)menu; | 152 - (void)tagEmptyMenu:(NSMenu*)menu; |
| 54 - (void)clearMenuTagMap; | 153 - (void)clearMenuTagMap; |
| 55 - (int)preferredHeight; | 154 - (int)preferredHeight; |
| 56 - (void)addNonBookmarkButtonsToView; | 155 - (void)addNonBookmarkButtonsToView; |
| 57 - (void)addButtonsToView; | 156 - (void)addButtonsToView; |
| 58 - (void)resizeButtons; | 157 - (void)resizeButtons; |
| 59 - (void)centerNoItemsLabel; | 158 - (void)centerNoItemsLabel; |
| 60 - (NSImage*)getFavIconForNode:(const BookmarkNode*)node; | 159 - (NSImage*)getFavIconForNode:(const BookmarkNode*)node; |
| 61 @end | 160 @end |
| 62 | 161 |
| 63 @implementation BookmarkBarController | 162 @implementation BookmarkBarController |
| 64 | 163 |
| 164 @synthesize visualState = visualState_; |
| 165 @synthesize lastVisualState = lastVisualState_; |
| 166 @synthesize delegate = delegate_; |
| 167 |
| 65 - (id)initWithBrowser:(Browser*)browser | 168 - (id)initWithBrowser:(Browser*)browser |
| 66 initialWidth:(float)initialWidth | 169 initialWidth:(float)initialWidth |
| 67 compressDelegate:(id<ToolbarCompressable>)compressDelegate | 170 delegate:(id<BookmarkBarControllerDelegate>)delegate |
| 68 resizeDelegate:(id<ViewResizer>)resizeDelegate { | 171 resizeDelegate:(id<ViewResizer>)resizeDelegate { |
| 69 if ((self = [super initWithNibName:@"BookmarkBar" | 172 if ((self = [super initWithNibName:@"BookmarkBar" |
| 70 bundle:mac_util::MainAppBundle()])) { | 173 bundle:mac_util::MainAppBundle()])) { |
| 174 // Initialize to an invalid state. |
| 175 visualState_ = bookmarks::kInvalidState; |
| 176 lastVisualState_ = bookmarks::kInvalidState; |
| 177 |
| 71 browser_ = browser; | 178 browser_ = browser; |
| 72 initialWidth_ = initialWidth; | 179 initialWidth_ = initialWidth; |
| 73 bookmarkModel_ = browser_->profile()->GetBookmarkModel(); | 180 bookmarkModel_ = browser_->profile()->GetBookmarkModel(); |
| 74 buttons_.reset([[NSMutableArray alloc] init]); | 181 buttons_.reset([[NSMutableArray alloc] init]); |
| 75 compressDelegate_ = compressDelegate; | 182 delegate_ = delegate; |
| 76 resizeDelegate_ = resizeDelegate; | 183 resizeDelegate_ = resizeDelegate; |
| 77 tabObserver_.reset( | 184 [[self animatableView] setResizeDelegate:resizeDelegate]; |
| 78 new TabStripModelObserverBridge(browser_->tabstrip_model(), self)); | |
| 79 | 185 |
| 80 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 186 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 81 folderImage_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]); | 187 folderImage_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]); |
| 82 defaultImage_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]); | 188 defaultImage_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]); |
| 83 } | 189 } |
| 84 return self; | 190 return self; |
| 85 } | 191 } |
| 86 | 192 |
| 87 - (void)dealloc { | 193 - (void)dealloc { |
| 194 // We better stop any in-flight animation if we're being killed. |
| 195 [[self animatableView] stopAnimation]; |
| 196 |
| 88 // Remove our view from its superview so it doesn't attempt to reference | 197 // Remove our view from its superview so it doesn't attempt to reference |
| 89 // it when the controller is gone. | 198 // it when the controller is gone. |
| 90 //TODO(dmaclach): Remove -- http://crbug.com/25845 | 199 //TODO(dmaclach): Remove -- http://crbug.com/25845 |
| 91 [[self view] removeFromSuperview]; | 200 [[self view] removeFromSuperview]; |
| 92 | 201 |
| 93 bridge_.reset(NULL); | 202 bridge_.reset(NULL); |
| 94 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 203 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 95 [super dealloc]; | 204 [super dealloc]; |
| 96 } | 205 } |
| 97 | 206 |
| 98 - (void)awakeFromNib { | 207 - (void)awakeFromNib { |
| 99 // We default to NOT open, which means height=0. | 208 // We default to NOT open, which means height=0. |
| 100 DCHECK([[self view] isHidden]); // Hidden so it's OK to change. | 209 DCHECK([[self view] isHidden]); // Hidden so it's OK to change. |
| 101 | 210 |
| 102 // Set our initial height to zero, since that is what the superview | 211 // Set our initial height to zero, since that is what the superview |
| 103 // expects. We will resize ourselves open later if needed. | 212 // expects. We will resize ourselves open later if needed. |
| 104 [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)]; | 213 [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)]; |
| 105 | 214 |
| 106 // We are enabled by default. | 215 // We are enabled by default. |
| 107 barIsEnabled_ = YES; | 216 barIsEnabled_ = YES; |
| 108 | 217 |
| 109 // Don't pass ourself along (as 'self') until our init is completely | 218 // Don't pass ourself along (as 'self') until our init is completely |
| 110 // done. Thus, this call is (almost) last. | 219 // done. Thus, this call is (almost) last. |
| 111 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_)); | 220 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_)); |
| 112 | 221 |
| 113 DCHECK([offTheSideButton_ attachedMenu]); | 222 DCHECK([offTheSideButton_ attachedMenu]); |
| 114 | 223 |
| 115 // To make life happier when the bookmark bar is floating, the | 224 // To make life happier when the bookmark bar is floating, the chevron is a |
| 116 // chevron is a child of the button view. | 225 // child of the button view. |
| 117 [offTheSideButton_ removeFromSuperview]; | 226 [offTheSideButton_ removeFromSuperview]; |
| 118 [buttonView_ addSubview:offTheSideButton_]; | 227 [buttonView_ addSubview:offTheSideButton_]; |
| 119 | 228 |
| 120 // When resized we may need to add new buttons, or remove them (if | 229 // When resized we may need to add new buttons, or remove them (if |
| 121 // no longer visible), or add/remove the "off the side" menu. | 230 // no longer visible), or add/remove the "off the side" menu. |
| 122 [[self view] setPostsFrameChangedNotifications:YES]; | 231 [[self view] setPostsFrameChangedNotifications:YES]; |
| 123 [[NSNotificationCenter defaultCenter] | 232 [[NSNotificationCenter defaultCenter] |
| 124 addObserver:self | 233 addObserver:self |
| 125 selector:@selector(frameDidChange) | 234 selector:@selector(frameDidChange) |
| 126 name:NSViewFrameDidChangeNotification | 235 name:NSViewFrameDidChangeNotification |
| 127 object:[self view]]; | 236 object:[self view]]; |
| 128 } | 237 } |
| 129 | 238 |
| 130 // Method is the same as [self view], but is provided to be explicit. | 239 // (Private) Method is the same as [self view], but is provided to be explicit. |
| 131 - (BackgroundGradientView*)backgroundGradientView { | 240 - (BackgroundGradientView*)backgroundGradientView { |
| 241 DCHECK([[self view] isKindOfClass:[BackgroundGradientView class]]); |
| 132 return (BackgroundGradientView*)[self view]; | 242 return (BackgroundGradientView*)[self view]; |
| 133 } | 243 } |
| 134 | 244 |
| 135 - (void)showIfNeeded { | 245 // (Private) Method is the same as [self view], but is provided to be explicit. |
| 136 if (browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar)) | 246 - (AnimatableView*)animatableView { |
| 137 [self showBookmarkBar:YES immediately:YES]; | 247 DCHECK([[self view] isKindOfClass:[AnimatableView class]]); |
| 248 return (AnimatableView*)[self view]; |
| 138 } | 249 } |
| 139 | 250 |
| 140 // Position the off-the-side chevron to the left of the otherBookmarks button. | 251 // Position the off-the-side chevron to the left of the otherBookmarks button. |
| 141 - (void)positionOffTheSideButton { | 252 - (void)positionOffTheSideButton { |
| 142 NSRect frame = [offTheSideButton_ frame]; | 253 NSRect frame = [offTheSideButton_ frame]; |
| 143 if (otherBookmarksButton_.get()) { | 254 if (otherBookmarksButton_.get()) { |
| 144 frame.origin.x = ([otherBookmarksButton_ frame].origin.x - | 255 frame.origin.x = ([otherBookmarksButton_ frame].origin.x - |
| 145 (frame.size.width + bookmarks::kBookmarkHorizontalPadding)
); | 256 (frame.size.width + bookmarks::kBookmarkHorizontalPadding)
); |
| 146 [offTheSideButton_ setFrame:frame]; | 257 [offTheSideButton_ setFrame:frame]; |
| 147 } | 258 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 178 } | 289 } |
| 179 | 290 |
| 180 // Keep the "no items" label centered in response to a frame size change. | 291 // Keep the "no items" label centered in response to a frame size change. |
| 181 - (void)centerNoItemsLabel { | 292 - (void)centerNoItemsLabel { |
| 182 NSView* noItemsView = [buttonView_ noItemTextfield]; | 293 NSView* noItemsView = [buttonView_ noItemTextfield]; |
| 183 NSRect frame = [noItemsView frame]; | 294 NSRect frame = [noItemsView frame]; |
| 184 NSRect parent = [buttonView_ bounds]; | 295 NSRect parent = [buttonView_ bounds]; |
| 185 NSPoint newOrigin; | 296 NSPoint newOrigin; |
| 186 newOrigin.x = parent.origin.x + bookmarks::kNoBookmarksHorizontalOffset; | 297 newOrigin.x = parent.origin.x + bookmarks::kNoBookmarksHorizontalOffset; |
| 187 newOrigin.y = parent.origin.y + parent.size.height - | 298 newOrigin.y = parent.origin.y + parent.size.height - |
| 188 ([self isAlwaysVisible] ? bookmarks::kNoBookmarksVerticalOffset : | 299 ([self isShownAsToolbar] ? bookmarks::kNoBookmarksVerticalOffset : |
| 189 bookmarks::kNoBookmarksNTPVerticalOffset); | 300 bookmarks::kNoBookmarksNTPVerticalOffset); |
| 190 [noItemsView setFrameOrigin:newOrigin]; | 301 [noItemsView setFrameOrigin:newOrigin]; |
| 191 } | 302 } |
| 192 | 303 |
| 193 // Change the layout of the bookmark bar's subviews in response to a | 304 // Change the layout of the bookmark bar's subviews in response to a visibility |
| 194 // visibility change (e.g. show or hide the bar) or style change | 305 // change (e.g., show or hide the bar) or style change (attached or floating). |
| 195 // (attached or floating). | |
| 196 - (void)layoutSubviews { | 306 - (void)layoutSubviews { |
| 197 if ([self drawAsFloatingBar]) { | 307 if (visualState_ == bookmarks::kDetachedState) { |
| 198 // The internal bookmark bar should have padding to center it. | 308 // The internal bookmark bar should have padding to center it. |
| 199 NSRect frame = [[self view] frame]; | 309 NSRect frame = [[self view] frame]; |
| 200 [buttonView_ setFrame: | 310 [buttonView_ setFrame: |
| 201 NSMakeRect(bookmarks::kNTPBookmarkBarPadding, | 311 NSMakeRect(bookmarks::kNTPBookmarkBarPadding, |
| 202 bookmarks::kNTPBookmarkBarPadding, | 312 bookmarks::kNTPBookmarkBarPadding, |
| 203 (NSWidth(frame) - | 313 (NSWidth(frame) - |
| 204 bookmarks::kNTPBookmarkBarPadding*2), | 314 bookmarks::kNTPBookmarkBarPadding*2), |
| 205 (NSHeight(frame) - | 315 (NSHeight(frame) - |
| 206 bookmarks::kNTPBookmarkBarPadding))]; | 316 bookmarks::kNTPBookmarkBarPadding))]; |
| 207 } else { | 317 } else { |
| 208 // The frame of our child should be equal to our frame, excluding | 318 // The frame of our child should be equal to our frame, excluding |
| 209 // space for stuff on the right side (e.g. off-the-side chevron). | 319 // space for stuff on the right side (e.g. off-the-side chevron). |
| 210 NSRect frame = [[self view] frame]; | 320 NSRect frame = [[self view] frame]; |
| 211 [buttonView_ setFrame:NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame))]; | 321 [buttonView_ setFrame:NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame))]; |
| 212 } | 322 } |
| 213 } | 323 } |
| 214 | 324 |
| 215 // Show or hide the bar based on the value of |show|. Handles animating the | 325 // (Private) |
| 216 // resize of the content view. if |immediately| is YES, make changes | 326 - (void)showBookmarkBarWithAnimation:(BOOL)animate { |
| 217 // immediately instead of using an animator. The routine which enables the bar | 327 if (animate) { |
| 218 // will show it if relevant using other mechanisms (the pref) to determine | 328 // Animating from hidden to normal bar. |
| 219 // desired state. | 329 if (lastVisualState_ == bookmarks::kHiddenState && |
| 220 - (void)showBookmarkBar:(BOOL)show immediately:(BOOL)immediately { | 330 visualState_ == bookmarks::kShowingState) { |
| 221 BOOL compressed = [self isAlwaysVisible]; | 331 [[self backgroundGradientView] setShowsDivider:YES]; |
| 222 [compressDelegate_ setShouldBeCompressed:compressed]; | 332 [[self view] setHidden:NO]; |
| 333 AnimatableView* view = [self animatableView]; |
| 334 // Height takes into account the extra height we have since the toolbar |
| 335 // only compresses when we're done. |
| 336 [view animateToNewHeight:([self preferredHeight] - kBookmarkBarOverlap) |
| 337 duration:kBookmarkBarAnimationDuration]; |
| 338 return; |
| 339 } |
| 223 | 340 |
| 341 // Animating from normal bar to hidden. |
| 342 if (lastVisualState_ == bookmarks::kShowingState && |
| 343 visualState_ == bookmarks::kHiddenState) { |
| 344 // The toolbar uncompresses immediately at the beginning (otherwise the |
| 345 // slide looks wrong, since we slide into the bottom of stuff in the |
| 346 // toolbar). Do this only if we're at the beginning height since we may |
| 347 // enter this mid-animation. |
| 348 if (NSHeight([[self view] frame]) == bookmarks::kBookmarkBarHeight) { |
| 349 [resizeDelegate_ resizeView:[self view] |
| 350 newHeight:(bookmarks::kBookmarkBarHeight - |
| 351 kBookmarkBarOverlap)]; |
| 352 } |
| 353 [[self backgroundGradientView] setShowsDivider:YES]; |
| 354 [[self view] setHidden:NO]; |
| 355 AnimatableView* view = [self animatableView]; |
| 356 [view animateToNewHeight:0 |
| 357 duration:kBookmarkBarAnimationDuration]; |
| 358 return; |
| 359 } |
| 360 |
| 361 // TODO(viettrungluu): other animation cases. Note: will need to fade in/out |
| 362 // divider when animating from/to detached bar (to/from normal bar). |
| 363 |
| 364 // Fall through for any cases we don't know about. |
| 365 } |
| 366 |
| 367 BOOL show = [self isVisible]; |
| 224 CGFloat height = show ? [self preferredHeight] : 0; | 368 CGFloat height = show ? [self preferredHeight] : 0; |
| 225 [resizeDelegate_ resizeView:[self view] newHeight:height]; | 369 [resizeDelegate_ resizeView:[self view] newHeight:height]; |
| 226 [[self view] setHidden:show ? NO : YES]; | |
| 227 | 370 |
| 228 DCHECK([[self view] isKindOfClass:[BookmarkBarToolbarView class]]); | 371 // Only show the divider if showing the normal bookmark bar. |
| 372 BOOL showDivider = (visualState_ == bookmarks::kShowingState || |
| 373 lastVisualState_ == bookmarks::kShowingState) ? YES : NO; |
| 374 [[self backgroundGradientView] setShowsDivider:showDivider]; |
| 375 |
| 376 // Make sure we're shown. |
| 377 [[self view] setHidden:(show ? NO : YES)]; |
| 229 [self layoutSubviews]; | 378 [self layoutSubviews]; |
| 230 [self frameDidChange]; | 379 [self frameDidChange]; |
| 231 } | 380 } |
| 232 | 381 |
| 233 // We don't change a preference; we only change visibility. | 382 // We don't change a preference; we only change visibility. Preference changing |
| 234 // Preference changing (global state) is handled in | 383 // (global state) is handled in |BrowserWindowCocoa::ToggleBookmarkBar()|. We |
| 235 // BrowserWindowCocoa::ToggleBookmarkBar(). We simply update the visibility of | 384 // simply update based on what we're told. |
| 236 // the bar based on the current value of the pref. | |
| 237 - (void)updateVisibility { | 385 - (void)updateVisibility { |
| 238 [self showBookmarkBar:[self isVisible] immediately:YES]; | 386 [self showBookmarkBarWithAnimation:NO]; |
| 239 } | 387 } |
| 240 | 388 |
| 241 - (void)setBookmarkBarEnabled:(BOOL)enabled { | 389 - (void)setBookmarkBarEnabled:(BOOL)enabled { |
| 242 barIsEnabled_ = enabled ? YES : NO; | 390 barIsEnabled_ = enabled; |
| 243 [self updateVisibility]; | 391 [self updateVisibility]; |
| 244 } | 392 } |
| 245 | 393 |
| 246 - (BOOL)isVisible { | 394 - (BOOL)isVisible { |
| 247 return ([self isAlwaysVisible] && barIsEnabled_) || [self isNewTabPage]; | 395 return (barIsEnabled_ && (visualState_ == bookmarks::kShowingState || |
| 396 visualState_ == bookmarks::kDetachedState)) ? |
| 397 YES : NO; |
| 248 } | 398 } |
| 249 | 399 |
| 250 - (BOOL)isNewTabPage { | 400 - (BOOL)isAnimationRunning { |
| 251 return browser_ && browser_->GetSelectedTabContents() && | 401 return (lastVisualState_ == bookmarks::kInvalidState) ? NO : YES; |
| 252 browser_->GetSelectedTabContents()->ShouldShowBookmarkBar(); | |
| 253 } | 402 } |
| 254 | 403 |
| 255 - (BOOL)isAlwaysVisible { | 404 - (BOOL)isShownAsToolbar { |
| 256 return browser_ && | 405 return (visualState_ == bookmarks::kShowingState) ? YES : NO; |
| 257 browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar); | 406 } |
| 407 |
| 408 - (BOOL)isShownAsDetachedBar { |
| 409 return (visualState_ == bookmarks::kDetachedState) ? YES : NO; |
| 410 } |
| 411 |
| 412 - (CGFloat)getDesiredToolbarHeightCompression { |
| 413 // Some special cases.... |
| 414 if ([self isAnimationRunning]) { |
| 415 // No toolbar compression when animating between showing and hidden. |
| 416 if ((lastVisualState_ == bookmarks::kHiddenState && |
| 417 visualState_ == bookmarks::kShowingState) || |
| 418 (lastVisualState_ == bookmarks::kShowingState && |
| 419 visualState_ == bookmarks::kHiddenState)) |
| 420 return 0; |
| 421 |
| 422 // TODO(viettrungluu): other animation cases. |
| 423 } |
| 424 |
| 425 return (visualState_ == bookmarks::kShowingState) ? kBookmarkBarOverlap : 0; |
| 426 } |
| 427 |
| 428 - (BOOL)shouldToolbarShowDivider { |
| 429 // Some special cases.... |
| 430 if ([self isAnimationRunning]) { |
| 431 // In general, the toolbar shouldn't show a divider while we're animating |
| 432 // between showing and hidden. The exception is when our height is < 1, in |
| 433 // which case we can't draw it. |
| 434 if ((lastVisualState_ == bookmarks::kHiddenState && |
| 435 visualState_ == bookmarks::kShowingState) || |
| 436 (lastVisualState_ == bookmarks::kShowingState && |
| 437 visualState_ == bookmarks::kHiddenState)) |
| 438 return (NSHeight([[self view] frame]) < 1) ? YES : NO; |
| 439 |
| 440 // TODO(viettrungluu): other animation cases. |
| 441 } |
| 442 |
| 443 return (visualState_ == bookmarks::kShowingState) ? NO : YES; |
| 258 } | 444 } |
| 259 | 445 |
| 260 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { | 446 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { |
| 261 // TODO(jrg): Support drops on folders etc | 447 // TODO(jrg): Support drops on folders etc |
| 262 // TODO(jrg): Use |point|. | 448 // TODO(jrg): Use |point|. |
| 263 DCHECK([urls count] == [titles count]); | 449 DCHECK([urls count] == [titles count]); |
| 264 const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode(); | 450 const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode(); |
| 265 | 451 |
| 266 for (size_t i = 0; i < [urls count]; ++i) { | 452 for (size_t i = 0; i < [urls count]; ++i) { |
| 267 bookmarkModel_->AddURL( | 453 bookmarkModel_->AddURL( |
| 268 node, | 454 node, |
| 269 node->GetChildCount(), | 455 node->GetChildCount(), |
| 270 base::SysNSStringToWide([titles objectAtIndex:i]), | 456 base::SysNSStringToWide([titles objectAtIndex:i]), |
| 271 GURL([[urls objectAtIndex:i] UTF8String])); | 457 GURL([[urls objectAtIndex:i] UTF8String])); |
| 272 } | 458 } |
| 273 return YES; | 459 return YES; |
| 274 } | 460 } |
| 275 | 461 |
| 276 - (int)currentTabContentsHeight { | 462 - (int)currentTabContentsHeight { |
| 277 return browser_->GetSelectedTabContents()->view()->GetContainerSize(). | 463 return browser_->GetSelectedTabContents() ? |
| 278 height(); | 464 browser_->GetSelectedTabContents()->view()->GetContainerSize().height() : |
| 465 0; |
| 279 } | 466 } |
| 280 | 467 |
| 281 - (ThemeProvider*)themeProvider { | 468 - (ThemeProvider*)themeProvider { |
| 282 return browser_->profile()->GetThemeProvider(); | 469 return browser_->profile()->GetThemeProvider(); |
| 283 } | 470 } |
| 284 | 471 |
| 285 - (BOOL)drawAsFloatingBar { | |
| 286 return ![self isAlwaysVisible] && [self isNewTabPage]; | |
| 287 } | |
| 288 | |
| 289 // Return nil if menuItem has no delegate. | 472 // Return nil if menuItem has no delegate. |
| 290 - (BookmarkNode*)nodeFromMenuItem:(id)menuItem { | 473 - (BookmarkNode*)nodeFromMenuItem:(id)menuItem { |
| 291 NSCell* cell = reinterpret_cast<NSCell*>([[menuItem menu] delegate]); | 474 NSCell* cell = reinterpret_cast<NSCell*>([[menuItem menu] delegate]); |
| 292 if (!cell) | 475 if (!cell) |
| 293 return nil; | 476 return nil; |
| 294 BookmarkNode* node = static_cast<BookmarkNode*>( | 477 BookmarkNode* node = static_cast<BookmarkNode*>( |
| 295 [[cell representedObject] pointerValue]); | 478 [[cell representedObject] pointerValue]); |
| 296 return node; | 479 return node; |
| 297 } | 480 } |
| 298 | 481 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 menuTagMap_[tag] = menuid; | 525 menuTagMap_[tag] = menuid; |
| 343 return tag; | 526 return tag; |
| 344 } | 527 } |
| 345 | 528 |
| 346 - (void)clearMenuTagMap { | 529 - (void)clearMenuTagMap { |
| 347 seedId_ = 0; | 530 seedId_ = 0; |
| 348 menuTagMap_.clear(); | 531 menuTagMap_.clear(); |
| 349 } | 532 } |
| 350 | 533 |
| 351 - (int)preferredHeight { | 534 - (int)preferredHeight { |
| 352 return [self isAlwaysVisible] ? bookmarks::kBookmarkBarHeight : | 535 return [self isShownAsToolbar] ? bookmarks::kBookmarkBarHeight : |
| 353 bookmarks::kNTPBookmarkBarHeight; | 536 bookmarks::kNTPBookmarkBarHeight; |
| 354 } | 537 } |
| 355 | 538 |
| 356 - (void)selectTabWithContents:(TabContents*)newContents | |
| 357 previousContents:(TabContents*)oldContents | |
| 358 atIndex:(NSInteger)index | |
| 359 userGesture:(bool)wasUserGesture { | |
| 360 // We need selectTabWithContents: for when we change from a tab that is the | |
| 361 // new tab page to a tab that isn't. | |
| 362 [self updateVisibility]; | |
| 363 } | |
| 364 | |
| 365 - (void)tabChangedWithContents:(TabContents*)contents | |
| 366 atIndex:(NSInteger)index | |
| 367 loadingOnly:(BOOL)loading { | |
| 368 // We need tabChangedWithContents: for when the user clicks a bookmark from | |
| 369 // the bookmark bar on the new tab page. | |
| 370 [self updateVisibility]; | |
| 371 } | |
| 372 | |
| 373 // Recursively add the given bookmark node and all its children to | 539 // Recursively add the given bookmark node and all its children to |
| 374 // menu, one menu item per node. | 540 // menu, one menu item per node. |
| 375 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu { | 541 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu { |
| 376 NSString* title = [BookmarkMenuCocoaController menuTitleForNode:child]; | 542 NSString* title = [BookmarkMenuCocoaController menuTitleForNode:child]; |
| 377 NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title | 543 NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title |
| 378 action:nil | 544 action:nil |
| 379 keyEquivalent:@""] autorelease]; | 545 keyEquivalent:@""] autorelease]; |
| 380 [menu addItem:item]; | 546 [menu addItem:item]; |
| 381 [item setImage:[self getFavIconForNode:child]]; | 547 [item setImage:[self getFavIconForNode:child]]; |
| 382 if (child->is_folder()) { | 548 if (child->is_folder()) { |
| (...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 927 if (node->is_folder()) | 1093 if (node->is_folder()) |
| 928 return folderImage_; | 1094 return folderImage_; |
| 929 | 1095 |
| 930 const SkBitmap& favIcon = bookmarkModel_->GetFavIcon(node); | 1096 const SkBitmap& favIcon = bookmarkModel_->GetFavIcon(node); |
| 931 if (!favIcon.isNull()) | 1097 if (!favIcon.isNull()) |
| 932 return gfx::SkBitmapToNSImage(favIcon); | 1098 return gfx::SkBitmapToNSImage(favIcon); |
| 933 | 1099 |
| 934 return defaultImage_; | 1100 return defaultImage_; |
| 935 } | 1101 } |
| 936 | 1102 |
| 1103 // Determines the appropriate state for the given situation. |
| 1104 + (bookmarks::VisualState)visualStateToShowNormalBar:(BOOL)showNormalBar |
| 1105 showDetachedBar:(BOOL)showDetachedBar { |
| 1106 if (showNormalBar) |
| 1107 return bookmarks::kShowingState; |
| 1108 if (showDetachedBar) |
| 1109 return bookmarks::kDetachedState; |
| 1110 return bookmarks::kHiddenState; |
| 1111 } |
| 1112 |
| 1113 - (void)moveToVisualState:(bookmarks::VisualState)nextVisualState |
| 1114 withAnimation:(BOOL)animate { |
| 1115 BOOL isAnimationRunning = [self isAnimationRunning]; |
| 1116 |
| 1117 // No-op if the next state is the same as the "current" one, subject to the |
| 1118 // following conditions: |
| 1119 // - no animation is running; or |
| 1120 // - an animation is running and |animate| is YES ([*] if it's NO, we'd want |
| 1121 // to cancel the animation and jump to the final state). |
| 1122 if ((nextVisualState == visualState_) && (!isAnimationRunning || animate)) |
| 1123 return; |
| 1124 |
| 1125 // If an animation is running, we want to finalize it. Otherwise we'd have to |
| 1126 // be able to animate starting from the middle of one type of animation. We |
| 1127 // assume that animations that we know about can be "reversed". |
| 1128 if (isAnimationRunning) { |
| 1129 // Don't cancel if we're going to reverse the animation. |
| 1130 if (nextVisualState != lastVisualState_) { |
| 1131 [self stopCurrentAnimation]; |
| 1132 [self finalizeVisualState]; |
| 1133 } |
| 1134 |
| 1135 // If we're in case [*] above, we can stop here. |
| 1136 if (nextVisualState == visualState_) |
| 1137 return; |
| 1138 } |
| 1139 |
| 1140 // Now update with the new state change. |
| 1141 lastVisualState_ = visualState_; |
| 1142 visualState_ = nextVisualState; |
| 1143 |
| 1144 if (animate) { |
| 1145 // Take care of any animation cases we know how to handle. |
| 1146 |
| 1147 // We know how to handle hidden <-> normal.... |
| 1148 if ((lastVisualState_ == bookmarks::kHiddenState && |
| 1149 visualState_ == bookmarks::kShowingState) || |
| 1150 (lastVisualState_ == bookmarks::kShowingState && |
| 1151 visualState_ == bookmarks::kHiddenState)) { |
| 1152 [delegate_ bookmarkBar:self willAnimateFromState:lastVisualState_ |
| 1153 toState:visualState_]; |
| 1154 [self showBookmarkBarWithAnimation:YES]; |
| 1155 return; |
| 1156 } |
| 1157 |
| 1158 // TODO(viettrungluu): we don't know about any yet.... |
| 1159 |
| 1160 // Let any animation cases which we don't know how to handle fall through to |
| 1161 // the unanimated case. |
| 1162 } |
| 1163 |
| 1164 // Just jump to the state. |
| 1165 [self finalizeVisualState]; |
| 1166 } |
| 1167 |
| 1168 // N.B.: |-moveToVisualState:...| will check if this should be a no-op or not. |
| 1169 - (void)updateAndShowNormalBar:(BOOL)showNormalBar |
| 1170 showDetachedBar:(BOOL)showDetachedBar |
| 1171 withAnimation:(BOOL)animate { |
| 1172 bookmarks::VisualState newVisualState = |
| 1173 [BookmarkBarController visualStateToShowNormalBar:showNormalBar |
| 1174 showDetachedBar:showDetachedBar]; |
| 1175 [self moveToVisualState:newVisualState |
| 1176 withAnimation:animate]; |
| 1177 } |
| 1178 |
| 1179 // (Private) |
| 1180 - (void)finalizeVisualState { |
| 1181 // We promise that our delegate that the variables will be finalized before |
| 1182 // the call to |-bookmarkBar:didChangeFromState:toState:|. |
| 1183 bookmarks::VisualState oldVisualState = lastVisualState_; |
| 1184 lastVisualState_ = bookmarks::kInvalidState; |
| 1185 |
| 1186 // Notify our delegate. |
| 1187 [delegate_ bookmarkBar:self didChangeFromState:oldVisualState |
| 1188 toState:visualState_]; |
| 1189 |
| 1190 // Update ourselves visually. |
| 1191 [self updateVisibility]; |
| 1192 } |
| 1193 |
| 1194 // (Private) |
| 1195 - (void)stopCurrentAnimation { |
| 1196 [[self animatableView] stopAnimation]; |
| 1197 } |
| 1198 |
| 1199 // Delegate method for |AnimatableView| (a superclass of |
| 1200 // |BookmarkBarToolbarView|). |
| 1201 - (void)animationDidEnd:(NSAnimation*)animation { |
| 1202 [self finalizeVisualState]; |
| 1203 } |
| 1204 |
| 937 @end | 1205 @end |
| OLD | NEW |