mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-06-01 13:11:55 +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
687d59cb1a
commit
29d0dc690f
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>
|
2010-10-17 Fred Kiefer <FredKiefer@gmx.de>
|
||||||
|
|
||||||
* Source/NSMenuView.m: Revert the WinUX theme specific patch Doug
|
* Source/NSMenuView.m: Revert the WinUX theme specific patch Doug
|
||||||
|
|
|
@ -221,6 +221,12 @@ typedef void NSAppleEventDescriptor;
|
||||||
inRole: (NSString*)role
|
inRole: (NSString*)role
|
||||||
forExtension: (NSString*)ext;
|
forExtension: (NSString*)ext;
|
||||||
- (void) setBestIcon: (NSString*)iconPath 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
|
@end
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -400,6 +400,9 @@ static id GSLaunched(NSNotification *notification, BOOL active)
|
||||||
- (BOOL) _extension: (NSString*)ext
|
- (BOOL) _extension: (NSString*)ext
|
||||||
role: (NSString*)role
|
role: (NSString*)role
|
||||||
app: (NSString**)app;
|
app: (NSString**)app;
|
||||||
|
- (BOOL) _scheme: (NSString*)scheme
|
||||||
|
role: (NSString*)role
|
||||||
|
app: (NSString**)app;
|
||||||
|
|
||||||
// application communication
|
// application communication
|
||||||
- (BOOL) _launchApplication: (NSString*)appName
|
- (BOOL) _launchApplication: (NSString*)appName
|
||||||
|
@ -512,6 +515,9 @@ static NSDictionary *applications = nil;
|
||||||
|
|
||||||
static NSString *extPrefPath = nil;
|
static NSString *extPrefPath = nil;
|
||||||
static NSDictionary *extPreferences = nil;
|
static NSDictionary *extPreferences = nil;
|
||||||
|
|
||||||
|
static NSString *urlPrefPath = nil;
|
||||||
|
static NSDictionary *urlPreferences = nil;
|
||||||
// FIXME: Won't work for MINGW32
|
// FIXME: Won't work for MINGW32
|
||||||
static NSString *_rootPath = @"/";
|
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.
|
* Load cached application information.
|
||||||
*/
|
*/
|
||||||
|
@ -811,18 +834,10 @@ static NSString *_rootPath = @"/";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NSDictionary *map;
|
|
||||||
NSString *appName;
|
NSString *appName;
|
||||||
NSPasteboard *pb;
|
NSPasteboard *pb;
|
||||||
|
|
||||||
/* Look up an application to handle this URL scheme.
|
appName = [self getBestAppInRole: nil forScheme: [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];
|
|
||||||
if (appName != nil)
|
if (appName != nil)
|
||||||
{
|
{
|
||||||
id app;
|
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)
|
if ([mgr isReadableFileAtPath: appListPath] == YES)
|
||||||
{
|
{
|
||||||
data = [NSData dataWithContentsOfFile: appListPath];
|
data = [NSData dataWithContentsOfFile: appListPath];
|
||||||
|
@ -2140,6 +2166,94 @@ inFileViewerRootedAtPath: (NSString*)rootFullpath
|
||||||
[data writeToFile: extPrefPath atomically: YES];
|
[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
|
@end
|
||||||
|
|
||||||
@implementation NSWorkspace (Private)
|
@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
|
* Launch an application locally (ie without reference to the workspace
|
||||||
* manager application). We should only call this method when we want
|
* manager application). We should only call this method when we want
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue