mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-03 15:46:16 +00:00
Merge branch '0.9.1' of git://github.com/280north/cappuccino into 0.9.1
This commit is contained in:
@@ -952,6 +952,17 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)_sendDelegateDeleteKeyPressed
|
||||
{
|
||||
if ([[self delegate] respondsToSelector: @selector(outlineViewDeleteKeyPressed:)])
|
||||
{
|
||||
[[self delegate] outlineViewDeleteKeyPressed:self];
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the delegate object for the outlineview.
|
||||
*/
|
||||
|
||||
+15
-1
@@ -21,11 +21,25 @@
|
||||
*/
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScreen
|
||||
|
||||
A CPScreen object describes the attributes of a display device available
|
||||
to Cappuccino.
|
||||
*/
|
||||
@implementation CPScreen : CPObject
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the position and size of the visible area of the receiving screen.
|
||||
This will normally be smaller than the full size of the screen to account
|
||||
for system UI elements. For example, on a Mac the top of the visible frame
|
||||
is placed below the bottom of the menu bar.
|
||||
|
||||
@return the visible screen rectangle
|
||||
*/
|
||||
- (CGRect)visibleFrame
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
@@ -35,4 +49,4 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
+19
-2
@@ -16,6 +16,14 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
CPTabViewWillSelectTabViewItemSelector = 4,
|
||||
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTabView
|
||||
|
||||
A CPTabView object presents a tabbed interface where each page is one a
|
||||
complete view hiearchy of its own. The user can navigate between various
|
||||
pages by clicking on the tab headers.
|
||||
*/
|
||||
@implementation CPTabView : CPView
|
||||
{
|
||||
CPArray _items;
|
||||
@@ -75,8 +83,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
}
|
||||
|
||||
/*!
|
||||
Inserts a CPTabViewItem into the tab view
|
||||
at the specified index.
|
||||
Inserts a CPTabViewItem into the tab view at the specified index.
|
||||
@param aTabViewItem the item to insert
|
||||
@param anIndex the index for the item
|
||||
*/
|
||||
@@ -122,6 +129,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
/*!
|
||||
Returns the index of the specified item
|
||||
@param aTabViewItem the item to find the index for
|
||||
@return the index of aTabViewItem or CPNotFound
|
||||
*/
|
||||
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
@@ -131,6 +139,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
/*!
|
||||
Returns the index of the CPTabViewItem with the specified identifier.
|
||||
@param anIdentifier the identifier of the item
|
||||
@return the index of the tab view item identified by anIdentifier, or CPNotFound
|
||||
*/
|
||||
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
|
||||
{
|
||||
@@ -143,6 +152,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the number of items in the tab view.
|
||||
@return the number of tab view items in the receiver
|
||||
*/
|
||||
- (unsigned)numberOfTabViewItems
|
||||
{
|
||||
@@ -151,6 +161,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the CPTabViewItem at the specified index.
|
||||
@return a tab view item, or nil
|
||||
*/
|
||||
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
@@ -159,6 +170,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the array of items that backs this tab view.
|
||||
@return a copy of the array of items in the receiver
|
||||
*/
|
||||
- (CPArray)tabViewItems
|
||||
{
|
||||
@@ -262,6 +274,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the current item being displayed.
|
||||
@return the tab view item currenly being displayed by the receiver
|
||||
*/
|
||||
- (CPTabViewItem)selectedTabViewItem
|
||||
{
|
||||
@@ -271,6 +284,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
// Modifying the font
|
||||
/*!
|
||||
Returns the font for tab label text.
|
||||
@return the font for tab label text
|
||||
*/
|
||||
- (CPFont)font
|
||||
{
|
||||
@@ -279,6 +293,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Sets the font for tab label text to font.
|
||||
@param font the font the receiver should use for tab label text
|
||||
*/
|
||||
- (void)setFont:(CPFont)font
|
||||
{
|
||||
@@ -336,6 +351,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the tab view type.
|
||||
@return the tab view type of the receiver
|
||||
*/
|
||||
- (CPTabViewType)tabViewType
|
||||
{
|
||||
@@ -344,6 +360,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
/*!
|
||||
Returns the receiver's delegate.
|
||||
@return the receiver's delegate
|
||||
*/
|
||||
- (id)delegate
|
||||
{
|
||||
|
||||
+59
-31
@@ -29,26 +29,38 @@
|
||||
|
||||
var CPViewControllerCachedCibs;
|
||||
|
||||
/*! @class CPViewController
|
||||
The CPViewController class provides the fundamental view-management controller for Cappuccino applications.
|
||||
The basic view controller class supports the presentation of an associated view in addition to basic support
|
||||
for managing modal views and, in the future, animations. Subclasses such as CPNavigationController and
|
||||
CPTabBarController provide additional behavior for managing complex hierarchies of view controllers and views.
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPViewController
|
||||
|
||||
You use each instance of CPViewController to manage a single view (and hierarchy). For a simple view controller,
|
||||
this entails managing the view hierarchy responsible for presenting your application content.
|
||||
A typical view hierarchy consists of a root viewŃa reference to which is available in the view property of this classŃ
|
||||
and one or more subviews presenting the actual content. In the case of navigation and tab bar controllers, the view
|
||||
controller manages not only the high-level view hierarchy (which provides the navigation controls) but also one
|
||||
or more additional view controllers that handle the presentation of the application content.
|
||||
The CPViewController class provides the fundamental view-management
|
||||
controller for Cappuccino applications. The basic view controller class
|
||||
supports the presentation of an associated view in addition to basic
|
||||
support for managing modal views and, in the future, animations.
|
||||
Subclasses such as CPNavigationController and CPTabBarController provide
|
||||
additional behavior for managing complex hierarchies of view controllers
|
||||
and views.
|
||||
|
||||
Unlike UIViewController in Cocoa Touch, a CPViewController does not represent an entire screen of content. You
|
||||
will add your root view to an existing view or window's content view. You can manage many view controllers
|
||||
on screen at once. CPViewController is also the preferred way of working with Cibs.
|
||||
You use each instance of CPViewController to manage a single view (and
|
||||
hierarchy). For a simple view controller, this entails managing the view
|
||||
hierarchy responsible for presenting your application content. A typical
|
||||
view hierarchy consists of a root view, a reference to which is available
|
||||
in the view property of this class, and one or more subviews presenting
|
||||
the actual content. In the case of navigation and tab bar controllers, the
|
||||
view controller manages not only the high-level view hierarchy (which
|
||||
provides the navigation controls) but also one or more additional view
|
||||
controllers that handle the presentation of the application content.
|
||||
|
||||
Subclasses can override -loadView to create their custom view hierarchy, or specify a cib name to be loaded automatically.
|
||||
It has methods that are called when a view appears or disappears.
|
||||
This class is also a good place for delegate & datasource methods, and other controller stuff.
|
||||
Unlike UIViewController in Cocoa Touch, a CPViewController does not
|
||||
represent an entire screen of content. You will add your root view to an
|
||||
existing view or window's content view. You can manage many view
|
||||
controllers on screen at once. CPViewController is also the preferred way
|
||||
of working with Cibs.
|
||||
|
||||
Subclasses can override -loadView to create their custom view hierarchy,
|
||||
or specify a cib name to be loaded automatically. It has methods that are
|
||||
called when a view appears or disappears. This class is also a good place
|
||||
for delegate & datasource methods, and other controller stuff.
|
||||
*/
|
||||
@implementation CPViewController : CPResponder
|
||||
{
|
||||
@@ -88,9 +100,14 @@ var CPViewControllerCachedCibs;
|
||||
}
|
||||
|
||||
/*!
|
||||
The designated initializer. If you subclass CPViewController, you must call the super implementation of this method, even if you aren't using a Cib.
|
||||
In the specified Cib, the File's Owner proxy should have its class set to your view controller subclass, with the view outlet connected to the main view.
|
||||
If you pass in a nil Cib name, then you must either call -setView: before -view is invoked, or override -loadView to set up your views.
|
||||
The designated initializer. If you subclass CPViewController, you must
|
||||
call the super implementation of this method, even if you aren't using a
|
||||
Cib.
|
||||
|
||||
In the specified Cib, the File's Owner proxy should have its class set to
|
||||
your view controller subclass, with the view outlet connected to the main
|
||||
view. If you pass in a nil Cib name, then you must either call -setView:
|
||||
before -view is invoked, or override -loadView to set up your views.
|
||||
|
||||
@param cibNameOrNil The path to the cib to load for the root view or nil to programmatically create views.
|
||||
@param cibBundleOrNil The bundle that the cib is located in or nil for the main bundle.
|
||||
@@ -113,14 +130,18 @@ var CPViewControllerCachedCibs;
|
||||
}
|
||||
|
||||
/*!
|
||||
Programmatically creates the view that the controller manages.
|
||||
You should never call this method directly. The view controller calls this method when the view property is requested but is nil.
|
||||
Programmatically creates the view that the controller manages. You should
|
||||
never call this method directly. The view controller calls this method
|
||||
when the view property is requested but is nil.
|
||||
|
||||
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
|
||||
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
|
||||
If you create your views manually, you must override this method and use
|
||||
it to create your view and assign it to the view property. The default
|
||||
implementation for programmatic views is to create a plain view. You can
|
||||
invoke super to utilize this view.
|
||||
|
||||
If you use Interface Builder to create your views, you initialize the view using the
|
||||
initWithCibName:bundle: method then you must not override this method. The consequences risk shattering the space-time continuum.
|
||||
If you use Interface Builder to create your views, you initialize the view
|
||||
using the initWithCibName:bundle: method then you must not override this
|
||||
method. The consequences risk shattering the space-time continuum.
|
||||
|
||||
Note: The cib loading system is currently synchronous.
|
||||
*/
|
||||
@@ -144,8 +165,10 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
/*!
|
||||
Returns the view that the controller manages.
|
||||
If this property is nil, the controller sends loadView to itself to create the view that it manages.
|
||||
Subclasses should override the loadView method to create any custom views. The default value is nil.
|
||||
|
||||
If this property is nil, the controller sends loadView to itself to create
|
||||
the view that it manages. Subclasses should override the loadView method
|
||||
to create any custom views. The default value is nil.
|
||||
*/
|
||||
- (CPView)view
|
||||
{
|
||||
@@ -183,8 +206,11 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
/*!
|
||||
This method is called after the view controller has loaded its associated views into memory.
|
||||
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
|
||||
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
|
||||
|
||||
This method is called regardless of whether the views were stored in a nib
|
||||
file or created programmatically in the loadView method. This method is
|
||||
most commonly used to perform additional initialization steps on views
|
||||
that are loaded from cib files.
|
||||
*/
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
@@ -194,7 +220,9 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
/*!
|
||||
Manually sets the view that the controller manages.
|
||||
Setting to nil will cause -loadView to be called on all subsequent calls of -view.
|
||||
|
||||
Setting to nil will cause -loadView to be called on all subsequent calls
|
||||
of -view.
|
||||
|
||||
@param aView The view this controller should represent.
|
||||
*/
|
||||
|
||||
@@ -11,12 +11,12 @@ if [ -d Foundation.doc ]; then
|
||||
fi
|
||||
|
||||
echo "Processing source files..."
|
||||
tar cf AppKit.doc.tar --exclude='_*' -s /^AppKit/AppKit.doc/ AppKit/*.j AppKit/**/*.j
|
||||
tar xf AppKit.doc.tar
|
||||
bsdtar cf AppKit.doc.tar --exclude='_*' -s /^AppKit/AppKit.doc/ AppKit/*.j AppKit/**/*.j
|
||||
bsdtar xf AppKit.doc.tar
|
||||
rm AppKit.doc.tar
|
||||
|
||||
tar cf Foundation.doc.tar --exclude='_*' -s /^Foundation/Foundation.doc/ Foundation/*.j Foundation/**/*.j
|
||||
tar xf Foundation.doc.tar
|
||||
bsdtar cf Foundation.doc.tar --exclude='_*' -s /^Foundation/Foundation.doc/ Foundation/*.j Foundation/**/*.j
|
||||
bsdtar xf Foundation.doc.tar
|
||||
rm Foundation.doc.tar
|
||||
|
||||
find AppKit.doc -name *.j -exec sed -e '/@import.*/ d' -i '' {} \;
|
||||
|
||||
+8
-2
@@ -1,8 +1,12 @@
|
||||
|
||||
require ("../../common.jake");
|
||||
|
||||
var app = require("objective-j/jake").app;
|
||||
var BundleTask = require("objective-j/jake").BundleTask;
|
||||
var app = require("objective-j/jake").app,
|
||||
BundleTask = require("objective-j/jake").BundleTask,
|
||||
fileCreate = require("jake").fileCreate,
|
||||
FILE = require("file"),
|
||||
OS = require("os"),
|
||||
stream = require("narwhal/term").stream;
|
||||
|
||||
app ("capp", function(cappTask)
|
||||
{
|
||||
@@ -36,6 +40,8 @@ filedir($BUILD_CJS_CAPP, ["capp"], function()
|
||||
make_objj_executable($BUILD_CJS_CAPP);
|
||||
});
|
||||
|
||||
copyManPage("capp", 1);
|
||||
|
||||
task ("build", ["capp", $BUILD_CJS_CAPP]);
|
||||
|
||||
CLOBBER.include($BUILD_CJS_CAPPUCCINO_BIN);
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
.Dd March 30, 2011
|
||||
.Os "Cappuccino"
|
||||
.Dt CAPP 1 "PRM"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh NAME
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Nm capp
|
||||
.Nd generate cappuccino projects
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh SYNOPSIS
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Nm
|
||||
.Sy gen
|
||||
.Op options
|
||||
.Pa path
|
||||
.Nm
|
||||
.Cm gen
|
||||
.Op --list-templates | --list-frameworks
|
||||
.Nm
|
||||
.Cm config
|
||||
.Op options
|
||||
.Nm
|
||||
.Op --version | -h | --help
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh "DESCRIPTION"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Nm
|
||||
generates starter projects for cappuccino, ensuring that all of the necessary files
|
||||
are present, and applying the values in your
|
||||
.Ar configuration
|
||||
to placeholders the template.
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh "GENERATING PROJECTS"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
When invoked using
|
||||
.Nm
|
||||
.Cm gen ,
|
||||
you either create a new project or modify the frameworks of an existing project.
|
||||
.Ss Create options
|
||||
When creating a new project, if no options are specified,
|
||||
.Nm
|
||||
will use the
|
||||
.Ar Application
|
||||
template, which by default does not use a
|
||||
.Ar cib
|
||||
to create its interface. If you wish to use a different template, the following options are available:
|
||||
.Bl -tag -width 4n
|
||||
.It Fl t, \-template Ar template
|
||||
Specifies the template name to use when generating the project. This determines the type
|
||||
of project to generate.
|
||||
.It Fl \-list-templates
|
||||
Displays the templates names available for use with the
|
||||
.Sy -t/--template
|
||||
option.
|
||||
.El
|
||||
.Ss Frameworks options
|
||||
There are a number of options available for specifying how to create or update
|
||||
the Frameworks directory in your project. The available options are:
|
||||
.Bl -tag -width 4n
|
||||
.It Fl f, \-frameworks
|
||||
This will copy or symlink
|
||||
.Sy only
|
||||
the Frameworks directory instead of generating an entire project. This is
|
||||
especially useful if you want to update the Frameworks for an existing project.
|
||||
.It Fl F, \-framework Ar name
|
||||
The
|
||||
.Sy -f/--frameworks
|
||||
option always copies/symlinks the Objective-J, Foundation, and AppKit frameworks. You may
|
||||
include additional frameworks with this option. You may use this option multiple times
|
||||
to include multiple frameworks.
|
||||
.It Fl \-list-frameworks
|
||||
Displays a list of frameworks that are available for use with the
|
||||
.Sy -F/--framework
|
||||
option.
|
||||
.It Fl \-symlink
|
||||
By default frameworks are copied to the project directory. Use this option to symlink
|
||||
to the source frameworks instead of copying.
|
||||
.It Fl \-build
|
||||
By default frameworks are copied/symlinked from the installed version created with
|
||||
.Sy jake install.
|
||||
Use this option to copy/symlink the version created in
|
||||
.Ar $CAPP_BUILD
|
||||
with
|
||||
.Sy jake debug
|
||||
or
|
||||
.Sy jake release.
|
||||
.It Fl l
|
||||
This is a handy shortcut for
|
||||
.Sy --symlink --build.
|
||||
.El
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh CONFIGURING
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
When invoked using
|
||||
.Nm
|
||||
.Cm config ,
|
||||
you can set or inspect the values used to replace placeholder text in the templates. The syntax
|
||||
for
|
||||
.Cm capp config
|
||||
is as follows:
|
||||
.Bl -tag -width 4n
|
||||
.It Ar key value
|
||||
Creates or updates a configuration item with the given key and value.
|
||||
.It Fl \-get Ar key
|
||||
Displays the configuration value with the given key. If no item with the given key exists,
|
||||
nothing happens.
|
||||
.It Fl \-remove Ar key
|
||||
Removes the configuration value with the given key. If no item with the given key exists,
|
||||
nothing happens.
|
||||
.It Fl -l, \-list
|
||||
Displays a list of all configuration items in the form
|
||||
.Sy key=value.
|
||||
.El
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh GENERAL OPTIONS
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Bl -tag -width 4n
|
||||
.It Fl \-version
|
||||
Displays the current
|
||||
.Nm
|
||||
version and exits.
|
||||
.It Fl h, \-help
|
||||
Displays a concise list of the available commands and options.
|
||||
.El
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh FILES
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Bl -hang -width 4n
|
||||
.It Em ~/.cappconfig
|
||||
Contains your configuration in 280north plist format.
|
||||
.El
|
||||
@@ -27,13 +27,13 @@ task ("build", function()
|
||||
|
||||
task ("clean", function()
|
||||
{
|
||||
if (OS.system("xcodebuild clean"))
|
||||
if (executableExists("xcodebuild") && OS.system("xcodebuild clean"))
|
||||
OS.exit(1);
|
||||
});
|
||||
|
||||
task ("clobber", function()
|
||||
{
|
||||
if (OS.system("xcodebuild clean"))
|
||||
if (executableExists("xcodebuild") && OS.system("xcodebuild clean"))
|
||||
OS.exit(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -132,7 +132,16 @@
|
||||
{
|
||||
var bold = [nibFont isBold];
|
||||
|
||||
cibFont = [theme valueForAttributeWithName:@"font" inState:[object themeState] forClass:[object class]];
|
||||
for (var i = 0; i < themes.length; ++i)
|
||||
{
|
||||
cibFont = [themes[i] valueForAttributeWithName:@"font" inState:[object themeState] forClass:[object class]];
|
||||
|
||||
if (cibFont)
|
||||
{
|
||||
source = " (from " + [themes[i] name] + ")";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Substitute legacy theme fonts for the current system font
|
||||
if (!cibFont || [cibFont familyName] === CPFontDefaultSystemFontFace)
|
||||
@@ -144,7 +153,6 @@
|
||||
size = [CPFont systemFontSize];
|
||||
|
||||
cibFont = bold ? [CPFont boldSystemFontOfSize:size] : [CPFont systemFontOfSize:size];
|
||||
source = " (from theme)"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ ConverterConversionException = @"ConverterConversionException";
|
||||
CPString outputPath @accessors;
|
||||
CPString resourcesPath @accessors;
|
||||
NibFormat format @accessors(readonly);
|
||||
CPTheme theme @accessors(readonly);
|
||||
CPArray themes @accessors(readonly);
|
||||
}
|
||||
|
||||
+ (Converter)sharedConverter
|
||||
@@ -55,7 +55,7 @@ ConverterConversionException = @"ConverterConversionException";
|
||||
return SharedConverter;
|
||||
}
|
||||
|
||||
- (id)initWithInputPath:(CPString)aPath format:(NibFormat)nibFormat theme:(CPTheme)aTheme
|
||||
- (id)initWithInputPath:(CPString)aPath format:(NibFormat)nibFormat themes:(CPArray)themeList
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
@@ -63,7 +63,7 @@ ConverterConversionException = @"ConverterConversionException";
|
||||
{
|
||||
inputPath = aPath;
|
||||
format = nibFormat;
|
||||
theme = aTheme;
|
||||
themes = themeList;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -36,6 +36,8 @@ filedir($BUILD_CJS_NIB2CIB, ["nib2cib"], function()
|
||||
make_objj_executable($BUILD_CJS_NIB2CIB);
|
||||
});
|
||||
|
||||
copyManPage("nib2cib", 1);
|
||||
|
||||
task ("build", ["nib2cib", $BUILD_CJS_NIB2CIB]);
|
||||
|
||||
CLOBBER.include($BUILD_CJS_NIB2CIB);
|
||||
|
||||
@@ -47,9 +47,9 @@ var FILE = require("file");
|
||||
var resourcePath = [aCoder resourcePathForName:_resourceName];
|
||||
|
||||
if (!resourcePath)
|
||||
CPLog.warn("Resource named " + _resourceName + " not found in the supplied resources path.");
|
||||
CPLog.warn("Resource \"" + _resourceName + "\" not found in the resources path: " + [aCoder resourcesPath]);
|
||||
else
|
||||
size = imageSize(FILE.join(FILE.cwd(), resourcePath));
|
||||
size = imageSize(FILE.canonical(resourcePath));
|
||||
|
||||
// Account for the fact that an extension may have been inferred.
|
||||
if (resourcePath && FILE.extension(resourcePath) !== FILE.extension(_resourceName))
|
||||
|
||||
+302
-145
@@ -35,13 +35,16 @@ var FILE = require("file"),
|
||||
SYS = require("system"),
|
||||
FileList = require("jake").FileList,
|
||||
stream = require("narwhal/term").stream,
|
||||
StaticResource = require("objective-j").StaticResource,
|
||||
|
||||
DefaultTheme = "Aristo",
|
||||
BuildTypes = ["Debug", "Release"],
|
||||
DefaultXibFile = "MainMenu.xib";
|
||||
DefaultFile = "MainMenu";
|
||||
|
||||
var parser = new (require("narwhal/args").Parser)(),
|
||||
nibInfo = {};
|
||||
nibInfo = {},
|
||||
appDirectory = "",
|
||||
resourcesDirectory = "";
|
||||
|
||||
|
||||
function main(args)
|
||||
@@ -57,7 +60,7 @@ function main(args)
|
||||
}
|
||||
catch (anException)
|
||||
{
|
||||
CPLog.fatal([anException reason]);
|
||||
CPLog.fatal(exceptionReason(anException));
|
||||
OS.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -68,50 +71,52 @@ function convert(options, inputFile)
|
||||
{
|
||||
inputFile = inputFile || getInputFile(options.args);
|
||||
|
||||
getAppAndResourceDirectoriesFromInputFile(inputFile, options);
|
||||
|
||||
var outputFile = getOutputFile(inputFile, options.args),
|
||||
resourcesPath = "";
|
||||
configInfo = readConfigFile(options.configFile || "", inputFile),
|
||||
defaultTheme = null;
|
||||
|
||||
if (options.resources)
|
||||
if (configInfo.plist)
|
||||
{
|
||||
resourcesPath = FILE.canonical(options.resources);
|
||||
var systemFontFace = configInfo.plist.valueForKey("CPSystemFontFace");
|
||||
|
||||
if (!FILE.isDirectory(resourcesPath) || !FILE.isReadable(resourcesPath))
|
||||
fail("Cannot read resources at: " + resourcesPath);
|
||||
if (systemFontFace)
|
||||
[CPFont setSystemFontFace:systemFontFace];
|
||||
|
||||
var systemFontSize = configInfo.plist.valueForKey("CPSystemFontSize");
|
||||
|
||||
if (systemFontSize)
|
||||
[CPFont setSystemFontSize:parseFloat(systemFontSize, 10)];
|
||||
|
||||
if (!options.defaultTheme)
|
||||
defaultTheme = configInfo.plist.valueForKey("CPDefaultTheme");
|
||||
}
|
||||
|
||||
var configPath = setSystemFontAndSize(options.configFile || "", inputFile),
|
||||
themeName = "",
|
||||
themeDir = options.themeDir || "";
|
||||
|
||||
if (themeDir)
|
||||
themeName = FILE.basename(themeDir, FILE.extension(themeDir));
|
||||
|
||||
themeName = themeName || getDefaultThemeName();
|
||||
|
||||
if (!themeName)
|
||||
fail("Could not determine the theme name.");
|
||||
|
||||
var theme = loadTheme(themeName, themeDir);
|
||||
var themeList = getThemeList(defaultTheme || options.defaultTheme, options),
|
||||
themes = loadThemes(themeList);
|
||||
|
||||
CPLog.info("\n-------------------------------------------------------------");
|
||||
CPLog.info("Input : " + inputFile);
|
||||
CPLog.info("Output : " + outputFile);
|
||||
CPLog.info("Format : " + ["Auto", "Mac", "iPhone"][options.format]);
|
||||
CPLog.info("Resources : " + resourcesPath);
|
||||
CPLog.info("Frameworks : " + (options.frameworks || ""));
|
||||
CPLog.info("Theme : " + themeName);
|
||||
CPLog.info("Config file : " + (configPath || ""));
|
||||
CPLog.info("System Font : " + [CPFont systemFontSize] + "px " + [CPFont systemFontFace]);
|
||||
CPLog.info("Input : " + inputFile);
|
||||
CPLog.info("Output : " + outputFile);
|
||||
CPLog.info("Format : " + ["Auto", "Mac", "iPhone"][options.format]);
|
||||
CPLog.info("Application : " + appDirectory);
|
||||
CPLog.info("Resources : " + resourcesDirectory);
|
||||
CPLog.info("Frameworks : " + (options.frameworks || ""));
|
||||
CPLog.info("Default theme : " + themeList[0]);
|
||||
CPLog.info("Extra 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
|
||||
theme:theme];
|
||||
themes:themes];
|
||||
|
||||
[converter setOutputPath:outputFile];
|
||||
[converter setResourcesPath:resourcesPath];
|
||||
[converter setResourcesPath:resourcesDirectory];
|
||||
|
||||
loadFrameworks(options.frameworks, function()
|
||||
loadFrameworks(options.frameworks, options.verbosity, function()
|
||||
{
|
||||
[converter convert];
|
||||
});
|
||||
@@ -120,7 +125,7 @@ function convert(options, inputFile)
|
||||
}
|
||||
catch (anException)
|
||||
{
|
||||
CPLog.fatal([anException reason]);
|
||||
CPLog.fatal(exceptionReason(anException));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -128,39 +133,72 @@ function convert(options, inputFile)
|
||||
function watch(options)
|
||||
{
|
||||
var verbosity = options.quiet ? -1 : options.verbosity,
|
||||
directory = options.args[0];
|
||||
watchDir = options.args[0];
|
||||
|
||||
if (!directory)
|
||||
directory = FILE.isDirectory("Resources") ? "Resources" : ".";
|
||||
if (!watchDir)
|
||||
watchDir = FILE.canonical(FILE.isDirectory("Resources") ? "Resources" : ".");
|
||||
else
|
||||
{
|
||||
watchDir = FILE.canonical(watchDir);
|
||||
|
||||
directory = FILE.canonical(directory);
|
||||
if (FILE.basename(watchDir) !== "Resources")
|
||||
{
|
||||
var path = FILE.join(watchDir, "Resources");
|
||||
|
||||
if (!FILE.isDirectory(directory))
|
||||
fail("Cannot find the directory: " + directory);
|
||||
if (FILE.isDirectory(path))
|
||||
watchDir = path;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FILE.isDirectory(watchDir))
|
||||
fail("Cannot find the directory: " + watchDir);
|
||||
|
||||
// Turn on info messages
|
||||
setLogLevel(1);
|
||||
|
||||
CPLog.info("Watching: " + CPLogColorize(directory, "debug"));
|
||||
var nibs = new FileList(FILE.join(watchDir, "*.[nx]ib")).items(),
|
||||
count = nibs.length;
|
||||
|
||||
// First time through only IB files with no corresponding cib
|
||||
// or a cib with an earlier or equal mtime are converted.
|
||||
while (count--)
|
||||
{
|
||||
var nib = nibs[count],
|
||||
cib = nib.substr(0, nib.length - 4) + ".cib";
|
||||
|
||||
if (FILE.exists(cib) && (FILE.mtime(nib) - FILE.mtime(cib)) <= 0)
|
||||
nibInfo[nib] = FILE.mtime(nib);
|
||||
}
|
||||
|
||||
CPLog.info("Watching: " + CPLogColorize(watchDir, "debug"));
|
||||
CPLog.info("Press Control-C to stop...");
|
||||
|
||||
while (true)
|
||||
{
|
||||
var modifiedNibs = getModifiedNibs(directory);
|
||||
var modifiedNibs = getModifiedNibs(watchDir);
|
||||
|
||||
for (var i = 0; i < modifiedNibs.length; ++i)
|
||||
{
|
||||
var action = modifiedNibs[i][0],
|
||||
path = modifiedNibs[i][1],
|
||||
label = action === "add" ? "Added:" : "Modified:",
|
||||
nib = modifiedNibs[i][1],
|
||||
label = action === "add" ? "Added" : "Modified",
|
||||
level = action === "add" ? "info" : "debug";
|
||||
|
||||
CPLog.info(">> %s %s", CPLogColorize(label, level), path);
|
||||
CPLog.info(">> %s: %s", CPLogColorize(label, level), nib);
|
||||
|
||||
// Don't convert an add if there is an existing cib with a later mtime
|
||||
if (action === "add")
|
||||
{
|
||||
var cib = nib.substr(0, nib.length - 4) + ".cib";
|
||||
|
||||
if (FILE.exists(cib) && (FILE.mtime(nib) - FILE.mtime(cib)) < 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Let the converter log however the user configured it
|
||||
setLogLevel(verbosity);
|
||||
|
||||
var success = convert(options, path);
|
||||
var success = convert(options, nib);
|
||||
|
||||
setLogLevel(1);
|
||||
|
||||
@@ -185,25 +223,24 @@ function parseOptions(args)
|
||||
.set(true)
|
||||
.help("Ask nib2cib to watch a directory for changes");
|
||||
|
||||
parser.option("-F", "framework", "frameworks")
|
||||
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")
|
||||
.help("Specify a custom default theme which is not set in your Info.plist");
|
||||
|
||||
parser.option("-t", "--theme", "extraThemes")
|
||||
.push()
|
||||
.help("Add a framework to load");
|
||||
|
||||
parser.option("-R", "resources")
|
||||
.set()
|
||||
.help("Set the Resources directory");
|
||||
|
||||
parser.option("--mac", "format")
|
||||
.set(NibFormatMac)
|
||||
.def(NibFormatUndetermined)
|
||||
.help("Set format to Mac");
|
||||
|
||||
parser.option("-t", "--theme-dir", "themeDir")
|
||||
.set()
|
||||
.help("A <theme>.build directory to use for theme attribute values");
|
||||
.displayName("name")
|
||||
.help("An additional theme loaded dynamically by your application");
|
||||
|
||||
parser.option("--config", "configFile")
|
||||
.set()
|
||||
.displayName("path")
|
||||
.help("A path to an Info.plist file from which the system font and/or size can be retrieved");
|
||||
|
||||
// parser.option("--iphone", "format")
|
||||
@@ -218,6 +255,15 @@ function parseOptions(args)
|
||||
.set(true)
|
||||
.help("No output");
|
||||
|
||||
parser.option("-F", "framework", "frameworks")
|
||||
.push()
|
||||
.help("Add a framework to load");
|
||||
|
||||
parser.option("--mac", "format")
|
||||
.set(NibFormatMac)
|
||||
.def(NibFormatUndetermined)
|
||||
.help("Set format to Mac");
|
||||
|
||||
parser.option("--version", "showVersion")
|
||||
.action(printVersionAndExit)
|
||||
.help("Show the version of nib2cib and quit");
|
||||
@@ -254,21 +300,80 @@ function setLogLevel(level)
|
||||
|
||||
function getInputFile(args)
|
||||
{
|
||||
var inputFile = args[0] || DefaultXibFile;
|
||||
var inputFile = args[0] || DefaultFile,
|
||||
path = "";
|
||||
|
||||
if (!/^.+\.xib$/.test(inputFile))
|
||||
inputFile += ".xib";
|
||||
if (!/^.+\.[nx]ib$/.test(inputFile))
|
||||
{
|
||||
if (path = findInputFile(inputFile, ".xib"))
|
||||
inputFile = path;
|
||||
else if (path = findInputFile(inputFile, ".nib"))
|
||||
inputFile = path;
|
||||
else
|
||||
fail("Cannot find the input file (.xib or .nib): " + FILE.canonical(inputFile));
|
||||
}
|
||||
else if (path = findInputFile(inputFile))
|
||||
inputFile = path;
|
||||
else
|
||||
fail("Could not read the input file: " + FILE.canonical(inputFile));
|
||||
|
||||
inputFile = FILE.canonical(inputFile);
|
||||
return FILE.canonical(inputFile);
|
||||
}
|
||||
|
||||
if (!FILE.exists(inputFile) && FILE.basename(FILE.dirname(inputFile)) !== "Resources")
|
||||
if (FILE.isDirectory("Resources"))
|
||||
inputFile = FILE.resolve(inputFile, FILE.join("Resources", FILE.basename(inputFile)));
|
||||
function findInputFile(inputFile, extension)
|
||||
{
|
||||
var path = inputFile;
|
||||
|
||||
if (!FILE.isReadable(inputFile))
|
||||
fail("Cannot read the input file: " + inputFile);
|
||||
if (extension)
|
||||
path += extension;
|
||||
|
||||
return inputFile;
|
||||
if (FILE.isReadable(path))
|
||||
return path;
|
||||
|
||||
if (FILE.basename(FILE.dirname(inputFile)) !== "Resources" && FILE.isDirectory("Resources"))
|
||||
{
|
||||
path = FILE.resolve(path, FILE.join("Resources", FILE.basename(path)));
|
||||
|
||||
if (FILE.isReadable(path))
|
||||
return path;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getAppAndResourceDirectoriesFromInputFile(inputFile, options)
|
||||
{
|
||||
appDirectory = resourcesDirectory = "";
|
||||
|
||||
if (options.resourcesDir)
|
||||
{
|
||||
var path = FILE.canonical(options.resourcesDir);
|
||||
|
||||
if (!FILE.isDirectory(path))
|
||||
fail("Cannot read resources at: " + path);
|
||||
|
||||
resourcesDirectory = path;
|
||||
}
|
||||
|
||||
var parentDir = FILE.dirname(inputFile);
|
||||
|
||||
if (FILE.basename(parentDir) === "Resources")
|
||||
{
|
||||
appDirectory = FILE.dirname(parentDir);
|
||||
resourcesDirectory = resourcesDirectory || parentDir;
|
||||
}
|
||||
else
|
||||
{
|
||||
appDirectory = parentDir;
|
||||
|
||||
if (!resourcesDirectory)
|
||||
{
|
||||
var path = FILE.join(appDirectory, "Resources");
|
||||
|
||||
if (FILE.isDirectory(path))
|
||||
resourcesDirectory = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getOutputFile(inputFile, args)
|
||||
@@ -276,14 +381,16 @@ function getOutputFile(inputFile, args)
|
||||
var outputFile = null;
|
||||
|
||||
if (args.length > 1)
|
||||
{
|
||||
outputFile = args[1];
|
||||
|
||||
if (!/^.+\.cib$/.test(outputFile))
|
||||
outputFile += ".cib";
|
||||
}
|
||||
else
|
||||
outputFile = FILE.basename(inputFile, FILE.extension(inputFile));
|
||||
outputFile = FILE.join(FILE.dirname(inputFile), FILE.basename(inputFile, FILE.extension(inputFile))) + ".cib";
|
||||
|
||||
if (!/^.+\.cib$/.test(outputFile))
|
||||
outputFile += ".cib";
|
||||
|
||||
outputFile = FILE.resolve(inputFile, outputFile);
|
||||
outputFile = FILE.canonical(outputFile);
|
||||
|
||||
if (!FILE.isWritable(FILE.dirname(outputFile)))
|
||||
fail("Cannot write the output file at: " + outputFile);
|
||||
@@ -291,18 +398,30 @@ function getOutputFile(inputFile, args)
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
function loadFrameworks(frameworkPaths, aCallback)
|
||||
function loadFrameworks(frameworkPaths, verbosity, aCallback)
|
||||
{
|
||||
if (!frameworkPaths || frameworkPaths.length === 0)
|
||||
return aCallback();
|
||||
|
||||
frameworkPaths.forEach(function(aFrameworkPath)
|
||||
{
|
||||
setLogLevel(verbosity);
|
||||
CPLog.info("Loading " + aFrameworkPath);
|
||||
|
||||
var frameworkBundle = [[CPBundle alloc] initWithPath:aFrameworkPath];
|
||||
try
|
||||
{
|
||||
// CPBundle is a bit loquacious with logging, we will defer
|
||||
// logging its exceptions till later.
|
||||
setLogLevel(-1);
|
||||
|
||||
[frameworkBundle loadWithDelegate:nil];
|
||||
var frameworkBundle = [[CPBundle alloc] initWithPath:aFrameworkPath];
|
||||
|
||||
[frameworkBundle loadWithDelegate:nil];
|
||||
}
|
||||
finally
|
||||
{
|
||||
setLogLevel(verbosity);
|
||||
}
|
||||
|
||||
require("browser/timeout").serviceTimeouts();
|
||||
});
|
||||
@@ -318,6 +437,18 @@ function logFormatter(aString, aLevel, aTitle)
|
||||
return CPLogColorize(aString, aLevel);
|
||||
}
|
||||
|
||||
function getThemeList(defaultTheme, options)
|
||||
{
|
||||
var themes = [defaultTheme || getDefaultThemeName()];
|
||||
|
||||
if (options.extraThemes)
|
||||
for (var i = 0; i < options.extraThemes.length; ++i)
|
||||
if (themes.indexOf(options.extraThemes[i]) < 0)
|
||||
themes.push(options.extraThemes[i]);
|
||||
|
||||
return themes;
|
||||
}
|
||||
|
||||
function getDefaultThemeName()
|
||||
{
|
||||
var themeName = nil,
|
||||
@@ -328,6 +459,7 @@ function getDefaultThemeName()
|
||||
for (var i = 0; i < BuildTypes.length; ++i)
|
||||
{
|
||||
var path = FILE.join(cappBuild, BuildTypes[i], "AppKit", "Info.plist");
|
||||
|
||||
themeName = themeNameFromPropertyList(path);
|
||||
|
||||
if (themeName)
|
||||
@@ -352,11 +484,36 @@ function themeNameFromPropertyList(path)
|
||||
return themeName;
|
||||
}
|
||||
|
||||
function loadThemes(themeList)
|
||||
{
|
||||
var themes = [];
|
||||
|
||||
for (var i = 0; i < themeList.length; ++i)
|
||||
themes.push(loadTheme(themeList[i], resourcesDirectory));
|
||||
|
||||
return themes;
|
||||
}
|
||||
|
||||
function loadTheme(themeName, themeDir)
|
||||
{
|
||||
if (/^.+\.blend$/.test(themeName))
|
||||
themeName = themeName.substr(0, themeName.length - ".blend".length);
|
||||
|
||||
var blendName = themeName + ".blend",
|
||||
themePath = "";
|
||||
|
||||
if (themeDir)
|
||||
{
|
||||
themePath = FILE.join(FILE.canonical(themeDir), blendName);
|
||||
|
||||
if (!FILE.isDirectory(themePath))
|
||||
themePath = themeDir = null;
|
||||
}
|
||||
|
||||
if (!themeDir)
|
||||
{
|
||||
cappBuild = SYS.env["CAPP_BUILD"];
|
||||
// Try in $CAPP_BUILD
|
||||
cappBuild = FILE.canonical(SYS.env["CAPP_BUILD"]);
|
||||
|
||||
if (!cappBuild)
|
||||
fail("$CAPP_BUILD is not set, exiting.");
|
||||
@@ -364,69 +521,76 @@ function loadTheme(themeName, themeDir)
|
||||
if (!FILE.isDirectory(cappBuild))
|
||||
fail("$CAPP_BUILD does not exist: " + cappBuild)
|
||||
|
||||
var baseThemeName = themeName,
|
||||
pos = themeName.indexOf("-");
|
||||
|
||||
if (pos > 0)
|
||||
baseThemeName = themeName.substr(0, pos);
|
||||
|
||||
themeDir = FILE.join(cappBuild, baseThemeName + ".build");
|
||||
}
|
||||
|
||||
themeDir = FILE.canonical(themeDir);
|
||||
|
||||
if (!FILE.isDirectory(themeDir))
|
||||
fail("Cannot find the theme directory: " + themeDir);
|
||||
|
||||
var themePath = null;
|
||||
|
||||
for (var i = 0; i < BuildTypes.length; ++i)
|
||||
{
|
||||
var path = FILE.join(themeDir, BuildTypes[i], "Browser.environment/Resources", themeName + ".keyedtheme");
|
||||
|
||||
if (FILE.isReadable(path))
|
||||
for (var i = 0; i < BuildTypes.length; ++i)
|
||||
{
|
||||
themePath = path;
|
||||
break;
|
||||
var path = FILE.join(cappBuild, BuildTypes[i], blendName);
|
||||
|
||||
if (FILE.isDirectory(path))
|
||||
{
|
||||
themePath = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Last resort, try the cwd
|
||||
if (!themePath)
|
||||
{
|
||||
var path = FILE.canonical(blendName);
|
||||
|
||||
if (FILE.isDirectory(path))
|
||||
themePath = path;
|
||||
}
|
||||
}
|
||||
|
||||
if (!themePath)
|
||||
fail("Could not find the keyed theme data for \"" + themeName + "\" in the directory: " + themeDir);
|
||||
fail("Cannot find the theme \"" + themeName + "\"");
|
||||
|
||||
themePath = FILE.canonical(themePath);
|
||||
var plist = FILE.read(themePath);
|
||||
return readTheme(themeName, themePath);
|
||||
}
|
||||
|
||||
if (!plist)
|
||||
fail("Could not read the keyed theme at: " + themePath);
|
||||
function readTheme(name, path)
|
||||
{
|
||||
var themeBundle = new CFBundle(path);
|
||||
|
||||
// The .keyedtheme file has a header that is data I don't need. Strip it off.
|
||||
var m = plist.match(/^t;\d+;/);
|
||||
// By default when we try to load the bundle it will use the CommonJS environment,
|
||||
// but we want the Browser environment. So we override mostEligibleEnvironment().
|
||||
themeBundle.mostEligibleEnvironment = function() { return "Browser"; }
|
||||
themeBundle.load();
|
||||
|
||||
if (!m || m.length === 0)
|
||||
fail("Invalid keyed theme data at: " + themePath);
|
||||
var keyedThemes = themeBundle.valueForInfoDictionaryKey("CPKeyedThemes");
|
||||
|
||||
plist = plist.substr(m[0].length);
|
||||
plist = CFPropertyList.propertyListFromString(plist);
|
||||
if (!keyedThemes)
|
||||
fail("Could not find the keyed themes in the theme: " + path);
|
||||
|
||||
var data = [CPData dataWithPlistObject:plist],
|
||||
theme = [CPKeyedUnarchiver unarchiveObjectWithData:data];
|
||||
var index = keyedThemes.indexOf(name + ".keyedtheme");
|
||||
|
||||
if (index < 0)
|
||||
fail("Could not find the main theme data (" + name + ".keyedtheme" + ") in the theme: " + path);
|
||||
|
||||
// Load the keyed theme data, making sure to resolve it
|
||||
var resourcePath = themeBundle.pathForResource(keyedThemes[index]),
|
||||
themeData = new CFMutableData();
|
||||
|
||||
themeData.setRawString(StaticResource.resourceAtURL(new CFURL(resourcePath), true).contents());
|
||||
|
||||
var theme = [CPKeyedUnarchiver unarchiveObjectWithData:themeData];
|
||||
|
||||
if (!theme)
|
||||
fail("Could not unarchive the theme at: " + themePath);
|
||||
fail("Could not unarchive the theme at: " + path);
|
||||
|
||||
CPLog.debug("Loaded theme: " + themePath);
|
||||
CPLog.debug("Loaded theme: " + path);
|
||||
return theme;
|
||||
}
|
||||
|
||||
function setSystemFontAndSize(configFile, inputFile)
|
||||
function readConfigFile(configFile, inputFile)
|
||||
{
|
||||
var configPath = null;
|
||||
var configPath = null,
|
||||
path;
|
||||
|
||||
// First see if the user passed a config file path
|
||||
if (configFile)
|
||||
{
|
||||
var path = FILE.canonical(configFile);
|
||||
path = FILE.canonical(configFile);
|
||||
|
||||
if (!FILE.isReadable(path))
|
||||
fail("Cannot find the config file: " + path);
|
||||
@@ -435,19 +599,14 @@ function setSystemFontAndSize(configFile, inputFile)
|
||||
}
|
||||
else
|
||||
{
|
||||
// See if we can find an Info.plist in the parent directory of the input file,
|
||||
// if the input file's directory is "Resources".
|
||||
var path = FILE.canonical(FILE.dirname(inputFile));
|
||||
path = FILE.join(appDirectory, "Info.plist");
|
||||
|
||||
if (FILE.basename(path) === "Resources")
|
||||
{
|
||||
path = FILE.join(FILE.dirname(path), "Info.plist");
|
||||
|
||||
if (FILE.isReadable(path))
|
||||
configPath = path;
|
||||
}
|
||||
if (FILE.isReadable(path))
|
||||
configPath = path;
|
||||
}
|
||||
|
||||
var plist = null;
|
||||
|
||||
if (configPath)
|
||||
{
|
||||
var plist = FILE.read(configPath);
|
||||
@@ -459,24 +618,14 @@ function setSystemFontAndSize(configFile, inputFile)
|
||||
|
||||
if (!plist)
|
||||
fail("Could not parse the Info.plist at: " + configPath);
|
||||
|
||||
var systemFontFace = plist.valueForKey("CPSystemFontFace");
|
||||
|
||||
if (systemFontFace)
|
||||
[CPFont setSystemFontFace:systemFontFace];
|
||||
|
||||
var systemFontSize = plist.valueForKey("CPSystemFontSize");
|
||||
|
||||
if (systemFontSize)
|
||||
[CPFont setSystemFontSize:parseFloat(systemFontSize, 10)];
|
||||
}
|
||||
|
||||
return configPath;
|
||||
return {path: configPath, plist: plist};
|
||||
}
|
||||
|
||||
function getModifiedNibs(path)
|
||||
{
|
||||
var nibs = new FileList(FILE.join(path, "*.xib")).items(),
|
||||
var nibs = new FileList(FILE.join(path, "*.[nx]ib")).items(),
|
||||
count = nibs.length,
|
||||
newNibInfo = {},
|
||||
modifiedNibs = [];
|
||||
@@ -501,10 +650,8 @@ function getModifiedNibs(path)
|
||||
}
|
||||
|
||||
for (var nib in nibInfo)
|
||||
{
|
||||
if (nibInfo.hasOwnProperty(nib))
|
||||
CPLog.info(">> %s %s", CPLogColorize("Deleted:", "warn"), nib);
|
||||
}
|
||||
CPLog.info(">> %s: %s", CPLogColorize("Deleted", "warn"), nib);
|
||||
|
||||
nibInfo = newNibInfo;
|
||||
|
||||
@@ -558,6 +705,16 @@ function printVersion()
|
||||
stream.print("<No version info available>");
|
||||
}
|
||||
|
||||
function exceptionReason(exception)
|
||||
{
|
||||
if (typeof(exception) === "string")
|
||||
return exception;
|
||||
else if (exception.isa && [exception respondsToSelector:@selector(reason)])
|
||||
return [exception reason];
|
||||
else
|
||||
return "An unknown error occurred";
|
||||
}
|
||||
|
||||
function fail(message)
|
||||
{
|
||||
[CPException raise:ConverterConversionException reason:message];
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
.Dd April 3, 2011
|
||||
.Os "Cappuccino"
|
||||
.Dt NIB2CIB 1 "PRM"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh NAME
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Nm nib2cib
|
||||
.Nd convert Interface Builder files to Cappuccino cib files
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh SYNOPSIS
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Nm
|
||||
--watch
|
||||
.Op options
|
||||
.Op Pa directory
|
||||
.Nm
|
||||
.Op options
|
||||
.Op Pa input Op Pa output
|
||||
.Nm
|
||||
.Op --version | -h | --help
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh "DESCRIPTION"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Nm
|
||||
converts an Interface Builder file into a Cappuccino cib file that can be loaded
|
||||
into a Cappuccino application.
|
||||
.Pp
|
||||
There are two main converting modes in which nib2cib can be used:
|
||||
.Sy watch mode
|
||||
and
|
||||
.Sy single mode.
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Ss "Watch Mode"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
The easiest way to use nib2cib is in
|
||||
.Sy watch mode.
|
||||
This is done by using the syntax:
|
||||
.Pp
|
||||
.D1 nib2cib --watch [options] Op Pa directory
|
||||
.Pp
|
||||
If
|
||||
.Ar directory
|
||||
is omitted, a "Resources" directory in the current working directory is watched,
|
||||
and if no "Resources" directory exists, the current working directory is watched.
|
||||
.Pp
|
||||
If
|
||||
.Ar directory
|
||||
is passed, is not a path to a "Resources" directory, and there is a "Resources" directory
|
||||
within
|
||||
.Ar directory ,
|
||||
then that "Resources" directory is watched. Otherwise
|
||||
.Ar directory
|
||||
is watched. This allows you to pass the path to your application directory instead
|
||||
of its "Resources" directory.
|
||||
.Pp
|
||||
In watch mode,
|
||||
.Nm
|
||||
goes into an infinite loop and monitors the watched directory for changes to xib/nib
|
||||
files. There are three types of changes
|
||||
.Nm
|
||||
will respond to:
|
||||
.Bl -tag -hang
|
||||
.It add, modify
|
||||
When a new xib/nib file is detected or an existing xib/nib file is modified, it is converted into
|
||||
a cib file with the same base name if there is no corresponding cib file with a later
|
||||
modification time.
|
||||
.It delete
|
||||
When a xib/nib file is deleted, the corresponding cib file is deleted as well.
|
||||
.El
|
||||
.Pp
|
||||
Ordinarily in watch mode
|
||||
.Nm
|
||||
will only display a log line for each file that is added, modified or deleted, and a confirmation
|
||||
when the corresponding cib has been generated or deleted. You can use the
|
||||
.Fl v
|
||||
option in watch mode to display more detailed information when a cib is generated.
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Ss "Single Mode"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
In
|
||||
.Sy single mode,
|
||||
you convert a single file xib/nib file into a cib. The only advantages of using single mode over
|
||||
watch mode are:
|
||||
.Bl -dash -width 0n
|
||||
.It
|
||||
You may want to view verbose output temporarily to debug the conversion, or use different
|
||||
options for different source files.
|
||||
.It
|
||||
You can specify an output name that is not based on the input name.
|
||||
.El
|
||||
.Pp
|
||||
Most of the time watch mode will be sufficient, but if you do need to use single mode,
|
||||
.Nm
|
||||
tries to make it as easy as possible. If you navigate to your application directory and invoke:
|
||||
.Pp
|
||||
.D1 nib2cib
|
||||
.Pp
|
||||
this will look for "MainMenu.xib" or "MainMenu.nib" in the current directory and then in a "Resources"
|
||||
directory within the current directory, if such a directory exists. Since these are
|
||||
the default names used in Cappuccino, this usage covers the default case with no extra work.
|
||||
.Pp
|
||||
If your xib/nib file is not named "MainMenu.xib" or "MainMenu.nib", or you want to run
|
||||
.Nm
|
||||
from a directory other than the application directory or its "Resources" directory,
|
||||
you can specify an input path:
|
||||
.Pp
|
||||
.D1 nib2cib Pa path
|
||||
.Pp
|
||||
Note that
|
||||
.Pa path
|
||||
does not need the ".xib" or ".nib" extension, since that is assumed. If you were to invoke:
|
||||
.Pp
|
||||
.D1 nib2cib foo
|
||||
.Pp
|
||||
this would look for "foo.xib" and "foo.nib" in the current directory and in a "Resources" directory
|
||||
within the current directory. The output of nib2cib in this case would be "foo.cib" in
|
||||
the same directory as the source file.
|
||||
.Pp
|
||||
If you want
|
||||
.Nm
|
||||
to generate a cib file with a different base name or in a different directory than
|
||||
the input file, you may also specify an output path:
|
||||
.Pp
|
||||
.D1 nib2cib Pa input Pa output
|
||||
.Pp
|
||||
As with input filenames, you do not need to add the ".cib" extension to the output path,
|
||||
this is assumed.
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Ss "Themes"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
To do its conversions accurately,
|
||||
.Nm
|
||||
needs to access the themes you use. If you are using the standard Aristo theme, there is
|
||||
nothing extra to do.
|
||||
.Pp
|
||||
If you are using a custom default theme, usually you specify this using a
|
||||
.Ar CPDefaultTheme
|
||||
item in your application's Info.plist. In this case
|
||||
.Nm
|
||||
will read the theme name from the Info.plist. If you set the default theme programmatically
|
||||
and not in the Info.plist, then you should use the
|
||||
.Fl \-default-theme
|
||||
option to specify the theme name.
|
||||
.Pp
|
||||
If you are loading additional themes in your code using:
|
||||
.Pp
|
||||
.D1 [[CPThemeBlend alloc] initWithContentsOfURL:]
|
||||
.Pp
|
||||
then you should inform
|
||||
.Nm
|
||||
about it by passing the theme names as
|
||||
.Fl \-theme Ar name
|
||||
options, one for each theme that you load.
|
||||
.Pp
|
||||
Themes are searched for in the Resources, $CAPP_BUILD/Debug and
|
||||
$CAPP_BUILD/Release directories.
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh "COMMON OPTIONS"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
The following options are available in watch mode or single mode:
|
||||
.Bl -tag -width 4n
|
||||
.It Fl v, \-verbose
|
||||
Displays more information about the internal workings of nib2cib. This can be set multiple
|
||||
times to increase the amount of information displayed. If passed once, general information
|
||||
is displayed. If passed more than once, detailed information about individual view conversions
|
||||
is displayed.
|
||||
.It Fl R Pa path
|
||||
NOTE: This option is for the most part no longer necessary.
|
||||
.Pp
|
||||
Specifies the path (relative or absolute) to a directory from which images
|
||||
and custom themes are retrieved. Formerly
|
||||
it was necessary to use this when your xib/nib contained references to images, but now
|
||||
.Nm
|
||||
infers the "Resources" directory from the input file, so usually you will not need to use
|
||||
this option.
|
||||
.It Fl \-default-theme Ar name
|
||||
Specifies the name of the default theme used by your application. This is only necessary
|
||||
if you are not using Aristo and you have not specified the default theme in your application's
|
||||
Info.plist. For more information see
|
||||
.Sy Themes
|
||||
above.
|
||||
.It Fl t, \-theme Ar name
|
||||
Specifies the name of an additional theme to load. May be used multiple times. For more
|
||||
information, see
|
||||
.Sy Themes
|
||||
above.
|
||||
.It Fl \-config Pa path
|
||||
Specifies the path to an Info.plist file from which to read configuration information about
|
||||
your application, such as the system font and default theme. Ordinarily you do not need to
|
||||
use this option, as
|
||||
.Nm
|
||||
uses the Info.plist in the application directory, which is inferred from
|
||||
the input file.
|
||||
.It Fl F
|
||||
Specify the path of a framework to load before converting. This is only useful if:
|
||||
.Bl -dash -width 0n -hang
|
||||
.It
|
||||
Your IB files use classes from the framework.
|
||||
.It
|
||||
Those classes need to serialize/deserialize more data than their superclasses.
|
||||
.It
|
||||
Those classes implement encodeWithCoder: and initWithCoder:.
|
||||
.El
|
||||
.Pp
|
||||
This option may be used multiple times to load multiple frameworks.
|
||||
.It Fl \-quiet
|
||||
Tells
|
||||
.Nm
|
||||
to output nothing. This is useful if you are using
|
||||
.Nm
|
||||
in a shell script and are only interested in the return value.
|
||||
.It Fl \-version
|
||||
Prints the current version of
|
||||
.Nm
|
||||
and immediately exits.
|
||||
.Nm
|
||||
in a shell script and are only interested in the return value.
|
||||
.It Fl h, \-help
|
||||
Displays
|
||||
.Nm
|
||||
usage and options.
|
||||
.El
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Sh "RETURN VALUES"
|
||||
.\"-----------------------------------------------------------------------------------------
|
||||
.Nm
|
||||
returns 0 for a successful conversion and >0 if an error occurred.
|
||||
+45
@@ -412,6 +412,51 @@ global.sudo = function(/*String*/ aTaskName)
|
||||
OS.exit(1); //rake abort if ($? != 0)
|
||||
}
|
||||
|
||||
global.copyManPage = function(/*String*/ name, /*int*/ section)
|
||||
{
|
||||
var manDir = "/usr/local/share/man/man" + section,
|
||||
pageFile = name + "." + section,
|
||||
manPagePath = FILE.join(manDir, pageFile);
|
||||
|
||||
if (!FILE.exists(manPagePath) || FILE.mtime(pageFile) > FILE.mtime(manPagePath))
|
||||
{
|
||||
var sudo = ["sudo", "-p", "\nEnter your admin password: "],
|
||||
useSudo = false,
|
||||
success = true,
|
||||
cmd;
|
||||
|
||||
if (!FILE.isDirectory(manDir))
|
||||
{
|
||||
cmd = ["mkdir", "-p", "-m", "0755", manDir];
|
||||
|
||||
if (FILE.isWritable(FILE.dirname(manDir)))
|
||||
success = OS.system(cmd) === 0;
|
||||
else
|
||||
{
|
||||
useSudo = true;
|
||||
success = OS.system(sudo.concat(cmd)) === 0;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
stream.print("\0red(Unable to create the man directory.\0)");
|
||||
OS.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
cmd = ["cp", "-f", pageFile, manDir];
|
||||
|
||||
if (FILE.isWritable(manDir))
|
||||
success = OS.system(cmd) === 0;
|
||||
else
|
||||
success = OS.system(sudo.concat(cmd)) === 0;
|
||||
|
||||
if (!success)
|
||||
stream.print("\0red(Unable to copy the man file.\0)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// built in tasks
|
||||
|
||||
task ("build");
|
||||
|
||||
Reference in New Issue
Block a user