OLD | NEW |
| (Empty) |
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 "components/bookmarks/core/browser/bookmark_pasteboard_helper_mac.h" | |
6 | |
7 #import <Cocoa/Cocoa.h> | |
8 | |
9 #include "base/files/file_path.h" | |
10 #include "base/strings/sys_string_conversions.h" | |
11 #include "components/bookmarks/core/browser/bookmark_node.h" | |
12 #include "ui/base/clipboard/clipboard.h" | |
13 | |
14 NSString* const kBookmarkDictionaryListPboardType = | |
15 @"BookmarkDictionaryListPboardType"; | |
16 | |
17 namespace { | |
18 | |
19 // An unofficial standard pasteboard title type to be provided alongside the | |
20 // |NSURLPboardType|. | |
21 NSString* const kNSURLTitlePboardType = @"public.url-name"; | |
22 | |
23 // Pasteboard type used to store profile path to determine which profile | |
24 // a set of bookmarks came from. | |
25 NSString* const kChromiumProfilePathPboardType = | |
26 @"ChromiumProfilePathPboardType"; | |
27 | |
28 // Internal bookmark ID for a bookmark node. Used only when moving inside | |
29 // of one profile. | |
30 NSString* const kChromiumBookmarkId = @"ChromiumBookmarkId"; | |
31 | |
32 // Mac WebKit uses this type, declared in | |
33 // WebKit/mac/History/WebURLsWithTitles.h. | |
34 NSString* const kCrWebURLsWithTitlesPboardType = @"WebURLsWithTitlesPboardType"; | |
35 | |
36 // Keys for the type of node in BookmarkDictionaryListPboardType. | |
37 NSString* const kWebBookmarkType = @"WebBookmarkType"; | |
38 | |
39 NSString* const kWebBookmarkTypeList = @"WebBookmarkTypeList"; | |
40 | |
41 NSString* const kWebBookmarkTypeLeaf = @"WebBookmarkTypeLeaf"; | |
42 | |
43 void ConvertPlistToElements(NSArray* input, | |
44 std::vector<BookmarkNodeData::Element>& elements) { | |
45 NSUInteger len = [input count]; | |
46 for (NSUInteger i = 0; i < len; ++i) { | |
47 NSDictionary* pboardBookmark = [input objectAtIndex:i]; | |
48 scoped_ptr<BookmarkNode> new_node(new BookmarkNode(GURL())); | |
49 int64 node_id = | |
50 [[pboardBookmark objectForKey:kChromiumBookmarkId] longLongValue]; | |
51 new_node->set_id(node_id); | |
52 BOOL is_folder = [[pboardBookmark objectForKey:kWebBookmarkType] | |
53 isEqualToString:kWebBookmarkTypeList]; | |
54 if (is_folder) { | |
55 new_node->set_type(BookmarkNode::FOLDER); | |
56 NSString* title = [pboardBookmark objectForKey:@"Title"]; | |
57 new_node->SetTitle(base::SysNSStringToUTF16(title)); | |
58 } else { | |
59 new_node->set_type(BookmarkNode::URL); | |
60 NSDictionary* uriDictionary = | |
61 [pboardBookmark objectForKey:@"URIDictionary"]; | |
62 NSString* title = [uriDictionary objectForKey:@"title"]; | |
63 NSString* urlString = [pboardBookmark objectForKey:@"URLString"]; | |
64 new_node->SetTitle(base::SysNSStringToUTF16(title)); | |
65 new_node->set_url(GURL(base::SysNSStringToUTF8(urlString))); | |
66 } | |
67 BookmarkNodeData::Element e = BookmarkNodeData::Element(new_node.get()); | |
68 if(is_folder) | |
69 ConvertPlistToElements([pboardBookmark objectForKey:@"Children"], | |
70 e.children); | |
71 elements.push_back(e); | |
72 } | |
73 } | |
74 | |
75 bool ReadBookmarkDictionaryListPboardType( | |
76 NSPasteboard* pb, | |
77 std::vector<BookmarkNodeData::Element>& elements) { | |
78 NSArray* bookmarks = | |
79 [pb propertyListForType:kBookmarkDictionaryListPboardType]; | |
80 if (!bookmarks) | |
81 return false; | |
82 ConvertPlistToElements(bookmarks, elements); | |
83 return true; | |
84 } | |
85 | |
86 bool ReadWebURLsWithTitlesPboardType( | |
87 NSPasteboard* pb, | |
88 std::vector<BookmarkNodeData::Element>& elements) { | |
89 NSArray* bookmarkPairs = | |
90 [pb propertyListForType:kCrWebURLsWithTitlesPboardType]; | |
91 if (![bookmarkPairs isKindOfClass:[NSArray class]]) | |
92 return false; | |
93 | |
94 NSArray* urlsArr = [bookmarkPairs objectAtIndex:0]; | |
95 NSArray* titlesArr = [bookmarkPairs objectAtIndex:1]; | |
96 if ([urlsArr count] < 1) | |
97 return false; | |
98 if ([urlsArr count] != [titlesArr count]) | |
99 return false; | |
100 | |
101 NSUInteger len = [titlesArr count]; | |
102 for (NSUInteger i = 0; i < len; ++i) { | |
103 base::string16 title = base::SysNSStringToUTF16([titlesArr objectAtIndex:i])
; | |
104 std::string url = base::SysNSStringToUTF8([urlsArr objectAtIndex:i]); | |
105 if (!url.empty()) { | |
106 BookmarkNodeData::Element element; | |
107 element.is_url = true; | |
108 element.url = GURL(url); | |
109 element.title = title; | |
110 elements.push_back(element); | |
111 } | |
112 } | |
113 return true; | |
114 } | |
115 | |
116 bool ReadNSURLPboardType(NSPasteboard* pb, | |
117 std::vector<BookmarkNodeData::Element>& elements) { | |
118 NSURL* url = [NSURL URLFromPasteboard:pb]; | |
119 if (url == nil) | |
120 return false; | |
121 | |
122 std::string urlString = base::SysNSStringToUTF8([url absoluteString]); | |
123 NSString* title = [pb stringForType:kNSURLTitlePboardType]; | |
124 if (!title) | |
125 title = [pb stringForType:NSStringPboardType]; | |
126 | |
127 BookmarkNodeData::Element element; | |
128 element.is_url = true; | |
129 element.url = GURL(urlString); | |
130 element.title = base::SysNSStringToUTF16(title); | |
131 elements.push_back(element); | |
132 return true; | |
133 } | |
134 | |
135 NSArray* GetPlistForBookmarkList( | |
136 const std::vector<BookmarkNodeData::Element>& elements) { | |
137 NSMutableArray* plist = [NSMutableArray array]; | |
138 for (size_t i = 0; i < elements.size(); ++i) { | |
139 BookmarkNodeData::Element element = elements[i]; | |
140 if (element.is_url) { | |
141 NSString* title = base::SysUTF16ToNSString(element.title); | |
142 NSString* url = base::SysUTF8ToNSString(element.url.spec()); | |
143 int64 elementId = element.id(); | |
144 NSNumber* idNum = [NSNumber numberWithLongLong:elementId]; | |
145 NSDictionary* uriDictionary = [NSDictionary dictionaryWithObjectsAndKeys: | |
146 title, @"title", nil]; | |
147 NSDictionary* object = [NSDictionary dictionaryWithObjectsAndKeys: | |
148 uriDictionary, @"URIDictionary", | |
149 url, @"URLString", | |
150 kWebBookmarkTypeLeaf, kWebBookmarkType, | |
151 idNum, kChromiumBookmarkId, | |
152 nil]; | |
153 [plist addObject:object]; | |
154 } else { | |
155 NSString* title = base::SysUTF16ToNSString(element.title); | |
156 NSArray* children = GetPlistForBookmarkList(element.children); | |
157 int64 elementId = element.id(); | |
158 NSNumber* idNum = [NSNumber numberWithLongLong:elementId]; | |
159 NSDictionary* object = [NSDictionary dictionaryWithObjectsAndKeys: | |
160 title, @"Title", | |
161 children, @"Children", | |
162 kWebBookmarkTypeList, kWebBookmarkType, | |
163 idNum, kChromiumBookmarkId, | |
164 nil]; | |
165 [plist addObject:object]; | |
166 } | |
167 } | |
168 return plist; | |
169 } | |
170 | |
171 void WriteBookmarkDictionaryListPboardType( | |
172 NSPasteboard* pb, | |
173 const std::vector<BookmarkNodeData::Element>& elements) { | |
174 NSArray* plist = GetPlistForBookmarkList(elements); | |
175 [pb setPropertyList:plist forType:kBookmarkDictionaryListPboardType]; | |
176 } | |
177 | |
178 void FillFlattenedArraysForBookmarks( | |
179 const std::vector<BookmarkNodeData::Element>& elements, | |
180 NSMutableArray* titles, | |
181 NSMutableArray* urls) { | |
182 for (size_t i = 0; i < elements.size(); ++i) { | |
183 BookmarkNodeData::Element element = elements[i]; | |
184 if (element.is_url) { | |
185 NSString* title = base::SysUTF16ToNSString(element.title); | |
186 NSString* url = base::SysUTF8ToNSString(element.url.spec()); | |
187 [titles addObject:title]; | |
188 [urls addObject:url]; | |
189 } else { | |
190 FillFlattenedArraysForBookmarks(element.children, titles, urls); | |
191 } | |
192 } | |
193 } | |
194 | |
195 void WriteSimplifiedBookmarkTypes( | |
196 NSPasteboard* pb, | |
197 const std::vector<BookmarkNodeData::Element>& elements) { | |
198 NSMutableArray* titles = [NSMutableArray array]; | |
199 NSMutableArray* urls = [NSMutableArray array]; | |
200 FillFlattenedArraysForBookmarks(elements, titles, urls); | |
201 | |
202 // These bookmark types only act on urls, not folders. | |
203 if ([urls count] < 1) | |
204 return; | |
205 | |
206 // Write WebURLsWithTitlesPboardType. | |
207 [pb setPropertyList:[NSArray arrayWithObjects:urls, titles, nil] | |
208 forType:kCrWebURLsWithTitlesPboardType]; | |
209 | |
210 // Write NSStringPboardType. | |
211 [pb setString:[urls componentsJoinedByString:@"\n"] | |
212 forType:NSStringPboardType]; | |
213 | |
214 // Write NSURLPboardType (with title). | |
215 NSURL* url = [NSURL URLWithString:[urls objectAtIndex:0]]; | |
216 [url writeToPasteboard:pb]; | |
217 NSString* titleString = [titles objectAtIndex:0]; | |
218 [pb setString:titleString forType:kNSURLTitlePboardType]; | |
219 } | |
220 | |
221 NSPasteboard* PasteboardFromType(ui::ClipboardType type) { | |
222 NSString* type_string = nil; | |
223 switch (type) { | |
224 case ui::CLIPBOARD_TYPE_COPY_PASTE: | |
225 type_string = NSGeneralPboard; | |
226 break; | |
227 case ui::CLIPBOARD_TYPE_DRAG: | |
228 type_string = NSDragPboard; | |
229 break; | |
230 case ui::CLIPBOARD_TYPE_SELECTION: | |
231 NOTREACHED(); | |
232 break; | |
233 } | |
234 | |
235 return [NSPasteboard pasteboardWithName:type_string]; | |
236 } | |
237 | |
238 } // namespace | |
239 | |
240 void WriteBookmarksToPasteboard( | |
241 ui::ClipboardType type, | |
242 const std::vector<BookmarkNodeData::Element>& elements, | |
243 const base::FilePath& profile_path) { | |
244 if (elements.empty()) | |
245 return; | |
246 | |
247 NSPasteboard* pb = PasteboardFromType(type); | |
248 | |
249 NSArray* types = [NSArray arrayWithObjects:kBookmarkDictionaryListPboardType, | |
250 kCrWebURLsWithTitlesPboardType, | |
251 NSStringPboardType, | |
252 NSURLPboardType, | |
253 kNSURLTitlePboardType, | |
254 kChromiumProfilePathPboardType, | |
255 nil]; | |
256 [pb declareTypes:types owner:nil]; | |
257 [pb setString:base::SysUTF8ToNSString(profile_path.value()) | |
258 forType:kChromiumProfilePathPboardType]; | |
259 WriteBookmarkDictionaryListPboardType(pb, elements); | |
260 WriteSimplifiedBookmarkTypes(pb, elements); | |
261 } | |
262 | |
263 bool ReadBookmarksFromPasteboard( | |
264 ui::ClipboardType type, | |
265 std::vector<BookmarkNodeData::Element>& elements, | |
266 base::FilePath* profile_path) { | |
267 NSPasteboard* pb = PasteboardFromType(type); | |
268 | |
269 elements.clear(); | |
270 NSString* profile = [pb stringForType:kChromiumProfilePathPboardType]; | |
271 *profile_path = base::FilePath(base::SysNSStringToUTF8(profile)); | |
272 return ReadBookmarkDictionaryListPboardType(pb, elements) || | |
273 ReadWebURLsWithTitlesPboardType(pb, elements) || | |
274 ReadNSURLPboardType(pb, elements); | |
275 } | |
276 | |
277 bool PasteboardContainsBookmarks(ui::ClipboardType type) { | |
278 NSPasteboard* pb = PasteboardFromType(type); | |
279 | |
280 NSArray* availableTypes = | |
281 [NSArray arrayWithObjects:kBookmarkDictionaryListPboardType, | |
282 kCrWebURLsWithTitlesPboardType, | |
283 NSURLPboardType, | |
284 nil]; | |
285 return [pb availableTypeFromArray:availableTypes] != nil; | |
286 } | |
OLD | NEW |