| 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 "base/sys_string_conversions.h" | 5 #include "base/sys_string_conversions.h" |
| 6 #include "chrome/browser/bookmarks/bookmark_model.h" | 6 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 7 #include "chrome/browser/browser.h" | 7 #include "chrome/browser/browser.h" |
| 8 #include "chrome/browser/browser_list.h" | 8 #include "chrome/browser/browser_list.h" |
| 9 #import "chrome/browser/cocoa/bookmark_bar_bridge.h" | 9 #import "chrome/browser/cocoa/bookmark_bar_bridge.h" |
| 10 #import "chrome/browser/cocoa/bookmark_bar_controller.h" | 10 #import "chrome/browser/cocoa/bookmark_bar_controller.h" |
| 11 #import "chrome/browser/cocoa/bookmark_bar_view.h" | 11 #import "chrome/browser/cocoa/bookmark_bar_view.h" |
| 12 #import "chrome/browser/cocoa/bookmark_button_cell.h" | 12 #import "chrome/browser/cocoa/bookmark_button_cell.h" |
| 13 #include "chrome/browser/profile.h" | 13 #include "chrome/browser/profile.h" |
| 14 #include "chrome/common/pref_names.h" | 14 #include "chrome/common/pref_names.h" |
| 15 #include "chrome/common/pref_service.h" | 15 #include "chrome/common/pref_service.h" |
| 16 #include "skia/ext/skia_utils_mac.h" | 16 #include "skia/ext/skia_utils_mac.h" |
| 17 | 17 |
| 18 @interface BookmarkBarController(Private) | 18 @interface BookmarkBarController(Private) |
| 19 - (void)applyContentAreaOffset:(BOOL)apply immediately:(BOOL)immediately; | 19 - (void)applyContentAreaOffset:(BOOL)apply immediately:(BOOL)immediately; |
| 20 - (void)positionBar; | |
| 21 - (void)showBookmarkBar:(BOOL)enable immediately:(BOOL)immediately; | 20 - (void)showBookmarkBar:(BOOL)enable immediately:(BOOL)immediately; |
| 22 @end | 21 @end |
| 23 | 22 |
| 24 namespace { | 23 namespace { |
| 24 |
| 25 // Our height, when opened. |
| 25 const int kBookmarkBarHeight = 30; | 26 const int kBookmarkBarHeight = 30; |
| 27 // How much to adjust our parent view. |
| 28 const int kBookmarkBarSuperviewHeightAdjustment = 25; |
| 29 // How much to adjust the web frame. |
| 30 const int kBookmarkBarWebframeHeightAdjustment = 25; |
| 31 |
| 26 // Magic numbers from Cole | 32 // Magic numbers from Cole |
| 27 const CGFloat kDefaultBookmarkWidth = 150.0; | 33 const CGFloat kDefaultBookmarkWidth = 150.0; |
| 28 const CGFloat kBookmarkVerticalPadding = 2.0; | 34 const CGFloat kBookmarkVerticalPadding = 2.0; |
| 29 const CGFloat kBookmarkHorizontalPadding = 8.0; | 35 const CGFloat kBookmarkHorizontalPadding = 8.0; |
| 30 }; | 36 }; |
| 31 | 37 |
| 32 @implementation BookmarkBarController | 38 @implementation BookmarkBarController |
| 33 | 39 |
| 34 - (id)initWithProfile:(Profile*)profile | 40 - (id)initWithProfile:(Profile*)profile |
| 35 contentView:(NSView*)content | 41 view:(BookmarkBarView*)view |
| 42 webContentView:(NSView*)webContentView |
| 36 delegate:(id<BookmarkURLOpener>)delegate { | 43 delegate:(id<BookmarkURLOpener>)delegate { |
| 37 if ((self = [super init])) { | 44 if ((self = [super init])) { |
| 38 bookmarkModel_ = profile->GetBookmarkModel(); | 45 bookmarkModel_ = profile->GetBookmarkModel(); |
| 39 contentView_ = content; | 46 bookmarkBarView_ = view; |
| 47 // We default to NOT open, which means height=0. |
| 48 DCHECK([view isHidden]); // OK to change |
| 49 NSRect frame = [view frame]; |
| 50 frame.size.height = 0; |
| 51 [view setFrame:frame]; |
| 52 |
| 53 // Make sure the nodes stay bottom-aligned. |
| 54 [bookmarkBarView_ setAutoresizingMask:(NSViewWidthSizable | |
| 55 NSViewMinYMargin)]; |
| 56 webContentView_ = webContentView; |
| 40 delegate_ = delegate; | 57 delegate_ = delegate; |
| 41 // Be sure to enable the bar before trying to show it... | 58 // Be sure to enable the bar before trying to show it... |
| 42 barIsEnabled_ = YES; | 59 barIsEnabled_ = YES; |
| 43 // Create and initialize the view's position. Show it if appropriate. | |
| 44 // TODO(jrg): put it in a nib if necessary. | |
| 45 NSRect frame = NSMakeRect(0, 0, 0, 30); | |
| 46 bookmarkBarView_ = [[BookmarkBarView alloc] initWithFrame:frame]; | |
| 47 [self positionBar]; | |
| 48 preferences_ = profile->GetPrefs(); | 60 preferences_ = profile->GetPrefs(); |
| 49 if (preferences_->GetBoolean(prefs::kShowBookmarkBar)) | 61 if (preferences_->GetBoolean(prefs::kShowBookmarkBar)) |
| 50 [self showBookmarkBar:YES immediately:NO]; | 62 [self showBookmarkBar:YES immediately:YES]; |
| 51 [[[contentView_ window] contentView] addSubview:bookmarkBarView_]; | |
| 52 } | 63 } |
| 53 // Don't pass ourself along until our init is done. | 64 // Don't pass ourself along until our init is done. |
| 54 // Thus, this call is (almost) last. | 65 // Thus, this call is (almost) last. |
| 55 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_)); | 66 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_)); |
| 56 return self; | 67 return self; |
| 57 } | 68 } |
| 58 | 69 |
| 59 - (void)dealloc { | |
| 60 [bookmarkBarView_ release]; | |
| 61 [super dealloc]; | |
| 62 } | |
| 63 | |
| 64 // Initializes the bookmark bar at the top edge of |contentArea_| and the | |
| 65 // view's visibility to match the pref. This doesn't move the content view at | |
| 66 // all, you need to call |-showBookmarkBar:| to do that. | |
| 67 - (void)positionBar { | |
| 68 // Hide or show bar based on initial visibility and set the resize flags. | |
| 69 [bookmarkBarView_ setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; | |
| 70 [bookmarkBarView_ setHidden:!barShouldBeShown_]; | |
| 71 | |
| 72 // Set the bar's height to zero and position it at the top of the | |
| 73 // content area, within the window's content view (as opposed to the | |
| 74 // tab strip, which is a sibling). We'll enlarge it and slide the | |
| 75 // content area down when we need to show this strip. | |
| 76 NSRect contentFrame = [contentView_ frame]; | |
| 77 NSRect barFrame = NSMakeRect(0, NSMaxY(contentFrame), | |
| 78 contentFrame.size.width, 0); | |
| 79 [bookmarkBarView_ setFrame:barFrame]; | |
| 80 } | |
| 81 | |
| 82 // Called when the contentView's frame changes. Enlarge the view to | |
| 83 // stay with the top of the contentView. | |
| 84 - (void)resizeBookmarkBar { | |
| 85 NSRect barFrame = [bookmarkBarView_ frame]; | |
| 86 const int maxY = NSMaxY(barFrame); | |
| 87 barFrame.origin.y = NSMaxY([contentView_ frame]); | |
| 88 barFrame.size.height = maxY - barFrame.origin.y; | |
| 89 [bookmarkBarView_ setFrame:barFrame]; | |
| 90 } | |
| 91 | |
| 92 // Show or hide the bar based on the value of |show|. Handles | 70 // Show or hide the bar based on the value of |show|. Handles |
| 93 // animating the resize of the content view. if |immediately| is YES, | 71 // animating the resize of the content view. if |immediately| is YES, |
| 94 // make changes immediately instead of using an animator. If the bar | 72 // make changes immediately instead of using an animator. If the bar |
| 95 // is disabled, do absolutely nothing. The routine which enables the | 73 // is disabled, do absolutely nothing. The routine which enables the |
| 96 // bar will show it if relevant using other mechanisms (the pref) to | 74 // bar will show it if relevant using other mechanisms (the pref) to |
| 97 // determine desired state. | 75 // determine desired state. |
| 98 - (void)showBookmarkBar:(BOOL)show immediately:(BOOL)immediately { | 76 - (void)showBookmarkBar:(BOOL)show immediately:(BOOL)immediately { |
| 99 if (barIsEnabled_) { | 77 if (barIsEnabled_ && (barShouldBeShown_ != show)) { |
| 100 contentViewHasOffset_ = show; | 78 contentViewHasOffset_ = show; |
| 101 [bookmarkBarView_ setHidden:show ? NO : YES]; | 79 [bookmarkBarView_ setHidden:show ? NO : YES]; |
| 102 [self applyContentAreaOffset:show immediately:immediately]; | |
| 103 barShouldBeShown_ = show; | 80 barShouldBeShown_ = show; |
| 104 if (show) { | 81 if (show) { |
| 105 [self loaded:bookmarkModel_]; | 82 [self loaded:bookmarkModel_]; |
| 106 } | 83 } |
| 84 [self applyContentAreaOffset:show immediately:immediately]; |
| 107 } | 85 } |
| 108 } | 86 } |
| 109 | 87 |
| 110 // Apply a contents box offset to make (or remove) room for the | 88 // Apply a contents box offset to make (or remove) room for the |
| 111 // bookmark bar. If apply==YES, always make room (the contentView_ is | 89 // bookmark bar. If apply==YES, always make room (the contentView_ is |
| 112 // "full size"). If apply==NO we are trying to undo an offset. If no | 90 // "full size"). If apply==NO we are trying to undo an offset. If no |
| 113 // offset there is nothing to undo. | 91 // offset there is nothing to undo. |
| 92 // |
| 93 // TODO(jrg): it is awkward we change the sizes of views for our |
| 94 // parent and siblings; ideally they change their own sizes. |
| 95 // |
| 96 // TODO(jrg): unlike windows, we process events while an animator is |
| 97 // running. Thus, if you resize the window while the bookmark bar is |
| 98 // animating, you'll mess things up. Fix. |
| 114 - (void)applyContentAreaOffset:(BOOL)apply immediately:(BOOL)immediately { | 99 - (void)applyContentAreaOffset:(BOOL)apply immediately:(BOOL)immediately { |
| 115 if (bookmarkBarView_ == nil) { | 100 if (bookmarkBarView_ == nil) { |
| 116 // We're too early, but awakeFromNib will call me again. | 101 // We're too early, but awakeFromNib will call me again. |
| 117 return; | 102 return; |
| 118 } | 103 } |
| 119 if (!contentViewHasOffset_ && apply) { | 104 if (!contentViewHasOffset_ && apply) { |
| 120 // There is no offset to unconditionally apply. | 105 // There is no offset to unconditionally apply. |
| 121 return; | 106 return; |
| 122 } | 107 } |
| 123 | 108 |
| 124 NSRect frame = [contentView_ frame]; | 109 // None of these locals are members of the Hall of Justice. |
| 125 if (apply) | 110 NSView* superview = [bookmarkBarView_ superview]; |
| 111 NSRect superframe = [superview frame]; |
| 112 NSRect frame = [bookmarkBarView_ frame]; |
| 113 NSRect webframe = [webContentView_ frame]; |
| 114 if (apply) { |
| 115 superframe.size.height += kBookmarkBarSuperviewHeightAdjustment; |
| 116 superframe.origin.y -= kBookmarkBarSuperviewHeightAdjustment; |
| 117 frame.size.height += kBookmarkBarHeight; |
| 118 webframe.size.height -= kBookmarkBarWebframeHeightAdjustment; |
| 119 } else { |
| 120 superframe.size.height -= kBookmarkBarSuperviewHeightAdjustment; |
| 121 superframe.origin.y += kBookmarkBarSuperviewHeightAdjustment; |
| 126 frame.size.height -= kBookmarkBarHeight; | 122 frame.size.height -= kBookmarkBarHeight; |
| 127 else | 123 webframe.size.height += kBookmarkBarWebframeHeightAdjustment; |
| 128 frame.size.height += kBookmarkBarHeight; | 124 } |
| 129 | 125 |
| 130 if (immediately) { | 126 // TODO(jrg): Animators can be a little fussy. Setting these three |
| 131 [contentView_ setFrame:frame]; | 127 // off can sometimes causes races where the finish isn't as |
| 132 [contentView_ setNeedsDisplay:YES]; | 128 // expected. Fix, or clean out the animators as an option. |
| 129 // Odd racing is FAR worse than a lack of an animator. |
| 130 if (1 /* immediately */) { |
| 131 [superview setFrame:superframe]; |
| 132 [webContentView_ setFrame:webframe]; |
| 133 [bookmarkBarView_ setFrame:frame]; |
| 133 } else { | 134 } else { |
| 134 [[contentView_ animator] setFrame:frame]; | 135 [[superview animator] setFrame:superframe]; |
| 136 [[webContentView_ animator] setFrame:webframe]; |
| 137 [[bookmarkBarView_ animator] setFrame:frame]; |
| 135 } | 138 } |
| 136 | 139 |
| 137 [bookmarkBarView_ setNeedsDisplay:YES]; | 140 [bookmarkBarView_ setNeedsDisplay:YES]; |
| 138 [contentView_ setNeedsDisplay:YES]; | 141 [superview setNeedsDisplay:YES]; |
| 142 [webContentView_ setNeedsDisplay:YES]; |
| 139 } | 143 } |
| 140 | 144 |
| 141 - (BOOL)isBookmarkBarVisible { | 145 - (BOOL)isBookmarkBarVisible { |
| 142 return barShouldBeShown_; | 146 return barShouldBeShown_; |
| 143 } | 147 } |
| 144 | 148 |
| 145 // We don't change a preference; we only change visibility. | 149 // We don't change a preference; we only change visibility. |
| 146 // Preference changing (global state) is handled in | 150 // Preference changing (global state) is handled in |
| 147 // BrowserWindowCocoa::ToggleBookmarkBar(). | 151 // BrowserWindowCocoa::ToggleBookmarkBar(). |
| 148 - (void)toggleBookmarkBar { | 152 - (void)toggleBookmarkBar { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 166 | 170 |
| 167 // Delete all items from the bookmark bar. | 171 // Delete all items from the bookmark bar. |
| 168 - (void)clearBookmarkBar { | 172 - (void)clearBookmarkBar { |
| 169 [bookmarkBarView_ setSubviews:[NSArray array]]; | 173 [bookmarkBarView_ setSubviews:[NSArray array]]; |
| 170 } | 174 } |
| 171 | 175 |
| 172 // TODO(jrg): add an openBookmarkInBackground() for ctrl-click which | 176 // TODO(jrg): add an openBookmarkInBackground() for ctrl-click which |
| 173 // has a different disposition. | 177 // has a different disposition. |
| 174 - (void)openBookmark:(id)sender { | 178 - (void)openBookmark:(id)sender { |
| 175 const BookmarkNode* node = static_cast<const BookmarkNode*>( | 179 const BookmarkNode* node = static_cast<const BookmarkNode*>( |
| 176 [[[sender cell]representedObject]pointerValue]); | 180 [[[sender cell] representedObject] pointerValue]); |
| 177 DCHECK(node); | 181 DCHECK(node); |
| 178 [delegate_ openBookmarkURL:node->GetURL() disposition:CURRENT_TAB]; | 182 [delegate_ openBookmarkURL:node->GetURL() disposition:CURRENT_TAB]; |
| 179 } | 183 } |
| 180 | 184 |
| 181 // Return an autoreleased NSCell suitable for a bookmark button. | 185 // Return an autoreleased NSCell suitable for a bookmark button. |
| 186 // TODO(jrg): move much of the cell config into the BookmarkButtonCell class. |
| 182 - (NSCell *)cellForBookmarkNode:(const BookmarkNode*)node frame:(NSRect)frame { | 187 - (NSCell *)cellForBookmarkNode:(const BookmarkNode*)node frame:(NSRect)frame { |
| 183 NSString* title = base::SysWideToNSString(node->GetTitle()); | 188 NSString* title = base::SysWideToNSString(node->GetTitle()); |
| 184 NSButtonCell *cell = [[[BookmarkButtonCell alloc] initTextCell:nil] | 189 NSButtonCell *cell = [[[BookmarkButtonCell alloc] initTextCell:nil] |
| 185 autorelease]; | 190 autorelease]; |
| 186 DCHECK(cell); | 191 DCHECK(cell); |
| 187 [cell setRepresentedObject:[NSValue valueWithPointer:node]]; | 192 [cell setRepresentedObject:[NSValue valueWithPointer:node]]; |
| 188 [cell setButtonType:NSMomentaryPushInButton]; | 193 [cell setButtonType:NSMomentaryPushInButton]; |
| 189 [cell setBezelStyle:NSShadowlessSquareBezelStyle]; | 194 [cell setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 190 [cell setShowsBorderOnlyWhileMouseInside:YES]; | 195 [cell setShowsBorderOnlyWhileMouseInside:YES]; |
| 191 | 196 |
| 192 // The favicon may be NULL if we haven't loaded it yet. Bookmarks | 197 // The favicon may be NULL if we haven't loaded it yet. Bookmarks |
| 193 // (and their icons) are loaded on the IO thread to speed launch. | 198 // (and their icons) are loaded on the IO thread to speed launch. |
| 194 const SkBitmap& favicon = bookmarkModel_->GetFavIcon(node); | 199 const SkBitmap& favicon = bookmarkModel_->GetFavIcon(node); |
| 195 if (!favicon.isNull()) { | 200 if (!favicon.isNull()) { |
| 196 NSImage* image = gfx::SkBitmapToNSImage(favicon); | 201 NSImage* image = gfx::SkBitmapToNSImage(favicon); |
| 197 if (image) { | 202 if (image) { |
| 198 [cell setImage:image]; | 203 [cell setImage:image]; |
| 199 [cell setImagePosition:NSImageLeft]; | 204 [cell setImagePosition:NSImageLeft]; |
| 200 } | 205 } |
| 201 } | 206 } |
| 202 | 207 |
| 203 [cell setTitle:title]; | 208 [cell setTitle:title]; |
| 204 [cell setControlSize:NSSmallControlSize]; | 209 [cell setControlSize:NSSmallControlSize]; |
| 205 [cell setAlignment:NSLeftTextAlignment]; | 210 [cell setAlignment:NSLeftTextAlignment]; |
| 206 [cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; | 211 [cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; |
| 207 [cell setWraps:NO]; | 212 [cell setWraps:NO]; |
| 208 [cell setLineBreakMode:NSLineBreakByTruncatingMiddle]; | 213 [cell setLineBreakMode:NSLineBreakByTruncatingMiddle]; |
| 209 [cell setBordered:NO]; | |
| 210 return cell; | 214 return cell; |
| 211 } | 215 } |
| 212 | 216 |
| 213 // TODO(jrg): accomodation for bookmarks less than minimum width in | 217 // TODO(jrg): accomodation for bookmarks less than minimum width in |
| 214 // size (like Windows)? | 218 // size (like Windows)? |
| 215 - (NSRect)frameForBookmarkAtIndex:(int)index { | 219 - (NSRect)frameForBookmarkAtIndex:(int)index { |
| 216 NSRect bounds = [[self view] bounds]; | 220 NSRect bounds = [[self view] bounds]; |
| 217 // TODO: be smarter about this; the animator delays the right height | 221 // TODO: be smarter about this; the animator delays the right height |
| 218 if (bounds.size.height == 0) | 222 if (bounds.size.height == 0) |
| 219 bounds.size.height = kBookmarkBarHeight; | 223 bounds.size.height = kBookmarkBarHeight; |
| 220 | 224 |
| 221 NSRect frame = NSInsetRect(bounds, | 225 NSRect frame = NSInsetRect(bounds, |
| 222 kBookmarkHorizontalPadding, | 226 kBookmarkHorizontalPadding, |
| 223 kBookmarkVerticalPadding); | 227 kBookmarkVerticalPadding); |
| 224 frame.origin.x += (kDefaultBookmarkWidth * index); | 228 frame.origin.x += (kDefaultBookmarkWidth * index); |
| 225 frame.size.width = kDefaultBookmarkWidth; | 229 frame.size.width = kDefaultBookmarkWidth; |
| 226 return frame; | 230 return frame; |
| 227 } | 231 } |
| 228 | 232 |
| 229 // Add all items from the given model to our bookmark bar. | 233 // Add all items from the given model to our bookmark bar. |
| 230 // TODO(jrg): lots of things! | 234 // TODO(jrg): lots of things! |
| 231 // - bookmark folders (e.g. menu from the button) | 235 // - bookmark folders (e.g. menu from the button) |
| 232 // - favicos | |
| 233 // - button and menu on the right for when bookmarks don't all fit on the | 236 // - button and menu on the right for when bookmarks don't all fit on the |
| 234 // screen | 237 // screen |
| 235 // - ... | 238 // - ... |
| 236 // | 239 // |
| 237 // TODO(jrg): contextual menu (e.g. Open In New Tab) for each button | 240 // TODO(jrg): contextual menu (e.g. Open In New Tab) for each button |
| 238 // in this function) | 241 // in this function) |
| 239 // | 242 // |
| 240 // TODO(jrg): write a "build bar" so there is a nice spot for things | 243 // TODO(jrg): write a "build bar" so there is a nice spot for things |
| 241 // like the contextual menu which is invoked when not over a | 244 // like the contextual menu which is invoked when not over a |
| 242 // bookmark. On Safari that menu has a "new folder" option. | 245 // bookmark. On Safari that menu has a "new folder" option. |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 // TODO(jrg): for now this is brute force. | 337 // TODO(jrg): for now this is brute force. |
| 335 - (void)nodeChildrenReordered:(BookmarkModel*)model | 338 - (void)nodeChildrenReordered:(BookmarkModel*)model |
| 336 node:(const BookmarkNode*)node { | 339 node:(const BookmarkNode*)node { |
| 337 [self loaded:model]; | 340 [self loaded:model]; |
| 338 } | 341 } |
| 339 | 342 |
| 340 - (NSView*)view { | 343 - (NSView*)view { |
| 341 return bookmarkBarView_; | 344 return bookmarkBarView_; |
| 342 } | 345 } |
| 343 | 346 |
| 347 - (void)setDelegate:(id<BookmarkURLOpener>)delegate { |
| 348 delegate_ = delegate; |
| 349 } |
| 350 |
| 344 @end | 351 @end |
| OLD | NEW |