diff --git a/mozilla/camino/src/bookmarks/BookmarkManager.h b/mozilla/camino/src/bookmarks/BookmarkManager.h index 7079427a4df..eb671403e98 100644 --- a/mozilla/camino/src/bookmarks/BookmarkManager.h +++ b/mozilla/camino/src/bookmarks/BookmarkManager.h @@ -97,6 +97,7 @@ const int kBookmarksContextMenuArrangeSeparatorTag = 100; + (NSArray*)serializableArrayWithBookmarkItems:(NSArray*)bmArray; + (NSArray*)bookmarkItemsFromSerializableArray:(NSArray*)bmArray; ++ (NSArray*)bookmarkURLsFromSerializableArray:(NSArray*)bmArray; // Getters/Setters - (BookmarkFolder *)rootBookmarks; diff --git a/mozilla/camino/src/bookmarks/BookmarkManager.mm b/mozilla/camino/src/bookmarks/BookmarkManager.mm index 540faa8665b..2ae1be56d83 100644 --- a/mozilla/camino/src/bookmarks/BookmarkManager.mm +++ b/mozilla/camino/src/bookmarks/BookmarkManager.mm @@ -184,6 +184,21 @@ static BookmarkManager* gBookmarkManager = nil; return itemsArray; } ++ (NSArray*)bookmarkURLsFromSerializableArray:(NSArray*)dataArray +{ + NSArray* bookmarkItems = [self bookmarkItemsFromSerializableArray:dataArray]; + NSMutableArray* bookmarkURLs = [NSMutableArray arrayWithCapacity:[bookmarkItems count]]; + NSEnumerator* enumerator = [bookmarkItems objectEnumerator]; + BookmarkItem* aBookmark; + while ((aBookmark = [enumerator nextObject])) { + if ([aBookmark isKindOfClass:[Bookmark class]] && ![aBookmark isSeparator]) + [bookmarkURLs addObject:[(Bookmark*)aBookmark url]]; + else if ([aBookmark isKindOfClass:[BookmarkFolder class]]) + [bookmarkURLs addObjectsFromArray:[(BookmarkFolder*)aBookmark childURLs]]; + } + return bookmarkURLs; +} + // return a string with the "canonical" bookmark url (strip trailing slashes, lowercase) + (NSString*)canonicalBookmarkURL:(NSString*)inBookmarkURL { diff --git a/mozilla/camino/src/bookmarks/BookmarkToolbar.mm b/mozilla/camino/src/bookmarks/BookmarkToolbar.mm index dbdcdcc9dc8..47e77c4a911 100644 --- a/mozilla/camino/src/bookmarks/BookmarkToolbar.mm +++ b/mozilla/camino/src/bookmarks/BookmarkToolbar.mm @@ -618,7 +618,7 @@ static const int kBMBarScanningStep = 5; // NSDraggingDestination /////////// -- (unsigned int)draggingEntered:(id )sender +- (NSDragOperation)draggingEntered:(id )sender { // we have to set the drag target before we can test for drop validation [self setButtonInsertionPoint:sender]; @@ -648,7 +648,7 @@ static const int kBMBarScanningStep = 5; mDragInsertionPosition = CHInsertNone; } -- (unsigned int)draggingUpdated:(id )sender +- (NSDragOperation)draggingUpdated:(id )sender { if (mDragInsertionPosition) [self setNeedsDisplayInRect:[self insertionHiliteRectForButton:mDragInsertionButton position:mDragInsertionPosition]]; diff --git a/mozilla/camino/src/browser/BrowserTabBarView.mm b/mozilla/camino/src/browser/BrowserTabBarView.mm index 965b913d103..88488087b39 100644 --- a/mozilla/camino/src/browser/BrowserTabBarView.mm +++ b/mozilla/camino/src/browser/BrowserTabBarView.mm @@ -719,8 +719,11 @@ static const float kScrollButtonInterval = 0.15; // time (in seconds) between f #pragma mark - // NSDraggingDestination destination methods --(unsigned int)draggingEntered:(id )sender +-(NSDragOperation)draggingEntered:(id )sender { + if (![mTabView shouldAcceptDrag:sender]) + return NSDragOperationNone; + mDragOverBar = YES; [self setNeedsDisplay:YES]; @@ -738,7 +741,7 @@ static const float kScrollButtonInterval = 0.15; // time (in seconds) between f -(BOOL)prepareForDragOperation:(id )sender { - return [mTabView prepareForDragOperation:sender]; + return YES; } -(BOOL)performDragOperation:(id )sender @@ -746,7 +749,7 @@ static const float kScrollButtonInterval = 0.15; // time (in seconds) between f mDragOverBar = NO; [self setNeedsDisplay:YES]; - return [mTabView performDragOperation:sender]; + return [mTabView handleDrop:sender onTab:nil]; } @end diff --git a/mozilla/camino/src/browser/BrowserTabView.h b/mozilla/camino/src/browser/BrowserTabView.h index a0ff3b75b2d..2bb9d543131 100644 --- a/mozilla/camino/src/browser/BrowserTabView.h +++ b/mozilla/camino/src/browser/BrowserTabView.h @@ -48,8 +48,6 @@ extern NSString* const kTabBarBackgroundDoubleClickedNotification; @interface BrowserTabView : NSTabView { BOOL mBarAlwaysVisible; - BOOL mIsDropTarget; - BOOL mLastClickIsPotentialDrag; BOOL mVisible; // YES if the view is in the hierarchy IBOutlet BrowserTabBarView * mTabBar; @@ -79,6 +77,12 @@ extern NSString* const kTabBarBackgroundDoubleClickedNotification; - (BOOL)windowShouldClose; - (void)windowClosed; +// Returns YES if |dragInfo| is a valid drag for a tab or the tab bar, NO if not. +- (BOOL)shouldAcceptDrag:(id )dragInfo; +// Handle drag and drop of one or more URLs; returns YES if the drop was valid. +// If |targetTab| is nil, then the drop is on the tab bar background. +- (BOOL)handleDrop:(id )dragInfo onTab:(NSTabViewItem*)targetTab; + // get and set the "jumpback tab", the tab that is jumped to when the currently // visible tab is closed. Reset automatically when switching tabs or after // jumping back. This isn't designed to be a tab history, it only lives for a very diff --git a/mozilla/camino/src/browser/BrowserTabView.mm b/mozilla/camino/src/browser/BrowserTabView.mm index 3baac1672bf..d834e3c6357 100644 --- a/mozilla/camino/src/browser/BrowserTabView.mm +++ b/mozilla/camino/src/browser/BrowserTabView.mm @@ -44,8 +44,6 @@ #import "BrowserTabViewItem.h" #import "TabButtonView.h" #import "BrowserWrapper.h" -#import "BookmarkFolder.h" -#import "Bookmark.h" #import "BookmarkManager.h" #import "BrowserTabBarView.h" #import "BrowserWindowController.h" @@ -64,17 +62,11 @@ NSString* const kTabBarBackgroundDoubleClickedNotification = @"kTabBarBackground @interface BrowserTabView (Private) - (void)showOrHideTabsAsAppropriate; -- (void)handleDropOnTab:(NSTabViewItem*)targetTab withURLs:(NSArray*)urls; -- (BrowserTabViewItem*)getTabViewItemFromWindowPoint:(NSPoint)point; -- (void)showDragDestinationIndicator; -- (void)hideDragDestinationIndicator; - +- (NSArray*)urlsFromPasteboard:(NSPasteboard*)pasteboard; @end #pragma mark - -#define kTabDropTargetHeight 18.0 - @implementation BrowserTabView /******************************************/ @@ -95,9 +87,6 @@ NSString* const kTabBarBackgroundDoubleClickedNotification = @"kTabBarBackground mBarAlwaysVisible = NO; mVisible = YES; [self showOrHideTabsAsAppropriate]; - [self registerForDraggedTypes:[NSArray arrayWithObjects: - kCaminoBookmarkListPBoardType, kWebURLsWithTitlesPboardType, - NSStringPboardType, NSFilenamesPboardType, NSURLPboardType, nil]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tabWillChange:) name:kTabWillChangeNotifcation object:nil]; } @@ -112,21 +101,6 @@ NSString* const kTabBarBackgroundDoubleClickedNotification = @"kTabBarBackground /*** Overridden Methods ***/ /******************************************/ -- (void)drawRect:(NSRect)aRect -{ - if (mIsDropTarget) - { - NSRect hilightRect = aRect; - hilightRect.size.height = kTabDropTargetHeight; // no need to move origin.y; our coords are flipped - NSBezierPath* dropTargetOutline = [NSBezierPath bezierPathWithRect:hilightRect]; - - [[[NSColor colorForControlTint:NSDefaultControlTint] colorWithAlphaComponent:0.5] set]; - [dropTargetOutline fill]; - } - - [super drawRect:aRect]; -} - - (void)addTabViewItem:(NSTabViewItem *)tabViewItem { // creating a new tab means clearing the jumpback tab. @@ -344,122 +318,40 @@ NSString* const kTabBarBackgroundDoubleClickedNotification = @"kTabBarBackground [self showOrHideTabsAsAppropriate]; } -- (BrowserTabViewItem*)getTabViewItemFromWindowPoint:(NSPoint)point -{ - NSPoint localPoint = [self convertPoint: point fromView: nil]; - NSTabViewItem* overTabViewItem = [self tabViewItemAtPoint: localPoint]; - return (BrowserTabViewItem*)overTabViewItem; -} - -- (void)showDragDestinationIndicator -{ - if (!mIsDropTarget) - { - NSRect invalidRect = [self bounds]; - invalidRect.size.height = kTabDropTargetHeight; - [self setNeedsDisplayInRect:invalidRect]; - mIsDropTarget = YES; - } -} - -- (void)hideDragDestinationIndicator -{ - if (mIsDropTarget) - { - NSRect invalidRect = [self bounds]; - invalidRect.size.height = kTabDropTargetHeight; - [self setNeedsDisplayInRect:invalidRect]; - mIsDropTarget = NO; - } -} - #pragma mark - +// Drag helpers for tabs and the tab bar. -// NSDraggingDestination /////////// - -- (unsigned int)draggingEntered:(id )sender +// Private method to extract recognized URL types from the pasteboard. +- (NSArray*)urlsFromPasteboard:(NSPasteboard*)pasteboard { - NSPoint localPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; - NSTabViewItem* overTabViewItem = [self tabViewItemAtPoint: localPoint]; - - if (overTabViewItem) - return NSDragOperationNone; // the tab will handle it - - [self showDragDestinationIndicator]; // XXX optimize - return NSDragOperationGeneric; -} - -- (unsigned int)draggingUpdated:(id )sender -{ - NSPoint localPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; - NSTabViewItem* overTabViewItem = [self tabViewItemAtPoint: localPoint]; - - if (overTabViewItem) - return NSDragOperationNone; // the tab will handle it - - [self showDragDestinationIndicator]; - return NSDragOperationGeneric; -} - -- (void)draggingExited:(id )sender -{ - [self hideDragDestinationIndicator]; -} - -- (BOOL)prepareForDragOperation:(id )sender -{ - return YES; -} - -- (BOOL)performDragOperation:(id )sender -{ - [self hideDragDestinationIndicator]; - NSArray* urls = nil; - NSArray* pasteBoardTypes = [[sender draggingPasteboard] types]; + NSArray* pasteBoardTypes = [pasteboard types]; if ([pasteBoardTypes containsObject:kCaminoBookmarkListPBoardType]) { - NSArray* bookmarkUUIDs = [[sender draggingPasteboard] propertyListForType:kCaminoBookmarkListPBoardType]; - NSArray* draggedItems = [BookmarkManager bookmarkItemsFromSerializableArray:bookmarkUUIDs]; - - NSMutableArray* bookmarkURLs = [NSMutableArray arrayWithCapacity:[draggedItems count]]; - BookmarkItem* aBookmark; - NSEnumerator* enumerator = [draggedItems objectEnumerator]; - while ((aBookmark = [enumerator nextObject])) { - if ([aBookmark isKindOfClass:[Bookmark class]] && ![aBookmark isSeparator]) - [bookmarkURLs addObject:[(Bookmark*)aBookmark url]]; - else if ([aBookmark isKindOfClass:[BookmarkFolder class]]) - [bookmarkURLs addObjectsFromArray:[(BookmarkFolder*)aBookmark childURLs]]; - } - urls = bookmarkURLs; + NSArray* bookmarkUUIDs = [pasteboard propertyListForType:kCaminoBookmarkListPBoardType]; + urls = [BookmarkManager bookmarkURLsFromSerializableArray:bookmarkUUIDs]; } - else if ([[sender draggingPasteboard] containsURLData]) { + else if ([pasteboard containsURLData]) { NSArray* titles; // discarded - [[sender draggingPasteboard] getURLs:&urls andTitles:&titles]; + [pasteboard getURLs:&urls andTitles:&titles]; } + return urls; +} - if (!urls || [urls count] == 0) +- (BOOL)shouldAcceptDrag:(id )dragInfo +{ + // This must stay in sync with the behavior of urlsForDrag:; we don't just + // call through to it because it does more work than we need for a yes/no. + NSArray* pasteBoardTypes = [[dragInfo draggingPasteboard] types]; + return ([pasteBoardTypes containsObject:kCaminoBookmarkListPBoardType] || + [[dragInfo draggingPasteboard] containsURLData]); +} + +- (BOOL)handleDrop:(id )dragInfo onTab:(NSTabViewItem*)targetTab +{ + NSArray* urls = [self urlsFromPasteboard:[dragInfo draggingPasteboard]]; + if ([urls count] == 0) return NO; - // determine if we are over a tab or the content area - NSPoint localPoint = [self convertPoint:[sender draggingLocation] fromView: nil]; - NSTabViewItem* targetTab; - if (NSPointInRect(localPoint, [self contentRect])) // drop is on content area - targetTab = [self selectedTabViewItem]; - else - targetTab = [self tabViewItemAtPoint:localPoint]; - // if there's no tabviewitem at the point within our view, check the tab bar. - if (!targetTab) - targetTab = [mTabBar tabViewItemAtPoint:[sender draggingLocation]]; - - [self handleDropOnTab:targetTab withURLs:urls]; - - return YES; -} - -// Private method to handle drag and drop of one or more URLs. If |targetTab| is nil, -// then the drop is on the tab bar background, as opposed to a tab or its content area. -- (void)handleDropOnTab:(NSTabViewItem*)targetTab withURLs:(NSArray*)urls -{ if ([urls count] == 1) { NSString* url = [urls objectAtIndex:0]; BOOL loadInBackground = [BrowserWindowController shouldLoadInBackgroundForDestination:eDestinationNewTab @@ -477,6 +369,7 @@ NSString* const kTabBarBackgroundDoubleClickedNotification = @"kTabBarBackground else { [[[self window] windowController] openURLArray:urls tabOpenPolicy:(targetTab ? eReplaceTabs : eAppendTabs) allowPopups:NO]; } + return YES; } #pragma mark - diff --git a/mozilla/camino/src/browser/BrowserTabViewItem.h b/mozilla/camino/src/browser/BrowserTabViewItem.h index c5302dac2ce..d7a07121172 100644 --- a/mozilla/camino/src/browser/BrowserTabViewItem.h +++ b/mozilla/camino/src/browser/BrowserTabViewItem.h @@ -85,4 +85,9 @@ extern NSString* const kTabWillChangeNotifcation; + (NSImage*)closeIconPressed; + (NSImage*)closeIconHover; +// Returns YES if |sender| is a valid drag for a tab, NO if not. +- (BOOL)shouldAcceptDrag:(id )dragInfo; +// Handle drag and drop of one or more URLs; returns YES if the drop was valid. +- (BOOL)handleDrop:(id )dragInfo; + @end diff --git a/mozilla/camino/src/browser/BrowserTabViewItem.mm b/mozilla/camino/src/browser/BrowserTabViewItem.mm index 29d5b03c140..d4ce8c86ce7 100644 --- a/mozilla/camino/src/browser/BrowserTabViewItem.mm +++ b/mozilla/camino/src/browser/BrowserTabViewItem.mm @@ -44,6 +44,7 @@ #import "BrowserTabView.h" #import "TabButtonView.h" +#import "BrowserWindowController.h" #import "BrowserWrapper.h" #import "TruncatingTextAndImageCell.h" @@ -211,4 +212,25 @@ const int kMenuTruncationChars = 60; return sCloseIconHover; } +#pragma mark - + +- (BOOL)shouldAcceptDrag:(id )dragInfo +{ + id dragSource = [dragInfo draggingSource]; + if ((dragSource == self) || (dragSource == mTabButtonView)) + return NO; + + // TODO: find another way to do this that doesn't involve knowledge about BWC. + BrowserWindowController *windowController = (BrowserWindowController *)[[[self view] window] windowController]; + if (dragSource == [windowController proxyIconView]) + return NO; + + return [(BrowserTabView*)[self tabView] shouldAcceptDrag:dragInfo]; +} + +- (BOOL)handleDrop:(id )dragInfo +{ + return [(BrowserTabView*)[self tabView] handleDrop:dragInfo onTab:self]; +} + @end diff --git a/mozilla/camino/src/browser/TabButtonView.mm b/mozilla/camino/src/browser/TabButtonView.mm index cfeb859e4b0..a965f2e6936 100644 --- a/mozilla/camino/src/browser/TabButtonView.mm +++ b/mozilla/camino/src/browser/TabButtonView.mm @@ -44,7 +44,6 @@ #import "NSString+Utils.h" #import "BrowserTabViewItem.h" -#import "BrowserWindowController.h" #import "BrowserWrapper.h" #import "RolloverImageButton.h" #import "TruncatingTextAndImageCell.h" @@ -360,27 +359,17 @@ static NSImage* sTabButtonDividerImage = nil; } } -- (BOOL)shouldAcceptDragFrom:(id)sender -{ - if ((sender == self) || (sender == mTabViewItem)) - return NO; - - NSWindowController *windowController = [[[mTabViewItem view] window] windowController]; - if ([windowController isMemberOfClass:[BrowserWindowController class]]) { - if (sender == [(BrowserWindowController *)windowController proxyIconView]) - return NO; - } - - return YES; -} - // NSDraggingDestination destination methods -- (unsigned int)draggingEntered:(id )sender +- (NSDragOperation)draggingEntered:(id )sender { - if (![self shouldAcceptDragFrom:[sender draggingSource]]) + if (![mTabViewItem shouldAcceptDrag:sender]) return NSDragOperationNone; [self setDragTarget:YES]; + + if ([sender draggingSourceOperationMask] & NSDragOperationCopy) + return NSDragOperationCopy; + return NSDragOperationGeneric; } @@ -398,11 +387,7 @@ static NSImage* sTabButtonDividerImage = nil; { [self setDragTarget:NO]; - if (![self shouldAcceptDragFrom:[sender draggingSource]]) - return NO; - - // let the tab view handle it - return [[mTabViewItem tabView] performDragOperation:sender]; + return [mTabViewItem handleDrop:sender]; } #pragma mark -