| 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 |