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;
29 @implementation BookmarkBarFolderView
31 - (void)awakeFromNib {
32 NSArray* types = [NSArray arrayWithObjects:
36 kBookmarkButtonDragType,
37 kBookmarkDictionaryListPboardType,
39 [self registerForDraggedTypes:types];
43 [self unregisterDraggedTypes];
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 {
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]];
68 [self setDropIndicatorShown:NO];
70 [self setDropIndicatorShown:YES];
72 CGFloat y = [[self controller]
73 indicatorPosForDragToPoint:[info draggingLocation]];
74 NSRect frame = [dropIndicator_ frame];
75 if (NSMinY(frame) != y) {
77 [dropIndicator_ setFrame:frame];
81 [[self controller] draggingEntered:info]; // allow hover-open to work
82 return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy;
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.
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
108 // http://crbug.com/35968
110 // The bookmark_bar_folder_hover_state expects continuous callbacks.
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 {
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]);
136 NSArray* titles = nil;
137 [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
139 return [[self controller] addURLs:urls
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 {
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
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());
170 !([info draggingSourceOperationMask] & NSDragOperationMove) ||
171 (source_node != target_node);
172 doDrag = [[self controller] dragButton:button
173 to:[info draggingLocation]
175 content::RecordAction(UserMetricsAction("BookmarkBarFolder_DragEnd"));
180 - (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
181 if ([[self controller] dragBookmarkData:info])
183 NSPasteboard* pboard = [info draggingPasteboard];
184 if ([pboard dataForType:kBookmarkButtonDragType] &&
185 [self performDragOperationForBookmarkButton:info])
187 if ([pboard containsURLData] && [self performDragOperationForURL:info])
192 - (void)setDropIndicatorShown:(BOOL)flag {
193 if (dropIndicatorShown_ == flag)
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_];
206 [dropIndicator_ removeFromSuperview];
207 dropIndicator_.reset();