diff --git a/ChangeLog b/ChangeLog index 186b4f19f..a7d985f84 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,8 @@ 2003-06-27 Richard Frith-Macdonald * Source/NSPasteboard.m: Documented all methods, fixed minor bugs - writign fiels to pastebaords, implemented ([+typesFilterableTo:]) + writing fiels to pastebaords, implemented ([+typesFilterableTo:]) + wrote (partial implementation ...) the unimplemented filters stuff. 2003-06-26 Ludovic Marcotte diff --git a/Source/GSServicesManager.m b/Source/GSServicesManager.m index 24a5dc8f3..d5efd647f 100644 --- a/Source/GSServicesManager.m +++ b/Source/GSServicesManager.m @@ -1312,16 +1312,8 @@ GSContactApplication(NSString *appName, NSString *port, NSDate *expire) return app; } -/** - *

Given the name of a serviceItem, and some data in a pasteboard - * this function sends the data to the service provider (launching - * another application if necessary) and retrieves the result of - * the service in the pastebaord. - *

- * Returns YES on success, NO otherwise. - */ BOOL -NSPerformService(NSString *serviceItem, NSPasteboard *pboard) +GSPerformService(NSString *serviceItem, NSPasteboard *pboard, BOOL isFilter) { NSDictionary *service; NSString *port; @@ -1335,7 +1327,14 @@ NSPerformService(NSString *serviceItem, NSPasteboard *pboard) NSString *userData; NSString *error = nil; - service = [[manager menuServices] objectForKey: serviceItem]; + if (isFilter == YES) + { + service = [[manager filters] objectForKey: serviceItem]; + } + else + { + service = [[manager menuServices] objectForKey: serviceItem]; + } if (service == nil) { NSRunAlertPanel(nil, @@ -1417,6 +1416,20 @@ NSPerformService(NSString *serviceItem, NSPasteboard *pboard) return YES; } +/** + *

Given the name of a serviceItem, and some data in a pasteboard + * this function sends the data to the service provider (launching + * another application if necessary) and retrieves the result of + * the service in the pastebaord. + *

+ * Returns YES on success, NO otherwise. + */ +BOOL +NSPerformService(NSString *serviceItem, NSPasteboard *pboard) +{ + return GSPerformService(serviceItem, pboard, NO); +} + /** *

Controls whether the item name should be included in the services menu. *

diff --git a/Source/NSPasteboard.m b/Source/NSPasteboard.m index accc77347..d33af45eb 100644 --- a/Source/NSPasteboard.m +++ b/Source/NSPasteboard.m @@ -69,6 +69,37 @@ @end @implementation FilteredPasteboard +/** + * Find a filter specification to use. + */ ++ (NSString*) _filterForType: (NSString*)type fromTypes: (NSArray*)types +{ + NSDictionary *filters = [[GSServicesManager manager] filters]; + NSEnumerator *enumerator = [filters keyEnumerator]; + NSString *key; + + while ((key = [enumerator nextObject]) != nil) + { + NSDictionary *info = [filters objectForKey: key]; + NSArray *returnTypes = [info objectForKey: @"NSReturnTypes"]; + + if ([returnTypes containsObject: type] == YES) + { + NSArray *sendTypes = [info objectForKey: @"NSSendTypes"]; + unsigned i; + + for (i = 0; i < [types count]; i++) + { + if ([sendTypes containsObject: [types objectAtIndex: i]] == YES) + { + return key; + } + } + } + } + return nil; +} + /** * Given an array of types, produce an array of all the types we can * make from that using a single filter. @@ -116,12 +147,76 @@ - (void) pasteboard: (NSPasteboard*)sender provideDataForType: (NSString*)type { + NSDictionary *info; + NSString *filterName = nil; + NSString *fromType = nil; + NSString *mechanism; + + NSAssert(sender == self, NSInvalidArgumentException); + /* * If the requested type is the same as one of the original types, * no filtering is required ... and we can just write what we have. */ if ([originalTypes containsObject: type] == YES) { + info = [NSDictionary dictionaryWithObjectsAndKeys: + @"NSIdentity", @"NSInputMechanism", + nil]; + filterName = nil; + } + else + { + NSDictionary *filters; + NSEnumerator *enumerator; + + /* + * Locate the filter information needed, including the type we are + * converting from and the name of the filter to use. + */ + filters = [[GSServicesManager manager] filters]; + enumerator = [filters keyEnumerator]; + while (fromType == nil && (filterName = [enumerator nextObject]) != nil) + { + NSArray *returnTypes; + + info = [filters objectForKey: filterName]; + returnTypes = [info objectForKey: @"NSReturnTypes"]; + + if ([returnTypes containsObject: type] == YES) + { + NSArray *sendTypes = [info objectForKey: @"NSSendTypes"]; + unsigned i; + + for (i = 0; i < [types count]; i++) + { + fromType = [types objectAtIndex: i]; + if ([sendTypes containsObject: fromType] == YES) + { + break; + } + fromType = nil; + } + } + } + } + + mechanism = [info objectForKey: @"NSInputMechanism"]; + + if ([mechanism isEqualToString: @"NSUnixStdio"] == YES) + { +// FIXME + } + else if ([mechanism isEqualToString: @"NSMapFile"] == YES) + { +// FIXME + } + else if ([mechanism isEqualToString: @"NSIdentity"] == YES) + { + /* + * An 'identity' filter simply places the required data on the + * pasteboard. + */ if (data != nil) { [sender setData: data forType: type]; @@ -139,7 +234,36 @@ } else { -// FIXME + extern BOOL GSPerformService(NSString*, NSPasteboard*, BOOL); + NSPasteboard *tmp; + + /* + * Put data onto a pasteboard that can be used by the service provider. + */ + if (data != nil) + { + tmp = [NSPasteboard pasteboardWithUniqueName]; + [tmp setData: data forType: fromType]; + } + else if (file != nil) + { + tmp = [NSPasteboard pasteboardWithUniqueName]; + [tmp writeFileContents: file]; + } + else + { + tmp = pboard; // Already in a pasteboard. + } + + /* + * Now get the service provider to do the job. + */ + GSPerformService(filterName, tmp, YES) + + /* + * Finally, make it available. + */ + [sender setData: [tmp dataForType: type] forType: type]; } }