API  0.9.7
 All Classes Files Functions Variables Macros Groups Pages
CPPasteboard.j
Go to the documentation of this file.
1 /*
2  * CPPasteboard.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 CPGeneralPboard = @"CPGeneralPboard";
26 CPFontPboard = @"CPFontPboard";
27 CPRulerPboard = @"CPRulerPboard";
28 CPFindPboard = @"CPFindPboard";
29 CPDragPboard = @"CPDragPboard";
30 
31 CPColorPboardType = @"CPColorPboardType";
32 CPFilenamesPboardType = @"CPFilenamesPboardType";
33 CPFontPboardType = @"CPFontPboardType";
34 CPHTMLPboardType = @"CPHTMLPboardType";
35 CPStringPboardType = @"CPStringPboardType";
36 CPURLPboardType = @"CPURLPboardType";
37 CPImagesPboardType = @"CPImagesPboardType";
38 CPVideosPboardType = @"CPVideosPboardType";
39 
40 UTF8PboardType = @"public.utf8-plain-text";
41 
42 // Deprecated
43 CPImagePboardType = @"CPImagePboardType";
44 
45 
46 var CPPasteboards = nil,
48 
55 @implementation CPPasteboard : CPObject
56 {
57  CPArray _types;
58  CPDictionary _owners;
59  CPDictionary _provided;
60 
61  unsigned _changeCount;
62  CPString _stateUID;
63 
64  WebScriptObject _nativePasteboard;
65 }
66 
67 /*
68  @ignore
69 */
70 + (void)initialize
71 {
72  if (self !== [CPPasteboard class])
73  return;
74 
75  [self setVersion:1.0];
76 
77  CPPasteboards = @{};
78 
79  if (typeof window.cpPasteboardWithName !== "undefined")
81 }
82 
86 + (id)generalPasteboard
87 {
88  return [CPPasteboard pasteboardWithName:CPGeneralPboard];
89 }
90 
96 + (id)pasteboardWithName:(CPString)aName
97 {
98  var pasteboard = [CPPasteboards objectForKey:aName];
99 
100  if (pasteboard)
101  return pasteboard;
102 
103  pasteboard = [[CPPasteboard alloc] _initWithName:aName];
104  [CPPasteboards setObject:pasteboard forKey:aName];
105 
106  return pasteboard;
107 }
108 
109 /* @ignore */
110 - (id)_initWithName:(CPString)aName
111 {
112  self = [super init];
113 
114  if (self)
115  {
116 // _name = aName;
117  _types = [];
118 
119  _owners = @{};
120  _provided = @{};
121 
122  _changeCount = 0;
123 
125  {
126  _nativePasteboard = window.cpPasteboardWithName(aName);
127  [self _synchronizePasteboard];
128  }
129  }
130 
131  return self;
132 }
133 
140 - (unsigned)addTypes:(CPArray)types owner:(id)anOwner
141 {
142  var i = 0,
143  count = types.length;
144 
145  for (; i < count; ++i)
146  {
147  var type = types[i];
148 
149  if (![_owners objectForKey:type])
150  {
151  [_types addObject:type];
152  [_provided removeObjectForKey:type];
153  }
154 
155  [_owners setObject:anOwner forKey:type];
156  }
157 
158  if (_nativePasteboard)
159  {
160  var nativeTypes = [types copy];
161  if ([types containsObject:CPStringPboardType])
162  nativeTypes.push(UTF8PboardType);
163 
164  _nativePasteboard.addTypes_(nativeTypes);
165  }
166 
167  return ++_changeCount;
168 }
169 
176 - (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
177 {
178  [self _declareTypes:types owner:anOwner updateNativePasteboard:YES];
179 }
180 
182 - (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate
183 {
184  [_types setArray:types];
185 
186  _owners = @{};
187  _provided = @{};
188 
189  if (anOwner)
190  {
191  var count = _types.length;
192  while (count--)
193  [_owners setObject:anOwner forKey:_types[count]];
194  }
195 
196  if (_nativePasteboard && shouldUpdate)
197  {
198  var nativeTypes = [types copy];
199  if ([types containsObject:CPStringPboardType])
200  nativeTypes.push(UTF8PboardType);
201 
202  _nativePasteboard.declareTypes_(nativeTypes);
203  _changeCount = _nativePasteboard.changeCount();
204  }
205 
206  return ++_changeCount;
207 }
208 
215 - (BOOL)setData:(CPData)aData forType:(CPString)aType
216 {
217  [_provided setObject:aData forKey:aType];
218 
219  if (aType === CPStringPboardType)
220  [self setData:aData forType:UTF8PboardType];
221 
222  return YES;
223 }
224 
231 - (BOOL)setPropertyList:(id)aPropertyList forType:(CPString)aType
232 {
233  return [self setData:[CPPropertyListSerialization dataFromPropertyList:aPropertyList format:CPPropertyList280NorthFormat_v1_0] forType:aType];
234 }
235 
242 - (void)setString:(CPString)aString forType:(CPString)aType
243 {
244  // Putting a non-string on the string pasteboard can lead to strange crashes.
245  if (aString && aString.isa && ![aString isKindOfClass:CPString])
246  [CPException raise:CPInvalidArgumentException reason:"CPPasteboard setString:forType: must be called with a string."];
247 
248  [self setPropertyList:aString forType:aType];
249 }
250 
251 // Determining Types
258 - (CPString)availableTypeFromArray:(CPArray)anArray
259 {
260  return [anArray firstObjectCommonWithArray:[self types]];
261 }
262 
266 - (CPArray)types
267 {
268  [self _synchronizePasteboard];
269  return _types;
270 }
271 
272 // Reading data
276 - (unsigned)changeCount
277 {
278  return _changeCount;
279 }
280 
286 - (CPData)dataForType:(CPString)aType
287 {
288  var data = [_provided objectForKey:aType];
289 
290  if (data)
291  return data;
292 
293  var owner = [_owners objectForKey:aType];
294 
295  if (owner)
296  {
297  [owner pasteboard:self provideDataForType:aType];
298  return [_provided objectForKey:aType];
299  }
300 
301  if (aType === CPStringPboardType)
302  return [self dataForType:UTF8PboardType];
303 
304  return nil;
305 }
306 
307 - (void)_synchronizePasteboard
308 {
309  if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount)
310  {
311  var nativeTypes = [_nativePasteboard.types() copy];
312  if ([nativeTypes containsObject:UTF8PboardType])
313  nativeTypes.push(CPStringPboardType);
314 
315  [self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO];
316 
317  _changeCount = _nativePasteboard.changeCount();
318  }
319 }
320 
324 - (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
325 {
326  if (aType === CPStringPboardType)
327  {
328  var string = _nativePasteboard.stringForType_(UTF8PboardType);
329 
330  [self setString:string forType:CPStringPboardType];
331  [self setString:string forType:UTF8PboardType];
332  }
333  else
334  [self setString:_nativePasteboard.stringForType_(aType) forType:aType];
335 }
336 
342 - (id)propertyListForType:(CPString)aType
343 {
344  var data = [self dataForType:aType];
345 
346  if (data)
347  return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyList280NorthFormat_v1_0];
348 
349  return nil;
350 }
351 
357 - (CPString)stringForType:(CPString)aType
358 {
359  return [self propertyListForType:aType];
360 }
361 
362 /* @ignore */
363 - (CPString)_generateStateUID
364 {
365  var bits = 32;
366 
367  _stateUID = @"";
368 
369  while (bits--)
370  _stateUID += FLOOR(RAND() * 16.0).toString(16).toUpperCase();
371 
372  return _stateUID;
373 }
374 
375 /* @ignore */
376 - (CPString)_stateUID
377 {
378  return _stateUID;
379 }
380 
381 @end
382 
383 #if PLATFORM(DOM)
384 
385 var DOMDataTransferPasteboard = nil;
386 
387 @implementation _CPDOMDataTransferPasteboard : CPPasteboard
388 {
389  DataTransfer _dataTransfer;
390 }
391 
392 + (_CPDOMDataTransferPasteboard)DOMDataTransferPasteboard
393 {
394  if (!DOMDataTransferPasteboard)
395  DOMDataTransferPasteboard = [[_CPDOMDataTransferPasteboard alloc] init];
396 
397  return DOMDataTransferPasteboard;
398 }
399 
400 - (void)_setDataTransfer:(DataTransfer)aDataTransfer
401 {
402  _dataTransfer = aDataTransfer;
403 }
404 
405 - (void)_setPasteboard:(CPPasteboard)aPasteboard
406 {
407  _dataTransfer.clearData();
408 
409  var types = [aPasteboard types],
410  count = types.length;
411 
412  while (count--)
413  {
414  var type = types[count];
415 
416  if (type === CPStringPboardType)
417  _dataTransfer.setData(type, [aPasteboard stringForType:type]);
418  else
419  _dataTransfer.setData(type, [[aPasteboard dataForType:type] rawString]);
420  }
421 }
422 
423 - (CPArray)types
424 {
425  return Array.prototype.slice.apply(_dataTransfer.types);
426 }
427 
428 - (CPData)dataForType:(CPString)aType
429 {
430  var dataString = _dataTransfer.getData(aType);
431 
432  if (aType === CPStringPboardType)
433  return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0];
434 
435  return [CPData dataWithRawString:dataString];
436 }
437 
438 - (id)propertyListForType:(CPString)aType
439 {
440  if (aType === CPStringPboardType)
441  return _dataTransfer.getData(aType);
442 
443  return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat];
444 }
445 
446 @end
447 
448 #endif