Lots of tidyups

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@17076 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2003-06-30 16:17:45 +00:00
parent ccb28dedd8
commit 6a39184087
4 changed files with 258 additions and 134 deletions

View file

@ -66,7 +66,7 @@
- (BOOL) application: (NSApplication*)theApp
printFile: (NSString*)file;
- (void) doService: (NSMenuItem*)item;
- (NSDictionary*) filters;
- (NSArray*) filters;
- (BOOL) hasRegisteredTypes: (NSDictionary*)service;
- (NSString*) item2title: (NSMenuItem*)item;
- (void) loadServices;

View file

@ -548,7 +548,7 @@ static NSString *disabledName = @".GNUstepDisabled";
/**
* Return a dictionary of information about registered filter services.
*/
- (NSDictionary*) filters
- (NSArray*) filters
{
return [_allServices objectForKey: @"ByFilter"];
}
@ -1312,8 +1312,16 @@ GSContactApplication(NSString *appName, NSString *port, NSDate *expire)
return app;
}
/**
* <p>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.
* </p>
* Returns YES on success, NO otherwise.
*/
BOOL
GSPerformService(NSString *serviceItem, NSPasteboard *pboard, BOOL isFilter)
NSPerformService(NSString *serviceItem, NSPasteboard *pboard)
{
NSDictionary *service;
NSString *port;
@ -1327,26 +1335,14 @@ GSPerformService(NSString *serviceItem, NSPasteboard *pboard, BOOL isFilter)
NSString *userData;
NSString *error = nil;
if (isFilter == YES)
service = [[manager menuServices] objectForKey: serviceItem];
if (service == nil)
{
service = [[manager filters] objectForKey: serviceItem];
if (service == nil)
{
NSLog(@"No service matching '%@'", serviceItem);
return NO; /* No matching service. */
}
}
else
{
service = [[manager menuServices] objectForKey: serviceItem];
if (service == nil)
{
NSRunAlertPanel(nil,
@"No service matching '%@'",
@"Continue", nil, nil,
serviceItem);
return NO; /* No matching service. */
}
NSRunAlertPanel(nil,
@"No service matching '%@'",
@"Continue", nil, nil,
serviceItem);
return NO; /* No matching service. */
}
port = [service objectForKey: @"NSPortName"];
@ -1362,14 +1358,7 @@ GSPerformService(NSString *serviceItem, NSPasteboard *pboard, BOOL isFilter)
finishBy = [NSDate dateWithTimeIntervalSinceNow: seconds];
appPath = [service objectForKey: @"ServicePath"];
userData = [service objectForKey: @"NSUserData"];
if (isFilter == YES)
{
message = [service objectForKey: @"NSFilter"];
}
else
{
message = [service objectForKey: @"NSMessage"];
}
message = [service objectForKey: @"NSMessage"];
selName = [message stringByAppendingString: @":userData:error:"];
/*
@ -1379,17 +1368,10 @@ GSPerformService(NSString *serviceItem, NSPasteboard *pboard, BOOL isFilter)
provider = GSContactApplication(appPath, port, finishBy);
if (provider == nil)
{
if (isFilter == YES)
{
NSLog(@"Failed to contact service provider for '%@'", serviceItem);
}
else
{
NSRunAlertPanel(nil,
@"Failed to contact service provider for '%@'",
@"Continue", nil, nil,
serviceItem);
}
NSRunAlertPanel(nil,
@"Failed to contact service provider for '%@'",
@"Continue", nil, nil,
serviceItem);
return NO;
}
@ -1425,38 +1407,16 @@ GSPerformService(NSString *serviceItem, NSPasteboard *pboard, BOOL isFilter)
if (error != nil)
{
if (isFilter == YES)
{
NSLog(@"Failed to contact service provider for '%@': %@",
serviceItem, error);
}
else
{
NSRunAlertPanel(nil,
@"Failed to contact service provider for '%@': %@",
@"Continue", nil, nil,
serviceItem, error);
}
NSRunAlertPanel(nil,
@"Failed to contact service provider for '%@': %@",
@"Continue", nil, nil,
serviceItem, error);
return NO;
}
return YES;
}
/**
* <p>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.
* </p>
* Returns YES on success, NO otherwise.
*/
BOOL
NSPerformService(NSString *serviceItem, NSPasteboard *pboard)
{
return GSPerformService(serviceItem, pboard, NO);
}
/**
* <p>Controls whether the item name should be included in the services menu.
* </p>

View file

@ -352,6 +352,55 @@
data of a particular type, but the pasteboard only contains data of
some other type.
</p>
<p>
A filter service definition in the Info.plist file differs from that
of a standard service in that the <em>NSMessage</em> entry is replaced
by an <em>NSFilter</em> entry, the <em>NSMenuItem</em> and
<em>NSKeyEquivalent</em> entries are omitted, and a few other entries
may be added -
</p>
<deflist>
<term>NSFilter</term>
<desc>
This is the first part of the message name for the method
which actually implements the filter service ... just like
the NSMessage entry in a normal service.
</desc>
<term>NSInputMechanism</term>
<desc>
This (optional) entry is a string value specifying an alternative
mechanism for performing the filer service (instead of sending a
message to an application to ask it to do it).<be />
Possible values are -
<deflist>
<term>NSIdentity</term>
<desc>
The data to be filtered is simply placed upon the pasteboard
without any transformation.
</desc>
<term>NSMapFile</term>
<desc>
The data to be filtered is the name of a file, which is
loaded into memory and placed on the pasteboard without
any transformation.<br />
If the data to be filtered contains multiple file names,
only the first is used.
</desc>
<term>NSUnixStdio</term>
<desc>
The data to be filtered is the name of a file, which is
passed as the argument to a unix command-line program,
and the standard output of that program is captured and
placed on the pasteboard. The program is run each time
data is requested, so this is inefficient in comparison
to a filter implemented using the standard method (of
sending a message to a running application).<br />
If the data to be filtered contains multiple file names,
only the first is used.
</desc>
</deflist>
</desc>
</deflist>
</section>
</chapter>
*/
@ -402,36 +451,6 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
@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
@ -440,18 +459,20 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
+ (NSArray*) _typesFilterableFrom: (NSArray*)from
{
NSMutableSet *types = [NSMutableSet setWithCapacity: 8];
NSDictionary *info = [[GSServicesManager manager] filters];
NSArray *filters = [[GSServicesManager manager] filters];
unsigned c = [filters count];
unsigned i;
for (i = 0; i < [from count]; i++)
{
NSString *type = [from objectAtIndex: i];
NSEnumerator *enumerator = [info objectEnumerator];
NSString *type = [from objectAtIndex: i];
unsigned j;
[types addObject: type]; // Always include original type
while ((info = [enumerator nextObject]) != nil)
for (j = 0; j < c; j++)
{
NSDictionary *info = [filters objectAtIndex: j];
NSArray *sendTypes = [info objectForKey: @"NSSendTypes"];
if ([sendTypes containsObject: type] == YES)
@ -480,7 +501,6 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
provideDataForType: (NSString*)type
{
NSDictionary *info;
NSString *filterName = nil;
NSString *fromType = nil;
NSString *mechanism;
@ -495,24 +515,24 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
info = [NSDictionary dictionaryWithObjectsAndKeys:
@"NSIdentity", @"NSInputMechanism",
nil];
filterName = nil;
}
else
{
NSDictionary *filters;
NSEnumerator *enumerator;
NSArray *filters;
unsigned count;
unsigned filterNumber = 0;
/*
* 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)
count = [filters count];
while (fromType == nil && filterNumber < count)
{
NSArray *returnTypes;
info = [filters objectForKey: filterName];
info = [filters objectAtIndex: filterNumber++];
returnTypes = [info objectForKey: @"NSReturnTypes"];
if ([returnTypes containsObject: type] == YES)
@ -548,7 +568,8 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
/*
* The data for an NSUnixStdio filter must be one or more filenames
*/
if ([fromType isEqualToString: NSFilenamesPboardType] == NO
if ([fromType isEqualToString: NSStringPboardType] == NO
&& [fromType isEqualToString: NSFilenamesPboardType] == NO
&& [fromType hasPrefix: namePrefix] == NO)
{
[sender setData: [NSData data] forType: type];
@ -616,8 +637,43 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
*/
[sender setData: m forType: type];
}
else if ([mechanism isEqualToString: @"NSIdentity"] == YES
|| [mechanism isEqualToString: @"NSMapFile"] == YES)
else if ([mechanism isEqualToString: @"NSMapFile"] == YES)
{
NSString *filename;
NSData *d;
id o;
if ([fromType isEqualToString: NSStringPboardType] == NO
&& [fromType isEqualToString: NSFilenamesPboardType] == NO
&& [fromType hasPrefix: namePrefix] == NO)
{
[sender setData: [NSData data] forType: type];
return; // Not the name of a file to filter.
}
o = [NSDeserializer deserializePropertyListFromData: d
mutableContainers: NO];
if ([o isKindOfClass: [NSString class]] == YES)
{
filename = o;
}
else if ([o isKindOfClass: [NSArray class]] == YES
&& [o count] > 0
&& [[o objectAtIndex: 0] isKindOfClass: [NSString class]] == YES)
{
filename = [o objectAtIndex: 0];
}
else
{
[sender setData: [NSData data] forType: type];
return; // Not the name of a file to filter.
}
d = [NSData dataWithContentsOfFile: filename];
[sender setData: d forType: type];
}
else if ([mechanism isEqualToString: @"NSIdentity"] == YES)
{
/*
* An 'identity' filter simply places the required data on the
@ -640,8 +696,17 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
}
else
{
extern BOOL GSPerformService(NSString*, NSPasteboard*, BOOL);
NSPasteboard *tmp;
NSString *port;
NSString *timeout;
double seconds;
NSDate *finishBy;
NSString *appPath;
id provider;
NSString *message;
NSString *selName;
NSString *userData;
NSString *error = nil;
/*
* Put data onto a pasteboard that can be used by the service provider.
@ -663,10 +728,86 @@ static NSString *namePrefix = @"NSTypedFilenamesPboardType:";
tmp = pboard; // Already in a pasteboard.
}
port = [info objectForKey: @"NSPortName"];
timeout = [info objectForKey: @"NSTimeout"];
if (timeout && [timeout floatValue] > 100)
{
seconds = [timeout floatValue] / 1000.0;
}
else
{
seconds = 30.0;
}
finishBy = [NSDate dateWithTimeIntervalSinceNow: seconds];
appPath = [info objectForKey: @"NSExecutable"];
if ([appPath length] > 0)
{
/*
* A relative path for NSExecutable is relative to the bundle.
*/
if ([appPath isAbsolutePath] == NO)
{
NSString *bundlePath = [info objectForKey: @"ServicePath"];
appPath = [bundlePath stringByAppendingPathComponent: appPath];
}
}
else
{
appPath = [info objectForKey: @"ServicePath"];
}
userData = [info objectForKey: @"NSUserData"];
message = [info objectForKey: @"NSFilter"];
selName = [message stringByAppendingString: @":userData:error:"];
/*
* Now get the service provider to do the job.
* Locate the service provider ... this will be a proxy to the remote
* object, or a local object (if we provide the service ourself)
*/
GSPerformService(filterName, tmp, YES);
provider = GSContactApplication(appPath, port, finishBy);
if (provider == nil)
{
NSLog(@"Failed to contact service provider at '%@' '%@'",
appPath, port);
return;
}
/*
* If the service provider is a remote object, we can set timeouts on
* the NSConnection so we don't hang waiting for it to reply.
*/
if ([provider isProxy] == YES)
{
NSConnection *connection;
connection = [(NSDistantObject*)provider connectionForProxy];
seconds = [finishBy timeIntervalSinceNow];
[connection setRequestTimeout: seconds];
[connection setReplyTimeout: seconds];
}
/*
* At last, we ask for the service to be performed.
*/
NS_DURING
{
[provider performService: selName
withPasteboard: tmp
userData: userData
error: &error];
}
NS_HANDLER
{
error = [NSString stringWithFormat: @"%@", [localException reason]];
}
NS_ENDHANDLER
if (error != nil)
{
NSLog(@"Failed to contact service provider for '%@': %@",
appPath, error);
return;
}
/*
* Finally, make it available.
@ -1117,8 +1258,9 @@ static NSMapTable *mimeMap = NULL;
+ (NSArray*) typesFilterableTo: (NSString*)type
{
NSMutableSet *types = [NSMutableSet setWithCapacity: 8];
NSDictionary *info = [[GSServicesManager manager] filters];
NSEnumerator *enumerator = [info objectEnumerator];
NSArray *filters = [[GSServicesManager manager] filters];
NSEnumerator *enumerator = [filters objectEnumerator];
NSDictionary *info;
[types addObject: type]; // Always include original type

View file

@ -24,6 +24,7 @@
#include <Foundation/NSArray.h>
#include <Foundation/NSBundle.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSSet.h>
#include <Foundation/NSFileManager.h>
#include <Foundation/NSString.h>
#include <Foundation/NSProcessInfo.h>
@ -44,7 +45,8 @@ static NSString *cacheName = @".GNUstepServices";
static BOOL verbose = NO;
static NSMutableDictionary *serviceMap;
static NSMutableDictionary *filterMap;
static NSMutableArray *filterList;
static NSMutableSet *filterSet;
static NSMutableDictionary *printMap;
static NSMutableDictionary *spellMap;
static NSMutableDictionary *applicationMap;
@ -94,7 +96,8 @@ main(int argc, char** argv, char **env_c)
[NSSerializer shouldBeCompact: YES];
serviceMap = [NSMutableDictionary dictionaryWithCapacity: 64];
filterMap = [NSMutableDictionary dictionaryWithCapacity: 66];
filterList = [NSMutableArray arrayWithCapacity: 16];
filterSet = [NSMutableSet setWithCapacity: 64];
printMap = [NSMutableDictionary dictionaryWithCapacity: 8];
spellMap = [NSMutableDictionary dictionaryWithCapacity: 8];
applicationMap = [NSMutableDictionary dictionaryWithCapacity: 64];
@ -286,7 +289,7 @@ main(int argc, char** argv, char **env_c)
fullMap = [NSMutableDictionary dictionaryWithCapacity: 5];
[fullMap setObject: services forKey: @"ByPath"];
[fullMap setObject: serviceMap forKey: @"ByService"];
[fullMap setObject: filterMap forKey: @"ByFilter"];
[fullMap setObject: filterList forKey: @"ByFilter"];
[fullMap setObject: printMap forKey: @"ByPrint"];
[fullMap setObject: spellMap forKey: @"BySpell"];
@ -815,13 +818,13 @@ validateService(NSDictionary *service, NSString *path, unsigned pos)
*/
if ((obj = [result objectForKey: @"NSFilter"]) != nil)
{
NSDictionary *inf;
NSString *str;
NSArray *snd;
NSArray *ret;
BOOL notPresent = NO;
str = [result objectForKey: @"NSInputMechanism"];
if (str)
if (str != nil)
{
if ([str isEqualToString: @"NSUnixStdio"] == NO
&& [str isEqualToString: @"NSMapFile"] == NO
@ -831,25 +834,45 @@ validateService(NSDictionary *service, NSString *path, unsigned pos)
return nil;
}
}
else
else if ([result objectForKey: @"NSPortName"] == nil)
{
if ([result objectForKey: @"NSPortName"] == nil)
{
NSLog(@"NSServices entry %u NSPortName missing - %@", pos, path);
return nil;
}
NSLog(@"NSServices entry %u NSPortName missing - %@", pos, path);
return nil;
}
snd = [result objectForKey: @"NSSendTypes"];
ret = [result objectForKey: @"NSReturnTypes"];
if (snd == nil || ret == nil)
if ([snd count] == 0 || [ret count] == 0)
{
NSLog(@"NSServices entry %u types missing - %@", pos, path);
NSLog(@"NSServices entry %u types empty or missing - %@", pos, path);
return nil;
}
else
{
unsigned i = [snd count];
inf = [filterMap objectForKey: obj];
if (inf != nil)
/*
* See if this filter handles any send/return combination
* which is not alreadly present.
*/
while (notPresent == NO && i-- > 0)
{
unsigned j = [ret count];
while (notPresent == NO && j-- > 0)
{
str = [NSString stringWithFormat: @"%@==>%@",
[snd objectAtIndex: i], [ret objectAtIndex: j]];
if ([filterSet member: str] == nil)
{
notPresent = YES;
[filterSet addObject: str];
[filterList addObject: result];
}
}
}
}
if (notPresent == NO)
{
if (verbose)
{
@ -857,7 +880,6 @@ validateService(NSDictionary *service, NSString *path, unsigned pos)
}
return nil;
}
[filterMap setObject: result forKey: obj];
}
else if ((obj = [result objectForKey: @"NSMessage"]) != nil)
{
@ -871,8 +893,8 @@ validateService(NSDictionary *service, NSString *path, unsigned pos)
NSLog(@"NSServices entry %u NSPortName missing - %@", pos, path);
return nil;
}
if ([result objectForKey: @"NSSendTypes"] == nil &&
[result objectForKey: @"NSReturnTypes"] == nil)
if ([result objectForKey: @"NSSendTypes"] == nil
&& [result objectForKey: @"NSReturnTypes"] == nil)
{
NSLog(@"NSServices entry %u types missing - %@", pos, path);
return nil;