bookmark_bar_view.mm revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
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_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_button.h" 11#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" 12#import "chrome/browser/ui/cocoa/themed_window.h" 13#import "chrome/browser/ui/cocoa/view_id_util.h" 14#import "chrome/browser/themes/browser_theme_provider.h" 15#import "third_party/mozilla/NSPasteboard+Utils.h" 16 17@interface BookmarkBarView (Private) 18- (void)themeDidChangeNotification:(NSNotification*)aNotification; 19- (void)updateTheme:(ThemeProvider*)themeProvider; 20@end 21 22@implementation BookmarkBarView 23 24@synthesize dropIndicatorShown = dropIndicatorShown_; 25@synthesize dropIndicatorPosition = dropIndicatorPosition_; 26@synthesize noItemContainer = noItemContainer_; 27 28- (void)dealloc { 29 [[NSNotificationCenter defaultCenter] removeObserver:self]; 30 // This probably isn't strictly necessary, but can't hurt. 31 [self unregisterDraggedTypes]; 32 [super dealloc]; 33 34 // To be clear, our controller_ is an IBOutlet and owns us, so we 35 // don't deallocate it explicitly. It is owned by the browser 36 // window controller, so gets deleted with a browser window is 37 // closed. 38} 39 40- (void)awakeFromNib { 41 NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; 42 [defaultCenter addObserver:self 43 selector:@selector(themeDidChangeNotification:) 44 name:kBrowserThemeDidChangeNotification 45 object:nil]; 46 47 DCHECK(controller_) << "Expected this to be hooked up via Interface Builder"; 48 NSArray* types = [NSArray arrayWithObjects: 49 NSStringPboardType, 50 NSHTMLPboardType, 51 NSURLPboardType, 52 kBookmarkButtonDragType, 53 kBookmarkDictionaryListPboardType, 54 nil]; 55 [self registerForDraggedTypes:types]; 56} 57 58// We need the theme to color the bookmark buttons properly. But our 59// controller desn't have access to it until it's placed in the view 60// hierarchy. This is the spot where we close the loop. 61- (void)viewWillMoveToWindow:(NSWindow*)window { 62 ThemeProvider* themeProvider = [window themeProvider]; 63 [self updateTheme:themeProvider]; 64 [controller_ updateTheme:themeProvider]; 65} 66 67- (void)viewDidMoveToWindow { 68 [controller_ viewDidMoveToWindow]; 69} 70 71// Called after the current theme has changed. 72- (void)themeDidChangeNotification:(NSNotification*)aNotification { 73 ThemeProvider* themeProvider = 74 static_cast<ThemeProvider*>([[aNotification object] pointerValue]); 75 [self updateTheme:themeProvider]; 76} 77 78// Adapt appearance to the current theme. Called after theme changes and before 79// this is shown for the first time. 80- (void)updateTheme:(ThemeProvider*)themeProvider { 81 if (!themeProvider) 82 return; 83 84 NSColor* color = 85 themeProvider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT, 86 true); 87 [noItemTextfield_ setTextColor:color]; 88} 89 90// Mouse down events on the bookmark bar should not allow dragging the parent 91// window around. 92- (BOOL)mouseDownCanMoveWindow { 93 return NO; 94} 95 96-(NSTextField*)noItemTextfield { 97 return noItemTextfield_; 98} 99 100-(NSButton*)importBookmarksButton { 101 return importBookmarksButton_; 102} 103 104- (BookmarkBarController*)controller { 105 return controller_; 106} 107 108-(void)drawRect:(NSRect)dirtyRect { 109 [super drawRect:dirtyRect]; 110 111 // Draw the bookmark-button-dragging drop indicator if necessary. 112 if (dropIndicatorShown_) { 113 const CGFloat kBarWidth = 1; 114 const CGFloat kBarHalfWidth = kBarWidth / 2.0; 115 const CGFloat kBarVertPad = 4; 116 const CGFloat kBarOpacity = 0.85; 117 118 // Prevent the indicator from being clipped on the left. 119 CGFloat xLeft = MAX(dropIndicatorPosition_ - kBarHalfWidth, 0); 120 121 NSRect uglyBlackBar = 122 NSMakeRect(xLeft, kBarVertPad, 123 kBarWidth, NSHeight([self bounds]) - 2 * kBarVertPad); 124 NSColor* uglyBlackBarColor = [[self window] themeProvider]-> 125 GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT, true); 126 [[uglyBlackBarColor colorWithAlphaComponent:kBarOpacity] setFill]; 127 [[NSBezierPath bezierPathWithRect:uglyBlackBar] fill]; 128 } 129} 130 131// Shim function to assist in unit testing. 132- (BOOL)dragClipboardContainsBookmarks { 133 return bookmark_pasteboard_helper_mac::DragClipboardContainsBookmarks(); 134} 135 136// NSDraggingDestination methods 137 138- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info { 139 if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] || 140 [self dragClipboardContainsBookmarks] || 141 [[info draggingPasteboard] containsURLData]) { 142 // We only show the drop indicator if we're not in a position to 143 // perform a hover-open since it doesn't make sense to do both. 144 BOOL showIt = [controller_ shouldShowIndicatorShownForPoint: 145 [info draggingLocation]]; 146 if (!showIt) { 147 if (dropIndicatorShown_) { 148 dropIndicatorShown_ = NO; 149 [self setNeedsDisplay:YES]; 150 } 151 } else { 152 CGFloat x = 153 [controller_ indicatorPosForDragToPoint:[info draggingLocation]]; 154 // Need an update if the indicator wasn't previously shown or if it has 155 // moved. 156 if (!dropIndicatorShown_ || dropIndicatorPosition_ != x) { 157 dropIndicatorShown_ = YES; 158 dropIndicatorPosition_ = x; 159 [self setNeedsDisplay:YES]; 160 } 161 } 162 163 [controller_ draggingEntered:info]; // allow hover-open to work. 164 return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy; 165 } 166 return NSDragOperationNone; 167} 168 169- (void)draggingExited:(id<NSDraggingInfo>)info { 170 // Regardless of the type of dragging which ended, we need to get rid of the 171 // drop indicator if one was shown. 172 if (dropIndicatorShown_) { 173 dropIndicatorShown_ = NO; 174 [self setNeedsDisplay:YES]; 175 } 176} 177 178- (void)draggingEnded:(id<NSDraggingInfo>)info { 179 // For now, we just call |-draggingExited:|. 180 [self draggingExited:info]; 181} 182 183- (BOOL)wantsPeriodicDraggingUpdates { 184 // TODO(port): This should probably return |YES| and the controller should 185 // slide the existing bookmark buttons interactively to the side to make 186 // room for the about-to-be-dropped bookmark. 187 return NO; 188} 189 190- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info { 191 // For now it's the same as draggingEntered:. 192 // TODO(jrg): once we return YES for wantsPeriodicDraggingUpdates, 193 // this should ping the controller_ to perform animations. 194 return [self draggingEntered:info]; 195} 196 197- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info { 198 return YES; 199} 200 201// Implement NSDraggingDestination protocol method 202// performDragOperation: for URLs. 203- (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info { 204 NSPasteboard* pboard = [info draggingPasteboard]; 205 DCHECK([pboard containsURLData]); 206 207 NSArray* urls = nil; 208 NSArray* titles = nil; 209 [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES]; 210 211 return [controller_ addURLs:urls 212 withTitles:titles 213 at:[info draggingLocation]]; 214} 215 216// Implement NSDraggingDestination protocol method 217// performDragOperation: for bookmark buttons. 218- (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info { 219 BOOL rtn = NO; 220 NSData* data = [[info draggingPasteboard] 221 dataForType:kBookmarkButtonDragType]; 222 // [info draggingSource] is nil if not the same application. 223 if (data && [info draggingSource]) { 224 BookmarkButton* button = nil; 225 [data getBytes:&button length:sizeof(button)]; 226 BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove); 227 rtn = [controller_ dragButton:button 228 to:[info draggingLocation] 229 copy:copy]; 230 UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragEnd")); 231 } 232 return rtn; 233} 234 235- (BOOL)performDragOperation:(id<NSDraggingInfo>)info { 236 if ([controller_ dragBookmarkData:info]) 237 return YES; 238 NSPasteboard* pboard = [info draggingPasteboard]; 239 if ([pboard dataForType:kBookmarkButtonDragType]) { 240 if ([self performDragOperationForBookmarkButton:info]) 241 return YES; 242 // Fall through.... 243 } 244 if ([pboard containsURLData]) { 245 if ([self performDragOperationForURL:info]) 246 return YES; 247 } 248 return NO; 249} 250 251- (void)setController:(id)controller { 252 controller_ = controller; 253} 254 255- (ViewID)viewID { 256 return VIEW_ID_BOOKMARK_BAR; 257} 258 259@end // @implementation BookmarkBarView 260