mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-22 17:52:42 +00:00
Add methods to manage the user's preferred applications for URL
schemes to NSWorkspace. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@31523 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
eb812a70c0
commit
782128949e
3 changed files with 284 additions and 9 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2010-10-18 Wolfgang Lux <wolfgang.lux@gmail.com>
|
||||
|
||||
* Headers/AppKit/NSWorkspace.h:
|
||||
* Source/NSWorkspace.m (urlPrefsPath, urlPreferences,
|
||||
+initialize, -openURL:, -findApplications, -infoForScheme:,
|
||||
-getBestAppInRole:forScheme:, -setBestApp:inRole:forScheme:,
|
||||
-_scheme:role:app:):
|
||||
Add methods to manage the user's preferred applications for URL
|
||||
schemes to NSWorkspace.
|
||||
|
||||
2010-10-17 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/NSMenuView.m: Revert the WinUX theme specific patch Doug
|
||||
|
|
|
@ -221,6 +221,12 @@ typedef void NSAppleEventDescriptor;
|
|||
inRole: (NSString*)role
|
||||
forExtension: (NSString*)ext;
|
||||
- (void) setBestIcon: (NSString*)iconPath forExtension: (NSString*)ext;
|
||||
- (NSDictionary*) infoForScheme: (NSString*)scheme;
|
||||
- (NSString*) getBestAppInRole: (NSString*)role
|
||||
forScheme: (NSString*)scheme;
|
||||
- (void) setBestApp: (NSString*)appName
|
||||
inRole: (NSString*)role
|
||||
forScheme: (NSString*)scheme;
|
||||
@end
|
||||
#endif
|
||||
|
||||
|
|
|
@ -400,6 +400,9 @@ static id GSLaunched(NSNotification *notification, BOOL active)
|
|||
- (BOOL) _extension: (NSString*)ext
|
||||
role: (NSString*)role
|
||||
app: (NSString**)app;
|
||||
- (BOOL) _scheme: (NSString*)scheme
|
||||
role: (NSString*)role
|
||||
app: (NSString**)app;
|
||||
|
||||
// application communication
|
||||
- (BOOL) _launchApplication: (NSString*)appName
|
||||
|
@ -512,6 +515,9 @@ static NSDictionary *applications = nil;
|
|||
|
||||
static NSString *extPrefPath = nil;
|
||||
static NSDictionary *extPreferences = nil;
|
||||
|
||||
static NSString *urlPrefPath = nil;
|
||||
static NSDictionary *urlPreferences = nil;
|
||||
// FIXME: Won't work for MINGW32
|
||||
static NSString *_rootPath = @"/";
|
||||
|
||||
|
@ -562,6 +568,23 @@ static NSString *_rootPath = @"/";
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Load URL scheme preferences.
|
||||
*/
|
||||
urlPrefPath = [service
|
||||
stringByAppendingPathComponent: @".GNUstepURLPrefs"];
|
||||
RETAIN(urlPrefPath);
|
||||
if ([mgr isReadableFileAtPath: urlPrefPath] == YES)
|
||||
{
|
||||
data = [NSData dataWithContentsOfFile: urlPrefPath];
|
||||
if (data)
|
||||
{
|
||||
dict = [NSDeserializer deserializePropertyListFromData: data
|
||||
mutableContainers: NO];
|
||||
urlPreferences = RETAIN(dict);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Load cached application information.
|
||||
*/
|
||||
|
@ -811,18 +834,10 @@ static NSString *_rootPath = @"/";
|
|||
}
|
||||
else
|
||||
{
|
||||
NSDictionary *map;
|
||||
NSString *appName;
|
||||
NSPasteboard *pb;
|
||||
|
||||
/* Look up an application to handle this URL scheme.
|
||||
* We get a dictionary containing all apps for the scheme.
|
||||
* FIXME ... we just use the last app in the dictionary,
|
||||
* but we really ought to have some way of saying which we want.
|
||||
*/
|
||||
map = [applications objectForKey: @"GSSchemesMap"];
|
||||
map = [map objectForKey: [[url scheme] lowercaseString]];
|
||||
appName = [[map allKeys] lastObject];
|
||||
appName = [self getBestAppInRole: nil forScheme: [url scheme]];
|
||||
if (appName != nil)
|
||||
{
|
||||
id app;
|
||||
|
@ -1341,6 +1356,17 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
|
|||
}
|
||||
}
|
||||
|
||||
if ([mgr isReadableFileAtPath: urlPrefPath] == YES)
|
||||
{
|
||||
data = [NSData dataWithContentsOfFile: urlPrefPath];
|
||||
if (data)
|
||||
{
|
||||
dict = [NSDeserializer deserializePropertyListFromData: data
|
||||
mutableContainers: NO];
|
||||
ASSIGN(urlPreferences, dict);
|
||||
}
|
||||
}
|
||||
|
||||
if ([mgr isReadableFileAtPath: appListPath] == YES)
|
||||
{
|
||||
data = [NSData dataWithContentsOfFile: appListPath];
|
||||
|
@ -2140,6 +2166,94 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
|
|||
[data writeToFile: extPrefPath atomically: YES];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the applications cache (generated by the make_services tool)
|
||||
* and looks up the special entry that contains a dictionary of all
|
||||
* URL schemes recognised by GNUstep applications. Then finds the
|
||||
* dictionary of applications that can handle our scheme and returns
|
||||
* it.
|
||||
*/
|
||||
- (NSDictionary*) infoForScheme: (NSString*)scheme
|
||||
{
|
||||
NSDictionary *map;
|
||||
|
||||
scheme = [scheme lowercaseString];
|
||||
map = [applications objectForKey: @"GSSchemesMap"];
|
||||
return [map objectForKey: scheme];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 'best' application to open a file with the specified URL
|
||||
* scheme using the given role. If the role is nil then apps which can
|
||||
* edit are preferred but viewers are also acceptable. Uses a user preferred
|
||||
* app or picks any good match.
|
||||
*/
|
||||
- (NSString*) getBestAppInRole: (NSString*)role
|
||||
forScheme: (NSString*)scheme
|
||||
{
|
||||
NSString *appName = nil;
|
||||
|
||||
if ([self _scheme: scheme role: role app: &appName] == NO)
|
||||
{
|
||||
appName = nil;
|
||||
}
|
||||
return appName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a user preference for which app should be used to open files
|
||||
* of the specified URL scheme
|
||||
*/
|
||||
- (void) setBestApp: (NSString*)appName
|
||||
inRole: (NSString*)role
|
||||
forScheme: (NSString*)scheme
|
||||
{
|
||||
NSMutableDictionary *map;
|
||||
NSMutableDictionary *inf;
|
||||
NSData *data;
|
||||
|
||||
scheme = [scheme lowercaseString];
|
||||
if (urlPreferences != nil)
|
||||
map = [urlPreferences mutableCopy];
|
||||
else
|
||||
map = [NSMutableDictionary new];
|
||||
|
||||
inf = [[map objectForKey: scheme] mutableCopy];
|
||||
if (inf == nil)
|
||||
{
|
||||
inf = [NSMutableDictionary new];
|
||||
}
|
||||
if (appName == nil)
|
||||
{
|
||||
if (role == nil)
|
||||
{
|
||||
NSString *iconPath = [inf objectForKey: @"Icon"];
|
||||
|
||||
RETAIN(iconPath);
|
||||
[inf removeAllObjects];
|
||||
if (iconPath)
|
||||
{
|
||||
[inf setObject: iconPath forKey: @"Icon"];
|
||||
RELEASE(iconPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[inf removeObjectForKey: role];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[inf setObject: appName forKey: (role ? (id)role : (id)@"Editor")];
|
||||
}
|
||||
[map setObject: inf forKey: scheme];
|
||||
RELEASE(inf);
|
||||
RELEASE(urlPreferences);
|
||||
urlPreferences = map;
|
||||
data = [NSSerializer serializePropertyList: urlPreferences];
|
||||
[data writeToFile: urlPrefPath atomically: YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSWorkspace (Private)
|
||||
|
@ -2507,6 +2621,151 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
|
|||
}
|
||||
}
|
||||
|
||||
- (BOOL) _scheme: (NSString*)scheme
|
||||
role: (NSString*)role
|
||||
app: (NSString**)app
|
||||
{
|
||||
NSEnumerator *enumerator;
|
||||
NSString *appName = nil;
|
||||
NSDictionary *apps = [self infoForScheme: scheme];
|
||||
NSDictionary *prefs;
|
||||
NSDictionary *info;
|
||||
|
||||
scheme = [scheme lowercaseString];
|
||||
|
||||
/*
|
||||
* Look for the name of the preferred app in this role.
|
||||
* A 'nil' roll is a wildcard - find the preferred Editor or Viewer.
|
||||
*/
|
||||
prefs = [urlPreferences objectForKey: scheme];
|
||||
if (role == nil || [role isEqualToString: @"Editor"])
|
||||
{
|
||||
appName = [prefs objectForKey: @"Editor"];
|
||||
if (appName != nil)
|
||||
{
|
||||
info = [apps objectForKey: appName];
|
||||
if (info != nil)
|
||||
{
|
||||
if (app != 0)
|
||||
{
|
||||
*app = appName;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
else if ([self locateApplicationBinary: appName] != nil)
|
||||
{
|
||||
/*
|
||||
* Return the preferred application even though it doesn't
|
||||
* say it opens this type of file ... preferences overrule.
|
||||
*/
|
||||
if (app != 0)
|
||||
{
|
||||
*app = appName;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (role == nil || [role isEqualToString: @"Viewer"])
|
||||
{
|
||||
appName = [prefs objectForKey: @"Viewer"];
|
||||
if (appName != nil)
|
||||
{
|
||||
info = [apps objectForKey: appName];
|
||||
if (info != nil)
|
||||
{
|
||||
if (app != 0)
|
||||
{
|
||||
*app = appName;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
else if ([self locateApplicationBinary: appName] != nil)
|
||||
{
|
||||
/*
|
||||
* Return the preferred application even though it doesn't
|
||||
* say it opens this type of file ... preferences overrule.
|
||||
*/
|
||||
if (app != 0)
|
||||
{
|
||||
*app = appName;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through the dictionary of apps that know about this file type and
|
||||
* determine the best application to open the file by examining the
|
||||
* type information for each app.
|
||||
* The 'NSRole' field specifies what the app can do with the file - if it
|
||||
* is missing, we assume an 'Editor' role.
|
||||
*/
|
||||
if (apps == nil || [apps count] == 0)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
enumerator = [apps keyEnumerator];
|
||||
|
||||
if (role == nil)
|
||||
{
|
||||
BOOL found = NO;
|
||||
|
||||
/*
|
||||
* If the requested role is 'nil', we can accept an app that is either
|
||||
* an Editor (preferred) or a Viewer, or unknown.
|
||||
*/
|
||||
while ((appName = [enumerator nextObject]) != nil)
|
||||
{
|
||||
NSString *str;
|
||||
|
||||
info = [apps objectForKey: appName];
|
||||
str = [info objectForKey: @"NSRole"];
|
||||
/* NB. If str is nil or an empty string, there is no role set,
|
||||
* and we treat this as an Editor since the role is unrestricted.
|
||||
*/
|
||||
if ([str length] == 0 || [str isEqualToString: @"Editor"])
|
||||
{
|
||||
if (app != 0)
|
||||
{
|
||||
*app = appName;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
if ([str isEqualToString: @"Viewer"])
|
||||
{
|
||||
if (app != 0)
|
||||
{
|
||||
*app = appName;
|
||||
}
|
||||
found = YES;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((appName = [enumerator nextObject]) != nil)
|
||||
{
|
||||
NSString *str;
|
||||
|
||||
info = [apps objectForKey: appName];
|
||||
str = [info objectForKey: @"NSRole"];
|
||||
if ((str == nil && [role isEqualToString: @"Editor"])
|
||||
|| [str isEqualToString: role])
|
||||
{
|
||||
if (app != 0)
|
||||
{
|
||||
*app = appName;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch an application locally (ie without reference to the workspace
|
||||
* manager application). We should only call this method when we want
|
||||
|
|
Loading…
Reference in a new issue