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