/**
The pasteboard system is the primary mechanism for data exchange * between OpenStep applications. It is used for cut and paste of data, * as the exchange mechanism for services (as listed on the * services menu), for communicating with a spelling server in order to * perform spell checking, and for filter services which convert * data of one typ to another transparently. *
*Pasteboards are identified by names, some of which are standard * and are intended to exist permenantly and be shared between all * applications, others are temporary or private and are used to handle * specific services. *
*All data transferred to/from pasteboards is typed. Mostly * using one of several standard types for common data or using standardised * names which identify particular kinds of files and their contents * (see the NSCreateFileContentsPboardType() an * NSCreateFilenamePboardType() functions for details). It is also possible * for cooperating applications to use their own private types ... any string * value will do. *
*Each pasteboard has an owner ... an object which declares the
* types of data it can provide. Unless versions of the pasteboard data
* corresponding to all the declared types are written to the pasteboard,
* the owner is responsible for producing the data for the pasteboard when
* it is called for (lazy provision of data).
* The pasteboard owner needs to implement the methods of the
* NSPasteboardOwner informal protocl in order to do this.
*
Returns the pasteboard for the specified name. Creates a new pasreboard * if (and only if) one with the given name does not exist. *
* Standard pasteboard names are - *Creates and returns a pasteboard from which the data in the named
* file can be read in all the types to which it can be converted by
* filter services.
* The type of data in the file is inferred from the file extension.
*
No filtering is actually performed until some object asks the * pasteboard for the data, so calling this method is quite inexpensive. *
*/ + (NSPasteboard*) pasteboardByFilteringData: (NSData*)data ofType: (NSString*)type { FilteredPasteboard *p; NSArray *types; NSArray *originalTypes; originalTypes = [NSArray arrayWithObject: type]; types = [FilteredPasteboard _typesFilterableFrom: originalTypes]; p = (FilteredPasteboard*)[FilteredPasteboard pasteboardWithUniqueName]; p->originalTypes = [originalTypes copy]; p->data = [data copy]; [p declareTypes: types owner: p]; return p; } /** *Creates and returns a pasteboard from which the data in the named
* file can be read in all the types to which it can be converted by
* filter services.
* The type of data in the file is inferred from the file extension.
*
Creates and returns a pasteboard where the data contained in pboard * is available for reading in as many types as it can be converted to by * available filter services. This normally expands on the range of types * available in pboard. *
*NB. This only permits a single level of filtering ... if pboard was * previously returned by another filtering method, it is returned instead * of a new pasteboard. *
*/ + (NSPasteboard*) pasteboardByFilteringTypesInPasteboard: (NSPasteboard*)pboard { FilteredPasteboard *p; NSArray *types; NSArray *originalTypes; if ([pboard isKindOfClass: [FilteredPasteboard class]] == YES) { return pboard; } originalTypes = [pboard types]; types = [FilteredPasteboard _typesFilterableFrom: originalTypes]; p = (FilteredPasteboard*)[FilteredPasteboard pasteboardWithUniqueName]; p->originalTypes = [originalTypes copy]; p->pboard = RETAIN(pboard); [p declareTypes: types owner: p]; return p; } /** * Returns an array of the types from which data of the specified type * can be produced by registered filter services.Adds newTypes to the pasteboard and declares newOwner to be the owner * of the pasteboard. Use only after -declareTypes:owner: has been called * for the same owner, because the new owner may not support all the types * declared by a previous owner. *
*Returns the new change count for the pasteboard, or zero if an error * occurs. *
*/ - (int) addTypes: (NSArray*)newTypes owner: (id)newOwner { int count = 0; NS_DURING { count = [target addTypes: newTypes owner: newOwner pasteboard: self oldCount: changeCount]; if (count > 0) { changeCount = count; } } NS_HANDLER { count = 0; [NSException raise: NSPasteboardCommunicationException format: @"%@", [localException reason]]; } NS_ENDHANDLER return count; } /** *Sets the owner of the pasteboard to be newOwner and declares newTypes * as the types of data supported by it. *
*Returns the new change count for the pasteboard, or zero if an error * occurs. *
*/ - (int) declareTypes: (NSArray*)newTypes owner: (id)newOwner { NS_DURING { changeCount = [target declareTypes: newTypes owner: newOwner pasteboard: self]; } NS_HANDLER { [NSException raise: NSPasteboardCommunicationException format: @"%@", [localException reason]]; } NS_ENDHANDLER return changeCount; } /* * Hack to ensure correct release of NSPasteboard objects - * If we are released such that the only thing retaining us * is the pasteboards dictionary, remove us from that dictionary * as well. */ - (void) release { if ([self retainCount] == 2) { [dictionary_lock lock]; RETAIN(super); [pasteboards removeObjectForKey: name]; RELEASE(super); [dictionary_lock unlock]; } RELEASE(super); } /** *Writes data of type dataType to the pasteboard server so that other * applications can read it. The dataType must be one of the types * previously declared for the pasteboard. *
*Returns YES on success, NO if the data could not be written for some * reason. *
*/ - (BOOL) setData: (NSData*)data forType: (NSString*)dataType { BOOL ok = NO; NS_DURING { ok = [target setData: data forType: dataType isFile: NO oldCount: changeCount]; } NS_HANDLER { ok = NO; [NSException raise: NSPasteboardCommunicationException format: @"%@", [localException reason]]; } NS_ENDHANDLER return ok; } /** * Serialises the data in the supplied property list and writes it to the * pasteboard server using the -setData:forType: method. */ - (BOOL) setPropertyList: (id)propertyList forType: (NSString*)dataType { NSData *d = [NSSerializer serializePropertyList: propertyList]; return [self setData: d forType: dataType]; } /** * Writes string it to the pasteboard server using the * -setPropertyList:forType: method. */ - (BOOL) setString: (NSString*)string forType: (NSString*)dataType { return [self setPropertyList: string forType: dataType]; } /** * Writes the contents of the file filename to the pasteboard server * after declaring the type NSFileContentsPboardType as well as a type * based on the file extension (given by the NSCreateFileContentsPboardType() * function) if there is one. */ - (BOOL) writeFileContents: (NSString*)filename { NSFileWrapper *wrapper; NSData *data; NSArray *types; NSString *ext = [filename pathExtension]; BOOL ok = NO; wrapper = [[NSFileWrapper alloc] initWithPath: filename]; data = [wrapper serializedRepresentation]; RELEASE(wrapper); if ([ext length] > 0) { types = [NSArray arrayWithObjects: NSFileContentsPboardType, NSCreateFileContentsPboardType(ext), nil]; } else { types = [NSArray arrayWithObject: NSFileContentsPboardType]; } if ([self declareTypes: types owner: owner] == 0) { return NO; // Unable to declare types. } NS_DURING { ok = [target setData: data forType: NSFileContentsPboardType isFile: YES oldCount: changeCount]; } NS_HANDLER { ok = NO; [NSException raise: NSPasteboardCommunicationException format: @"%@", [localException reason]]; } NS_ENDHANDLER return ok; } /** *Writes the contents of the file wrapper to the pasteboard server * after declaring the type NSFileContentsPboardType as well as a type * based on the file extension of the wrappers preferred filename. *
*Raises an exception if there is no preferred filename. *
*/ - (BOOL) writeFileWrapper: (NSFileWrapper *)wrapper { NSString *filename = [wrapper preferredFilename]; NSData *data; NSArray *types; NSString *ext = [filename pathExtension]; BOOL ok = NO; if (filename == nil) { [NSException raise: NSInvalidArgumentException format: @"Cannot put file on pastboard with " @"no preferred filename"]; } data = [wrapper serializedRepresentation]; if ([ext length] > 0) { types = [NSArray arrayWithObjects: NSFileContentsPboardType, NSCreateFileContentsPboardType(ext), nil]; } else { types = [NSArray arrayWithObject: NSFileContentsPboardType]; } if ([self declareTypes: types owner: owner] == 0) { return NO; // Unable to declare types. } NS_DURING { ok = [target setData: data forType: NSFileContentsPboardType isFile: YES oldCount: changeCount]; } NS_HANDLER { ok = NO; [NSException raise: NSPasteboardCommunicationException format: @"%@", [localException reason]]; } NS_ENDHANDLER return ok; } /** * Returns the first type listed in types which the receiver has been * declared to support. */ - (NSString*) availableTypeFromArray: (NSArray*)types { NSString *type = nil; NS_DURING { int count = 0; type = [target availableTypeFromArray: types changeCount: &count]; changeCount = count; } NS_HANDLER { type = nil; [NSException raise: NSPasteboardCommunicationException format: @"%@", [localException reason]]; } NS_ENDHANDLER return type; } /** * Returns all the types that the receiver has been declared to support. */ - (NSArray*) types { NSArray *result = nil; NS_DURING { int count = 0; result = [target typesAndChangeCount: &count]; changeCount = count; } NS_HANDLER { result = nil; [NSException raise: NSPasteboardCommunicationException format: @"%@", [localException reason]]; } NS_ENDHANDLER return result; } /** * Returns the change count for the receiving pasteboard. This count * is incremented whenever the owner of the pasteboard is changed. */ - (int) changeCount { NS_DURING { int count; count = [target changeCount]; changeCount = count; } NS_HANDLER { [NSException raise: NSPasteboardCommunicationException format: @"%@", [localException reason]]; } NS_ENDHANDLER return changeCount; } /** * Returns data from the pasteboard of the specified dataType, or nil * if no such data is available.GNUstep adds a mechanism for mapping between OpenStep pasteboard * types and MIME types. This is useful for interopration with other * systems, as MIME types have come into common usage (long after the * OpenStep specification was created). *
*The other extension to the pasteboard system produced by GNUstep * is the ability to keep a history of recent items placed in a * pasteboard, and retrieve data from that history rather than just * the current item. *
*/ @implementation NSPasteboard (GNUstepExtensions) /** * Once the -setChangeCount: message has been sent to an NSPasteboard * the object will gain an extra GNUstep behaviour - when geting data * from the pasteboard, the data need no longer be from the latest * version but may be a version from a previous representation with * the specified change count. */ - (void) setChangeCount: (int)count { useHistory = YES; changeCount = count; } /** * Sets the number of changes for which pasteboard data is kept.Returns a standardised pasteboard type for file contents, * formed from the supplied file extension. *
*Data written to a pasteboard with a file contents type should * be written using the [NSPasteboard-writeFileContents:] or * [NSPasteboard-writeFileWrapper:] method. Similarly, the data should * be read using the [NSPasteboard-readFileContentsType:toFile:] or * [NSPasteboard-readFileWrapper] method. */ NSString* NSCreateFileContentsPboardType(NSString *fileType) { NSString *ext = [fileType pathExtension]; if ([ext length] == 0) { ext = fileType; } return [NSString stringWithFormat: @"%@%@", contentsPrefix, ext]; } /** *
Returns a standardised pasteboard type for file names, * formed from the supplied file extension. *
*Data written to a pasteboard with a file names type should
* be a single name writen using [NSPasteboard-setString:forType:] or
* an array of strings written using
* [NSPasteboard-setPropertyList:forType:].
* Similarly, the data should be read using
* the [NSPasteboard-stringForType:] or
* [NSPasteboard-propertyListForType:] method.
*
See also the NSGetFileType() and NSGetFileTypes() functions.
*/
NSString*
NSCreateFilenamePboardType(NSString *fileType)
{
NSString *ext = [fileType pathExtension];
if ([ext length] == 0)
{
ext = fileType;
}
return [NSString stringWithFormat: @"%@%@", namePrefix, ext];
}
/**
* Returns the file type (fileType extension) corresponding to the
* pasteboard type given.
* This is a counterpart to the NSCreateFilenamePboardType() function.
*/
NSString*
NSGetFileType(NSString *pboardType)
{
if ([pboardType hasPrefix: contentsPrefix])
{
return [pboardType substringFromIndex: [contentsPrefix length]];
}
if ([pboardType hasPrefix: namePrefix])
{
return [pboardType substringFromIndex: [namePrefix length]];
}
return nil;
}
/**
* Returns the file types (filename extensions) corresponding to the
* pasteboard types given.
*/
NSArray*
NSGetFileTypes(NSArray *pboardTypes)
{
NSMutableArray *a = [NSMutableArray arrayWithCapacity: [pboardTypes count]];
unsigned int i;
for (i = 0; i < [pboardTypes count]; i++)
{
NSString *s = NSGetFileType([pboardTypes objectAtIndex: i]);
if (s && ! [a containsObject: s])
{
[a addObject: s];
}
}
if ([a count] > 0)
{
return AUTORELEASE([a copy]);
}
return nil;
}