Home | History | Annotate | Download | only in bookmarks
      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_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_button.h"
     11 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
     12 #import "chrome/browser/ui/cocoa/themed_window.h"
     13 #import "chrome/browser/ui/cocoa/view_id_util.h"
     14 #import "chrome/browser/themes/theme_service.h"
     15 #import "third_party/mozilla/NSPasteboard+Utils.h"
     16 
     17 @interface BookmarkBarView (Private)
     18 - (void)themeDidChangeNotification:(NSNotification*)aNotification;
     19 - (void)updateTheme:(ui::ThemeProvider*)themeProvider;
     20 @end
     21 
     22 @implementation BookmarkBarView
     23 
     24 @synthesize dropIndicatorShown = dropIndicatorShown_;
     25 @synthesize dropIndicatorPosition = dropIndicatorPosition_;
     26 @synthesize noItemContainer = noItemContainer_;
     27 
     28 
     29 - (void)dealloc {
     30   [[NSNotificationCenter defaultCenter] removeObserver:self];
     31   // This probably isn't strictly necessary, but can't hurt.
     32   [self unregisterDraggedTypes];
     33   [super dealloc];
     34 
     35   // To be clear, our controller_ is an IBOutlet and owns us, so we
     36   // don't deallocate it explicitly.  It is owned by the browser
     37   // window controller, so gets deleted with a browser window is
     38   // closed.
     39 }
     40 
     41 - (void)awakeFromNib {
     42   NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
     43   [defaultCenter addObserver:self
     44                     selector:@selector(themeDidChangeNotification:)
     45                         name:kBrowserThemeDidChangeNotification
     46                       object:nil];
     47 
     48   DCHECK(controller_) << "Expected this to be hooked up via Interface Builder";
     49   NSArray* types = [NSArray arrayWithObjects:
     50                     NSStringPboardType,
     51                     NSHTMLPboardType,
     52                     NSURLPboardType,
     53                     kBookmarkButtonDragType,
     54                     kBookmarkDictionaryListPboardType,
     55                     nil];
     56   [self registerForDraggedTypes:types];
     57 }
     58 
     59 // We need the theme to color the bookmark buttons properly.  But our
     60 // controller desn't have access to it until it's placed in the view
     61 // hierarchy.  This is the spot where we close the loop.
     62 - (void)viewWillMoveToWindow:(NSWindow*)window {
     63   ui::ThemeProvider* themeProvider = [window themeProvider];
     64   [self updateTheme:themeProvider];
     65   [controller_ updateTheme:themeProvider];
     66 }
     67 
     68 - (void)viewDidMoveToWindow {
     69   [controller_ viewDidMoveToWindow];
     70 }
     71 
     72 // Called after the current theme has changed.
     73 - (void)themeDidChangeNotification:(NSNotification*)aNotification {
     74   ui::ThemeProvider* themeProvider =
     75       static_cast<ThemeService*>([[aNotification object] pointerValue]);
     76   [self updateTheme:themeProvider];
     77 }
     78 
     79 // Adapt appearance to the current theme. Called after theme changes and before
     80 // this is shown for the first time.
     81 - (void)updateTheme:(ui::ThemeProvider*)themeProvider {
     82   if (!themeProvider)
     83     return;
     84 
     85   NSColor* color =
     86       themeProvider->GetNSColor(ThemeService::COLOR_BOOKMARK_TEXT,
     87                                 true);
     88   [noItemTextfield_ setTextColor:color];
     89 }
     90 
     91 // Mouse down events on the bookmark bar should not allow dragging the parent
     92 // window around.
     93 - (BOOL)mouseDownCanMoveWindow {
     94   return NO;
     95 }
     96 
     97 -(NSTextField*)noItemTextfield {
     98   return noItemTextfield_;
     99 }
    100 
    101 -(NSButton*)importBookmarksButton {
    102   return importBookmarksButton_;
    103 }
    104 
    105 - (BookmarkBarController*)controller {
    106   return controller_;
    107 }
    108 
    109 // Internal method, needs to be called whenever a change has been made to
    110 // dropIndicatorShown_ or dropIndicatorPosition_ so it can get the controller
    111 // to reflect the change by moving buttons around.
    112 -(void)dropIndicatorChanged {
    113   if (dropIndicatorShown_)
    114     [controller_ setDropInsertionPos:dropIndicatorPosition_];
    115   else
    116     [controller_ clearDropInsertionPos];
    117 }
    118 
    119 -(void)drawRect:(NSRect)dirtyRect {
    120   [super drawRect:dirtyRect];
    121 }
    122 
    123 // Shim function to assist in unit testing.
    124 - (BOOL)dragClipboardContainsBookmarks {
    125   return bookmark_pasteboard_helper_mac::DragClipboardContainsBookmarks();
    126 }
    127 
    128 // NSDraggingDestination methods
    129 
    130 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
    131   if (![controller_ draggingAllowed:info])
    132     return NSDragOperationNone;
    133   if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] ||
    134       [self dragClipboardContainsBookmarks] ||
    135       [[info draggingPasteboard] containsURLData]) {
    136     // We only show the drop indicator if we're not in a position to
    137     // perform a hover-open since it doesn't make sense to do both.
    138     BOOL showIt = [controller_ shouldShowIndicatorShownForPoint:
    139                    [info draggingLocation]];
    140     if (!showIt) {
    141       if (dropIndicatorShown_) {
    142         dropIndicatorShown_ = NO;
    143         [self dropIndicatorChanged];
    144       }
    145     } else {
    146       CGFloat x =
    147       [controller_ indicatorPosForDragToPoint:[info draggingLocation]];
    148       // Need an update if the indicator wasn't previously shown or if it has
    149       // moved.
    150       if (!dropIndicatorShown_ || dropIndicatorPosition_ != x) {
    151         dropIndicatorShown_ = YES;
    152         dropIndicatorPosition_ = x;
    153         [self dropIndicatorChanged];
    154       }
    155     }
    156 
    157     [controller_ draggingEntered:info];  // allow hover-open to work.
    158     return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy;
    159   }
    160   return NSDragOperationNone;
    161 }
    162 
    163 - (void)draggingExited:(id<NSDraggingInfo>)info {
    164   // Regardless of the type of dragging which ended, we need to get rid of the
    165   // drop indicator if one was shown.
    166   if (dropIndicatorShown_) {
    167     dropIndicatorShown_ = NO;
    168     [self dropIndicatorChanged];
    169   }
    170 }
    171 
    172 - (void)draggingEnded:(id<NSDraggingInfo>)info {
    173   [[BookmarkButton draggedButton] setHidden:NO];
    174   if (dropIndicatorShown_) {
    175     dropIndicatorShown_ = NO;
    176     [self dropIndicatorChanged];
    177   }
    178   [controller_ draggingEnded:info];
    179 }
    180 
    181 - (BOOL)wantsPeriodicDraggingUpdates {
    182   return YES;
    183 }
    184 
    185 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
    186   // For now it's the same as draggingEntered:.
    187   return [self draggingEntered:info];
    188 }
    189 
    190 - (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
    191   return YES;
    192 }
    193 
    194 // Implement NSDraggingDestination protocol method
    195 // performDragOperation: for URLs.
    196 - (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info {
    197   NSPasteboard* pboard = [info draggingPasteboard];
    198   DCHECK([pboard containsURLData]);
    199 
    200   NSArray* urls = nil;
    201   NSArray* titles = nil;
    202   [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
    203 
    204   return [controller_ addURLs:urls
    205                    withTitles:titles
    206                            at:[info draggingLocation]];
    207 }
    208 
    209 // Implement NSDraggingDestination protocol method
    210 // performDragOperation: for bookmark buttons.
    211 - (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info {
    212   BOOL rtn = NO;
    213   NSData* data = [[info draggingPasteboard]
    214                   dataForType:kBookmarkButtonDragType];
    215   // [info draggingSource] is nil if not the same application.
    216   if (data && [info draggingSource]) {
    217     BookmarkButton* button = nil;
    218     [data getBytes:&button length:sizeof(button)];
    219     BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
    220     rtn = [controller_ dragButton:button
    221                                to:[info draggingLocation]
    222                              copy:copy];
    223     UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragEnd"));
    224   }
    225   return rtn;
    226 }
    227 
    228 - (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
    229   if ([controller_ dragBookmarkData:info])
    230     return YES;
    231   NSPasteboard* pboard = [info draggingPasteboard];
    232   if ([pboard dataForType:kBookmarkButtonDragType]) {
    233     if ([self performDragOperationForBookmarkButton:info])
    234       return YES;
    235     // Fall through....
    236   }
    237   if ([pboard containsURLData]) {
    238     if ([self performDragOperationForURL:info])
    239       return YES;
    240   }
    241   return NO;
    242 }
    243 
    244 - (void)setController:(id)controller {
    245   controller_ = controller;
    246 }
    247 
    248 - (ViewID)viewID {
    249   return VIEW_ID_BOOKMARK_BAR;
    250 }
    251 
    252 @end  // @implementation BookmarkBarView
    253