From 16c2ec5de001cf6022ee487e3d3cfbb0b47bb711 Mon Sep 17 00:00:00 2001 From: qmathe Date: Mon, 22 Jul 2013 15:24:32 +0000 Subject: [PATCH] Fixed missing theme images if not listed in the theme bundle Info.plist. Theme bundles that contain theme images named using either GNUstep or OPENSTEP names now work properly again (bug introduced in r36836). git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@36916 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 11 ++ Images/nsmapping.strings | 15 ++- Source/NSImage.m | 233 +++++++++++++++++++++++---------------- 3 files changed, 163 insertions(+), 96 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6b984b301..c5cbb65fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2013-07-22 Quentin Mathe + + * Source/NSImage.m (+_pathForImageNamed:, +_pathForSystemImageNamed:type:, + +_pathForThemeImageNamed:type:, +_resourceNameForImageNamed:type:): + Fixed missing theme images if not listed in the theme bundle Info.plist. + Theme bundles that contain theme images named using either GNUstep or + OPENSTEP names now work properly again (bug introduced in r36836). + Finished to clean and reduce duplication in the image searching code + related to -_pathForImageNamed:. + * Images/nsmapping.strings: Updated documentation. + 2013-07-18 German A. Arias * Source/NSPopUpButtonCell.m (-attachPopUpWithFrame:inView:): Revert diff --git a/Images/nsmapping.strings b/Images/nsmapping.strings index e352a2563..2d8b1896b 100644 --- a/Images/nsmapping.strings +++ b/Images/nsmapping.strings @@ -1,6 +1,15 @@ -/* This file contains the mapping of the OPENSTEP names of the images to the - actual files where the GNUstep keeps them. The format is the "strings" - format and content is trivial. */ +/* This file maps the old OPENSTEP and GNUstep names of the images to the + standard theme image names (declared as constants in GSTheme.h) or icon + names (declared as constants in their related header). + + For now, the GNUstep names also represent the actual file names in the + Images directory. As a result, this mapping is also used to access the + image files at loading time. In the long run, the images could just be + renamed to the standard theme image names (without breaking compatibility + with existing applications and themes, since NSImage checks this mapping + in +imageNamed:). + + The format is the "strings" format and content is trivial. */ /* We do not remap the application icon to GNUstep */ /* GNUstep = NSApplicationIcon; */ diff --git a/Source/NSImage.m b/Source/NSImage.m index c2d6692c3..fa9926a45 100644 --- a/Source/NSImage.m +++ b/Source/NSImage.m @@ -1933,21 +1933,75 @@ iterate_reps_for_types(NSArray* imageReps, SEL method) NSEnumerator *e = [[self imageFileTypes] objectEnumerator]; id o = nil; - NSString *path = nil; while ((o = [e nextObject]) != nil) { - path = [NSBundle pathForLibraryResource: aName - ofType: o - inDirectory: aDir]; + NSString *path = [NSBundle pathForLibraryResource: aName + ofType: o + inDirectory: aDir]; if (path != nil && [path length] != 0) - break; + return path; + } + + return nil; +} + ++ (NSString *) _pathForSystemImageNamed: (NSString *)realName + ofType: (NSString *)ext +{ + NSString *path = [self _pathForLibraryImageNamed: realName + ofType: ext + inDirectory: @"Images"]; + + /* If not found then search in system using the reverse NSImage nsmapping */ + if (path == nil) + { + NSEnumerator *e = + [[nsmapping allKeysForObject: realName] objectEnumerator]; + NSString *aliasName = nil; + + while ((aliasName = [e nextObject]) != nil) + { + path = [self _pathForLibraryImageNamed: aliasName + ofType: ext + inDirectory: @"Images"]; + + if (path != nil) + break; + } } return path; } ++ (NSString *) _resourceNameForImageNamed: (NSString *)aName + type: (NSString **)aType +{ + NSString *name = aName; + NSString *ext = [aName pathExtension]; + + if (ext != nil && [ext length] == 0) + { + ext = nil; + } + + /* Check if extension is one of the image types */ + if (ext != nil && [[self imageFileTypes] indexOfObject: ext] != NSNotFound) + { + /* Extension is one of the image types, so remove from the name */ + name = [aName stringByDeletingPathExtension]; + } + else + { + /* Otherwise extension is not an image type, so leave it alone */ + ext = nil; + } + + *aType = ext; + return name; +} + + (NSString *) _pathForImageNamed: (NSString *)aName ofType: (NSString *)ext subdirectory: (NSString *)aDir @@ -1962,19 +2016,83 @@ iterate_reps_for_types(NSArray* imageReps, SEL method) NSEnumerator *e = [[self imageFileTypes] objectEnumerator]; id o = nil; - NSString *path = nil; while ((o = [e nextObject]) != nil) { - path = [aBundle pathForResource: aName - ofType: o - inDirectory: aDir]; + NSString * path = [aBundle pathForResource: aName + ofType: o + inDirectory: aDir]; if (path != nil && [path length] != 0) - break; + return path; } - return path; + return nil; +} + +/* + * The type received in argument is meaningfull for searching image files + * using the proposed image name, but useless otherwise. + */ ++ (NSString *) _pathForThemeImageNamed: (NSString *)aName + ofType: (NSString *)ext +{ + NSDictionary *themeMapping = + [[[GSTheme theme] infoDictionary] objectForKey: @"GSThemeImages"]; + NSString *mappedName = [themeMapping objectForKey: aName]; + NSString *path = nil; + + /* First search among the theme images using the GSTheme mapping */ + if (mappedName != nil) + { + NSString *extension = nil; + NSString *proposedName = [self _resourceNameForImageNamed: mappedName + type: &extension]; + + /* If the image file name from the theme mapping uses an extension, this + extension is used to look up the path. If the image file cannot found, + _pathForImageNamed:ofType:subdirectory:inBundle: searches an image + file for the file extensions from -imageFileTypes. */ + path = [self _pathForImageNamed: proposedName + ofType: extension + subdirectory: @"ThemeImages" + inBundle: [[GSTheme theme] bundle]]; + } + + /* If not found, search among the theme images using the reverse NSImage + mapping (for GNUstep and OpenStep image names such as common_SwitchOff + or NSSwitch) */ + if (path == nil) + { + NSEnumerator *e = + [[nsmapping allKeysForObject: aName] objectEnumerator]; + NSString *aliasName = nil; + + while ((aliasName = [e nextObject]) != nil) + { + NSAssert([[aliasName pathExtension] length] == 0, @"nsmapping.strings " + "must include no extensions in image file names"); + + path = [self _pathForImageNamed: aliasName + ofType: nil + subdirectory: @"ThemeImages" + inBundle: [[GSTheme theme] bundle]]; + + if (path != nil) + break; + } + } + + /* If not found, search among the theme images using the image name directly */ + if (path == nil) + { + path = [self _pathForImageNamed: aName + ofType: ext + subdirectory: @"ThemeImages" + inBundle: [[GSTheme theme] bundle]]; + } + + return path; } /* @@ -1998,100 +2116,29 @@ iterate_reps_for_types(NSArray* imageReps, SEL method) */ + (NSString *) _pathForImageNamed: (NSString *)aName { - NSString *realName = aName; - NSString *ext; + NSString *ext = nil; + NSString *proposedName = [self _resourceNameForImageNamed: aName type: &ext]; NSString *path = nil; - NSBundle *main_bundle; - NSArray *array; - if (nil == realName) - { - realName = aName; - } - - // FIXME: This should use [NSBundle pathForImageResource], but this will - // only allow imageUnfilteredFileTypes. - /* If there is no image with that name, search in the main bundle */ - main_bundle = [NSBundle mainBundle]; - ext = [realName pathExtension]; - if (ext != nil && [ext length] == 0) - { - ext = nil; - } - - /* Check if extension is one of the image types */ - array = [self imageFileTypes]; - if (ext != nil && [array indexOfObject: ext] != NSNotFound) - { - /* Extension is one of the image types - So remove from the name */ - realName = [realName stringByDeletingPathExtension]; - } - else - { - /* Otherwise extension is not an image type - So leave it alone */ - ext = nil; - } + // FIXME: This should use [NSBundle pathForImageResource] if possible, but + // this will only allow imageUnfilteredFileTypes. /* First search locally */ - if (ext) - path = [main_bundle pathForResource: realName ofType: ext]; - else - { - id o, e; - - e = [array objectEnumerator]; - while ((o = [e nextObject])) - { - path = [main_bundle pathForResource: realName - ofType: o]; - if (path != nil && [path length] != 0) - break; - } - } + path = [self _pathForImageNamed: proposedName + ofType: ext + subdirectory: nil + inBundle: [NSBundle mainBundle]]; - /* If not found then search in the theme */ + /* If not found then search in theme */ if (path == nil) { - NSDictionary *themeMapping = - [[[GSTheme theme] infoDictionary] objectForKey: @"GSThemeImages"]; - NSString *mappedName = [themeMapping objectForKey: realName]; - - if (mappedName != nil) - { - // TODO: Could search the images if no file extension is provided - if ([[mappedName pathExtension] isEqual: @""]) - { - NSLog(@"Theme image name %@ requires a file extension in the " - "theme Info.plist to get loaded.", mappedName); - } - - path = [[[GSTheme theme] bundle] pathForResource: mappedName - ofType: nil - inDirectory: @"ThemeImages"]; - } + path = [self _pathForThemeImageNamed: proposedName ofType: ext]; } /* If not found then search in system */ if (path == nil) { - path = [self _pathForLibraryImageNamed: realName ofType: ext inDirectory: @"Images"]; - } - - /* If not found then search in system using reverse nsmapping */ - if (path == nil) - { - NSEnumerator *e = [[nsmapping allKeysForObject: realName] objectEnumerator]; - NSString *aliasName = nil; - - while ((aliasName = [e nextObject]) != nil) - { - path = [self _pathForLibraryImageNamed: aliasName ofType: ext inDirectory: @"Images"]; - - if (path != nil) - break; - } + path = [self _pathForSystemImageNamed: proposedName ofType: ext]; } return path;