1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h" 6 7 #include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h" 8 #include "chrome/browser/metrics/user_metrics.h" 9 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" 10 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" 11 #import "third_party/mozilla/NSPasteboard+Utils.h" 12 13 @implementation BookmarkBarFolderView 14 15 @synthesize dropIndicatorShown = dropIndicatorShown_; 16 @synthesize dropIndicatorPosition = dropIndicatorPosition_; 17 18 - (void)awakeFromNib { 19 NSArray* types = [NSArray arrayWithObjects: 20 NSStringPboardType, 21 NSHTMLPboardType, 22 NSURLPboardType, 23 kBookmarkButtonDragType, 24 kBookmarkDictionaryListPboardType, 25 nil]; 26 [self registerForDraggedTypes:types]; 27 } 28 29 - (void)dealloc { 30 [self unregisterDraggedTypes]; 31 [super dealloc]; 32 } 33 34 - (id<BookmarkButtonControllerProtocol>)controller { 35 // When needed for testing, set the local data member |controller_| to 36 // the test controller. 37 return controller_ ? controller_ : [[self window] windowController]; 38 } 39 40 - (void)setController:(id)controller { 41 controller_ = controller; 42 } 43 44 - (void)drawRect:(NSRect)rect { 45 // TODO(jrg): copied from bookmark_bar_view but orientation changed. 46 // Code dup sucks but I'm not sure I can take 16 lines and make it 47 // generic for horiz vs vertical while keeping things simple. 48 // TODO(jrg): when throwing it all away and using animations, try 49 // hard to make a common routine for both. 50 // http://crbug.com/35966, http://crbug.com/35968 51 52 // Draw the bookmark-button-dragging drop indicator if necessary. 53 if (dropIndicatorShown_) { 54 const CGFloat kBarHeight = 1; 55 const CGFloat kBarHorizPad = 4; 56 const CGFloat kBarOpacity = 0.85; 57 58 NSRect uglyBlackBar = 59 NSMakeRect(kBarHorizPad, dropIndicatorPosition_, 60 NSWidth([self bounds]) - 2*kBarHorizPad, 61 kBarHeight); 62 NSColor* uglyBlackBarColor = [NSColor blackColor]; 63 [[uglyBlackBarColor colorWithAlphaComponent:kBarOpacity] setFill]; 64 [[NSBezierPath bezierPathWithRect:uglyBlackBar] fill]; 65 } 66 } 67 68 // TODO(mrossetti,jrg): Identical to -[BookmarkBarView 69 // dragClipboardContainsBookmarks]. http://crbug.com/35966 70 // Shim function to assist in unit testing. 71 - (BOOL)dragClipboardContainsBookmarks { 72 return bookmark_pasteboard_helper_mac::DragClipboardContainsBookmarks(); 73 } 74 75 // Virtually identical to [BookmarkBarView draggingEntered:]. 76 // TODO(jrg): find a way to share code. Lack of multiple inheritance 77 // makes things more of a pain but there should be no excuse for laziness. 78 // http://crbug.com/35966 79 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info { 80 inDrag_ = YES; 81 if (![[self controller] draggingAllowed:info]) 82 return NSDragOperationNone; 83 if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] || 84 [self dragClipboardContainsBookmarks] || 85 [[info draggingPasteboard] containsURLData]) { 86 // Find the position of the drop indicator. 87 BOOL showIt = [[self controller] 88 shouldShowIndicatorShownForPoint:[info draggingLocation]]; 89 if (!showIt) { 90 if (dropIndicatorShown_) { 91 dropIndicatorShown_ = NO; 92 [self setNeedsDisplay:YES]; 93 } 94 } else { 95 CGFloat y = 96 [[self controller] 97 indicatorPosForDragToPoint:[info draggingLocation]]; 98 99 // Need an update if the indicator wasn't previously shown or if it has 100 // moved. 101 if (!dropIndicatorShown_ || dropIndicatorPosition_ != y) { 102 dropIndicatorShown_ = YES; 103 dropIndicatorPosition_ = y; 104 [self setNeedsDisplay:YES]; 105 } 106 } 107 108 [[self controller] draggingEntered:info]; // allow hover-open to work 109 return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy; 110 } 111 return NSDragOperationNone; 112 } 113 114 - (void)draggingExited:(id<NSDraggingInfo>)info { 115 [[self controller] draggingExited:info]; 116 117 // Regardless of the type of dragging which ended, we need to get rid of the 118 // drop indicator if one was shown. 119 if (dropIndicatorShown_) { 120 dropIndicatorShown_ = NO; 121 [self setNeedsDisplay:YES]; 122 } 123 } 124 125 - (void)draggingEnded:(id<NSDraggingInfo>)info { 126 // Awkwardness since views open and close out from under us. 127 if (inDrag_) { 128 inDrag_ = NO; 129 } 130 131 [self draggingExited:info]; 132 } 133 134 - (BOOL)wantsPeriodicDraggingUpdates { 135 // TODO(jrg): This should probably return |YES| and the controller should 136 // slide the existing bookmark buttons interactively to the side to make 137 // room for the about-to-be-dropped bookmark. 138 // http://crbug.com/35968 139 return NO; 140 } 141 142 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info { 143 // For now it's the same as draggingEntered:. 144 // TODO(jrg): once we return YES for wantsPeriodicDraggingUpdates, 145 // this should ping the [self controller] to perform animations. 146 // http://crbug.com/35968 147 return [self draggingEntered:info]; 148 } 149 150 - (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info { 151 return YES; 152 } 153 154 // This code is practically identical to the same function in BookmarkBarView 155 // with the only difference being how the controller is retrieved. 156 // TODO(mrossetti,jrg): http://crbug.com/35966 157 // Implement NSDraggingDestination protocol method 158 // performDragOperation: for URLs. 159 - (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info { 160 NSPasteboard* pboard = [info draggingPasteboard]; 161 DCHECK([pboard containsURLData]); 162 163 NSArray* urls = nil; 164 NSArray* titles = nil; 165 [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES]; 166 167 return [[self controller] addURLs:urls 168 withTitles:titles 169 at:[info draggingLocation]]; 170 } 171 172 // This code is practically identical to the same function in BookmarkBarView 173 // with the only difference being how the controller is retrieved. 174 // http://crbug.com/35966 175 // Implement NSDraggingDestination protocol method 176 // performDragOperation: for bookmark buttons. 177 - (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info { 178 BOOL doDrag = NO; 179 NSData* data = [[info draggingPasteboard] 180 dataForType:kBookmarkButtonDragType]; 181 // [info draggingSource] is nil if not the same application. 182 if (data && [info draggingSource]) { 183 BookmarkButton* button = nil; 184 [data getBytes:&button length:sizeof(button)]; 185 BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove); 186 doDrag = [[self controller] dragButton:button 187 to:[info draggingLocation] 188 copy:copy]; 189 UserMetrics::RecordAction(UserMetricsAction("BookmarkBarFolder_DragEnd")); 190 } 191 return doDrag; 192 } 193 194 - (BOOL)performDragOperation:(id<NSDraggingInfo>)info { 195 if ([[self controller] dragBookmarkData:info]) 196 return YES; 197 NSPasteboard* pboard = [info draggingPasteboard]; 198 if ([pboard dataForType:kBookmarkButtonDragType] && 199 [self performDragOperationForBookmarkButton:info]) 200 return YES; 201 if ([pboard containsURLData] && [self performDragOperationForURL:info]) 202 return YES; 203 return NO; 204 } 205 206 @end 207