Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / bookmarks / bookmark_bar_folder_view.mm
blobcf12996a41007d802a51c3cc904f9a1cfdd1c990
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_folder_view.h"
7 #include "chrome/browser/profiles/profile.h"
8 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
9 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
10 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
11 #include "components/bookmarks/browser/bookmark_pasteboard_helper_mac.h"
12 #include "components/bookmarks/browser/bookmark_utils.h"
13 #include "content/public/browser/user_metrics.h"
15 using base::UserMetricsAction;
16 using bookmarks::BookmarkModel;
17 using bookmarks::BookmarkNode;
19 #import "third_party/mozilla/NSPasteboard+Utils.h"
21 @interface BookmarkBarFolderView()
23 @property(readonly, nonatomic) id<BookmarkButtonControllerProtocol> controller;
25 - (void)setDropIndicatorShown:(BOOL)flag;
27 @end
29 @implementation BookmarkBarFolderView
31 - (void)awakeFromNib {
32   NSArray* types = [NSArray arrayWithObjects:
33                     NSStringPboardType,
34                     NSHTMLPboardType,
35                     NSURLPboardType,
36                     kBookmarkButtonDragType,
37                     kBookmarkDictionaryListPboardType,
38                     nil];
39   [self registerForDraggedTypes:types];
42 - (void)dealloc {
43   [self unregisterDraggedTypes];
44   [super dealloc];
47 - (id<BookmarkButtonControllerProtocol>)controller {
48   // When needed for testing, set the local data member |controller_| to
49   // the test controller.
50   return controller_ ? controller_ : [[self window] windowController];
53 // Virtually identical to [BookmarkBarView draggingEntered:].
54 // TODO(jrg): find a way to share code.  Lack of multiple inheritance
55 // makes things more of a pain but there should be no excuse for laziness.
56 // http://crbug.com/35966
57 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
58   inDrag_ = YES;
59   if (![[self controller] draggingAllowed:info])
60     return NSDragOperationNone;
61   if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] ||
62       bookmarks::PasteboardContainsBookmarks(ui::CLIPBOARD_TYPE_DRAG) ||
63       [[info draggingPasteboard] containsURLData]) {
64     // Find the position of the drop indicator.
65     BOOL showIt = [[self controller]
66                    shouldShowIndicatorShownForPoint:[info draggingLocation]];
67     if (!showIt) {
68       [self setDropIndicatorShown:NO];
69     } else {
70       [self setDropIndicatorShown:YES];
72       CGFloat y = [[self controller]
73           indicatorPosForDragToPoint:[info draggingLocation]];
74       NSRect frame = [dropIndicator_ frame];
75       if (NSMinY(frame) != y) {
76         frame.origin.y = y;
77         [dropIndicator_ setFrame:frame];
78       }
79     }
81     [[self controller] draggingEntered:info];  // allow hover-open to work
82     return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy;
83   }
84   return NSDragOperationNone;
87 - (void)draggingExited:(id<NSDraggingInfo>)info {
88   [[self controller] draggingExited:info];
90   // Regardless of the type of dragging which ended, we need to get rid of the
91   // drop indicator if one was shown.
92   [self setDropIndicatorShown:NO];
95 - (void)draggingEnded:(id<NSDraggingInfo>)info {
96   // Awkwardness since views open and close out from under us.
97   if (inDrag_) {
98     inDrag_ = NO;
99   }
101   [self draggingExited:info];
104 - (BOOL)wantsPeriodicDraggingUpdates {
105   // TODO(jrg): The controller should slide the existing bookmark buttons
106   // interactively to the side to make room for the about-to-be-dropped
107   // bookmark.
108   // http://crbug.com/35968
110   // The bookmark_bar_folder_hover_state expects continuous callbacks.
111   return YES;
114 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
115   // For now it's the same as draggingEntered:.
116   // TODO(jrg): once we return YES for wantsPeriodicDraggingUpdates,
117   // this should ping the [self controller] to perform animations.
118   // http://crbug.com/35968
119   return [self draggingEntered:info];
122 - (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
123   return YES;
126 // This code is practically identical to the same function in BookmarkBarView
127 // with the only difference being how the controller is retrieved.
128 // TODO(mrossetti,jrg): http://crbug.com/35966
129 // Implement NSDraggingDestination protocol method
130 // performDragOperation: for URLs.
131 - (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info {
132   NSPasteboard* pboard = [info draggingPasteboard];
133   DCHECK([pboard containsURLData]);
135   NSArray* urls = nil;
136   NSArray* titles = nil;
137   [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
139   return [[self controller] addURLs:urls
140                          withTitles:titles
141                                  at:[info draggingLocation]];
144 // This code is practically identical to the same function in BookmarkBarView
145 // with the only difference being how the controller is retrieved.
146 // http://crbug.com/35966
147 // Implement NSDraggingDestination protocol method
148 // performDragOperation: for bookmark buttons.
149 - (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info {
150   BOOL doDrag = NO;
151   NSData* data = [[info draggingPasteboard]
152                    dataForType:kBookmarkButtonDragType];
153   // [info draggingSource] is nil if not the same application.
154   if (data && [info draggingSource]) {
155     BookmarkButton* button = nil;
156     [data getBytes:&button length:sizeof(button)];
158     // If we're dragging from one profile to another, disallow moving (only
159     // allow copying). Each profile has its own bookmark model, so one way to
160     // check whether we are dragging across profiles is to see if the
161     // |BookmarkNode| corresponding to |button| exists in this profile. If it
162     // does, we're dragging within a profile; otherwise, we're dragging across
163     // profiles.
164     const BookmarkModel* const model = [[self controller] bookmarkModel];
165     const BookmarkNode* const source_node = [button bookmarkNode];
166     const BookmarkNode* const target_node =
167         bookmarks::GetBookmarkNodeByID(model, source_node->id());
169     BOOL copy =
170         !([info draggingSourceOperationMask] & NSDragOperationMove) ||
171         (source_node != target_node);
172     doDrag = [[self controller] dragButton:button
173                                         to:[info draggingLocation]
174                                       copy:copy];
175     content::RecordAction(UserMetricsAction("BookmarkBarFolder_DragEnd"));
176   }
177   return doDrag;
180 - (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
181   if ([[self controller] dragBookmarkData:info])
182     return YES;
183   NSPasteboard* pboard = [info draggingPasteboard];
184   if ([pboard dataForType:kBookmarkButtonDragType] &&
185       [self performDragOperationForBookmarkButton:info])
186     return YES;
187   if ([pboard containsURLData] && [self performDragOperationForURL:info])
188     return YES;
189   return NO;
192 - (void)setDropIndicatorShown:(BOOL)flag {
193   if (dropIndicatorShown_ == flag)
194     return;
196   dropIndicatorShown_ = flag;
197   if (dropIndicatorShown_) {
198     NSRect frame = NSInsetRect([self bounds], 4, 0);
199     frame.size.height = 1;
200     dropIndicator_.reset([[NSBox alloc] initWithFrame:frame]);
201     [dropIndicator_ setBoxType:NSBoxSeparator];
202     [dropIndicator_ setBorderType:NSLineBorder];
203     [dropIndicator_ setAlphaValue:0.85];
204     [self addSubview:dropIndicator_];
205   } else {
206     [dropIndicator_ removeFromSuperview];
207     dropIndicator_.reset();
208   }
211 @end