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