diff --git a/AppKit/Cib/_CPCibCustomResource.j b/AppKit/Cib/_CPCibCustomResource.j index aefe07e67..d929cd0c7 100644 --- a/AppKit/Cib/_CPCibCustomResource.j +++ b/AppKit/Cib/_CPCibCustomResource.j @@ -31,7 +31,7 @@ @import "CPTheme.j" @class CPButtonBar - +@class CPView var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey", _CPCibCustomResourceResourceNameKey = @"_CPCibCustomResourceResourceNameKey", @@ -42,6 +42,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey", CPString _className; CPString _resourceName; CPDictionary _properties; + CPBundle _bundle; } + (id)imageResourceWithName:(CPString)aResourceName size:(CGSize)aSize @@ -63,6 +64,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey", _className = aClassName; _resourceName = aResourceName; _properties = properties; + _bundle = nil; } return self; @@ -77,6 +79,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey", _className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey]; _resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey]; _properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey]; + _bundle = nil; } return self; @@ -100,39 +103,72 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey", else if (_resourceName == "CPRemoveTemplate") return [[CPTheme defaultTheme] valueForAttributeWithName:@"button-image-minus" forClass:[CPButtonBar class]]; - return [self imageFromBundle:[aCoder bundle]]; + return [self imageFromCoder:aCoder]; } return self; } -- (CPImage)imageFromBundle:(CPBundle)aBundle -{ - if (!aBundle) - { - var bundleClass = _properties.valueForKey(@"bundleClass"); - - if (bundleClass) - { - bundleClass = CPClassFromString(bundleClass); - - if (bundleClass) - aBundle = [CPBundle bundleForClass:bundleClass]; - } - else - aBundle = [CPBundle mainBundle]; - } - - return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:_resourceName] size:_properties.valueForKey(@"size")]; -} - @end @implementation _CPCibCustomResource (CPImage) +- (CPBundle)imageBundleWithCoder:(CPCoder)aCoder +{ + if (_bundle) + return _bundle; + + var bundleIdentifier = [_properties valueForKey:@"bundleIdentifier"]; + + if (bundleIdentifier) + _bundle = [CPBundle bundleWithIdentifier:bundleIdentifier]; + else + { + var bundleClass = [_properties valueForKey:@"bundleClass"]; + + if (bundleClass) + { + bundleClass = CPClassFromString(bundleClass); + + if (bundleClass) + _bundle = [CPBundle bundleForClass:bundleClass]; + } + } + + if (!_bundle) + { + var framework = [_properties valueForKey:@"framework"]; + + if (framework) + { + // Get AppKit and hope the framework is in the same directory + var appKit = [CPBundle bundleForClass:[CPView class]], + url = [[appKit bundleURL] URLByDeletingLastPathComponent]; + + url = [CPURL URLWithString:framework relativeToURL:url]; + _bundle = [CPBundle bundleWithURL:url]; + } + } + + if (!_bundle) + { + if (aCoder) + _bundle = [aCoder bundle]; + else + _bundle = [CPBundle mainBundle]; + } + + return _bundle; +} + +- (CPImage)imageFromCoder:(CPCoder)aCoder +{ + return [[CPImage alloc] initWithContentsOfFile:[[self imageBundleWithCoder:aCoder] pathForResource:_resourceName] size:[_properties valueForKey:@"size"]]; +} + - (CPString)filename { - return [[CPBundle mainBundle] pathForResource:_resourceName]; + return [[self imageBundleWithCoder:nil] pathForResource:_resourceName]; } - (CGSize)size @@ -162,7 +198,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey", - (CPString)description { - var image = [self imageFromBundle:nil]; + var image = [self imageFromCoder:nil]; return [image description]; } diff --git a/Tools/capp/Resources/Templates/NibApplication/Jakefile b/Tools/capp/Resources/Templates/NibApplication/Jakefile index 9e688f19f..81068711d 100644 --- a/Tools/capp/Resources/Templates/NibApplication/Jakefile +++ b/Tools/capp/Resources/Templates/NibApplication/Jakefile @@ -30,7 +30,6 @@ app ("__project.nameasidentifier__", function(task) task.setResources(new FileList("Resources/**")); task.setIndexFilePath("index.html"); task.setInfoPlistPath("Info.plist"); - task.setNib2CibFlags("-R Resources/"); if (configuration === "Debug") task.setCompilerFlags("-DDEBUG -g"); diff --git a/Tools/nib2cib/Converter+Mac.j b/Tools/nib2cib/Converter+Mac.j index 606717d5e..e6145cfdf 100644 --- a/Tools/nib2cib/Converter+Mac.j +++ b/Tools/nib2cib/Converter+Mac.j @@ -24,12 +24,14 @@ @import "Nib2CibKeyedUnarchiver.j" @import "NSFont.j" +@class Nib2Cib + @implementation Converter (Mac) -- (void)convertedDataFromMacData:(CPData)data resourcesPath:(CPString)aResourcesPath +- (void)convertedDataFromMacData:(CPData)data { // Unarchive the NS data - var unarchiver = [[Nib2CibKeyedUnarchiver alloc] initForReadingWithData:data resourcesPath:aResourcesPath], + var unarchiver = [[Nib2CibKeyedUnarchiver alloc] initForReadingWithData:data], objectData = [unarchiver decodeObjectForKey:@"IB.objectdata"], objects = [unarchiver allObjects], count = [objects count]; @@ -106,7 +108,8 @@ // nil cibFont means try to use theme font if (!cibFont) { - var bold = [nibFont isBold]; + var bold = [nibFont isBold], + themes = [[Nib2Cib sharedNib2Cib] themes]; for (var i = 0; i < themes.length; ++i) { diff --git a/Tools/nib2cib/Converter.j b/Tools/nib2cib/Converter.j index a8c6d65ff..ed9857fa1 100644 --- a/Tools/nib2cib/Converter.j +++ b/Tools/nib2cib/Converter.j @@ -30,6 +30,8 @@ @import "NSFoundation.j" @import "NSAppKit.j" +@class Nib2Cib + @global java var FILE = require("file"), @@ -48,13 +50,8 @@ ConverterConversionException = @"ConverterConversionException"; @implementation Converter : CPObject { - CPString inputPath @accessors(readonly); - CPString outputPath @accessors; - CPString resourcesPath @accessors; - NibFormat format @accessors(readonly); - CPArray themes @accessors(readonly); - CPArray userNSClasses @accessors; - BOOL compileNib @accessors; + CPString inputPath @accessors(readonly); + CPString outputPath @accessors; } + (Converter)sharedConverter @@ -62,7 +59,7 @@ ConverterConversionException = @"ConverterConversionException"; return SharedConverter; } -- (id)initWithInputPath:(CPString)aPath format:(NibFormat)nibFormat themes:(CPArray)themeList +- (id)initWithInputPath:(CPString)anInputPath outputPath:(CPString)anOutputPath { self = [super init]; @@ -71,52 +68,43 @@ ConverterConversionException = @"ConverterConversionException"; if (!SharedConverter) SharedConverter = self; - inputPath = aPath; - format = nibFormat; - themes = themeList; - compileNib = YES; + inputPath = anInputPath; + outputPath = anOutputPath; } return self; } -- (void)convert +- (CPData)convert { - if ([resourcesPath length] && !FILE.isReadable(resourcesPath)) - [CPException raise:ConverterConversionException reason:@"Could not read Resources at path \"" + resourcesPath + "\""]; + // Assume its a Mac file. + var inferredFormat = NibFormatMac; - var inferredFormat = format; + // Some .xibs are iPhone nibs, check the actual contents in this case. + if (FILE.extension(inputPath) !== ".nib" && FILE.isFile(inputPath) && + FILE.read(inputPath, { charset:"UTF-8" }).indexOf(" @import -@class Converter +@class Nib2Cib @global CP_NSMapClassName @@ -48,7 +48,7 @@ var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey", // If this is a userland NS class, call its KVC methods directly var nsClass = nil; - if ([[[Converter sharedConverter] userNSClasses] containsObject:aClassName]) + if ([[[Nib2Cib sharedNib2Cib] userNSClasses] containsObject:aClassName]) nsClass = objj_lookUpClass("NS_" + aClassName); var originalClass = nsClass || objj_lookUpClass(anOriginalClassName); diff --git a/Tools/nib2cib/NSComboBox.j b/Tools/nib2cib/NSComboBox.j index 27b9d0715..f2c227adf 100644 --- a/Tools/nib2cib/NSComboBox.j +++ b/Tools/nib2cib/NSComboBox.j @@ -25,7 +25,7 @@ @import "NSTextField.j" -@class Converter +@class Nib2Cib @implementation CPComboBox (NSCoding) @@ -48,12 +48,13 @@ [self setEnabled:[cell isEnabled]]; // Make sure the height is clipped to the max given by the theme - var maxSize = [[[Converter sharedConverter] themes][0] valueForAttributeWithName:@"max-size" forClass:[CPComboBox class]], + var theme = [Nib2Cib defaultTheme], + maxSize = [theme valueForAttributeWithName:@"max-size" forClass:[CPComboBox class]], size = [self frameSize], widthOffset = -3; // Adjust for differences between Cocoa and Cappuccino widget framing. - if ([[[Converter sharedConverter] themes][0] name] == @"Aristo") + if ([theme name] == @"Aristo") { _frame.origin.x += 1; widthOffset = -5; diff --git a/Tools/nib2cib/NSCustomResource.j b/Tools/nib2cib/NSCustomResource.j index 0864f222a..ad0886c38 100644 --- a/Tools/nib2cib/NSCustomResource.j +++ b/Tools/nib2cib/NSCustomResource.j @@ -41,7 +41,8 @@ var FILE = require("file"), _className = CP_NSMapClassName([aCoder decodeObjectForKey:@"NSClassName"]); _resourceName = [aCoder decodeObjectForKey:@"NSResourceName"]; - var size = CGSizeMakeZero(); + var size = CGSizeMakeZero(), + framework = @""; if (_resourceName == "NSSwitch") return nil; @@ -52,21 +53,47 @@ var FILE = require("file"), } else { - var resourcePath = [aCoder resourcePathForName:_resourceName]; + var match = /^(.+)@(.+)$/.exec(_resourceName), + framework = @"", + bundleIdentifier = @""; - if (!resourcePath) - CPLog.warn("Resource \"" + _resourceName + "\" not found in the resources path: " + [aCoder resourcesPath]); + if (match) + { + framework = match[1]; + _resourceName = match[2]; + } + + var resourceInfo = [aCoder resourceInfoForName:_resourceName inFramework:framework]; + + if (!resourceInfo) + CPLog.warn("Resource \"" + _resourceName + "\" not found in the Resources directories"); else - size = imageSize(FILE.canonical(resourcePath)) || CGSizeMakeZero(); + { + size = imageSize(FILE.canonical(resourceInfo.path)) || CGSizeMakeZero(); + framework = resourceInfo.framework; + } // Account for the fact that an extension may have been inferred. - if (resourcePath && FILE.extension(resourcePath) !== FILE.extension(_resourceName)) - _resourceName += FILE.extension(resourcePath); + if (resourceInfo && + resourceInfo.path && + FILE.extension(resourceInfo.path) !== FILE.extension(_resourceName)) + { + _resourceName += FILE.extension(resourceInfo.path); + } - CPLog.debug(" Rsrc: %s\n Path: %s\n Size: %d x %d", _resourceName, FILE.canonical(resourcePath), size.width, size.height); + CPLog.debug(" Resource: %s\n Framework: %s\n Path: %s\n Size: %d x %d", _resourceName, framework, resourceInfo ? FILE.canonical(resourceInfo.path) : "", size.width, size.height); } - _properties = [CPDictionary dictionaryWithObject:size forKey:@"size"]; + if (resourceInfo && resourceInfo.path && resourceInfo.framework) + { + var frameworkPath = FILE.dirname(FILE.dirname(resourceInfo.path)), + bundle = [CPBundle bundleWithPath:frameworkPath]; + + [bundle loadWithDelegate:nil]; + bundleIdentifier = [bundle bundleIdentifier] || @""; + } + + _properties = @{ @"size":size, @"bundleIdentifier":bundleIdentifier, @"framework":framework }; } return self; diff --git a/Tools/nib2cib/NSDatePicker.j b/Tools/nib2cib/NSDatePicker.j index 0d2335299..f0ebb2579 100644 --- a/Tools/nib2cib/NSDatePicker.j +++ b/Tools/nib2cib/NSDatePicker.j @@ -24,7 +24,7 @@ @import "NSCell.j" -@class Converter +@class Nib2Cib @global CPTextFieldDatePickerStyle @global CPTextFieldAndStepperDatePickerStyle @@ -57,7 +57,7 @@ var NSDatePickerDefaultSize = 22, [self setBezeled:[cell isBezeled]]; [self setBordered:[cell isBordered]]; - var theme = [[Converter sharedConverter] themes][0]; + var theme = [Nib2Cib defaultTheme]; if (_datePickerStyle != CPClockAndCalendarDatePickerStyle) { @@ -225,4 +225,4 @@ var NSDatePickerDefaultSize = 22, return [CPDate class]; } -@end \ No newline at end of file +@end diff --git a/Tools/nib2cib/NSNib.j b/Tools/nib2cib/NSNib.j index aaf13a2c0..f25f49e63 100644 --- a/Tools/nib2cib/NSNib.j +++ b/Tools/nib2cib/NSNib.j @@ -34,23 +34,15 @@ var FILE = require("file"), { self = [super init]; + // FIXME: change /tmp/ to os.tmpDir() in Node var nibPath = @"/tmp/" + UUID.uuid() + ".nib", - data = [aCoder decodeObjectForKey:@"NSNibFileData"], - sharedConverter = [Converter sharedConverter]; + data = [aCoder decodeObjectForKey:@"NSNibFileData"]; FILE.write(nibPath, data.bytes(), { charset:"UTF-16" }); - var converter = [[Converter alloc] initWithInputPath:@"" - format:[sharedConverter format] - themes:[sharedConverter themes]]; - [converter setCompileNib:NO]; - [converter setResourcesPath:[sharedConverter resourcesPath]]; - [converter setUserNSClasses:[sharedConverter userNSClasses]]; + var converter = [[Converter alloc] initWithInputPath:nibPath outputPath:nil]; - CPLog.info("Converting sub nib to plist..."); - - var nibData = [converter CPCompliantNibDataAtFilePath:nibPath]; - _data = [converter convertedDataFromMacData:nibData resourcesPath:[sharedConverter resourcesPath]]; + _data = [converter convert]; return self; } diff --git a/Tools/nib2cib/NSProgressIndicator.j b/Tools/nib2cib/NSProgressIndicator.j index 94795d77f..fa4ceff82 100644 --- a/Tools/nib2cib/NSProgressIndicator.j +++ b/Tools/nib2cib/NSProgressIndicator.j @@ -22,7 +22,7 @@ @import -@class Converter +@class Nib2Cib var NSProgressIndicatorSpinningFlag = 1 << 12; @@ -59,7 +59,7 @@ var NSProgressIndicatorSpinningFlag = 1 << 12; if (_style !== CPProgressIndicatorSpinningStyle) { - var theme = [[Converter sharedConverter] themes][0], + var theme = [Nib2Cib defaultTheme], height = [theme valueForAttributeWithName:@"default-height" forClass:CPProgressIndicator]; currentFrameSize.height = height; diff --git a/Tools/nib2cib/NSSearchField.j b/Tools/nib2cib/NSSearchField.j index 30bf0d384..367b5a7ed 100644 --- a/Tools/nib2cib/NSSearchField.j +++ b/Tools/nib2cib/NSSearchField.j @@ -24,7 +24,7 @@ @import "NSTextField.j" -@class Converter +@class Nib2Cib @implementation CPSearchField (NSCoding) @@ -43,7 +43,7 @@ [self setSendsWholeSearchString:[cell sendsWholeSearchString]]; [self setSendsSearchStringImmediately:[cell sendsSearchStringImmediately]]; - if ([[[Converter sharedConverter] themes][0] name] == @"Aristo" && [self isBezeled]) + if ([[Nib2Cib defaultTheme] name] === @"Aristo" && [self isBezeled]) { // NSTextField.j makes the field +7.0 pixels tall. We want +8.0 to go to 30. var frame = [self frame]; diff --git a/Tools/nib2cib/NSSegmentedControl.j b/Tools/nib2cib/NSSegmentedControl.j index 8525a2611..27abc164b 100644 --- a/Tools/nib2cib/NSSegmentedControl.j +++ b/Tools/nib2cib/NSSegmentedControl.j @@ -24,7 +24,7 @@ @import "NSCell.j" -@class Converter +@class Nib2Cib @implementation CPSegmentedControl (CPCoding) @@ -68,7 +68,7 @@ // Adjust for differences between Cocoa and Cappuccino widget framing. frame.origin.x += 6; - if ([[[Converter sharedConverter] themes][0] name] == @"Aristo2") + if ([[Nib2Cib defaultTheme] name] == @"Aristo2") frame.size.height += 1; frame.size.width = originalWidth; diff --git a/Tools/nib2cib/NSTableColumn.j b/Tools/nib2cib/NSTableColumn.j index 8a16d7a4d..cd53c1827 100644 --- a/Tools/nib2cib/NSTableColumn.j +++ b/Tools/nib2cib/NSTableColumn.j @@ -31,6 +31,7 @@ @import "NSTextField.j" @class Converter +@class Nib2Cib var IBDefaultFontSizeTableHeader = 11.0; @@ -63,7 +64,7 @@ var IBDefaultFontSizeTableHeader = 11.0; var headerCell = [aCoder decodeObjectForKey:@"NSHeaderCell"], headerView = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()], - theme = [[Converter sharedConverter] themes][0]; + theme = [Nib2Cib defaultTheme]; [headerView setStringValue:[headerCell objectValue]]; [headerView setFont:[headerCell font]]; @@ -124,7 +125,7 @@ var IBDefaultFontSizeTableHeader = 11.0; - (id)valueForDataViewThemeAttribute:(CPString)attribute inState:(int)state { - var themes = [[Converter sharedConverter] themes]; + var themes = [[Nib2Cib sharedNib2Cib] themes]; for (var i = 0; i < themes.length; ++i) { diff --git a/Tools/nib2cib/NSTableHeaderView.j b/Tools/nib2cib/NSTableHeaderView.j index 2ed89607a..48b0eab71 100644 --- a/Tools/nib2cib/NSTableHeaderView.j +++ b/Tools/nib2cib/NSTableHeaderView.j @@ -22,8 +22,8 @@ @import -@class Converter @class CPTableView +@class Nib2Cib @implementation CPTableHeaderView (NSCoding) @@ -37,7 +37,7 @@ // change the default height if (_bounds.size.height === 17) { - var theme = [[Converter sharedConverter] themes][0], + var theme = [Nib2Cib defaultTheme], height = [theme valueForAttributeWithName:@"default-row-height" forClass:CPTableView]; _bounds.size.height = height; diff --git a/Tools/nib2cib/NSTableView.j b/Tools/nib2cib/NSTableView.j index 46eefdd7c..3b4da3f54 100644 --- a/Tools/nib2cib/NSTableView.j +++ b/Tools/nib2cib/NSTableView.j @@ -22,7 +22,7 @@ @import -@class Converter +@class Nib2Cib @implementation CPTableView (NSCoding) @@ -43,7 +43,7 @@ // Convert xib default to cib default if (_rowHeight == 17) { - var theme = [[Converter sharedConverter] themes][0], + var theme = [Nib2Cib defaultTheme], height = [theme valueForAttributeWithName:@"default-row-height" forClass:CPTableView]; _rowHeight = height; diff --git a/Tools/nib2cib/Nib2Cib.j b/Tools/nib2cib/Nib2Cib.j index fa0887f01..e3080b9f1 100644 --- a/Tools/nib2cib/Nib2Cib.j +++ b/Tools/nib2cib/Nib2Cib.j @@ -42,7 +42,9 @@ var FILE = require("file"), BuildTypes = ["Debug", "Release"], DefaultFile = "MainMenu", AllowedStoredOptionsRe = new RegExp("^(defaultTheme|auxThemes|verbosity|quiet|frameworks|format)$"), - ArgsRe = /"[^\"]+"|'[^\']+'|\S+/g; + ArgsRe = /"[^\"]+"|'[^\']+'|\S+/g, + + SharedNib2Cib = nil; @implementation Nib2Cib : CPObject @@ -50,10 +52,22 @@ var FILE = require("file"), CPArray commandLineArgs; JSObject parser; JSObject nibInfo; - CPString appDirectory; - CPString resourcesDirectory; - CPDictionary infoPlist; - CPArray userNSClasses; + CPString appDirectory @accessors(readonly); + CPDictionary frameworks @accessors(readonly); + CPString appResourceDirectory @accessors(readonly); + CPDictionary infoPlist @accessors(readonly); + CPArray userNSClasses @accessors(readonly); + CPArray themes @accessors(readonly); +} + ++ (Nib2Cib)sharedNib2Cib +{ + return SharedNib2Cib; +} + ++ (CPTheme)defaultTheme +{ + return [SharedNib2Cib themes][0]; } - (id)initWithArgs:(CPArray)theArgs @@ -62,13 +76,18 @@ var FILE = require("file"), if (self) { + if (!SharedNib2Cib) + SharedNib2Cib = self; + commandLineArgs = theArgs; parser = new (require("narwhal/args").Parser)(); nibInfo = {}; appDirectory = @""; - resourcesDirectory = @""; + frameworks = [CPDictionary dictionary]; + appResourceDirectory = @""; infoPlist = @{}; userNSClasses = []; + themes = []; } return self; @@ -86,7 +105,7 @@ var FILE = require("file"), if (options.watch) [self watchWithOptions:options]; else - [self convertWithOptions:options inputFile:nil]; + [self convertWithOptions:options inputPath:nil]; } catch (anException) { @@ -104,25 +123,55 @@ var FILE = require("file"), [self failWithMessage:@"fontinfo does not appear to be installed"]; } -- (BOOL)convertWithOptions:(JSObject)options inputFile:(CPString)inputFile +- (void)enumerateFrameworks +{ + var frameworksDirectory = FILE.join(appDirectory, "Frameworks"), + debugFrameworksDirectory = FILE.join(frameworksDirectory, "Debug"); + + [debugFrameworksDirectory, frameworksDirectory].forEach(function(directory) + { + if (FILE.isDirectory(directory)) + { + var frameworkList = FILE.list(directory); + + frameworkList.forEach(function(framework) + { + if (framework !== @"Debug" && ![frameworks containsKey:framework]) + { + var resourceDirectory = FILE.join(directory, framework, "Resources"); + + if (FILE.isDirectory(resourceDirectory)) + resourceDirectory = FILE.canonical(resourceDirectory); + else + resourceDirectory = @""; + + [frameworks setValue:{resourceDirectory:resourceDirectory, loaded:false} forKey:framework]; + } + }); + } + }); +} + +- (BOOL)convertWithOptions:(JSObject)options inputPath:(CPString)inputPath { try { - inputFile = inputFile || [self getInputFile:options.args]; + inputPath = inputPath || [self getInputPath:options.args]; - [self getAppAndResourceDirectoriesFromInputFile:inputFile options:options]; + [self getAppAndResourceDirectoriesFromInputPath:inputPath options:options]; + [self enumerateFrameworks]; if (options.readStoredOptions) { - options = [self mergeOptionsWithStoredOptions:options inputFile:inputFile]; + options = [self mergeOptionsWithStoredOptions:options inputPath:inputPath]; [self setLogLevel:options.quiet ? -1 : options.verbosity]; } if (!options.quiet && options.verbosity > 0) [self printVersion]; - var outputFile = [self getOutputFileFromInputFile:inputFile args:options.args], - configInfo = [self readConfigFile:options.configFile || @"" inputFile:inputFile]; + var configInfo = [self readConfigFile:options.configFile || @"" inputPath:inputPath], + outputPath = [self getOutputPathFromInputPath:inputPath args:options.args]; infoPlist = configInfo.plist; @@ -141,37 +190,40 @@ var FILE = require("file"), else infoPlist = @{}; - var themeList = [self getThemeList:options], - themes = [self loadThemesFromList:themeList]; + var themeList = [self getThemeList:options]; + + [self loadThemesFromList:themeList]; + [self loadFrameworks:options.frameworks verbosity:options.verbosity]; + [self loadNSClassesFromBundle:[CPBundle mainBundle]]; + + var frameworkList = []; + + [frameworks allKeys].forEach(function(name) + { + var info = [frameworks valueForKey:name]; + + if (info.resourceDirectory) + name += "*"; + + if (info.loaded) + name += "+"; + + frameworkList.push(name); + }); CPLog.info("\n-------------------------------------------------------------"); - CPLog.info("Input : " + inputFile); - CPLog.info("Output : " + outputFile); - CPLog.info("Format : " + ["Auto", "Mac", "iPhone"][options.format]); + CPLog.info("Input : " + inputPath); + CPLog.info("Output : " + outputPath); CPLog.info("Application : " + appDirectory); - CPLog.info("Resources : " + resourcesDirectory); - CPLog.info("Frameworks : " + (options.frameworks || "")); + CPLog.info("Frameworks : " + (frameworkList.join(", ") || "")); CPLog.info("Default theme : " + themeList[0]); CPLog.info("Aux themes : " + themeList.slice(1).join(", ")); CPLog.info("Config file : " + (configInfo.path || "")); CPLog.info("System Font : " + [CPFont systemFontSize] + "px " + [CPFont systemFontFace]); CPLog.info("-------------------------------------------------------------\n"); - var converter = [[Converter alloc] initWithInputPath:inputFile - format:options.format - themes:themes]; - - [converter setOutputPath:outputFile]; - [converter setResourcesPath:resourcesDirectory]; - - var loadFrameworksCallback = function() - { - [self loadNSClassesFromBundle:[CPBundle mainBundle]]; - [converter setUserNSClasses:userNSClasses]; - [converter convert]; - }; - - [self loadFrameworks:options.frameworks verbosity:options.verbosity callback:loadFrameworksCallback]; + var converter = [[Converter alloc] initWithInputPath:inputPath outputPath:outputPath]; + [converter convert]; return YES; } @@ -250,7 +302,7 @@ var FILE = require("file"), // Let the converter log however the user configured it [self setLogLevel:verbosity]; - var success = [self convertWithOptions:options inputFile:nib]; + var success = [self convertWithOptions:options inputPath:nib]; [self setLogLevel:1]; @@ -275,11 +327,6 @@ var FILE = require("file"), .set(true) .help("Ask nib2cib to watch a directory for changes"); - parser.option("-R", "resourcesDir") - .set() - .displayName("directory") - .help("Set the Resources directory, usually unnecessary as it is inferred from the input path"); - parser.option("--default-theme", "defaultTheme") .set() .displayName("name") @@ -312,15 +359,15 @@ var FILE = require("file"), .def(true) .help("Do not read stored options"); - parser.option("--mac", "format") - .set(NibFormatMac) - .def(NibFormatUndetermined) - .help("Set format to Mac"); - parser.option("--version", "showVersion") .action(function() { [self printVersionAndExit]; }) .help("Show the version of nib2cib and quit"); + parser.option("-R", "deprecatedResourcesDir") + .set() + .displayName("resources directory") + .help("This option is deprecated."); + parser.helpful(); var options = parser.parse(theArgs, null, null, true); @@ -334,13 +381,13 @@ var FILE = require("file"), return options; } -- (JSObject)mergeOptionsWithStoredOptions:(JSObject)options inputFile:(CPString)inputFile +- (JSObject)mergeOptionsWithStoredOptions:(JSObject)options inputPath:(CPString)inputPath { // We have to clone options var userOptions = [self readStoredOptionsAtPath:FILE.join(SYS.env["HOME"], ".nib2cibconfig")], appOptions = [self readStoredOptionsAtPath:FILE.join(appDirectory, "nib2cib.conf")], - filename = FILE.basename(inputFile, FILE.extension(inputFile)) + ".conf", - fileOptions = [self readStoredOptionsAtPath:FILE.join(FILE.dirname(inputFile), filename)]; + filename = FILE.basename(inputPath, FILE.extension(inputPath)) + ".conf", + fileOptions = [self readStoredOptionsAtPath:FILE.join(FILE.dirname(inputPath), filename)]; // At this point we have an array of args without the initial command in args[0], // add the command and parse the options. @@ -445,31 +492,31 @@ var FILE = require("file"), CPLogRegister(CPLogPrint, null, logFormatter); } -- (CPString)getInputFile:(CPArray)theArgs +- (CPString)getInputPath:(CPArray)theArgs { - var inputFile = theArgs[0] || DefaultFile, + var inputPath = theArgs[0] || DefaultFile, path = ""; - if (!/^.+\.[nx]ib$/.test(inputFile)) + if (!/^.+\.[nx]ib$/.test(inputPath)) { - if (path = [self findInputFile:inputFile extension:@".xib"]) - inputFile = path; - else if (path = [self findInputFile:inputFile extension:@".nib"]) - inputFile = path; + if (path = [self findInputPath:inputPath extension:@".xib"]) + inputPath = path; + else if (path = [self findInputPath:inputPath extension:@".nib"]) + inputPath = path; else - [self failWithMessage:@"Cannot find the input file (.xib or .nib): " + FILE.canonical(inputFile)]; + [self failWithMessage:@"Cannot find the input file (.xib or .nib): " + FILE.canonical(inputPath)]; } - else if (path = [self findInputFile:inputFile extension:nil]) - inputFile = path; + else if (path = [self findInputPath:inputPath extension:nil]) + inputPath = path; else - [self failWithMessage:@"Could not read the input file: " + FILE.canonical(inputFile)]; + [self failWithMessage:@"Could not read the input file: " + FILE.canonical(inputPath)]; - return FILE.canonical(inputFile); + return FILE.canonical(inputPath); } -- (void)findInputFile:(CPString)inputFile extension:(CPString)extension +- (void)findInputPath:(CPString)inputPath extension:(CPString)extension { - var path = inputFile; + var path = inputPath; if (extension) path += extension; @@ -477,7 +524,7 @@ var FILE = require("file"), if (FILE.isReadable(path)) return path; - if (FILE.basename(FILE.dirname(inputFile)) !== "Resources" && FILE.isDirectory("Resources")) + if (FILE.basename(FILE.dirname(inputPath)) !== "Resources" && FILE.isDirectory("Resources")) { path = FILE.resolve(path, FILE.join("Resources", FILE.basename(path))); @@ -488,71 +535,59 @@ var FILE = require("file"), return null; } -- (void)getAppAndResourceDirectoriesFromInputFile:(CPString)inputFile options:(JSObject)options +- (void)getAppAndResourceDirectoriesFromInputPath:(CPString)aPath options:(JSObject)options { - appDirectory = resourcesDirectory = ""; + appDirectory = @""; - if (options.resourcesDir) - { - var path = FILE.canonical(options.resourcesDir); - - if (!FILE.isDirectory(path)) - [self failWithMessage:@"Cannot read resources at: " + path]; - - resourcesDirectory = path; - } - - var parentDir = FILE.dirname(inputFile); + var parentDir = FILE.dirname(aPath); if (FILE.basename(parentDir) === "Resources") { appDirectory = FILE.dirname(parentDir); - resourcesDirectory = resourcesDirectory || parentDir; + appResourceDirectory = parentDir; } else { appDirectory = parentDir; - if (!resourcesDirectory) + if (!appResourceDirectory) { var path = FILE.join(appDirectory, "Resources"); if (FILE.isDirectory(path)) - resourcesDirectory = path; + appResourceDirectory = path; } } } -- (CPString)getOutputFileFromInputFile:(CPString)inputFile args:(CPArray)theArgs +- (CPString)getOutputPathFromInputPath:(CPString)aPath args:(CPArray)theArgs { - var outputFile = null; + var outputPath = null; if (theArgs.length > 1) { - outputFile = theArgs[1]; + outputPath = theArgs[1]; - if (!/^.+\.cib$/.test(outputFile)) - outputFile += ".cib"; + if (!/^.+\.cib$/.test(outputPath)) + outputPath += ".cib"; } else - outputFile = FILE.join(FILE.dirname(inputFile), FILE.basename(inputFile, FILE.extension(inputFile))) + ".cib"; + outputPath = FILE.join(FILE.dirname(aPath), FILE.basename(aPath, FILE.extension(aPath))) + ".cib"; - outputFile = FILE.canonical(outputFile); + outputPath = FILE.canonical(outputPath); - if (!FILE.isWritable(FILE.dirname(outputFile))) - [self failWithMessage:@"Cannot write the output file at: " + outputFile]; + if (!FILE.isWritable(FILE.dirname(outputPath))) + [self failWithMessage:@"Cannot write the output file at: " + outputPath]; - return outputFile; + return outputPath; } -- (void)loadFrameworks:(CPArray)frameworks verbosity:(int)verbosity callback:(JSObject)aCallback +- (void)loadFrameworks:(CPArray)frameworksToLoad verbosity:(int)verbosity { - if (!frameworks || frameworks.length === 0) - return aCallback(); + if (!frameworksToLoad || frameworksToLoad.length === 0) + return; - var returnPath = function(path) { return path; }; - - frameworks.forEach(function(aFramework) + frameworksToLoad.forEach(function(aFramework) { [self setLogLevel:verbosity]; @@ -561,19 +596,13 @@ var FILE = require("file"), // If it is just a name with no path components, try to locate it if (aFramework.indexOf("/") === -1) { - frameworkPath = [self findInCappBuild:aFramework isDirectory:YES callback:returnPath]; - - if (!frameworkPath) - frameworkPath = [self findInFrameworks:FILE.join(appDirectory, "Frameworks") - path:aFramework - isDirectory:YES - callback:returnPath]; - - if (!frameworkPath) - frameworkPath = [self findInInstalledFrameworks:aFramework isDirectory:YES callback:returnPath]; + frameworkPath = [self findInFrameworks:FILE.join(appDirectory, "Frameworks") + path:aFramework + isDirectory:YES + callback:function(path) { return path; }]; } else - frameworkPath = FILE.canonical(aFramework); + [self failWithMessage:@"-F should be used only with a framework name that is in the app's Framework directory"]; if (!frameworkPath) [self failWithMessage:@"Cannot find the framework \"" + aFramework + "\""]; @@ -592,6 +621,11 @@ var FILE = require("file"), [self setLogLevel:verbosity]; [self loadNSClassesFromBundle:frameworkBundle]; + + var frameworkName = FILE.basename(frameworkPath), + info = [frameworks valueForKey:frameworkName]; + + info.loaded = true; } finally { @@ -600,8 +634,6 @@ var FILE = require("file"), require("browser/timeout").serviceTimeouts(); }); - - aCallback(); } - (void)loadNSClassesFromBundle:(CPBundle)aBundle @@ -634,20 +666,20 @@ var FILE = require("file"), if (!defaultTheme) defaultTheme = [self getAppKitDefaultThemeName]; - var themes = [CPSet setWithObject:defaultTheme]; + var themeList = [CPSet setWithObject:defaultTheme]; if (options.auxThemes) - [themes addObjectsFromArray:options.auxThemes]; + [themeList addObjectsFromArray:options.auxThemes]; var auxThemes = infoPlist.valueForKey("CPAuxiliaryThemes"); if (auxThemes) - [themes addObjectsFromArray:auxThemes]; + [themeList addObjectsFromArray:auxThemes]; // Now remove the default theme, get the list as an array, and insert the default at the beginning - [themes removeObject:defaultTheme]; + [themeList removeObject:defaultTheme]; - var allThemes = [themes allObjects]; + var allThemes = [themeList allObjects]; [allThemes insertObject:defaultTheme atIndex:0]; @@ -735,23 +767,20 @@ var FILE = require("file"), return themeName; } -- (CPArray)loadThemesFromList:(CPArray)themeList +- (void)loadThemesFromList:(CPArray)themeList { - var themes = []; - for (var i = 0; i < themeList.length; ++i) - themes.push([self loadThemeNamed:themeList[i] directory:resourcesDirectory]); - - return themes; + themes.push([self loadThemeNamed:themeList[i]]); } -- (CPTheme)loadThemeNamed:(CPString)themeName directory:(CPString)themeDir +- (CPTheme)loadThemeNamed:(CPString)themeName { if (/^.+\.blend$/.test(themeName)) themeName = themeName.substr(0, themeName.length - ".blend".length); var blendName = themeName + ".blend", - themePath = ""; + themePath = "", + themeDir = appResourceDirectory; if (themeDir) { @@ -820,7 +849,7 @@ var FILE = require("file"), return theme; } -- (JSObject)readConfigFile:(CPString)configFile inputFile:(CPString)inputFile +- (JSObject)readConfigFile:(CPString)configFile inputPath:(CPString)inputPath { var configPath = null, path; diff --git a/Tools/nib2cib/Nib2CibKeyedUnarchiver.j b/Tools/nib2cib/Nib2CibKeyedUnarchiver.j index e60efd233..256a19759 100644 --- a/Tools/nib2cib/Nib2CibKeyedUnarchiver.j +++ b/Tools/nib2cib/Nib2CibKeyedUnarchiver.j @@ -22,22 +22,13 @@ @import +@class Nib2Cib + var FILE = require("file"); @implementation Nib2CibKeyedUnarchiver : CPKeyedUnarchiver { - CPString resourcesPath @accessors(readonly); -} - -- (id)initForReadingWithData:(CPData)data resourcesPath:(CPString)aResourcesPath -{ - self = [super initForReadingWithData:data]; - - if (self) - resourcesPath = aResourcesPath; - - return self; } - (CPArray)allObjects @@ -45,12 +36,51 @@ var FILE = require("file"); return _objects; } -- (CPString)resourcePathForName:(CPString)aName +- (JSObject)resourceInfoForName:(CPString)aName inFramework:(CPString)framework { - if (!resourcesPath) - return NULL; + var nib2cib = [Nib2Cib sharedNib2Cib], + frameworks = [nib2cib frameworks]; - var pathGroups = [FILE.listPaths(resourcesPath)]; + if (framework) + { + var info = [frameworks valueForKey:framework]; + + if (!info || !info.resourceDirectory) + return nil; + + return { path:[self _resourcePathForName:aName inDirectory:info.resourceDirectory], framework:framework }; + } + else + { + // Try the app's resource directory first + var resourcesDirectory = [nib2cib appResourceDirectory], + path = [self _resourcePathForName:aName inDirectory:resourcesDirectory]; + + if (path) + return { path:path, framework:framework }; + + var enumerator = [frameworks keyEnumerator]; + + while ((framework = [enumerator nextObject])) + { + var info = [frameworks valueForKey:framework]; + + if (!info || !info.resourceDirectory) + continue; + + path = [self _resourcePathForName:aName inDirectory:info.resourceDirectory]; + + if (path) + return { path:path, framework:framework }; + } + } + + return nil; +} + +- (CPString)_resourcePathForName:(CPString)aName inDirectory:(CPString)directory +{ + var pathGroups = [FILE.listPaths(directory)]; while (pathGroups.length > 0) { @@ -73,7 +103,7 @@ var FILE = require("file"); } } - return NULL; + return nil; } @end