blob: 69008e581ce46d1788978303917c7c6302e79d8b [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h"
#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
#include "chrome/browser/profiles/profile.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.h"
#include "content/public/browser/user_metrics.h"
using content::UserMetricsAction;
#import "third_party/mozilla/NSPasteboard+Utils.h"
@interface BookmarkBarFolderView()
@property(readonly, nonatomic) id<BookmarkButtonControllerProtocol> controller;
- (void)setDropIndicatorShown:(BOOL)flag;
@end
@implementation BookmarkBarFolderView
- (void)awakeFromNib {
NSArray* types = [NSArray arrayWithObjects:
NSStringPboardType,
NSHTMLPboardType,
NSURLPboardType,
kBookmarkButtonDragType,
kBookmarkDictionaryListPboardType,
nil];
[self registerForDraggedTypes:types];
}
- (void)dealloc {
[self unregisterDraggedTypes];
[super dealloc];
}
- (id<BookmarkButtonControllerProtocol>)controller {
// When needed for testing, set the local data member |controller_| to
// the test controller.
return controller_ ? controller_ : [[self window] windowController];
}
// Virtually identical to [BookmarkBarView draggingEntered:].
// TODO(jrg): find a way to share code. Lack of multiple inheritance
// makes things more of a pain but there should be no excuse for laziness.
// http://crbug.com/35966
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
inDrag_ = YES;
if (![[self controller] draggingAllowed:info])
return NSDragOperationNone;
if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] ||
PasteboardContainsBookmarks(ui::CLIPBOARD_TYPE_DRAG) ||
[[info draggingPasteboard] containsURLData]) {
// Find the position of the drop indicator.
BOOL showIt = [[self controller]
shouldShowIndicatorShownForPoint:[info draggingLocation]];
if (!showIt) {
[self setDropIndicatorShown:NO];
} else {
[self setDropIndicatorShown:YES];
CGFloat y = [[self controller]
indicatorPosForDragToPoint:[info draggingLocation]];
NSRect frame = [dropIndicator_ frame];
if (NSMinY(frame) != y) {
frame.origin.y = y;
[dropIndicator_ setFrame:frame];
}
}
[[self controller] draggingEntered:info]; // allow hover-open to work
return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy;
}
return NSDragOperationNone;
}
- (void)draggingExited:(id<NSDraggingInfo>)info {
[[self controller] draggingExited:info];
// Regardless of the type of dragging which ended, we need to get rid of the
// drop indicator if one was shown.
[self setDropIndicatorShown:NO];
}
- (void)draggingEnded:(id<NSDraggingInfo>)info {
// Awkwardness since views open and close out from under us.
if (inDrag_) {
inDrag_ = NO;
}
[self draggingExited:info];
}
- (BOOL)wantsPeriodicDraggingUpdates {
// TODO(jrg): This should probably return |YES| and the controller should
// slide the existing bookmark buttons interactively to the side to make
// room for the about-to-be-dropped bookmark.
// http://crbug.com/35968
return NO;
}
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
// For now it's the same as draggingEntered:.
// TODO(jrg): once we return YES for wantsPeriodicDraggingUpdates,
// this should ping the [self controller] to perform animations.
// http://crbug.com/35968
return [self draggingEntered:info];
}
- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
return YES;
}
// This code is practically identical to the same function in BookmarkBarView
// with the only difference being how the controller is retrieved.
// TODO(mrossetti,jrg): http://crbug.com/35966
// Implement NSDraggingDestination protocol method
// performDragOperation: for URLs.
- (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info {
NSPasteboard* pboard = [info draggingPasteboard];
DCHECK([pboard containsURLData]);
NSArray* urls = nil;
NSArray* titles = nil;
[pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
return [[self controller] addURLs:urls
withTitles:titles
at:[info draggingLocation]];
}
// This code is practically identical to the same function in BookmarkBarView
// with the only difference being how the controller is retrieved.
// http://crbug.com/35966
// Implement NSDraggingDestination protocol method
// performDragOperation: for bookmark buttons.
- (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info {
BOOL doDrag = NO;
NSData* data = [[info draggingPasteboard]
dataForType:kBookmarkButtonDragType];
// [info draggingSource] is nil if not the same application.
if (data && [info draggingSource]) {
BookmarkButton* button = nil;
[data getBytes:&button length:sizeof(button)];
// If we're dragging from one profile to another, disallow moving (only
// allow copying). Each profile has its own bookmark model, so one way to
// check whether we are dragging across profiles is to see if the
// |BookmarkNode| corresponding to |button| exists in this profile. If it
// does, we're dragging within a profile; otherwise, we're dragging across
// profiles.
const BookmarkModel* const model = [[self controller] bookmarkModel];
const BookmarkNode* const source_node = [button bookmarkNode];
const BookmarkNode* const target_node =
model->GetNodeByID(source_node->id());
BOOL copy =
!([info draggingSourceOperationMask] & NSDragOperationMove) ||
(source_node != target_node);
doDrag = [[self controller] dragButton:button
to:[info draggingLocation]
copy:copy];
content::RecordAction(UserMetricsAction("BookmarkBarFolder_DragEnd"));
}
return doDrag;
}
- (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
if ([[self controller] dragBookmarkData:info])
return YES;
NSPasteboard* pboard = [info draggingPasteboard];
if ([pboard dataForType:kBookmarkButtonDragType] &&
[self performDragOperationForBookmarkButton:info])
return YES;
if ([pboard containsURLData] && [self performDragOperationForURL:info])
return YES;
return NO;
}
- (void)setDropIndicatorShown:(BOOL)flag {
if (dropIndicatorShown_ == flag)
return;
dropIndicatorShown_ = flag;
if (dropIndicatorShown_) {
NSRect frame = NSInsetRect([self bounds], 4, 0);
frame.size.height = 1;
dropIndicator_.reset([[NSBox alloc] initWithFrame:frame]);
[dropIndicator_ setBoxType:NSBoxSeparator];
[dropIndicator_ setBorderType:NSLineBorder];
[dropIndicator_ setAlphaValue:0.85];
[self addSubview:dropIndicator_];
} else {
[dropIndicator_ removeFromSuperview];
dropIndicator_.reset();
}
}
@end