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