• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2010 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/bookmarks/bookmark_pasteboard_helper_mac.h"
8#include "chrome/browser/metrics/user_metrics.h"
9#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
10#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
11#import "third_party/mozilla/NSPasteboard+Utils.h"
12
13@implementation BookmarkBarFolderView
14
15@synthesize dropIndicatorShown = dropIndicatorShown_;
16@synthesize dropIndicatorPosition = dropIndicatorPosition_;
17
18- (void)awakeFromNib {
19  NSArray* types = [NSArray arrayWithObjects:
20                    NSStringPboardType,
21                    NSHTMLPboardType,
22                    NSURLPboardType,
23                    kBookmarkButtonDragType,
24                    kBookmarkDictionaryListPboardType,
25                    nil];
26  [self registerForDraggedTypes:types];
27}
28
29- (void)dealloc {
30  [self unregisterDraggedTypes];
31  [super dealloc];
32}
33
34- (id<BookmarkButtonControllerProtocol>)controller {
35  // When needed for testing, set the local data member |controller_| to
36  // the test controller.
37  return controller_ ? controller_ : [[self window] windowController];
38}
39
40- (void)setController:(id)controller {
41  controller_ = controller;
42}
43
44- (void)drawRect:(NSRect)rect {
45  // TODO(jrg): copied from bookmark_bar_view but orientation changed.
46  // Code dup sucks but I'm not sure I can take 16 lines and make it
47  // generic for horiz vs vertical while keeping things simple.
48  // TODO(jrg): when throwing it all away and using animations, try
49  // hard to make a common routine for both.
50  // http://crbug.com/35966, http://crbug.com/35968
51
52  // Draw the bookmark-button-dragging drop indicator if necessary.
53  if (dropIndicatorShown_) {
54    const CGFloat kBarHeight = 1;
55    const CGFloat kBarHorizPad = 4;
56    const CGFloat kBarOpacity = 0.85;
57
58    NSRect uglyBlackBar =
59        NSMakeRect(kBarHorizPad, dropIndicatorPosition_,
60                   NSWidth([self bounds]) - 2*kBarHorizPad,
61                   kBarHeight);
62    NSColor* uglyBlackBarColor = [NSColor blackColor];
63    [[uglyBlackBarColor colorWithAlphaComponent:kBarOpacity] setFill];
64    [[NSBezierPath bezierPathWithRect:uglyBlackBar] fill];
65  }
66}
67
68// TODO(mrossetti,jrg): Identical to -[BookmarkBarView
69// dragClipboardContainsBookmarks].  http://crbug.com/35966
70// Shim function to assist in unit testing.
71- (BOOL)dragClipboardContainsBookmarks {
72  return bookmark_pasteboard_helper_mac::DragClipboardContainsBookmarks();
73}
74
75// Virtually identical to [BookmarkBarView draggingEntered:].
76// TODO(jrg): find a way to share code.  Lack of multiple inheritance
77// makes things more of a pain but there should be no excuse for laziness.
78// http://crbug.com/35966
79- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
80  inDrag_ = YES;
81  if (![[self controller] draggingAllowed:info])
82    return NSDragOperationNone;
83  if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] ||
84      [self dragClipboardContainsBookmarks] ||
85      [[info draggingPasteboard] containsURLData]) {
86    // Find the position of the drop indicator.
87    BOOL showIt = [[self controller]
88                   shouldShowIndicatorShownForPoint:[info draggingLocation]];
89    if (!showIt) {
90      if (dropIndicatorShown_) {
91        dropIndicatorShown_ = NO;
92        [self setNeedsDisplay:YES];
93      }
94    } else {
95      CGFloat y =
96      [[self controller]
97       indicatorPosForDragToPoint:[info draggingLocation]];
98
99      // Need an update if the indicator wasn't previously shown or if it has
100      // moved.
101      if (!dropIndicatorShown_ || dropIndicatorPosition_ != y) {
102        dropIndicatorShown_ = YES;
103        dropIndicatorPosition_ = y;
104        [self setNeedsDisplay:YES];
105      }
106    }
107
108    [[self controller] draggingEntered:info];  // allow hover-open to work
109    return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy;
110  }
111  return NSDragOperationNone;
112}
113
114- (void)draggingExited:(id<NSDraggingInfo>)info {
115  [[self controller] draggingExited:info];
116
117  // Regardless of the type of dragging which ended, we need to get rid of the
118  // drop indicator if one was shown.
119  if (dropIndicatorShown_) {
120    dropIndicatorShown_ = NO;
121    [self setNeedsDisplay:YES];
122  }
123}
124
125- (void)draggingEnded:(id<NSDraggingInfo>)info {
126  // Awkwardness since views open and close out from under us.
127  if (inDrag_) {
128    inDrag_ = NO;
129  }
130
131  [self draggingExited:info];
132}
133
134- (BOOL)wantsPeriodicDraggingUpdates {
135  // TODO(jrg): This should probably return |YES| and the controller should
136  // slide the existing bookmark buttons interactively to the side to make
137  // room for the about-to-be-dropped bookmark.
138  // http://crbug.com/35968
139  return NO;
140}
141
142- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
143  // For now it's the same as draggingEntered:.
144  // TODO(jrg): once we return YES for wantsPeriodicDraggingUpdates,
145  // this should ping the [self controller] to perform animations.
146  // http://crbug.com/35968
147  return [self draggingEntered:info];
148}
149
150- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
151  return YES;
152}
153
154// This code is practically identical to the same function in BookmarkBarView
155// with the only difference being how the controller is retrieved.
156// TODO(mrossetti,jrg): http://crbug.com/35966
157// Implement NSDraggingDestination protocol method
158// performDragOperation: for URLs.
159- (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info {
160  NSPasteboard* pboard = [info draggingPasteboard];
161  DCHECK([pboard containsURLData]);
162
163  NSArray* urls = nil;
164  NSArray* titles = nil;
165  [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
166
167  return [[self controller] addURLs:urls
168                         withTitles:titles
169                                 at:[info draggingLocation]];
170}
171
172// This code is practically identical to the same function in BookmarkBarView
173// with the only difference being how the controller is retrieved.
174// http://crbug.com/35966
175// Implement NSDraggingDestination protocol method
176// performDragOperation: for bookmark buttons.
177- (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info {
178  BOOL doDrag = NO;
179  NSData* data = [[info draggingPasteboard]
180                   dataForType:kBookmarkButtonDragType];
181  // [info draggingSource] is nil if not the same application.
182  if (data && [info draggingSource]) {
183    BookmarkButton* button = nil;
184    [data getBytes:&button length:sizeof(button)];
185    BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
186    doDrag = [[self controller] dragButton:button
187                                        to:[info draggingLocation]
188                                      copy:copy];
189    UserMetrics::RecordAction(UserMetricsAction("BookmarkBarFolder_DragEnd"));
190  }
191  return doDrag;
192}
193
194- (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
195  if ([[self controller] dragBookmarkData:info])
196    return YES;
197  NSPasteboard* pboard = [info draggingPasteboard];
198  if ([pboard dataForType:kBookmarkButtonDragType] &&
199      [self performDragOperationForBookmarkButton:info])
200    return YES;
201  if ([pboard containsURLData] && [self performDragOperationForURL:info])
202    return YES;
203  return NO;
204}
205
206@end
207