diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller.h | 10 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller.mm | 74 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller_unittest.mm | 35 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_view.mm | 23 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_view_unittest.mm | 1 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_button.h | 19 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_button.mm | 42 |
7 files changed, 160 insertions, 44 deletions
diff --git a/chrome/browser/cocoa/bookmark_bar_controller.h b/chrome/browser/cocoa/bookmark_bar_controller.h index e80cfa1..8ab0e8c 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.h +++ b/chrome/browser/cocoa/bookmark_bar_controller.h @@ -13,6 +13,7 @@ #include "chrome/browser/cocoa/bookmark_bar_bridge.h" #import "chrome/browser/cocoa/bookmark_bar_state.h" #import "chrome/browser/cocoa/bookmark_bar_toolbar_view.h" +#import "chrome/browser/cocoa/bookmark_button.h" #include "chrome/browser/cocoa/tab_strip_model_observer_bridge.h" #include "webkit/glue/window_open_disposition.h" @@ -66,7 +67,9 @@ willAnimateFromState:(bookmarks::VisualState)oldState // A controller for the bookmark bar in the browser window. Handles showing // and hiding based on the preference in the given profile. @interface BookmarkBarController : - NSViewController<BookmarkBarState, BookmarkBarToolbarViewController> { + NSViewController<BookmarkBarState, + BookmarkBarToolbarViewController, + BookmarkButtonDelegate> { @private // The visual state of the bookmark bar. If an animation is running, this is // set to the "destination" and |lastVisualState_| is set to the "original" @@ -242,4 +245,9 @@ willAnimateFromState:(bookmarks::VisualState)oldState - (void)updateTheme:(GTMTheme*)theme; @end +// The (internal) |NSPasteboard| type string for bookmark button drags, used for +// dragging buttons around the bookmark bar. The data for this type is just a +// pointer to the |BookmarkButton| being dragged. +extern NSString* kBookmarkButtonDragType; + #endif // CHROME_BROWSER_COCOA_BOOKMARK_BAR_CONTROLLER_H_ diff --git a/chrome/browser/cocoa/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmark_bar_controller.mm index 79e505a..73a8715 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller.mm @@ -98,6 +98,8 @@ // |-bookmarkBar:willAnimateFromState:toState:| in order to inform the // toolbar of required changes. +NSString* kBookmarkButtonDragType = @"ChromiumBookmarkButtonDragType"; + namespace { // Overlap (in pixels) between the toolbar and the bookmark bar (when showing in @@ -150,6 +152,11 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; - (int)indexForDragOfButton:(BookmarkButton*)sourceButton toPoint:(NSPoint)point; +// Copies the given bookmark node to the given pasteboard, declaring appropriate +// types (to paste a URL with a title). +- (void)copyBookmarkNode:(const BookmarkNode*)node + toPasteboard:(NSPasteboard*)pboard; + - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu; - (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu; - (void)tagEmptyMenu:(NSMenu*)menu; @@ -215,6 +222,13 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; //TODO(dmaclach): Remove -- http://crbug.com/25845 [[self view] removeFromSuperview]; + // For safety, make sure the buttons can no longer call us. + for (BookmarkButton* button in buttons_.get()) { + [button setDelegate:nil]; + [button setTarget:nil]; + [button setAction:nil]; + } + bridge_.reset(NULL); [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; @@ -863,13 +877,9 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; - (IBAction)copyBookmark:(id)sender { BookmarkNode* node = [self nodeFromMenuItem:sender]; - const std::string spec = node->GetURL().spec(); - NSString* url = base::SysUTF8ToNSString(spec); - NSString* title = base::SysWideToNSString(node->GetTitle()); - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - [pasteboard declareURLPasteboardWithAdditionalTypes:[NSArray array] - owner:nil]; - [pasteboard setDataForURL:url title:title]; + NSPasteboard* pboard = [NSPasteboard generalPasteboard]; + [self copyBookmarkNode:node + toPasteboard:pboard]; } - (IBAction)deleteBookmark:(id)sender { @@ -1059,9 +1069,9 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; NSCell* cell = [self cellForBookmarkNode:child]; NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:&xOffset]; - NSButton* button = [[[BookmarkButton alloc] initWithFrame:frame] - autorelease]; - DCHECK(button); + scoped_nsobject<BookmarkButton> + button([[BookmarkButton alloc] initWithFrame:frame]); + DCHECK(button.get()); [buttons_ addObject:button]; // [NSButton setCell:] warns to NOT use setCell: other than in the @@ -1070,6 +1080,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; // object. To honor the assumed semantics, we do nothing with // NSButton between alloc/init and setCell:. [button setCell:cell]; + [button setDelegate:self]; if (child->is_folder()) { [button setTarget:self]; @@ -1163,6 +1174,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; // Peg at right; keep same height as bar. [button setAutoresizingMask:(NSViewMinXMargin)]; [button setCell:cell]; + [button setDelegate:self]; [button setTarget:self]; [button setAction:@selector(openFolderMenuFromButton:)]; [buttonView_ addSubview:button]; @@ -1379,6 +1391,31 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; [[self animatableView] stopAnimation]; } +// (Private) +- (void)copyBookmarkNode:(const BookmarkNode*)node + toPasteboard:(NSPasteboard*)pboard { + if (!node) { + NOTREACHED(); + return; + } + + if (node->is_folder()) { + // TODO(viettrungluu): I'm not sure what we should do, so just declare the + // "additional" types we're given for now. Maybe we want to add a list of + // URLs? Would we then have to recurse if there were subfolders? + // In the meanwhile, we *must* set it to a known state. (If this survives to + // a 10.6-only release, it can be replaced with |-clearContents|.) + [pboard declareTypes:[NSArray array] owner:nil]; + } else { + const std::string spec = node->GetURL().spec(); + NSString* url = base::SysUTF8ToNSString(spec); + NSString* title = base::SysWideToNSString(node->GetTitle()); + [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array] + owner:nil]; + [pboard setDataForURL:url title:title]; + } +} + // Delegate method for |AnimatableView| (a superclass of // |BookmarkBarToolbarView|). - (void)animationDidEnd:(NSAnimation*)animation { @@ -1444,4 +1481,21 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; return 0; } +// (BookmarkButtonDelegate protocol) +- (void)fillPasteboard:(NSPasteboard*)pboard + forDragOfButton:(BookmarkButton*)button { + if (BookmarkNode* node = [self nodeFromButton:button]) { + // Put the bookmark information into the pasteboard, and then write our own + // data for |kBookmarkButtonDragType|. + [self copyBookmarkNode:node + toPasteboard:pboard]; + [pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType] + owner:nil]; + [pboard setData:[NSData dataWithBytes:&button length:sizeof(button)] + forType:kBookmarkButtonDragType]; + } else { + NOTREACHED(); + } +} + @end diff --git a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm index 91c9fb4..345b96e 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm @@ -10,6 +10,7 @@ #import "chrome/browser/cocoa/bookmark_bar_constants.h" #import "chrome/browser/cocoa/bookmark_bar_controller.h" #import "chrome/browser/cocoa/bookmark_bar_view.h" +#import "chrome/browser/cocoa/bookmark_button.h" #import "chrome/browser/cocoa/bookmark_menu.h" #include "chrome/browser/cocoa/browser_test_helper.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" @@ -893,6 +894,40 @@ TEST_F(BookmarkBarControllerTest, TestThemedButton) { } } +// Test that delegates and targets of buttons are cleared on dealloc. +TEST_F(BookmarkBarControllerTest, TestClearOnDealloc) { + // Make some bookmark buttons. + BookmarkModel* model = helper_.profile()->GetBookmarkModel(); + GURL gurls[] = { GURL("http://www.foo.com/"), + GURL("http://www.bar.com/"), + GURL("http://www.baz.com/") }; + std::wstring titles[] = { L"foo", L"bar", L"baz" }; + for (size_t i = 0; i < arraysize(titles); i++) + model->SetURLStarred(gurls[i], titles[i], true); + + // Get and retain the buttons so we can examine them after dealloc. + scoped_nsobject<NSArray> buttons([[bar_ buttons] retain]); + EXPECT_EQ([buttons count], arraysize(titles)); + + // Make sure that everything is set. + for (BookmarkButton* button in buttons.get()) { + ASSERT_TRUE([button isKindOfClass:[BookmarkButton class]]); + EXPECT_TRUE([button delegate]); + EXPECT_TRUE([button target]); + EXPECT_TRUE([button action]); + } + + // This will dealloc.... + bar_.reset(); + + // Make sure that everything is cleared. + for (BookmarkButton* button in buttons.get()) { + EXPECT_FALSE([button delegate]); + EXPECT_FALSE([button target]); + EXPECT_FALSE([button action]); + } +} + // TODO(viettrungluu): figure out how to test animations. } // namespace diff --git a/chrome/browser/cocoa/bookmark_bar_view.mm b/chrome/browser/cocoa/bookmark_bar_view.mm index 2b6d69c..fd7bbe8 100644 --- a/chrome/browser/cocoa/bookmark_bar_view.mm +++ b/chrome/browser/cocoa/bookmark_bar_view.mm @@ -99,8 +99,6 @@ // NSDraggingDestination methods - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info { - if ([[info draggingPasteboard] containsURLData]) - return NSDragOperationCopy; if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType]) { NSData* data = [[info draggingPasteboard] dataForType:kBookmarkButtonDragType]; @@ -120,10 +118,13 @@ dropIndicatorPosition_ = x; [self setNeedsDisplay:YES]; } - } - return NSDragOperationMove; + return NSDragOperationMove; + } + // Fall through otherwise. } + if ([[info draggingPasteboard] containsURLData]) + return NSDragOperationCopy; return NSDragOperationNone; } @@ -191,14 +192,16 @@ - (BOOL)performDragOperation:(id<NSDraggingInfo>)info { NSPasteboard* pboard = [info draggingPasteboard]; + if ([pboard dataForType:kBookmarkButtonDragType]) { + if ([self performDragOperationForBookmark:info]) + return YES; + // Fall through.... + } if ([pboard containsURLData]) { - return [self performDragOperationForURL:info]; - } else if ([pboard dataForType:kBookmarkButtonDragType]) { - return [self performDragOperationForBookmark:info]; - } else { - NOTREACHED() << "Unknown drop type onto bookmark bar."; - return NO; + if ([self performDragOperationForURL:info]) + return YES; } + return NO; } @end // @implementation BookmarkBarView diff --git a/chrome/browser/cocoa/bookmark_bar_view_unittest.mm b/chrome/browser/cocoa/bookmark_bar_view_unittest.mm index fabe97d..e99dda1 100644 --- a/chrome/browser/cocoa/bookmark_bar_view_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_view_unittest.mm @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/scoped_nsobject.h" +#import "chrome/browser/cocoa/bookmark_bar_controller.h" #import "chrome/browser/cocoa/bookmark_bar_view.h" #import "chrome/browser/cocoa/bookmark_button.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" diff --git a/chrome/browser/cocoa/bookmark_button.h b/chrome/browser/cocoa/bookmark_button.h index ea3decc..631a7ba 100644 --- a/chrome/browser/cocoa/bookmark_button.h +++ b/chrome/browser/cocoa/bookmark_button.h @@ -4,12 +4,15 @@ #import <Cocoa/Cocoa.h> +@protocol BookmarkButtonDelegate; + // Class for bookmark bar buttons that can be drag sources. @interface BookmarkButton : NSButton { @private BOOL draggable_; // Is this a draggable type of button? BOOL mayDragStart_; // Set to YES on mouse down, NO on up or drag. BOOL beingDragged_; + id<BookmarkButtonDelegate> delegate_; // Initial mouse-down to prevent a hair-trigger drag. NSPoint initialMouseDownLocation_; @@ -18,7 +21,19 @@ // Enable or disable dragability for special buttons like "Other Bookmarks". @property BOOL draggable; -@end +@property(assign, nonatomic) id<BookmarkButtonDelegate> delegate; + +@end // @interface BookmarkButton + +// Protocol for a |BookmarkButton|'s delegate, which is responsible for doing +// things which require information about the bookmark represented by this +// button. +@protocol BookmarkButtonDelegate -extern NSString* kBookmarkButtonDragType; +// Fill the given pasteboard with appropriate data when the given button is +// dragged. Since the delegate has no way of providing pasteboard data later, +// all data must actually be put into the pasteboard and not merely promised. +- (void)fillPasteboard:(NSPasteboard*)pboard + forDragOfButton:(BookmarkButton*)button; +@end // @protocol BookmarkButtonDelegate diff --git a/chrome/browser/cocoa/bookmark_button.mm b/chrome/browser/cocoa/bookmark_button.mm index 38b549f..55c95f6 100644 --- a/chrome/browser/cocoa/bookmark_button.mm +++ b/chrome/browser/cocoa/bookmark_button.mm @@ -8,8 +8,6 @@ #import "chrome/browser/cocoa/bookmark_button_cell.h" #import "third_party/GTM/AppKit/GTMTheme.h" -NSString* kBookmarkButtonDragType = @"ChromiumBookmarkButtonDragType"; - namespace { // Code taken from <http://codereview.chromium.org/180036/diff/3001/3004>. @@ -32,6 +30,7 @@ const CGFloat kDragImageOpacity = 0.7; @implementation BookmarkButton @synthesize draggable = draggable_; +@synthesize delegate = delegate_; - (id)initWithFrame:(NSRect)frame { if ((self = [super initWithFrame:frame])) { @@ -49,28 +48,28 @@ const CGFloat kDragImageOpacity = 0.7; // Starting drag. Never start another drag until another mouse down. mayDragStart_ = NO; - NSSize dragOffset = NSMakeSize(0.0, 0.0); - NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - [pboard declareTypes:[NSArray arrayWithObject:kBookmarkButtonDragType] - owner:self]; + if (delegate_) { + // Ask our delegate to fill the pasteboard for us. + NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - // This NSData is no longer referenced once the function ends so - // there is no need to retain/release when placing in here as an - // opaque pointer. - [pboard setData:[NSData dataWithBytes:&self length:sizeof(self)] - forType:kBookmarkButtonDragType]; + [delegate_ fillPasteboard:pboard forDragOfButton:self]; - // At the moment, moving bookmarks causes their buttons (like me!) - // to be destroyed and rebuilt. Make sure we don't go away while on - // the stack. - [self retain]; + // At the moment, moving bookmarks causes their buttons (like me!) + // to be destroyed and rebuilt. Make sure we don't go away while on + // the stack. + [self retain]; - CGFloat yAt = [self bounds].size.height; - [self dragImage:[self dragImage] at:NSMakePoint(0, yAt) offset:dragOffset - event:event pasteboard:pboard source:self slideBack:YES]; + CGFloat yAt = [self bounds].size.height; + NSSize dragOffset = NSMakeSize(0.0, 0.0); + [self dragImage:[self dragImage] at:NSMakePoint(0, yAt) offset:dragOffset + event:event pasteboard:pboard source:self slideBack:YES]; - // And we're done. - [self autorelease]; + // And we're done. + [self autorelease]; + } else { + // Avoid blowing up, but we really shouldn't get here. + NOTREACHED(); + } } - (void)draggedImage:(NSImage*)anImage @@ -81,7 +80,8 @@ const CGFloat kDragImageOpacity = 0.7; } - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { - return isLocal ? NSDragOperationMove : NSDragOperationNone; + return isLocal ? NSDragOperationCopy | NSDragOperationMove + : NSDragOperationCopy; } - (void)mouseUp:(NSEvent*)theEvent { |