bookmark_bar_view.mm revision bb1529ce867d8845a77ec7cdf3e3003ef1771a40
1// Copyright (c) 2011 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/profiles/profile.h" 9#import "chrome/browser/themes/theme_properties.h" 10#import "chrome/browser/themes/theme_service.h" 11#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" 12#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" 13#import "chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controller.h" 14#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h" 15#import "chrome/browser/ui/cocoa/browser_window_controller.h" 16#import "chrome/browser/ui/cocoa/themed_window.h" 17#import "chrome/browser/ui/cocoa/view_id_util.h" 18#include "content/public/browser/user_metrics.h" 19#import "third_party/mozilla/NSPasteboard+Utils.h" 20 21using content::UserMetricsAction; 22 23@interface BookmarkBarView (Private) 24- (void)themeDidChangeNotification:(NSNotification*)aNotification; 25- (void)updateTheme:(ui::ThemeProvider*)themeProvider; 26@end 27 28@implementation BookmarkBarView 29 30@synthesize dropIndicatorShown = dropIndicatorShown_; 31@synthesize dropIndicatorPosition = dropIndicatorPosition_; 32@synthesize noItemContainer = noItemContainer_; 33 34 35- (void)dealloc { 36 [[NSNotificationCenter defaultCenter] removeObserver:self]; 37 // This probably isn't strictly necessary, but can't hurt. 38 [self unregisterDraggedTypes]; 39 [super dealloc]; 40 41 // To be clear, our controller_ is an IBOutlet and owns us, so we 42 // don't deallocate it explicitly. It is owned by the browser 43 // window controller, so gets deleted with a browser window is 44 // closed. 45} 46 47- (void)awakeFromNib { 48 NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; 49 [defaultCenter addObserver:self 50 selector:@selector(themeDidChangeNotification:) 51 name:kBrowserThemeDidChangeNotification 52 object:nil]; 53 54 DCHECK(controller_) << "Expected this to be hooked up via Interface Builder"; 55 NSArray* types = [NSArray arrayWithObjects: 56 NSStringPboardType, 57 NSHTMLPboardType, 58 NSURLPboardType, 59 kBookmarkButtonDragType, 60 kBookmarkDictionaryListPboardType, 61 nil]; 62 [self registerForDraggedTypes:types]; 63} 64 65// We need the theme to color the bookmark buttons properly. But our 66// controller desn't have access to it until it's placed in the view 67// hierarchy. This is the spot where we close the loop. 68- (void)viewWillMoveToWindow:(NSWindow*)window { 69 ui::ThemeProvider* themeProvider = [window themeProvider]; 70 [self updateTheme:themeProvider]; 71 [controller_ updateTheme:themeProvider]; 72 [super viewWillMoveToWindow:window]; 73} 74 75- (void)viewDidMoveToWindow { 76 [controller_ viewDidMoveToWindow]; 77} 78 79// Called after a theme change took place, possibly for a different profile. 80- (void)themeDidChangeNotification:(NSNotification*)notification { 81 [self updateTheme:[[self window] themeProvider]]; 82} 83 84// Adapt appearance to the current theme. Called after theme changes and before 85// this is shown for the first time. 86- (void)updateTheme:(ui::ThemeProvider*)themeProvider { 87 if (!themeProvider) 88 return; 89 90 NSColor* color = 91 themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT); 92 [noItemTextfield_ setTextColor:color]; 93} 94 95// Mouse down events on the bookmark bar should not allow dragging the parent 96// window around. 97- (BOOL)mouseDownCanMoveWindow { 98 return NO; 99} 100 101- (BookmarkBarTextField*)noItemTextfield { 102 return noItemTextfield_; 103} 104 105- (NSButton*)importBookmarksButton { 106 return importBookmarksButton_; 107} 108 109- (BookmarkBarController*)controller { 110 return controller_; 111} 112 113// Internal method, needs to be called whenever a change has been made to 114// dropIndicatorShown_ or dropIndicatorPosition_ so it can get the controller 115// to reflect the change by moving buttons around. 116- (void)dropIndicatorChanged { 117 if (dropIndicatorShown_) 118 [controller_ setDropInsertionPos:dropIndicatorPosition_]; 119 else 120 [controller_ clearDropInsertionPos]; 121} 122 123// Shim function to assist in unit testing. 124- (BOOL)dragClipboardContainsBookmarks { 125 return bookmark_pasteboard_helper_mac::PasteboardContainsBookmarks( 126 bookmark_pasteboard_helper_mac::kDragPasteboard); 127} 128 129// NSDraggingDestination methods 130 131- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info { 132 if (![controller_ draggingAllowed:info]) 133 return NSDragOperationNone; 134 if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] || 135 [self dragClipboardContainsBookmarks] || 136 [[info draggingPasteboard] containsURLData]) { 137 // We only show the drop indicator if we're not in a position to 138 // perform a hover-open since it doesn't make sense to do both. 139 BOOL showIt = [controller_ shouldShowIndicatorShownForPoint: 140 [info draggingLocation]]; 141 if (!showIt) { 142 if (dropIndicatorShown_) { 143 dropIndicatorShown_ = NO; 144 [self dropIndicatorChanged]; 145 } 146 } else { 147 CGFloat x = 148 [controller_ indicatorPosForDragToPoint:[info draggingLocation]]; 149 // Need an update if the indicator wasn't previously shown or if it has 150 // moved. 151 if (!dropIndicatorShown_ || dropIndicatorPosition_ != x) { 152 dropIndicatorShown_ = YES; 153 dropIndicatorPosition_ = x; 154 [self dropIndicatorChanged]; 155 } 156 } 157 158 [controller_ draggingEntered:info]; // allow hover-open to work. 159 return [[info draggingSource] isKindOfClass: [BookmarkButton class]] ? 160 NSDragOperationMove : NSDragOperationCopy; 161 } 162 return NSDragOperationNone; 163} 164 165- (void)draggingExited:(id<NSDraggingInfo>)info { 166 [controller_ draggingExited:info]; 167 168 // Regardless of the type of dragging which ended, we need to get rid of the 169 // drop indicator if one was shown. 170 if (dropIndicatorShown_) { 171 dropIndicatorShown_ = NO; 172 [self dropIndicatorChanged]; 173 } 174} 175 176- (void)draggingEnded:(id<NSDraggingInfo>)info { 177 [controller_ draggingEnded:info]; 178 179 [[BookmarkButton draggedButton] setHidden:NO]; 180 if (dropIndicatorShown_) { 181 dropIndicatorShown_ = NO; 182 [self dropIndicatorChanged]; 183 } 184 [controller_ draggingEnded:info]; 185} 186 187- (BOOL)wantsPeriodicDraggingUpdates { 188 return YES; 189} 190 191- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info { 192 // For now it's the same as draggingEntered:. 193 return [self draggingEntered:info]; 194} 195 196- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info { 197 return YES; 198} 199 200// Implement NSDraggingDestination protocol method 201// performDragOperation: for URLs. 202- (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info { 203 NSPasteboard* pboard = [info draggingPasteboard]; 204 DCHECK([pboard containsURLData]); 205 206 NSArray* urls = nil; 207 NSArray* titles = nil; 208 [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES]; 209 210 return [controller_ addURLs:urls 211 withTitles:titles 212 at:[info draggingLocation]]; 213} 214 215// Implement NSDraggingDestination protocol method 216// performDragOperation: for bookmark buttons. 217- (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info { 218 BOOL rtn = NO; 219 NSData* data = [[info draggingPasteboard] 220 dataForType:kBookmarkButtonDragType]; 221 // [info draggingSource] is nil if not the same application. 222 if (data && [info draggingSource]) { 223 BookmarkButton* button = nil; 224 [data getBytes:&button length:sizeof(button)]; 225 226 // If we're dragging from one profile to another, disallow moving (only 227 // allow copying). Each profile has its own bookmark model, so one way to 228 // check whether we are dragging across profiles is to see if the 229 // |BookmarkNode| corresponding to |button| exists in this profile. If it 230 // does, we're dragging within a profile; otherwise, we're dragging across 231 // profiles. 232 const BookmarkModel* const model = [[self controller] bookmarkModel]; 233 const BookmarkNode* const source_node = [button bookmarkNode]; 234 const BookmarkNode* const target_node = 235 model->GetNodeByID(source_node->id()); 236 237 BOOL copy = 238 !([info draggingSourceOperationMask] & NSDragOperationMove) || 239 (source_node != target_node); 240 rtn = [controller_ dragButton:button 241 to:[info draggingLocation] 242 copy:copy]; 243 content::RecordAction(UserMetricsAction("BookmarkBar_DragEnd")); 244 } 245 return rtn; 246} 247 248- (BOOL)performDragOperation:(id<NSDraggingInfo>)info { 249 if ([controller_ dragBookmarkData:info]) 250 return YES; 251 NSPasteboard* pboard = [info draggingPasteboard]; 252 if ([pboard dataForType:kBookmarkButtonDragType]) { 253 if ([self performDragOperationForBookmarkButton:info]) 254 return YES; 255 // Fall through.... 256 } 257 if ([pboard containsURLData]) { 258 if ([self performDragOperationForURL:info]) 259 return YES; 260 } 261 return NO; 262} 263 264- (NSMenu*)menu { 265 return [[controller_ menuController] menuForBookmarkNode:NULL]; 266} 267 268- (void)setController:(id)controller { 269 controller_ = controller; 270} 271 272- (ViewID)viewID { 273 return VIEW_ID_BOOKMARK_BAR; 274} 275 276@end // @implementation BookmarkBarView 277 278@implementation BookmarkBarTextField 279 280- (NSMenu*)menu { 281 return [barView_ menu]; 282} 283 284@end // @implementation BookmarkBarTextField 285 286@implementation BookmarkBarItemContainer 287 288- (NSMenu*)menu { 289 return [barView_ menu]; 290} 291 292@end // @implementation BookmarkBarItemContainer 293