Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / bookmarks / bookmark_pasteboard_helper_mac.mm
blob7ec2fb6ae6fbe178b4cd940f3934416daac62b9d
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.
5 #include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/files/file_path.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "chrome/browser/bookmarks/bookmark_model.h"
12 #include "ui/base/clipboard/clipboard.h"
14 NSString* const kBookmarkDictionaryListPboardType =
15     @"BookmarkDictionaryListPboardType";
17 namespace {
19 // An unofficial standard pasteboard title type to be provided alongside the
20 // |NSURLPboardType|.
21 NSString* const kNSURLTitlePboardType = @"public.url-name";
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";
28 // Internal bookmark ID for a bookmark node.  Used only when moving inside
29 // of one profile.
30 NSString* const kChromiumBookmarkId = @"ChromiumBookmarkId";
32 // Mac WebKit uses this type, declared in
33 // WebKit/mac/History/WebURLsWithTitles.h.
34 NSString* const kCrWebURLsWithTitlesPboardType = @"WebURLsWithTitlesPboardType";
36 // Keys for the type of node in BookmarkDictionaryListPboardType.
37 NSString* const kWebBookmarkType = @"WebBookmarkType";
39 NSString* const kWebBookmarkTypeList = @"WebBookmarkTypeList";
41 NSString* const kWebBookmarkTypeLeaf = @"WebBookmarkTypeLeaf";
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   }
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;
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;
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;
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;
116 bool ReadNSURLPboardType(NSPasteboard* pb,
117                          std::vector<BookmarkNodeData::Element>& elements) {
118   NSURL* url = [NSURL URLFromPasteboard:pb];
119   if (url == nil)
120     return false;
122   std::string urlString = base::SysNSStringToUTF8([url absoluteString]);
123   NSString* title = [pb stringForType:kNSURLTitlePboardType];
124   if (!title)
125     title = [pb stringForType:NSStringPboardType];
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;
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;
171 void WriteBookmarkDictionaryListPboardType(
172     NSPasteboard* pb,
173     const std::vector<BookmarkNodeData::Element>& elements) {
174   NSArray* plist = GetPlistForBookmarkList(elements);
175   [pb setPropertyList:plist forType:kBookmarkDictionaryListPboardType];
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   }
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);
202   // These bookmark types only act on urls, not folders.
203   if ([urls count] < 1)
204     return;
206   // Write WebURLsWithTitlesPboardType.
207   [pb setPropertyList:[NSArray arrayWithObjects:urls, titles, nil]
208               forType:kCrWebURLsWithTitlesPboardType];
210   // Write NSStringPboardType.
211   [pb setString:[urls componentsJoinedByString:@"\n"]
212         forType:NSStringPboardType];
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];
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   }
235   return [NSPasteboard pasteboardWithName:type_string];
238 }  // namespace
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;
247   NSPasteboard* pb = PasteboardFromType(type);
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);
263 bool ReadBookmarksFromPasteboard(
264     ui::ClipboardType type,
265     std::vector<BookmarkNodeData::Element>& elements,
266     base::FilePath* profile_path) {
267   NSPasteboard* pb = PasteboardFromType(type);
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);
277 bool PasteboardContainsBookmarks(ui::ClipboardType type) {
278   NSPasteboard* pb = PasteboardFromType(type);
280   NSArray* availableTypes =
281       [NSArray arrayWithObjects:kBookmarkDictionaryListPboardType,
282                                 kCrWebURLsWithTitlesPboardType,
283                                 NSURLPboardType,
284                                 nil];
285   return [pb availableTypeFromArray:availableTypes] != nil;