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