1// Copyright 2014 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#include "ui/base/dragdrop/os_exchange_data_provider_mac.h"
6
7#import <Cocoa/Cocoa.h>
8
9#include "base/logging.h"
10#include "base/pickle.h"
11#include "base/strings/sys_string_conversions.h"
12#import "third_party/mozilla/NSPasteboard+Utils.h"
13#include "url/gurl.h"
14
15namespace ui {
16
17OSExchangeDataProviderMac::OSExchangeDataProviderMac()
18    : pasteboard_([[NSPasteboard pasteboardWithUniqueName] retain]) {
19}
20
21OSExchangeDataProviderMac::OSExchangeDataProviderMac(NSPasteboard* pasteboard)
22    : pasteboard_([pasteboard retain]) {
23}
24
25OSExchangeDataProviderMac::~OSExchangeDataProviderMac() {
26}
27
28OSExchangeData::Provider* OSExchangeDataProviderMac::Clone() const {
29  return new OSExchangeDataProviderMac(pasteboard_);
30}
31
32void OSExchangeDataProviderMac::MarkOriginatedFromRenderer() {
33  NOTIMPLEMENTED();
34}
35
36bool OSExchangeDataProviderMac::DidOriginateFromRenderer() const {
37  NOTIMPLEMENTED();
38  return false;
39}
40
41void OSExchangeDataProviderMac::SetString(const base::string16& string) {
42  [pasteboard_ writeObjects:@[ base::SysUTF16ToNSString(string) ]];
43}
44
45void OSExchangeDataProviderMac::SetURL(const GURL& url,
46                                       const base::string16& title) {
47  NSURL* ns_url = [NSURL URLWithString:base::SysUTF8ToNSString(url.spec())];
48  [pasteboard_ writeObjects:@[ ns_url ]];
49
50  [pasteboard_ setString:base::SysUTF16ToNSString(title)
51                 forType:kCorePasteboardFlavorType_urln];
52}
53
54void OSExchangeDataProviderMac::SetFilename(const base::FilePath& path) {
55  [pasteboard_ setPropertyList:@[ base::SysUTF8ToNSString(path.value()) ]
56                       forType:NSFilenamesPboardType];
57}
58
59void OSExchangeDataProviderMac::SetFilenames(
60    const std::vector<FileInfo>& filenames) {
61  NOTIMPLEMENTED();
62}
63
64void OSExchangeDataProviderMac::SetPickledData(
65    const OSExchangeData::CustomFormat& format,
66    const Pickle& data) {
67  NSData* ns_data = [NSData dataWithBytes:data.data() length:data.size()];
68  [pasteboard_ setData:ns_data forType:format.ToNSString()];
69}
70
71bool OSExchangeDataProviderMac::GetString(base::string16* data) const {
72  DCHECK(data);
73  NSArray* items = [pasteboard_ readObjectsForClasses:@[ [NSString class] ]
74                                              options:@{ }];
75  if ([items count] == 0)
76    return false;
77
78  *data = base::SysNSStringToUTF16([items objectAtIndex:0]);
79  return true;
80}
81
82bool OSExchangeDataProviderMac::GetURLAndTitle(
83    OSExchangeData::FilenameToURLPolicy policy,
84    GURL* url,
85    base::string16* title) const {
86  DCHECK(url);
87  DCHECK(title);
88  NSArray* items = [pasteboard_ readObjectsForClasses:@[ [NSURL class] ]
89                                              options:@{ }];
90  if ([items count] == 0)
91    return false;
92
93  NSURL* ns_url = [items objectAtIndex:0];
94
95  if (policy == OSExchangeData::DO_NOT_CONVERT_FILENAMES) {
96    // If the URL matches a filename, assume that it came from SetFilename().
97    // Don't return it if we are not supposed to convert filename to URL.
98    NSArray* paths = [pasteboard_ propertyListForType:NSFilenamesPboardType];
99    NSString* url_path = [[ns_url path] stringByStandardizingPath];
100    for (NSString* path in paths) {
101      if ([[path stringByStandardizingPath] isEqualToString:url_path])
102        return false;
103    }
104  }
105
106  *url = GURL([[ns_url absoluteString] UTF8String]);
107  *title = base::SysNSStringToUTF16(
108      [pasteboard_ stringForType:kCorePasteboardFlavorType_urln]);
109  return true;
110}
111
112bool OSExchangeDataProviderMac::GetFilename(base::FilePath* path) const {
113  NSArray* paths = [pasteboard_ propertyListForType:NSFilenamesPboardType];
114  if ([paths count] == 0)
115    return false;
116
117  *path = base::FilePath([[paths objectAtIndex:0] UTF8String]);
118  return true;
119}
120
121bool OSExchangeDataProviderMac::GetFilenames(
122    std::vector<FileInfo>* filenames) const {
123  NOTIMPLEMENTED();
124  return false;
125}
126
127bool OSExchangeDataProviderMac::GetPickledData(
128    const OSExchangeData::CustomFormat& format,
129    Pickle* data) const {
130  DCHECK(data);
131  NSData* ns_data = [pasteboard_ dataForType:format.ToNSString()];
132  if (!ns_data)
133    return false;
134
135  *data = Pickle(static_cast<const char*>([ns_data bytes]), [ns_data length]);
136  return true;
137}
138
139bool OSExchangeDataProviderMac::HasString() const {
140  NSArray* classes = @[ [NSString class] ];
141  return [pasteboard_ canReadObjectForClasses:classes options:nil];
142}
143
144bool OSExchangeDataProviderMac::HasURL(
145    OSExchangeData::FilenameToURLPolicy policy) const {
146  GURL url;
147  base::string16 title;
148  return GetURLAndTitle(policy, &url, &title);
149}
150
151bool OSExchangeDataProviderMac::HasFile() const {
152  return [[pasteboard_ types] containsObject:NSFilenamesPboardType];
153}
154
155bool OSExchangeDataProviderMac::HasCustomFormat(
156    const OSExchangeData::CustomFormat& format) const {
157  return [[pasteboard_ types] containsObject:format.ToNSString()];
158}
159
160///////////////////////////////////////////////////////////////////////////////
161// OSExchangeData, public:
162
163// static
164OSExchangeData::Provider* OSExchangeData::CreateProvider() {
165  return new OSExchangeDataProviderMac;
166}
167
168}  // namespace ui
169