Home | History | Annotate | Download | only in bookmarks
      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