From a9034de9cd3e376eda95da001532e52293cd83a0 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 2 Feb 2009 18:16:23 -0700 Subject: [PATCH 01/62] Fix for textfield placeholders being completely broken. --- AppKit/CPTextField.j | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index c61740720..17584e3af 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -389,17 +389,17 @@ var _CPTextFieldSquareBezelColor = nil, /* @ignore */ - (BOOL)acceptsFirstResponder { - return _isEditable; + return _isEditable && _isEnabled; } /* @ignore */ - (BOOL)becomeFirstResponder -{ +{ +#if PLATFORM(DOM) var string = [self stringValue]; [self setStringValue:""]; - -#if PLATFORM(DOM) + var element = [[self class] _inputElement]; element.value = string; @@ -479,7 +479,7 @@ var _CPTextFieldSquareBezelColor = nil, // If current value is the placeholder value, remove it to allow user to update. if ([string lowercaseString] == [[self placeholderString] lowercaseString]) - [self setStringValue:""]; + element.value = ""; //post CPControlTextDidBeginEditingNotification [self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]]; @@ -519,7 +519,7 @@ var _CPTextFieldSquareBezelColor = nil, { if (![self isEditable]) return [[self nextResponder] mouseDown:anEvent]; - + [super mouseDown:anEvent]; } /* @@ -683,7 +683,7 @@ var _CPTextFieldSquareBezelColor = nil, else displayString += aValue; } - + if ([[self window] firstResponder] == self) [[self class] _inputElement].value = displayString; @@ -712,7 +712,7 @@ var _CPTextFieldSquareBezelColor = nil, //if there is no set value, automatically display the placeholder if (!_value) - [self setStringValue:aStringValue]; + [self setStringValue:_placeholderString]; } /*! From 94c838dfde11d96db3287f0ce0a63ed94f0a0da7 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 2 Feb 2009 18:24:06 -0700 Subject: [PATCH 02/62] Various fixes. --- AppKit/CPMenuItem.j | 8 ++++++++ AppKit/CPPopUpButton.j | 9 +++++++++ Foundation/CPArray.j | 12 ++++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/AppKit/CPMenuItem.j b/AppKit/CPMenuItem.j index 217382ed6..77031d9ea 100644 --- a/AppKit/CPMenuItem.j +++ b/AppKit/CPMenuItem.j @@ -230,6 +230,14 @@ return _title; } +/*! + Set's the item's text color +*/ +- (void)setTextColor:(CPString)aColor +{ + //FIXME IMPLEMENT +} + /*! Sets the font for the text of this menu item @param aFont the font for the menu item diff --git a/AppKit/CPPopUpButton.j b/AppKit/CPPopUpButton.j index d36c8a68d..9e0131bf3 100644 --- a/AppKit/CPPopUpButton.j +++ b/AppKit/CPPopUpButton.j @@ -138,6 +138,15 @@ var CPPopUpButtonArrowsImage = nil; } // Inserting and Deleting Items + +/*! + Adds a new menu item using a CPMenuItem object. +*/ +- (void)addItem:(CPMenuItem)anItem +{ + [_menu addItem:anItem]; +} + /*! Adds a new menu item with the specified title. @param the new menu item's tite diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index cb4951ad6..98b5bcf05 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -51,7 +51,7 @@ if (++_index >= [_array count]) return nil; - return _array[_index]; + return [_array objectAtIndex:_index]; } @end @@ -81,7 +81,7 @@ if (--_index < 0) return nil; - return _array[_index]; + return [_array objectAtIndex:_index]; } @end @@ -735,6 +735,14 @@ return sorted; } +/*! + Return a copy of the receiver sorted using the function passed into the first parameter. +*/ +- (CPArray)sortedArrayUsingFunction:(Function)aFunction +{ + return [self sortedArrayUsingFunction:aFunction context:nil]; +} + /*! Returns an array in which the objects are ordered according to a sort with aFunction. This invokes From f671b89da558b89f68c938e65ddc3624f0d4172a Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 4 Feb 2009 08:11:46 -0700 Subject: [PATCH 03/62] Add "setCenter:" to CPView, which takes a point and moves the center of the view's frame to that point. --- AppKit/CPView.j | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 86257d3fc..20967cdbe 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -561,6 +561,18 @@ var DOMElementPrototype = nil, return _CGRectMakeCopy(_frame); } +/*! + Moves the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system. + The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver + is configured to do so. If the specified origin is the same as the frame's current origin, the method will + simply return (and no notification will be posted). + @param aPoint the new origin point +*/ +- (void)setCenter:(CGPoint)aPoint +{ + [self setFrameOrigin:CGPointMake(aPoint.x - _frame.size.width / 2.0, aPoint.y - _frame.size.height / 2.0)]; +} + /*! Sets the receiver's frame origin to the provided point. The point is defined in the superview's coordinate system. The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver From ecaab49c08d2a6738cf17fcece862bbcb62ad59d Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 4 Feb 2009 08:52:18 -0700 Subject: [PATCH 04/62] In addition to setting the center of a view's frame, now you can query it. --- AppKit/CPView.j | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 20967cdbe..504983e56 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -573,6 +573,15 @@ var DOMElementPrototype = nil, [self setFrameOrigin:CGPointMake(aPoint.x - _frame.size.width / 2.0, aPoint.y - _frame.size.height / 2.0)]; } +/*! + Returns the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system. + @return CGPoint the center point of the receiver's frame +*/ +- (void)center +{ + return CGPointMake(_frame.size.width / 2.0 + _frame.origin.x, _frame.size.height / 2.0 + _frame.origin.y); +} + /*! Sets the receiver's frame origin to the provided point. The point is defined in the superview's coordinate system. The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver From 0e965f73b75cb2ad549ff157a8c7fa9c7fe8c6af Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 4 Feb 2009 09:17:45 -0700 Subject: [PATCH 05/62] Return type was incorrect on "center" --- AppKit/CPView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 504983e56..31ce618aa 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -577,7 +577,7 @@ var DOMElementPrototype = nil, Returns the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system. @return CGPoint the center point of the receiver's frame */ -- (void)center +- (CGPoint)center { return CGPointMake(_frame.size.width / 2.0 + _frame.origin.x, _frame.size.height / 2.0 + _frame.origin.y); } From 40def352d95b6997d767b60eaccf6095d180eacc Mon Sep 17 00:00:00 2001 From: Marc Chung Date: Wed, 4 Feb 2009 11:23:10 -0700 Subject: [PATCH 06/62] Removing borking characters from CPURLResponse.j --- Foundation/CPURLResponse.j | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Foundation/CPURLResponse.j b/Foundation/CPURLResponse.j index 1287a0c15..15bf17f66 100644 --- a/Foundation/CPURLResponse.j +++ b/Foundation/CPURLResponse.j @@ -53,13 +53,13 @@ } /* Creating a Response -РinitWithURL:MIMEType:expectedContentLength:textEncodingName: +initWithURL:MIMEType:expectedContentLength:textEncodingName: Getting the Response Properties -РexpectedContentLength -РsuggestedFilename -РMIMEType -РtextEncodingName -РURL +expectedContentLength +suggestedFilename +MIMEType +textEncodingName +URL */ @end From 1758e18bd248cb07814bd4aabfbc0caa30fbffec Mon Sep 17 00:00:00 2001 From: nciagra Date: Fri, 30 Jan 2009 23:19:51 -0500 Subject: [PATCH 07/62] Added UUID generator method to CPString. --- Foundation/CPString.j | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Foundation/CPString.j b/Foundation/CPString.j index 6a83344a5..b91974d3c 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -662,4 +662,22 @@ var CPStringHashes = new objj_dictionary(); @end + +@implementation CPString (UUID) + +/*! + Returns a randomly generated Universally Unique Identifier. +*/ ++ (CPString)UUID +{ + var g = @""; + + for(var i = 0; i < 32; i++) + g += Math.floor(Math.random() * 0xF).toString(0xF); + + return g; +} + +@end + String.prototype.isa = CPString; From 471f6cb5e54b93869ff73fd992b884d22d1e8c57 Mon Sep 17 00:00:00 2001 From: nciagra Date: Fri, 30 Jan 2009 01:13:04 -0500 Subject: [PATCH 08/62] Added setTitle: accessors to CPAlert. --- AppKit/CPAlert.j | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 152fe19ef..9d7572f57 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -84,6 +84,7 @@ var CPAlertWarningImage, CPImageView _alertImageView; CPAlertStyle _alertStyle; + CPString _windowTitle; int _windowStyle; int _buttonCount; CPArray _buttons; @@ -163,6 +164,23 @@ var CPAlertWarningImage, [[_alertPanel contentView] addSubview:_alertImageView]; } +/*! + Sets the window's title. If this is not defined, a default title based on your warning level will be used. + @param aTitle the title to use in place of the default. Set to nil to use default. +*/ +- (void)setTitle:(CPString)aTitle +{ + _windowTitle = aTitle; +} + +/*! + Gets the window's title. +*/ +- (CPString)title +{ + return _windowTitle; +} + /*! Gets the window's style. */ @@ -252,19 +270,23 @@ var CPAlertWarningImage, */ - (void)runModal { + var theTitle; + switch (_alertStyle) { case CPWarningAlertStyle: [_alertImageView setImage:CPAlertWarningImage]; - [_alertPanel setTitle:@"Warning"]; + theTitle = @"Warning"; break; case CPInformationalAlertStyle: [_alertImageView setImage:CPAlertInformationImage]; - [_alertPanel setTitle:@"Information"]; + theTitle = @"Information"; break; case CPCriticalAlertStyle: [_alertImageView setImage:CPAlertErrorImage]; - [_alertPanel setTitle:@"Error"]; + theTitle = @"Error"; break; } - + + [_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle]; + [CPApp runModalForWindow:_alertPanel]; } From c29b5f2fef6c4b4b06c5c2984aa8926908091aee Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 4 Feb 2009 14:37:48 -0700 Subject: [PATCH 09/62] Use cached math library functions in UUID. --- Foundation/CPString.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPString.j b/Foundation/CPString.j index b91974d3c..96be2311f 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -673,7 +673,7 @@ var CPStringHashes = new objj_dictionary(); var g = @""; for(var i = 0; i < 32; i++) - g += Math.floor(Math.random() * 0xF).toString(0xF); + g += FLOOR(RAND() * 0xF).toString(0xF); return g; } From 3f410ea6888f980b6821ca754e96f7d9287c632f Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 4 Feb 2009 23:11:00 -0700 Subject: [PATCH 10/62] Add missing _delegate to CAAnimation.j --- AppKit/CoreAnimation/CAAnimation.j | 1 + 1 file changed, 1 insertion(+) diff --git a/AppKit/CoreAnimation/CAAnimation.j b/AppKit/CoreAnimation/CAAnimation.j index fbaca60fd..8303b7ef4 100644 --- a/AppKit/CoreAnimation/CAAnimation.j +++ b/AppKit/CoreAnimation/CAAnimation.j @@ -31,6 +31,7 @@ @implementation CAAnimation : CPObject { BOOL _isRemovedOnCompletion; + id _delegate; } /*! From 48fb8f00caf29d28aaf0bea5045a5e22f220faa6 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 9 Feb 2009 23:34:49 -0800 Subject: [PATCH 11/62] Add convenience methods for full screen. --- AppKit/CPView.j | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 31ce618aa..dd4b5c92d 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -874,6 +874,15 @@ var DOMElementPrototype = nil, } // Fullscreen Mode + +/*! + Puts the receiver into full screen mode. +*/ +- (BOOL)enterFullScreenMode +{ + return [self enterFullScreenMode:nil withOptions:nil]; +} + /*! Puts the receiver into full screen mode. @param aScreen the that should be used @@ -905,6 +914,14 @@ var DOMElementPrototype = nil, return YES; } +/*! + The receiver should exit full screen mode. +*/ +- (void)exitFullScreenMode +{ + [self exitFullScreenModeWithOptions:nil]; +} + /*! The receiver should exit full screen mode. @param options configurations options From a5f23035ae7f6374a13db4449b8d825a74e1d9a1 Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Sun, 15 Feb 2009 22:54:29 -0800 Subject: [PATCH 12/62] Added Frameworks to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 496ee2ca6..68dba5b20 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.DS_Store \ No newline at end of file +.DS_Store +Frameworks From 0bd543b57b2dcedcfcf9439d500729372827a08d Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 16 Feb 2009 22:59:44 -0800 Subject: [PATCH 13/62] Added support for autoresizing inner split view subviews. --- AppKit/CPSplitView.j | 55 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j index 703fa8c9c..2c3405b55 100644 --- a/AppKit/CPSplitView.j +++ b/AppKit/CPSplitView.j @@ -459,20 +459,51 @@ var CPSplitViewHorizontalImage = nil, var index = 0, count = [_subviews count], bounds = [self bounds], - dividerThickness = [self dividerThickness]; - - for (; index < count; ++index) + dividerThickness = [self dividerThickness], + totalDividers = count - 1, + totalSizableSpace = 0, + nonSizableSpace = 0, + lastSizableIndex = -1, + isVertical = [self isVertical]; + + for (index = 0; index < count; ++index) { var view = _subviews[index], - viewFrame = CGRectMakeCopy(bounds); - - if (index + 1 == count) - viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent]; - else - viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] * ([view frame].size[_sizeComponent] / oldSize[_sizeComponent]); - - bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness; - + isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable; + + if (isSizable) + { + totalSizableSpace += [view frame].size[_sizeComponent]; + lastSizableIndex = index; + } + } + + var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0, + ratio = (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace), + remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent]; + + for (index = 0; index < count; ++index) + { + var view = _subviews[index], + viewFrame = CGRectMakeCopy(bounds), + isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable; + + if (index + 1 == count) + viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent]; + else if (totalSizableSpace && isSizable && lastSizableIndex === index) + viewFrame.size[_sizeComponent] = MAX(0, ROUND([view frame].size[_sizeComponent] + remainingFlexibleSpace)) + else if (isSizable || !totalSizableSpace) + { + viewFrame.size[_sizeComponent] = MAX(0, ROUND(ratio * [view frame].size[_sizeComponent])); + remainingFlexibleSpace -= (viewFrame.size[_sizeComponent] - [view frame].size[_sizeComponent]); + } + else if (totalSizableSpace && !isSizable) + viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent]; + else + alert("SHOULD NEVER GET HERE"); + + bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness; + [view setFrame:viewFrame]; } From b7f2f315e28006504c1adb7729858b0a8b29ef98 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Tue, 17 Feb 2009 02:21:46 -0800 Subject: [PATCH 14/62] Bugfix for new splitview resze behavior. --- AppKit/CPSplitView.j | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j index 2c3405b55..38d001f14 100644 --- a/AppKit/CPSplitView.j +++ b/AppKit/CPSplitView.j @@ -464,6 +464,7 @@ var CPSplitViewHorizontalImage = nil, totalSizableSpace = 0, nonSizableSpace = 0, lastSizableIndex = -1, + totalSizablePanes = 0, isVertical = [self isVertical]; for (index = 0; index < count; ++index) @@ -475,9 +476,13 @@ var CPSplitViewHorizontalImage = nil, { totalSizableSpace += [view frame].size[_sizeComponent]; lastSizableIndex = index; + totalSizablePanes++; } } + if (totalSizablePanes === count) + totalSizableSpace = 0; + var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0, ratio = (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace), remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent]; From ac6260bf0d9731985fe619649a8657cca3cfd651 Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Thu, 19 Feb 2009 04:19:22 -0800 Subject: [PATCH 15/62] CPException CPCoding bug fixes --- Foundation/CPException.j | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Foundation/CPException.j b/Foundation/CPException.j index 861e4bf51..e6b615f4d 100755 --- a/Foundation/CPException.j +++ b/Foundation/CPException.j @@ -146,6 +146,10 @@ if (input == nil) @end +var CPExceptionNameKey = "CPExceptionNameKey", + CPExceptionReasonKey = "CPExceptionReasonKey", + CPExceptionUserInfoKey = "CPExceptionUserInfoKey"; + @implementation CPException (CPCoding) /*! @@ -161,7 +165,7 @@ if (input == nil) { name = [aCoder decodeObjectForKey:CPExceptionNameKey]; reason = [aCoder decodeObjectForKey:CPExceptionReasonKey]; - userInfo = [aCoer decodeObjectForKey:CPExceptionUserInfoKey]; + userInfo = [aCoder decodeObjectForKey:CPExceptionUserInfoKey]; } return self; From ec3dcaa2875eaf9e7def9076d110a5a357c0e185 Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Thu, 19 Feb 2009 04:32:15 -0800 Subject: [PATCH 16/62] Delete the stupid debug.txt file after building documentation. --- build.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.xml b/build.xml index eb3fa2de8..81f14bba4 100644 --- a/build.xml +++ b/build.xml @@ -125,6 +125,8 @@ + + From 1da9e93241740c1b4cfe3c0bfb30648db07cfa4f Mon Sep 17 00:00:00 2001 From: Landon Fuller Date: Thu, 19 Feb 2009 22:59:37 -0800 Subject: [PATCH 17/62] Implement support for UNIX epoch initialization. Add support for the +[CPDate dateWithTimeIntervalSince1970:] and -[CPDate initWithTimeIntervalSince1970]. --- Foundation/CPDate.j | 10 +++++++++- Tests/Foundation/CPDateTest.j | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index db83c63c4..d30084ce6 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -43,6 +43,9 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); { return [[CPDate alloc] initWithTimeIntervalSinceNow:seconds]; } ++ (id)dateWithTimeIntervalSince1970:(CPTimeInterval)seconds { + return [[CPDate alloc] initWithTimeIntervalSince1970:seconds]; +} + (id)dateWithTimeIntervalSinceReferenceDate:(CPTimeInterval)seconds { return [[CPDate alloc] initWithTimeIntervalSinceReferenceDate:seconds]; @@ -63,6 +66,11 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); self = new Date((new Date()).getTime() + seconds * 1000); return self; } +- (id)initWithTimeIntervalSince1970:(CPTimeInterval)seconds +{ + self = new Date(seconds * 1000); + return self; +} - (id)initWithTimeIntervalSinceReferenceDate:(CPTimeInterval)seconds { self = [self initWithTimeInterval:seconds sinceDate:CPDateReferenceDate]; @@ -129,4 +137,4 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); @end -Date.prototype.isa = CPDate; \ No newline at end of file +Date.prototype.isa = CPDate; diff --git a/Tests/Foundation/CPDateTest.j b/Tests/Foundation/CPDateTest.j index a94ec00c5..075f93ce7 100644 --- a/Tests/Foundation/CPDateTest.j +++ b/Tests/Foundation/CPDateTest.j @@ -2,6 +2,14 @@ import @implementation CPDateTest : OJTestCase +- (void)testSince1970 +{ + /* These two dates should be equal to Fri Feb 13 2009 15:31:30 GMT-0800 */ + unixDate = [CPDate dateWithTimeIntervalSince1970: 1234567890]; + cocoaDate = [CPDate dateWithTimeIntervalSinceReferenceDate: 253582290]; + [self assertTrue:[unixDate isEqualToDate: cocoaDate]]; +} + - (void)testDate { var before = new Date(); @@ -17,4 +25,4 @@ import [self assert:middle equals:[middle laterDate:past] message:"laterDate incorrect"]; } -@end \ No newline at end of file +@end From 8da7b0ee911c4f9b0aa5f8b1ae195f9734941aed Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Thu, 26 Feb 2009 17:21:40 -0800 Subject: [PATCH 18/62] Fix some spacing/style issues in CPDate. --- Foundation/CPDate.j | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index d30084ce6..cf893248e 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -39,13 +39,17 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); { return [[self alloc] init]; } + + (id)dateWithTimeIntervalSinceNow:(CPTimeInterval)seconds { return [[CPDate alloc] initWithTimeIntervalSinceNow:seconds]; } -+ (id)dateWithTimeIntervalSince1970:(CPTimeInterval)seconds { + ++ (id)dateWithTimeIntervalSince1970:(CPTimeInterval)seconds +{ return [[CPDate alloc] initWithTimeIntervalSince1970:seconds]; } + + (id)dateWithTimeIntervalSinceReferenceDate:(CPTimeInterval)seconds { return [[CPDate alloc] initWithTimeIntervalSinceReferenceDate:seconds]; @@ -66,28 +70,31 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); self = new Date((new Date()).getTime() + seconds * 1000); return self; } + - (id)initWithTimeIntervalSince1970:(CPTimeInterval)seconds { self = new Date(seconds * 1000); return self; } + - (id)initWithTimeIntervalSinceReferenceDate:(CPTimeInterval)seconds { self = [self initWithTimeInterval:seconds sinceDate:CPDateReferenceDate]; return self; } + - (id)initWithTimeInterval:(CPTimeInterval)seconds sinceDate:(CPDate)refDate { self = new Date(refDate.getTime() + seconds * 1000); return self; } + - (id)initWithString:(CPString)description { self = new Date(description); // FIXME: not same format as NSString return self; } - - (CPTimeInterval)timeIntervalSinceDate:(CPDate)anotherDate { return (self.getTime() - anotherDate.getTime()) / 1000.0; @@ -97,14 +104,17 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); { return [self timeIntervalSinceDate:[CPDate date]]; } + - (CPTimeInterval)timeIntervalSince1970 { return self.getTime() / 1000.0; } + - (CPTimeInterval)timeIntervalSinceReferenceDate { return (self.getTime() - CPDateReferenceDate.getTime()) / 1000.0; } + + (CPTimeInterval)timeIntervalSinceReferenceDate { return [[CPDate date] timeIntervalSinceReferenceDate]; From 547ed38855691a472783320c6eded20bd8d6a6d5 Mon Sep 17 00:00:00 2001 From: Leif Singer Date: Sun, 8 Feb 2009 17:16:22 +0100 Subject: [PATCH 19/62] Modified CPColor's hexToRGB to also accept hex colors with only three characters, as is possible in CSS. E.g., 'ccc' will expand to 'cccccc', etc. --- AppKit/CPColor.j | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AppKit/CPColor.j b/AppKit/CPColor.j index 97cb4364b..0fde08dd2 100644 --- a/AppKit/CPColor.j +++ b/AppKit/CPColor.j @@ -523,6 +523,8 @@ var hexCharacters = "0123456789ABCDEF"; */ function hexToRGB(hex) { + if ( hex.length == 3 ) + hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2); if(hex.length != 6) return null; From 1d38ca64c75cbd58297a28ac4c9381fdbe27f2ff Mon Sep 17 00:00:00 2001 From: Thomas Balthazar Date: Fri, 13 Feb 2009 18:03:29 +0100 Subject: [PATCH 20/62] ticket 220 fixed http://cappuccino.lighthouseapp.com:80/projects/16499/tickets/220-typo-in-cppopupbutton-indexofitemwithrepresentedobject#ticket-220-1 --- AppKit/CPPopUpButton.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPPopUpButton.j b/AppKit/CPPopUpButton.j index 9e0131bf3..9f6d1092a 100644 --- a/AppKit/CPPopUpButton.j +++ b/AppKit/CPPopUpButton.j @@ -476,7 +476,7 @@ var CPPopUpButtonArrowsImage = nil; */ - (int)indexOfItemWithRepresentedObject:(id)anObject { - return [_menu indexOfItemWithRepresentedObejct:anObject]; + return [_menu indexOfItemWithRepresentedObject:anObject]; } /*! From 723c9ae55677b85683f626412730f1de3c4e33d9 Mon Sep 17 00:00:00 2001 From: Russell Mull Date: Sun, 14 Sep 2008 10:57:35 -0700 Subject: [PATCH 21/62] improved CPStringTest --- Tests/Foundation/CPStringTest.j | 108 ++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 5 deletions(-) diff --git a/Tests/Foundation/CPStringTest.j b/Tests/Foundation/CPStringTest.j index f509e8128..61aa61a50 100644 --- a/Tests/Foundation/CPStringTest.j +++ b/Tests/Foundation/CPStringTest.j @@ -16,14 +16,112 @@ import } - (void)testStringByAppendingFormat { - var format = @"%d X %d = %d"; - var expectedString = "2 X 3 = 6"; - var dummyString = @""; - var actualString = [dummyString stringByAppendingFormat:format ,2 ,3 ,6]; + var format = @"%d X %d = %d", + expectedString = "2 X 3 = 6", + dummyString = @"", + actualString = [dummyString stringByAppendingFormat:format, 2, 3, 6]; + [self assertTrue:(expectedString === actualString) message:"stringByAppendingFormat: expected:" + expectedString + " actual:" + actualString]; - } + +- (void)testStringWithString +{ + var original = [[CPString alloc] initWithString:"str"], + copy = [CPString stringWithString:original]; + + [self assertTrue:(original == copy) message:"Contents should be equal"]; +} + +- (void)testInitWithString +{ + var str = [[CPString alloc] initWithString:"str"]; + [self assert:"str" equals:str]; +} + +- (void) testInitWithFormat +{ + // this could be really big + var str = [[CPString alloc] initWithFormat:"%s", "str"]; + [self assert:"str" equals:str]; + + str = [[CPString alloc] initWithFormat:"%d", 42]; + [self assert:"42" equals:str]; + + str = [[CPString alloc] initWithFormat:"%f", 42.2]; + [self assert:"42.2" equals:str]; +} + +- (void)testStringWithFormat +{ + // this could be equally big + var str = [CPString stringWithFormat:"%s", "str"]; + [self assert:"str" equals:str]; + + str = [CPString stringWithFormat:"%d", 42]; + [self assert:"42" equals:str]; + + str = [CPString stringWithFormat:"%f", 42.2]; + [self assert:"42.2" equals:str]; +} + +- (void)testLength +{ + [self assert:0 equals:["" length]]; + [self assert:1 equals:["a" length]]; + [self assert:5 equals:["abcde" length]]; + [self assert:3 equals:["日本語" length]]; +} + +- (void)testCharacterAtIndex +{ + [self assert:"a" equals:["abcd" characterAtIndex:0]]; + [self assert:"b" equals:["abcd" characterAtIndex:1]]; + [self assert:"d" equals:["abcd" characterAtIndex:3]]; + [self assert:"語" equals:["日本語" characterAtIndex:2]]; +} + +- (void)testStringByAppendingSting +{ + [self assert:"onetwo" equals:["one" stringByAppendingString:"two"]]; +} + + +- (void)testStringByPaddingToLength +{ + [self assert:"onebcd" + equals:["one" stringByPaddingToLength:6 + withString:"abcdefg" + startingAtIndex:1]]; +} + +- (void)testComponentsSeparatedByString +{ + [self assert:["arash", "francisco", "ross", "tom"] + equals:["arash.francisco.ross.tom" componentsSeparatedByString:"."]]; +} + +- (void)testSubstringFromIndex +{ + [self assert:"abcd" equals:["abcd" substringFromIndex:0]]; + [self assert:"bcd" equals:["abcd" substringFromIndex:1]]; + [self assert:"" equals:["abcd" substringFromIndex:4]]; +} + +- (void)testSubstringWithRange +{ + [self assert:"bcd" equals:["abcde" substringWithRange:CPMakeRange(1,3)]]; + [self assert:"abcde" equals:["abcde" substringWithRange:CPMakeRange(0,5)]]; + [self assert:"" equals:["abcde" substringWithRange:CPMakeRange(1,0)]]; +} + +- (void)testSubstringToIndex +{ + [self assert:"abcd" equals:["abcd" substringToIndex:4]]; + [self assert:"abc" equals:["abcd" substringToIndex:3]]; + [self assert:"" equals:["abcd" substringToIndex:0]]; +} + - (void)testBoolValue { var testStrings = [ From 6750b906717c7efb067cea71824483c92ae149d0 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Thu, 26 Feb 2009 21:30:54 -0800 Subject: [PATCH 22/62] Fixes for some new CPString tests. --- Foundation/CPString.j | 11 +++++++---- Tests/Foundation/CPStringTest.j | 27 ++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Foundation/CPString.j b/Foundation/CPString.j index 96be2311f..cf2953388 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -91,7 +91,7 @@ var CPStringHashes = new objj_dictionary(); */ + (id)stringWithHash:(unsigned)aHash { - var hashString = String(aHash); + var hashString = parseInt(aHash, 10).toString(16); return "000000".substring(0, MAX(6-hashString.length, 0)) + hashString; } @@ -222,13 +222,16 @@ var CPStringHashes = new objj_dictionary(); return substr(0, aLength); var string = self, - substring = aString.substr(anIndex), + substring = aString.substring(anIndex), difference = aLength - length; - while ((difference -= substring.length) > 0) + while ((difference -= substring.length) >= 0) string += substring; - if (difference) string += substring.substr(difference + substring.length); + if (-difference < substring.length) + string += substring.substring(0, -difference); + + return string; } //Dividing Strings diff --git a/Tests/Foundation/CPStringTest.j b/Tests/Foundation/CPStringTest.j index 61aa61a50..a7d8f0e8d 100644 --- a/Tests/Foundation/CPStringTest.j +++ b/Tests/Foundation/CPStringTest.j @@ -90,9 +90,9 @@ import - (void)testStringByPaddingToLength { [self assert:"onebcd" - equals:["one" stringByPaddingToLength:6 - withString:"abcdefg" - startingAtIndex:1]]; + equals:["one" stringByPaddingToLength:6 + withString:"abcdefg" + startingAtIndex:1]]; } - (void)testComponentsSeparatedByString @@ -157,6 +157,27 @@ import [self assert:[testStrings[i][0] capitalizedString] equals:testStrings[i][1]]; } +- (void)testUppercaseString +{ + var str = "This is a test"; + [self assert:[str uppercaseString] equals:"THIS IS A TEST"]; +} + +- (void)testLowercaseString +{ + var str = "This Is A TEST"; + [self assert:"this is a test" equals:[str lowercaseString]]; +} + +- (void)testStringWithHash +{ + [self assert:"000000" equals:[CPString stringWithHash:0]]; + [self assert:"000001" equals:[CPString stringWithHash:1]]; + [self assert:"00000a" equals:[CPString stringWithHash:10]]; + [self assert:"000010" equals:[CPString stringWithHash:16]]; + [self assert:"ffffff" equals:[CPString stringWithHash:16777215]]; +} + - (void)testStringByDeletingLastPathComponent { var testStrings = [ From d81c944e457c4710b08544fe6b720e5fcc4c6262 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 2 Mar 2009 15:59:58 -0800 Subject: [PATCH 23/62] minor fix to the objective-j mode. --- Tools/SubEthaEdit/Objective-J.mode.zip | Bin 78342 -> 78383 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Tools/SubEthaEdit/Objective-J.mode.zip b/Tools/SubEthaEdit/Objective-J.mode.zip index 95f9b988fec9225db7533c6bf94e27d783e7cdb4..83fa37b092c3fc13f8679b37a3f2d97bd334ca7d 100644 GIT binary patch delta 22626 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

|r0 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 Y$Dqy-<0k?E-1j*x2;>37skMUs2Xd!a*Z=?k delta 22550 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 Date: Sun, 1 Mar 2009 12:40:48 +0000 Subject: [PATCH 24/62] Added @mainpage for doxygen that simply includes the README and LiCENSE docs. Also added groups for appkit and foundation classes. --- Foundation/Foundation.j | 16 ++++++++++++++++ Tools/Documentation/Cappuccino.doxygen | 3 ++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j index 0fbdad3c3..8fbec7323 100755 --- a/Foundation/Foundation.j +++ b/Foundation/Foundation.j @@ -55,3 +55,19 @@ @import "CPURLResponse.j" @import "CPUserSessionManager.j" @import "CPValue.j" + +/*! @defgroup appkit AppKit + @defgroup foundation Foundation + + @mainpage + Cappuccino is distributed under the @ref license "GNU LGPL". + + @htmlonly

@endhtmlonly
+    @htmlinclude README
+    @htmlonly 
@endhtmlonly + + @page license License + @htmlonly
@endhtmlonly
+    @htmlinclude LICENSE
+    @htmlonly 
@endhtmlonly +*/ diff --git a/Tools/Documentation/Cappuccino.doxygen b/Tools/Documentation/Cappuccino.doxygen index d083ca453..91129133f 100644 --- a/Tools/Documentation/Cappuccino.doxygen +++ b/Tools/Documentation/Cappuccino.doxygen @@ -137,7 +137,8 @@ EXCLUDE = AppKit/Cib \ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = _* EXCLUDE_SYMBOLS = _* -EXAMPLE_PATH = +EXAMPLE_PATH = ./README \ + ./LICENSE EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = From 0508c5479934908b1ce0562d71f1e6861816e922 Mon Sep 17 00:00:00 2001 From: stephen Date: Sun, 1 Mar 2009 14:11:47 +0000 Subject: [PATCH 25/62] Defgroups must go at end of comment otherwise previous obj-j statements become part of the group name. --- Foundation/Foundation.j | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j index 8fbec7323..cf2719ef9 100755 --- a/Foundation/Foundation.j +++ b/Foundation/Foundation.j @@ -56,10 +56,7 @@ @import "CPUserSessionManager.j" @import "CPValue.j" -/*! @defgroup appkit AppKit - @defgroup foundation Foundation - - @mainpage +/*! @mainpage Cappuccino is distributed under the @ref license "GNU LGPL". @htmlonly
@endhtmlonly
@@ -70,4 +67,7 @@
     @htmlonly 
@endhtmlonly
     @htmlinclude LICENSE
     @htmlonly 
@endhtmlonly + + @defgroup appkit AppKit + @defgroup foundation Foundation */ From 46a975b9660707205ee55bf3f08967f87a29d0e9 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Thu, 5 Mar 2009 14:30:38 -0800 Subject: [PATCH 26/62] Updated CPObject's instancesRespondToSelector to return BOOL --- Foundation/CPArray.j | 2 +- Foundation/CPObject.j | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 98b5bcf05..fa8e3e73e 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -674,7 +674,7 @@ */ - (CPArray)arrayByAddingObject:(id)anObject { - if (!anObject) + if (anObject === nil || anObject === undefined) [CPException raise:CPInvalidArgumentException reason:"arrayByAddingObject: object can't be nil"]; diff --git a/Foundation/CPObject.j b/Foundation/CPObject.j index 224439bd6..eeb8406be 100644 --- a/Foundation/CPObject.j +++ b/Foundation/CPObject.j @@ -177,7 +177,7 @@ */ + (BOOL)instancesRespondToSelector:(SEL)aSelector { - return class_getInstanceMethod(self, aSelector); + return !!class_getInstanceMethod(self, aSelector); } /*! @@ -187,7 +187,7 @@ */ - (BOOL)respondsToSelector:(SEL)aSelector { - return class_getInstanceMethod(isa, aSelector) != NULL; + return !!class_getInstanceMethod(isa, aSelector); } // Obtaining method information From a1e3feda4ffd53d2ea436b4611bdfa308e25b601 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Sat, 7 Feb 2009 15:28:28 +0100 Subject: [PATCH 27/62] Fixed typo --- AppKit/CoreAnimation/CAMediaTimingFunction.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CoreAnimation/CAMediaTimingFunction.j b/AppKit/CoreAnimation/CAMediaTimingFunction.j index 9a6091da1..c75df75cf 100644 --- a/AppKit/CoreAnimation/CAMediaTimingFunction.j +++ b/AppKit/CoreAnimation/CAMediaTimingFunction.j @@ -95,7 +95,7 @@ var CAMediaNamedTimingFunctions = nil; else { reference[0] = 1.0; - reference[0] = 1.0; + reference[1] = 1.0; } } From 55fa6024dbade24c5263ded5aa61d471c22b825a Mon Sep 17 00:00:00 2001 From: M ESCO Date: Sat, 7 Feb 2009 14:26:37 +0100 Subject: [PATCH 28/62] Added tooltip support --- AppKit/CPControl.j | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 23fbf5b1e..3edb5a8bb 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -100,6 +100,8 @@ var CPControlBlackColor = [CPColor blackColor]; CPCellImagePosition _imagePosition; CPImageScaling _imageScaling; + CPString _toolTip; + // Target-Action Support id _target; SEL _action; @@ -314,6 +316,30 @@ var CPControlBlackColor = [CPColor blackColor]; return _textShadow; } +/*! + Sets the tooltip for the receiver. + @param aToolTip the tooltip +*/ +-(void)setToolTip:(CPString)aToolTip +{ + if (_toolTip == aToolTip) + return; + + _toolTip = aToolTip; + +#if PLATFORM(DOM) + _DOMElement.title = [aToolTip cssString]; +#endif +} + +/*! + Returns the receiver's tooltip +*/ +-(CPString)toolTip +{ + return _toolTip; +} + /*! Returns the receiver's target action */ From 0fdfd8919f492e6e4f9d3da8df5a973d49fed774 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Thu, 5 Mar 2009 14:45:34 -0800 Subject: [PATCH 29/62] Remove the tabs. --- AppKit/CPControl.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 3edb5a8bb..adbc5c5d2 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -100,7 +100,7 @@ var CPControlBlackColor = [CPColor blackColor]; CPCellImagePosition _imagePosition; CPImageScaling _imageScaling; - CPString _toolTip; + CPString _toolTip; // Target-Action Support id _target; @@ -337,7 +337,7 @@ var CPControlBlackColor = [CPColor blackColor]; */ -(CPString)toolTip { - return _toolTip; + return _toolTip; } /*! From faac82287f43c57775b859f1e180e8b31e71aa88 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Sat, 7 Feb 2009 17:12:44 +0100 Subject: [PATCH 30/62] Fixed bug in previous commit of setToolTip: --- AppKit/CPControl.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index adbc5c5d2..e08fbed6b 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -328,7 +328,7 @@ var CPControlBlackColor = [CPColor blackColor]; _toolTip = aToolTip; #if PLATFORM(DOM) - _DOMElement.title = [aToolTip cssString]; + _DOMElement.title = aToolTip; #endif } From 546c95bdf645abee13863f637a3e8583dee631df Mon Sep 17 00:00:00 2001 From: cacaodev Date: Sat, 7 Feb 2009 16:46:52 +0100 Subject: [PATCH 31/62] Fixed typos in CPArray+KVO ; added suport for *objects:atIndexes: --- Foundation/CPArray+KVO.j | 59 +++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/Foundation/CPArray+KVO.j b/Foundation/CPArray+KVO.j index 37772dd13..64ccd2a8f 100644 --- a/Foundation/CPArray+KVO.j +++ b/Foundation/CPArray+KVO.j @@ -57,7 +57,16 @@ SEL _replaceSEL; Function _replace; + + SEL _insertManySEL; + Function _insertMany; + SEL _removeManySEL; + Function _removeMany; + + SEL _replaceManySEL; + Function _replaceMany; + SEL _objectAtIndexSEL; Function _objectAtIndex; @@ -95,32 +104,44 @@ var capitalizedKey = _key.charAt(0).toUpperCase() + _key.substring(1); _insertSEL = sel_getName(@"insertObject:in"+capitalizedKey+"AtIndex:"); - if ([_proxyObject respondsToSelector:selector]) - _insert = [_proxyObject methodForSelector:selector]; + if ([_proxyObject respondsToSelector:_insertSEL]) + _insert = [_proxyObject methodForSelector:_insertSEL]; _removeSEL = sel_getName(@"removeObjectFrom"+capitalizedKey+"AtIndex:"); - if ([_proxyObject respondsToSelector:selector]) - _remove = [_proxyObject methodForSelector:selector]; + if ([_proxyObject respondsToSelector:_removeSEL]) + _remove = [_proxyObject methodForSelector:_removeSEL]; _replaceSEL = sel_getName(@"replaceObjectFrom"+capitalizedKey+"AtIndex:withObject:"); - if ([_proxyObject respondsToSelector:selector]) - _replace = [_proxyObject methodForSelector:selector]; + if ([_proxyObject respondsToSelector:_replaceSEL]) + _replace = [_proxyObject methodForSelector:_replaceSEL]; + + _insertManySEL = sel_getName(@"insertObjects:in"+capitalizedKey+"AtIndexes:"); + if ([_proxyObject respondsToSelector:_insertManySEL]) + _insert = [_proxyObject methodForSelector:_insertManySEL]; + + _removeManySEL = sel_getName(@"removeObjectsFrom"+capitalizedKey+"AtIndexes:"); + if ([_proxyObject respondsToSelector:_removeManySEL]) + _remove = [_proxyObject methodForSelector:_removeManySEL]; + + _replaceManySEL = sel_getName(@"replaceObjectsFrom"+capitalizedKey+"AtIndexes:withObjects:"); + if ([_proxyObject respondsToSelector:_replaceManySEL]) + _replace = [_proxyObject methodForSelector:_replaceManySEL]; _objectAtIndexSEL = sel_getName(@"objectIn"+capitalizedKey+"AtIndex:"); - if ([_proxyObject respondsToSelector:selector]) - _objectAtIndex = [_proxyObject methodForSelector:selector]; + if ([_proxyObject respondsToSelector:_objectAtIndexSEL]) + _objectAtIndex = [_proxyObject methodForSelector:_objectAtIndexSEL]; _countSEL = sel_getName(@"countOf"+capitalizedKey); - if ([_proxyObject respondsToSelector:selector]) - _count = [_proxyObject methodForSelector:selector]; + if ([_proxyObject respondsToSelector:_countSEL]) + _count = [_proxyObject methodForSelector:_countSEL]; _accessSEL = sel_getName(_key); - if ([_proxyObject respondsToSelector:selector]) - _access = [_proxyObject methodForSelector:selector]; + if ([_proxyObject respondsToSelector:_accessSEL]) + _access = [_proxyObject methodForSelector:_accessSEL]; _setSEL = sel_getName(@"set"+capitalizedKey+":"); - if ([_proxyObject respondsToSelector:selector]) - _set = [_proxyObject methodForSelector:selector]; + if ([_proxyObject respondsToSelector:_setSEL]) + _set = [_proxyObject methodForSelector:_setSEL]; return self; } @@ -176,7 +197,7 @@ var target = [[self _representedObject] copy]; [target addObject:anObject]; - [_self _setRepresentedObject:target]; + [self _setRepresentedObject:target]; } - (void)insertObject:(id)anObject atIndex:(unsigned)anIndex @@ -187,7 +208,7 @@ var target = [[self _representedObject] copy]; [target insertObject:anObject atIndex:anIndex]; - [_self _setRepresentedObject:target]; + [self _setRepresentedObject:target]; } - (void)removeLastObject @@ -198,7 +219,7 @@ var target = [[self _representedObject] copy]; [target removeLastObject]; - [_self _setRepresentedObject:target]; + [self _setRepresentedObject:target]; } - (void)removeObjectAtIndex:(unsigned)anIndex @@ -209,7 +230,7 @@ var target = [[self _representedObject] copy]; [target removeObjectAtIndex:anIndex]; - [_self _setRepresentedObject:target]; + [self _setRepresentedObject:target]; } - (void)replaceObjectAtIndex:(unsigned)anIndex withObject:(id)anObject @@ -220,7 +241,7 @@ var target = [[self _representedObject] copy]; [target replaceObjectAtIndex:anIndex withObject:anObject]; - [_self _setRepresentedObject:target]; + [self _setRepresentedObject:target]; } - (CPArray)objectsAtIndexes:(CPIndexSet)indexes From bbe1b58437eab5519f95498f59ecb7c931296644 Mon Sep 17 00:00:00 2001 From: Vladimir Pouzanov Date: Thu, 5 Mar 2009 21:38:17 +0200 Subject: [PATCH 32/62] Added more api docs to CPObject --- Foundation/CPObject.j | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/Foundation/CPObject.j b/Foundation/CPObject.j index eeb8406be..90f59227d 100644 --- a/Foundation/CPObject.j +++ b/Foundation/CPObject.j @@ -23,8 +23,41 @@ /*! @class CPObject - CPObject is the root class for most Cappuccino classes. Your custom classes - should almost always subclass CPObject or one of its children. + CPObject is the root class for most Cappuccino classes. Like in Objective-C, + you have to declare parent class explicitly in Objective-J, so your custom + classes should almost always subclass CPObject or one of its children. + + CPObject provides facilities for class allocation and initialization, + querying runtime about parent classes and available selectors, using KVC + (key-value coding). + + When you subclass CPObject, most of the time you override one selector - init. + It is called for default initialization of custom object. You must call + parent class init in your overriden code: +
- (id)init
+{
+    self = [super init];
+    if(self) {
+        ... provide default initialization code for your object ...
+    }
+    return self;
+}
+ + One more useful thing to override is description(). This selector + is used to provide developer-readable information about object. description + selector is often used with CPLog debugging: +
- (CPString)description
+{
+    return [CPString stringWithFormat:@"", someValue];
+}
+ To get description value you can use %@ specifier everywhere where format + specifiers are allowed: +
var inst = [[SomeClass alloc] initWithSomeValue:10];
+CPLog(@"Got some class: %@", inst);
+ would output: +
Got some class: 
+ + @todo document KVC usage. */ @implementation CPObject { From 4422530fe447963893681a29041a435cc80b02fc Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Sat, 7 Mar 2009 19:34:24 -0800 Subject: [PATCH 33/62] Fixed press bug (hasOwnProperty to lookup dependencies) and cleaned up output --- Tools/press/objj-analysis-tools.j | 4 +-- Tools/press/press.j | 45 +++++++++++++++++++------------ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/Tools/press/objj-analysis-tools.j b/Tools/press/objj-analysis-tools.j index 628c6c78a..c225998fc 100644 --- a/Tools/press/objj-analysis-tools.j +++ b/Tools/press/objj-analysis-tools.j @@ -85,7 +85,7 @@ function traverseDependencies(context, file) { if (context.dependencies[token]) { - var files = context.dependencies[token] + var files = context.dependencies[token]; for (var j = 0; j < files.length; j++) { // don't record references to self @@ -232,7 +232,7 @@ function findGlobalDefines(context, scope, rootPath, evaledFragments) if (evaledFragments) { - evaledFragments.push(aFragment); + evaledFragments.push(aFragment); } var result = fragment_evaluate_code_original(aFragment); diff --git a/Tools/press/press.j b/Tools/press/press.j index b3aa7aba9..ed96f4536 100644 --- a/Tools/press/press.j +++ b/Tools/press/press.j @@ -11,7 +11,8 @@ var usageMessage = --frameworks path The relative path (from root_directory) to the frameworks directory (default: 'Frameworks')\n\ --png Run pngcrush on all PNGs (pngcrush must be installed!)\n\ --flatten Flatten all code into a single Application.js file and attempt add script tag to index.html (useful for Adobe AIR and CDN deployment)\n\ - --nostrip Don't strip any files"; + --nostrip Don't strip any files\n\ + --v Verbose"; function main() { @@ -22,7 +23,7 @@ function main() optimizePNG = false, flatten = false, noStrip = false, - verbose = true; + verbose = false; var usageError = false; while (args.length && !usageError) @@ -51,6 +52,9 @@ function main() case "--nostrip": noStrip = true; break; + case "--v": + verbose = true; + break; default: if (rootDirectory == null) rootDirectory = arg.replace(/\/$/, ""); @@ -125,6 +129,11 @@ function main() // coalesce the results var dependencies = coalesceGlobalDefines(globals); + // Log + CPLog.trace("Global defines:"); + for (var i in dependencies) + CPLog.trace(" " + i + " => " + dependencies[i]); + // phase 2: walk the dependency tree (both imports and references) to determine exactly which files need to be included CPLog.error("PHASE 2: Walk dependency tree..."); @@ -143,7 +152,7 @@ function main() return; } - CPLog.info("Analyzing dependencies..."); + CPLog.warn("Analyzing dependencies..."); var context = { scope : scope, @@ -172,21 +181,21 @@ function main() } else { - CPLog.warn("Excluded: " + path); + CPLog.info("Excluded: " + path); } total++; } - CPLog.info("Total required files: " + count + " out of " + total); + CPLog.warn("Total required files: " + count + " out of " + total); // FIXME: sprite images - for (var i in context.bundleImages) - { - var images = context.bundleImages[i]; - - //CPLog.info("Bundle images for " + i); - //for (var j in images) - // CPLog.debug(j + " = " + images[j]); - } + //for (var i in context.bundleImages) + //{ + // var images = context.bundleImages[i]; + // + // CPLog.debug("Bundle images for " + i); + // for (var j in images) + // CPLog.trace(j + " = " + images[j]); + //} } var outputFiles = {}; @@ -236,7 +245,7 @@ function main() } else { - CPLog.warn("Stripping " + evaledFragments[i].file.path); + CPLog.info("Stripping " + evaledFragments[i].file.path); } } @@ -272,7 +281,7 @@ function main() directory = dirname(path); if (file.path != path) - CPLog.warn("Sanity check (file path): " + file.path + " vs. " + path); + CPLog.warn("Sanity check failed (file path): " + file.path + " vs. " + path); if (file.bundle) { @@ -282,7 +291,7 @@ function main() bundles[file.bundle.path] = file.bundle; if (bundleDirectory != directory) - CPLog.warn("Sanity check (directory path): " + directory + " vs. " + bundleDirectory); + CPLog.warn("Sanity check failed (directory path): " + directory + " vs. " + bundleDirectory); // if it's in a .sj var dict = file.bundle.info, @@ -337,7 +346,7 @@ function main() } } else - CPLog.warn("Ignoring import fragment " + file.fragments[i].info + " in " + path); + CPLog.info("Ignoring import fragment " + file.fragments[i].info + " in " + path); } else CPLog.error("Unknown fragment type"); @@ -362,6 +371,8 @@ function main() dict = bundles[path].info, replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"]; + CPLog.info("Modifying .sj: " + path); + if (replacedFiles) { var newReplacedFiles = []; From 25c7d98d2c353582dddc9a662c67536647cbf1ec Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Sat, 7 Mar 2009 19:35:14 -0800 Subject: [PATCH 34/62] Fix cplutil using "arguments" instead of "args" --- Tools/cplutil/cplutil.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/cplutil/cplutil.js b/Tools/cplutil/cplutil.js index 455df7a0f..1904d0a29 100644 --- a/Tools/cplutil/cplutil.js +++ b/Tools/cplutil/cplutil.js @@ -100,4 +100,4 @@ function main() } } -main.apply(main, arguments); +main.apply(main, args); From 88035429bb5de912a7d804a8659b5af542f6faeb Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sat, 7 Mar 2009 21:05:18 -0800 Subject: [PATCH 35/62] Fix in CPString setPlaceholderString [#238 state:resolved] --- AppKit/CPTextField.j | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 17584e3af..40ac8c58c 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -708,6 +708,9 @@ var _CPTextFieldSquareBezelColor = nil, */ -(void)setPlaceholderString:(CPString)aStringValue { + if(_placeholderString && [self stringValue] === _placeholderString) + _value = @""; + _placeholderString = aStringValue; //if there is no set value, automatically display the placeholder From 3268081d1f5cc0b813f2ba46a1c679f4cc86a0e3 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sat, 7 Mar 2009 21:54:39 -0800 Subject: [PATCH 36/62] CPDictionary should check for isa's before calling isEqual: in isEqualToDictionary: --- Foundation/CPDictionary.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPDictionary.j b/Foundation/CPDictionary.j index 593558502..1c6238a2b 100755 --- a/Foundation/CPDictionary.j +++ b/Foundation/CPDictionary.j @@ -236,7 +236,7 @@ if (lhsObject === rhsObject) continue; - if ([lhsObject respondsToSelector:@selector(isEqual:)] && [lhsObject isEqual:rhsObject]) + if (lhsObject.isa && rhsObject.isa && [lhsObject respondsToSelector:@selector(isEqual:)] && [lhsObject isEqual:rhsObject]) continue; return NO; From 2f85a417d650a3d26a854e07d0e1dd23c78ce216 Mon Sep 17 00:00:00 2001 From: Thomas Balthazar Date: Sun, 8 Mar 2009 14:53:13 +0100 Subject: [PATCH 37/62] [#239 state:resolved] : typo in CPNotificationCenter --- Foundation/CPNotificationCenter.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPNotificationCenter.j b/Foundation/CPNotificationCenter.j index 7a78d662f..375ff855c 100644 --- a/Foundation/CPNotificationCenter.j +++ b/Foundation/CPNotificationCenter.j @@ -41,7 +41,7 @@ var CPNotificationDefaultCenter = nil; /*! Returns the application's notification center */ -+ (CPNotifcationCenter)defaultCenter ++ (CPNotificationCenter)defaultCenter { if (!CPNotificationDefaultCenter) CPNotificationDefaultCenter = [[CPNotificationCenter alloc] init]; From 19d26f148f8ab57bca83c2807d12869abe85c234 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Tue, 10 Mar 2009 11:50:31 -0700 Subject: [PATCH 38/62] Reverting the tooltip change, fixes bug in CPToolbar. --- AppKit/CPControl.j | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index e08fbed6b..532e50a25 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -320,6 +320,7 @@ var CPControlBlackColor = [CPColor blackColor]; Sets the tooltip for the receiver. @param aToolTip the tooltip */ +/* -(void)setToolTip:(CPString)aToolTip { if (_toolTip == aToolTip) @@ -331,15 +332,16 @@ var CPControlBlackColor = [CPColor blackColor]; _DOMElement.title = aToolTip; #endif } - +*/ /*! Returns the receiver's tooltip */ +/* -(CPString)toolTip { return _toolTip; } - +*/ /*! Returns the receiver's target action */ From 38d72bc672ebe10ef9aa28ac823b10517b3a57ef Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Tue, 10 Mar 2009 23:18:43 -0700 Subject: [PATCH 39/62] Respect _isSelectable on CPCollectionView --- AppKit/CPCollectionView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 0768d9b69..c05deeef2 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -258,7 +258,7 @@ */ - (void)setSelectionIndexes:(CPIndexSet)anIndexSet { - if (_selectionIndexes == anIndexSet) + if (_selectionIndexes == anIndexSet || !_isSelectable) return; var index = CPNotFound; From 9f8ca93a577f879f66d1d225fd66178c18e471de Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Fri, 13 Mar 2009 15:51:54 -0700 Subject: [PATCH 40/62] Collection views should be selectable by default. --- AppKit/CPCollectionView.j | 1 + 1 file changed, 1 insertion(+) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index c05deeef2..07e5abdcf 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -111,6 +111,7 @@ _tileWidth = -1.0; _selectionIndexes = [CPIndexSet indexSet]; + _isSelectable = YES; } return self; From b22d1837becee59566e5ec27b9554f08027ae8b1 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Sun, 15 Mar 2009 02:54:09 -0700 Subject: [PATCH 41/62] Added cplutil to rake. Reviewed by me. --- Objective-J/Tools/rakefile | 2 +- Tools/cplutil/build.xml | 46 ----------------- Tools/cplutil/cplutil | 34 ------------ Tools/cplutil/cplutil.js | 103 ------------------------------------- 4 files changed, 1 insertion(+), 184 deletions(-) delete mode 100644 Tools/cplutil/build.xml delete mode 100644 Tools/cplutil/cplutil delete mode 100644 Tools/cplutil/cplutil.js diff --git a/Objective-J/Tools/rakefile b/Objective-J/Tools/rakefile index 9c0540866..caa3700a6 100644 --- a/Objective-J/Tools/rakefile +++ b/Objective-J/Tools/rakefile @@ -4,7 +4,7 @@ require 'rake' require '../../common' -subprojects = %w{objj objjc} +subprojects = %w{cplutil objj objjc} %w(build clean).each do |task_name| task task_name do diff --git a/Tools/cplutil/build.xml b/Tools/cplutil/build.xml deleted file mode 100644 index 39463c3d1..000000000 --- a/Tools/cplutil/build.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Tools/cplutil/cplutil b/Tools/cplutil/cplutil deleted file mode 100644 index db0767b56..000000000 --- a/Tools/cplutil/cplutil +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -# if OBJJ_HOME isn't set, try to determine it -if [ -z $OBJJ_HOME ]; then - # get path of the executable - SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") - - # resolve symlinks - if [ -h $SELF_PATH ]; then - SELF_PATH=`readlink $SELF_PATH` - fi - - # get second ancestor directory - SELF_DIR=`dirname $SELF_PATH` - export OBJJ_HOME=`dirname $SELF_DIR` - - # check to ensure it exists, print message - if [ -d $OBJJ_HOME ]; then - echo "OBJJ_HOME not set, defaulting to $OBJJ_HOME" 1>&2 - else - echo "OBJJ_HOME not set, default at $OBJJ_HOME doesn't exist, exiting" 1>&2 - exit 2 - fi -fi - -OBJJ_LIB="$OBJJ_HOME/lib" -CLASSPATH="$OBJJ_LIB:$OBJJ_LIB/js.jar" - -# convert paths for Cygwin -if [[ `uname` == CYGWIN* ]]; then - CLASSPATH=`cygpath -wp "$CLASSPATH"` -fi - -java -classpath $CLASSPATH cplutil $@ diff --git a/Tools/cplutil/cplutil.js b/Tools/cplutil/cplutil.js deleted file mode 100644 index 455df7a0f..000000000 --- a/Tools/cplutil/cplutil.js +++ /dev/null @@ -1,103 +0,0 @@ - -importPackage(java.lang); - -importClass(java.io.File); -importClass(java.io.BufferedReader); -importClass(java.io.FileReader); -importClass(java.io.BufferedWriter); -importClass(java.io.FileWriter); - - -function printUsage() -{ - print("this is where you say the usage"); -} - -function main() -{ - if (arguments.length < 1) - return printUsage(); - - var allFiles = NO, - format = nil, - filePaths = [], - outPath = nil, - outExtension = nil; - - index = 0, - count = arguments.length; - - for (; index < count; ++index) - { - var argument = arguments[index]; - - if (argument.charAt(0) === '-' && !allFiles) - { - if (filePaths.length > 0) - return printUsage(); - - else if (argument === "-convert") - format = arguments[++index]; - - else if (argument === "-o") - outPath = arguments[++index]; - - else if (argument === "-e") - outExtension = arguments[++index]; - - else if (argument === "--") - allFiles = YES; - - else if (argument === "-help") - return printUsage(); - } - else - filePaths.push(arguments[index]); - } - - index = 0; - count = filePaths.length; - - for (; index < count; ++index) - { - // Read the plist file - var file = new File(filePaths[index]), - reader = new BufferedReader(new FileReader(file)), - fileContents = ""; - - // Get contents of the file - while (reader.ready()) - fileContents += reader.readLine() + '\n'; - - reader.close(); - - var data = new objj_data(); - - data.string = fileContents; - - var plistObject = new CPPropertyListCreateFromData(data); - - if (format === "280north1") - data = CPPropertyListCreate280NorthData(plistObject); - - else if (format === "xml1") - data = CPPropertyListCreateXMLData(plistObject); - - var outFile = file; - - if (outPath) - outFile = new File(outPath); - -// else if (outExtension) - - - // Write out file - var writer = new BufferedWriter(new FileWriter(outFile)); - - writer.write(data.string); - - writer.close(); - } -} - -main.apply(main, arguments); From 9c3c239162d005c34dd0417a397c81e4709852da Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Sun, 15 Mar 2009 02:54:55 -0700 Subject: [PATCH 42/62] Added rakefile to cplutil. Reviewed by me. --- Objective-J/Tools/cplutil/rakefile | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Objective-J/Tools/cplutil/rakefile diff --git a/Objective-J/Tools/cplutil/rakefile b/Objective-J/Tools/cplutil/rakefile new file mode 100644 index 000000000..4e96cb871 --- /dev/null +++ b/Objective-J/Tools/cplutil/rakefile @@ -0,0 +1,32 @@ +#!/usr/bin/env ruby + +require 'rake' +require '../../../common' +require 'objective-j' + + +$CPLUTIL_SCRIPT = File.join($BUILD_DIR, 'cplutil.build', $CONFIGURATION, 'main-concat.js') +$CPLUTIL_CLASS = File.join($ENVIRONMENT_LIB_DIR, 'cplutil', 'main.class') +$CPLUTIL_EXECUTABLE = File.join($ENVIRONMENT_BIN_DIR, 'cplutil') +$STANDARD_EXECUTABLE = File.expand_path(File.join('..', 'executable')) + +task :build => [$CPLUTIL_CLASS, $CPLUTIL_EXECUTABLE] + +Files = [ File.join($HOME_DIR, 'Tools', 'Utilities', 'bridge.js'), #yuck! + File.join($HOME_DIR, 'Tools', 'Utilities', 'regex-bridge.js'), #double-yuck! + File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J', 'Rhino.platform', 'Objective-J.js'), + 'main.js']; + +file_d $CPLUTIL_EXECUTABLE => [$STANDARD_EXECUTABLE] do + cp($STANDARD_EXECUTABLE, $CPLUTIL_EXECUTABLE) + File.chmod 0755, $CPLUTIL_EXECUTABLE +end + +file_d $CPLUTIL_SCRIPT => Files do |t| + cat(Files, $CPLUTIL_SCRIPT) +end + +file_d $CPLUTIL_CLASS => $CPLUTIL_SCRIPT do |t| + js2java($CPLUTIL_SCRIPT, 'main.class', false) + cp(File.join(File.dirname($CPLUTIL_SCRIPT), 'main.class'), $CPLUTIL_CLASS) +end From 101cf4db2c2a7c99d65689c63bcae66f94476236 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Sun, 15 Mar 2009 15:32:29 -0700 Subject: [PATCH 43/62] Further Tools changes. Reviewed by me. --- Objective-J/Tools/executable | 16 +- Objective-J/Tools/objj/main.js | 17 +- Rake/Resources/objj-exec | 53 ---- Rake/Resources/objj-executable | 36 +++ Tools/blend/BlendKit/BKShowcaseController.j | 120 -------- Tools/blend/BlendKit/BKUtilities.j | 145 ---------- Tools/blend/BlendKit/BlendKit.j | 3 - Tools/blend/BlendKit/BlendKit.steam | 42 --- Tools/blend/BlendKit/Info.plist | 14 - Tools/blend/BlendKit/build.xml | 33 --- Tools/blend/Tool/blend | 57 ---- Tools/blend/Tool/blend.steam | 46 --- Tools/blend/Tool/build.xml | 23 -- Tools/blend/Tool/main.j | 298 -------------------- Tools/blend/build.xml | 28 -- common.rb | 7 + 16 files changed, 61 insertions(+), 877 deletions(-) delete mode 100644 Rake/Resources/objj-exec create mode 100755 Rake/Resources/objj-executable delete mode 100644 Tools/blend/BlendKit/BKShowcaseController.j delete mode 100644 Tools/blend/BlendKit/BKUtilities.j delete mode 100644 Tools/blend/BlendKit/BlendKit.j delete mode 100644 Tools/blend/BlendKit/BlendKit.steam delete mode 100644 Tools/blend/BlendKit/Info.plist delete mode 100644 Tools/blend/BlendKit/build.xml delete mode 100755 Tools/blend/Tool/blend delete mode 100644 Tools/blend/Tool/blend.steam delete mode 100644 Tools/blend/Tool/build.xml delete mode 100644 Tools/blend/Tool/main.j delete mode 100644 Tools/blend/build.xml diff --git a/Objective-J/Tools/executable b/Objective-J/Tools/executable index f2d87c461..efec401f6 100644 --- a/Objective-J/Tools/executable +++ b/Objective-J/Tools/executable @@ -1,7 +1,7 @@ #!/bin/sh # if OBJJ_HOME isn't set, try to determine it out -if [ -z $OBJJ_HOME ]; then +#if [ -z $OBJJ_HOME ]; then # get path of the executable SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") @@ -15,13 +15,13 @@ if [ -z $OBJJ_HOME ]; then export OBJJ_HOME=`dirname $SELF_DIR` # check to ensure it exists, print message - if [ -d $OBJJ_HOME ]; then - echo "OBJJ_HOME not set, defaulting to $OBJJ_HOME" 1>&2 - else - echo "OBJJ_HOME not set, default at $OBJJ_HOME doesn't exist, exiting" 1>&2 - exit 2 - fi -fi +# if [ -d $OBJJ_HOME ]; then +# echo "OBJJ_HOME not set, defaulting to $OBJJ_HOME" 1>&2 +# else +# echo "OBJJ_HOME not set, default at $OBJJ_HOME doesn't exist, exiting" 1>&2 +# exit 2 +# fi +#fi OBJJ_LIB="$OBJJ_HOME/lib" CLASSPATH="$OBJJ_LIB:$OBJJ_LIB/js.jar:$OBJJ_HOME/lib/$(basename $SELF_PATH):$CLASSPATH" diff --git a/Objective-J/Tools/objj/main.js b/Objective-J/Tools/objj/main.js index 3dce72c56..9db3b3284 100644 --- a/Objective-J/Tools/objj/main.js +++ b/Objective-J/Tools/objj/main.js @@ -2,6 +2,7 @@ debug = false; args = arguments; // FIXME: remove these Rhino/Java dependencies +/* var OBJJ_LIB = Packages.java.lang.System.getenv("OBJJ_LIB"); // chicken/egg problem, getenv is defined in bridge.js if (!this.window) @@ -15,17 +16,13 @@ if (!this.objj_import) print("Loading Objective-J."); load(OBJJ_LIB+'/Frameworks-Rhino/Objective-J/Objective-J.js'); } - -var defaultFrameworks = OBJJ_LIB+'/Frameworks-Rhino'; -OBJJ_INCLUDE_PATHS = [defaultFrameworks]; +*/ +OBJJ_INCLUDE_PATHS = []; var OBJJ_INCLUDE_PATHS_STRING = getenv("OBJJ_INCLUDE_PATHS"); if (OBJJ_INCLUDE_PATHS_STRING) -{ - OBJJ_INCLUDE_PATHS = OBJJ_INCLUDE_PATHS_STRING.split(":"); - OBJJ_INCLUDE_PATHS.push(defaultFrameworks); -} + OBJJ_INCLUDE_PATHS = OBJJ_INCLUDE_PATHS.concat(OBJJ_INCLUDE_PATHS_STRING.split(":")); try { @@ -37,6 +34,12 @@ try while (count--) args[count] = String(args[count]); + while (args.length && args[0].indexOf('-I') === 0) + OBJJ_INCLUDE_PATHS = OBJJ_INCLUDE_PATHS.concat(args.shift().substr(2).split(':')) + } + + if (args.length > 0) + { // Grab the location of the objj file to run. var mainFilePath = args.shift(); diff --git a/Rake/Resources/objj-exec b/Rake/Resources/objj-exec deleted file mode 100644 index f2d87c461..000000000 --- a/Rake/Resources/objj-exec +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# if OBJJ_HOME isn't set, try to determine it out -if [ -z $OBJJ_HOME ]; then - # get path of the executable - SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") - - # resolve symlinks - if [ -h $SELF_PATH ]; then - SELF_PATH=`readlink $SELF_PATH` - fi - - # get second ancestor directory - SELF_DIR=`dirname $SELF_PATH` - export OBJJ_HOME=`dirname $SELF_DIR` - - # check to ensure it exists, print message - if [ -d $OBJJ_HOME ]; then - echo "OBJJ_HOME not set, defaulting to $OBJJ_HOME" 1>&2 - else - echo "OBJJ_HOME not set, default at $OBJJ_HOME doesn't exist, exiting" 1>&2 - exit 2 - fi -fi - -OBJJ_LIB="$OBJJ_HOME/lib" -CLASSPATH="$OBJJ_LIB:$OBJJ_LIB/js.jar:$OBJJ_HOME/lib/$(basename $SELF_PATH):$CLASSPATH" - -OBJJ="$OBJJ_LIB/objj.js" -RLWRAP=`which rlwrap` - -# if there's a "lib" directory, add all the jars from it -if [ -d "lib" ]; then - JARS=`find ./lib -name '*.jar' 2> /dev/null | tr "\n" ":"` - CLASSPATH="$JARS:$CLASSPATH" -fi - -# convert paths for Cygwin -if [[ `uname` == CYGWIN* ]]; then - OBJJ_HOME=`cygpath -wp "$OBJJ_HOME"` - OBJJ_LIB=`cygpath -wp "$OBJJ_LIB"` - OBJJ=`cygpath -wp "$OBJJ"` - CLASSPATH=`cygpath -wp "$CLASSPATH"` -fi - -export OBJJ_LIB -echo $RLWRAP java -classpath $CLASSPATH main $@ -#if [ -e $STEAM_BUILD/Objective-J.build/Release/Rhino ]; then - $RLWRAP java -classpath $CLASSPATH main $@ - #$RLWRAP java -classpath $CLASSPATH org.mozilla.javascript.tools.shell.Main $OBJJ $@ -#else -# echo "Missing frameworks at $STEAM_BUILD/Objective-J.build/Release/Rhino" 1>&2 -#fi diff --git a/Rake/Resources/objj-executable b/Rake/Resources/objj-executable new file mode 100755 index 000000000..7465df500 --- /dev/null +++ b/Rake/Resources/objj-executable @@ -0,0 +1,36 @@ +#!/bin/sh + +# if OBJJ_HOME isn't set, try to determine it +#if [ -z $OBJJ_HOME ]; then + # get path of the executable + SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") + + # resolve symlinks + if [ -h $SELF_PATH ]; then + SELF_PATH=`readlink $SELF_PATH` + fi + + # get second ancestor directory + SELF_DIR=`dirname $SELF_PATH` + export OBJJ_HOME=`dirname $SELF_DIR` + + # check to ensure it exists, print message +# if [ -d $OBJJ_HOME ]; then +# echo "OBJJ_HOME not set, defaulting to $OBJJ_HOME" 1>&2 +# else +# echo "OBJJ_HOME not set, default at $OBJJ_HOME doesn't exist, exiting" 1>&2 +# exit 2 +# fi +#fi + +OBJJ_LIB="$OBJJ_HOME/lib" + +MAIN="$OBJJ_LIB/$(basename $SELF_PATH)/main.j" + +# convert paths for Cygwin +if [[ `uname` == CYGWIN* ]]; then + OBJJ_HOME=`cygpath -w "$OBJJ_HOME"` + BAKE=`cygpath -w "$BLEND"` +fi + +objj $MAIN $@ diff --git a/Tools/blend/BlendKit/BKShowcaseController.j b/Tools/blend/BlendKit/BKShowcaseController.j deleted file mode 100644 index 885417f3e..000000000 --- a/Tools/blend/BlendKit/BKShowcaseController.j +++ /dev/null @@ -1,120 +0,0 @@ - -@import -@import - -@import "BKUtilities.j" - - -@implementation BKShowcaseController : CPObject -{ -} - -- (void)applicationDidFinishLaunching:(CPNotification)aNotification -{ - var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], - contentView = [theWindow contentView], - bounds = [contentView bounds], - themeDescriptorClasses = BKThemeDescriptorClasses(); - - var tabView = [[CPTabView alloc] initWithFrame:bounds]; - - [tabView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; - - [contentView addSubview:tabView]; - - var count = [themeDescriptorClasses count]; - - while (count--) - { - var theClass = themeDescriptorClasses[count], - item = [[CPTabViewItem alloc] initWithIdentifier:[theClass themeName]], - templates = BKThemeObjectTemplatesForClass(theClass), - templatesCount = [templates count], - viewTemplates = [], - itemSize = CGSizeMake(0.0, 0.0); - - while (templatesCount--) - { - var template = templates[templatesCount], - object = [template valueForKey:@"themedObject"]; - - if ([object isKindOfClass:[CPView class]]) - { - var size = [object frame].size, - labelWidth = [[template valueForKey:@"label"] sizeWithFont:[CPFont boldSystemFontOfSize:12.0]].width + 20.0; - - if (size.width > itemSize.width) - itemSize.width = size.width; - - if (labelWidth > itemSize.width) - itemSize.width = labelWidth; - - if (size.height > itemSize.height) - itemSize.height = size.height; - - [viewTemplates addObject:template]; - } - } - - itemSize.height += 30; - - var collectionView = [[CPCollectionView alloc] initWithFrame:CGRectMakeZero()], - collectionViewItem = [[CPCollectionViewItem alloc] init]; - - [collectionViewItem setView:[[BKShowcaseCell alloc] init]]; - - [collectionView setItemPrototype:collectionViewItem]; - [collectionView setMinItemSize:itemSize]; - [collectionView setMaxItemSize:itemSize]; - [collectionView setVerticalMargin:5.0]; - [collectionView setContent:viewTemplates]; - - [item setLabel:[theClass themeName]]; - [item setView:collectionView]; - - [tabView addTabViewItem:item]; - } - - [theWindow orderFront:self]; -} - -@end - - -@implementation BKShowcaseCell : CPView -{ - CPView _view; - CPTextField _label; -} - -- (void)setRepresentedObject:(id)anObject -{ - if (!_label) - { - _label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; - - [_label setAlignment:CPCenterTextAlignment]; - [_label setAutoresizingMask:CPViewMinYMargin | CPViewWidthSizable]; - [_label setFont:[CPFont boldSystemFontOfSize:12.0]]; - - [self addSubview:_label]; - } - - [_label setStringValue:[anObject valueForKey:@"label"]]; - [_label sizeToFit]; - - [_label setFrame:CGRectMake(0.0, CGRectGetHeight([self bounds]) - CGRectGetHeight([_label frame]), - CGRectGetWidth([self bounds]), CGRectGetHeight([_label frame]))]; - - if (_view) - [_view removeFromSuperview]; - - _view = [anObject valueForKey:@"themedObject"]; - - [_view setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin]; - [_view setFrameOrigin:CGPointMake((CGRectGetWidth([self bounds]) - CGRectGetWidth([_view frame])) / 2.0, (CGRectGetMinY([_label frame]) - CGRectGetHeight([_view frame])) / 2.0)]; - - [self addSubview:_view]; -} - -@end diff --git a/Tools/blend/BlendKit/BKUtilities.j b/Tools/blend/BlendKit/BKUtilities.j deleted file mode 100644 index bda6e696a..000000000 --- a/Tools/blend/BlendKit/BKUtilities.j +++ /dev/null @@ -1,145 +0,0 @@ - -@implementation AKThemeTemplate : CPObject -{ - CPString _name; - CPString _description; -} - -- (id)initWithCoder:(CPCoder)aCoder -{ - self = [super init]; - - if (self) - { - _name = [aCoder decodeObjectForKey:@"AKThemeTemplateName"]; - _description = [aCoder decodeObjectForKey:@"AKThemeTemplateDescription"]; - } - - return self; -} - -- (void)encodeWithCoder:(CPCoder)aCoder -{ - [aCoder encodeObject:_name forKey:@"AKThemeTemplateName"]; - [aCoder encodeObject:_description forKey:@"AKThemeTemplateDescription"]; -} - -@end - -@implementation AKThemeObjectTemplate : CPView -{ - CPString _label; - id _themedObject; -} - -- (id)initWithCoder:(CPCoder)aCoder -{ - self = [super init]; - - if (self) - { - _label = [aCoder decodeObjectForKey:@"AKThemeObjectTemplateLabel"]; - _themedObject = [aCoder decodeObjectForKey:@"AKThemeObjectTemplateThemedObject"]; - } - - return self; -} - -- (void)encodeWithCoder:(CPCoder)aCoder -{ - [aCoder encodeObject:_label forKey:@"AKThemeObjectTemplateLabel"]; - [aCoder encodeObject:_themedObject forKey:@"AKThemeObjectTemplateThemedObject"]; -} - -@end - -function BKThemeDescriptorClasses() -{ - // Grab Theme Descriptor Classes. - var themeDescriptorClasses = []; - - for (candidate in window) - { - var theClass = objj_getClass(candidate), - theClassName = class_getName(theClass), - index = theClassName.indexOf("ThemeDescriptor"); - - if ((index >= 0) && (index === theClassName.length - "ThemeDescriptor".length)) - themeDescriptorClasses.push(theClass); - } - - return themeDescriptorClasses; -} - -function BKThemeObjectTemplatesForClass(aClass) -{ - var templates = [], - methods = class_copyMethodList(aClass.isa), - count = [methods count]; - - while (count--) - { - var method = methods[count], - selector = method_getName(method); - - if (selector.indexOf("themed") === 0) - { - var impl = method_getImplementation(method), - object = impl(aClass, selector); - - if (object) - { - var template = [[AKThemeObjectTemplate alloc] init]; - - [template setValue:object forKey:@"themedObject"]; - [template setValue:BKLabelFromIdentifier(selector) forKey:@"label"]; - - [templates addObject:template]; - } - } - } - - return templates; -} - -function BKLabelFromIdentifier(anIdentifier) -{ - var string = anIdentifier.substr("themed".length); - index = 0, - count = string.length, - label = "", - lastCapital = null, - isLeadingCapital = YES; - - for (; index < count; ++index) - { - var character = string.charAt(index), - isCapital = /^[A-Z]/.test(character); - - if (isCapital) - { - if (!isLeadingCapital) - { - if (lastCapital === null) - label += ' ' + character.toLowerCase(); - else - label += character; - } - - lastCapital = character; - } - else - { - if (isLeadingCapital && lastCapital !== null) - label += lastCapital; - - label += character; - - lastCapital = null; - isLeadingCapital = NO; - } - } - - return label; -} - diff --git a/Tools/blend/BlendKit/BlendKit.j b/Tools/blend/BlendKit/BlendKit.j deleted file mode 100644 index 09821ddd7..000000000 --- a/Tools/blend/BlendKit/BlendKit.j +++ /dev/null @@ -1,3 +0,0 @@ - -@import "BKShowcaseController.j" -@import "BKUtilities.j" diff --git a/Tools/blend/BlendKit/BlendKit.steam b/Tools/blend/BlendKit/BlendKit.steam deleted file mode 100644 index 75d93232e..000000000 --- a/Tools/blend/BlendKit/BlendKit.steam +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Name - BlendKit - Targets - - - Name - BlendKit - - - Configurations - - - Name - Debug - Flags - -DDEBUG -DPLATFORM_DOM -g - - - Name - Release - Flags - -DPLATFORM_DOM -O - - - Name - Debug-Rhino - Flags - -DDEBUG -g - - - Name - Release-Rhino - Flags - -O - - - - diff --git a/Tools/blend/BlendKit/Info.plist b/Tools/blend/BlendKit/Info.plist deleted file mode 100644 index 898e2e6c0..000000000 --- a/Tools/blend/BlendKit/Info.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - CPBundleIdentifier - com.280n.BlendKit - CPBundleInfoDictionaryVersion - 6.0 - CPBundleName - BlendKit - CPBundlePackageType - FMWK - - diff --git a/Tools/blend/BlendKit/build.xml b/Tools/blend/BlendKit/build.xml deleted file mode 100644 index 67c5ff641..000000000 --- a/Tools/blend/BlendKit/build.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Tools/blend/Tool/blend b/Tools/blend/Tool/blend deleted file mode 100755 index 7d3ae9cac..000000000 --- a/Tools/blend/Tool/blend +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh -# -# blend -# blend -# -# Created by Francisco Tolmasky. -# Copyright 2008, 280 North, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -# if OBJJ_HOME isn't set, try to determine it -if [ -z $OBJJ_HOME ]; then - # get path of the executable - SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") - - # resolve symlinks - if [ -h $SELF_PATH ]; then - SELF_PATH=`readlink $SELF_PATH` - fi - - # get second ancestor directory - SELF_DIR=`dirname $SELF_PATH` - export OBJJ_HOME=`dirname $SELF_DIR` - - # check to ensure it exists, print message - if [ -d $OBJJ_HOME ]; then - echo "OBJJ_HOME not set, defaulting to $OBJJ_HOME" 1>&2 - else - echo "OBJJ_HOME not set, default at $OBJJ_HOME doesn't exist, exiting" 1>&2 - exit 2 - fi -fi - -OBJJ_LIB="$OBJJ_HOME/lib" - -BLEND="$OBJJ_LIB/blend/main.j" - -# convert paths for Cygwin -if [[ `uname` == CYGWIN* ]]; then - OBJJ_HOME=`cygpath -w "$OBJJ_HOME"` - BAKE=`cygpath -w "$BLEND"` -fi - -objj $BLEND $@ diff --git a/Tools/blend/Tool/blend.steam b/Tools/blend/Tool/blend.steam deleted file mode 100644 index b4287d226..000000000 --- a/Tools/blend/Tool/blend.steam +++ /dev/null @@ -1,46 +0,0 @@ - - - - - Name - blend - Targets - - - Name - blend - Excluded - - BlendKit - - - - Configurations - - - Name - Debug - Flags - -DDEBUG -DPLATFORM_DOM -g - - - Name - Release - Flags - -DPLATFORM_DOM -O - - - Name - Debug-Rhino - Flags - -DDEBUG -g - - - Name - Release-Rhino - Flags - -O - - - - diff --git a/Tools/blend/Tool/build.xml b/Tools/blend/Tool/build.xml deleted file mode 100644 index a3773f38b..000000000 --- a/Tools/blend/Tool/build.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Tools/blend/Tool/main.j b/Tools/blend/Tool/main.j deleted file mode 100644 index d441154e4..000000000 --- a/Tools/blend/Tool/main.j +++ /dev/null @@ -1,298 +0,0 @@ - -@import -@import -@import -@import -@import - -importClass(java.io.File); -importClass(java.io.FileOutputStream); -importClass(java.io.BufferedWriter); -importClass(java.io.OutputStreamWriter); - - -function main() -{ - var index = 0, - count = arguments.length, - - outputFilePath = "", - descriptorFiles = [], - resourcesPath = nil, - cibFiles = []; - - for (; index < count; ++index) - { - var argument = arguments[index]; - - switch (argument) - { - case "-c": - case "--cib": cibFiles.push(arguments[++index]); - break; - - case "-d": - case "-descriptor": descriptorFiles.push(arguments[++index]); - break; - - case "-o": outputFilePath = arguments[++index]; - break; - - case "-R": resourcesPath = arguments[++index]; - break; - - default: jExtensionIndex = argument.indexOf(".j"); - - if ((jExtensionIndex > 0) && (jExtensionIndex === argument.length - ".j".length)) - descriptorFiles.push(argument); - else - cibFiles.push(argument); - } - } - - if (descriptorFiles.length === 0) - return buildBlendFromCibFiles(cibFiles); - - objj_import(descriptorFiles, YES, function() - { - var themeDescriptorClasses = BKThemeDescriptorClasses(), - count = [themeDescriptorClasses count]; - - while (count--) - { - var theClass = themeDescriptorClasses[count], - themeTemplate = [[AKThemeTemplate alloc] init]; - - [themeTemplate setValue:[theClass themeName] forKey:@"name"]; - - var objectTemplates = BKThemeObjectTemplatesForClass(theClass); - data = cibDataFromTopLevelObjects(objectTemplates.concat([themeTemplate])), - temporaryCibFile = File.createTempFile("temp", ".cib"), - temporaryCibFilePath = temporaryCibFile.getAbsolutePath(), - writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(temporaryCibFilePath), "UTF-8")); - - writer.write([data string]); - writer.close(); - - cibFiles.push(temporaryCibFilePath); - } - - buildBlendFromCibFiles(cibFiles, outputFilePath, resourcesPath); - }); -} - -function cibDataFromTopLevelObjects(objects) -{ - var data = [CPData data], - archiver = [[CPKeyedArchiver alloc] initForWritingWithMutableData:data], - objectData = [[_CPCibObjectData alloc] init]; - - objectData._fileOwner = [_CPCibCustomObject new]; - objectData._fileOwner._className = @"CPObject"; - - var index = 0, - count = objects.length; - - for (; index < count; ++index) - { - objectData._objectsValues[index] = objectData._fileOwner; - objectData._objectsKeys[index] = objects[index]; - } - - [archiver encodeObject:objectData forKey:@"CPCibObjectDataKey"]; - - [archiver finishEncoding]; - - return data; -} - -function getDirectory(aPath) -{ - return (aPath).substr(0, (aPath).lastIndexOf('/') + 1) -} - -function buildBlendFromCibFiles(cibFiles, outputFilePath, resourcesPath) -{ - var resourcesFile = nil; - - if (resourcesPath) - resourcesFile = new File(resourcesPath); - - var count = cibFiles.length, - replacedFiles = [], - staticContent = @""; - - while (count--) - { - var theme = themeFromCibFile(new File(cibFiles[count])), - - // Archive our theme. - filePath = [theme name] + ".keyedtheme", - fileContents = [[CPKeyedArchiver archivedDataWithRootObject:theme] string]; - - replacedFiles.push(filePath); - - staticContent += MARKER_PATH + ';' + filePath.length + ';' + filePath + MARKER_TEXT + ';' + fileContents.length + ';' + fileContents; - } - - staticContent = "@STATIC;1.0;" + staticContent; - - var infoDictionary = [CPDictionary dictionary]; - staticContentName = "Aristo";//getFileNameWithoutExtension(project.activeTarget().name()); - - [infoDictionary setObject:@"Yikes." forKey:@"CPBundleName"]; - [infoDictionary setObject:@"Yikes." forKey:@"CPBundleIdentifier"]; - [infoDictionary setObject:replacedFiles forKey:@"CPBundleReplacedFiles"]; - [infoDictionary setObject:staticContentName forKey:@"CPBundleExecutable"]; - - var outputFile = new File(outputFilePath).getCanonicalFile(); - - outputFile.mkdirs(); - - var writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFilePath + "/Info.plist"), "UTF-8")); - - writer.write(CPPropertyListCreate280NorthData(infoDictionary).string); - - writer.close(); - - writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFilePath + '/' + staticContentName), "UTF-8")); - - writer.write(staticContent); - - writer.close(); - - if (resourcesPath) - rsync(new File(resourcesPath), new File(outputFilePath)); -} - -function themeFromCibFile(aFile) -{ - var cib = [[CPCib alloc] initWithContentsOfURL:aFile.getCanonicalPath()], - topLevelObjects = []; - - [cib _setAwakenCustomResources:NO]; - [cib instantiateCibWithExternalNameTable:[CPDictionary dictionaryWithObject:topLevelObjects forKey:CPCibTopLevelObjects]]; - - var count = topLevelObjects.length, - theme = nil, - templates = []; - - while (count--) - { - var object = topLevelObjects[count]; - - templates = templates.concat([object blendThemeObjectTemplates]); - - if ([object isKindOfClass:[AKThemeTemplate class]]) - theme = [[CPTheme alloc] initWithName:[object valueForKey:@"name"]]; - } - - [templates makeObjectsPerformSelector:@selector(blendAddThemedObjectAttributesToTheme:) withObject:theme]; - - return theme; -} - -function rsync(srcFile, dstFile) -{ - var src, dst; - - if (String(java.lang.System.getenv("OS")).indexOf("Windows") < 0) - { - src = srcFile.getAbsolutePath(); - dst = dstFile.getAbsolutePath(); - } - else - { - src = exec(["cygpath", "-u", srcFile.getAbsolutePath() + '/']); - dst = exec(["cygpath", "-u", dstFile.getAbsolutePath() + "/Resources"]); - } - - if (srcFile.exists()) - exec(["rsync", "-avz", src, dst]); -} - -function exec(/*Array*/ command, /*Boolean*/ showOutput) -{ - var line = "", - output = "", - - process = Packages.java.lang.Runtime.getRuntime().exec(command),//jsArrayToJavaArray(command)); - reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getInputStream())); - - while (line = reader.readLine()) - { - if (showOutput) - System.out.println(line); - - output += line + '\n'; - } - - reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getErrorStream())); - - while (line = reader.readLine()) - System.out.println(line); - - try - { - if (process.waitFor() != 0) - System.err.println("exit value = " + process.exitValue()); - } - catch (anException) - { - System.err.println(anException); - } - - return output; -} - -@implementation CPObject (BlendAdditions) - -- (CPArray)blendThemeObjectTemplates -{ - var theClass = [self class]; - - if ([theClass isKindOfClass:[AKThemeObjectTemplate class]]) - return [self]; - - if ([theClass isKindOfClass:[CPView class]]) - { - var templates = [], - subviews = [self subviews], - count = [subviews count]; - - while (count--) - templates = templates.concat([subviews[count] blendThemeObjectTemplates]); - - return templates; - } - - return []; -} - -@end - -@implementation AKThemeObjectTemplate (BlendAdditions) - -- (void)blendAddThemedObjectAttributesToTheme:(CPTheme)aTheme -{ - var themedObject = [self valueForKey:@"themedObject"]; - - if (!themedObject) - { - var subviews = [self subviews]; - - if ([subviews count] > 0) - themedObject = subviews[0]; - } - - if (themedObject) - { - print(" Recording theme for " + [themedObject className] + "."); - - [aTheme takeThemeFromObject:themedObject]; - } -} - -@end - -main.apply(main, args); diff --git a/Tools/blend/build.xml b/Tools/blend/build.xml deleted file mode 100644 index 903d5a94a..000000000 --- a/Tools/blend/build.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/common.rb b/common.rb index 7cba7ef64..e94392af6 100644 --- a/common.rb +++ b/common.rb @@ -79,5 +79,12 @@ def cat(files, outfile) end end +$OBJJ_TEMPLATE_EXECUTABLE = File.join($HOME_DIR, 'Rake', 'Resources', 'objj-executable') + +def make_objj_executable(path) + cp($OBJJ_TEMPLATE_EXECUTABLE, path) + File.chmod 0755, path +end + task :build => [$ENVIRONMENT_JS] task :default => [:build] From df6ec644e9383fc2d685bb3cfd67d2885d035f01 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Sun, 15 Mar 2009 19:36:24 -0700 Subject: [PATCH 44/62] Started moving blend over. Reviewed by me. --- AppKit/Tools/BlendKit/BKShowcaseController.j | 120 ++++++++ AppKit/Tools/BlendKit/BKUtilities.j | 145 +++++++++ AppKit/Tools/BlendKit/BlendKit.j | 3 + AppKit/Tools/BlendKit/BlendKit.steam | 42 +++ AppKit/Tools/BlendKit/Info.plist | 14 + AppKit/Tools/BlendKit/build.xml | 33 ++ AppKit/Tools/BlendKit/rakefile | 54 ++++ AppKit/Tools/blend/blend | 57 ++++ AppKit/Tools/blend/blend.steam | 46 +++ AppKit/Tools/blend/build.xml | 23 ++ AppKit/Tools/blend/main.j | 298 +++++++++++++++++++ AppKit/Tools/blend/rakefile | 59 ++++ AppKit/Tools/rakefile | 13 + AppKit/rakefile | 6 +- Objective-J/Runtime/file.js | 8 +- Objective-J/Tools/objj/main.js | 5 +- Rake/Resources/objj-executable | 4 +- 17 files changed, 920 insertions(+), 10 deletions(-) create mode 100644 AppKit/Tools/BlendKit/BKShowcaseController.j create mode 100644 AppKit/Tools/BlendKit/BKUtilities.j create mode 100644 AppKit/Tools/BlendKit/BlendKit.j create mode 100644 AppKit/Tools/BlendKit/BlendKit.steam create mode 100644 AppKit/Tools/BlendKit/Info.plist create mode 100644 AppKit/Tools/BlendKit/build.xml create mode 100644 AppKit/Tools/BlendKit/rakefile create mode 100755 AppKit/Tools/blend/blend create mode 100644 AppKit/Tools/blend/blend.steam create mode 100644 AppKit/Tools/blend/build.xml create mode 100644 AppKit/Tools/blend/main.j create mode 100644 AppKit/Tools/blend/rakefile create mode 100644 AppKit/Tools/rakefile diff --git a/AppKit/Tools/BlendKit/BKShowcaseController.j b/AppKit/Tools/BlendKit/BKShowcaseController.j new file mode 100644 index 000000000..885417f3e --- /dev/null +++ b/AppKit/Tools/BlendKit/BKShowcaseController.j @@ -0,0 +1,120 @@ + +@import +@import + +@import "BKUtilities.j" + + +@implementation BKShowcaseController : CPObject +{ +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView], + bounds = [contentView bounds], + themeDescriptorClasses = BKThemeDescriptorClasses(); + + var tabView = [[CPTabView alloc] initWithFrame:bounds]; + + [tabView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; + + [contentView addSubview:tabView]; + + var count = [themeDescriptorClasses count]; + + while (count--) + { + var theClass = themeDescriptorClasses[count], + item = [[CPTabViewItem alloc] initWithIdentifier:[theClass themeName]], + templates = BKThemeObjectTemplatesForClass(theClass), + templatesCount = [templates count], + viewTemplates = [], + itemSize = CGSizeMake(0.0, 0.0); + + while (templatesCount--) + { + var template = templates[templatesCount], + object = [template valueForKey:@"themedObject"]; + + if ([object isKindOfClass:[CPView class]]) + { + var size = [object frame].size, + labelWidth = [[template valueForKey:@"label"] sizeWithFont:[CPFont boldSystemFontOfSize:12.0]].width + 20.0; + + if (size.width > itemSize.width) + itemSize.width = size.width; + + if (labelWidth > itemSize.width) + itemSize.width = labelWidth; + + if (size.height > itemSize.height) + itemSize.height = size.height; + + [viewTemplates addObject:template]; + } + } + + itemSize.height += 30; + + var collectionView = [[CPCollectionView alloc] initWithFrame:CGRectMakeZero()], + collectionViewItem = [[CPCollectionViewItem alloc] init]; + + [collectionViewItem setView:[[BKShowcaseCell alloc] init]]; + + [collectionView setItemPrototype:collectionViewItem]; + [collectionView setMinItemSize:itemSize]; + [collectionView setMaxItemSize:itemSize]; + [collectionView setVerticalMargin:5.0]; + [collectionView setContent:viewTemplates]; + + [item setLabel:[theClass themeName]]; + [item setView:collectionView]; + + [tabView addTabViewItem:item]; + } + + [theWindow orderFront:self]; +} + +@end + + +@implementation BKShowcaseCell : CPView +{ + CPView _view; + CPTextField _label; +} + +- (void)setRepresentedObject:(id)anObject +{ + if (!_label) + { + _label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; + + [_label setAlignment:CPCenterTextAlignment]; + [_label setAutoresizingMask:CPViewMinYMargin | CPViewWidthSizable]; + [_label setFont:[CPFont boldSystemFontOfSize:12.0]]; + + [self addSubview:_label]; + } + + [_label setStringValue:[anObject valueForKey:@"label"]]; + [_label sizeToFit]; + + [_label setFrame:CGRectMake(0.0, CGRectGetHeight([self bounds]) - CGRectGetHeight([_label frame]), + CGRectGetWidth([self bounds]), CGRectGetHeight([_label frame]))]; + + if (_view) + [_view removeFromSuperview]; + + _view = [anObject valueForKey:@"themedObject"]; + + [_view setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin]; + [_view setFrameOrigin:CGPointMake((CGRectGetWidth([self bounds]) - CGRectGetWidth([_view frame])) / 2.0, (CGRectGetMinY([_label frame]) - CGRectGetHeight([_view frame])) / 2.0)]; + + [self addSubview:_view]; +} + +@end diff --git a/AppKit/Tools/BlendKit/BKUtilities.j b/AppKit/Tools/BlendKit/BKUtilities.j new file mode 100644 index 000000000..bda6e696a --- /dev/null +++ b/AppKit/Tools/BlendKit/BKUtilities.j @@ -0,0 +1,145 @@ + +@implementation AKThemeTemplate : CPObject +{ + CPString _name; + CPString _description; +} + +- (id)initWithCoder:(CPCoder)aCoder +{ + self = [super init]; + + if (self) + { + _name = [aCoder decodeObjectForKey:@"AKThemeTemplateName"]; + _description = [aCoder decodeObjectForKey:@"AKThemeTemplateDescription"]; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [aCoder encodeObject:_name forKey:@"AKThemeTemplateName"]; + [aCoder encodeObject:_description forKey:@"AKThemeTemplateDescription"]; +} + +@end + +@implementation AKThemeObjectTemplate : CPView +{ + CPString _label; + id _themedObject; +} + +- (id)initWithCoder:(CPCoder)aCoder +{ + self = [super init]; + + if (self) + { + _label = [aCoder decodeObjectForKey:@"AKThemeObjectTemplateLabel"]; + _themedObject = [aCoder decodeObjectForKey:@"AKThemeObjectTemplateThemedObject"]; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [aCoder encodeObject:_label forKey:@"AKThemeObjectTemplateLabel"]; + [aCoder encodeObject:_themedObject forKey:@"AKThemeObjectTemplateThemedObject"]; +} + +@end + +function BKThemeDescriptorClasses() +{ + // Grab Theme Descriptor Classes. + var themeDescriptorClasses = []; + + for (candidate in window) + { + var theClass = objj_getClass(candidate), + theClassName = class_getName(theClass), + index = theClassName.indexOf("ThemeDescriptor"); + + if ((index >= 0) && (index === theClassName.length - "ThemeDescriptor".length)) + themeDescriptorClasses.push(theClass); + } + + return themeDescriptorClasses; +} + +function BKThemeObjectTemplatesForClass(aClass) +{ + var templates = [], + methods = class_copyMethodList(aClass.isa), + count = [methods count]; + + while (count--) + { + var method = methods[count], + selector = method_getName(method); + + if (selector.indexOf("themed") === 0) + { + var impl = method_getImplementation(method), + object = impl(aClass, selector); + + if (object) + { + var template = [[AKThemeObjectTemplate alloc] init]; + + [template setValue:object forKey:@"themedObject"]; + [template setValue:BKLabelFromIdentifier(selector) forKey:@"label"]; + + [templates addObject:template]; + } + } + } + + return templates; +} + +function BKLabelFromIdentifier(anIdentifier) +{ + var string = anIdentifier.substr("themed".length); + index = 0, + count = string.length, + label = "", + lastCapital = null, + isLeadingCapital = YES; + + for (; index < count; ++index) + { + var character = string.charAt(index), + isCapital = /^[A-Z]/.test(character); + + if (isCapital) + { + if (!isLeadingCapital) + { + if (lastCapital === null) + label += ' ' + character.toLowerCase(); + else + label += character; + } + + lastCapital = character; + } + else + { + if (isLeadingCapital && lastCapital !== null) + label += lastCapital; + + label += character; + + lastCapital = null; + isLeadingCapital = NO; + } + } + + return label; +} + diff --git a/AppKit/Tools/BlendKit/BlendKit.j b/AppKit/Tools/BlendKit/BlendKit.j new file mode 100644 index 000000000..09821ddd7 --- /dev/null +++ b/AppKit/Tools/BlendKit/BlendKit.j @@ -0,0 +1,3 @@ + +@import "BKShowcaseController.j" +@import "BKUtilities.j" diff --git a/AppKit/Tools/BlendKit/BlendKit.steam b/AppKit/Tools/BlendKit/BlendKit.steam new file mode 100644 index 000000000..75d93232e --- /dev/null +++ b/AppKit/Tools/BlendKit/BlendKit.steam @@ -0,0 +1,42 @@ + + + + + Name + BlendKit + Targets + + + Name + BlendKit + + + Configurations + + + Name + Debug + Flags + -DDEBUG -DPLATFORM_DOM -g + + + Name + Release + Flags + -DPLATFORM_DOM -O + + + Name + Debug-Rhino + Flags + -DDEBUG -g + + + Name + Release-Rhino + Flags + -O + + + + diff --git a/AppKit/Tools/BlendKit/Info.plist b/AppKit/Tools/BlendKit/Info.plist new file mode 100644 index 000000000..898e2e6c0 --- /dev/null +++ b/AppKit/Tools/BlendKit/Info.plist @@ -0,0 +1,14 @@ + + + + + CPBundleIdentifier + com.280n.BlendKit + CPBundleInfoDictionaryVersion + 6.0 + CPBundleName + BlendKit + CPBundlePackageType + FMWK + + diff --git a/AppKit/Tools/BlendKit/build.xml b/AppKit/Tools/BlendKit/build.xml new file mode 100644 index 000000000..67c5ff641 --- /dev/null +++ b/AppKit/Tools/BlendKit/build.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AppKit/Tools/BlendKit/rakefile b/AppKit/Tools/BlendKit/rakefile new file mode 100644 index 000000000..279095890 --- /dev/null +++ b/AppKit/Tools/BlendKit/rakefile @@ -0,0 +1,54 @@ +#!/usr/bin/env ruby + +require 'rake' +require '../../../common' +require 'objective-j' +require 'objective-j/bundle' + + +$PRODUCT = 'BlendKit' + $CONFIGURATION +$ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'BlendKit') + +task :build => [$PRODUCT, $ENVIRONMENT_PRODUCT] + +Specs = {} + +# Debug Framework +Specs[:BlendKitDebug] = ObjectiveJ::BundleSpecification.new do |s| + s.name = 'BlendKit' + s.identifier = 'com.280n.BlendKit' + s.version = '0.6.5' + s.author = '280 North, Inc.' + s.email = 'feedback @nospam@ 280north.com' + s.summary = 'BlendKit classes for Cappuccino' + s.sources = FileList['**/*.j'] + s.resources = FileList['Resources/*'] + s.license = ObjectiveJ::License::LGPL_v2_1 + s.build_path = File.join($BUILD_DIR, 'Debug', 'BlendKit') + s.intermediates_path = File.join($BUILD_DIR, 'BlendKit.build', 'Debug') + s.flag = 'DEBUG' +end + +bundle Specs[:BlendKitDebug], :BlendKitDebug + +# Release Framework +Specs[:BlendKitRelease] = ObjectiveJ::BundleSpecification.new do |s| + s.name = 'BlendKit' + s.identifier = 'com.280n.BlendKit' + s.version = '0.6.5' + s.author = '280 North, Inc.' + s.email = 'feedback @nospam@ 280north.com' + s.summary = 'BlendKit classes for Cappuccino' + s.sources = FileList['**/*.j'] + s.resources = FileList['Resources/*'] + s.license = ObjectiveJ::License::LGPL_v2_1 + s.build_path = File.join($BUILD_DIR, 'Release', 'BlendKit') + s.intermediates_path = File.join($BUILD_DIR, 'BlendKit.build', 'Release') +end + +bundle Specs[:BlendKitRelease], :BlendKitRelease + +#Framework in environment directory +file_d $ENVIRONMENT_PRODUCT => [$PRODUCT] do + cp_r(Specs[$PRODUCT.to_sym].build_path, $ENVIRONMENT_PRODUCT) +end diff --git a/AppKit/Tools/blend/blend b/AppKit/Tools/blend/blend new file mode 100755 index 000000000..7d3ae9cac --- /dev/null +++ b/AppKit/Tools/blend/blend @@ -0,0 +1,57 @@ +#!/bin/sh +# +# blend +# blend +# +# Created by Francisco Tolmasky. +# Copyright 2008, 280 North, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +# if OBJJ_HOME isn't set, try to determine it +if [ -z $OBJJ_HOME ]; then + # get path of the executable + SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") + + # resolve symlinks + if [ -h $SELF_PATH ]; then + SELF_PATH=`readlink $SELF_PATH` + fi + + # get second ancestor directory + SELF_DIR=`dirname $SELF_PATH` + export OBJJ_HOME=`dirname $SELF_DIR` + + # check to ensure it exists, print message + if [ -d $OBJJ_HOME ]; then + echo "OBJJ_HOME not set, defaulting to $OBJJ_HOME" 1>&2 + else + echo "OBJJ_HOME not set, default at $OBJJ_HOME doesn't exist, exiting" 1>&2 + exit 2 + fi +fi + +OBJJ_LIB="$OBJJ_HOME/lib" + +BLEND="$OBJJ_LIB/blend/main.j" + +# convert paths for Cygwin +if [[ `uname` == CYGWIN* ]]; then + OBJJ_HOME=`cygpath -w "$OBJJ_HOME"` + BAKE=`cygpath -w "$BLEND"` +fi + +objj $BLEND $@ diff --git a/AppKit/Tools/blend/blend.steam b/AppKit/Tools/blend/blend.steam new file mode 100644 index 000000000..b4287d226 --- /dev/null +++ b/AppKit/Tools/blend/blend.steam @@ -0,0 +1,46 @@ + + + + + Name + blend + Targets + + + Name + blend + Excluded + + BlendKit + + + + Configurations + + + Name + Debug + Flags + -DDEBUG -DPLATFORM_DOM -g + + + Name + Release + Flags + -DPLATFORM_DOM -O + + + Name + Debug-Rhino + Flags + -DDEBUG -g + + + Name + Release-Rhino + Flags + -O + + + + diff --git a/AppKit/Tools/blend/build.xml b/AppKit/Tools/blend/build.xml new file mode 100644 index 000000000..a3773f38b --- /dev/null +++ b/AppKit/Tools/blend/build.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AppKit/Tools/blend/main.j b/AppKit/Tools/blend/main.j new file mode 100644 index 000000000..d441154e4 --- /dev/null +++ b/AppKit/Tools/blend/main.j @@ -0,0 +1,298 @@ + +@import +@import +@import +@import +@import + +importClass(java.io.File); +importClass(java.io.FileOutputStream); +importClass(java.io.BufferedWriter); +importClass(java.io.OutputStreamWriter); + + +function main() +{ + var index = 0, + count = arguments.length, + + outputFilePath = "", + descriptorFiles = [], + resourcesPath = nil, + cibFiles = []; + + for (; index < count; ++index) + { + var argument = arguments[index]; + + switch (argument) + { + case "-c": + case "--cib": cibFiles.push(arguments[++index]); + break; + + case "-d": + case "-descriptor": descriptorFiles.push(arguments[++index]); + break; + + case "-o": outputFilePath = arguments[++index]; + break; + + case "-R": resourcesPath = arguments[++index]; + break; + + default: jExtensionIndex = argument.indexOf(".j"); + + if ((jExtensionIndex > 0) && (jExtensionIndex === argument.length - ".j".length)) + descriptorFiles.push(argument); + else + cibFiles.push(argument); + } + } + + if (descriptorFiles.length === 0) + return buildBlendFromCibFiles(cibFiles); + + objj_import(descriptorFiles, YES, function() + { + var themeDescriptorClasses = BKThemeDescriptorClasses(), + count = [themeDescriptorClasses count]; + + while (count--) + { + var theClass = themeDescriptorClasses[count], + themeTemplate = [[AKThemeTemplate alloc] init]; + + [themeTemplate setValue:[theClass themeName] forKey:@"name"]; + + var objectTemplates = BKThemeObjectTemplatesForClass(theClass); + data = cibDataFromTopLevelObjects(objectTemplates.concat([themeTemplate])), + temporaryCibFile = File.createTempFile("temp", ".cib"), + temporaryCibFilePath = temporaryCibFile.getAbsolutePath(), + writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(temporaryCibFilePath), "UTF-8")); + + writer.write([data string]); + writer.close(); + + cibFiles.push(temporaryCibFilePath); + } + + buildBlendFromCibFiles(cibFiles, outputFilePath, resourcesPath); + }); +} + +function cibDataFromTopLevelObjects(objects) +{ + var data = [CPData data], + archiver = [[CPKeyedArchiver alloc] initForWritingWithMutableData:data], + objectData = [[_CPCibObjectData alloc] init]; + + objectData._fileOwner = [_CPCibCustomObject new]; + objectData._fileOwner._className = @"CPObject"; + + var index = 0, + count = objects.length; + + for (; index < count; ++index) + { + objectData._objectsValues[index] = objectData._fileOwner; + objectData._objectsKeys[index] = objects[index]; + } + + [archiver encodeObject:objectData forKey:@"CPCibObjectDataKey"]; + + [archiver finishEncoding]; + + return data; +} + +function getDirectory(aPath) +{ + return (aPath).substr(0, (aPath).lastIndexOf('/') + 1) +} + +function buildBlendFromCibFiles(cibFiles, outputFilePath, resourcesPath) +{ + var resourcesFile = nil; + + if (resourcesPath) + resourcesFile = new File(resourcesPath); + + var count = cibFiles.length, + replacedFiles = [], + staticContent = @""; + + while (count--) + { + var theme = themeFromCibFile(new File(cibFiles[count])), + + // Archive our theme. + filePath = [theme name] + ".keyedtheme", + fileContents = [[CPKeyedArchiver archivedDataWithRootObject:theme] string]; + + replacedFiles.push(filePath); + + staticContent += MARKER_PATH + ';' + filePath.length + ';' + filePath + MARKER_TEXT + ';' + fileContents.length + ';' + fileContents; + } + + staticContent = "@STATIC;1.0;" + staticContent; + + var infoDictionary = [CPDictionary dictionary]; + staticContentName = "Aristo";//getFileNameWithoutExtension(project.activeTarget().name()); + + [infoDictionary setObject:@"Yikes." forKey:@"CPBundleName"]; + [infoDictionary setObject:@"Yikes." forKey:@"CPBundleIdentifier"]; + [infoDictionary setObject:replacedFiles forKey:@"CPBundleReplacedFiles"]; + [infoDictionary setObject:staticContentName forKey:@"CPBundleExecutable"]; + + var outputFile = new File(outputFilePath).getCanonicalFile(); + + outputFile.mkdirs(); + + var writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFilePath + "/Info.plist"), "UTF-8")); + + writer.write(CPPropertyListCreate280NorthData(infoDictionary).string); + + writer.close(); + + writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFilePath + '/' + staticContentName), "UTF-8")); + + writer.write(staticContent); + + writer.close(); + + if (resourcesPath) + rsync(new File(resourcesPath), new File(outputFilePath)); +} + +function themeFromCibFile(aFile) +{ + var cib = [[CPCib alloc] initWithContentsOfURL:aFile.getCanonicalPath()], + topLevelObjects = []; + + [cib _setAwakenCustomResources:NO]; + [cib instantiateCibWithExternalNameTable:[CPDictionary dictionaryWithObject:topLevelObjects forKey:CPCibTopLevelObjects]]; + + var count = topLevelObjects.length, + theme = nil, + templates = []; + + while (count--) + { + var object = topLevelObjects[count]; + + templates = templates.concat([object blendThemeObjectTemplates]); + + if ([object isKindOfClass:[AKThemeTemplate class]]) + theme = [[CPTheme alloc] initWithName:[object valueForKey:@"name"]]; + } + + [templates makeObjectsPerformSelector:@selector(blendAddThemedObjectAttributesToTheme:) withObject:theme]; + + return theme; +} + +function rsync(srcFile, dstFile) +{ + var src, dst; + + if (String(java.lang.System.getenv("OS")).indexOf("Windows") < 0) + { + src = srcFile.getAbsolutePath(); + dst = dstFile.getAbsolutePath(); + } + else + { + src = exec(["cygpath", "-u", srcFile.getAbsolutePath() + '/']); + dst = exec(["cygpath", "-u", dstFile.getAbsolutePath() + "/Resources"]); + } + + if (srcFile.exists()) + exec(["rsync", "-avz", src, dst]); +} + +function exec(/*Array*/ command, /*Boolean*/ showOutput) +{ + var line = "", + output = "", + + process = Packages.java.lang.Runtime.getRuntime().exec(command),//jsArrayToJavaArray(command)); + reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getInputStream())); + + while (line = reader.readLine()) + { + if (showOutput) + System.out.println(line); + + output += line + '\n'; + } + + reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getErrorStream())); + + while (line = reader.readLine()) + System.out.println(line); + + try + { + if (process.waitFor() != 0) + System.err.println("exit value = " + process.exitValue()); + } + catch (anException) + { + System.err.println(anException); + } + + return output; +} + +@implementation CPObject (BlendAdditions) + +- (CPArray)blendThemeObjectTemplates +{ + var theClass = [self class]; + + if ([theClass isKindOfClass:[AKThemeObjectTemplate class]]) + return [self]; + + if ([theClass isKindOfClass:[CPView class]]) + { + var templates = [], + subviews = [self subviews], + count = [subviews count]; + + while (count--) + templates = templates.concat([subviews[count] blendThemeObjectTemplates]); + + return templates; + } + + return []; +} + +@end + +@implementation AKThemeObjectTemplate (BlendAdditions) + +- (void)blendAddThemedObjectAttributesToTheme:(CPTheme)aTheme +{ + var themedObject = [self valueForKey:@"themedObject"]; + + if (!themedObject) + { + var subviews = [self subviews]; + + if ([subviews count] > 0) + themedObject = subviews[0]; + } + + if (themedObject) + { + print(" Recording theme for " + [themedObject className] + "."); + + [aTheme takeThemeFromObject:themedObject]; + } +} + +@end + +main.apply(main, args); diff --git a/AppKit/Tools/blend/rakefile b/AppKit/Tools/blend/rakefile new file mode 100644 index 000000000..77f0428bb --- /dev/null +++ b/AppKit/Tools/blend/rakefile @@ -0,0 +1,59 @@ +#!/usr/bin/env ruby + +require 'rake' +require '../../../common' +require 'objective-j' +require 'objective-j/bundle' + + +$PRODUCT = 'blend' + $CONFIGURATION +$ENVIRONMENT_BIN_PRODUCT = File.join($ENVIRONMENT_BIN_DIR, 'blend') +$ENVIRONMENT_LIB_PRODUCT = File.join($ENVIRONMENT_LIB_DIR, 'blend') + +task :build => [$PRODUCT, $ENVIRONMENT_BIN_PRODUCT, $ENVIRONMENT_LIB_PRODUCT] + +Specs = {} + +# Debug Framework +Specs[:blendDebug] = ObjectiveJ::BundleSpecification.new do |s| + s.name = 'blend' + s.identifier = 'com.280n.blend' + s.version = '0.6.5' + s.author = '280 North, Inc.' + s.email = 'feedback @nospam@ 280north.com' + s.summary = 'blend classes for Cappuccino' + s.sources = FileList['**/*.j'] + s.resources = FileList['Resources/*'] + s.license = ObjectiveJ::License::LGPL_v2_1 + s.build_path = File.join($BUILD_DIR, 'Debug', 'blend') + s.intermediates_path = File.join($BUILD_DIR, 'blend.build', 'Debug') + s.flag = 'DEBUG' +end + +bundle Specs[:blendDebug], :blendDebug + +# Release Framework +Specs[:blendRelease] = ObjectiveJ::BundleSpecification.new do |s| + s.name = 'blend' + s.identifier = 'com.280n.blend' + s.version = '0.6.5' + s.author = '280 North, Inc.' + s.email = 'feedback @nospam@ 280north.com' + s.summary = 'blend classes for Cappuccino' + s.sources = FileList['**/*.j'] + s.resources = FileList['Resources/*'] + s.license = ObjectiveJ::License::LGPL_v2_1 + s.build_path = File.join($BUILD_DIR, 'Release', 'blend') + s.intermediates_path = File.join($BUILD_DIR, 'blend.build', 'Release') +end + +bundle Specs[:blendRelease], :blendRelease + +#executable in environment directory +file_d $ENVIRONMENT_BIN_PRODUCT do + make_objj_executable($ENVIRONMENT_BIN_PRODUCT) +end + +file_d $ENVIRONMENT_LIB_PRODUCT => [$PRODUCT] do + cp_r(Specs[$PRODUCT.to_sym].build_path, $ENVIRONMENT_LIB_PRODUCT) +end diff --git a/AppKit/Tools/rakefile b/AppKit/Tools/rakefile new file mode 100644 index 000000000..843707f53 --- /dev/null +++ b/AppKit/Tools/rakefile @@ -0,0 +1,13 @@ +#!/usr/bin/env ruby + +require 'rake' +require '../../common' + + +subprojects = %w{BlendKit blend} + +%w(build clean).each do |task_name| + task task_name do + subrake(subprojects) + end +end diff --git a/AppKit/rakefile b/AppKit/rakefile index 13fe5b1c0..b34898877 100644 --- a/AppKit/rakefile +++ b/AppKit/rakefile @@ -9,11 +9,15 @@ require 'objective-j/bundle' $PRODUCT = 'AppKit' + $CONFIGURATION $ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'AppKit') +subprojects = %w{Tools} + +subrake(subprojects) + task :build => [$PRODUCT, $ENVIRONMENT_PRODUCT] Specs = {} -AppKitFiles = FileList['**/*.j'].exclude('CoreGraphics/CGContextCanvas.j', 'CoreGraphics/CGContextVML.j', 'Themes/**') +AppKitFiles = FileList['**/*.j'].exclude('CoreGraphics/CGContextCanvas.j', 'CoreGraphics/CGContextVML.j', 'Themes/**', 'Tools/**') # Debug Framework Specs[:AppKitDebug] = ObjectiveJ::BundleSpecification.new do |s| diff --git a/Objective-J/Runtime/file.js b/Objective-J/Runtime/file.js index d495a4deb..fefdf1aec 100644 --- a/Objective-J/Runtime/file.js +++ b/Objective-J/Runtime/file.js @@ -39,8 +39,8 @@ var objj_files = { }, var OBJJ_NO_FILE = {}; -if (!window.OBJJ_INCLUDE_PATHS) - var OBJJ_INCLUDE_PATHS = ["Frameworks", "SomethingElse"]; +if (typeof OBJJ_INCLUDE_PATHS === "undefined") + OBJJ_INCLUDE_PATHS = ["Frameworks", "SomethingElse"]; var OBJJ_BASE_URI = ""; @@ -127,7 +127,7 @@ objj_search.prototype.attemptNextSearchPath = function() { var searchPath = this.nextSearchPath(), file = objj_files[searchPath]; - + objj_alert("Will attempt to find " + this.filePath + " at " + searchPath); // If a file for this search path already exists, then it has already been downloaded. @@ -150,7 +150,7 @@ objj_search.prototype.attemptNextSearchPath = function() } var existingSearch = objj_searches[searchPath]; - + // If there is already an ongoing search for this search path, then we can let it find // the file for us. Make sure to assign it our callback, if we have one, since only // one search can have a callback at a time. diff --git a/Objective-J/Tools/objj/main.js b/Objective-J/Tools/objj/main.js index 9db3b3284..d4d1ba9d4 100644 --- a/Objective-J/Tools/objj/main.js +++ b/Objective-J/Tools/objj/main.js @@ -17,12 +17,11 @@ if (!this.objj_import) load(OBJJ_LIB+'/Frameworks-Rhino/Objective-J/Objective-J.js'); } */ -OBJJ_INCLUDE_PATHS = []; var OBJJ_INCLUDE_PATHS_STRING = getenv("OBJJ_INCLUDE_PATHS"); if (OBJJ_INCLUDE_PATHS_STRING) - OBJJ_INCLUDE_PATHS = OBJJ_INCLUDE_PATHS.concat(OBJJ_INCLUDE_PATHS_STRING.split(":")); + OBJJ_INCLUDE_PATHS = OBJJ_INCLUDE_PATHS_STRING.split(":").concat(OBJJ_INCLUDE_PATHS); try { @@ -35,7 +34,7 @@ try args[count] = String(args[count]); while (args.length && args[0].indexOf('-I') === 0) - OBJJ_INCLUDE_PATHS = OBJJ_INCLUDE_PATHS.concat(args.shift().substr(2).split(':')) + OBJJ_INCLUDE_PATHS = args.shift().substr(2).split(':').concat(OBJJ_INCLUDE_PATHS); } if (args.length > 0) diff --git a/Rake/Resources/objj-executable b/Rake/Resources/objj-executable index 7465df500..451929d45 100755 --- a/Rake/Resources/objj-executable +++ b/Rake/Resources/objj-executable @@ -24,7 +24,7 @@ #fi OBJJ_LIB="$OBJJ_HOME/lib" - +FRAMEWORKS="$OBJJ_HOME/lib/Frameworks" MAIN="$OBJJ_LIB/$(basename $SELF_PATH)/main.j" # convert paths for Cygwin @@ -33,4 +33,4 @@ if [[ `uname` == CYGWIN* ]]; then BAKE=`cygpath -w "$BLEND"` fi -objj $MAIN $@ +objj -I$FRAMEWORKS $MAIN $@ From 409fab31e60d1b5e0e31bd8cf99881c416978271 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Mon, 16 Mar 2009 00:39:28 -0700 Subject: [PATCH 45/62] Added beginnings of bundle app. Reviewed by me. --- Objective-J/{Runtime => }/Object.j | 0 Objective-J/Runtime/build.xml | 64 ------ Objective-J/Runtime/rakefile | 65 ------ Objective-J/Tools/bundle/main.js | 253 ++++++++++++++++++++++++ Objective-J/Tools/bundle/rakefile | 31 +++ Objective-J/Tools/rakefile | 2 +- Objective-J/{Runtime => }/bootstrap.js | 0 Objective-J/build.xml | 73 +++++-- Objective-J/{Runtime => }/constants.js | 0 Objective-J/{Runtime => }/debug.js | 0 Objective-J/{Runtime => }/dictionary.js | 0 Objective-J/{Runtime => }/evaluate.js | 0 Objective-J/{Runtime => }/exception.js | 0 Objective-J/{Runtime => }/file.js | 0 Objective-J/{Runtime => }/license.txt | 0 Objective-J/{Runtime => }/plist.js | 0 Objective-J/{Runtime => }/preprocess.js | 0 Objective-J/rakefile | 61 +++++- Objective-J/{Runtime => }/runtime.js | 0 Objective-J/{Runtime => }/utilities.js | 0 Rake/objective-j.rb | 15 +- 21 files changed, 408 insertions(+), 156 deletions(-) rename Objective-J/{Runtime => }/Object.j (100%) delete mode 100644 Objective-J/Runtime/build.xml delete mode 100644 Objective-J/Runtime/rakefile create mode 100644 Objective-J/Tools/bundle/main.js create mode 100644 Objective-J/Tools/bundle/rakefile rename Objective-J/{Runtime => }/bootstrap.js (100%) rename Objective-J/{Runtime => }/constants.js (100%) rename Objective-J/{Runtime => }/debug.js (100%) rename Objective-J/{Runtime => }/dictionary.js (100%) rename Objective-J/{Runtime => }/evaluate.js (100%) rename Objective-J/{Runtime => }/exception.js (100%) rename Objective-J/{Runtime => }/file.js (100%) rename Objective-J/{Runtime => }/license.txt (100%) rename Objective-J/{Runtime => }/plist.js (100%) rename Objective-J/{Runtime => }/preprocess.js (100%) rename Objective-J/{Runtime => }/runtime.js (100%) rename Objective-J/{Runtime => }/utilities.js (100%) diff --git a/Objective-J/Runtime/Object.j b/Objective-J/Object.j similarity index 100% rename from Objective-J/Runtime/Object.j rename to Objective-J/Object.j diff --git a/Objective-J/Runtime/build.xml b/Objective-J/Runtime/build.xml deleted file mode 100644 index 4084587f5..000000000 --- a/Objective-J/Runtime/build.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Objective-J/Runtime/rakefile b/Objective-J/Runtime/rakefile deleted file mode 100644 index 84b542598..000000000 --- a/Objective-J/Runtime/rakefile +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env ruby - -require 'rake' -require '../../common' -require 'objective-j' - - -$PRODUCT = File.join($PRODUCT_DIR, 'Objective-J') -$ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J') - -$LICENSE_FILE = File.join($PRODUCT, 'LICENSE') -$BROWSER_FILE = File.join($PRODUCT, 'Objective-J.js') -$RHINO_FILE = File.join($PRODUCT, 'Rhino.platform', 'Objective-J.js') - -task :Products => [$BROWSER_FILE, $RHINO_FILE] - -task :build => [:Products, $ENVIRONMENT_PRODUCT] - -=begin -task :environment => [$PRODUCT_FILE, $LICENSE_FILE, ENVIRONMENT_FRAMEWORKS_DIR] do - cp_r($BUILD_PRODUCT_DIR, ENVIRONMENT_FRAMEWORKS_DIR) -end -=end -Files = [ 'LICENSE.txt', - 'constants.js', - 'utilities.js', - 'runtime.js', - 'dictionary.js', - 'plist.js', - 'file.js', - 'exception.js', - 'preprocess.js', - 'evaluate.js', - 'debug.js', - 'bootstrap.js']; - -file_d $BROWSER_FILE => Files do |t| - build_product(t.name) -end - -file_d $RHINO_FILE => Files do |t| - build_product(t.name) -end - -#Framework in environment directory -file_d $ENVIRONMENT_PRODUCT => [:Products] do - cp_r($PRODUCT, $ENVIRONMENT_PRODUCT) -end - -def build_product(path, *flags) - - IO.popen("gcc -E -x c -P -", "w+") do |preprocessor| - - Files.select { |name| name.match(/\.js$/) }.each do |fileName| - preprocessor.puts IO.read(fileName) - end - - preprocessor.close_write - - File.open(path, "w") do |file| - file.write(IO.read("LICENSE.txt") + preprocessor.read) - end - - end -end diff --git a/Objective-J/Tools/bundle/main.js b/Objective-J/Tools/bundle/main.js new file mode 100644 index 000000000..168661523 --- /dev/null +++ b/Objective-J/Tools/bundle/main.js @@ -0,0 +1,253 @@ + +importPackage(java.lang); + +importClass(java.io.File); +importClass(java.io.BufferedReader); +importClass(java.io.FileReader); +importClass(java.io.BufferedWriter); +importClass(java.io.FileWriter); + + +function main() +{ + var index = 0, + count = arguments.length, + bundlePath = NULL; + + for (; index < count; ++index) + bundlePath = arguments[index]; +alert(bundlePath) + var bundleFile = new File(bundlePath).getCanonicalFile(), + bundlePath = String(bundleFile.getCanonicalPath()), + inlinedBundle = readBundle(bundleFile, true), + inlinedFiles = [], + replacedFiles = [], + staticContent = ""; + + // Find all internal bundles. + var bundleCandidates = getFiles(bundleFile, "plist"), + bundleCandidatesCount = bundleCandidates.length; + + while (bundleCandidatesCount--) + { + var bundleCandidate = bundleCandidates[bundleCandidatesCount]; + + // We only care about Info.plists, specifically the ones that aren't us. + if (String(bundleCandidate.getName()) !== "Info.plist" || String(bundleCandidate.getCanonicalPath()) === inlinedBundle.path) + continue; + + var infoDictionary = readPlist(bundleCandidate); + + // At least one of these two has to be present for this to be a real deal bundle. + if (!dictionary_getValue(infoDictionary, "CPBundleIdentifier") && !dictionary_getValue(infoDictionary, "CPBundleName")) + continue; + + java.lang.System.out.println(" Examining " + pathRelativeTo(bundleCandidate.getCanonicalPath(), bundlePath)); + + dictionary_removeValue(infoDictionary, "CPBundleExecutable"); + + var bundle = readBundle(bundleCandidate.getParentFile(), true); + + bundle.path = pathRelativeTo(bundle.path, bundlePath); + + // We want to inline the info plist too. + var inlinedFiles = [makeOBJJPlistFile(infoDictionary, bundleCandidate, bundle)].concat(bundle.files), + index = 0, + count = inlinedFiles.length; + + for (; index < count; ++index) + { + var file = inlinedFiles[index]; + + file.path = pathRelativeTo(String(file.path), bundlePath); + + java.lang.System.out.println(" Inlining " + file.path); + + replacedFiles.push(file.path); + staticContent += fileToMarkedString(inlinedFiles[index], true); + } + } + + var index = 0, + existingStaticFiles = inlinedBundle.files, + count = existingStaticFiles.length, + topLevelContent = "@STATIC;1.0;"; + + for (; index < count; ++index) + { + var file = existingStaticFiles[index]; + + // If this isn't actually part of our bundle, drop it! + if (file.bundle !== inlinedBundle) + continue; + + file.path = pathRelativeTo(String(file.path), bundlePath); + + replacedFiles.push(file.path); + topLevelContent += fileToMarkedString(file, false); + } + + dictionary_setValue(inlinedBundle.info, "CPBundleReplacedFiles", replacedFiles); + + writeContentsToFile(CPPropertyListCreateXMLData(inlinedBundle.info).string, inlinedBundle.path); + writeContentsToFile(topLevelContent + staticContent, inlinedBundle._staticContentPath); +} + +function fileToMarkedString(anOBJJFile, encodeBundle) +{ + var markedString = ""; + + markedString += MARKER_PATH + ';' + anOBJJFile.path.length + ';' + anOBJJFile.path; + + if (encodeBundle) + markedString += MARKER_BUNDLE + ';' + anOBJJFile.bundle.path.length + ';' + anOBJJFile.bundle.path; + + var fragments = anOBJJFile.fragments; + + if (fragments && fragments.length > 0) + { + var fragmentIndex = 0, + fragmentCount = fragments.length; + + for (; fragmentIndex < fragmentCount; ++fragmentIndex) + markedString += fragments[fragmentIndex].toMarkedString(); + } + + else + markedString += MARKER_TEXT + ';' + anOBJJFile.contents.length + ';' + anOBJJFile.contents; + + return markedString; +} + +function makeOBJJPlistFile(aDictionary, aFile, aBundle) +{ + var file = new objj_file(); + + file.path = typeof aFile === "string" ? aFile : aFile.getCanonicalPath(); + file.bundle = aBundle; + file.contents = CPPropertyListCreate280NorthData(aDictionary).string; + + return file; +} + +function pathRelativeTo(target, relativeTo) +{ + var components = [], + targetParts = target.split("/"), + relativeParts = relativeTo ? relativeTo.split("/") : []; + + var i = 0; + while (i < targetParts.length) + { + if (targetParts[i] != relativeParts[i]) + break; + i++; + } + + for (var j = i; j < relativeParts.length; j++) + components.push(".."); + + for (var j = i; j < targetParts.length; j++) + components.push(targetParts[j]); + + var result = components.join("/"); + + return result; +} + +function readPlist(/*File*/ aFile) +{ + var fileContents = readFile(aFile); + + var data = new objj_data(); + data.string = fileContents; + + return new CPPropertyListCreateFromData(data); +} + +function readBundle(/*File*/ aFile, /*Boolean*/ shouldDecompile) +{ + var bundlePath = typeof aFile === "string" ? new File(aFile).getCanonicalPath() : aFile.getCanonicalPath(), + infoPath = bundlePath + "/Info.plist"; + + //err + var bundle = new objj_bundle(); + + bundle.path = infoPath; + bundle.info = readPlist(infoPath); + bundle._staticFilePaths = dictionary_getValue(bundle.info, "CPBundleReplacedFiles"); + + if (bundle._staticFilePaths.length) + { + bundle._staticContentPath = staticContentPath = bundlePath + '/' + dictionary_getValue(bundle.info, "CPBundleExecutable"); + + //err + + bundle._staticContent = readFile(staticContentPath); + + if (shouldDecompile) + bundle.files = objj_decompile(bundle._staticContent, bundle); + } + else + bundle._staticContent = ""; + + return bundle; +} + +function getFiles(/*File*/ sourceDirectory, /*nil|String|Array*/ extensions, /*Array*/ exclusions) +{ + var matches = [], + files = sourceDirectory.listFiles(), + hasMultipleExtensions = typeof extensions !== "string"; + + if (files) + { + var index = 0, + count = files.length; + + for (; index < count; ++index) + { + var file = files[index].getCanonicalFile(), + name = String(file.getName()), + isValidExtension = !extensions; + + if (exclusions && fileArrayContainsFile(exclusions, file)) + continue; + + if (!isValidExtension) + if (hasMultipleExtensions) + { + var extensionCount = extensions.length; + + while (extensionCount-- && !isValidExtension) + { + var extension = extensions[extensionCount]; + + if (name.substring(name.length - extension.length - 1) === ("." + extension)) + isValidExtension = true; + } + } + else if (name.substring(name.length - extensions.length - 1) === ("." + extensions)) + isValidExtension = true; + + if (isValidExtension) + matches.push(file); + + if (file.isDirectory()) + matches = matches.concat(getFiles(file, extensions, exclusions)); + } + } + + return matches; +} + +function writeContentsToFile(/*String*/ contents, /*File*/ aFile) +{ + var writer = new BufferedWriter(new FileWriter(aFile)); + + writer.write(contents); + + writer.close(); +} + +main.apply(main, arguments); diff --git a/Objective-J/Tools/bundle/rakefile b/Objective-J/Tools/bundle/rakefile new file mode 100644 index 000000000..efecda507 --- /dev/null +++ b/Objective-J/Tools/bundle/rakefile @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +require 'rake' +require '../../../common' +require 'objective-j' + + +$BUNDLE_SCRIPT = File.join($BUILD_DIR, 'bundle.build', $CONFIGURATION, 'main-concat.js') +$BUNDLE_CLASS = File.join($ENVIRONMENT_LIB_DIR, 'bundle', 'main.class') +$BUNDLE_EXECUTABLE = File.join($ENVIRONMENT_BIN_DIR, 'bundle') +$STANDARD_EXECUTABLE = File.expand_path(File.join('..', 'executable')) + +task :build => [$BUNDLE_CLASS, $BUNDLE_EXECUTABLE] + +Files = [ File.join($HOME_DIR, 'Tools', 'Utilities', 'bridge.js'), #yuck! + File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J', 'Rhino.platform', 'Objective-J.js'), + 'main.js']; + +file_d $BUNDLE_EXECUTABLE => [$STANDARD_EXECUTABLE] do + cp($STANDARD_EXECUTABLE, $BUNDLE_EXECUTABLE) + File.chmod 0755, $BUNDLE_EXECUTABLE +end + +file_d $BUNDLE_SCRIPT => Files do |t| + cat(Files, $BUNDLE_SCRIPT) +end + +file_d $BUNDLE_CLASS => $BUNDLE_SCRIPT do |t| + js2java($BUNDLE_SCRIPT, 'main.class', false) + cp(File.join(File.dirname($BUNDLE_SCRIPT), 'main.class'), $BUNDLE_CLASS) +end diff --git a/Objective-J/Tools/rakefile b/Objective-J/Tools/rakefile index caa3700a6..40a27a38b 100644 --- a/Objective-J/Tools/rakefile +++ b/Objective-J/Tools/rakefile @@ -4,7 +4,7 @@ require 'rake' require '../../common' -subprojects = %w{cplutil objj objjc} +subprojects = %w{bundle cplutil objj objjc} %w(build clean).each do |task_name| task task_name do diff --git a/Objective-J/Runtime/bootstrap.js b/Objective-J/bootstrap.js similarity index 100% rename from Objective-J/Runtime/bootstrap.js rename to Objective-J/bootstrap.js diff --git a/Objective-J/build.xml b/Objective-J/build.xml index 9e1a1bd0f..4084587f5 100644 --- a/Objective-J/build.xml +++ b/Objective-J/build.xml @@ -1,27 +1,64 @@ - + - + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/Objective-J/Runtime/constants.js b/Objective-J/constants.js similarity index 100% rename from Objective-J/Runtime/constants.js rename to Objective-J/constants.js diff --git a/Objective-J/Runtime/debug.js b/Objective-J/debug.js similarity index 100% rename from Objective-J/Runtime/debug.js rename to Objective-J/debug.js diff --git a/Objective-J/Runtime/dictionary.js b/Objective-J/dictionary.js similarity index 100% rename from Objective-J/Runtime/dictionary.js rename to Objective-J/dictionary.js diff --git a/Objective-J/Runtime/evaluate.js b/Objective-J/evaluate.js similarity index 100% rename from Objective-J/Runtime/evaluate.js rename to Objective-J/evaluate.js diff --git a/Objective-J/Runtime/exception.js b/Objective-J/exception.js similarity index 100% rename from Objective-J/Runtime/exception.js rename to Objective-J/exception.js diff --git a/Objective-J/Runtime/file.js b/Objective-J/file.js similarity index 100% rename from Objective-J/Runtime/file.js rename to Objective-J/file.js diff --git a/Objective-J/Runtime/license.txt b/Objective-J/license.txt similarity index 100% rename from Objective-J/Runtime/license.txt rename to Objective-J/license.txt diff --git a/Objective-J/Runtime/plist.js b/Objective-J/plist.js similarity index 100% rename from Objective-J/Runtime/plist.js rename to Objective-J/plist.js diff --git a/Objective-J/Runtime/preprocess.js b/Objective-J/preprocess.js similarity index 100% rename from Objective-J/Runtime/preprocess.js rename to Objective-J/preprocess.js diff --git a/Objective-J/rakefile b/Objective-J/rakefile index 4631e50dd..ceb53bde6 100644 --- a/Objective-J/rakefile +++ b/Objective-J/rakefile @@ -2,12 +2,63 @@ require 'rake' require '../common' +require 'objective-j' -subprojects = %w{Runtime Tools} +$PRODUCT = File.join($PRODUCT_DIR, 'Objective-J') +$ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J') -%w(build clean).each do |task_name| - task task_name do - subrake(subprojects) - end +$LICENSE_FILE = File.join($PRODUCT, 'LICENSE') +$BROWSER_FILE = File.join($PRODUCT, 'Objective-J.js') +$RHINO_FILE = File.join($PRODUCT, 'Rhino.platform', 'Objective-J.js') + +task :Products => [$BROWSER_FILE, $RHINO_FILE] + +task :build => [:Products, $ENVIRONMENT_PRODUCT, :Tools] + +task :Tools => [:Products] do + subrake(%w{Tools}) +end + +Files = [ 'LICENSE.txt', + 'constants.js', + 'utilities.js', + 'runtime.js', + 'dictionary.js', + 'plist.js', + 'file.js', + 'exception.js', + 'preprocess.js', + 'evaluate.js', + 'debug.js', + 'bootstrap.js']; + +file_d $BROWSER_FILE => Files do |t| + build_product(t.name) +end + +file_d $RHINO_FILE => Files do |t| + build_product(t.name, 'RHINO') +end + +#Framework in environment directory +file_d $ENVIRONMENT_PRODUCT => [:Products] do + cp_r($PRODUCT, $ENVIRONMENT_PRODUCT) +end + +def build_product(path, *flags) + + IO.popen("gcc #{resolve_flags(flags)} -E -x c -P -", "w+") do |preprocessor| + + Files.select { |name| name.match(/\.js$/) }.each do |fileName| + preprocessor.puts IO.read(fileName) + end + + preprocessor.close_write + + File.open(path, "w") do |file| + file.write(IO.read("LICENSE.txt") + preprocessor.read) + end + + end end diff --git a/Objective-J/Runtime/runtime.js b/Objective-J/runtime.js similarity index 100% rename from Objective-J/Runtime/runtime.js rename to Objective-J/runtime.js diff --git a/Objective-J/Runtime/utilities.js b/Objective-J/utilities.js similarity index 100% rename from Objective-J/Runtime/utilities.js rename to Objective-J/utilities.js diff --git a/Rake/objective-j.rb b/Rake/objective-j.rb index 7d41aa4b6..b09f5c5a1 100644 --- a/Rake/objective-j.rb +++ b/Rake/objective-j.rb @@ -508,17 +508,26 @@ module ObjectiveJ end def file_d(*args, &block) - - fileTask = file_create(*args, &block) + fileTask = Rake::FileTask.define_task(*args, &block) + fileDirectory = File.dirname(fileTask.name) directory fileDirectory file fileTask.name => fileDirectory - end def bundle(spec, *args, &block) task = ObjectiveJ::BundleTask.define_task(*args, &block) task.bundle_spec = spec end + +def resolve_flags(flags) + + case flags + when nil then '' + when String then '-D' + flags + when Array then flags.map { |flag| '-D' + flag }.join(' ') + when Hash then flags.map { |flag, value| '-D' + flag + '=' + value }.join(' ') + end +end From b3cc75fe4652b1d353d993a3de5008a0150c4c74 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Mon, 16 Mar 2009 07:10:42 -0700 Subject: [PATCH 46/62] Added significantly improved platform support. Reviewed by me. --- AppKit/rakefile | 5 +- Objective-J/Tools/bundle/main.js | 253 ----------------------------- Objective-J/Tools/bundle/rakefile | 31 ---- Objective-J/Tools/cplutil/rakefile | 2 +- Objective-J/Tools/objj/rakefile | 2 +- Objective-J/Tools/objjc/main.js | 2 +- Objective-J/Tools/objjc/rakefile | 2 +- Objective-J/Tools/rakefile | 2 +- Objective-J/file.js | 25 ++- Objective-J/rakefile | 12 +- Rake/objective-j.rb | 14 +- Rake/objective-j/bundle.rb | 186 ++++++++++++--------- Rake/objective-j/plist.rb | 134 --------------- 13 files changed, 159 insertions(+), 511 deletions(-) delete mode 100644 Objective-J/Tools/bundle/main.js delete mode 100644 Objective-J/Tools/bundle/rakefile delete mode 100644 Rake/objective-j/plist.rb diff --git a/AppKit/rakefile b/AppKit/rakefile index b34898877..bc6a5da6d 100644 --- a/AppKit/rakefile +++ b/AppKit/rakefile @@ -32,7 +32,8 @@ Specs[:AppKitDebug] = ObjectiveJ::BundleSpecification.new do |s| s.license = ObjectiveJ::License::LGPL_v2_1 s.build_path = File.join($BUILD_DIR, 'Debug', 'AppKit') s.intermediates_path = File.join($BUILD_DIR, 'AppKit.build', 'Debug') - s.flags = ['PLATFORM_DOM', 'DEBUG'] + s.flags = ['DEBUG'] + s.platforms = [ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::Rhino] end bundle Specs[:AppKitDebug], :AppKitDebug @@ -50,7 +51,7 @@ Specs[:AppKitRelease] = ObjectiveJ::BundleSpecification.new do |s| s.license = ObjectiveJ::License::LGPL_v2_1 s.build_path = File.join($BUILD_DIR, 'Release', 'AppKit') s.intermediates_path = File.join($BUILD_DIR, 'AppKit.build', 'Release') - s.flag = 'PLATFORM_DOM' + s.platforms = [ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::Rhino] end bundle Specs[:AppKitRelease], :AppKitRelease diff --git a/Objective-J/Tools/bundle/main.js b/Objective-J/Tools/bundle/main.js deleted file mode 100644 index 168661523..000000000 --- a/Objective-J/Tools/bundle/main.js +++ /dev/null @@ -1,253 +0,0 @@ - -importPackage(java.lang); - -importClass(java.io.File); -importClass(java.io.BufferedReader); -importClass(java.io.FileReader); -importClass(java.io.BufferedWriter); -importClass(java.io.FileWriter); - - -function main() -{ - var index = 0, - count = arguments.length, - bundlePath = NULL; - - for (; index < count; ++index) - bundlePath = arguments[index]; -alert(bundlePath) - var bundleFile = new File(bundlePath).getCanonicalFile(), - bundlePath = String(bundleFile.getCanonicalPath()), - inlinedBundle = readBundle(bundleFile, true), - inlinedFiles = [], - replacedFiles = [], - staticContent = ""; - - // Find all internal bundles. - var bundleCandidates = getFiles(bundleFile, "plist"), - bundleCandidatesCount = bundleCandidates.length; - - while (bundleCandidatesCount--) - { - var bundleCandidate = bundleCandidates[bundleCandidatesCount]; - - // We only care about Info.plists, specifically the ones that aren't us. - if (String(bundleCandidate.getName()) !== "Info.plist" || String(bundleCandidate.getCanonicalPath()) === inlinedBundle.path) - continue; - - var infoDictionary = readPlist(bundleCandidate); - - // At least one of these two has to be present for this to be a real deal bundle. - if (!dictionary_getValue(infoDictionary, "CPBundleIdentifier") && !dictionary_getValue(infoDictionary, "CPBundleName")) - continue; - - java.lang.System.out.println(" Examining " + pathRelativeTo(bundleCandidate.getCanonicalPath(), bundlePath)); - - dictionary_removeValue(infoDictionary, "CPBundleExecutable"); - - var bundle = readBundle(bundleCandidate.getParentFile(), true); - - bundle.path = pathRelativeTo(bundle.path, bundlePath); - - // We want to inline the info plist too. - var inlinedFiles = [makeOBJJPlistFile(infoDictionary, bundleCandidate, bundle)].concat(bundle.files), - index = 0, - count = inlinedFiles.length; - - for (; index < count; ++index) - { - var file = inlinedFiles[index]; - - file.path = pathRelativeTo(String(file.path), bundlePath); - - java.lang.System.out.println(" Inlining " + file.path); - - replacedFiles.push(file.path); - staticContent += fileToMarkedString(inlinedFiles[index], true); - } - } - - var index = 0, - existingStaticFiles = inlinedBundle.files, - count = existingStaticFiles.length, - topLevelContent = "@STATIC;1.0;"; - - for (; index < count; ++index) - { - var file = existingStaticFiles[index]; - - // If this isn't actually part of our bundle, drop it! - if (file.bundle !== inlinedBundle) - continue; - - file.path = pathRelativeTo(String(file.path), bundlePath); - - replacedFiles.push(file.path); - topLevelContent += fileToMarkedString(file, false); - } - - dictionary_setValue(inlinedBundle.info, "CPBundleReplacedFiles", replacedFiles); - - writeContentsToFile(CPPropertyListCreateXMLData(inlinedBundle.info).string, inlinedBundle.path); - writeContentsToFile(topLevelContent + staticContent, inlinedBundle._staticContentPath); -} - -function fileToMarkedString(anOBJJFile, encodeBundle) -{ - var markedString = ""; - - markedString += MARKER_PATH + ';' + anOBJJFile.path.length + ';' + anOBJJFile.path; - - if (encodeBundle) - markedString += MARKER_BUNDLE + ';' + anOBJJFile.bundle.path.length + ';' + anOBJJFile.bundle.path; - - var fragments = anOBJJFile.fragments; - - if (fragments && fragments.length > 0) - { - var fragmentIndex = 0, - fragmentCount = fragments.length; - - for (; fragmentIndex < fragmentCount; ++fragmentIndex) - markedString += fragments[fragmentIndex].toMarkedString(); - } - - else - markedString += MARKER_TEXT + ';' + anOBJJFile.contents.length + ';' + anOBJJFile.contents; - - return markedString; -} - -function makeOBJJPlistFile(aDictionary, aFile, aBundle) -{ - var file = new objj_file(); - - file.path = typeof aFile === "string" ? aFile : aFile.getCanonicalPath(); - file.bundle = aBundle; - file.contents = CPPropertyListCreate280NorthData(aDictionary).string; - - return file; -} - -function pathRelativeTo(target, relativeTo) -{ - var components = [], - targetParts = target.split("/"), - relativeParts = relativeTo ? relativeTo.split("/") : []; - - var i = 0; - while (i < targetParts.length) - { - if (targetParts[i] != relativeParts[i]) - break; - i++; - } - - for (var j = i; j < relativeParts.length; j++) - components.push(".."); - - for (var j = i; j < targetParts.length; j++) - components.push(targetParts[j]); - - var result = components.join("/"); - - return result; -} - -function readPlist(/*File*/ aFile) -{ - var fileContents = readFile(aFile); - - var data = new objj_data(); - data.string = fileContents; - - return new CPPropertyListCreateFromData(data); -} - -function readBundle(/*File*/ aFile, /*Boolean*/ shouldDecompile) -{ - var bundlePath = typeof aFile === "string" ? new File(aFile).getCanonicalPath() : aFile.getCanonicalPath(), - infoPath = bundlePath + "/Info.plist"; - - //err - var bundle = new objj_bundle(); - - bundle.path = infoPath; - bundle.info = readPlist(infoPath); - bundle._staticFilePaths = dictionary_getValue(bundle.info, "CPBundleReplacedFiles"); - - if (bundle._staticFilePaths.length) - { - bundle._staticContentPath = staticContentPath = bundlePath + '/' + dictionary_getValue(bundle.info, "CPBundleExecutable"); - - //err - - bundle._staticContent = readFile(staticContentPath); - - if (shouldDecompile) - bundle.files = objj_decompile(bundle._staticContent, bundle); - } - else - bundle._staticContent = ""; - - return bundle; -} - -function getFiles(/*File*/ sourceDirectory, /*nil|String|Array*/ extensions, /*Array*/ exclusions) -{ - var matches = [], - files = sourceDirectory.listFiles(), - hasMultipleExtensions = typeof extensions !== "string"; - - if (files) - { - var index = 0, - count = files.length; - - for (; index < count; ++index) - { - var file = files[index].getCanonicalFile(), - name = String(file.getName()), - isValidExtension = !extensions; - - if (exclusions && fileArrayContainsFile(exclusions, file)) - continue; - - if (!isValidExtension) - if (hasMultipleExtensions) - { - var extensionCount = extensions.length; - - while (extensionCount-- && !isValidExtension) - { - var extension = extensions[extensionCount]; - - if (name.substring(name.length - extension.length - 1) === ("." + extension)) - isValidExtension = true; - } - } - else if (name.substring(name.length - extensions.length - 1) === ("." + extensions)) - isValidExtension = true; - - if (isValidExtension) - matches.push(file); - - if (file.isDirectory()) - matches = matches.concat(getFiles(file, extensions, exclusions)); - } - } - - return matches; -} - -function writeContentsToFile(/*String*/ contents, /*File*/ aFile) -{ - var writer = new BufferedWriter(new FileWriter(aFile)); - - writer.write(contents); - - writer.close(); -} - -main.apply(main, arguments); diff --git a/Objective-J/Tools/bundle/rakefile b/Objective-J/Tools/bundle/rakefile deleted file mode 100644 index efecda507..000000000 --- a/Objective-J/Tools/bundle/rakefile +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env ruby - -require 'rake' -require '../../../common' -require 'objective-j' - - -$BUNDLE_SCRIPT = File.join($BUILD_DIR, 'bundle.build', $CONFIGURATION, 'main-concat.js') -$BUNDLE_CLASS = File.join($ENVIRONMENT_LIB_DIR, 'bundle', 'main.class') -$BUNDLE_EXECUTABLE = File.join($ENVIRONMENT_BIN_DIR, 'bundle') -$STANDARD_EXECUTABLE = File.expand_path(File.join('..', 'executable')) - -task :build => [$BUNDLE_CLASS, $BUNDLE_EXECUTABLE] - -Files = [ File.join($HOME_DIR, 'Tools', 'Utilities', 'bridge.js'), #yuck! - File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J', 'Rhino.platform', 'Objective-J.js'), - 'main.js']; - -file_d $BUNDLE_EXECUTABLE => [$STANDARD_EXECUTABLE] do - cp($STANDARD_EXECUTABLE, $BUNDLE_EXECUTABLE) - File.chmod 0755, $BUNDLE_EXECUTABLE -end - -file_d $BUNDLE_SCRIPT => Files do |t| - cat(Files, $BUNDLE_SCRIPT) -end - -file_d $BUNDLE_CLASS => $BUNDLE_SCRIPT do |t| - js2java($BUNDLE_SCRIPT, 'main.class', false) - cp(File.join(File.dirname($BUNDLE_SCRIPT), 'main.class'), $BUNDLE_CLASS) -end diff --git a/Objective-J/Tools/cplutil/rakefile b/Objective-J/Tools/cplutil/rakefile index 4e96cb871..3c90a0481 100644 --- a/Objective-J/Tools/cplutil/rakefile +++ b/Objective-J/Tools/cplutil/rakefile @@ -14,7 +14,7 @@ task :build => [$CPLUTIL_CLASS, $CPLUTIL_EXECUTABLE] Files = [ File.join($HOME_DIR, 'Tools', 'Utilities', 'bridge.js'), #yuck! File.join($HOME_DIR, 'Tools', 'Utilities', 'regex-bridge.js'), #double-yuck! - File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J', 'Rhino.platform', 'Objective-J.js'), + File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J', 'rhino.platform', 'Objective-J.js'), 'main.js']; file_d $CPLUTIL_EXECUTABLE => [$STANDARD_EXECUTABLE] do diff --git a/Objective-J/Tools/objj/rakefile b/Objective-J/Tools/objj/rakefile index 83744b388..d6c4b2f66 100644 --- a/Objective-J/Tools/objj/rakefile +++ b/Objective-J/Tools/objj/rakefile @@ -13,7 +13,7 @@ $STANDARD_EXECUTABLE = File.expand_path(File.join('..', 'executable')) task :build => [$OBJJ_CLASS, $OBJJ_EXECUTABLE] Files = [ File.join($HOME_DIR, 'Tools', 'Utilities', 'bridge.js'), #yuck! - File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J', 'Rhino.platform', 'Objective-J.js'), + File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J', 'rhino.platform', 'Objective-J.js'), 'main.js']; file_d $OBJJ_EXECUTABLE => [$STANDARD_EXECUTABLE] do diff --git a/Objective-J/Tools/objjc/main.js b/Objective-J/Tools/objjc/main.js index 2256ad544..81d62d58e 100644 --- a/Objective-J/Tools/objjc/main.js +++ b/Objective-J/Tools/objjc/main.js @@ -123,7 +123,7 @@ function preprocess(aFilePath, outFilePath, gccArgs, flags) fragments = objj_preprocess(fileContents, { path:"/x" }, {path:filePath}, flags), index = 0, count = fragments.length, - preprocessed = MARKER_PATH + ';' + filePath.length + ';' + filePath; + preprocessed = ""; // Writer preprocessed fragments out. for (; index < count; ++index) diff --git a/Objective-J/Tools/objjc/rakefile b/Objective-J/Tools/objjc/rakefile index f2edbb35f..0f701426f 100644 --- a/Objective-J/Tools/objjc/rakefile +++ b/Objective-J/Tools/objjc/rakefile @@ -15,7 +15,7 @@ task :build => [$OBJJC_CLASS, $OBJJC_EXECUTABLE, $OBJJC_JS_COMPILER] Files = [ File.join($HOME_DIR, 'Tools', 'Utilities', 'bridge.js'), #yuck! File.join($HOME_DIR, 'Tools', 'Utilities', 'regex-bridge.js'), #double-yuck! - File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J', 'Rhino.platform', 'Objective-J.js'), + File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J', 'rhino.platform', 'Objective-J.js'), 'main.js']; file_d $OBJJC_EXECUTABLE => [$STANDARD_EXECUTABLE] do diff --git a/Objective-J/Tools/rakefile b/Objective-J/Tools/rakefile index 40a27a38b..caa3700a6 100644 --- a/Objective-J/Tools/rakefile +++ b/Objective-J/Tools/rakefile @@ -4,7 +4,7 @@ require 'rake' require '../../common' -subprojects = %w{bundle cplutil objj objjc} +subprojects = %w{cplutil objj objjc} %w(build clean).each do |task_name| task task_name do diff --git a/Objective-J/file.js b/Objective-J/file.js index fefdf1aec..716b5e5af 100644 --- a/Objective-J/file.js +++ b/Objective-J/file.js @@ -27,6 +27,7 @@ // Look inside bundleResponseCallback. +OBJJ_PLATFORMS = PLATFORMS #define DIRECTORY(aPath) (aPath).substr(0, (aPath).lastIndexOf('/') + 1) OBJJFileNotFoundException = "OBJJFileNotFoundException"; @@ -364,6 +365,28 @@ objj_search.prototype.didReceiveBundleResponse = function(aResponse) if (executablePath) { + var platform = NULL, + platforms = dictionary_getValue(bundle.info, "CPBundlePlatforms"), + index = 0, + count = OBJJ_PLATFORMS.length, + inner_count = platforms.length; + + // Ugh, no indexOf, no objects-in-common. + for(; index < count; ++index) + { + var innerIndex = 0, + currentPlatform = OBJJ_PLATFORMS[index]; + + for (; innerIndex < inner_count; ++innerIndex) + if(OBJJ_PLATFORMS[index] === platforms[innerIndex]) + { + platform = currentPlatform; + break; + } + } + + executablePath = platform + ".platform/" + executablePath; + this.request(DIRECTORY(aResponse.filePath) + executablePath, this.didReceiveExecutableResponse); // FIXME: Is this the right approach? @@ -581,7 +604,7 @@ function objj_decompile(aString, bundle) { case MARKER_PATH: if (file && file.contents && file.path === file.bundle.path) file.bundle.info = CPPropertyListCreateWithData({string:file.contents}); - + file = new objj_file(); file.path = DIRECTORY(bundle.path) + text; file.bundle = bundle; diff --git a/Objective-J/rakefile b/Objective-J/rakefile index ceb53bde6..3b48c3e7a 100644 --- a/Objective-J/rakefile +++ b/Objective-J/rakefile @@ -10,7 +10,7 @@ $ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Objective-J') $LICENSE_FILE = File.join($PRODUCT, 'LICENSE') $BROWSER_FILE = File.join($PRODUCT, 'Objective-J.js') -$RHINO_FILE = File.join($PRODUCT, 'Rhino.platform', 'Objective-J.js') +$RHINO_FILE = File.join($PRODUCT, 'rhino.platform', 'Objective-J.js') task :Products => [$BROWSER_FILE, $RHINO_FILE] @@ -34,11 +34,11 @@ Files = [ 'LICENSE.txt', 'bootstrap.js']; file_d $BROWSER_FILE => Files do |t| - build_product(t.name) + build_product(t.name, platform_flags(ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::ObjJ)) end file_d $RHINO_FILE => Files do |t| - build_product(t.name, 'RHINO') + build_product(t.name, platform_flags(ObjectiveJ::Platform::Rhino, ObjectiveJ::Platform::ObjJ)) end #Framework in environment directory @@ -46,7 +46,11 @@ file_d $ENVIRONMENT_PRODUCT => [:Products] do cp_r($PRODUCT, $ENVIRONMENT_PRODUCT) end -def build_product(path, *flags) +def platform_flags(*platforms) + return { 'PLATFORMS' => ('"[' + platforms.uniq.map { |platform| '\"' + platform + '\"' }.join(', ') + ']"') } +end + +def build_product(path, flags) IO.popen("gcc #{resolve_flags(flags)} -E -x c -P -", "w+") do |preprocessor| diff --git a/Rake/objective-j.rb b/Rake/objective-j.rb index b09f5c5a1..4e78133a2 100644 --- a/Rake/objective-j.rb +++ b/Rake/objective-j.rb @@ -1,12 +1,18 @@ require 'rake' require 'date' +require 'plist' module ObjectiveJ class Platform - OBJJ = 'objj' - RHINO = 'rhino' - BROWSER = 'browser' + ObjJ = 'objj' + + Rhino = 'rhino' + Desktop = 'desktop' + Browser = 'browser' + BrowserDesktop = 'browser-desktop' + BrowserIPhone = 'browser-iphone' + BrowseriPhone = 'browser-iphone' end ## @@ -197,6 +203,7 @@ module ObjectiveJ attribute :date required_attribute :summary required_attribute :identifier + required_attribute :platforms, [Platform::ObjJ] read_only :specification_version @@ -224,6 +231,7 @@ module ObjectiveJ # attribute_alias_singular :executable, :executables attribute_alias_singular :author, :authors attribute_alias_singular :flag, :flags + attribute_alias_singular :platform, :platforms # attribute_alias_singular :require_path, :require_paths # attribute_alias_singular :test_file, :test_files diff --git a/Rake/objective-j/bundle.rb b/Rake/objective-j/bundle.rb index fb0ced840..95e49a0de 100644 --- a/Rake/objective-j/bundle.rb +++ b/Rake/objective-j/bundle.rb @@ -1,43 +1,29 @@ require 'rake' -require 'objective-j/plist' + + module ObjectiveJ - # Create a package based upon a Gem spec. Gem packages, as well as - # zip files and tar/gzipped packages can be produced by this task. - # - # In addition to the Rake targets generated by PackageTask, a - # GemPackageTask will also generate the following tasks: - # - # ["package_dir/name-version.gem"] - # Create a Ruby GEM package with the given name and version. - # - # Example using a Ruby GEM spec: - # - # require 'rubygems' - # - # spec = Gem::Specification.new do |s| - # s.platform = Gem::Platform::RUBY - # s.summary = "Ruby based make-like utility." - # s.name = 'rake' - # s.version = PKG_VERSION - # s.requirements << 'none' - # s.require_path = 'lib' - # s.autorequire = 'rake' - # s.files = PKG_FILES - # s.description = < 'objj.platform', + Platform::Rhino => 'rhino.platform', + Platform::Browser => 'browser.platform', + Platform::BrowserDesktop => 'browser-desktop.platform', + Platform::BrowserIPhone => 'browser-iphone.platform' + } + + PLATFORM_FLAGS = + { + Platform::ObjJ => [], + Platform::Rhino => ['PLATFORM_RHINO'], + Platform::Browser => ['PLATFORM_BROWSER', 'PLATFORM_DOM'], + Platform::BrowserDesktop => ['PLATFORM_BROWSER', 'PLATFORM_DOM', 'PLATFORM_DESKTOP'], + Platform::BrowserIPhone => ['PLATFORM_BROWSER', 'PLATFORM_DOM', 'PLATFORM_IPHONE', 'PLATFORM_MOBILE'] + } + # Objective-J Bundle spec containing the metadata for this bundle. attr_accessor :bundle_spec @@ -67,33 +53,48 @@ module ObjectiveJ copied_resources << copied_resource end - objects_path = @bundle_spec.intermediates_path - objects = [] - replaced_files = [] - - # create file tasks for object files - @bundle_spec.sources.each do |source| - - object_path = File.join(objects_path, File.basename(source, File.extname(source))) + '.o' - flags = [] - - @bundle_spec.flags.each do |flag| - flags << '-D' + flag + info_plist_path = @bundle_spec.build_path + '/Info.plist' + info_plist = @bundle_spec.info_plist + + info_plist['CPBundlePlatforms'] = @bundle_spec.platforms; + + file_d info_plist_path do + File.open(info_plist_path, 'w') do |file| + file.puts info_plist.to_plist end - - file_d object_path => source do - IO.popen("objjc #{flags.join(' ')} #{source} -o #{object_path}") do |objjc| - puts objjc.read - end - end - - objects << object_path - replaced_files << File.basename(source) end - #the actual executable path - executable_path = File.join(@bundle_spec.build_path, @bundle_spec.name + '.sj') + preprocessed_files = [] + # create file tasks for object files + @bundle_spec.platforms.uniq.each do |platform| + + executable_path = File.join(@bundle_spec.build_path, PLATFORM_DIRECTORIES[platform], @bundle_spec.name + '.sj') + enhance([executable_path]) + + file_d executable_path do + BundleTask.compact(@bundle_spec.build_path) + end + + # Yes its unfortunate that we need to regenerate the whole executable if the Info.plist changes. Oh well. + file_d executable_path => info_plist_path + + @bundle_spec.sources.each do |source| + + preprocessed_file = File.join(@bundle_spec.build_path, PLATFORM_DIRECTORIES[platform], File.basename(source)) + + file_d preprocessed_file => source do + IO.popen("objjc #{resolve_flags(@bundle_spec.flags)} #{resolve_flags(PLATFORM_FLAGS[platform])} #{source} -o #{preprocessed_file}") do |objjc| + puts objjc.read + end + end + + preprocessed_files << preprocessed_file + + file_d executable_path => preprocessed_file + end + end + # copy license file license_path = nil @@ -108,39 +109,68 @@ module ObjectiveJ else license_path = license end - - file_d executable_path => copied_license file_d copied_license => license_path do cp(license_path, copied_license) end end + + enhance(preprocessed_files + copied_resources + [info_plist_path]) + end + + def BundleTask.compact(path, *patterns) + + puts 'Compacting ' + path - file executable_path => objects do - - File.open(executable_path, "w") do |file| - - file.write('@STATIC;1.0;') + info_plist_path = File.join(path, 'Info.plist') + info_plist = Plist::parse_xml(info_plist_path) + + absolute_path = File.expand_path(path) + '/' + + patterns = patterns.map { |pattern| "#{path}/#{pattern}" } + + bundle_name = info_plist['CPBundleName'] + replaced_files = [] + + FileList.new(File.join(path, '**', '*.platform')).each do |platform| + + FileList.new(File.join(platform, '*.j')) do |list| - objects.each do |object| - file.write(IO.read(object)) - end + list.include(*patterns) + + executable_path = File.join(platform, bundle_name) + '.sj' + platform_absolute_path = File.expand_path(platform) + '/' + + File.open(executable_path, 'w+') do |executable| + + executable.write '@STATIC;1.0;' + + list.each do |fileName| + + File.open(fileName) do |file| + + if fileName.index(platform_absolute_path) == 0 + fileName = File.expand_path(fileName)[platform_absolute_path.length..-1] + else + fileName = File.expand_path(fileName)[absolute_path.length..-1] + end + + executable.write "p;#{fileName.length};#{fileName}#{file.read}" + + replaced_files << fileName + end + end + end end end - info_plist_path = @bundle_spec.build_path + '/Info.plist' - info_plist = @bundle_spec.info_plist + info_plist['CPBundleReplacedFiles'] = replaced_files.uniq + info_plist['CPBundleExecutable'] = bundle_name + '.sj' - info_plist['CPBundleExecutable'] = File.basename(executable_path) - info_plist['CPBundleReplacedFiles'] = replaced_files - - file_d info_plist_path do - File.open(info_plist_path, 'w') do |file| - file.puts info_plist.to_plist - end + File.open(info_plist_path, 'w') do |file| + file.puts info_plist.to_plist end - - enhance(copied_resources + [executable_path, info_plist_path]) + end end end diff --git a/Rake/objective-j/plist.rb b/Rake/objective-j/plist.rb deleted file mode 100644 index d993be27a..000000000 --- a/Rake/objective-j/plist.rb +++ /dev/null @@ -1,134 +0,0 @@ -require 'rake' - -module ObjectiveJ - PLIST_START = ' - -' - PLIST_END = '' -end - -class Module - - def objj_extension(method) - - if instance_methods.include?(method) - $stderr.puts "WARNING: Possible conflict with Objective-J extension: #{self}##{method} already exists" - else - yield - end - end - -end - -class Array - - objj_extension('to_plist') do - def to_plist(start = true) - - str = '' - - each do |value| - str += value.to_plist(false) - end - - str = str + '' - str = ObjectiveJ::PLIST_START + str + ObjectiveJ::PLIST_END if start - - return str - end - end -end - -class FalseClass - - objj_extension('to_plist') do - def to_plist(start = true) - - str = '' - str = ObjectiveJ::PLIST_START + str + ObjectiveJ::PLIST_END if start - - return str - end - end -end - -class Float - - objj_extension('to_plist') do - def to_plist(start = true) - - str = '' + to_s + '' - str = ObjectiveJ::PLIST_START + str + ObjectiveJ::PLIST_END if start - - return str - end - end -end - -class Hash - - objj_extension('to_plist') do - def to_plist(start = true) - - str = '' - - each do |key, value| - str += '' + key.html_encode + '' + value.to_plist(false) - end - - str += '' - str = ObjectiveJ::PLIST_START + str + ObjectiveJ::PLIST_END if start - - return str - end - end -end - -class Integer - - objj_extension('to_plist') do - def to_plist(start = true) - - str = '' + to_s + '' - str = ObjectiveJ::PLIST_START + str + ObjectiveJ::PLIST_END - - return str - end - end -end - -class String - - objj_extension('to_plist') do - def to_plist(start = true) - - str = '' + html_encode + '' - str = ObjectiveJ::PLIST_START + str + ObjectiveJ::PLIST_END if start - - return str - end - end - - objj_extension('html_encode') do - def html_encode - return self.gsub(//, '>'). - gsub(/"/,'"'). - gsub(/'/, '''). - gsub(/&/, '&') - end - end -end - -class TrueClass - - objj_extension('to_plist') do - def to_plist(start = true) - - str = '' - str = ObjectiveJ::PLIST_START + str + ObjectiveJ::PLIST_END if start - - return str - end - end -end From 6d34f53e435212ed01725803baa3372ae43fd2d3 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Mon, 16 Mar 2009 14:50:45 -0700 Subject: [PATCH 47/62] Fix for platform stuff. Reviewed by me. --- AppKit/rakefile | 14 ++++++++++++-- Objective-J/file.js | 8 ++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/AppKit/rakefile b/AppKit/rakefile index bc6a5da6d..e50ece46c 100644 --- a/AppKit/rakefile +++ b/AppKit/rakefile @@ -13,8 +13,6 @@ subprojects = %w{Tools} subrake(subprojects) -task :build => [$PRODUCT, $ENVIRONMENT_PRODUCT] - Specs = {} AppKitFiles = FileList['**/*.j'].exclude('CoreGraphics/CGContextCanvas.j', 'CoreGraphics/CGContextVML.j', 'Themes/**', 'Tools/**') @@ -60,3 +58,15 @@ bundle Specs[:AppKitRelease], :AppKitRelease file_d $ENVIRONMENT_PRODUCT => [$PRODUCT] do cp_r(Specs[$PRODUCT.to_sym].build_path, $ENVIRONMENT_PRODUCT) end + +ThemeFiles = FileList['Themes/Aristo/*'] + +$THEME_PRODUCT = File.join(Specs[$PRODUCT.to_sym].build_path, 'Resources', 'Aristo.blend') + +file_d $THEME_PRODUCT => ThemeFiles do + File.popen("blend -d Themes/Aristo/ThemeDescriptors.j -o #{$THEME_PRODUCT} -R Themes/Aristo/Resources") do |blend| + puts blend.read + end +end + +task :build => [$PRODUCT, $ENVIRONMENT_PRODUCT, $THEME_PRODUCT] diff --git a/Objective-J/file.js b/Objective-J/file.js index 716b5e5af..78f58af4d 100644 --- a/Objective-J/file.js +++ b/Objective-J/file.js @@ -369,7 +369,7 @@ objj_search.prototype.didReceiveBundleResponse = function(aResponse) platforms = dictionary_getValue(bundle.info, "CPBundlePlatforms"), index = 0, count = OBJJ_PLATFORMS.length, - inner_count = platforms.length; + innerCount = platforms.length; // Ugh, no indexOf, no objects-in-common. for(; index < count; ++index) @@ -377,8 +377,8 @@ objj_search.prototype.didReceiveBundleResponse = function(aResponse) var innerIndex = 0, currentPlatform = OBJJ_PLATFORMS[index]; - for (; innerIndex < inner_count; ++innerIndex) - if(OBJJ_PLATFORMS[index] === platforms[innerIndex]) + for (; innerIndex < innerCount; ++innerIndex) + if(currentPlatform === platforms[innerIndex]) { platform = currentPlatform; break; @@ -386,7 +386,7 @@ objj_search.prototype.didReceiveBundleResponse = function(aResponse) } executablePath = platform + ".platform/" + executablePath; - + this.request(DIRECTORY(aResponse.filePath) + executablePath, this.didReceiveExecutableResponse); // FIXME: Is this the right approach? From 0a32d13cb0bb7eb890ab694149ed2a8d959eece6 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Mon, 16 Mar 2009 17:00:02 -0700 Subject: [PATCH 48/62] Support for blends. Reviewed by me. --- AppKit/CPApplication.j | 16 +++++++++++++ AppKit/CPTheme.j | 54 ++++++++++++++++++++++++++++++++++++++++++ Foundation/CPBundle.j | 20 +++++++++++++--- 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index 3736ad700..e35b96dd0 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -739,7 +739,23 @@ var _CPRunModalLoop = function(anEvent) @class CPApplication @return void */ +@implementation X : CPObject +{ +} +- (void)blendDidFinishLoading:(CPBundle)aBundle +{ + [CPTheme setDefaultTheme:[CPTheme themeNamed:@"Aristo"]]; + _CPApplicationMain() +} +@end function CPApplicationMain(args, namedArgs) +{ + var blend = [[CPBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:@"Aristo.blend"]]; + + [blend loadWithDelegate:[X new]]; +} + +function _CPApplicationMain(args, namedArgs) { var mainBundle = [CPBundle mainBundle], principalClass = [mainBundle principalClass]; diff --git a/AppKit/CPTheme.j b/AppKit/CPTheme.j index 76f08eb06..e4c39a17f 100644 --- a/AppKit/CPTheme.j +++ b/AppKit/CPTheme.j @@ -27,6 +27,60 @@ @import "CPThemedAttribute.j" +@implementation CPBlend : CPObject +{ + CPBundle _bundle; + CPArray _themes @accessors(readonly); + id _loadDelegate; +} + +- (id)initWithContentsOfURL:(CPURL)aURL +{ + self = [super init]; + + if (self) + { + _bundle = [[CPBundle alloc] initWithPath:aURL + "/Info.plist"]; + } + + return self; +} + +- (void)loadWithDelegate:(id)aDelegate +{ + _loadDelegate = aDelegate; + + [_bundle loadWithDelegate:self]; +} + +- (void)bundleDidFinishLoading:(CPBundle)aBundle +{ + var paths = [_bundle objectForInfoDictionaryKey:@"CPBundleReplacedFiles"], + index = 0, + count = paths.length, + bundlePath = [_bundle bundlePath]; + + while (count--) + { + var path = paths[count]; + + if ([path pathExtension] === "keyedtheme") + { + var unarchiver = [[_CPThemeKeyedUnarchiver alloc] + initForReadingWithData:[CPData dataWithString:objj_files[bundlePath + '/' + path].contents] + bundle:_bundle]; + + [unarchiver decodeObjectForKey:@"root"]; + + [unarchiver finishDecoding]; + } + } + + [_loadDelegate blendDidFinishLoading:self]; +} + +@end + var CPThemesByName = nil, CPThemeDefaultTheme = nil, diff --git a/Foundation/CPBundle.j b/Foundation/CPBundle.j index b4565c6e5..32736b885 100644 --- a/Foundation/CPBundle.j +++ b/Foundation/CPBundle.j @@ -129,15 +129,29 @@ context.didCompleteCallback = function() { [_delegate bundleDidFinishLoading:self]; }; var files = [self objectForInfoDictionaryKey:@"CPBundleReplacedFiles"], - count = files.length; + count = files.length, + bundlePath = [self bundlePath]; while (count--) - context.pushFragment(fragment_create_file([self bundlePath] + '/' + files[count], new objj_bundle(""), YES, NULL)); + { + var fileName = files[count]; + + if (fileName.indexOf(".j") === fileName.length - 2) + context.pushFragment(fragment_create_file(bundlePath + '/' + fileName, new objj_bundle(""), YES, NULL)); + } - context.evaluate(); + if (context.fragments.length) + context.evaluate(); + else + [_delegate bundleDidFinishLoading:self]; } } +- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError +{ + alert("what the hell!?!!!" + anError) +} + - (void)connectionDidFinishLoading:(CPURLConnection)aConnection { } From b4cf1ba041c1c684c3fb9de983c37fb491961eea Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Mon, 16 Mar 2009 18:07:20 -0700 Subject: [PATCH 49/62] Added altIncrementValue/setAltIncrementValue:. Reviewed by me. --- AppKit/CPSlider.j | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/AppKit/CPSlider.j b/AppKit/CPSlider.j index 3bdc05543..efa3d9209 100644 --- a/AppKit/CPSlider.j +++ b/AppKit/CPSlider.j @@ -173,6 +173,16 @@ return [super createEphemeralSubviewNamed:aName]; } +- (void)setAltIncrementValue:(float)anAltIncrementValue +{ + _altIncrementValue = anAltIncrementValue; +} + +- (float)altIncrementValue +{ + return _altIncrementValue; +} + - (int)isVertical { var bounds = [self bounds], From 319127f88a525571d5b521159ed2ffc40cc96bea Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Mon, 16 Mar 2009 23:39:16 -0700 Subject: [PATCH 50/62] Cleaned up build scripts. Reviewed by me. --- AppKit/Tools/blend/rakefile | 57 ++-- AppKit/rakefile | 63 ++-- Foundation/rakefile | 57 ++-- Rake/objective-j/bundletask.rb | 530 +++++++++++++++++++++++++++++++++ 4 files changed, 584 insertions(+), 123 deletions(-) create mode 100644 Rake/objective-j/bundletask.rb diff --git a/AppKit/Tools/blend/rakefile b/AppKit/Tools/blend/rakefile index 77f0428bb..dbffcf2a0 100644 --- a/AppKit/Tools/blend/rakefile +++ b/AppKit/Tools/blend/rakefile @@ -3,57 +3,36 @@ require 'rake' require '../../../common' require 'objective-j' -require 'objective-j/bundle' +require 'objective-j/bundletask' -$PRODUCT = 'blend' + $CONFIGURATION +$PRODUCT = :blend +$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'blend') $ENVIRONMENT_BIN_PRODUCT = File.join($ENVIRONMENT_BIN_DIR, 'blend') $ENVIRONMENT_LIB_PRODUCT = File.join($ENVIRONMENT_LIB_DIR, 'blend') -task :build => [$PRODUCT, $ENVIRONMENT_BIN_PRODUCT, $ENVIRONMENT_LIB_PRODUCT] - -Specs = {} +task :build => [:blend, $ENVIRONMENT_BIN_PRODUCT, $ENVIRONMENT_LIB_PRODUCT] # Debug Framework -Specs[:blendDebug] = ObjectiveJ::BundleSpecification.new do |s| - s.name = 'blend' - s.identifier = 'com.280n.blend' - s.version = '0.6.5' - s.author = '280 North, Inc.' - s.email = 'feedback @nospam@ 280north.com' - s.summary = 'blend classes for Cappuccino' - s.sources = FileList['**/*.j'] - s.resources = FileList['Resources/*'] - s.license = ObjectiveJ::License::LGPL_v2_1 - s.build_path = File.join($BUILD_DIR, 'Debug', 'blend') - s.intermediates_path = File.join($BUILD_DIR, 'blend.build', 'Debug') - s.flag = 'DEBUG' +ObjectiveJ::BundleTask.new(:blend) do |t| + t.name = 'blend' + t.identifier = 'com.280n.blend' + t.version = '0.6.5' + t.author = '280 North, Inc.' + t.email = 'feedback @nospam@ 280north.com' + t.summary = 'blend classes for Cappuccino' + t.sources = FileList['**/*.j'] + t.resources = FileList['Resources/*'] + t.license = ObjectiveJ::License::LGPL_v2_1 + t.build_path = $BUILD_PATH + t.flag = 'DEBUG' if $CONFIGURATION == 'Debug' end -bundle Specs[:blendDebug], :blendDebug - -# Release Framework -Specs[:blendRelease] = ObjectiveJ::BundleSpecification.new do |s| - s.name = 'blend' - s.identifier = 'com.280n.blend' - s.version = '0.6.5' - s.author = '280 North, Inc.' - s.email = 'feedback @nospam@ 280north.com' - s.summary = 'blend classes for Cappuccino' - s.sources = FileList['**/*.j'] - s.resources = FileList['Resources/*'] - s.license = ObjectiveJ::License::LGPL_v2_1 - s.build_path = File.join($BUILD_DIR, 'Release', 'blend') - s.intermediates_path = File.join($BUILD_DIR, 'blend.build', 'Release') -end - -bundle Specs[:blendRelease], :blendRelease - #executable in environment directory file_d $ENVIRONMENT_BIN_PRODUCT do make_objj_executable($ENVIRONMENT_BIN_PRODUCT) end -file_d $ENVIRONMENT_LIB_PRODUCT => [$PRODUCT] do - cp_r(Specs[$PRODUCT.to_sym].build_path, $ENVIRONMENT_LIB_PRODUCT) +file_d $ENVIRONMENT_LIB_PRODUCT => [:blend] do + cp_r($BUILD_PATH, $ENVIRONMENT_LIB_PRODUCT) end diff --git a/AppKit/rakefile b/AppKit/rakefile index e50ece46c..f5888a5ab 100644 --- a/AppKit/rakefile +++ b/AppKit/rakefile @@ -3,70 +3,45 @@ require 'rake' require '../common' require 'objective-j' -require 'objective-j/bundle' +require 'objective-j/bundletask' -$PRODUCT = 'AppKit' + $CONFIGURATION +$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'AppKit') $ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'AppKit') +$THEME_PRODUCT = File.join($BUILD_PATH, 'Resources', 'Aristo.blend') subprojects = %w{Tools} subrake(subprojects) -Specs = {} - AppKitFiles = FileList['**/*.j'].exclude('CoreGraphics/CGContextCanvas.j', 'CoreGraphics/CGContextVML.j', 'Themes/**', 'Tools/**') -# Debug Framework -Specs[:AppKitDebug] = ObjectiveJ::BundleSpecification.new do |s| - s.name = 'AppKit' - s.identifier = 'com.280n.AppKit' - s.version = '0.6.5' - s.author = '280 North, Inc.' - s.email = 'feedback @nospam@ 280north.com' - s.summary = 'AppKit classes for Cappuccino' - s.sources = AppKitFiles - s.resources = FileList['Resources/*'] - s.license = ObjectiveJ::License::LGPL_v2_1 - s.build_path = File.join($BUILD_DIR, 'Debug', 'AppKit') - s.intermediates_path = File.join($BUILD_DIR, 'AppKit.build', 'Debug') - s.flags = ['DEBUG'] - s.platforms = [ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::Rhino] +ObjectiveJ::BundleTask.new(:AppKit) do |t| + t.name = 'AppKit' + t.identifier = 'com.280n.AppKit' + t.version = '0.6.5' + t.author = '280 North, Inc.' + t.email = 'feedback @nospam@ 280north.com' + t.summary = 'AppKit classes for Cappuccino' + t.sources = AppKitFiles + t.resources = FileList['Resources/*'] + t.license = ObjectiveJ::License::LGPL_v2_1 + t.build_path = $BUILD_PATH + t.flag = 'DEBUG' if $CONFIGURATION == 'Debug' + t.platforms = [ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::Rhino] end -bundle Specs[:AppKitDebug], :AppKitDebug - -# Release Framework -Specs[:AppKitRelease] = ObjectiveJ::BundleSpecification.new do |s| - s.name = 'AppKit' - s.identifier = 'com.280n.AppKit' - s.version = '0.6.5' - s.author = '280 North, Inc.' - s.email = 'feedback @nospam@ 280north.com' - s.summary = 'AppKit classes for Cappuccino' - s.sources = AppKitFiles - s.resources = FileList['Resources/*'] - s.license = ObjectiveJ::License::LGPL_v2_1 - s.build_path = File.join($BUILD_DIR, 'Release', 'AppKit') - s.intermediates_path = File.join($BUILD_DIR, 'AppKit.build', 'Release') - s.platforms = [ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::Rhino] -end - -bundle Specs[:AppKitRelease], :AppKitRelease - #Framework in environment directory -file_d $ENVIRONMENT_PRODUCT => [$PRODUCT] do - cp_r(Specs[$PRODUCT.to_sym].build_path, $ENVIRONMENT_PRODUCT) +file_d $ENVIRONMENT_PRODUCT => [:AppKit] do + cp_r($BUILD_PATH, $ENVIRONMENT_PRODUCT) end ThemeFiles = FileList['Themes/Aristo/*'] -$THEME_PRODUCT = File.join(Specs[$PRODUCT.to_sym].build_path, 'Resources', 'Aristo.blend') - file_d $THEME_PRODUCT => ThemeFiles do File.popen("blend -d Themes/Aristo/ThemeDescriptors.j -o #{$THEME_PRODUCT} -R Themes/Aristo/Resources") do |blend| puts blend.read end end -task :build => [$PRODUCT, $ENVIRONMENT_PRODUCT, $THEME_PRODUCT] +task :build => [:AppKit, $ENVIRONMENT_PRODUCT, $THEME_PRODUCT] diff --git a/Foundation/rakefile b/Foundation/rakefile index fca544604..e9fc33948 100644 --- a/Foundation/rakefile +++ b/Foundation/rakefile @@ -3,52 +3,29 @@ require 'rake' require '../common' require 'objective-j' -require 'objective-j/bundle' +require 'objective-j/bundletask' -$PRODUCT = 'Foundation' + $CONFIGURATION $ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'Foundation') +$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'Foundation') -task :build => [$PRODUCT, $ENVIRONMENT_PRODUCT] +task :build => [:Foundation, $ENVIRONMENT_PRODUCT] -Specs = {} - -# Debug Framework -Specs[:FoundationDebug] = ObjectiveJ::BundleSpecification.new do |s| - s.name = 'Foundation' - s.identifier = 'com.280n.Foundation' - s.version = '0.6.5' - s.author = '280 North, Inc.' - s.email = 'feedback @nospam@ 280north.com' - s.summary = 'Foundation classes for Cappuccino' - s.sources = FileList['*.j'] - s.resources = FileList['Resources/*'].to_a - s.license = ObjectiveJ::License::LGPL_v2_1 - s.build_path = File.join($BUILD_DIR, 'Debug', 'Foundation') - s.intermediates_path = File.join($BUILD_DIR, 'Foundation.build', 'Debug') - s.flag = 'DEBUG' +ObjectiveJ::BundleTask.new(:Foundation) do |t| + t.name = 'Foundation' + t.identifier = 'com.280n.Foundation' + t.version = '0.6.5' + t.author = '280 North, Inc.' + t.email = 'feedback @nospam@ 280north.com' + t.summary = 'Foundation classes for Cappuccino' + t.sources = FileList['*.j'] + t.resources = FileList['Resources/*'].to_a + t.license = ObjectiveJ::License::LGPL_v2_1 + t.build_path = $BUILD_PATH + t.flag = 'DEBUG' if $CONFIGURATION == 'Debug' end -bundle Specs[:FoundationDebug], :FoundationDebug - -# Release Framework -Specs[:FoundationRelease] = ObjectiveJ::BundleSpecification.new do |s| - s.name = 'Foundation' - s.identifier = 'com.280n.Foundation' - s.version = '0.6.5' - s.author = '280 North, Inc.' - s.email = 'feedback @nospam@ 280north.com' - s.summary = 'Foundation classes for Cappuccino' - s.sources = FileList['*.j'] - s.resources = FileList['Resources/*'].to_a - s.license = ObjectiveJ::License::LGPL_v2_1 - s.build_path = File.join($BUILD_DIR, 'Release', 'Foundation') - s.intermediates_path = File.join($BUILD_DIR, 'Foundation.build', 'Release') -end - -bundle Specs[:FoundationRelease], :FoundationRelease - #Framework in environment directory -file_d $ENVIRONMENT_PRODUCT => [$PRODUCT] do - cp_r(Specs[$PRODUCT.to_sym].build_path, $ENVIRONMENT_PRODUCT) +file_d $ENVIRONMENT_PRODUCT => [:Foundation] do + cp_r($BUILD_PATH, $ENVIRONMENT_PRODUCT) end diff --git a/Rake/objective-j/bundletask.rb b/Rake/objective-j/bundletask.rb new file mode 100644 index 000000000..3abb284a0 --- /dev/null +++ b/Rake/objective-j/bundletask.rb @@ -0,0 +1,530 @@ + +require 'objective-j' +require 'rake' + +module Rake + class Application + # Is there a better (read:supported) way to do this? + def add_task(name, task) + @tasks[name.to_s] = task + end + end +end + +module ObjectiveJ + + class BundleTask < Rake::Task + + def initialize(name) + super name, Rake.application + Rake.application.add_task name, self + + # Each attribute has a default value (possibly nil). Here, we + # initialize all attributes to their default value. This is done + # through the accessor methods, so special behaviours will be honored. + # Furthermore, we take a _copy_ of the default so each specification + # instance has its own empty + # arrays, etc. + @@attributes.each do |name, default| + self.send "#{name}=", copy_of(default) + end + + @loaded = false + @@list << self + yield self if block_given? + @@gather.call(self) if @@gather + define + end + + # ------------------------- Class variables. + + # List of Specification instances. + @@list = [] + + # Optional block used to gather newly defined instances. + @@gather = nil + + # List of attribute names: [:name, :version, ...] + @@required_attributes = [] + + # List of _all_ attributes and default values: [[:name, nil], [:bindir, 'bin'], ...] + @@attributes = [] + + # List of array attributes + @@array_attributes = [] + + # Map of attribute names to default values. + @@default_value = {} + + # ------------------------- Convenience class methods. + + def self.attribute_names + @@attributes.map { |name, default| name } + end + + def self.attribute_defaults + @@attributes.dup + end + + def self.default_value(name) + @@default_value[name] + end + + def self.required_attributes + @@required_attributes.dup + end + + def self.required_attribute?(name) + @@required_attributes.include? name.to_sym + end + + def self.array_attributes + @@array_attributes.dup + end + + # ------------------------- Infrastructure class methods. + + # A list of Specification instances that have been defined in this Ruby instance. + def self.list + @@list + end + + ## + # Used to specify the name and default value of a specification attribute. The side + # effects are: + # * the name and default value are added to the @@attributes list and + # @@default_value map + # * a standard _writer_ method (attribute=) is created + # * a non-standard _reader method (attribute) is created + # + # The reader method behaves like this: + # def attribute + # @attribute ||= (copy of default value) + # end + # + # This allows lazy initialization of attributes to their default values. + # + def self.attribute(name, default=nil) + @@attributes << [name, default] + @@default_value[name] = default + attr_accessor(name) + end + + # Same as :attribute, but ensures that values assigned to the + # attribute are array values by applying :to_a to the value. + def self.array_attribute(name) + @@array_attributes << name + @@attributes << [name, []] + @@default_value[name] = [] + module_eval %{ + def #{name} + @#{name} ||= [] + end + def #{name}=(value) + @#{name} = value.to_a + end + } + end + + # Same as attribute above, but also records this attribute as mandatory. + def self.required_attribute(*args) + @@required_attributes << args.first + attribute(*args) + end + + # Sometimes we don't want the world to use a setter method for a particular attribute. + # +read_only+ makes it private so we can still use it internally. + def self.read_only(*names) + names.each do |name| + private "#{name}=" + end + end + + # Shortcut for creating several attributes at once (each with a default value of + # +nil+). + def self.attributes(*args) + args.each do |arg| + attribute(arg, nil) + end + end + + # Some attributes require special behaviour when they are accessed. This allows for + # that. + def self.overwrite_accessor(name, &block) + remove_method name + define_method(name, &block) + end + + ## + # Defines a _singular_ version of an existing _plural_ attribute (i.e. one whose value + # is expected to be an array). This means just creating a helper method that takes a + # single value and appends it to the array. These are created for convenience, so + # that in a spec, one can write + # + # s.require_path = 'mylib' + # + # instead of + # + # s.require_paths = ['mylib'] + # + # That above convenience is available courtesy of + # + # attribute_alias_singular :require_path, :require_paths + # + def self.attribute_alias_singular(singular, plural) + define_method("#{singular}=") { |val| + send("#{plural}=", [val]) + } + define_method("#{singular}") { + val = send("#{plural}") + val.nil? ? nil : val.first + } + end + + # ------------------------- REQUIRED framework attributes. + + required_attribute :name + required_attribute :version + #required_attribute :date + attribute :date + required_attribute :summary + required_attribute :identifier + required_attribute :platforms, [Platform::ObjJ] + + # ------------------------- OPTIONAL gemspec attributes. + + attributes :email, :homepage, :github_project, :description, :license_file, :license + attributes :build_path, :intermediates_path + # attributes :autorequire, :default_executable + # attribute :platform, Gem::Platform::RUBY + + array_attribute :authors + array_attribute :sources + array_attribute :resources + array_attribute :flags + # array_attribute :test_files + # array_attribute :executables + # array_attribute :extensions + # array_attribute :requirements + # array_attribute :dependencies + + #read_only :dependencies + + # ------------------------- ALIASED gemspec attributes. + + # attribute_alias_singular :executable, :executables + attribute_alias_singular :author, :authors + attribute_alias_singular :flag, :flags + attribute_alias_singular :platform, :platforms + # attribute_alias_singular :require_path, :require_paths + # attribute_alias_singular :test_file, :test_files + + # ------------------------- RUNTIME attributes (not persisted). + + attr_writer :loaded + attr_accessor :loaded_from + + # ------------------------- Special accessor behaviours (overwriting default). + +# overwrite_accessor :version= do |version| +# @version = Version.create(version) +# end + + overwrite_accessor :date= do |date| + # We want to end up with a Time object with one-day resolution. This is + # the cleanest, most-readable, faster-than-using-Date way to do it. + case date + when String then + @date = Time.parse date + when Time then + @date = Time.parse date.strftime("%Y-%m-%d") + when Date then + @date = Time.parse date.to_s + else + @date = Time.today + end + end + + overwrite_accessor :date do + self.date = nil if @date.nil? # HACK Sets the default value for date + @date + end + + overwrite_accessor :summary= do |str| + if str + @summary = str.strip.gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').gsub(/\n[ \t]*/, " ") + end + end + + overwrite_accessor :description= do |str| + if str + @description = str.strip.gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').gsub(/\n[ \t]*/, " ") + end + end + + def files + (@sources || []) | (@resources || []) | (@license_file ? [@license_file] : []) + end + + overwrite_accessor :intermediates_path do + return @intermediates_path || name + '.build' + end + + overwrite_accessor :build_path do + return @build_path || './' + name + end + + # ------------------------- Predicates. + + def loaded?; @loaded ? true : false ; end + + # ------------------------- Instance methods. + + ## + # Returns the full name (name-version) of this Framework. + # + def full_name + @name + end + + # ------------------------- Comparison methods. + + ## + # Compare specs (name then version). + # + def <=>(other) + [@name, @version] <=> [other.name, other.version] + end + + # Tests specs for equality (across all attributes). + def ==(other) + @@attributes.each do |name, default| + return false unless self.send(name) == other.send(name) + end + true + end + + # ------------------------- Validation and normalization methods. + + ## + # Checks that the specification contains all required fields, and + # does a very basic sanity check. + # + # Raises InvalidSpecificationException if the spec does not pass + # the checks.. + def validate +=begin + normalize + if rubygems_version != RubyGemsVersion + raise InvalidSpecificationException.new(%[ + Expected RubyGems Version #{RubyGemsVersion}, was #{rubygems_version} + ].strip) + end +=end + @@required_attributes.each do |symbol| + unless self.send(symbol) + raise InvalidSpecificationException.new("Missing value for attribute #{symbol}") + end + end +=begin + if require_paths.empty? + raise InvalidSpecificationException.new("Framework spec needs to have at least one require_path") + end +=end + end + + ## + # Normalize the list of files so that: + # * All file lists have redundancies removed. + # * Files referenced in the extra_rdoc_files are included in the package file list. + # + # Also, the summary and description are converted to a normal format. + def normalize +=begin + if @extra_rdoc_files + @extra_rdoc_files.uniq! + @files ||= [] + @files.concat(@extra_rdoc_files) + end +=end + @files.uniq! if @files + end + + def copy_of(obj) + case obj + when Numeric, Symbol, true, false, nil then obj + else obj.dup + end + end + +######### + + + PLATFORM_DIRECTORIES = + { + Platform::ObjJ => 'objj.platform', + Platform::Rhino => 'rhino.platform', + Platform::Browser => 'browser.platform', + Platform::BrowserDesktop => 'browser-desktop.platform', + Platform::BrowserIPhone => 'browser-iphone.platform' + } + + PLATFORM_FLAGS = + { + Platform::ObjJ => [], + Platform::Rhino => ['PLATFORM_RHINO'], + Platform::Browser => ['PLATFORM_BROWSER', 'PLATFORM_DOM'], + Platform::BrowserDesktop => ['PLATFORM_BROWSER', 'PLATFORM_DOM', 'PLATFORM_DESKTOP'], + Platform::BrowserIPhone => ['PLATFORM_BROWSER', 'PLATFORM_DOM', 'PLATFORM_IPHONE', 'PLATFORM_MOBILE'] + } + + # Objective-J Bundle spec containing the metadata for this bundle. + attr_accessor :bundle_spec + + def self.overwrite_accessor(name, &block) + remove_method name + define_method(name, &block) + end + + def define + + validate + + resources_path = File.join(build_path, 'Resources') + copied_resources = [] + + # create file tasks for copied resources + resources.each do |resource| + + copied_resource = File.join(resources_path, File.basename(resource)) + + file_d copied_resource => [resource] do + cp_r(resource, resources_path) + end + + copied_resources << copied_resource + end + + info_plist_path = build_path + '/Info.plist' + info_plist = { 'CPBundleName' => name, 'CPBundleIdentifier' => identifier, 'CPBundleInfoDictionaryVersion' => 6.0, 'CPBundleVersion' => version } + + info_plist['CPBundlePlatforms'] = platforms; + + file_d info_plist_path do + File.open(info_plist_path, 'w') do |file| + file.puts info_plist.to_plist + end + end + + preprocessed_files = [] + + # create file tasks for object files + platforms.uniq.each do |platform| + + executable_path = File.join(build_path, PLATFORM_DIRECTORIES[platform], name + '.sj') + enhance([executable_path]) + + file_d executable_path do + BundleTask.compact(build_path) + end + + # Yes its unfortunate that we need to regenerate the whole executable if the Info.plist changes. Oh well. + file_d executable_path => info_plist_path + + sources.each do |source| + + preprocessed_file = File.join(build_path, PLATFORM_DIRECTORIES[platform], File.basename(source)) + + file_d preprocessed_file => source do + IO.popen("objjc #{resolve_flags(flags)} #{resolve_flags(PLATFORM_FLAGS[platform])} #{source} -o #{preprocessed_file}") do |objjc| + puts objjc.read + end + end + + preprocessed_files << preprocessed_file + + file_d executable_path => preprocessed_file + end + end + + # copy license file + license_path = nil + + # check if a license type has been specified + if license != nil + + copied_license = build_path + '/LICENSE' + + case license + when License::LGPL_v2_1 + license_path = File.expand_path(File.join(File.dirname(__FILE__), '../LGPL-v2.1')) + else + license_path = license + end + + file_d copied_license => license_path do + cp(license_path, copied_license) + end + end + + enhance(preprocessed_files + copied_resources + [info_plist_path]) + end + + def BundleTask.compact(path, *patterns) + + puts 'Compacting ' + path + + info_plist_path = File.join(path, 'Info.plist') + info_plist = Plist::parse_xml(info_plist_path) + + absolute_path = File.expand_path(path) + '/' + + patterns = patterns.map { |pattern| "#{path}/#{pattern}" } + + bundle_name = info_plist['CPBundleName'] + replaced_files = [] + + FileList.new(File.join(path, '**', '*.platform')).each do |platform| + + FileList.new(File.join(platform, '*.j')) do |list| + + list.include(*patterns) + + executable_path = File.join(platform, bundle_name) + '.sj' + platform_absolute_path = File.expand_path(platform) + '/' + + File.open(executable_path, 'w+') do |executable| + + executable.write '@STATIC;1.0;' + + list.each do |fileName| + + File.open(fileName) do |file| + + if fileName.index(platform_absolute_path) == 0 + fileName = File.expand_path(fileName)[platform_absolute_path.length..-1] + else + fileName = File.expand_path(fileName)[absolute_path.length..-1] + end + + executable.write "p;#{fileName.length};#{fileName}#{file.read}" + + replaced_files << fileName + end + end + end + end + end + + info_plist['CPBundleReplacedFiles'] = replaced_files.uniq + info_plist['CPBundleExecutable'] = bundle_name + '.sj' + + File.open(info_plist_path, 'w') do |file| + file.puts info_plist.to_plist + end + + end + + end # class BundleSpecification + +end # module ObjectiveJ From 10422caa92a1d8b5e9fe186116c744a346065a99 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Tue, 17 Mar 2009 00:22:09 -0700 Subject: [PATCH 51/62] Moved nib2cib to new build system. Reviewed by me. --- Tools/nib2cib/Rakefile | 38 +++++++++++++++++++++++++++++++++++ Tools/nib2cib/build.xml | 25 ----------------------- Tools/nib2cib/nib2cib.steam | 40 ------------------------------------- 3 files changed, 38 insertions(+), 65 deletions(-) create mode 100644 Tools/nib2cib/Rakefile delete mode 100644 Tools/nib2cib/build.xml delete mode 100644 Tools/nib2cib/nib2cib.steam diff --git a/Tools/nib2cib/Rakefile b/Tools/nib2cib/Rakefile new file mode 100644 index 000000000..201dc116d --- /dev/null +++ b/Tools/nib2cib/Rakefile @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby + +require 'rake' +require '../../common' +require 'objective-j' +require 'objective-j/bundletask' + + +$PRODUCT = :nib2cib +$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'nib2cib') +$ENVIRONMENT_BIN_PRODUCT = File.join($ENVIRONMENT_BIN_DIR, 'nib2cib') +$ENVIRONMENT_LIB_PRODUCT = File.join($ENVIRONMENT_LIB_DIR, 'nib2cib') + +task :build => [:nib2cib, $ENVIRONMENT_BIN_PRODUCT, $ENVIRONMENT_LIB_PRODUCT] + +# Debug Framework +ObjectiveJ::BundleTask.new(:nib2cib) do |t| + t.name = 'nib2cib' + t.identifier = 'com.280n.nib2cib' + t.version = '0.6.5' + t.author = '280 North, Inc.' + t.email = 'feedback @nospam@ 280north.com' + t.summary = 'nib2cib converts Cocoa nib and xibs to Cappuccino cibs' + t.sources = FileList['**/*.j'] + t.resources = FileList['Resources/*'] + t.license = ObjectiveJ::License::LGPL_v2_1 + t.build_path = $BUILD_PATH + t.flag = 'DEBUG' if $CONFIGURATION == 'Debug' +end + +#executable in environment directory +file_d $ENVIRONMENT_BIN_PRODUCT do + make_objj_executable($ENVIRONMENT_BIN_PRODUCT) +end + +file_d $ENVIRONMENT_LIB_PRODUCT => [:nib2cib] do + cp_r($BUILD_PATH, $ENVIRONMENT_LIB_PRODUCT) +end diff --git a/Tools/nib2cib/build.xml b/Tools/nib2cib/build.xml deleted file mode 100644 index 4ab48491f..000000000 --- a/Tools/nib2cib/build.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Tools/nib2cib/nib2cib.steam b/Tools/nib2cib/nib2cib.steam deleted file mode 100644 index 06ed7627c..000000000 --- a/Tools/nib2cib/nib2cib.steam +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Name - nib2cib - Targets - - - Name - nib2cib - - - Configurations - - - Name - Debug - Settings - - PREPROCESS - - FLAGS - -DDEBUG - - - - Name - Release - Settings - - PREPROCESS - - PREINTERPRET - - - - - - From 1dcc6db07986fa7b5c4e073a2c665c7da133bae1 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Tue, 17 Mar 2009 00:33:22 -0700 Subject: [PATCH 52/62] Moved BlendKit to new build system. Reviewd by me. --- AppKit/Tools/BlendKit/BlendKit.steam | 42 --- AppKit/Tools/BlendKit/build.xml | 33 -- AppKit/Tools/BlendKit/rakefile | 57 +-- Objective-J/rakefile | 5 +- Rake/objective-j.rb | 513 ++------------------------- Rake/objective-j/bundle.rb | 176 --------- 6 files changed, 43 insertions(+), 783 deletions(-) delete mode 100644 AppKit/Tools/BlendKit/BlendKit.steam delete mode 100644 AppKit/Tools/BlendKit/build.xml delete mode 100644 Rake/objective-j/bundle.rb diff --git a/AppKit/Tools/BlendKit/BlendKit.steam b/AppKit/Tools/BlendKit/BlendKit.steam deleted file mode 100644 index 75d93232e..000000000 --- a/AppKit/Tools/BlendKit/BlendKit.steam +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Name - BlendKit - Targets - - - Name - BlendKit - - - Configurations - - - Name - Debug - Flags - -DDEBUG -DPLATFORM_DOM -g - - - Name - Release - Flags - -DPLATFORM_DOM -O - - - Name - Debug-Rhino - Flags - -DDEBUG -g - - - Name - Release-Rhino - Flags - -O - - - - diff --git a/AppKit/Tools/BlendKit/build.xml b/AppKit/Tools/BlendKit/build.xml deleted file mode 100644 index 67c5ff641..000000000 --- a/AppKit/Tools/BlendKit/build.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AppKit/Tools/BlendKit/rakefile b/AppKit/Tools/BlendKit/rakefile index 279095890..bdcad5ff4 100644 --- a/AppKit/Tools/BlendKit/rakefile +++ b/AppKit/Tools/BlendKit/rakefile @@ -3,52 +3,29 @@ require 'rake' require '../../../common' require 'objective-j' -require 'objective-j/bundle' +require 'objective-j/bundletask' -$PRODUCT = 'BlendKit' + $CONFIGURATION $ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'BlendKit') +$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'BlendKit') -task :build => [$PRODUCT, $ENVIRONMENT_PRODUCT] +task :build => [:BlendKit, $ENVIRONMENT_PRODUCT] -Specs = {} - -# Debug Framework -Specs[:BlendKitDebug] = ObjectiveJ::BundleSpecification.new do |s| - s.name = 'BlendKit' - s.identifier = 'com.280n.BlendKit' - s.version = '0.6.5' - s.author = '280 North, Inc.' - s.email = 'feedback @nospam@ 280north.com' - s.summary = 'BlendKit classes for Cappuccino' - s.sources = FileList['**/*.j'] - s.resources = FileList['Resources/*'] - s.license = ObjectiveJ::License::LGPL_v2_1 - s.build_path = File.join($BUILD_DIR, 'Debug', 'BlendKit') - s.intermediates_path = File.join($BUILD_DIR, 'BlendKit.build', 'Debug') - s.flag = 'DEBUG' +ObjectiveJ::BundleTask.new(:BlendKit) do |t| + t.name = 'BlendKit' + t.identifier = 'com.280n.BlendKit' + t.version = '0.6.5' + t.author = '280 North, Inc.' + t.email = 'feedback @nospam@ 280north.com' + t.summary = 'BlendKit classes for Cappuccino' + t.sources = FileList['*.j'] + t.resources = FileList['Resources/*'].to_a + t.license = ObjectiveJ::License::LGPL_v2_1 + t.build_path = $BUILD_PATH + t.flag = 'DEBUG' if $CONFIGURATION == 'Debug' end -bundle Specs[:BlendKitDebug], :BlendKitDebug - -# Release Framework -Specs[:BlendKitRelease] = ObjectiveJ::BundleSpecification.new do |s| - s.name = 'BlendKit' - s.identifier = 'com.280n.BlendKit' - s.version = '0.6.5' - s.author = '280 North, Inc.' - s.email = 'feedback @nospam@ 280north.com' - s.summary = 'BlendKit classes for Cappuccino' - s.sources = FileList['**/*.j'] - s.resources = FileList['Resources/*'] - s.license = ObjectiveJ::License::LGPL_v2_1 - s.build_path = File.join($BUILD_DIR, 'Release', 'BlendKit') - s.intermediates_path = File.join($BUILD_DIR, 'BlendKit.build', 'Release') -end - -bundle Specs[:BlendKitRelease], :BlendKitRelease - #Framework in environment directory -file_d $ENVIRONMENT_PRODUCT => [$PRODUCT] do - cp_r(Specs[$PRODUCT.to_sym].build_path, $ENVIRONMENT_PRODUCT) +file_d $ENVIRONMENT_PRODUCT => [:BlendKit] do + cp_r($BUILD_PATH, $ENVIRONMENT_PRODUCT) end diff --git a/Objective-J/rakefile b/Objective-J/rakefile index 3b48c3e7a..99aed6c05 100644 --- a/Objective-J/rakefile +++ b/Objective-J/rakefile @@ -38,7 +38,10 @@ file_d $BROWSER_FILE => Files do |t| end file_d $RHINO_FILE => Files do |t| - build_product(t.name, platform_flags(ObjectiveJ::Platform::Rhino, ObjectiveJ::Platform::ObjJ)) + flags = platform_flags(ObjectiveJ::Platform::Rhino, ObjectiveJ::Platform::ObjJ) + flags['RHINO'] = '' + + build_product(t.name, flags) end #Framework in environment directory diff --git a/Rake/objective-j.rb b/Rake/objective-j.rb index 4e78133a2..f29eaa719 100644 --- a/Rake/objective-j.rb +++ b/Rake/objective-j.rb @@ -13,497 +13,33 @@ module ObjectiveJ BrowserDesktop = 'browser-desktop' BrowserIPhone = 'browser-iphone' BrowseriPhone = 'browser-iphone' - end - ## - # == ObjectiveJ::BundleSpecification - # - # The Specification class contains the metadata for a Framework. Typically defined in a - # Rakefile, and looks like this: - # - # spec = ObjJ::BundleSpecification.new do |s| - # s.name = 'NewKit' - # s.version = '1.0' - # s.summary = 'Example framework specification' - # ... - # end - # - # There are many framework attributes, and the best place to learn about them in - # the "Framework Reference" linked from the Cappuccino wiki. - # - - class BundleSpecification - - # ------------------------- Specification version contstants. - - # The specification version applied to any new Specification instances created. This - # should be bumped whenever something in the spec format changes. - CURRENT_SPECIFICATION_VERSION = 1 - - # An informal list of changes to the specification. The highest-valued key should be - # equal to the CURRENT_SPECIFICATION_VERSION. - SPECIFICATION_VERSION_HISTORY = { - -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'], - 1 => [ - 'First Specification' - ] + PLATFORM_DIRECTORIES = + { + Platform::ObjJ => 'objj.platform', + Platform::Rhino => 'rhino.platform', + Platform::Browser => 'browser.platform', + Platform::BrowserDesktop => 'browser-desktop.platform', + Platform::BrowserIPhone => 'browser-iphone.platform' } - - # ------------------------- Class variables. - - # List of Specification instances. - @@list = [] - - # Optional block used to gather newly defined instances. - @@gather = nil - - # List of attribute names: [:name, :version, ...] - @@required_attributes = [] - - # List of _all_ attributes and default values: [[:name, nil], [:bindir, 'bin'], ...] - @@attributes = [] - - # List of array attributes - @@array_attributes = [] - - # Map of attribute names to default values. - @@default_value = {} - - # ------------------------- Convenience class methods. - - def self.attribute_names - @@attributes.map { |name, default| name } - end - - def self.attribute_defaults - @@attributes.dup - end - - def self.default_value(name) - @@default_value[name] - end - - def self.required_attributes - @@required_attributes.dup - end - - def self.required_attribute?(name) - @@required_attributes.include? name.to_sym - end - - def self.array_attributes - @@array_attributes.dup + + PLATFORM_FLAGS = + { + Platform::ObjJ => [], + Platform::Rhino => ['PLATFORM_RHINO'], + Platform::Browser => ['PLATFORM_BROWSER', 'PLATFORM_DOM'], + Platform::BrowserDesktop => ['PLATFORM_BROWSER', 'PLATFORM_DOM', 'PLATFORM_DESKTOP'], + Platform::BrowserIPhone => ['PLATFORM_BROWSER', 'PLATFORM_DOM', 'PLATFORM_IPHONE', 'PLATFORM_MOBILE'] + } + + def Platform.directory(aPlatform) + return PLATFORM_DIRECTORIES[aPlatform] end - # ------------------------- Infrastructure class methods. - - # A list of Specification instances that have been defined in this Ruby instance. - def self.list - @@list - end - - ## - # Used to specify the name and default value of a specification attribute. The side - # effects are: - # * the name and default value are added to the @@attributes list and - # @@default_value map - # * a standard _writer_ method (attribute=) is created - # * a non-standard _reader method (attribute) is created - # - # The reader method behaves like this: - # def attribute - # @attribute ||= (copy of default value) - # end - # - # This allows lazy initialization of attributes to their default values. - # - def self.attribute(name, default=nil) - @@attributes << [name, default] - @@default_value[name] = default - attr_accessor(name) - end - - # Same as :attribute, but ensures that values assigned to the - # attribute are array values by applying :to_a to the value. - def self.array_attribute(name) - @@array_attributes << name - @@attributes << [name, []] - @@default_value[name] = [] - module_eval %{ - def #{name} - @#{name} ||= [] - end - def #{name}=(value) - @#{name} = value.to_a - end - } - end - - # Same as attribute above, but also records this attribute as mandatory. - def self.required_attribute(*args) - @@required_attributes << args.first - attribute(*args) - end - - # Sometimes we don't want the world to use a setter method for a particular attribute. - # +read_only+ makes it private so we can still use it internally. - def self.read_only(*names) - names.each do |name| - private "#{name}=" - end - end - - # Shortcut for creating several attributes at once (each with a default value of - # +nil+). - def self.attributes(*args) - args.each do |arg| - attribute(arg, nil) - end - end - - # Some attributes require special behaviour when they are accessed. This allows for - # that. - def self.overwrite_accessor(name, &block) - remove_method name - define_method(name, &block) - end - - ## - # Defines a _singular_ version of an existing _plural_ attribute (i.e. one whose value - # is expected to be an array). This means just creating a helper method that takes a - # single value and appends it to the array. These are created for convenience, so - # that in a spec, one can write - # - # s.require_path = 'mylib' - # - # instead of - # - # s.require_paths = ['mylib'] - # - # That above convenience is available courtesy of - # - # attribute_alias_singular :require_path, :require_paths - # - def self.attribute_alias_singular(singular, plural) - define_method("#{singular}=") { |val| - send("#{plural}=", [val]) - } - define_method("#{singular}") { - val = send("#{plural}") - val.nil? ? nil : val.first - } - end - - # ------------------------- REQUIRED framework attributes. - - required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION - required_attribute :name - required_attribute :version - #required_attribute :date - attribute :date - required_attribute :summary - required_attribute :identifier - required_attribute :platforms, [Platform::ObjJ] - - read_only :specification_version - - # ------------------------- OPTIONAL gemspec attributes. - - attributes :email, :homepage, :github_project, :description, :license_file, :license - attributes :build_path, :intermediates_path - # attributes :autorequire, :default_executable - # attribute :platform, Gem::Platform::RUBY - - array_attribute :authors - array_attribute :sources - array_attribute :resources - array_attribute :flags - # array_attribute :test_files - # array_attribute :executables - # array_attribute :extensions - # array_attribute :requirements - # array_attribute :dependencies - - #read_only :dependencies - - # ------------------------- ALIASED gemspec attributes. - - # attribute_alias_singular :executable, :executables - attribute_alias_singular :author, :authors - attribute_alias_singular :flag, :flags - attribute_alias_singular :platform, :platforms - # attribute_alias_singular :require_path, :require_paths - # attribute_alias_singular :test_file, :test_files - - # ------------------------- RUNTIME attributes (not persisted). - - attr_writer :loaded - attr_accessor :loaded_from - - # ------------------------- Special accessor behaviours (overwriting default). - -# overwrite_accessor :version= do |version| -# @version = Version.create(version) -# end - - overwrite_accessor :date= do |date| - # We want to end up with a Time object with one-day resolution. This is - # the cleanest, most-readable, faster-than-using-Date way to do it. - case date - when String then - @date = Time.parse date - when Time then - @date = Time.parse date.strftime("%Y-%m-%d") - when Date then - @date = Time.parse date.to_s - else - @date = Time.today - end - end - - overwrite_accessor :date do - self.date = nil if @date.nil? # HACK Sets the default value for date - @date - end - - overwrite_accessor :summary= do |str| - if str - @summary = str.strip.gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').gsub(/\n[ \t]*/, " ") - end - end - - overwrite_accessor :description= do |str| - if str - @description = str.strip.gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').gsub(/\n[ \t]*/, " ") - end - end - - def files - (@sources || []) | (@resources || []) | (@license_file ? [@license_file] : []) - end - - overwrite_accessor :intermediates_path do - return @intermediates_path || name + '.build' - end - - overwrite_accessor :build_path do - return @build_path || './' + name - end -=begin - overwrite_accessor :test_files do - # Handle the possibility that we have @test_suite_file but not @test_files. This will - # happen when an old gem is loaded via YAML. - if @test_suite_file - @test_files = [@test_suite_file].flatten - @test_suite_file = nil - end - @test_files ||= [] - end -=end - - # ------------------------- Predicates. - - def loaded?; @loaded ? true : false ; end - # def has_unit_tests?; not test_files.empty?; end - - # ------------------------- Constructors. - - ## - # Specification constructor. Assigns the default values to the - # attributes, adds this spec to the list of loaded specs (see - # Specification.list), and yields itself for further initialization. - # - def initialize - # Each attribute has a default value (possibly nil). Here, we - # initialize all attributes to their default value. This is done - # through the accessor methods, so special behaviours will be honored. - # Furthermore, we take a _copy_ of the default so each specification - # instance has its own empty - # arrays, etc. - @@attributes.each do |name, default| - self.send "#{name}=", copy_of(default) - end - @loaded = false - @@list << self - yield self if block_given? - @@gather.call(self) if @@gather - end -=begin - ## - # Special loader for YAML files. When a Specification object is loaded from a YAML file, - # it bypasses the normal Ruby object initialization routine (#initialize). This method - # makes up for that and deals with gems of different ages. - # - # 'input' can be anything that YAML.load() accepts: String or IO. - # - def Specification.from_yaml(input) - spec = YAML.load(input) - if(spec.class == FalseClass) then - raise Gem::EndOfYAMLException - end - unless Specification === spec - raise Gem::Exception, "YAML data doesn't evaluate to gem specification" - end - unless spec.instance_variable_get :@specification_version - spec.instance_variable_set :@specification_version, NONEXISTENT_SPECIFICATION_VERSION - end - spec - end -=end - - def BundleSpecification.load(filename) - gemspec = nil - fail "NESTED Specification.load calls not allowed!" if @@gather - @@gather = proc { |gs| gemspec = gs } - data = File.read(filename) - eval(data) - gemspec - ensure - @@gather = nil - end - - # ------------------------- Instance methods. - - ## - # Returns the full name (name-version) of this Framework. - # - def full_name - @name - end - - # ------------------------- Comparison methods. - - ## - # Compare specs (name then version). - # - def <=>(other) - [@name, @version] <=> [other.name, other.version] - end - - # Tests specs for equality (across all attributes). - def ==(other) - @@attributes.each do |name, default| - return false unless self.send(name) == other.send(name) - end - true - end -=begin - # ------------------------- Export methods (YAML and Ruby code). - - # Returns an array of attribute names to be used when generating a YAML - # representation of this object. If an attribute still has its default - # value, it is omitted. - def to_yaml_properties - mark_version - @@attributes.map { |name, default| "@#{name}" } - end - - # Returns a Ruby code representation of this specification, such that it - # can be eval'ed and reconstruct the same specification later. Attributes - # that still have their default values are omitted. - def to_ruby - mark_version - result = "Gem::Specification.new do |s|\n" - @@attributes.each do |name, default| - # TODO better implementation of next line (read_only_attribute? ... something like that) - next if name == :dependencies or name == :specification_version - current_value = self.send(name) - result << " s.#{name} = #{ruby_code(current_value)}\n" unless current_value == default - end - dependencies.each do |dep| - version_reqs_param = dep.requirements_list.inspect - result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})\n" - end - result << "end\n" - end -=end - # ------------------------- Validation and normalization methods. - - ## - # Checks that the specification contains all required fields, and - # does a very basic sanity check. - # - # Raises InvalidSpecificationException if the spec does not pass - # the checks.. - def validate -=begin - normalize - if rubygems_version != RubyGemsVersion - raise InvalidSpecificationException.new(%[ - Expected RubyGems Version #{RubyGemsVersion}, was #{rubygems_version} - ].strip) - end -=end - @@required_attributes.each do |symbol| - unless self.send(symbol) - raise InvalidSpecificationException.new("Missing value for attribute #{symbol}") + def Platform.flags(aPlatform) + return PLATFORM_FLAGS[aPlatform] end end -=begin - if require_paths.empty? - raise InvalidSpecificationException.new("Framework spec needs to have at least one require_path") - end -=end - end - - ## - # Normalize the list of files so that: - # * All file lists have redundancies removed. - # * Files referenced in the extra_rdoc_files are included in the package file list. - # - # Also, the summary and description are converted to a normal format. - def normalize -=begin - if @extra_rdoc_files - @extra_rdoc_files.uniq! - @files ||= [] - @files.concat(@extra_rdoc_files) - end -=end - @files.uniq! if @files - end - - def to_s - "#" - end - - def info_plist - return { 'CPBundleName' => name, 'CPBundleIdentifier' => identifier, 'CPBundleInfoDictionaryVersion' => 6.0, 'CPBundleVersion' => version } - end - - private -=begin - def find_all_satisfiers(dep) - Gem.source_index.each do |name,gem| - if(gem.satisfies_requirement?(dep)) then - yield gem - end - end - end -=end - # Duplicate an object unless it's an immediate value. - def copy_of(obj) - case obj - when Numeric, Symbol, true, false, nil then obj - else obj.dup - end - end - - # Return a string containing a Ruby code representation of the given object. - def ruby_code(obj) - case obj - when String then '%q{' + obj + '}' - when Array then obj.inspect - when Gem::Version then obj.to_s.inspect - when Date, Time then '%q{' + obj.strftime('%Y-%m-%d') + '}' - when Numeric then obj.inspect - when true, false, nil then obj.inspect - when Gem::Version::Requirement then "Gem::Version::Requirement.new(#{obj.to_s.inspect})" - else raise Exception, "ruby_code case not handled: #{obj.class}" - end - end - - end # class BundleSpecification end # module ObjectiveJ @@ -525,17 +61,12 @@ def file_d(*args, &block) file fileTask.name => fileDirectory end -def bundle(spec, *args, &block) - task = ObjectiveJ::BundleTask.define_task(*args, &block) - task.bundle_spec = spec -end - def resolve_flags(flags) case flags when nil then '' when String then '-D' + flags when Array then flags.map { |flag| '-D' + flag }.join(' ') - when Hash then flags.map { |flag, value| '-D' + flag + '=' + value }.join(' ') + when Hash then flags.map { |flag, value| '-D' + flag + (value != '' ? '=' + value : '') }.join(' ') end end diff --git a/Rake/objective-j/bundle.rb b/Rake/objective-j/bundle.rb deleted file mode 100644 index 95e49a0de..000000000 --- a/Rake/objective-j/bundle.rb +++ /dev/null @@ -1,176 +0,0 @@ -require 'rake' - - - -module ObjectiveJ - - class BundleTask < Rake::Task - - PLATFORM_DIRECTORIES = - { - Platform::ObjJ => 'objj.platform', - Platform::Rhino => 'rhino.platform', - Platform::Browser => 'browser.platform', - Platform::BrowserDesktop => 'browser-desktop.platform', - Platform::BrowserIPhone => 'browser-iphone.platform' - } - - PLATFORM_FLAGS = - { - Platform::ObjJ => [], - Platform::Rhino => ['PLATFORM_RHINO'], - Platform::Browser => ['PLATFORM_BROWSER', 'PLATFORM_DOM'], - Platform::BrowserDesktop => ['PLATFORM_BROWSER', 'PLATFORM_DOM', 'PLATFORM_DESKTOP'], - Platform::BrowserIPhone => ['PLATFORM_BROWSER', 'PLATFORM_DOM', 'PLATFORM_IPHONE', 'PLATFORM_MOBILE'] - } - - # Objective-J Bundle spec containing the metadata for this bundle. - attr_accessor :bundle_spec - - def self.overwrite_accessor(name, &block) - remove_method name - define_method(name, &block) - end - - overwrite_accessor :bundle_spec= do |spec| - - @bundle_spec = spec - - @bundle_spec.validate - - resources_path = File.join(@bundle_spec.build_path, 'Resources') - copied_resources = [] - - # create file tasks for copied resources - @bundle_spec.resources.each do |resource| - - copied_resource = File.join(resources_path, File.basename(resource)) - - file_d copied_resource => [resource] do - cp_r(resource, resources_path) - end - - copied_resources << copied_resource - end - - info_plist_path = @bundle_spec.build_path + '/Info.plist' - info_plist = @bundle_spec.info_plist - - info_plist['CPBundlePlatforms'] = @bundle_spec.platforms; - - file_d info_plist_path do - File.open(info_plist_path, 'w') do |file| - file.puts info_plist.to_plist - end - end - - preprocessed_files = [] - - # create file tasks for object files - @bundle_spec.platforms.uniq.each do |platform| - - executable_path = File.join(@bundle_spec.build_path, PLATFORM_DIRECTORIES[platform], @bundle_spec.name + '.sj') - enhance([executable_path]) - - file_d executable_path do - BundleTask.compact(@bundle_spec.build_path) - end - - # Yes its unfortunate that we need to regenerate the whole executable if the Info.plist changes. Oh well. - file_d executable_path => info_plist_path - - @bundle_spec.sources.each do |source| - - preprocessed_file = File.join(@bundle_spec.build_path, PLATFORM_DIRECTORIES[platform], File.basename(source)) - - file_d preprocessed_file => source do - IO.popen("objjc #{resolve_flags(@bundle_spec.flags)} #{resolve_flags(PLATFORM_FLAGS[platform])} #{source} -o #{preprocessed_file}") do |objjc| - puts objjc.read - end - end - - preprocessed_files << preprocessed_file - - file_d executable_path => preprocessed_file - end - end - - # copy license file - license_path = nil - - # check if a license type has been specified - if @bundle_spec.license != nil - - copied_license = @bundle_spec.build_path + '/LICENSE' - - case @bundle_spec.license - when License::LGPL_v2_1 - license_path = File.expand_path(File.join(File.dirname(__FILE__), '../LGPL-v2.1')) - else - license_path = license - end - - file_d copied_license => license_path do - cp(license_path, copied_license) - end - end - - enhance(preprocessed_files + copied_resources + [info_plist_path]) - end - - def BundleTask.compact(path, *patterns) - - puts 'Compacting ' + path - - info_plist_path = File.join(path, 'Info.plist') - info_plist = Plist::parse_xml(info_plist_path) - - absolute_path = File.expand_path(path) + '/' - - patterns = patterns.map { |pattern| "#{path}/#{pattern}" } - - bundle_name = info_plist['CPBundleName'] - replaced_files = [] - - FileList.new(File.join(path, '**', '*.platform')).each do |platform| - - FileList.new(File.join(platform, '*.j')) do |list| - - list.include(*patterns) - - executable_path = File.join(platform, bundle_name) + '.sj' - platform_absolute_path = File.expand_path(platform) + '/' - - File.open(executable_path, 'w+') do |executable| - - executable.write '@STATIC;1.0;' - - list.each do |fileName| - - File.open(fileName) do |file| - - if fileName.index(platform_absolute_path) == 0 - fileName = File.expand_path(fileName)[platform_absolute_path.length..-1] - else - fileName = File.expand_path(fileName)[absolute_path.length..-1] - end - - executable.write "p;#{fileName.length};#{fileName}#{file.read}" - - replaced_files << fileName - end - end - end - end - end - - info_plist['CPBundleReplacedFiles'] = replaced_files.uniq - info_plist['CPBundleExecutable'] = bundle_name + '.sj' - - File.open(info_plist_path, 'w') do |file| - file.puts info_plist.to_plist - end - - end - end -end From b7b0ca40b09d7ea177d3b4c067d4e59c9a75525f Mon Sep 17 00:00:00 2001 From: tlrobinson Date: Tue, 17 Mar 2009 18:38:14 -0700 Subject: [PATCH 53/62] Fixed CPString pathComponents and lastPathComponent to match Cocoa. Added tests. --- Foundation/CPString.j | 7 ++++++- Tests/Foundation/CPStringTest.j | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Foundation/CPString.j b/Foundation/CPString.j index 96be2311f..5e26c0322 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -584,7 +584,12 @@ var CPStringHashes = new objj_dictionary(); */ - (CPArray)pathComponents { - return split('/'); + var result = split('/'); + if (result[0] === "") + result[0] = "/"; + if (result[result.length - 1] === "") + result.pop(); + return result; } /*! diff --git a/Tests/Foundation/CPStringTest.j b/Tests/Foundation/CPStringTest.j index f509e8128..1533ab0b7 100644 --- a/Tests/Foundation/CPStringTest.j +++ b/Tests/Foundation/CPStringTest.j @@ -80,4 +80,31 @@ import [self assert:[testStrings[i][0] stringByDeletingLastPathComponent] equals:testStrings[i][1]]; } +- (void)testPathComponents +{ + var testStrings = [ + ["tmp/scratch", ["tmp", "scratch"]], + ["/tmp/scratch", ["/", "tmp", "scratch"]] + ] + + for (var i = 0; i < testStrings.length; i++) { + var result = [testStrings[i][0] pathComponents]; + [self assertTrue:[result isEqualToArray:testStrings[i][1]] message:"Expected [" + testStrings[i][1] + "] was [" + result + "]"]; + } +} + +- (void)testLastPathComponent +{ + var testStrings = [ + ["/tmp/scratch.tiff", "scratch.tiff"], + ["/tmp/scratch", "scratch"], + ["/tmp/", "tmp"], + ["scratch", "scratch"], + ["/", "/"] + ]; + + for (var i = 0; i < testStrings.length; i++) + [self assert:testStrings[i][1] equals:[testStrings[i][0] lastPathComponent]]; +} + @end From ad93ad55cc136076617968e81379c12252a84483 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Tue, 17 Mar 2009 19:19:08 -0700 Subject: [PATCH 54/62] Fixed some build bugs and moved capp to new build system. Reviewed by me. --- AppKit/Tools/blend/main.j | 2 - AppKit/Tools/blend/rakefile | 2 +- Objective-J/Tools/objj/main.js | 2 +- Tools/Rakefile | 15 + Tools/Utilities/bridge.js | 84 ++++- Tools/capp/Rakefile | 38 ++ .../Templates/Application/AppController.j | 0 .../Templates/Application/Info.plist | 0 .../Templates/Application/index-debug.html | 0 .../Templates/Application/index.html | 0 .../Templates/Application/main.j | 0 .../Templates/ThemeDescriptor/Info.plist | 0 .../ThemeDescriptor/ThemeDescriptors.j | 0 .../ThemeDescriptor/index-debug.html | 0 .../Templates/ThemeDescriptor/index.html | 0 .../Templates/ThemeDescriptor/main.j | 0 .../create-frameworks.js => capp/main.j} | 69 +++- Tools/nib2cib/Rakefile | 2 +- Tools/nib2cib/main.j | 2 - Tools/steam/Project.js | 331 ------------------ Tools/steam/build.js | 102 ------ Tools/steam/build.xml | 55 --- Tools/steam/create.js | 54 --- Tools/steam/htaccess | 12 - Tools/steam/inline-bundle.js | 156 --------- Tools/steam/main.js | 203 ----------- Tools/steam/sjheader.txt | 1 - Tools/steam/steam | 38 -- Tools/steam/steam.xml | 37 -- Tools/steam/usage.js | 22 -- Tools/steam/version.js | 5 - rakefile | 2 +- 32 files changed, 201 insertions(+), 1033 deletions(-) create mode 100644 Tools/Rakefile create mode 100644 Tools/capp/Rakefile rename Tools/{steam => capp}/Templates/Application/AppController.j (100%) rename Tools/{steam => capp}/Templates/Application/Info.plist (100%) rename Tools/{steam => capp}/Templates/Application/index-debug.html (100%) rename Tools/{steam => capp}/Templates/Application/index.html (100%) rename Tools/{steam => capp}/Templates/Application/main.j (100%) rename Tools/{steam => capp}/Templates/ThemeDescriptor/Info.plist (100%) rename Tools/{steam => capp}/Templates/ThemeDescriptor/ThemeDescriptors.j (100%) rename Tools/{steam => capp}/Templates/ThemeDescriptor/index-debug.html (100%) rename Tools/{steam => capp}/Templates/ThemeDescriptor/index.html (100%) rename Tools/{steam => capp}/Templates/ThemeDescriptor/main.j (100%) rename Tools/{steam/create-frameworks.js => capp/main.j} (56%) delete mode 100644 Tools/steam/Project.js delete mode 100644 Tools/steam/build.js delete mode 100644 Tools/steam/build.xml delete mode 100644 Tools/steam/create.js delete mode 100644 Tools/steam/htaccess delete mode 100644 Tools/steam/inline-bundle.js delete mode 100644 Tools/steam/main.js delete mode 100644 Tools/steam/sjheader.txt delete mode 100644 Tools/steam/steam delete mode 100644 Tools/steam/steam.xml delete mode 100644 Tools/steam/usage.js delete mode 100644 Tools/steam/version.js diff --git a/AppKit/Tools/blend/main.j b/AppKit/Tools/blend/main.j index d441154e4..4b6faf9cb 100644 --- a/AppKit/Tools/blend/main.j +++ b/AppKit/Tools/blend/main.j @@ -294,5 +294,3 @@ function exec(/*Array*/ command, /*Boolean*/ showOutput) } @end - -main.apply(main, args); diff --git a/AppKit/Tools/blend/rakefile b/AppKit/Tools/blend/rakefile index dbffcf2a0..19afc0502 100644 --- a/AppKit/Tools/blend/rakefile +++ b/AppKit/Tools/blend/rakefile @@ -34,5 +34,5 @@ file_d $ENVIRONMENT_BIN_PRODUCT do end file_d $ENVIRONMENT_LIB_PRODUCT => [:blend] do - cp_r($BUILD_PATH, $ENVIRONMENT_LIB_PRODUCT) + cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_LIB_PRODUCT) end diff --git a/Objective-J/Tools/objj/main.js b/Objective-J/Tools/objj/main.js index d4d1ba9d4..99414de96 100644 --- a/Objective-J/Tools/objj/main.js +++ b/Objective-J/Tools/objj/main.js @@ -49,7 +49,7 @@ try if (debug) print("Loading: " + mainFilePath); - objj_import(mainFilePath, YES, function() { if (typeof main === "Function") main.apply(main, args); } ); + objj_import(mainFilePath, YES, function() { if (typeof main === "function") main.apply(main, args); } ); serviceTimeouts(); diff --git a/Tools/Rakefile b/Tools/Rakefile new file mode 100644 index 000000000..05ee29aa5 --- /dev/null +++ b/Tools/Rakefile @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby + +require 'rake' +require '../common' + + +subprojects = %w{capp nib2cib} + +%w(build clean).each do |task_name| + task task_name do + subrake(subprojects) + end +end + +#task :deploy => [:build] \ No newline at end of file diff --git a/Tools/Utilities/bridge.js b/Tools/Utilities/bridge.js index d86c72471..1306ef2c0 100644 --- a/Tools/Utilities/bridge.js +++ b/Tools/Utilities/bridge.js @@ -584,4 +584,86 @@ if (!OBJJ_HOME) { OBJJ_HOME = "/usr/local/share/objj"; alert("OBJJ_HOME environment variable not set, defaulting to " + OBJJ_HOME); -} \ No newline at end of file +} + +function exec(/*Array*/ command, /*Boolean*/ showOutput) +{ + var line = "", + output = "", + + process = Packages.java.lang.Runtime.getRuntime().exec(command),//jsArrayToJavaArray(command)); + reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getInputStream())); + + while (line = reader.readLine()) + { + if (showOutput) + Packages.java.lang.System.out.println(line); + + output += line + '\n'; + } + + reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getErrorStream())); + + while (line = reader.readLine()) + Packages.java.lang.System.out.println(line); + + try + { + if (process.waitFor() != 0) + Packages.java.lang.System.err.println("exit value = " + process.exitValue()); + } + catch (anException) + { + Packages.java.lang.System.err.println(anException); + } + + return output; +} + + +function getFiles(/*File*/ sourceDirectory, /*nil|String|Array*/ extensions, /*Array*/ exclusions) +{ + var matches = [], + files = sourceDirectory.listFiles(), + hasMultipleExtensions = typeof extensions !== "string"; + + if (files) + { + var index = 0, + count = files.length; + + for (; index < count; ++index) + { + var file = files[index].getCanonicalFile(), + name = String(file.getName()), + isValidExtension = !extensions; + + if (exclusions && fileArrayContainsFile(exclusions, file)) + continue; + + if (!isValidExtension) + if (hasMultipleExtensions) + { + var extensionCount = extensions.length; + + while (extensionCount-- && !isValidExtension) + { + var extension = extensions[extensionCount]; + + if (name.substring(name.length - extension.length - 1) === ("." + extension)) + isValidExtension = true; + } + } + else if (name.substring(name.length - extensions.length - 1) === ("." + extensions)) + isValidExtension = true; + + if (isValidExtension) + matches.push(file); + + if (file.isDirectory()) + matches = matches.concat(getFiles(file, extensions, exclusions)); + } + } + + return matches; +} diff --git a/Tools/capp/Rakefile b/Tools/capp/Rakefile new file mode 100644 index 000000000..13f047fdf --- /dev/null +++ b/Tools/capp/Rakefile @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby + +require 'rake' +require '../../common' +require 'objective-j' +require 'objective-j/bundletask' + + +$PRODUCT = :capp +$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'capp') +$ENVIRONMENT_BIN_PRODUCT = File.join($ENVIRONMENT_BIN_DIR, 'capp') +$ENVIRONMENT_LIB_PRODUCT = File.join($ENVIRONMENT_LIB_DIR, 'capp') + +task :build => [:capp, $ENVIRONMENT_BIN_PRODUCT, $ENVIRONMENT_LIB_PRODUCT] + +# Debug Framework +ObjectiveJ::BundleTask.new(:capp) do |t| + t.name = 'capp' + t.identifier = 'com.280n.capp' + t.version = '0.6.5' + t.author = '280 North, Inc.' + t.email = 'feedback @nospam@ 280north.com' + t.summary = 'Setup up Cappuccino projects' + t.sources = FileList['*.j'] + t.resources = FileList['Resources/*'] + t.license = ObjectiveJ::License::LGPL_v2_1 + t.build_path = $BUILD_PATH + t.flag = 'DEBUG' if $CONFIGURATION == 'Debug' +end + +#executable in environment directory +file_d $ENVIRONMENT_BIN_PRODUCT do + make_objj_executable($ENVIRONMENT_BIN_PRODUCT) +end + +file_d $ENVIRONMENT_LIB_PRODUCT => [:capp] do + cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_LIB_PRODUCT) +end diff --git a/Tools/steam/Templates/Application/AppController.j b/Tools/capp/Templates/Application/AppController.j similarity index 100% rename from Tools/steam/Templates/Application/AppController.j rename to Tools/capp/Templates/Application/AppController.j diff --git a/Tools/steam/Templates/Application/Info.plist b/Tools/capp/Templates/Application/Info.plist similarity index 100% rename from Tools/steam/Templates/Application/Info.plist rename to Tools/capp/Templates/Application/Info.plist diff --git a/Tools/steam/Templates/Application/index-debug.html b/Tools/capp/Templates/Application/index-debug.html similarity index 100% rename from Tools/steam/Templates/Application/index-debug.html rename to Tools/capp/Templates/Application/index-debug.html diff --git a/Tools/steam/Templates/Application/index.html b/Tools/capp/Templates/Application/index.html similarity index 100% rename from Tools/steam/Templates/Application/index.html rename to Tools/capp/Templates/Application/index.html diff --git a/Tools/steam/Templates/Application/main.j b/Tools/capp/Templates/Application/main.j similarity index 100% rename from Tools/steam/Templates/Application/main.j rename to Tools/capp/Templates/Application/main.j diff --git a/Tools/steam/Templates/ThemeDescriptor/Info.plist b/Tools/capp/Templates/ThemeDescriptor/Info.plist similarity index 100% rename from Tools/steam/Templates/ThemeDescriptor/Info.plist rename to Tools/capp/Templates/ThemeDescriptor/Info.plist diff --git a/Tools/steam/Templates/ThemeDescriptor/ThemeDescriptors.j b/Tools/capp/Templates/ThemeDescriptor/ThemeDescriptors.j similarity index 100% rename from Tools/steam/Templates/ThemeDescriptor/ThemeDescriptors.j rename to Tools/capp/Templates/ThemeDescriptor/ThemeDescriptors.j diff --git a/Tools/steam/Templates/ThemeDescriptor/index-debug.html b/Tools/capp/Templates/ThemeDescriptor/index-debug.html similarity index 100% rename from Tools/steam/Templates/ThemeDescriptor/index-debug.html rename to Tools/capp/Templates/ThemeDescriptor/index-debug.html diff --git a/Tools/steam/Templates/ThemeDescriptor/index.html b/Tools/capp/Templates/ThemeDescriptor/index.html similarity index 100% rename from Tools/steam/Templates/ThemeDescriptor/index.html rename to Tools/capp/Templates/ThemeDescriptor/index.html diff --git a/Tools/steam/Templates/ThemeDescriptor/main.j b/Tools/capp/Templates/ThemeDescriptor/main.j similarity index 100% rename from Tools/steam/Templates/ThemeDescriptor/main.j rename to Tools/capp/Templates/ThemeDescriptor/main.j diff --git a/Tools/steam/create-frameworks.js b/Tools/capp/main.j similarity index 56% rename from Tools/steam/create-frameworks.js rename to Tools/capp/main.j index 89b355ea9..6d3545d49 100644 --- a/Tools/steam/create-frameworks.js +++ b/Tools/capp/main.j @@ -1,9 +1,21 @@ -function createFrameworks() + +importClass(java.io.File); +importClass(java.io.FileOutputStream); +importClass(java.io.BufferedWriter); +importClass(java.io.OutputStreamWriter); + +function main() { - var shouldSymbolicallyLink = false, - index = 0, + if (arguments.length < 1) + return printUsage(); + + var index = 0, count = arguments.length, + shouldSymbolicallyLink = false, + justFrameworks = false, + + template = "Application", destination = ""; for (; index < count; ++index) @@ -12,14 +24,50 @@ function createFrameworks() switch (arguments[index]) { - case "-l": shouldSymbolicallyLink = true; - break; + case "-l": shouldSymbolicallyLink = true; + break; + + case "-h": + case "--help": printUsage(); + return; - default: destination = argument; + case "-t": + case "--template": template = arguments[++index]; + break; + + case "-f": + case "--frameworks": justFrameworks = true; + break; + + default: destination = argument; } } - createFrameworksInFile(new File(destination), shouldSymbolicallyLink); + var sourceTemplate = new File(OBJJ_HOME + "/lib/steam/Templates/" + template), + destinationProject = new File(destination); + + if (!destinationProject.exists()) + { + exec(["cp", "-vR", sourceTemplate.getCanonicalPath(), destinationProject.getCanonicalPath()], true); + + var files = getFiles(destinationProject, ['j', "plist", "html"]), + index = 0, + count = files.length; + + for (; index < count; ++index) + { + var file = files[index], + contents = readFile(file); + + contents = contents.replace(/__Product__/g, destinationProject.getName()); + + writeContentsToFile(contents, file); + } + + createFrameworksInFile(destinationProject, shouldSymbolicallyLink); + } + else + System.out.println("Directory already exists"); } function createFrameworksInFile(/*File*/ aFile, /*Boolean*/ shouldSymbolicallyLink) @@ -63,4 +111,9 @@ function createFrameworksInFile(/*File*/ aFile, /*Boolean*/ shouldSymbolicallyLi exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/AppKit").getCanonicalPath(), new File(aFile.getCanonicalPath() + "/Frameworks/Debug/AppKit").getCanonicalPath()], true); -} \ No newline at end of file +} + +function printUsage() +{ + print("capp /path/to/your/app [options]"); +} diff --git a/Tools/nib2cib/Rakefile b/Tools/nib2cib/Rakefile index 201dc116d..1d28a345f 100644 --- a/Tools/nib2cib/Rakefile +++ b/Tools/nib2cib/Rakefile @@ -34,5 +34,5 @@ file_d $ENVIRONMENT_BIN_PRODUCT do end file_d $ENVIRONMENT_LIB_PRODUCT => [:nib2cib] do - cp_r($BUILD_PATH, $ENVIRONMENT_LIB_PRODUCT) + cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_LIB_PRODUCT) end diff --git a/Tools/nib2cib/main.j b/Tools/nib2cib/main.j index cda30b1e3..52b5882c1 100644 --- a/Tools/nib2cib/main.j +++ b/Tools/nib2cib/main.j @@ -248,5 +248,3 @@ function main() else convert(inputFileName, outputFileName, resourcesPath); } - -main.apply(main, args); diff --git a/Tools/steam/Project.js b/Tools/steam/Project.js deleted file mode 100644 index 3e48b401c..000000000 --- a/Tools/steam/Project.js +++ /dev/null @@ -1,331 +0,0 @@ - -importClass(java.io.FileOutputStream); -importClass(java.io.BufferedWriter); -importClass(java.io.OutputStreamWriter); - -function Target(dictionary) -{ - this._name = dictionary_getValue(dictionary, "Name"); - - var flagsString = dictionary_getValue(dictionary, "Flags"); - - this._flags = flagsString ? flagsString.split(/\s+/) : []; - - this._type = dictionary_getValue(dictionary, "Type"); - - if (!this._type) - this._type = "280N.application"; - - this._exclusions = []; - - var exclusions = dictionary_getValue(dictionary, "Excluded"); - - if (exclusions) - { - var index = 0, - count = exclusions.length; - - for (; index < count; ++index) - this._exclusions.push(new File((exclusions[index])).getCanonicalFile()); - } - - return this; -} - -Target.prototype.name = function() -{ - return this._name; -} - -Target.prototype.exclusions = function() -{ - return this._exclusions; -} - -Target.prototype.flags = function() -{ - return this._flags; -} - -Target.prototype.type = function() -{ - return this._type; -} - -function Configuration(dictionary) -{ - this._name = dictionary_getValue(dictionary, "Name"); - - var flagsString = dictionary_getValue(dictionary, "Flags"); - - this._flags = flagsString ? flagsString.split(/\s+/) : []; - - return this; -} - -Configuration.prototype.name = function() -{ - return this._name; -} - -Configuration.prototype.flags = function() -{ - return this._flags; -} - -function Project(/*String*/ aFilePath, /*String*/ aBuildPath) -{ - this._file = new File(aFilePath).getCanonicalFile(); - this._root = this._file.getParentFile(); - - // Read the project file (its just a plist). - this._properties = readPlist(this._file); - - this._name = dictionary_getValue(this._properties, "Name"); - - // Read existing Info.plist if it exists. - var infoPlist = new File(this._root.getAbsolutePath() + "/Info.plist"); - - if (infoPlist.exists()) - this._infoDictionary = readPlist(new File(this._root.getAbsolutePath() + "/Info.plist")); - else - this._infoDictionary = new objj_dictionary(); - - this.buildPath = aBuildPath; - - // Covert target dictionaries to target objects. - var targetDictionaries = dictionary_getValue(this._properties, "Targets"); - - this._targets = []; - - for (var index = 0, count = targetDictionaries.length; index < count; ++index) - this._targets.push(new Target(targetDictionaries[index])); - - this.setActiveTarget(this._targets[0]); - - // Covert target dictionaries to target objects. - var configurationDictionaries = dictionary_getValue(this._properties, "Configurations"); - - this._configurations = []; - - for (index = 0, count = configurationDictionaries.length; index < count; ++index) - this._configurations.push(new Configuration(configurationDictionaries[index])); - - this.setActiveConfiguration(this._configurations[0]); - - // Grab the Resources Directory (if it exists) - this._resources = new File(this._root.getAbsolutePath() + "/Resources/").getCanonicalFile(); - - return this; -} - -Project.prototype.name = function() -{ - return this._name; -} - -Project.prototype.targetWithName = function(/*String*/ aName) -{ - var targets = this._targets, - index = 0, - count = targets.length; - - for (; index < count; ++index) - { - var target = targets[index]; - - if (target.name() == aName) - return target; - } - - return null; -} - -Project.prototype.configurationWithName = function(/*String*/ aName) -{ - var configurations = this._configurations, - index = 0, - count = configurations.length; - - for (; index < count; ++index) - { - var configuration = configurations[index]; - - if (configuration.name() == aName) - return configuration; - } - - return null; -} - -Project.prototype.setActiveTarget = function(/*Target*/ aTarget) -{ - this._activeTarget = aTarget; - - this._buildProducts = null; - this._buildIntermediates = null; - this._buildObjects = null; -} - -Project.prototype.activeTarget = function() -{ - return this._activeTarget; -} - -Project.prototype.setActiveConfiguration = function(/*Configuration*/ aConfiguration) -{ - this._activeConfiguration = aConfiguration; - - this._buildProducts = null; - this._buildIntermediates = null; - this._buildObjects = null; -} - -Project.prototype.activeConfiguration = function() -{ - return this._activeConfiguration; -} - -Project.prototype.buildProducts = function() -{ - if (!this._buildProducts) - { - this._buildProducts = new File(this.buildPath + '/' + this._activeConfiguration.name() + '/' + this._activeTarget.name()).getCanonicalFile(); - this._buildProducts.mkdirs(); - } - - return this._buildProducts; -} - -Project.prototype.buildIntermediates = function() -{ - if (!this._buildIntermediates) - { - this._buildIntermediates = new File(this.buildPath + '/' + this._activeTarget.name() + ".build/" + this._activeConfiguration.name()).getCanonicalFile(); - this._buildIntermediates.mkdirs(); - } - - return this._buildIntermediates; -} - -Project.prototype.buildObjects = function() -{ - if (!this._buildObjects) - { - this._buildObjects = new File(this.buildIntermediates().getAbsolutePath() + '/' + this._activeTarget.name()).getCanonicalFile(); - this._buildObjects.mkdirs(); - } - - return this._buildObjects; -} - -Project.prototype.activeFlags = function() -{ - return this.activeTarget().flags().concat(this.activeConfiguration().flags()); -} - -Project.prototype.build = function() -{ - java.lang.System.out.println("Building Target \"" + this.activeTarget().name() + - "\" of Project \"" + this.name() + - "\" with Configuration \"" + this.activeConfiguration().name() + "\"."); - - var jFiles = getFiles(this._root, "j", this._activeTarget.exclusions()), - replacedFiles = []; - hasModifiedJFiles = false; - shouldObjjPreprocess = true, - shouldGzip = this._gzip, - objjcComponents = ["sh", OBJJ_HOME + "/bin/objjc"]; - - objjcComponents = objjcComponents.concat(this.activeFlags()); - - if (!shouldObjjPreprocess) - objjcComponents.push("-E"); - - var buildObjects = this.buildObjects(), - buildProducts = this.buildProducts(); - - for (index = 0, count = jFiles.length; index < count; ++index) - { - var file = jFiles[index], - builtFile = new File(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o'); - - replacedFiles.push(file.getName() + ""); - - if (builtFile.exists() && file.lastModified() < builtFile.lastModified()) - continue; - else - hasModifiedJFiles = true; - - objjcComponents.push(file.getAbsolutePath()); - - objjcComponents.push("-o"); - objjcComponents.push(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o'); - } - - exec(objjcComponents, true); - - var oFiles = getFiles(buildObjects, 'o'), - sjFile = new File(buildProducts.getCanonicalPath() + '/' + this._activeTarget.name() + ".sj"); - - if (hasModifiedJFiles) - { - // concatenate sjheader.txt and individual .o - exec(["sh", "-c", "cat '" + OBJJ_STEAM + "/sjheader.txt' '" + oFiles.join("' '") + "' > '" + sjFile.getCanonicalPath() + "'"], true); - } - - if (shouldGzip) - { - // gzip and copy .htaccess file - exec(["sh", "-c", "gzip -c '" + sjFile.getCanonicalPath() + "' > '" + sjFile.getCanonicalPath() + ".gz'"], true); - exec(["cp", OBJJ_HOME + "/lib/htaccess", sjFile.getParentFile().getCanonicalPath() + "/.htaccess"], true); - } - else - { - // remove gzip and .htaccess file if present - exec(["rm", "-f", sjFile.getParentFile().getCanonicalPath() + "/.htaccess", sjFile.getCanonicalPath() + ".gz"], true); - } - - dictionary_setValue(this._infoDictionary, "CPBundleExecutable", this._activeTarget.name() + ".sj"); - dictionary_setValue(this._infoDictionary, "CPBundleReplacedFiles", replacedFiles); - - this.writeInfoPlist(); - - this.copyResources(); - - // FIXME: This should be, if this is an app... - if (dictionary_getValue(this._infoDictionary, "CPBundlePackageType") == "280N") - this.copyIndexFile(); - -} - -Project.prototype.clean = function() -{ - java.lang.System.out.println("Cleaning Target \"" + this.activeTarget().name() + - "\" of Project \"" + this.name() + - "\" with Configuration \"" + this.activeConfiguration().name() + "\"."); - - exec(["rm", "-rf", this.buildIntermediates().getAbsolutePath()], true); - exec(["rm", "-rf", this.buildProducts().getAbsolutePath()], true); -} - -Project.prototype.copyIndexFile = function() -{ - var indexFile = new File(this._root.getAbsolutePath() + "/index.html").getCanonicalFile(); - - rsync(indexFile, this.buildProducts()); -} - -Project.prototype.writeInfoPlist = function() -{ - var writer = new BufferedWriter(new FileWriter(this.buildProducts().getAbsolutePath() + '/' + "Info.plist")); - - writer.write(CPPropertyListCreateXMLData(this._infoDictionary).string); - - writer.close(); -} - -Project.prototype.copyResources = function() -{ - rsync(this._resources, this.buildProducts()); -} diff --git a/Tools/steam/build.js b/Tools/steam/build.js deleted file mode 100644 index 042decf11..000000000 --- a/Tools/steam/build.js +++ /dev/null @@ -1,102 +0,0 @@ -function build() -{ - var index = 0, - count = arguments.length, - - actions = [], - - targetName = null, - configurationName = null, - - buildPath = null, - projectFilePath = null, - - gzip = false; - - for (; index < count; ++index) - { - switch (arguments[index]) - { - case "-f": if (index + 1 == count) - throw "-f needs project file."; - - projectFilePath = arguments[++index]; - break; - - case "-t": if (index + 1 == count) - throw "-t needs a target"; - - targetName = arguments[++index]; - break; - - case "-c": if (index + 1 == count) - throw "-c needs configuration"; - - configurationName = arguments[++index]; - break; - - case "-b": if (index + 1 == count) - throw "-b needs a build location"; - - buildPath = arguments[++index]; - break; - - case "--gzip": gzip = true; - break; - - case "clean": - case "build": actions.push(arguments[index]); - break; - } - } - - // If no project file was specified, look for one. - if (!projectFilePath) - { - var candidates = getFiles(new File('.'), "steam"); - - if (candidates.length < 1) - throw "No project file specified or found."; - - projectFilePath = candidates[0]; - } - - // Construct the Build Directory - if (!buildPath) - { - buildPath = System.getenv("STEAM_BUILD"); - - if (!buildPath) - buildPath = "Build"; - } - - var project = new Project(projectFilePath, buildPath); - - project._gzip = gzip; - - if (targetName) - { - var target = project.targetWithName(targetName); - - if (!target) - throw "Target \"" + targetName + "\" not found in project."; - - project.setActiveTarget(target); - } - - if (configurationName) - { - var configuration = project.configurationWithName(configurationName); - - if (!configuration) - throw "Configuration \"" + configurationName + "\" not found in project."; - - project.setActiveConfiguration(configuration); - } - - if (!actions.length) - actions.push("build"); - - for (index = 0, count = actions.length; index < count; ++index) - project[actions[index]](); -} diff --git a/Tools/steam/build.xml b/Tools/steam/build.xml deleted file mode 100644 index 723ea5b2f..000000000 --- a/Tools/steam/build.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Tools/steam/create.js b/Tools/steam/create.js deleted file mode 100644 index 73abaa8dc..000000000 --- a/Tools/steam/create.js +++ /dev/null @@ -1,54 +0,0 @@ -function create() -{ - if (arguments.length < 1) - printUsage("create"); - - var shouldSymbolicallyLink = false, - index = 0, - count = arguments.length, - - template = "Application", - destination = ""; - - for (; index < count; ++index) - { - var argument = arguments[index]; - - switch (arguments[index]) - { - case "-l": shouldSymbolicallyLink = true; - break; - - case "--template": template = arguments[++index]; - break; - - default: destination = argument; - } - } - - var sourceTemplate = new File(OBJJ_HOME + "/lib/steam/Templates/" + template), - destinationProject = new File(destination); - - if (!destinationProject.exists()) - { - exec(["cp", "-vR", sourceTemplate.getCanonicalPath(), destinationProject.getCanonicalPath()], true); - - var files = getFiles(destinationProject, ['j', "plist", "html"]), - index = 0, - count = files.length; - - for (; index < count; ++index) - { - var file = files[index], - contents = readFile(file); - - contents = contents.replace(/__Product__/g, destinationProject.getName()); - - writeContentsToFile(contents, file); - } - - createFrameworksInFile(destinationProject, shouldSymbolicallyLink); - } - else - System.out.println("Directory already exists"); -} diff --git a/Tools/steam/htaccess b/Tools/steam/htaccess deleted file mode 100644 index 6afc67f10..000000000 --- a/Tools/steam/htaccess +++ /dev/null @@ -1,12 +0,0 @@ -Options +FollowSymLinks - -AddEncoding x-gzip .gz -AddType text/plain .gz - -RewriteEngine on - -# These conditions slow down the requests significantly. We can probably assume they're always true. -# We should ensure the gzipped version always exists if we include this .htaccess. All supported browsers accept gzip encoding. -#RewriteCond %{REQUEST_FILENAME}.gz -f -#RewriteCond %{HTTP:Accept-Encoding} gzip -RewriteRule ^(.*\.(sj|js))$ %{REQUEST_URI}/../$1.gz diff --git a/Tools/steam/inline-bundle.js b/Tools/steam/inline-bundle.js deleted file mode 100644 index 2e2dc8643..000000000 --- a/Tools/steam/inline-bundle.js +++ /dev/null @@ -1,156 +0,0 @@ -function inlineBundle() -{ - var index = 0, - count = arguments.length, - bundlePath = NULL; - - for (; index < count; ++index) - { - var argument = arguments[index]; - - switch (arguments[index]) - { - case "-d": directoryPath = arguments[++index]; - break; - - default: bundlePath = argument; - } - } - - var bundleFile = new File(bundlePath).getCanonicalFile(), - bundlePath = String(bundleFile.getCanonicalPath()), - inlinedBundle = readBundle(bundleFile, true), - inlinedFiles = [], - replacedFiles = [], - staticContent = ""; - - // Find all internal bundles. - var bundleCandidates = getFiles(bundleFile, "plist"), - bundleCandidatesCount = bundleCandidates.length; - - while (bundleCandidatesCount--) - { - var bundleCandidate = bundleCandidates[bundleCandidatesCount]; - - // We only care about Info.plists, specifically the ones that aren't us. - if (String(bundleCandidate.getName()) !== "Info.plist" || String(bundleCandidate.getCanonicalPath()) === inlinedBundle.path) - continue; - - var infoDictionary = readPlist(bundleCandidate); - - // At least one of these two has to be present for this to be a real deal bundle. - if (!dictionary_getValue(infoDictionary, "CPBundleIdentifier") && !dictionary_getValue(infoDictionary, "CPBundleName")) - continue; - - java.lang.System.out.println(" Examining " + pathRelativeTo(bundleCandidate.getCanonicalPath(), bundlePath)); - - dictionary_removeValue(infoDictionary, "CPBundleExecutable"); - - var bundle = readBundle(bundleCandidate.getParentFile(), true); - - bundle.path = pathRelativeTo(bundle.path, bundlePath); - - // We want to inline the info plist too. - var inlinedFiles = [makeOBJJPlistFile(infoDictionary, bundleCandidate, bundle)].concat(bundle.files), - index = 0, - count = inlinedFiles.length; - - for (; index < count; ++index) - { - var file = inlinedFiles[index]; - - file.path = pathRelativeTo(String(file.path), bundlePath); - - java.lang.System.out.println(" Inlining " + file.path); - - replacedFiles.push(file.path); - staticContent += fileToMarkedString(inlinedFiles[index], true); - } - } - - var index = 0, - existingStaticFiles = inlinedBundle.files, - count = existingStaticFiles.length, - topLevelContent = "@STATIC;1.0;"; - - for (; index < count; ++index) - { - var file = existingStaticFiles[index]; - - // If this isn't actually part of our bundle, drop it! - if (file.bundle !== inlinedBundle) - continue; - - file.path = pathRelativeTo(String(file.path), bundlePath); - - replacedFiles.push(file.path); - topLevelContent += fileToMarkedString(file, false); - } - - dictionary_setValue(inlinedBundle.info, "CPBundleReplacedFiles", replacedFiles); - - writeContentsToFile(CPPropertyListCreateXMLData(inlinedBundle.info).string, inlinedBundle.path); - writeContentsToFile(topLevelContent + staticContent, inlinedBundle._staticContentPath); -} - -function fileToMarkedString(anOBJJFile, encodeBundle) -{ - var markedString = ""; - - markedString += MARKER_PATH + ';' + anOBJJFile.path.length + ';' + anOBJJFile.path; - - if (encodeBundle) - markedString += MARKER_BUNDLE + ';' + anOBJJFile.bundle.path.length + ';' + anOBJJFile.bundle.path; - - var fragments = anOBJJFile.fragments; - - if (fragments && fragments.length > 0) - { - var fragmentIndex = 0, - fragmentCount = fragments.length; - - for (; fragmentIndex < fragmentCount; ++fragmentIndex) - markedString += fragments[fragmentIndex].toMarkedString(); - } - - else - markedString += MARKER_TEXT + ';' + anOBJJFile.contents.length + ';' + anOBJJFile.contents; - - return markedString; -} - -function makeOBJJPlistFile(aDictionary, aFile, aBundle) -{ - var file = new objj_file(); - - file.path = typeof aFile === "string" ? aFile : aFile.getCanonicalPath(); - file.bundle = aBundle; - file.contents = CPPropertyListCreate280NorthData(aDictionary).string; - - return file; -} - -function pathRelativeTo(target, relativeTo) -{ - var components = [], - targetParts = target.split("/"), - relativeParts = relativeTo ? relativeTo.split("/") : []; - - var i = 0; - while (i < targetParts.length) - { - if (targetParts[i] != relativeParts[i]) - break; - i++; - } - - for (var j = i; j < relativeParts.length; j++) - components.push(".."); - - for (var j = i; j < targetParts.length; j++) - components.push(targetParts[j]); - - var result = components.join("/"); - - return result; -} \ No newline at end of file diff --git a/Tools/steam/main.js b/Tools/steam/main.js deleted file mode 100644 index d007905f7..000000000 --- a/Tools/steam/main.js +++ /dev/null @@ -1,203 +0,0 @@ - -importPackage(java.lang); -importPackage(java.util); - -importClass(java.io.File); -importClass(java.io.BufferedReader); -importClass(java.io.FileReader); -importClass(java.io.BufferedWriter); -importClass(java.io.FileWriter); -importClass(java.io.SequenceInputStream); - -#include "../Utilities/bundle.js" - -#include "Project.js" - -OBJJ_STEAM = OBJJ_HOME + "/lib/steam/"; - -function main() -{ - if (arguments.length < 1) - printUsage(); - - var command = Array.prototype.shift.apply(arguments); - - switch (command) - { - case "create": create.apply(create, arguments); - break; - - case "create-frameworks": createFrameworks.apply(createFrameworks, arguments); - break; - - - case "inline-bundle": inlineBundle.apply(inlineBundle, arguments); - break; - - case "build": build.apply(build, arguments); - break; - - case "help": printUsage(arguments[1]); - break; - - case "version": - case "--version": printVersion(); - break; - - default : printUsage(command); - } - -} - -function fileArrayContainsFile(/*Array*/ files, /*File*/ aFile) -{ - var index = 0, - count = files.length; - - for (; index < count; ++index) - if (files[index].equals(aFile)) - return true; - - return false; -} - -function getFiles(/*File*/ sourceDirectory, /*nil|String|Array*/ extensions, /*Array*/ exclusions) -{ - var matches = [], - files = sourceDirectory.listFiles(), - hasMultipleExtensions = typeof extensions !== "string"; - - if (files) - { - var index = 0, - count = files.length; - - for (; index < count; ++index) - { - var file = files[index].getCanonicalFile(), - name = String(file.getName()), - isValidExtension = !extensions; - - if (exclusions && fileArrayContainsFile(exclusions, file)) - continue; - - if (!isValidExtension) - if (hasMultipleExtensions) - { - var extensionCount = extensions.length; - - while (extensionCount-- && !isValidExtension) - { - var extension = extensions[extensionCount]; - - if (name.substring(name.length - extension.length - 1) === ("." + extension)) - isValidExtension = true; - } - } - else if (name.substring(name.length - extensions.length - 1) === ("." + extensions)) - isValidExtension = true; - - if (isValidExtension) - matches.push(file); - - if (file.isDirectory()) - matches = matches.concat(getFiles(file, extensions, exclusions)); - } - } - - return matches; -} - -function exec(/*Array*/ command, /*Boolean*/ showOutput) -{ - var line = "", - output = "", - - process = Packages.java.lang.Runtime.getRuntime().exec(command),//jsArrayToJavaArray(command)); - reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getInputStream())); - - while (line = reader.readLine()) - { - if (showOutput) - System.out.println(line); - - output += line + '\n'; - } - - reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getErrorStream())); - - while (line = reader.readLine()) - System.out.println(line); - - try - { - if (process.waitFor() != 0) - System.err.println("exit value = " + process.exitValue()); - } - catch (anException) - { - System.err.println(anException); - } - - return output; -} - -function rsync(srcFile, dstFile) -{ - var src, dst; - - if (String(java.lang.System.getenv("OS")).indexOf("Windows") < 0) - { - src = srcFile.getAbsolutePath(); - dst = dstFile.getAbsolutePath(); - } - else - { - src = exec(["cygpath", "-u", srcFile.getAbsolutePath() + '/']); - dst = exec(["cygpath", "-u", dstFile.getAbsolutePath() + "/Resources"]); - } - - if (srcFile.exists()) - exec(["rsync", "-avz", src, dst]); -} - -function getFileName(aPath) -{ - var index = aPath.lastIndexOf('/'); - - if (index == -1) - return aPath; - - return aPath.substr(index + 1); -} - -function getFileNameWithoutExtension(aFileOrFileName) -{ - var name = typeof aFileOrFileName === "string" ? aFileOrFileName : aFileOrFileName.getName(), - index = name.lastIndexOf('.'); - - if (index == -1 || index == 0) - return name; - - return name.substr(0, index); -} - -function getFileExtension(aPath) -{ - var slash = aPath.lastIndexOf('/'), - period = aPath.lastIndexOf('.'); - - if (period < slash || (period == slash + 1)) - return ""; - - return aPath.substr(period + 1); -} - -main.apply(main, arguments); - -#include "build.js" -#include "create.js" -#include "create-frameworks.js" -#include "inline-bundle.js" -#include "usage.js" -#include "version.js" diff --git a/Tools/steam/sjheader.txt b/Tools/steam/sjheader.txt deleted file mode 100644 index 57390737c..000000000 --- a/Tools/steam/sjheader.txt +++ /dev/null @@ -1 +0,0 @@ -@STATIC;1.0; \ No newline at end of file diff --git a/Tools/steam/steam b/Tools/steam/steam deleted file mode 100644 index e66147478..000000000 --- a/Tools/steam/steam +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -# if OBJJ_HOME isn't set, try to determine it -if [ -z $OBJJ_HOME ]; then - # get path of the executable - SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") - - # resolve symlinks - if [ -h $SELF_PATH ]; then - SELF_PATH=`readlink $SELF_PATH` - fi - - # get second ancestor directory - SELF_DIR=`dirname $SELF_PATH` - export OBJJ_HOME=`dirname $SELF_DIR` - - # check to ensure it exists, print message - if [ -d $OBJJ_HOME ]; then - echo "OBJJ_HOME not set, defaulting to $OBJJ_HOME" 1>&2 - else - echo "OBJJ_HOME not set, default at $OBJJ_HOME doesn't exist, exiting" 1>&2 - exit 2 - fi -fi - -OBJJ_LIB="$OBJJ_HOME/lib" -STEAM="$OBJJ_LIB/steam" -CLASSPATH="$STEAM:$OBJJ_LIB:$OBJJ_LIB/js.jar" - -# convert paths for Cygwin -if [[ `uname` == CYGWIN* ]]; then - CLASSPATH=`cygpath -wp "$CLASSPATH"` - STEAM_BUILD=`cygpath -wp "$STEAM_BUILD"` -fi - -export OBJJ_LIB - -java -classpath $CLASSPATH steam $@ diff --git a/Tools/steam/steam.xml b/Tools/steam/steam.xml deleted file mode 100644 index 8b5e0a9f6..000000000 --- a/Tools/steam/steam.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Tools/steam/usage.js b/Tools/steam/usage.js deleted file mode 100644 index 389fadc53..000000000 --- a/Tools/steam/usage.js +++ /dev/null @@ -1,22 +0,0 @@ -function printUsage(command) -{ - var usage = "usage: steam COMMAND [ARGS]\n\n"+ -"The most commonly used steam commands are:\n"+ -"\tbuild Build a project\n"+ -"\tcreate Create a new project\n\n"+ -"See 'steam help COMMAND' for more information on a specific command."; - - switch (command) - { - case "--help": - case undefined: java.lang.System.out.println(usage); - break; - - case "create": java.lang.System.out.println("Creates a new Cappuccino project.\n\nusage: steam create PROJECT_NAME [-l]\n\n"+ - "\t-l Link Frameworks to $STEAM_BUILD/Release, instead of installing default Frameworks"); - break; - - default: java.lang.System.out.println("steam: '" + command + "' is not a steam command. See 'steam --help'."); - } - java.lang.System.exit(1); -} diff --git a/Tools/steam/version.js b/Tools/steam/version.js deleted file mode 100644 index c22171a3f..000000000 --- a/Tools/steam/version.js +++ /dev/null @@ -1,5 +0,0 @@ -function printVersion() -{ - java.lang.System.out.println("steam version 0.6"); - java.lang.System.exit(1); -} \ No newline at end of file diff --git a/rakefile b/rakefile index 253d35f74..a52f5a657 100644 --- a/rakefile +++ b/rakefile @@ -4,7 +4,7 @@ require 'rake' require 'common' -subprojects = %w{Objective-J Foundation AppKit} +subprojects = %w{Objective-J Foundation AppKit Tools} %w(build clean).each do |task_name| task task_name do From 487bf288e53e8cb771a8bcbdc64b0dd4eaf30def Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Tue, 17 Mar 2009 19:28:12 -0700 Subject: [PATCH 55/62] Moved all editing modes to one folder. Reviewed by me. --- .../{ => Editors}/SubEthaEdit/Objective-J.mode.zip | Bin .../TextMate/JavaScript Objective-J.tmbundle.zip | Bin Tools/{ => Editors}/Vim/objj.vim | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename Tools/{ => Editors}/SubEthaEdit/Objective-J.mode.zip (100%) rename Tools/{ => Editors}/TextMate/JavaScript Objective-J.tmbundle.zip (100%) rename Tools/{ => Editors}/Vim/objj.vim (100%) diff --git a/Tools/SubEthaEdit/Objective-J.mode.zip b/Tools/Editors/SubEthaEdit/Objective-J.mode.zip similarity index 100% rename from Tools/SubEthaEdit/Objective-J.mode.zip rename to Tools/Editors/SubEthaEdit/Objective-J.mode.zip diff --git a/Tools/TextMate/JavaScript Objective-J.tmbundle.zip b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle.zip similarity index 100% rename from Tools/TextMate/JavaScript Objective-J.tmbundle.zip rename to Tools/Editors/TextMate/JavaScript Objective-J.tmbundle.zip diff --git a/Tools/Vim/objj.vim b/Tools/Editors/Vim/objj.vim similarity index 100% rename from Tools/Vim/objj.vim rename to Tools/Editors/Vim/objj.vim From 31279a0cdcdbb8d57fad9b3a0ebcf02e30f576f2 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Wed, 18 Mar 2009 16:37:06 -0700 Subject: [PATCH 56/62] Fix for copy bug and added capp changes. Reviewed by me. --- AppKit/Tools/BlendKit/rakefile | 2 +- AppKit/rakefile | 2 +- Foundation/CPBundle.j | 5 +++++ Foundation/rakefile | 2 +- Objective-J/rakefile | 2 +- Tools/capp/Rakefile | 2 +- Tools/capp/main.j | 26 +++++++++++++++++++------- 7 files changed, 29 insertions(+), 12 deletions(-) diff --git a/AppKit/Tools/BlendKit/rakefile b/AppKit/Tools/BlendKit/rakefile index bdcad5ff4..d64831f9a 100644 --- a/AppKit/Tools/BlendKit/rakefile +++ b/AppKit/Tools/BlendKit/rakefile @@ -27,5 +27,5 @@ end #Framework in environment directory file_d $ENVIRONMENT_PRODUCT => [:BlendKit] do - cp_r($BUILD_PATH, $ENVIRONMENT_PRODUCT) + cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_PRODUCT) end diff --git a/AppKit/rakefile b/AppKit/rakefile index f5888a5ab..d7a944118 100644 --- a/AppKit/rakefile +++ b/AppKit/rakefile @@ -33,7 +33,7 @@ end #Framework in environment directory file_d $ENVIRONMENT_PRODUCT => [:AppKit] do - cp_r($BUILD_PATH, $ENVIRONMENT_PRODUCT) + cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_PRODUCT) end ThemeFiles = FileList['Themes/Aristo/*'] diff --git a/Foundation/CPBundle.j b/Foundation/CPBundle.j index 32736b885..56ad05349 100644 --- a/Foundation/CPBundle.j +++ b/Foundation/CPBundle.j @@ -93,6 +93,11 @@ return className ? CPClassFromString(className) : Nil; } +- (CPString)pathForResource:(CPString)aFilename +{ + return [self resourcePath] + '/' + aFilename; +} + - (CPDictionary)infoDictionary { return info; diff --git a/Foundation/rakefile b/Foundation/rakefile index e9fc33948..00ca83da1 100644 --- a/Foundation/rakefile +++ b/Foundation/rakefile @@ -27,5 +27,5 @@ end #Framework in environment directory file_d $ENVIRONMENT_PRODUCT => [:Foundation] do - cp_r($BUILD_PATH, $ENVIRONMENT_PRODUCT) + cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_PRODUCT) end diff --git a/Objective-J/rakefile b/Objective-J/rakefile index 99aed6c05..f20ce68dc 100644 --- a/Objective-J/rakefile +++ b/Objective-J/rakefile @@ -46,7 +46,7 @@ end #Framework in environment directory file_d $ENVIRONMENT_PRODUCT => [:Products] do - cp_r($PRODUCT, $ENVIRONMENT_PRODUCT) + cp_r(File.join($PRODUCT, '.'), $ENVIRONMENT_PRODUCT) end def platform_flags(*platforms) diff --git a/Tools/capp/Rakefile b/Tools/capp/Rakefile index 13f047fdf..afd9c0ec9 100644 --- a/Tools/capp/Rakefile +++ b/Tools/capp/Rakefile @@ -22,7 +22,7 @@ ObjectiveJ::BundleTask.new(:capp) do |t| t.email = 'feedback @nospam@ 280north.com' t.summary = 'Setup up Cappuccino projects' t.sources = FileList['*.j'] - t.resources = FileList['Resources/*'] + t.resources = FileList['Resources/*', 'Templates'] t.license = ObjectiveJ::License::LGPL_v2_1 t.build_path = $BUILD_PATH t.flag = 'DEBUG' if $CONFIGURATION == 'Debug' diff --git a/Tools/capp/main.j b/Tools/capp/main.j index 6d3545d49..024fdd617 100644 --- a/Tools/capp/main.j +++ b/Tools/capp/main.j @@ -1,14 +1,18 @@ +importClass(java.lang.System); importClass(java.io.File); +importClass(java.io.FileWriter); importClass(java.io.FileOutputStream); importClass(java.io.BufferedWriter); importClass(java.io.OutputStreamWriter); +@import + function main() { if (arguments.length < 1) return printUsage(); - + var index = 0, count = arguments.length, @@ -43,7 +47,7 @@ function main() } } - var sourceTemplate = new File(OBJJ_HOME + "/lib/steam/Templates/" + template), + var sourceTemplate = new File(OBJJ_HOME + "/lib/capp/Resources/Templates/" + template), destinationProject = new File(destination); if (!destinationProject.exists()) @@ -67,7 +71,7 @@ function main() createFrameworksInFile(destinationProject, shouldSymbolicallyLink); } else - System.out.println("Directory already exists"); + print("Directory already exists"); } function createFrameworksInFile(/*File*/ aFile, /*Boolean*/ shouldSymbolicallyLink) @@ -77,12 +81,10 @@ function createFrameworksInFile(/*File*/ aFile, /*Boolean*/ shouldSymbolicallyLi if (!shouldSymbolicallyLink) { - var sourceFrameworks = new File(OBJJ_HOME + "/lib/Frameworks"), - sourceDebugFrameworks = new File(OBJJ_HOME + "/lib/Frameworks-Debug"); + var sourceFrameworks = new File(OBJJ_HOME + "/lib/Frameworks"); exec(["cp", "-vR", sourceFrameworks.getCanonicalPath(), destinationFrameworks.getCanonicalPath()], true); - exec(["cp", "-vR", sourceDebugFrameworks.getCanonicalPath(), destinationDebugFrameworks.getCanonicalPath()], true); - + return true; } @@ -117,3 +119,13 @@ function printUsage() { print("capp /path/to/your/app [options]"); } + + +function writeContentsToFile(/*String*/ aString, /*File*/ aFile) +{ + var writer = new BufferedWriter(new FileWriter(aFile)); + + writer.write(aString); + + writer.close(); +} From bd07c5338a5d72eacd9c0984fc07e46ff7992af0 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Wed, 18 Mar 2009 16:41:42 -0700 Subject: [PATCH 57/62] Name changes Reviewed by me. --- AppKit/{rakefile => Rakefile} | 0 AppKit/Tools/BlendKit/Rakefile | 31 +++++++++++++++++++++++ AppKit/Tools/blend/{rakefile => Rakefile} | 0 Foundation/{rakefile => Rakefile} | 0 rakefile => Rakefile | 0 5 files changed, 31 insertions(+) rename AppKit/{rakefile => Rakefile} (100%) create mode 100644 AppKit/Tools/BlendKit/Rakefile rename AppKit/Tools/blend/{rakefile => Rakefile} (100%) rename Foundation/{rakefile => Rakefile} (100%) rename rakefile => Rakefile (100%) diff --git a/AppKit/rakefile b/AppKit/Rakefile similarity index 100% rename from AppKit/rakefile rename to AppKit/Rakefile diff --git a/AppKit/Tools/BlendKit/Rakefile b/AppKit/Tools/BlendKit/Rakefile new file mode 100644 index 000000000..d64831f9a --- /dev/null +++ b/AppKit/Tools/BlendKit/Rakefile @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +require 'rake' +require '../../../common' +require 'objective-j' +require 'objective-j/bundletask' + + +$ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'BlendKit') +$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'BlendKit') + +task :build => [:BlendKit, $ENVIRONMENT_PRODUCT] + +ObjectiveJ::BundleTask.new(:BlendKit) do |t| + t.name = 'BlendKit' + t.identifier = 'com.280n.BlendKit' + t.version = '0.6.5' + t.author = '280 North, Inc.' + t.email = 'feedback @nospam@ 280north.com' + t.summary = 'BlendKit classes for Cappuccino' + t.sources = FileList['*.j'] + t.resources = FileList['Resources/*'].to_a + t.license = ObjectiveJ::License::LGPL_v2_1 + t.build_path = $BUILD_PATH + t.flag = 'DEBUG' if $CONFIGURATION == 'Debug' +end + +#Framework in environment directory +file_d $ENVIRONMENT_PRODUCT => [:BlendKit] do + cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_PRODUCT) +end diff --git a/AppKit/Tools/blend/rakefile b/AppKit/Tools/blend/Rakefile similarity index 100% rename from AppKit/Tools/blend/rakefile rename to AppKit/Tools/blend/Rakefile diff --git a/Foundation/rakefile b/Foundation/Rakefile similarity index 100% rename from Foundation/rakefile rename to Foundation/Rakefile diff --git a/rakefile b/Rakefile similarity index 100% rename from rakefile rename to Rakefile From 07b6f54990ea60a6a4a169b61a00a266581cf311 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Wed, 18 Mar 2009 16:48:44 -0700 Subject: [PATCH 58/62] Name change. Reviewed by me. --- AppKit/Tools/{rakefile => Rakefile} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename AppKit/Tools/{rakefile => Rakefile} (100%) diff --git a/AppKit/Tools/rakefile b/AppKit/Tools/Rakefile similarity index 100% rename from AppKit/Tools/rakefile rename to AppKit/Tools/Rakefile From 3eed879fd2094c36a936e4d8c7756c1ab46cae56 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Wed, 18 Mar 2009 16:51:01 -0700 Subject: [PATCH 59/62] More name changes. Reviewed by me. --- Objective-J/{rakefile => Rakefile} | 0 Objective-J/Tools/{rakefile => Rakefile} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Objective-J/{rakefile => Rakefile} (100%) rename Objective-J/Tools/{rakefile => Rakefile} (100%) diff --git a/Objective-J/rakefile b/Objective-J/Rakefile similarity index 100% rename from Objective-J/rakefile rename to Objective-J/Rakefile diff --git a/Objective-J/Tools/rakefile b/Objective-J/Tools/Rakefile similarity index 100% rename from Objective-J/Tools/rakefile rename to Objective-J/Tools/Rakefile From c6e266b08fd8682fbc60cec7e13c597fc729f533 Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Wed, 18 Mar 2009 16:53:00 -0700 Subject: [PATCH 60/62] Name changes. Reviewed by me. --- .../Tools/cplutil/{rakefile => Rakefile} | 0 Objective-J/Tools/objj/{rakefile => Rakefile} | 0 .../Tools/objjc/{rakefile => Rakefile} | 0 Objective-J/Tools/steam/Project.js | 331 ------------------ .../Templates/Application/AppController.j | 39 --- .../steam/Templates/Application/Info.plist | 12 - .../Templates/Application/index-debug.html | 36 -- .../steam/Templates/Application/index.html | 37 -- .../Tools/steam/Templates/Application/main.j | 18 - .../Templates/ThemeDescriptor/Info.plist | 12 - .../ThemeDescriptor/ThemeDescriptors.j | 33 -- .../ThemeDescriptor/index-debug.html | 36 -- .../Templates/ThemeDescriptor/index.html | 37 -- .../steam/Templates/ThemeDescriptor/main.j | 19 - Objective-J/Tools/steam/build.js | 102 ------ Objective-J/Tools/steam/build.xml | 55 --- Objective-J/Tools/steam/create-frameworks.js | 66 ---- Objective-J/Tools/steam/create.js | 54 --- Objective-J/Tools/steam/htaccess | 12 - Objective-J/Tools/steam/inline-bundle.js | 156 --------- Objective-J/Tools/steam/main.js | 203 ----------- Objective-J/Tools/steam/sjheader.txt | 1 - Objective-J/Tools/steam/steam | 38 -- Objective-J/Tools/steam/steam.xml | 37 -- Objective-J/Tools/steam/usage.js | 22 -- Objective-J/Tools/steam/version.js | 5 - 26 files changed, 1361 deletions(-) rename Objective-J/Tools/cplutil/{rakefile => Rakefile} (100%) rename Objective-J/Tools/objj/{rakefile => Rakefile} (100%) rename Objective-J/Tools/objjc/{rakefile => Rakefile} (100%) delete mode 100644 Objective-J/Tools/steam/Project.js delete mode 100644 Objective-J/Tools/steam/Templates/Application/AppController.j delete mode 100644 Objective-J/Tools/steam/Templates/Application/Info.plist delete mode 100644 Objective-J/Tools/steam/Templates/Application/index-debug.html delete mode 100644 Objective-J/Tools/steam/Templates/Application/index.html delete mode 100755 Objective-J/Tools/steam/Templates/Application/main.j delete mode 100644 Objective-J/Tools/steam/Templates/ThemeDescriptor/Info.plist delete mode 100644 Objective-J/Tools/steam/Templates/ThemeDescriptor/ThemeDescriptors.j delete mode 100644 Objective-J/Tools/steam/Templates/ThemeDescriptor/index-debug.html delete mode 100644 Objective-J/Tools/steam/Templates/ThemeDescriptor/index.html delete mode 100755 Objective-J/Tools/steam/Templates/ThemeDescriptor/main.j delete mode 100644 Objective-J/Tools/steam/build.js delete mode 100644 Objective-J/Tools/steam/build.xml delete mode 100644 Objective-J/Tools/steam/create-frameworks.js delete mode 100644 Objective-J/Tools/steam/create.js delete mode 100644 Objective-J/Tools/steam/htaccess delete mode 100644 Objective-J/Tools/steam/inline-bundle.js delete mode 100644 Objective-J/Tools/steam/main.js delete mode 100644 Objective-J/Tools/steam/sjheader.txt delete mode 100644 Objective-J/Tools/steam/steam delete mode 100644 Objective-J/Tools/steam/steam.xml delete mode 100644 Objective-J/Tools/steam/usage.js delete mode 100644 Objective-J/Tools/steam/version.js diff --git a/Objective-J/Tools/cplutil/rakefile b/Objective-J/Tools/cplutil/Rakefile similarity index 100% rename from Objective-J/Tools/cplutil/rakefile rename to Objective-J/Tools/cplutil/Rakefile diff --git a/Objective-J/Tools/objj/rakefile b/Objective-J/Tools/objj/Rakefile similarity index 100% rename from Objective-J/Tools/objj/rakefile rename to Objective-J/Tools/objj/Rakefile diff --git a/Objective-J/Tools/objjc/rakefile b/Objective-J/Tools/objjc/Rakefile similarity index 100% rename from Objective-J/Tools/objjc/rakefile rename to Objective-J/Tools/objjc/Rakefile diff --git a/Objective-J/Tools/steam/Project.js b/Objective-J/Tools/steam/Project.js deleted file mode 100644 index 3e48b401c..000000000 --- a/Objective-J/Tools/steam/Project.js +++ /dev/null @@ -1,331 +0,0 @@ - -importClass(java.io.FileOutputStream); -importClass(java.io.BufferedWriter); -importClass(java.io.OutputStreamWriter); - -function Target(dictionary) -{ - this._name = dictionary_getValue(dictionary, "Name"); - - var flagsString = dictionary_getValue(dictionary, "Flags"); - - this._flags = flagsString ? flagsString.split(/\s+/) : []; - - this._type = dictionary_getValue(dictionary, "Type"); - - if (!this._type) - this._type = "280N.application"; - - this._exclusions = []; - - var exclusions = dictionary_getValue(dictionary, "Excluded"); - - if (exclusions) - { - var index = 0, - count = exclusions.length; - - for (; index < count; ++index) - this._exclusions.push(new File((exclusions[index])).getCanonicalFile()); - } - - return this; -} - -Target.prototype.name = function() -{ - return this._name; -} - -Target.prototype.exclusions = function() -{ - return this._exclusions; -} - -Target.prototype.flags = function() -{ - return this._flags; -} - -Target.prototype.type = function() -{ - return this._type; -} - -function Configuration(dictionary) -{ - this._name = dictionary_getValue(dictionary, "Name"); - - var flagsString = dictionary_getValue(dictionary, "Flags"); - - this._flags = flagsString ? flagsString.split(/\s+/) : []; - - return this; -} - -Configuration.prototype.name = function() -{ - return this._name; -} - -Configuration.prototype.flags = function() -{ - return this._flags; -} - -function Project(/*String*/ aFilePath, /*String*/ aBuildPath) -{ - this._file = new File(aFilePath).getCanonicalFile(); - this._root = this._file.getParentFile(); - - // Read the project file (its just a plist). - this._properties = readPlist(this._file); - - this._name = dictionary_getValue(this._properties, "Name"); - - // Read existing Info.plist if it exists. - var infoPlist = new File(this._root.getAbsolutePath() + "/Info.plist"); - - if (infoPlist.exists()) - this._infoDictionary = readPlist(new File(this._root.getAbsolutePath() + "/Info.plist")); - else - this._infoDictionary = new objj_dictionary(); - - this.buildPath = aBuildPath; - - // Covert target dictionaries to target objects. - var targetDictionaries = dictionary_getValue(this._properties, "Targets"); - - this._targets = []; - - for (var index = 0, count = targetDictionaries.length; index < count; ++index) - this._targets.push(new Target(targetDictionaries[index])); - - this.setActiveTarget(this._targets[0]); - - // Covert target dictionaries to target objects. - var configurationDictionaries = dictionary_getValue(this._properties, "Configurations"); - - this._configurations = []; - - for (index = 0, count = configurationDictionaries.length; index < count; ++index) - this._configurations.push(new Configuration(configurationDictionaries[index])); - - this.setActiveConfiguration(this._configurations[0]); - - // Grab the Resources Directory (if it exists) - this._resources = new File(this._root.getAbsolutePath() + "/Resources/").getCanonicalFile(); - - return this; -} - -Project.prototype.name = function() -{ - return this._name; -} - -Project.prototype.targetWithName = function(/*String*/ aName) -{ - var targets = this._targets, - index = 0, - count = targets.length; - - for (; index < count; ++index) - { - var target = targets[index]; - - if (target.name() == aName) - return target; - } - - return null; -} - -Project.prototype.configurationWithName = function(/*String*/ aName) -{ - var configurations = this._configurations, - index = 0, - count = configurations.length; - - for (; index < count; ++index) - { - var configuration = configurations[index]; - - if (configuration.name() == aName) - return configuration; - } - - return null; -} - -Project.prototype.setActiveTarget = function(/*Target*/ aTarget) -{ - this._activeTarget = aTarget; - - this._buildProducts = null; - this._buildIntermediates = null; - this._buildObjects = null; -} - -Project.prototype.activeTarget = function() -{ - return this._activeTarget; -} - -Project.prototype.setActiveConfiguration = function(/*Configuration*/ aConfiguration) -{ - this._activeConfiguration = aConfiguration; - - this._buildProducts = null; - this._buildIntermediates = null; - this._buildObjects = null; -} - -Project.prototype.activeConfiguration = function() -{ - return this._activeConfiguration; -} - -Project.prototype.buildProducts = function() -{ - if (!this._buildProducts) - { - this._buildProducts = new File(this.buildPath + '/' + this._activeConfiguration.name() + '/' + this._activeTarget.name()).getCanonicalFile(); - this._buildProducts.mkdirs(); - } - - return this._buildProducts; -} - -Project.prototype.buildIntermediates = function() -{ - if (!this._buildIntermediates) - { - this._buildIntermediates = new File(this.buildPath + '/' + this._activeTarget.name() + ".build/" + this._activeConfiguration.name()).getCanonicalFile(); - this._buildIntermediates.mkdirs(); - } - - return this._buildIntermediates; -} - -Project.prototype.buildObjects = function() -{ - if (!this._buildObjects) - { - this._buildObjects = new File(this.buildIntermediates().getAbsolutePath() + '/' + this._activeTarget.name()).getCanonicalFile(); - this._buildObjects.mkdirs(); - } - - return this._buildObjects; -} - -Project.prototype.activeFlags = function() -{ - return this.activeTarget().flags().concat(this.activeConfiguration().flags()); -} - -Project.prototype.build = function() -{ - java.lang.System.out.println("Building Target \"" + this.activeTarget().name() + - "\" of Project \"" + this.name() + - "\" with Configuration \"" + this.activeConfiguration().name() + "\"."); - - var jFiles = getFiles(this._root, "j", this._activeTarget.exclusions()), - replacedFiles = []; - hasModifiedJFiles = false; - shouldObjjPreprocess = true, - shouldGzip = this._gzip, - objjcComponents = ["sh", OBJJ_HOME + "/bin/objjc"]; - - objjcComponents = objjcComponents.concat(this.activeFlags()); - - if (!shouldObjjPreprocess) - objjcComponents.push("-E"); - - var buildObjects = this.buildObjects(), - buildProducts = this.buildProducts(); - - for (index = 0, count = jFiles.length; index < count; ++index) - { - var file = jFiles[index], - builtFile = new File(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o'); - - replacedFiles.push(file.getName() + ""); - - if (builtFile.exists() && file.lastModified() < builtFile.lastModified()) - continue; - else - hasModifiedJFiles = true; - - objjcComponents.push(file.getAbsolutePath()); - - objjcComponents.push("-o"); - objjcComponents.push(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o'); - } - - exec(objjcComponents, true); - - var oFiles = getFiles(buildObjects, 'o'), - sjFile = new File(buildProducts.getCanonicalPath() + '/' + this._activeTarget.name() + ".sj"); - - if (hasModifiedJFiles) - { - // concatenate sjheader.txt and individual .o - exec(["sh", "-c", "cat '" + OBJJ_STEAM + "/sjheader.txt' '" + oFiles.join("' '") + "' > '" + sjFile.getCanonicalPath() + "'"], true); - } - - if (shouldGzip) - { - // gzip and copy .htaccess file - exec(["sh", "-c", "gzip -c '" + sjFile.getCanonicalPath() + "' > '" + sjFile.getCanonicalPath() + ".gz'"], true); - exec(["cp", OBJJ_HOME + "/lib/htaccess", sjFile.getParentFile().getCanonicalPath() + "/.htaccess"], true); - } - else - { - // remove gzip and .htaccess file if present - exec(["rm", "-f", sjFile.getParentFile().getCanonicalPath() + "/.htaccess", sjFile.getCanonicalPath() + ".gz"], true); - } - - dictionary_setValue(this._infoDictionary, "CPBundleExecutable", this._activeTarget.name() + ".sj"); - dictionary_setValue(this._infoDictionary, "CPBundleReplacedFiles", replacedFiles); - - this.writeInfoPlist(); - - this.copyResources(); - - // FIXME: This should be, if this is an app... - if (dictionary_getValue(this._infoDictionary, "CPBundlePackageType") == "280N") - this.copyIndexFile(); - -} - -Project.prototype.clean = function() -{ - java.lang.System.out.println("Cleaning Target \"" + this.activeTarget().name() + - "\" of Project \"" + this.name() + - "\" with Configuration \"" + this.activeConfiguration().name() + "\"."); - - exec(["rm", "-rf", this.buildIntermediates().getAbsolutePath()], true); - exec(["rm", "-rf", this.buildProducts().getAbsolutePath()], true); -} - -Project.prototype.copyIndexFile = function() -{ - var indexFile = new File(this._root.getAbsolutePath() + "/index.html").getCanonicalFile(); - - rsync(indexFile, this.buildProducts()); -} - -Project.prototype.writeInfoPlist = function() -{ - var writer = new BufferedWriter(new FileWriter(this.buildProducts().getAbsolutePath() + '/' + "Info.plist")); - - writer.write(CPPropertyListCreateXMLData(this._infoDictionary).string); - - writer.close(); -} - -Project.prototype.copyResources = function() -{ - rsync(this._resources, this.buildProducts()); -} diff --git a/Objective-J/Tools/steam/Templates/Application/AppController.j b/Objective-J/Tools/steam/Templates/Application/AppController.j deleted file mode 100644 index 21ede646e..000000000 --- a/Objective-J/Tools/steam/Templates/Application/AppController.j +++ /dev/null @@ -1,39 +0,0 @@ -/* - * AppController.j - * __Product__ - * - * Created by __Me__ on __Date__. - * Copyright 2008 __MyCompanyName__. All rights reserved. - */ - -@import - - -@implementation AppController : CPObject -{ -} - -- (void)applicationDidFinishLaunching:(CPNotification)aNotification -{ - var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], - contentView = [theWindow contentView]; - - var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; - - [label setStringValue:@"Hello World!"]; - [label setFont:[CPFont boldSystemFontOfSize:24.0]]; - - [label sizeToFit]; - - [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin]; - [label setFrameOrigin:CGPointMake((CGRectGetWidth([contentView bounds]) - CGRectGetWidth([label frame])) / 2.0, (CGRectGetHeight([contentView bounds]) - CGRectGetHeight([label frame])) / 2.0)]; - - [contentView addSubview:label]; - - [theWindow orderFront:self]; - - // Uncomment the following line to turn on the standard menu bar. - //[CPMenu setMenuBarVisible:YES]; -} - -@end diff --git a/Objective-J/Tools/steam/Templates/Application/Info.plist b/Objective-J/Tools/steam/Templates/Application/Info.plist deleted file mode 100644 index a81852dcd..000000000 --- a/Objective-J/Tools/steam/Templates/Application/Info.plist +++ /dev/null @@ -1,12 +0,0 @@ - - - - - CPApplicationDelegateClass - AppController - CPBundleName - __Product__ - CPPrincipalClass - CPApplication - - diff --git a/Objective-J/Tools/steam/Templates/Application/index-debug.html b/Objective-J/Tools/steam/Templates/Application/index-debug.html deleted file mode 100644 index d941b006a..000000000 --- a/Objective-J/Tools/steam/Templates/Application/index-debug.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - Hello World - - - - - - - - -
-
- -
-
- - - diff --git a/Objective-J/Tools/steam/Templates/Application/index.html b/Objective-J/Tools/steam/Templates/Application/index.html deleted file mode 100644 index bea6f5f36..000000000 --- a/Objective-J/Tools/steam/Templates/Application/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - Hello World - - - - - - - - - -
-
- -
-
- - - - diff --git a/Objective-J/Tools/steam/Templates/Application/main.j b/Objective-J/Tools/steam/Templates/Application/main.j deleted file mode 100755 index d4cec69f3..000000000 --- a/Objective-J/Tools/steam/Templates/Application/main.j +++ /dev/null @@ -1,18 +0,0 @@ -/* - * main.j - * __Product__ - * - * Created by __Me__ on __Date__. - * Copyright 2008 __MyCompanyName__. All rights reserved. - */ - -@import -@import - -@import "AppController.j" - - -function main(args, namedArgs) -{ - CPApplicationMain(args, namedArgs); -} diff --git a/Objective-J/Tools/steam/Templates/ThemeDescriptor/Info.plist b/Objective-J/Tools/steam/Templates/ThemeDescriptor/Info.plist deleted file mode 100644 index f09701c61..000000000 --- a/Objective-J/Tools/steam/Templates/ThemeDescriptor/Info.plist +++ /dev/null @@ -1,12 +0,0 @@ - - - - - CPApplicationDelegateClass - BKShowcaseController - CPBundleName - __Product__ - CPPrincipalClass - CPApplication - - diff --git a/Objective-J/Tools/steam/Templates/ThemeDescriptor/ThemeDescriptors.j b/Objective-J/Tools/steam/Templates/ThemeDescriptor/ThemeDescriptors.j deleted file mode 100644 index aab4c6581..000000000 --- a/Objective-J/Tools/steam/Templates/ThemeDescriptor/ThemeDescriptors.j +++ /dev/null @@ -1,33 +0,0 @@ -/* - * ThemeDescriptors.j - * __Product__ - * - * Created by __Me__ on __Date__. - * Copyright 2008 __MyCompanyName__. All rights reserved. - */ - -@import - - -@implementation __Product__ThemeDescriptor : CPObject -{ -} - -+ (CPString)themeName -{ - return @"__Product__"; -} - -+ (CPTextField)themedTextField -{ - var textField = [[CPTextField alloc] initWithFrame:CGRectMake(0.0, 0.0, 200.0, 20.0)]; - - [textField setValue:[CPColor blueColor] forThemedAttributeName:@"bezel-color"]; - [textField setValue:[CPColor redColor] forThemedAttributeName:@"text-color"]; - - [textField setStringValue:@"Yikes!"]; - - return textField; -} - -@end diff --git a/Objective-J/Tools/steam/Templates/ThemeDescriptor/index-debug.html b/Objective-J/Tools/steam/Templates/ThemeDescriptor/index-debug.html deleted file mode 100644 index d941b006a..000000000 --- a/Objective-J/Tools/steam/Templates/ThemeDescriptor/index-debug.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - Hello World - - - - - - - - -
-
- -
-
- - - diff --git a/Objective-J/Tools/steam/Templates/ThemeDescriptor/index.html b/Objective-J/Tools/steam/Templates/ThemeDescriptor/index.html deleted file mode 100644 index bea6f5f36..000000000 --- a/Objective-J/Tools/steam/Templates/ThemeDescriptor/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - Hello World - - - - - - - - - -
-
- -
-
- - - - diff --git a/Objective-J/Tools/steam/Templates/ThemeDescriptor/main.j b/Objective-J/Tools/steam/Templates/ThemeDescriptor/main.j deleted file mode 100755 index cb02f4859..000000000 --- a/Objective-J/Tools/steam/Templates/ThemeDescriptor/main.j +++ /dev/null @@ -1,19 +0,0 @@ -/* - * main.j - * __Product__ - * - * Created by __Me__ on __Date__. - * Copyright 2008 __MyCompanyName__. All rights reserved. - */ - -@import -@import -@import - -@import "ThemeDescriptors.j" - - -function main(args, namedArgs) -{ - CPApplicationMain(args, namedArgs); -} diff --git a/Objective-J/Tools/steam/build.js b/Objective-J/Tools/steam/build.js deleted file mode 100644 index 042decf11..000000000 --- a/Objective-J/Tools/steam/build.js +++ /dev/null @@ -1,102 +0,0 @@ -function build() -{ - var index = 0, - count = arguments.length, - - actions = [], - - targetName = null, - configurationName = null, - - buildPath = null, - projectFilePath = null, - - gzip = false; - - for (; index < count; ++index) - { - switch (arguments[index]) - { - case "-f": if (index + 1 == count) - throw "-f needs project file."; - - projectFilePath = arguments[++index]; - break; - - case "-t": if (index + 1 == count) - throw "-t needs a target"; - - targetName = arguments[++index]; - break; - - case "-c": if (index + 1 == count) - throw "-c needs configuration"; - - configurationName = arguments[++index]; - break; - - case "-b": if (index + 1 == count) - throw "-b needs a build location"; - - buildPath = arguments[++index]; - break; - - case "--gzip": gzip = true; - break; - - case "clean": - case "build": actions.push(arguments[index]); - break; - } - } - - // If no project file was specified, look for one. - if (!projectFilePath) - { - var candidates = getFiles(new File('.'), "steam"); - - if (candidates.length < 1) - throw "No project file specified or found."; - - projectFilePath = candidates[0]; - } - - // Construct the Build Directory - if (!buildPath) - { - buildPath = System.getenv("STEAM_BUILD"); - - if (!buildPath) - buildPath = "Build"; - } - - var project = new Project(projectFilePath, buildPath); - - project._gzip = gzip; - - if (targetName) - { - var target = project.targetWithName(targetName); - - if (!target) - throw "Target \"" + targetName + "\" not found in project."; - - project.setActiveTarget(target); - } - - if (configurationName) - { - var configuration = project.configurationWithName(configurationName); - - if (!configuration) - throw "Configuration \"" + configurationName + "\" not found in project."; - - project.setActiveConfiguration(configuration); - } - - if (!actions.length) - actions.push("build"); - - for (index = 0, count = actions.length; index < count; ++index) - project[actions[index]](); -} diff --git a/Objective-J/Tools/steam/build.xml b/Objective-J/Tools/steam/build.xml deleted file mode 100644 index 568809646..000000000 --- a/Objective-J/Tools/steam/build.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Objective-J/Tools/steam/create-frameworks.js b/Objective-J/Tools/steam/create-frameworks.js deleted file mode 100644 index 89b355ea9..000000000 --- a/Objective-J/Tools/steam/create-frameworks.js +++ /dev/null @@ -1,66 +0,0 @@ -function createFrameworks() -{ - var shouldSymbolicallyLink = false, - index = 0, - count = arguments.length, - - destination = ""; - - for (; index < count; ++index) - { - var argument = arguments[index]; - - switch (arguments[index]) - { - case "-l": shouldSymbolicallyLink = true; - break; - - default: destination = argument; - } - } - - createFrameworksInFile(new File(destination), shouldSymbolicallyLink); -} - -function createFrameworksInFile(/*File*/ aFile, /*Boolean*/ shouldSymbolicallyLink) -{ - var destinationFrameworks = new File(aFile.getCanonicalPath()+ "/Frameworks"), - destinationDebugFrameworks = new File(aFile.getCanonicalPath() + "/Frameworks/Debug"); - - if (!shouldSymbolicallyLink) - { - var sourceFrameworks = new File(OBJJ_HOME + "/lib/Frameworks"), - sourceDebugFrameworks = new File(OBJJ_HOME + "/lib/Frameworks-Debug"); - - exec(["cp", "-vR", sourceFrameworks.getCanonicalPath(), destinationFrameworks.getCanonicalPath()], true); - exec(["cp", "-vR", sourceDebugFrameworks.getCanonicalPath(), destinationDebugFrameworks.getCanonicalPath()], true); - - return true; - } - - var STEAM_BUILD = System.getenv("STEAM_BUILD"); - - // Release Frameworks - new File(destinationFrameworks).mkdir(); - - exec(["ln", "-s", new File(STEAM_BUILD + "/Release/Objective-J").getCanonicalPath(), - new File(aFile.getCanonicalPath() + "/Frameworks/Objective-J").getCanonicalPath()], true); - - exec(["ln", "-s", new File(STEAM_BUILD + "/Release/Foundation").getCanonicalPath(), - new File(aFile.getCanonicalPath() + "/Frameworks/Foundation").getCanonicalPath()], true); - - exec(["ln", "-s", new File(STEAM_BUILD + "/Release/AppKit").getCanonicalPath(), - new File(aFile.getCanonicalPath() + "/Frameworks/AppKit").getCanonicalPath()], true); - - // Debug Frameworks - new File(destinationDebugFrameworks).mkdir(); - - exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/Objective-J").getCanonicalPath(), - new File(aFile.getCanonicalPath() + "/Frameworks/Debug/Objective-J").getCanonicalPath()], true); - - exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/Foundation").getCanonicalPath(), - new File(aFile.getCanonicalPath() + "/Frameworks/Debug/Foundation").getCanonicalPath()], true); - - exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/AppKit").getCanonicalPath(), - new File(aFile.getCanonicalPath() + "/Frameworks/Debug/AppKit").getCanonicalPath()], true); -} \ No newline at end of file diff --git a/Objective-J/Tools/steam/create.js b/Objective-J/Tools/steam/create.js deleted file mode 100644 index 73abaa8dc..000000000 --- a/Objective-J/Tools/steam/create.js +++ /dev/null @@ -1,54 +0,0 @@ -function create() -{ - if (arguments.length < 1) - printUsage("create"); - - var shouldSymbolicallyLink = false, - index = 0, - count = arguments.length, - - template = "Application", - destination = ""; - - for (; index < count; ++index) - { - var argument = arguments[index]; - - switch (arguments[index]) - { - case "-l": shouldSymbolicallyLink = true; - break; - - case "--template": template = arguments[++index]; - break; - - default: destination = argument; - } - } - - var sourceTemplate = new File(OBJJ_HOME + "/lib/steam/Templates/" + template), - destinationProject = new File(destination); - - if (!destinationProject.exists()) - { - exec(["cp", "-vR", sourceTemplate.getCanonicalPath(), destinationProject.getCanonicalPath()], true); - - var files = getFiles(destinationProject, ['j', "plist", "html"]), - index = 0, - count = files.length; - - for (; index < count; ++index) - { - var file = files[index], - contents = readFile(file); - - contents = contents.replace(/__Product__/g, destinationProject.getName()); - - writeContentsToFile(contents, file); - } - - createFrameworksInFile(destinationProject, shouldSymbolicallyLink); - } - else - System.out.println("Directory already exists"); -} diff --git a/Objective-J/Tools/steam/htaccess b/Objective-J/Tools/steam/htaccess deleted file mode 100644 index 6afc67f10..000000000 --- a/Objective-J/Tools/steam/htaccess +++ /dev/null @@ -1,12 +0,0 @@ -Options +FollowSymLinks - -AddEncoding x-gzip .gz -AddType text/plain .gz - -RewriteEngine on - -# These conditions slow down the requests significantly. We can probably assume they're always true. -# We should ensure the gzipped version always exists if we include this .htaccess. All supported browsers accept gzip encoding. -#RewriteCond %{REQUEST_FILENAME}.gz -f -#RewriteCond %{HTTP:Accept-Encoding} gzip -RewriteRule ^(.*\.(sj|js))$ %{REQUEST_URI}/../$1.gz diff --git a/Objective-J/Tools/steam/inline-bundle.js b/Objective-J/Tools/steam/inline-bundle.js deleted file mode 100644 index 2e2dc8643..000000000 --- a/Objective-J/Tools/steam/inline-bundle.js +++ /dev/null @@ -1,156 +0,0 @@ -function inlineBundle() -{ - var index = 0, - count = arguments.length, - bundlePath = NULL; - - for (; index < count; ++index) - { - var argument = arguments[index]; - - switch (arguments[index]) - { - case "-d": directoryPath = arguments[++index]; - break; - - default: bundlePath = argument; - } - } - - var bundleFile = new File(bundlePath).getCanonicalFile(), - bundlePath = String(bundleFile.getCanonicalPath()), - inlinedBundle = readBundle(bundleFile, true), - inlinedFiles = [], - replacedFiles = [], - staticContent = ""; - - // Find all internal bundles. - var bundleCandidates = getFiles(bundleFile, "plist"), - bundleCandidatesCount = bundleCandidates.length; - - while (bundleCandidatesCount--) - { - var bundleCandidate = bundleCandidates[bundleCandidatesCount]; - - // We only care about Info.plists, specifically the ones that aren't us. - if (String(bundleCandidate.getName()) !== "Info.plist" || String(bundleCandidate.getCanonicalPath()) === inlinedBundle.path) - continue; - - var infoDictionary = readPlist(bundleCandidate); - - // At least one of these two has to be present for this to be a real deal bundle. - if (!dictionary_getValue(infoDictionary, "CPBundleIdentifier") && !dictionary_getValue(infoDictionary, "CPBundleName")) - continue; - - java.lang.System.out.println(" Examining " + pathRelativeTo(bundleCandidate.getCanonicalPath(), bundlePath)); - - dictionary_removeValue(infoDictionary, "CPBundleExecutable"); - - var bundle = readBundle(bundleCandidate.getParentFile(), true); - - bundle.path = pathRelativeTo(bundle.path, bundlePath); - - // We want to inline the info plist too. - var inlinedFiles = [makeOBJJPlistFile(infoDictionary, bundleCandidate, bundle)].concat(bundle.files), - index = 0, - count = inlinedFiles.length; - - for (; index < count; ++index) - { - var file = inlinedFiles[index]; - - file.path = pathRelativeTo(String(file.path), bundlePath); - - java.lang.System.out.println(" Inlining " + file.path); - - replacedFiles.push(file.path); - staticContent += fileToMarkedString(inlinedFiles[index], true); - } - } - - var index = 0, - existingStaticFiles = inlinedBundle.files, - count = existingStaticFiles.length, - topLevelContent = "@STATIC;1.0;"; - - for (; index < count; ++index) - { - var file = existingStaticFiles[index]; - - // If this isn't actually part of our bundle, drop it! - if (file.bundle !== inlinedBundle) - continue; - - file.path = pathRelativeTo(String(file.path), bundlePath); - - replacedFiles.push(file.path); - topLevelContent += fileToMarkedString(file, false); - } - - dictionary_setValue(inlinedBundle.info, "CPBundleReplacedFiles", replacedFiles); - - writeContentsToFile(CPPropertyListCreateXMLData(inlinedBundle.info).string, inlinedBundle.path); - writeContentsToFile(topLevelContent + staticContent, inlinedBundle._staticContentPath); -} - -function fileToMarkedString(anOBJJFile, encodeBundle) -{ - var markedString = ""; - - markedString += MARKER_PATH + ';' + anOBJJFile.path.length + ';' + anOBJJFile.path; - - if (encodeBundle) - markedString += MARKER_BUNDLE + ';' + anOBJJFile.bundle.path.length + ';' + anOBJJFile.bundle.path; - - var fragments = anOBJJFile.fragments; - - if (fragments && fragments.length > 0) - { - var fragmentIndex = 0, - fragmentCount = fragments.length; - - for (; fragmentIndex < fragmentCount; ++fragmentIndex) - markedString += fragments[fragmentIndex].toMarkedString(); - } - - else - markedString += MARKER_TEXT + ';' + anOBJJFile.contents.length + ';' + anOBJJFile.contents; - - return markedString; -} - -function makeOBJJPlistFile(aDictionary, aFile, aBundle) -{ - var file = new objj_file(); - - file.path = typeof aFile === "string" ? aFile : aFile.getCanonicalPath(); - file.bundle = aBundle; - file.contents = CPPropertyListCreate280NorthData(aDictionary).string; - - return file; -} - -function pathRelativeTo(target, relativeTo) -{ - var components = [], - targetParts = target.split("/"), - relativeParts = relativeTo ? relativeTo.split("/") : []; - - var i = 0; - while (i < targetParts.length) - { - if (targetParts[i] != relativeParts[i]) - break; - i++; - } - - for (var j = i; j < relativeParts.length; j++) - components.push(".."); - - for (var j = i; j < targetParts.length; j++) - components.push(targetParts[j]); - - var result = components.join("/"); - - return result; -} \ No newline at end of file diff --git a/Objective-J/Tools/steam/main.js b/Objective-J/Tools/steam/main.js deleted file mode 100644 index d007905f7..000000000 --- a/Objective-J/Tools/steam/main.js +++ /dev/null @@ -1,203 +0,0 @@ - -importPackage(java.lang); -importPackage(java.util); - -importClass(java.io.File); -importClass(java.io.BufferedReader); -importClass(java.io.FileReader); -importClass(java.io.BufferedWriter); -importClass(java.io.FileWriter); -importClass(java.io.SequenceInputStream); - -#include "../Utilities/bundle.js" - -#include "Project.js" - -OBJJ_STEAM = OBJJ_HOME + "/lib/steam/"; - -function main() -{ - if (arguments.length < 1) - printUsage(); - - var command = Array.prototype.shift.apply(arguments); - - switch (command) - { - case "create": create.apply(create, arguments); - break; - - case "create-frameworks": createFrameworks.apply(createFrameworks, arguments); - break; - - - case "inline-bundle": inlineBundle.apply(inlineBundle, arguments); - break; - - case "build": build.apply(build, arguments); - break; - - case "help": printUsage(arguments[1]); - break; - - case "version": - case "--version": printVersion(); - break; - - default : printUsage(command); - } - -} - -function fileArrayContainsFile(/*Array*/ files, /*File*/ aFile) -{ - var index = 0, - count = files.length; - - for (; index < count; ++index) - if (files[index].equals(aFile)) - return true; - - return false; -} - -function getFiles(/*File*/ sourceDirectory, /*nil|String|Array*/ extensions, /*Array*/ exclusions) -{ - var matches = [], - files = sourceDirectory.listFiles(), - hasMultipleExtensions = typeof extensions !== "string"; - - if (files) - { - var index = 0, - count = files.length; - - for (; index < count; ++index) - { - var file = files[index].getCanonicalFile(), - name = String(file.getName()), - isValidExtension = !extensions; - - if (exclusions && fileArrayContainsFile(exclusions, file)) - continue; - - if (!isValidExtension) - if (hasMultipleExtensions) - { - var extensionCount = extensions.length; - - while (extensionCount-- && !isValidExtension) - { - var extension = extensions[extensionCount]; - - if (name.substring(name.length - extension.length - 1) === ("." + extension)) - isValidExtension = true; - } - } - else if (name.substring(name.length - extensions.length - 1) === ("." + extensions)) - isValidExtension = true; - - if (isValidExtension) - matches.push(file); - - if (file.isDirectory()) - matches = matches.concat(getFiles(file, extensions, exclusions)); - } - } - - return matches; -} - -function exec(/*Array*/ command, /*Boolean*/ showOutput) -{ - var line = "", - output = "", - - process = Packages.java.lang.Runtime.getRuntime().exec(command),//jsArrayToJavaArray(command)); - reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getInputStream())); - - while (line = reader.readLine()) - { - if (showOutput) - System.out.println(line); - - output += line + '\n'; - } - - reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getErrorStream())); - - while (line = reader.readLine()) - System.out.println(line); - - try - { - if (process.waitFor() != 0) - System.err.println("exit value = " + process.exitValue()); - } - catch (anException) - { - System.err.println(anException); - } - - return output; -} - -function rsync(srcFile, dstFile) -{ - var src, dst; - - if (String(java.lang.System.getenv("OS")).indexOf("Windows") < 0) - { - src = srcFile.getAbsolutePath(); - dst = dstFile.getAbsolutePath(); - } - else - { - src = exec(["cygpath", "-u", srcFile.getAbsolutePath() + '/']); - dst = exec(["cygpath", "-u", dstFile.getAbsolutePath() + "/Resources"]); - } - - if (srcFile.exists()) - exec(["rsync", "-avz", src, dst]); -} - -function getFileName(aPath) -{ - var index = aPath.lastIndexOf('/'); - - if (index == -1) - return aPath; - - return aPath.substr(index + 1); -} - -function getFileNameWithoutExtension(aFileOrFileName) -{ - var name = typeof aFileOrFileName === "string" ? aFileOrFileName : aFileOrFileName.getName(), - index = name.lastIndexOf('.'); - - if (index == -1 || index == 0) - return name; - - return name.substr(0, index); -} - -function getFileExtension(aPath) -{ - var slash = aPath.lastIndexOf('/'), - period = aPath.lastIndexOf('.'); - - if (period < slash || (period == slash + 1)) - return ""; - - return aPath.substr(period + 1); -} - -main.apply(main, arguments); - -#include "build.js" -#include "create.js" -#include "create-frameworks.js" -#include "inline-bundle.js" -#include "usage.js" -#include "version.js" diff --git a/Objective-J/Tools/steam/sjheader.txt b/Objective-J/Tools/steam/sjheader.txt deleted file mode 100644 index 57390737c..000000000 --- a/Objective-J/Tools/steam/sjheader.txt +++ /dev/null @@ -1 +0,0 @@ -@STATIC;1.0; \ No newline at end of file diff --git a/Objective-J/Tools/steam/steam b/Objective-J/Tools/steam/steam deleted file mode 100644 index e66147478..000000000 --- a/Objective-J/Tools/steam/steam +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -# if OBJJ_HOME isn't set, try to determine it -if [ -z $OBJJ_HOME ]; then - # get path of the executable - SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0") - - # resolve symlinks - if [ -h $SELF_PATH ]; then - SELF_PATH=`readlink $SELF_PATH` - fi - - # get second ancestor directory - SELF_DIR=`dirname $SELF_PATH` - export OBJJ_HOME=`dirname $SELF_DIR` - - # check to ensure it exists, print message - if [ -d $OBJJ_HOME ]; then - echo "OBJJ_HOME not set, defaulting to $OBJJ_HOME" 1>&2 - else - echo "OBJJ_HOME not set, default at $OBJJ_HOME doesn't exist, exiting" 1>&2 - exit 2 - fi -fi - -OBJJ_LIB="$OBJJ_HOME/lib" -STEAM="$OBJJ_LIB/steam" -CLASSPATH="$STEAM:$OBJJ_LIB:$OBJJ_LIB/js.jar" - -# convert paths for Cygwin -if [[ `uname` == CYGWIN* ]]; then - CLASSPATH=`cygpath -wp "$CLASSPATH"` - STEAM_BUILD=`cygpath -wp "$STEAM_BUILD"` -fi - -export OBJJ_LIB - -java -classpath $CLASSPATH steam $@ diff --git a/Objective-J/Tools/steam/steam.xml b/Objective-J/Tools/steam/steam.xml deleted file mode 100644 index 8b5e0a9f6..000000000 --- a/Objective-J/Tools/steam/steam.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Objective-J/Tools/steam/usage.js b/Objective-J/Tools/steam/usage.js deleted file mode 100644 index 389fadc53..000000000 --- a/Objective-J/Tools/steam/usage.js +++ /dev/null @@ -1,22 +0,0 @@ -function printUsage(command) -{ - var usage = "usage: steam COMMAND [ARGS]\n\n"+ -"The most commonly used steam commands are:\n"+ -"\tbuild Build a project\n"+ -"\tcreate Create a new project\n\n"+ -"See 'steam help COMMAND' for more information on a specific command."; - - switch (command) - { - case "--help": - case undefined: java.lang.System.out.println(usage); - break; - - case "create": java.lang.System.out.println("Creates a new Cappuccino project.\n\nusage: steam create PROJECT_NAME [-l]\n\n"+ - "\t-l Link Frameworks to $STEAM_BUILD/Release, instead of installing default Frameworks"); - break; - - default: java.lang.System.out.println("steam: '" + command + "' is not a steam command. See 'steam --help'."); - } - java.lang.System.exit(1); -} diff --git a/Objective-J/Tools/steam/version.js b/Objective-J/Tools/steam/version.js deleted file mode 100644 index c22171a3f..000000000 --- a/Objective-J/Tools/steam/version.js +++ /dev/null @@ -1,5 +0,0 @@ -function printVersion() -{ - java.lang.System.out.println("steam version 0.6"); - java.lang.System.exit(1); -} \ No newline at end of file From 9dcdf84824b0421bc935cf246d45027e4a1a726d Mon Sep 17 00:00:00 2001 From: Francisco Tolmasky Date: Wed, 18 Mar 2009 23:29:26 -0700 Subject: [PATCH 61/62] Gemed up Objective-J rake stuff. Reviewed by me. --- Rake/Rakefile | 36 ++++++++++++++++++++++++ Rake/{ => lib/licenses}/LGPL-v2.1 | 0 Rake/{ => lib}/objective-j.rb | 0 Rake/{ => lib}/objective-j/bundletask.rb | 2 +- Rake/{Resources => lib}/objj-executable | 0 common.rb | 4 +-- 6 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 Rake/Rakefile rename Rake/{ => lib/licenses}/LGPL-v2.1 (100%) rename Rake/{ => lib}/objective-j.rb (100%) rename Rake/{ => lib}/objective-j/bundletask.rb (99%) rename Rake/{Resources => lib}/objj-executable (100%) diff --git a/Rake/Rakefile b/Rake/Rakefile new file mode 100644 index 000000000..c924c3978 --- /dev/null +++ b/Rake/Rakefile @@ -0,0 +1,36 @@ + +require '../common' +require 'rubygems' +require 'rubygems/installer' +require 'rake' +require 'rake/gempackagetask' + + +PKG_FILES = FileList['lib/**/*'] + +spec = Gem::Specification.new do |s| + s.platform = Gem::Platform::RUBY + s.author = '280 North, Inc.' + s.email = 'feedback @nospam@ 280north.com' + s.homepage = 'cappuccino.org' + s.summary = "Objective-J extensions to Rake." + s.name = 'objective-j' + s.version = "0.7.0" + s.requirements << 'rake' + s.require_path = 'lib' + s.files = PKG_FILES + s.description = < Date: Wed, 18 Mar 2009 23:30:58 -0700 Subject: [PATCH 62/62] Added Aristo Theme Project. Reviewed by me. --- AppKit/Themes/Aristo/Info.plist | 12 + .../Aristo/Resources/button-bezel-center.png | Bin 0 -> 2844 bytes .../button-bezel-highlighted-center.png | Bin 0 -> 2824 bytes .../button-bezel-highlighted-left.png | Bin 0 -> 2905 bytes .../button-bezel-highlighted-right.png | Bin 0 -> 2910 bytes .../Aristo/Resources/button-bezel-left.png | Bin 0 -> 2898 bytes .../Aristo/Resources/button-bezel-right.png | Bin 0 -> 2895 bytes .../Resources/buttonbar-bezel-right.png | Bin 0 -> 370 bytes .../Aristo/Resources/buttonbar-bezel.png | Bin 0 -> 129 bytes .../Resources/horizontal-track-center.png | Bin 0 -> 2807 bytes .../Resources/horizontal-track-left.png | Bin 0 -> 2866 bytes .../Resources/horizontal-track-right.png | Bin 0 -> 2865 bytes .../Aristo/Resources/knob-highlighted.png | Bin 0 -> 3768 bytes AppKit/Themes/Aristo/Resources/knob.png | Bin 0 -> 3643 bytes .../scroller-down-arrow-disabled.png | Bin 0 -> 3181 bytes .../scroller-down-arrow-highlighted.png | Bin 0 -> 3439 bytes .../old-scroller/scroller-down-arrow.png | Bin 0 -> 3368 bytes .../scroller-up-arrow-disabled.png | Bin 0 -> 3124 bytes .../scroller-up-arrow-highlighted.png | Bin 0 -> 3366 bytes .../old-scroller/scroller-up-arrow.png | Bin 0 -> 3334 bytes .../scroller-vertical-knob-bottom.png | Bin 0 -> 3077 bytes .../scroller-vertical-knob-center.png | Bin 0 -> 2824 bytes .../scroller-vertical-knob-top.png | Bin 0 -> 3035 bytes .../scroller-vertical-track-disabled.png | Bin 0 -> 2812 bytes .../old-scroller/scroller-vertical-track.png | Bin 0 -> 2831 bytes .../Resources/popup-arrows-pullsdown.png | Bin 0 -> 2950 bytes .../Themes/Aristo/Resources/popup-arrows.png | Bin 0 -> 3072 bytes .../Resources/popup-bezel-right-pullsdown.png | Bin 0 -> 32722 bytes .../Aristo/Resources/popup-bezel-right.png | Bin 0 -> 3289 bytes .../scroller-down-arrow-disabled.png | Bin 0 -> 3196 bytes .../scroller-down-arrow-highlighted.png | Bin 0 -> 3447 bytes .../Aristo/Resources/scroller-down-arrow.png | Bin 0 -> 3365 bytes .../scroller-horizontal-knob-center.png | Bin 0 -> 2820 bytes .../scroller-horizontal-knob-left.png | Bin 0 -> 23854 bytes .../scroller-horizontal-knob-right.png | Bin 0 -> 3067 bytes .../Resources/scroller-horizontal-track.png | Bin 0 -> 173 bytes .../Aristo/Resources/scroller-left-arrow.png | Bin 0 -> 3401 bytes .../Aristo/Resources/scroller-right-arrow.png | Bin 0 -> 25008 bytes .../Resources/scroller-up-arrow-disabled.png | Bin 0 -> 3134 bytes .../scroller-up-arrow-highlighted.png | Bin 0 -> 3365 bytes .../Aristo/Resources/scroller-up-arrow.png | Bin 0 -> 3334 bytes .../scroller-vertical-knob-bottom.png | Bin 0 -> 3076 bytes .../scroller-vertical-knob-center.png | Bin 0 -> 2823 bytes .../Resources/scroller-vertical-knob-top.png | Bin 0 -> 3034 bytes .../scroller-vertical-track-disabled.png | Bin 0 -> 2814 bytes .../Resources/scroller-vertical-track.png | Bin 0 -> 2831 bytes .../textfield-bezel-rounded-center.png | Bin 0 -> 2815 bytes .../textfield-bezel-rounded-left.png | Bin 0 -> 3288 bytes .../textfield-bezel-rounded-right.png | Bin 0 -> 3307 bytes .../Resources/textfield-bezel-square-0.png | Bin 0 -> 124 bytes .../Resources/textfield-bezel-square-1.png | Bin 0 -> 117 bytes .../Resources/textfield-bezel-square-2.png | Bin 0 -> 126 bytes .../Resources/textfield-bezel-square-3.png | Bin 0 -> 112 bytes .../Resources/textfield-bezel-square-4.png | Bin 0 -> 109 bytes .../Resources/textfield-bezel-square-5.png | Bin 0 -> 112 bytes .../Resources/textfield-bezel-square-6.png | Bin 0 -> 120 bytes .../Resources/textfield-bezel-square-7.png | Bin 0 -> 113 bytes .../Resources/textfield-bezel-square-8.png | Bin 0 -> 120 bytes .../Resources/vertical-track-bottom.png | Bin 0 -> 2846 bytes .../Resources/vertical-track-center.png | Bin 0 -> 2809 bytes .../Aristo/Resources/vertical-track-top.png | Bin 0 -> 2881 bytes AppKit/Themes/Aristo/ThemeDescriptors.j | 321 ++++++++++++++++++ AppKit/Themes/Aristo/build.xml | 22 ++ AppKit/Themes/Aristo/index-debug.html | 36 ++ AppKit/Themes/Aristo/index.html | 37 ++ AppKit/Themes/Aristo/main.j | 19 ++ 66 files changed, 447 insertions(+) create mode 100644 AppKit/Themes/Aristo/Info.plist create mode 100644 AppKit/Themes/Aristo/Resources/button-bezel-center.png create mode 100644 AppKit/Themes/Aristo/Resources/button-bezel-highlighted-center.png create mode 100644 AppKit/Themes/Aristo/Resources/button-bezel-highlighted-left.png create mode 100644 AppKit/Themes/Aristo/Resources/button-bezel-highlighted-right.png create mode 100644 AppKit/Themes/Aristo/Resources/button-bezel-left.png create mode 100644 AppKit/Themes/Aristo/Resources/button-bezel-right.png create mode 100644 AppKit/Themes/Aristo/Resources/buttonbar-bezel-right.png create mode 100644 AppKit/Themes/Aristo/Resources/buttonbar-bezel.png create mode 100644 AppKit/Themes/Aristo/Resources/horizontal-track-center.png create mode 100644 AppKit/Themes/Aristo/Resources/horizontal-track-left.png create mode 100644 AppKit/Themes/Aristo/Resources/horizontal-track-right.png create mode 100644 AppKit/Themes/Aristo/Resources/knob-highlighted.png create mode 100644 AppKit/Themes/Aristo/Resources/knob.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-down-arrow-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-down-arrow-highlighted.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-down-arrow.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-up-arrow-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-up-arrow-highlighted.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-up-arrow.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-vertical-knob-bottom.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-vertical-knob-center.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-vertical-knob-top.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-vertical-track-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/old-scroller/scroller-vertical-track.png create mode 100644 AppKit/Themes/Aristo/Resources/popup-arrows-pullsdown.png create mode 100644 AppKit/Themes/Aristo/Resources/popup-arrows.png create mode 100644 AppKit/Themes/Aristo/Resources/popup-bezel-right-pullsdown.png create mode 100644 AppKit/Themes/Aristo/Resources/popup-bezel-right.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-down-arrow-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-down-arrow-highlighted.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-down-arrow.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-center.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-left.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-right.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-horizontal-track.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-left-arrow.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-right-arrow.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-up-arrow-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-up-arrow-highlighted.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-up-arrow.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-vertical-knob-bottom.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-vertical-knob-center.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-vertical-knob-top.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-vertical-track-disabled.png create mode 100644 AppKit/Themes/Aristo/Resources/scroller-vertical-track.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-center.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-left.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-rounded-right.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-square-0.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-square-1.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-square-2.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-square-3.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-square-4.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-square-5.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-square-6.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-square-7.png create mode 100644 AppKit/Themes/Aristo/Resources/textfield-bezel-square-8.png create mode 100644 AppKit/Themes/Aristo/Resources/vertical-track-bottom.png create mode 100644 AppKit/Themes/Aristo/Resources/vertical-track-center.png create mode 100644 AppKit/Themes/Aristo/Resources/vertical-track-top.png create mode 100644 AppKit/Themes/Aristo/ThemeDescriptors.j create mode 100644 AppKit/Themes/Aristo/build.xml create mode 100644 AppKit/Themes/Aristo/index-debug.html create mode 100644 AppKit/Themes/Aristo/index.html create mode 100644 AppKit/Themes/Aristo/main.j diff --git a/AppKit/Themes/Aristo/Info.plist b/AppKit/Themes/Aristo/Info.plist new file mode 100644 index 000000000..9acb0906e --- /dev/null +++ b/AppKit/Themes/Aristo/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + BKShowcaseController + CPBundleName + A + CPPrincipalClass + CPApplication + + diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-center.png b/AppKit/Themes/Aristo/Resources/button-bezel-center.png new file mode 100644 index 0000000000000000000000000000000000000000..9481b3044e95e7487f36af7c1181da8224b3d0e1 GIT binary patch literal 2844 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-highlighted-center.png b/AppKit/Themes/Aristo/Resources/button-bezel-highlighted-center.png new file mode 100644 index 0000000000000000000000000000000000000000..3e1b49146db43755797d218c77fc62e506667f1f GIT binary patch literal 2824 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 a17HBASqX{?X;C2n0000 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-highlighted-left.png b/AppKit/Themes/Aristo/Resources/button-bezel-highlighted-left.png new file mode 100644 index 0000000000000000000000000000000000000000..d6a3317de292e37c594ce501311aa7b0ecf37385 GIT binary patch literal 2905 zcmV-f3#RmmP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0001lNklAWlp!!Q8gW_E}OUU5lC>VcX4Xmp^IvUlU7@&-yNdzJ3? zKjrI&B(-rIad#vkGkdhwn5K!$#3kKotx;<|0r?yNQOyxv^b|Dj00000NkvXXu0mjf DtiWf8 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-highlighted-right.png b/AppKit/Themes/Aristo/Resources/button-bezel-highlighted-right.png new file mode 100644 index 0000000000000000000000000000000000000000..463623cad11c600da29e518aeed4dca23372058c GIT binary patch literal 2910 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/buttonbar-bezel-right.png b/AppKit/Themes/Aristo/Resources/buttonbar-bezel-right.png new file mode 100644 index 0000000000000000000000000000000000000000..cdde2d04e8c5b1b1c1136fcca4d0b9d10aeee0ed GIT binary patch literal 370 zcmV-&0ge8NP)ZvFRyO^gtn4H%4TUp`a)n{+CIOoGFZlR zux;z*M~!O$HK-X5%S~A`A>Y73yFpuunbj5xhmL|oLS*#~m+K9h5K|jpj1$M`q3X1D zKGqmyD58U}fi7AzZCsS>Jij+NF978H@CEcq2V|2K?fB($7e~Bqc2?+{P^}oN)7x~J- a$j0Een9Et=f7>yjat2RVKbLh*2~7a-)+r|d literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/horizontal-track-center.png b/AppKit/Themes/Aristo/Resources/horizontal-track-center.png new file mode 100644 index 0000000000000000000000000000000000000000..efccbec2957f927ad4f8f2b193bd21480b95836e GIT binary patch literal 2807 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 QyZ`_I07*qoM6N<$f`cGVVE_OC literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/horizontal-track-right.png b/AppKit/Themes/Aristo/Resources/horizontal-track-right.png new file mode 100644 index 0000000000000000000000000000000000000000..eea7bfae94404347f5b927c0733b2e1066270d98 GIT binary patch literal 2865 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 N002ovPDHLkV1gwr*P8$U literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/old-scroller/scroller-down-arrow-disabled.png b/AppKit/Themes/Aristo/Resources/old-scroller/scroller-down-arrow-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..01c0f95becdd34c37356c94be2c54675b5e431a9 GIT binary patch literal 3181 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 Twy&2*00000NkvXXu0mjfGM(%g literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/old-scroller/scroller-down-arrow-highlighted.png b/AppKit/Themes/Aristo/Resources/old-scroller/scroller-down-arrow-highlighted.png new file mode 100644 index 0000000000000000000000000000000000000000..1c7e4715efc84ac3fa7ebc9f9498f6f4685147f3 GIT binary patch literal 3439 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 Rbj|<(002ovPDHLkV1ktNZO;Gz literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/old-scroller/scroller-down-arrow.png b/AppKit/Themes/Aristo/Resources/old-scroller/scroller-down-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..51fe09670dfb7fb1c3d06e7ad5a1c9377b1999d0 GIT binary patch literal 3368 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/old-scroller/scroller-up-arrow.png b/AppKit/Themes/Aristo/Resources/old-scroller/scroller-up-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..6349869c739166fcd4539660d36a3decb98d2c22 GIT binary patch literal 3334 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/old-scroller/scroller-vertical-knob-center.png b/AppKit/Themes/Aristo/Resources/old-scroller/scroller-vertical-knob-center.png new file mode 100644 index 0000000000000000000000000000000000000000..d672d44108ce00ba07d580c9068ae9546ef8b798 GIT binary patch literal 2824 zcmV+j3-|PiP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0000pNklO{Qv(S1ONN?4~72y`!~by-@h6B0>cym00030 a{{sN&b||_C02oyO0000KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z00037Nkl-9S1c^)>KjmxrZesg=**f;XC zVMn9mMUo^l@4YRG0`EN`1OQZ(vMg-~VRm_Oz630Q0P^(sFizU-iE|F;9RD$f$#QW& z21I~HuXi+6RlN695yjCIXb2D=v|59zAwV2O10WWlS+CbSs#-a=)^>oV05xNb?4MJG dF-Cye_W)};Zj|)IKm-5)002ovPDHLkV1lJ}qR{{V literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/old-scroller/scroller-vertical-track-disabled.png b/AppKit/Themes/Aristo/Resources/old-scroller/scroller-vertical-track-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..cabb6e2c122f50b8c2799b91622867bd24397b62 GIT binary patch literal 2812 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/popup-arrows-pullsdown.png b/AppKit/Themes/Aristo/Resources/popup-arrows-pullsdown.png new file mode 100644 index 0000000000000000000000000000000000000000..ad83187fb19207d1705723b1b54585296d9ef984 GIT binary patch literal 2950 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/popup-arrows.png b/AppKit/Themes/Aristo/Resources/popup-arrows.png new file mode 100644 index 0000000000000000000000000000000000000000..9fbe069aac557b5d065a303294933f9cdb1cc929 GIT binary patch literal 3072 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/popup-bezel-right.png b/AppKit/Themes/Aristo/Resources/popup-bezel-right.png new file mode 100644 index 0000000000000000000000000000000000000000..0d8c2fc2287d29dbc0224ed886cfcf7f0602d0e8 GIT binary patch literal 3289 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 Z2LQWu*U)|gd?Ek<002ovPDHLkV1iP-Z8rb_ literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/scroller-down-arrow.png b/AppKit/Themes/Aristo/Resources/scroller-down-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..afa831cb8c214802c4c7c4f8ba6bb6914c19c2d8 GIT binary patch literal 3365 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-center.png b/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-center.png new file mode 100644 index 0000000000000000000000000000000000000000..1bc6431259ea137ede104fcec0f017b990096dd9 GIT binary patch literal 2820 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 JPDHLkV1lcjtq%YI literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/scroller-horizontal-track.png b/AppKit/Themes/Aristo/Resources/scroller-horizontal-track.png new file mode 100644 index 0000000000000000000000000000000000000000..34c1cc7e1e6ad8f50399e599e74c9c33f29e163f GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{N!3HE{4j&T&Qk(@Ik;M!Q+`=Ht$S`Y;1W-^R z*(1o8fuTy3fuW(9f#K(WApMeoq11qZ;Z*_ygVhWM2J!q!@kiZ&YK=Wz978H@`5fCQ zc))>!*}x#}zvB$SKdv!LE^4N^DM-F}XRqQL%F0kNGgD>eUEVu)x0^HE;1Vi2_D3uj PsGY&n)z4*}Q$iB}&loQK literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/scroller-left-arrow.png b/AppKit/Themes/Aristo/Resources/scroller-left-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..1fa62615b219c98a47d414ba54f5ef2a2a095a93 GIT binary patch literal 3401 zcmV-P4Yu-$P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0007XNklO8xiCL!l7c+g~@IJWXwAxozN}Rr)4`Qc7_g2gv91n5Nk? zCK8G8JiV9$_JJDkL!awFBbQnHt-!GWY}+Q4O0l)IMJN>N8e^I!j#J-VU0eUCU%jst zr~{3a>{8I0_9LZ0L@1R?q|<3^+Xle0EIiNaD*xwF`Gd}P9dH1*DShXChXRNQ#bS{{ zp@8rEv`9y{e+|Q+TCMKsVryvkfuOMR;*XX;6u>YHVzC&V-O>v{L@-U$==GRRQ-)#i zH&;qAHa5o0%nXS{q79%|d^{eH>%KPtQ=etx;$`UsKePx%1lM&L8X97Dc9vu^*``3J z`@YYa)2BuN3kYeqG>nKyn-WI?@O>Z0aR`UQOixcUIy%}DLPUr}B7+yk&yN6MAOf7! zAjbH_C20kaQmJ(0U7(c0vMiKRxUSo^3z~IPE`Qmax_)CG*apf#MehQqWf&cA4gh$b zhwHioLC`ZU2m*$OlV>NdT{#EDfk7Yv#DEj6b@9)mxHFfX=6N2IlUJv{RVt-d`PVfd zst1$XvJVe1`~4cXb*=_^39cB-}7>e|}+{N087 f?=-*x;Qbl^4;$sc>Y#PY00000NkvXXu0mjfkup^& literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/scroller-right-arrow.png b/AppKit/Themes/Aristo/Resources/scroller-right-arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..3ae19c5eb455265553cb71bae89931dfc35affdb GIT binary patch literal 25008 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/scroller-vertical-track-disabled.png b/AppKit/Themes/Aristo/Resources/scroller-vertical-track-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..4ade298c0ab5c438ed560779121771a073438845 GIT binary patch literal 2814 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 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-1.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-1.png new file mode 100644 index 0000000000000000000000000000000000000000..2c77bb764b5fcec9d4a081d58cf3e9a5525280fa GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^j6lrH!2~4l?*DWZNJ*BsMwA5SrGAr-fhB6pR%{QmxabP0l+XkKX!I#E literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-3.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-3.png new file mode 100644 index 0000000000000000000000000000000000000000..81cd274512cf61edd45262459f6fbfe946bc3fe9 GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^OhC-Y0V1m%Ufcyzk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XggjjwLn>}1?J9bD>Uh6ABNGpUkUDEn`Td}1{rdmk-l2h!fsKusLA$eLEl`TV)78&qol`;+ E0DoN_YybcN literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-5.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-5.png new file mode 100644 index 0000000000000000000000000000000000000000..21f81000edf05b5246b09fb3139cea6868f01ad1 GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^OhC-Y0V1m%Ufcyzk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XggjjwLn>}1{rU0n@#EwDj7&TX!u70m%T6`717#UJUHx3v IIVCg!05qi`djJ3c literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/textfield-bezel-square-6.png b/AppKit/Themes/Aristo/Resources/textfield-bezel-square-6.png new file mode 100644 index 0000000000000000000000000000000000000000..acc67dfa27a9cb969d98d06c4c56ec24d42e80ab GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^Od!kwBL7~QRScvgOI#yLg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+5iDSr z1<%~X^wgl##FWaylc_d9MZ%sgjv*DdlK%YvZ~ypszdR!o4}=$H)6;+SUL2^Y?do0|PUI9~-ybVP4Kj PKvfK$u6{1-oD!M<#hfON literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/vertical-track-bottom.png b/AppKit/Themes/Aristo/Resources/vertical-track-bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..54b7bf7df537f96e685441130ebcf3d0053a8b28 GIT binary patch literal 2846 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 z0000aNkl@P800000 LNkvXXu0mjfTZJ>0 literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/Resources/vertical-track-top.png b/AppKit/Themes/Aristo/Resources/vertical-track-top.png new file mode 100644 index 0000000000000000000000000000000000000000..425e1e99b1efb48b121218d255e7c51969a720f4 GIT binary patch literal 2881 zcmV-H3%>M;P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0001NNkl@0~bk~H8PduiG`3ldGM(B zeu~J;Id|WCf6VOZRrOtKy~P-@)_ROFidWTZYYid-GXoJ_e9k$PQjk&tGh@!_jt~Nv f`R74I`2QUMs)iWg1UMYH00000NkvXXu0mjfd9PQZ literal 0 HcmV?d00001 diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j new file mode 100644 index 000000000..95d365808 --- /dev/null +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -0,0 +1,321 @@ +/* + * AppController.j + * A + * + * Created by __Me__ on __Date__. + * Copyright 2008 __MyCompanyName__. All rights reserved. + */ + +@import + + +@implementation AristoThemeDescriptor : CPObject +{ +} + ++ (CPString)themeName +{ + return @"Aristo"; +} + ++ (CPScroller)themedVerticalScroller +{ + var scroller = [[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, 17.0, 170.0)], + trackColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-vertical-track.png" size:CGSizeMake(17.0, 1.0)]), + disabledTrackColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-vertical-track-disabled.png" size:CGSizeMake(17.0, 1.0)]); + + [scroller setValue:CGSizeMake(15.0, 19.0) forThemedAttributeName:@"minimum-knob-size" inControlState:CPControlStateVertical]; + + [scroller setValue:CGInsetMake(9.0, 9.0, 9.0, 9.0) forThemedAttributeName:@"track-overlap-inset" inControlState:CPControlStateVertical]; + [scroller setValue:trackColor forThemedAttributeName:@"knob-slot-color" inControlState:CPControlStateVertical]; + [scroller setValue:disabledTrackColor forThemedAttributeName:@"knob-slot-color" inControlState:CPControlStateVertical | CPControlStateDisabled]; + + var arrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow.png" size:CGSizeMake(17.0, 30.0)]), + highlightedArrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow-highlighted.png" size:CGSizeMake(17.0, 30.0)]), + disabledArrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow-disabled.png" size:CGSizeMake(17.0, 30.0)]); + + [scroller setValue:CGSizeMake(17.0, 30.0) forThemedAttributeName:@"decrement-line-size" inControlState:CPControlStateVertical]; + [scroller setValue:arrowColor forThemedAttributeName:@"decrement-line-color" inControlState:CPControlStateVertical]; + [scroller setValue:highlightedArrowColor forThemedAttributeName:@"decrement-line-color" inControlState:CPControlStateVertical | CPControlStateHighlighted], + [scroller setValue:disabledArrowColor forThemedAttributeName:@"decrement-line-color" inControlState:CPControlStateVertical | CPControlStateDisabled]; + + var arrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow.png" size:CGSizeMake(17.0, 30.0)]), + highlightedArrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow-highlighted.png" size:CGSizeMake(17.0, 30.0)]), + disabledArrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow-disabled.png" size:CGSizeMake(17.0, 30.0)]); + + [scroller setValue:CGSizeMake(17.0, 30.0) forThemedAttributeName:@"increment-line-size"]; + [scroller setValue:arrowColor forThemedAttributeName:@"increment-line-color" inControlState:CPControlStateVertical]; + [scroller setValue:highlightedArrowColor forThemedAttributeName:@"increment-line-color" inControlState:CPControlStateVertical | CPControlStateHighlighted]; + [scroller setValue:disabledArrowColor forThemedAttributeName:@"increment-line-color" inControlState:CPControlStateVertical | CPControlStateDisabled]; + + var knobColor = PatterColor([[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"scroller-vertical-knob-top.png" size:CGSizeMake(15.0, 8.0)], + [_CPCibCustomResource imageResourceWithName:"scroller-vertical-knob-center.png" size:CGSizeMake(15.0, 1.0)], + [_CPCibCustomResource imageResourceWithName:"scroller-vertical-knob-bottom.png" size:CGSizeMake(15.0, 10.0)] + ] + isVertical:YES]); + + [scroller setValue:knobColor forThemedAttributeName:@"knob-color" inControlState:CPControlStateVertical]; + + [scroller setFloatValue:0.1 knobProportion:0.5]; + + return scroller; +} + ++ (CPScroller)themedHorizontalScroller +{CPControlStateHorizontal = 0; + var scroller = [[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, 170.0, 17.0)], + trackColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-horizontal-track.png" size:CGSizeMake(1.0, 17.0)]), + disabledTrackColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-vertical-track-disabled.png" size:CGSizeMake(17.0, 1.0)]); + [scroller setBackgroundColor:[CPColor blueColor]]; + [scroller setValue:CGSizeMake(19.0, 15.0) forThemedAttributeName:@"minimum-knob-size" inControlState:CPControlStateHorizontal]; + + [scroller setValue:CGInsetMake(9.0, 9.0, 9.0, 9.0) forThemedAttributeName:@"track-overlap-inset" inControlState:CPControlStateHorizontal]; + [scroller setValue:trackColor forThemedAttributeName:@"knob-slot-color" inControlState:CPControlStateHorizontal]; + [scroller setValue:disabledTrackColor forThemedAttributeName:@"knob-slot-color" inControlState:CPControlStateHorizontal | CPControlStateDisabled]; + + var arrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-left-arrow.png" size:CGSizeMake(32.0, 17.0)]), + highlightedArrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow-highlighted.png" size:CGSizeMake(17.0, 30.0)]), + disabledArrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow-disabled.png" size:CGSizeMake(17.0, 30.0)]); + + [scroller setValue:CGSizeMake(32.0, 17.0) forThemedAttributeName:@"decrement-line-size" inControlState:CPControlStateHorizontal]; + [scroller setValue:arrowColor forThemedAttributeName:@"decrement-line-color" inControlState:CPControlStateHorizontal]; + [scroller setValue:highlightedArrowColor forThemedAttributeName:@"decrement-line-color" inControlState:CPControlStateHorizontal | CPControlStateHighlighted], + [scroller setValue:disabledArrowColor forThemedAttributeName:@"decrement-line-color" inControlState:CPControlStateHorizontal | CPControlStateDisabled]; + + var arrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-right-arrow.png" size:CGSizeMake(31.0, 17.0)]), + highlightedArrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow-highlighted.png" size:CGSizeMake(17.0, 30.0)]), + disabledArrowColor = PatterColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow-disabled.png" size:CGSizeMake(17.0, 30.0)]); + + [scroller setValue:CGSizeMake(31.0, 17.0) forThemedAttributeName:@"increment-line-size"]; + [scroller setValue:arrowColor forThemedAttributeName:@"increment-line-color" inControlState:CPControlStateHorizontal]; + [scroller setValue:highlightedArrowColor forThemedAttributeName:@"increment-line-color" inControlState:CPControlStateHorizontal | CPControlStateHighlighted]; + [scroller setValue:disabledArrowColor forThemedAttributeName:@"increment-line-color" inControlState:CPControlStateHorizontal | CPControlStateDisabled]; + + var knobColor = PatterColor([[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"scroller-horizontal-knob-left.png" size:CGSizeMake(11.0, 15.0)], + [_CPCibCustomResource imageResourceWithName:"scroller-horizontal-knob-center.png" size:CGSizeMake(1.0, 15.0)], + [_CPCibCustomResource imageResourceWithName:"scroller-horizontal-knob-right.png" size:CGSizeMake(9.0, 15.0)] + ] + isVertical:NO]); + + [scroller setValue:knobColor forThemedAttributeName:@"knob-color" inControlState:CPControlStateHorizontal]; + + [scroller setFloatValue:0.1 knobProportion:0.5]; + + return scroller; +} + ++ (CPTextField)themedStandardTextField +{ + var textfield = [[CPTextField alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 22.0)], + bezelColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-square-0.png" size:CGSizeMake(2.0, 3.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-square-1.png" size:CGSizeMake(1.0, 3.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-square-2.png" size:CGSizeMake(2.0, 3.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-square-3.png" size:CGSizeMake(2.0, 1.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-square-4.png" size:CGSizeMake(1.0, 1.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-square-5.png" size:CGSizeMake(2.0, 1.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-square-6.png" size:CGSizeMake(2.0, 2.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-square-7.png" size:CGSizeMake(1.0, 2.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-square-8.png" size:CGSizeMake(2.0, 2.0)] + ]]]; + + [textfield setBezeled:YES]; + [textfield setValue:bezelColor forThemedAttributeName:@"bezel-color" inControlState:CPControlStateBezeled]; + [textfield setValue:[CPFont systemFontOfSize:12.0] forThemedAttributeName:@"font"]; + [textfield setValue:CGInsetMake(5.0, 4.0, 2.0, 3.0) forThemedAttributeName:@"content-inset" inControlState:CPControlStateBezeled]; + + [textfield setValue:[CPColor colorWithCalibratedRed:189.0 / 255.0 green:199.0 / 255.0 blue:211.0 / 255.0 alpha:1.0] forThemedAttributeName:@"text-color" inControlState:CPTextFieldStatePlaceholder]; + + [textfield setPlaceholderString:"cheese cheese"]; + [textfield setStringValue:""]; + [textfield setEditable:YES]; + + return textfield; +} + ++ (CPTextField)themedRoundedTextField +{ + var textfield = [[CPTextField alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 22.0)], + bezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-rounded-left.png" size:CGSizeMake(13.0, 22.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-rounded-center.png" size:CGSizeMake(1.0, 22.0)], + [_CPCibCustomResource imageResourceWithName:"textfield-bezel-rounded-right.png" size:CGSizeMake(13.0, 22.0)] + ] isVertical:NO]]; + + [textfield setBezeled:YES]; + [textfield setBezelStyle:CPTextFieldRoundedBezel]; + [textfield setValue:bezelColor forThemedAttributeName:@"bezel-color" inControlState:CPControlStateBezeled | CPTextFieldStateRounded]; + [textfield setValue:[CPFont systemFontOfSize:12.0] forThemedAttributeName:@"font"]; + [textfield setValue:CGInsetMake(5.0, 10.0, 2.0, 10.0) forThemedAttributeName:@"content-inset" inControlState:CPControlStateBezeled | CPTextFieldStateRounded]; + + [textfield setValue:[CPColor colorWithCalibratedRed:189.0 / 255.0 green:199.0 / 255.0 blue:211.0 / 255.0 alpha:1.0] forThemedAttributeName:@"text-color" inControlState:CPTextFieldStatePlaceholder]; + + [textfield setPlaceholderString:"cheese cheese"]; + [textfield setStringValue:""]; + [textfield setEditable:YES]; + + return textfield; +} + ++ (CPButton)themedButton +{ + var button = [[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 24.0)], + + bezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]]; + + highlightedBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"button-bezel-highlighted-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]]; + + [button setTitle:@"Cancel"]; + + [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemedAttributeName:@"font" inControlState:CPControlStateBordered]; + [button setValue:[CPColor colorWithCalibratedWhite:79.0 / 255.0 alpha:1.0] forThemedAttributeName:@"text-color"]; + [button setValue:[CPColor colorWithCalibratedWhite:240.0 / 255.0 alpha:1.0] forThemedAttributeName:@"text-shadow-color" inControlState:CPControlStateBordered]; + [button setValue:CGSizeMake(0.0, 1.0) forThemedAttributeName:@"text-shadow-offset" inControlState:CPControlStateBordered]; + [button setValue:CPLineBreakByTruncatingTail forThemedAttributeName:@"line-break-mode"]; + + [button setValue:bezelColor forThemedAttributeName:@"bezel-color" inControlState:CPControlStateBordered]; + [button setValue:highlightedBezelColor forThemedAttributeName:@"bezel-color" inControlState:CPControlStateBordered|CPControlStateHighlighted]; + [button setValue:CGInsetMake(0.0, 5.0, 0.0, 5.0) forThemedAttributeName:@"content-inset" inControlState:CPControlStateBordered]; + + [button setValue:24.0 forThemedAttributeName:@"default-height"]; + + return button; +} + ++ (CPPopUpButton)themedPopUpButton +{ + var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 24.0) pullsDown:NO],color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"popup-bezel-right.png" size:CGSizeMake(27.0, 24.0)] + ] + isVertical:NO]]; + + [button setTitle:@"Pop Up"]; + + [button setValue:color forThemedAttributeName:@"bezel-color"]; + [button setValue:CGInsetMake(0, 5, 0, 27.0 + 5.0) forThemedAttributeName:@"content-inset"]; + [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemedAttributeName:@"font"]; + [button setValue:[CPColor colorWithCalibratedWhite:79.0 / 255.0 alpha:1.0] forThemedAttributeName:@"text-color"]; + [button setValue:[CPColor colorWithCalibratedWhite:240.0 / 255.0 alpha:1.0] forThemedAttributeName:@"text-shadow-color"]; + [button setValue:CGSizeMake(0.0, 1.0) forThemedAttributeName:@"text-shadow-offset"]; + + [button addItemWithTitle:@"item"]; + + return button; +} + ++ (CPPopUpButton)themedPullDownMenu +{ + var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 24.0) pullsDown:YES], + color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"popup-bezel-right-pullsdown.png" size:CGSizeMake(27.0, 24.0)] + ] + isVertical:NO]]; + + [button setTitle:@"Pop Up"]; + + [button setValue:color forThemedAttributeName:@"bezel-color" inControlState:CPPopUpButtonStatePullsDown]; + [button setValue:CGInsetMake(0, 5, 0, 27.0 + 5.0) forThemedAttributeName:@"content-inset"]; + [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemedAttributeName:@"font"]; + [button setValue:[CPColor colorWithCalibratedWhite:79.0 / 255.0 alpha:1.0] forThemedAttributeName:@"text-color"]; + [button setValue:[CPColor colorWithCalibratedWhite:240.0 / 255.0 alpha:1.0] forThemedAttributeName:@"text-shadow-color"]; + [button setValue:CGSizeMake(0.0, 1.0) forThemedAttributeName:@"text-shadow-offset"]; + + [button addItemWithTitle:@"item"]; + + return button; +} + ++ (CPSlider)themedHorizontalSlider +{ + var slider = [[CPSlider alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 24.0)], + trackColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"horizontal-track-left.png" size:CGSizeMake(4.0, 5.0)], + [_CPCibCustomResource imageResourceWithName:"horizontal-track-center.png" size:CGSizeMake(1.0, 5.0)], + [_CPCibCustomResource imageResourceWithName:"horizontal-track-right.png" size:CGSizeMake(4.0, 5.0)] + ] + isVertical:NO]]; + + [slider setValue:5.0 forThemedAttributeName:@"track-width"]; + [slider setValue:trackColor forThemedAttributeName:@"horizontal-track-color"]; + + var knobColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"knob.png" size:CGSizeMake(23.0, 24.0)]]; + knobHighlightedColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"knob-highlighted.png" size:CGSizeMake(23.0, 24.0)]]; + + [slider setValue:CGSizeMake(23.0, 24.0) forThemedAttributeName:@"knob-size"]; + [slider setValue:knobColor forThemedAttributeName:@"knob-color"]; + [slider setValue:knobHighlightedColor forThemedAttributeName:@"knob-color" inControlState:CPControlStateHighlighted]; + + return slider; +} + ++ (CPSlider)themedVerticalSlider +{ + var slider = [[CPSlider alloc] initWithFrame:CGRectMake(0.0, 0.0, 24.0, 50.0)], + trackColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"vertical-track-top.png" size:CGSizeMake(5.0, 6.0)], + [_CPCibCustomResource imageResourceWithName:"vertical-track-center.png" size:CGSizeMake(5.0, 1.0)], + [_CPCibCustomResource imageResourceWithName:"vertical-track-bottom.png" size:CGSizeMake(5.0, 4.0)] + ] + isVertical:YES]]; + + [slider setValue:5.0 forThemedAttributeName:@"track-width"]; + [slider setValue:trackColor forThemedAttributeName:@"vertical-track-color"]; + + var knobColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"knob.png" size:CGSizeMake(23.0, 24.0)]]; + knobHighlightedColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"knob-highlighted.png" size:CGSizeMake(23.0, 24.0)]]; + + [slider setValue:CGSizeMake(23.0, 24.0) forThemedAttributeName:@"knob-size"]; + [slider setValue:knobColor forThemedAttributeName:@"knob-color"]; + [slider setValue:knobHighlightedColor forThemedAttributeName:@"knob-color" inControlState:CPControlStateHighlighted]; + + return slider; +} +/* + var buttonBar = [[CPButtonBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 30.0)], + color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"buttonbar-bezel.png" size:CGSizeMake(1.0, 30.0)], + [_CPCibCustomResource imageResourceWithName:"buttonbar-bezel.png" size:CGSizeMake(1.0, 30.0)], + [_CPCibCustomResource imageResourceWithName:"buttonbar-bezel-right.png" size:CGSizeMake(13.0, 30.0)] + ] + isVertical:NO]]; + + [buttonBar setValue:color forThemedAttributeName:@"bezel-color"]; + [buttonBar setNeedsLayout]; + + views.push(buttonBar); + + return views; +*/ +@end + +function PatterColor(anImage) +{ + return [CPColor colorWithPatternImage:anImage]; +} diff --git a/AppKit/Themes/Aristo/build.xml b/AppKit/Themes/Aristo/build.xml new file mode 100644 index 000000000..bde34921e --- /dev/null +++ b/AppKit/Themes/Aristo/build.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/AppKit/Themes/Aristo/index-debug.html b/AppKit/Themes/Aristo/index-debug.html new file mode 100644 index 000000000..df94938fc --- /dev/null +++ b/AppKit/Themes/Aristo/index-debug.html @@ -0,0 +1,36 @@ + + + + + + + Hello World + + + + + + + + +
+
+ +
+
+ + + diff --git a/AppKit/Themes/Aristo/index.html b/AppKit/Themes/Aristo/index.html new file mode 100644 index 000000000..6088568e4 --- /dev/null +++ b/AppKit/Themes/Aristo/index.html @@ -0,0 +1,37 @@ + + + + + + + Hello World + + + + + + + + + +
+
+ +
+
+ + + + diff --git a/AppKit/Themes/Aristo/main.j b/AppKit/Themes/Aristo/main.j new file mode 100644 index 000000000..4e2dcfa77 --- /dev/null +++ b/AppKit/Themes/Aristo/main.j @@ -0,0 +1,19 @@ +/* + * main.j + * A + * + * Created by __Me__ on __Date__. + * Copyright 2008 __MyCompanyName__. All rights reserved. + */ + +@import +@import +@import + +@import "ThemeDescriptors.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +}