Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 315 lines (255 sloc) 10.883 kb
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
1 //
2 // KSWebLocationPasteboardUtilities.m
3 //
5e343ed @danwood update copyrights to 2012
danwood authored
4 // Copyright (c) 2007-2012 Mike Abdullah, Dan Wood and Karelia Software
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL MIKE ABDULLAH, DAN WOOD OR KARELIA SOFTWARE BE LIABLE FOR ANY
19 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 //
26
27
28 #import "KSWebLocationPasteboardUtilities.h"
29
1eb3fb9 @mikeabdullah Can use +[KSURLFormatter URLFromString:] instead of internal +URLWithStr...
mikeabdullah authored
30 #import "KSURLFormatter.h"
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
31 #import "KSURLUtilities.h"
32
33
34 @interface KSWebLocation (PasteboardPrivate)
35 + (NSArray *)webLocationsWithBookmarkDictionariesPasteboardPropertyList:(id)propertyList;
36 + (NSArray *)webLocationsWithWebURLsWithTitlesPasteboardPropertyList:(id)propertyList;
37 + (NSArray *)webLocationsWithFilenamesPasteboardPropertyList:(id)propertyList;
38 @end
39
40
41 #pragma mark -
42
43
44 @implementation KSWebLocation (Pasteboard)
45
46 #pragma mark Pasteboard Reading
47
48 + (NSArray *)readableTypesForPasteboard:(NSPasteboard *)pasteboard;
49 {
50 NSArray *URLTypes = nil;
51 if ([NSURL respondsToSelector:@selector(readableTypesForPasteboard:)])
52 {
53 URLTypes = [NSURL performSelector:@selector(readableTypesForPasteboard:)
54 withObject:pasteboard];
55 }
56
57 NSArray *result = [NSArray arrayWithObjects:
58 NSURLPboardType,
59 NSStringPboardType,
60 NSRTFPboardType,
61 NSRTFDPboardType, nil];
62
63 if (URLTypes) result = [URLTypes arrayByAddingObjectsFromArray:result];
64 return result;
65 }
66
67 #if (defined MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
68 + (NSUInteger)readingOptionsForType:(NSString *)type
69 pasteboard:(NSPasteboard *)pasteboard;
70 {
71 NSPasteboardReadingOptions result = NSPasteboardReadingAsString;
72
73 if ([type isEqualToString:@"WebURLsWithTitlesPboardType"] ||
74 [type isEqualToString:@"BookmarkDictionaryListPboardType"] ||
75 [type isEqualToString:NSFilenamesPboardType])
76 {
77 result = NSPasteboardReadingAsPropertyList;
78 }
79
80 return result;
81 }
82 #endif
83
d773175 @mikeabdullah Routine to guess title for a URL
mikeabdullah authored
84 + (NSString *)guessTitleForURL:(NSURL *)URL;
85 {
86 NSString *result = [[URL ks_lastPathComponent] stringByDeletingPathExtension];
87 result = [result stringByReplacingOccurrencesOfString:@"_" withString:@" "];
88 return result;
89 }
90
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
91 - (id)initWithPasteboardPropertyList:(id)propertyList ofType:(NSString *)type;
92 {
93 // Try with NSURL
94 NSURL *URL = [[NSURL alloc] initWithPasteboardPropertyList:propertyList ofType:type];
95 if (URL)
96 {
90e262e @mikeabdullah Guess titles when reading from web locations from pboard URLs
mikeabdullah authored
97 self = [self initWithURL:URL title:[[self class] guessTitleForURL:URL]];
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
98 [URL release];
99 }
100
101 // Fallback to trying to get a string out of the plist
102 else
103 {
104 NSString *string = [propertyList description];
105 if ([string length] <= 2048) // No point processing particularly long strings
106 {
ee98d74 @danwood Rename local variables so they don't cover earlier
danwood authored
107 NSURL *plistURL = [KSURLFormatter URLFromString:string]; /// encodeLegally to handle accented characters
108 if (plistURL && [plistURL ks_hasNetworkLocation])
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
109 {
1f98d05 @mikeabdullah Edge case where wrong value for self could be returned.
mikeabdullah authored
110 return [self initWithURL:plistURL title:[[self class] guessTitleForURL:URL]];
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
111 }
112 }
1f98d05 @mikeabdullah Edge case where wrong value for self could be returned.
mikeabdullah authored
113
114 [self release]; self = nil;
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
115 }
116
117 return self;
118 }
119
6e2e79d @mikeabdullah +webLocationFromPasteboard: doesn't need type argument.
mikeabdullah authored
120 + (KSWebLocation *)webLocationFromPasteboard:(NSPasteboard *)pasteboard;
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
121 {
122 KSWebLocation *result = nil;
123
4ef5615 @mikeabdullah Pasteboard reading uses NSTextCheckingResult when available for natural ...
mikeabdullah authored
124 NSURL *URL = [self URLFromPasteboard:pasteboard];
af949f5 Patch up reading of multiple files from Finder.
Mike authored
125 if (URL)
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
126 {
af949f5 Patch up reading of multiple files from Finder.
Mike authored
127 result = [KSWebLocation webLocationWithURL:URL
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
128 title:[WebView URLTitleFromPasteboard:pasteboard]];
129 }
130
131 return result;
132 }
133
4ef5615 @mikeabdullah Pasteboard reading uses NSTextCheckingResult when available for natural ...
mikeabdullah authored
134 + (NSURL *)URLFromPasteboard:(NSPasteboard *)pboard
135 {
136 NSURL *result = [WebView URLFromPasteboard:pboard];
137
138 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
139 if (!result)
140 {
141 NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker];
142 if ([spellChecker respondsToSelector:@selector(checkString:range:types:options:inSpellDocumentWithTag:orthography:wordCount:)])
143 {
144 NSString *string = [pboard stringForType:NSStringPboardType];
145
146 NSArray *checkResults = [spellChecker checkString:string
147 range:NSMakeRange(0, [string length])
148 types:NSTextCheckingTypeLink
149 options:nil
150 inSpellDocumentWithTag:0
151 orthography:NULL
152 wordCount:NULL];
153
154 if ([checkResults count])
155 {
156 result = [[checkResults objectAtIndex:0] URL];
157 }
158 }
159 }
160 #endif
161
162 return result;
163 }
164
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
165 #pragma mark Deprecated
166
167 + (NSArray *)webLocationPasteboardTypes
168 {
169 return [NSArray arrayWithObjects:
170 @"WebURLsWithTitlesPboardType",
171 @"BookmarkDictionaryListPboardType",
172 kUTTypeURL, // contains the target URL when dragging webloc
173 NSFilenamesPboardType,
174 NSURLPboardType,
175 NSStringPboardType,
176 NSRTFPboardType,
177 NSRTFDPboardType, nil];
178 }
179
180 /* Retrieve URLs and their titles from the pasteboard for the "BookmarkDictionaryListPboardType" type
181 */
182 + (NSArray *)webLocationsWithBookmarkDictionariesPasteboardPropertyList:(id)propertyList;
183 {
184 NSArray *result = nil;
185
186 NSArray *arrayFromData = propertyList;
187 if (arrayFromData && [arrayFromData isKindOfClass:[NSArray class]] && [arrayFromData count] > 0)
188 {
189 NSDictionary *objectInfo = [arrayFromData objectAtIndex:0];
190 if ([objectInfo isKindOfClass:[NSDictionary class]])
191 {
192 NSString *URLString = [objectInfo objectForKey:@"URLString"];
1eb3fb9 @mikeabdullah Can use +[KSURLFormatter URLFromString:] instead of internal +URLWithStr...
mikeabdullah authored
193 NSURL *URL = [KSURLFormatter URLFromString:URLString]; /// encodeLegally to handle accented characters
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
194
195 if (URL)
196 {
197 NSString *title = [[objectInfo objectForKey:@"URIDictionary"] objectForKey:@"title"];
90e262e @mikeabdullah Guess titles when reading from web locations from pboard URLs
mikeabdullah authored
198 if (!title) title = [[self class] guessTitleForURL:URL];
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
199
200 KSWebLocation *webLoc = [[KSWebLocation alloc] initWithURL:URL title:title];
201 result = [NSArray arrayWithObject:webLoc];
202 [webLoc release];
203 }
204 }
205 }
206
207 return result;
208 }
209
210 /* Retrieve URLs and their titles from the pasteboard for the "WebURLsWithTitlesPboardType" type
211 * /// Rewritten 1/5/07 to account for being passed a nil URL
212 */
213 + (NSArray *)webLocationsWithWebURLsWithTitlesPasteboardPropertyList:(id)propertyList
214 {
215 NSMutableArray *result = nil;
216
217 // Bail if we haven't been handed decent data
218 NSArray *rawDataArray = propertyList;
219 if (rawDataArray && [rawDataArray isKindOfClass:[NSArray class]] && [rawDataArray count] >= 2)
220 {
221 // Get the array of URLs and their titles
222 NSArray *URLStrings = [rawDataArray objectAtIndex:0];
223 NSArray *URLTitles = [rawDataArray objectAtIndex:1];
224
225
226 // Run through each URL
227 result = [NSMutableArray arrayWithCapacity:[URLStrings count]];
228
229 NSInteger i;
230 for (i=0; i<[URLStrings count]; i++)
231 {
232 // Convert the string to a proper URL. If actually valid, add it & title to the results
233 NSString *URLString = [URLStrings objectAtIndex:i];
1eb3fb9 @mikeabdullah Can use +[KSURLFormatter URLFromString:] instead of internal +URLWithStr...
mikeabdullah authored
234 NSURL *URL = [KSURLFormatter URLFromString:URLString]; /// encodeLegally to handle accented characters
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
235 if (URL)
236 {
237 KSWebLocation *aWebLocation = [[KSWebLocation alloc] initWithURL:URL title:[URLTitles objectAtIndex:i]];
238 [result addObject:aWebLocation];
239 [aWebLocation release];
240 }
241 }
242 }
243
244 return result;
245 }
246
247 + (NSArray *)webLocationsWithFilenamesPasteboardPropertyList:(id)propertyList;
248 {
249 NSArray *filenames = propertyList;
250 NSMutableArray *result = [NSMutableArray arrayWithCapacity:[filenames count]];
251
252 for (NSString *aFilename in filenames)
253 {
254 NSURL *URL = [NSURL fileURLWithPath:aFilename];
90e262e @mikeabdullah Guess titles when reading from web locations from pboard URLs
mikeabdullah authored
255 KSWebLocation *aLocation = [[KSWebLocation alloc] initWithURL:URL title:[[self class] guessTitleForURL:URL]];
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
256 [result addObject:aLocation];
257 [aLocation release];
258 }
259
260 return result;
261 }
262
263 @end
264
265
266 #pragma mark -
267
268
269 @implementation NSPasteboard (KSWebLocation)
270
271 - (NSArray *)readWebLocations;
272 {
273 NSArray *result = nil;
274
af949f5 Patch up reading of multiple files from Finder.
Mike authored
275 // Get the URLs and titles from the best type available on the pasteboard.
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
276 NSString *type = [self availableTypeFromArray:[KSWebLocation webLocationPasteboardTypes]];
277
af949f5 Patch up reading of multiple files from Finder.
Mike authored
278 // Ideally we want to read multiple kUTTypeURLs, but this requires 10.6 or dropping down to CorePasteboard. So for now, fake it by falling back to NSFilenamesPboardType for file URLs (when possible)
279 if ([type isEqualToString:(NSString *)kUTTypeFileURL])
280 {
15b3996 @mikeabdullah Apologies, NSARRAY() is a Karelia macro.
mikeabdullah authored
281 type = [self availableTypeFromArray:[NSArray arrayWithObjects:
282 NSFilenamesPboardType,
283 type,
284 nil]];
af949f5 Patch up reading of multiple files from Finder.
Mike authored
285 }
286
287
288 if ([type isEqualToString:@"BookmarkDictionaryListPboardType"])
289 {
290 result = [KSWebLocation webLocationsWithBookmarkDictionariesPasteboardPropertyList:
291 [self propertyListForType:type]];
292 }
293 else if ([type isEqualToString:@"WebURLsWithTitlesPboardType"])
294 {
295 result = [KSWebLocation webLocationsWithWebURLsWithTitlesPasteboardPropertyList:
296 [self propertyListForType:type]];
297 }
298 else if ([type isEqualToString:NSFilenamesPboardType])
299 {
300 result = [KSWebLocation webLocationsWithFilenamesPasteboardPropertyList:
301 [self propertyListForType:type]];
302 }
303 else
304 {
6e2e79d @mikeabdullah +webLocationFromPasteboard: doesn't need type argument.
mikeabdullah authored
305 KSWebLocation *webloc = [KSWebLocation webLocationFromPasteboard:self];
af949f5 Patch up reading of multiple files from Finder.
Mike authored
306 if (webloc) result = [NSArray arrayWithObject:webloc];
307 }
308
1dd85bd @mikeabdullah Split KSWebLocation pasteboard handling out to a seperate file so you ca...
mikeabdullah authored
309
310 return result;
311 }
312
313 @end
314
Something went wrong with that request. Please try again.