1// Copyright (c) 2012 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/url_drop_target.h"
6
7#include "base/basictypes.h"
8#include "chrome/browser/ui/cocoa/drag_util.h"
9#import "third_party/mozilla/NSPasteboard+Utils.h"
10#include "url/gurl.h"
11
12namespace {
13
14// Mac WebKit uses this type, declared in
15// WebKit/mac/History/WebURLsWithTitles.h.
16NSString* const kCrWebURLsWithTitlesPboardType =
17    @"WebURLsWithTitlesPboardType";
18
19}  // namespace
20
21@interface URLDropTargetHandler(Private)
22
23// Gets the appropriate drag operation given the |NSDraggingInfo|.
24- (NSDragOperation)getDragOperation:(id<NSDraggingInfo>)sender;
25
26// Tell the window controller to hide the drop indicator.
27- (void)hideIndicator;
28
29@end  // @interface URLDropTargetHandler(Private)
30
31@implementation URLDropTargetHandler
32
33+ (NSArray*)handledDragTypes {
34  return [NSArray arrayWithObjects:kCrWebURLsWithTitlesPboardType,
35                                   NSURLPboardType,
36                                   NSStringPboardType,
37                                   NSFilenamesPboardType,
38                                   nil];
39}
40
41- (id)initWithView:(NSView<URLDropTarget>*)view {
42  if ((self = [super init])) {
43    view_ = view;
44    [view_ registerForDraggedTypes:[URLDropTargetHandler handledDragTypes]];
45  }
46  return self;
47}
48
49// The following four methods implement parts of the |NSDraggingDestination|
50// protocol, which the owner should "forward" to its |URLDropTargetHandler|
51// (us).
52
53- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
54  if ([[view_ urlDropController] isUnsupportedDropData:sender])
55    return NSDragOperationNone;
56
57  return [self getDragOperation:sender];
58}
59
60- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
61  NSDragOperation dragOp = NSDragOperationNone;
62  BOOL showIndicator = NO;
63  // Show indicator for drag data supported for tab contents as well as for
64  // local file drags that may not be viewable in tab contents, but should
65  // still trigger hover tab selection.
66  if (![[view_ urlDropController] isUnsupportedDropData:sender]) {
67    dragOp = [self getDragOperation:sender];
68    if (dragOp == NSDragOperationCopy)
69      showIndicator = YES;
70  } else if (!drag_util::GetFileURLFromDropData(sender).is_empty()) {
71    showIndicator = YES;
72  }
73
74  if (showIndicator) {
75    // Just tell the window controller to update the indicator.
76    NSPoint hoverPoint = [view_ convertPoint:[sender draggingLocation]
77                                    fromView:nil];
78    [[view_ urlDropController] indicateDropURLsInView:view_ at:hoverPoint];
79  }
80  return dragOp;
81}
82
83- (void)draggingExited:(id<NSDraggingInfo>)sender {
84  [self hideIndicator];
85}
86
87- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
88  [self hideIndicator];
89
90  NSPasteboard* pboard = [sender draggingPasteboard];
91  NSArray* supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
92  NSString* bestType = [pboard availableTypeFromArray:supportedTypes];
93
94  NSPoint dropPoint =
95      [view_ convertPoint:[sender draggingLocation] fromView:nil];
96  // Tell the window controller about the dropped URL(s).
97  if ([pboard containsURLData]) {
98    NSArray* urls = nil;
99    NSArray* titles;  // discarded
100    [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
101
102    if ([urls count]) {
103      [[view_ urlDropController] dropURLs:urls inView:view_ at:dropPoint];
104      return YES;
105    }
106  } else if (NSString* text = [pboard stringForType:bestType]) {
107    // This does not include any URLs, so treat it as plain text if we can
108    // get NSString.
109    [[view_ urlDropController] dropText:text inView:view_ at:dropPoint];
110    return YES;
111  }
112
113  return NO;
114}
115
116@end  // @implementation URLDropTargetHandler
117
118@implementation URLDropTargetHandler(Private)
119
120- (NSDragOperation)getDragOperation:(id<NSDraggingInfo>)sender {
121  NSPasteboard* pboard = [sender draggingPasteboard];
122  NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
123  NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
124  if (![pboard containsURLData] && ![pboard stringForType:bestType])
125    return NSDragOperationNone;
126
127  // Only allow the copy operation.
128  return [sender draggingSourceOperationMask] & NSDragOperationCopy;
129}
130
131- (void)hideIndicator {
132  [[view_ urlDropController] hideDropURLsIndicatorInView:view_];
133}
134
135@end  // @implementation URLDropTargetHandler(Private)
136