diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 14bf6ccd5..97a2f1518 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -148,7 +148,8 @@ var CPAlertWarningImage, var button = _buttons[i]; [button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)]; - [button setTheme:[CPTheme themeNamed: _windowStyle === CPHUDBackgroundWindowMask ? "Aristo-HUD" : "Aristo"]]; + + [button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]]; [[_alertPanel contentView] addSubview:button]; } @@ -263,8 +264,8 @@ var CPAlertWarningImage, [button setTag:_buttonCount]; [button setAction:@selector(_notifyDelegate:)]; - [button setTheme:[CPTheme themeNamed: _windowStyle === CPHUDBackgroundWindowMask ? "Aristo-HUD" : "Aristo"]]; - [button setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin]; + [button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]]; + [button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin]; [[_alertPanel contentView] addSubview:button]; diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index ee53c6643..c8debf421 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -962,7 +962,7 @@ CPRunContinuesResponse = -1002; + (CPString)defaultThemeName { // FIXME: don't hardcode - return @"Aristo.blend"; + return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo"); } @end @@ -1069,7 +1069,7 @@ var _CPAppBootstrapperActions = nil; + (BOOL)loadDefaultTheme { - var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName]]]; + var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]]; [blend loadWithDelegate:self]; @@ -1078,7 +1078,7 @@ var _CPAppBootstrapperActions = nil; + (void)blendDidFinishLoading:(CPBundle)aBundle { - [CPTheme setDefaultTheme:[CPTheme themeNamed:@"Aristo"]]; + [CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]]; [self performActions]; } diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 40413eb5b..4a9ddecba 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -359,21 +359,29 @@ - (void)tile { var width = CGRectGetWidth([self bounds]); - + if (![_content count] || width == _tileWidth) return; - + // We try to fit as many views per row as possible. Any remaining space is then // either proportioned out to the views (if their minSize != maxSize) or used as // margin var itemSize = CGSizeMakeCopy(_minItemSize); - + _numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width)); - + if (_maxNumberOfColumns > 0) _numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns); - - var remaining = width - _numberOfColumns * itemSize.width, + + var nbItems = [_items count]; + if (_numberOfColumns > nbItems) + _numberOfColumns = nbItems; + + var maxItemSize = CGSizeMakeCopy(_maxItemSize); + if (maxItemSize.width==0) + maxItemSize.width = FLOOR(width / _numberOfColumns); + + var remaining = width - _numberOfColumns * itemSize.width, itemsNeedSizeUpdate = NO; if (remaining > 0 && itemSize.width < _maxItemSize.width) @@ -406,7 +414,7 @@ { if (index % _numberOfColumns == 0) { - x = _horizontalMargin; + x = 0; y += _verticalMargin + itemSize.height; } @@ -417,7 +425,7 @@ if (itemsNeedSizeUpdate) [view setFrameSize:_itemSize]; - x += itemSize.width + _horizontalMargin; + x += itemSize.width; } _tileWidth = width; diff --git a/AppKit/CPColor.j b/AppKit/CPColor.j index 636f96a3f..cdc3af3a7 100644 --- a/AppKit/CPColor.j +++ b/AppKit/CPColor.j @@ -735,6 +735,9 @@ var CPColorComponentsKey = @"CPColorComponentsKey", var hexCharacters = "0123456789ABCDEF"; +// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior +var hexToRGB, integerToBytes, rgbToHex, byteToHex; + /*! Used for the CPColor \c +colorWithHexString: implementation @ignore diff --git a/AppKit/CPFlashMovie.j b/AppKit/CPFlashMovie.j index b666c2391..22cd0c520 100644 --- a/AppKit/CPFlashMovie.j +++ b/AppKit/CPFlashMovie.j @@ -30,7 +30,7 @@ */ @implementation CPFlashMovie : CPObject { - CPString _fileName; + CPString _filename; } /*! @@ -38,9 +38,9 @@ @param aFilename the swf to load @return the initialized CPFlashMovie */ -+ (id)flashMovieWithFile:(CPString)aFileName ++ (id)flashMovieWithFile:(CPString)aFilename { - return [[self alloc] initWithFile:aFileName]; + return [[self alloc] initWithFile:aFilename]; } /*! @@ -48,14 +48,37 @@ @param aFilename the swf to load @return the initialized CPFlashMovie */ -- (id)initWithFile:(CPString)aFileName +- (id)initWithFile:(CPString)aFilename { self = [super init]; if (self) - _fileName = aFileName; + _filename = aFilename; return self; } +- (CPString)filename +{ + return _filename; +} + +@end + +var CPFlashMovieFilenameKey = "CPFlashMovieFilenameKey"; + +@implementation CPFlashMovie (CPCoding) + +- (id)initWithCoder:(CPCoder)aCoder +{ + _filename = [aCoder decodeObjectForKey:CPFlashMovieFilenameKey]; + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [aCoder encodeObject:_filename forKey:CPFlashMovieFilenameKey]; +} + @end \ No newline at end of file diff --git a/AppKit/CPFlashView.j b/AppKit/CPFlashView.j index d1c0a9ba0..8f1d99fa8 100644 --- a/AppKit/CPFlashView.j +++ b/AppKit/CPFlashView.j @@ -24,20 +24,21 @@ @import "CPView.j" +var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"; + /*! @ingroup appkit */ @implementation CPFlashView : CPView { CPFlashMovie _flashMovie; - CPDictionary _flashVars; CPDictionary _params; CPDictionary _paramElements; - DOMElement _DOMEmbedElement; - DOMElement _DOMMParamElement; + DOMElement _DOMParamElement; DOMElement _DOMObjectElement; + DOMElement _DOMInnerObjectElement; } - (id)initWithFrame:(CGRect)aFrame @@ -46,35 +47,30 @@ if (self) { - _DOMObjectElement = document.createElement("object"); - _DOMObjectElement.width = "100%"; - _DOMObjectElement.height = "100%"; - _DOMObjectElement.style.top = "0px"; - _DOMObjectElement.style.left = "0px"; - - _DOMParamElement = document.createElement("param"); - _DOMParamElement.name = "movie"; - - _DOMObjectElement.appendChild(_DOMParamElement); - - var param = document.createElement("param"); - - param.name = "wmode"; - param.value = "transparent"; - - _DOMObjectElement.appendChild(param); - - _DOMEmbedElement = document.createElement("embed"); - - _DOMEmbedElement.type = "application/x-shockwave-flash"; - _DOMEmbedElement.setAttribute("wmode", "transparent"); - _DOMEmbedElement.width = "100%"; - _DOMEmbedElement.height = "100%"; - - // IE requires this thing to be in the _DOMElement and not the _DOMObjectElement. - _DOMElement.appendChild(_DOMEmbedElement); - - _DOMElement.appendChild(_DOMObjectElement); + if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine)) + { + _DOMObjectElement = document.createElement(@"object"); + _DOMObjectElement.width = @"100%"; + _DOMObjectElement.height = @"100%"; + _DOMObjectElement.style.top = @"0px"; + _DOMObjectElement.style.left = @"0px"; + _DOMObjectElement.type = @"application/x-shockwave-flash"; + _DOMObjectElement.setAttribute(@"classid", IEFlashCLSID); + + _DOMParamElement = document.createElement(@"param"); + _DOMParamElement.name = @"movie"; + + _DOMInnerObjectElement = document.createElement(@"object"); + _DOMInnerObjectElement.width = @"100%"; + _DOMInnerObjectElement.height = @"100%"; + + _DOMObjectElement.appendChild(_DOMParamElement); + _DOMObjectElement.appendChild(_DOMInnerObjectElement); + + _DOMElement.appendChild(_DOMObjectElement); + } + else + [self _rebuildIEObjects]; } return self; @@ -87,10 +83,13 @@ _flashMovie = aFlashMovie; - _DOMParamElement.value = aFlashMovie._fileName; - - if (_DOMEmbedElement) - _DOMEmbedElement.src = aFlashMovie._fileName; + if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine)) + { + _DOMParamElement.value = [aFlashMovie filename]; + _DOMInnerObjectElement.data = [aFlashMovie filename]; + } + else + [self _rebuildIEObjects]; } - (CPFlashMovie)flashMovie @@ -100,33 +99,28 @@ - (void)setFlashVars:(CPDictionary)aDictionary { - _flashVars = aDictionary; - var varString = @"", - enumerator = [_flashVars keyEnumerator]; + enumerator = [aDictionary keyEnumerator]; var key; while (key = [enumerator nextObject]) - varString = [varString stringByAppendingFormat:@"&%@=%@", key, [_flashVars objectForKey:key]]; + varString = [varString stringByAppendingFormat:@"&%@=%@", key, [aDictionary objectForKey:key]]; - var param = document.createElement(@"param"); - param.name = @"flashvars"; - param.value = varString; + if (!_params) + _params = [CPDictionary dictionary]; - _DOMObjectElement.appendChild(param); - - if (_DOMEmbedElement) - _DOMEmbedElement.setAttribute(@"flashvars", varString); + [_params setObject:varString forKey:@"flashvars"]; + [self setParameters:_params]; } - (CPDictionary)flashVars { - return _flashVars; + return [_params objectForKey:@"flashvars"]; } - (void)setParameters:(CPDictionary)aDictionary { - if (_paramElements) + if (_paramElements && !CPBrowserIsEngine(CPInternetExplorerBrowserEngine)) { var elements = [_paramElements allValues], count = [elements count]; @@ -136,21 +130,27 @@ } _params = aDictionary; - _paramElements = [CPDictionary dictionary]; - var enumerator = [_params keyEnumerator], - key; - - while (key = [enumerator nextObject]) + if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine)) { - var param = document.createElement(@"param"); - param.name = key; - param.value = [_params objectForKey:key]; + _paramElements = [CPDictionary dictionary]; - _DOMObjectElement.appendChild(param); + var enumerator = [_params keyEnumerator], + key; - [_paramElements setObject:param forKey:key]; + while (key = [enumerator nextObject] && _DOMObjectElement) + { + var param = document.createElement(@"param"); + param.name = key; + param.value = [_params objectForKey:key]; + + _DOMObjectElement.appendChild(param); + + [_paramElements setObject:param forKey:key]; + } } + else + [self _rebuildIEObjects]; } - (CPDictionary)parameters @@ -158,6 +158,25 @@ return _params; } +- (void)_rebuildIEObjects +{ + _DOMElement.innerHTML = @""; + if (![_flashMovie filename]) + return; + + var paramString = [CPString stringWithFormat:@"", [_flashMovie filename]], + paramEnumerator = [_params keyEnumerator], + key; + + while (key = [paramEnumerator nextObject]) + paramString = [paramString stringByAppendingFormat:@"", key, [_params objectForKey:key]]; + + _DOMObjectElement = document.createElement(@"object"); + _DOMElement.appendChild(_DOMObjectElement); + + _DOMObjectElement.outerHTML = [CPString stringWithFormat:@"%@", IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString]; +} + - (void)mouseDragged:(CPEvent)anEvent { [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; diff --git a/AppKit/CPMenu/_CPMenuBarWindow.j b/AppKit/CPMenu/_CPMenuBarWindow.j index 1898e7252..da829d047 100644 --- a/AppKit/CPMenu/_CPMenuBarWindow.j +++ b/AppKit/CPMenu/_CPMenuBarWindow.j @@ -1,5 +1,6 @@ #include "../CoreGraphics/CGGeometry.h" +#include "../Platform/Platform.h" @import "_CPMenuWindow.j" diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j index 8022dad0e..33d243f22 100644 --- a/AppKit/CPSplitView.j +++ b/AppKit/CPSplitView.j @@ -144,12 +144,11 @@ var CPSplitViewHorizontalImage = nil, { if (_isPaneSplitter == shouldBePaneSplitter) return; - + _isPaneSplitter = shouldBePaneSplitter; -#if PLATFORM(DOM) - _DOMDividerElements = []; -#endif + if(_DOMDividerElements[_drawingDivider]) + [self _setupDOMDivider] // The divider changes size when pane splitter mode is toggled, so the // subviews need to change size too. @@ -160,7 +159,6 @@ var CPSplitViewHorizontalImage = nil, - (void)didAddSubview:(CPView)aSubview { _needsResizeSubviews = YES; -// [self adjustSubviews]; } - (BOOL)isSubviewCollapsed:(CPView)subview @@ -216,16 +214,7 @@ var CPSplitViewHorizontalImage = nil, CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]); - if (_isPaneSplitter) - { - _DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5"; - _DOMDividerElements[_drawingDivider].style.backgroundImage = ""; - } - else - { - _DOMDividerElements[_drawingDivider].style.backgroundColor = ""; - _DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')"; - } + [self _setupDOMDivider]; } CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect)); @@ -233,6 +222,20 @@ var CPSplitViewHorizontalImage = nil, #endif } +- (void)_setupDOMDivider +{ + if (_isPaneSplitter) + { + _DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5"; + _DOMDividerElements[_drawingDivider].style.backgroundImage = ""; + } + else + { + _DOMDividerElements[_drawingDivider].style.backgroundColor = ""; + _DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')"; + } +} + - (void)viewWillDraw { [self _adjustSubviewsWithCalculatedSize]; @@ -515,8 +518,6 @@ var CPSplitViewHorizontalImage = nil, } else if (totalSizableSpace && !isSizable) viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent]; - else - alert("SHOULD NEVER GET HERE"); bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness; diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 3a2b505e8..ff105e47a 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -481,10 +481,10 @@ window.setTimeout(function(){ [self setSelectionHightlightColor:[CPColor selectionColorSourceView]]; _destinationDragStyle = CPTableViewDraggingDestinationFeedbackStyleSourceList; } - else - { - [self setSelectionHightlightColor:[CPColor selectionColor]]; - _destinationDragStyle = CPTableViewDraggingDestinationFeedbackStyleRegular; + else + { + [self setSelectionHightlightColor:[CPColor selectionColor]]; + _destinationDragStyle = CPTableViewDraggingDestinationFeedbackStyleRegular; } } @@ -656,7 +656,7 @@ window.setTimeout(function(){ - (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection { - if (([rows firstIndex] != CPNotFound && [rows firstIndex] < 0) || [rows lastIndex] >= [self numberOfRows]) + if ([rows isEqualToIndexSet:_selectedRowIndexes] || (([rows firstIndex] != CPNotFound && [rows firstIndex] < 0) || [rows lastIndex] >= [self numberOfRows])) return; // We deselect all columns when selecting rows. @@ -1433,55 +1433,63 @@ window.setTimeout(function(){ } - (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows - tableColumns:(CPArray)theTableColumns - event:(CPEvent)dragEvent - offset:(CPPointPointer)dragImageOffset + tableColumns:(CPArray)theTableColumns + event:(CPEvent)dragEvent + offset:(CPPointPointer)dragImageOffset { return [[CPImage alloc] initWithContentsOfFile:@"Frameworks/AppKit/Resources/GenericFile.png" size:CGSizeMake(32,32)]; } - (CPView)dragViewForRowsWithIndexes:(CPIndexSet)theDraggedRows - tableColumns:(CPArray)theTableColumns - event:(CPEvent)theDragEvent - offset:(CPPoint)dragViewOffset + tableColumns:(CPArray)theTableColumns + event:(CPEvent)theDragEvent + offset:(CPPoint)dragViewOffset { - var size = [self bounds].size, - view = [[CPView alloc] initWithFrame:CPMakeRect(dragViewOffset.x, dragViewOffset.y, size.width, size.height)]; - - [view setBackgroundColor:[CPColor clearColor]]; - [view setAlphaValue:0.7]; - - // We have to fetch all the data views for the selected rows and columns - // After that we can copy these add them to a transparent drag view and use that drag view - // to make it appear we are dragging images of those rows (as you would do in regular Cocoa) - var firstExposedColumn = [_exposedColumns firstIndex], - exposedLength = [_exposedColumns lastIndex] - firstExposedColumn + 1, - columns = []; - - [_exposedColumns getIndexes:columns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedLength)]; - - var columnIndex = [columns count], - draggedDataViews = [], - dragViewHeight = 0.0; - - while (columnIndex--) { - var column = [_tableColumns objectAtIndex:columnIndex], - yOffset = 0, - rowIndex = CPNotFound; - - while ((rowIndex = [_selectedRowIndexes indexGreaterThanIndex:rowIndex]) !== CPNotFound) - { - var dataView = [self _newDataViewForRow:rowIndex tableColumn:column]; - - [dataView setBackgroundColor:[CPColor clearColor]]; - [dataView setFrame:[self frameOfDataViewAtColumn:columnIndex row:rowIndex]]; - [dataView setObjectValue:[self _objectValueForTableColumn:column row:rowIndex]]; - - [view addSubview:dataView]; - } - } - - return view; + var bounds = [self bounds], + view = [[CPView alloc] initWithFrame:bounds]; + + [view setBackgroundColor:[CPColor clearColor]]; + [view setAlphaValue:0.7]; + + // We have to fetch all the data views for the selected rows and columns + // After that we can copy these add them to a transparent drag view and use that drag view + // to make it appear we are dragging images of those rows (as you would do in regular Cocoa) + var firstExposedColumn = [_exposedColumns firstIndex], + firstExposedRow = [_exposedRows firstIndex], + exposedColumnsLength = [_exposedColumns lastIndex] - firstExposedColumn + 1, + exposedRowsLength = [_exposedRows lastIndex] - firstExposedRow + 1, + columns = [], + rows = []; + + [_exposedColumns getIndexes:columns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedColumnsLength)]; + [theDraggedRows getIndexes:rows maxCount:-1 inIndexRange:CPMakeRange(firstExposedRow, exposedRowsLength)]; + + var columnIndex = [columns count]; + + while (columnIndex--) + { + var column = columns[columnIndex], + tableColumn = [_tableColumns objectAtIndex:column], + rowIndex = [rows count]; + + while (rowIndex--) + { + var row = rows[rowIndex]; + var dataView = [self _newDataViewForRow:row tableColumn:tableColumn]; + + [dataView setBackgroundColor:[CPColor clearColor]]; + [dataView setFrame:[self frameOfDataViewAtColumn:column row:row]]; + [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]]; + + [view addSubview:dataView]; + } + } + + var dragPoint = [self convertPoint:[theDragEvent locationInWindow] fromView:nil]; + dragViewOffset.x = CGRectGetWidth(bounds)/2 - dragPoint.x; + dragViewOffset.y = CGRectGetHeight(bounds)/2 - dragPoint.y; + + return view; } - (void)setDraggingSourceOperationMask:(CPDragOperation)mask forLocal:(BOOL)isLocal @@ -1554,7 +1562,6 @@ window.setTimeout(function(){ - (id)_objectValueForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRowIndex { - CPLog.debug(@"_objectValueForTableColumn:%@ row: %@", aTableColumn, aRowIndex); var tableColumnUID = [aTableColumn UID], tableColumnObjectValues = _objectValues[tableColumnUID]; @@ -1572,7 +1579,6 @@ window.setTimeout(function(){ tableColumnObjectValues[aRowIndex] = objectValue; } - CPLog.debug(@"return %@", objectValue); return objectValue; } @@ -1976,7 +1982,7 @@ window.setTimeout(function(){ indexes = [], rectSelector = @selector(rectOfRow:); - [_selectionHightlightColor setFill]; + [_selectionHightlightColor setFill]; if ([_selectedRowIndexes count] >= 1) @@ -2148,10 +2154,7 @@ window.setTimeout(function(){ // if the table has drag support then we use mouseUp to select a single row. // otherwise it uses mouse down. if(!(_implementedDataSourceMethods & CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_)) - { - _previouslySelectedRowIndexes = nil; [self _updateSelectionWithMouseAtRow:row]; - } [[self window] makeFirstResponder:self]; return YES; @@ -2160,10 +2163,8 @@ window.setTimeout(function(){ /* ignore */ - (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint { - var row = [self rowAtPoint:aPoint]; - // begin the drag is the datasource lets us, we've move at least +-3px vertical or horizontal, or we're dragging from selected rows and we haven't begun a drag session if ( @@ -2175,7 +2176,7 @@ window.setTimeout(function(){ ) ) { - if([_selectedRowIndexes containsIndex:row]) + if ([_selectedRowIndexes containsIndex:row]) _draggedRowIndexes = [[CPIndexSet alloc] initWithIndexSet:_selectedRowIndexes]; else _draggedRowIndexes = [CPIndexSet indexSetWithIndex:row]; @@ -2184,33 +2185,34 @@ window.setTimeout(function(){ //ask the datasource for the data var pboard = [CPPasteboard pasteboardWithName:CPDragPboard]; - if([self canDragRowsWithIndexes:_draggedRowIndexes atPoint:aPoint] && [_dataSource tableView:self writeRowsWithIndexes:_draggedRowIndexes toPasteboard:pboard]) + if ([self canDragRowsWithIndexes:_draggedRowIndexes atPoint:aPoint] && [_dataSource tableView:self writeRowsWithIndexes:_draggedRowIndexes toPasteboard:pboard]) { - var currentEvent = [CPApp currentEvent], - offset = CPPointMakeZero(); - - // We deviate from the default Cocoa implementation here by asking for a view in stead of an image - // We support both, but the view prefered over the image because we can mimic the rows we are dragging - // by re-creating the data views for the dragged rows - var view = [self dragViewForRowsWithIndexes:_draggedRowIndexes - tableColumns:_exposedColumns - event:currentEvent - offset:CPPointMakeZero()]; - - if (!view) { - var image = [self dragImageForRowsWithIndexes:_draggedRowIndexes - tableColumns:_exposedColumns - event:currentEvent - offset:CPPointMakeZero()]; - - view = [[CPImageView alloc] initWithFrame:CPMakeRect(aPoint.x, aPoint.y, [image size].width, [image size].height)]; - [view setImage:image]; - - offset = aPoint; - } - - [self dragView:view at:offset offset:CPPointMakeZero() event:[CPApp currentEvent] pasteboard:pboard source:self slideBack:YES]; - + var currentEvent = [CPApp currentEvent], + offset = CPPointMakeZero(), + tableColumns = [_tableColumns objectsAtIndexes:_exposedColumns]; + + // We deviate from the default Cocoa implementation here by asking for a view in stead of an image + // We support both, but the view prefered over the image because we can mimic the rows we are dragging + // by re-creating the data views for the dragged rows + var view = [self dragViewForRowsWithIndexes:_draggedRowIndexes + tableColumns:tableColumns + event:currentEvent + offset:offset]; + + if (!view) + { + var image = [self dragImageForRowsWithIndexes:_draggedRowIndexes + tableColumns:tableColumns + event:currentEvent + offset:offset]; + view = [[CPImageView alloc] initWithFrame:CPMakeRect(0, 0, [image size].width, [image size].height)]; + [view setImage:image]; + } + + var bounds = [view bounds]; + var viewLocation = CPPointMake(aPoint.x - CGRectGetWidth(bounds)/2 + offset.x, aPoint.y - CGRectGetHeight(bounds)/2 + offset.y); + [self dragView:view at:viewLocation offset:CPPointMakeZero() event:[CPApp currentEvent] pasteboard:pboard source:self slideBack:YES]; + return NO; } } @@ -2254,15 +2256,11 @@ window.setTimeout(function(){ return; } // if the table has drag support then we use mouseUp to select a single row. - _previouslySelectedRowIndexes = nil; + _previouslySelectedRowIndexes = [_selectedRowIndexes copy]; [self _updateSelectionWithMouseAtRow:rowIndex]; } } - if (![_previouslySelectedRowIndexes isEqualToIndexSet:_selectedRowIndexes]) - [self _noteSelectionDidChange]; - - if (mouseIsUp && (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_) && !_trackingPointMovedOutOfClickSlop @@ -2574,13 +2572,9 @@ window.setTimeout(function(){ if ([newSelection isEqualToIndexSet:_selectedRowIndexes]) return; - if (!_previouslySelectedRowIndexes) - _previouslySelectedRowIndexes = [_selectedRowIndexes copy]; [self selectRowIndexes:newSelection byExtendingSelection:NO]; - [self _noteSelectionIsChanging]; - } - (void)_noteSelectionIsChanging @@ -2614,108 +2608,108 @@ window.setTimeout(function(){ [self interpretKeyEvents:[CPArray arrayWithObject:anEvent]]; } -- (void)interpretKeyEvents:(CPArray)events +- (void)moveDown:(id)sender { - [super interpretKeyEvents:events]; + if (_implementedDelegateMethods & CPTableViewDelegate_selectionShouldChangeInTableView_ && + ![_delegate selectionShouldChangeInTableView:self]) + return; - for(var i = 0; i < [events count]; i++) + var anEvent = [CPApp currentEvent]; + if([[self selectedRowIndexes] count] > 0) { - var anEvent = [events objectAtIndex:i], - key = [anEvent keyCode]; + var extend = NO; - if(key === CPDeleteKeyCode && [_delegate respondsToSelector: @selector(tableViewDeleteKeyPressed:)]) - [_delegate tableViewDeleteKeyPressed:self]; + if(([anEvent modifierFlags] & CPShiftKeyMask) && _allowsMultipleSelection) + extend = YES; - if(key === CPUpArrowKeyCode) - { - if([[self selectedRowIndexes] count] > 0) - { - var extend = NO; - - if(([anEvent modifierFlags] & CPShiftKeyMask) && _allowsMultipleSelection) - extend = YES; - - var i = [[self selectedRowIndexes] firstIndex]; - if(i > 0) - i--; //set index to the prev row before the first row selected - } - else - { - var extend = NO; - //no rows are currently selected - if([self numberOfRows] > 0) - var i = [self numberOfRows] - 1; //select the first row - } - - - if(_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldSelectRow_) - { - - while((![_delegate tableView:self shouldSelectRow:i]) && i > 0) - { - //check to see if the row can be selected if it can't be then see if the prev row can be selected - i--; - } - - //if the index still can be selected after the loop then just return - if(![_delegate tableView:self shouldSelectRow:i]) - return; - } - - [self selectRowIndexes:[CPIndexSet indexSetWithIndex:i] byExtendingSelection:extend]; - - if(i) - { - [self scrollRowToVisible:i]; - [self _noteSelectionDidChange]; - } - } - - if(key == CPDownArrowKeyCode) - { - if([[self selectedRowIndexes] count] > 0) - { - var extend = NO; - - if(([anEvent modifierFlags] & CPShiftKeyMask) && _allowsMultipleSelection) - extend = YES; - - var i = [[self selectedRowIndexes] lastIndex]; - if(i<[self numberOfRows] - 1) - i++; //set index to the next row after the last row selected - } - else - { - var extend = NO; - //no rows are currently selected - if([self numberOfRows] > 0) - var i = 0; //select the first row - } - - - if(_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldSelectRow_) - { - - while((![_delegate tableView:self shouldSelectRow:i]) && i<[self numberOfRows]) - { - //check to see if the row can be selected if it can't be then see if the next row can be selected - i++; - } - - //if the index still can be selected after the loop then just return - if(![_delegate tableView:self shouldSelectRow:i]) - return; - } - - [self selectRowIndexes:[CPIndexSet indexSetWithIndex:i] byExtendingSelection:extend]; - - if(i) - { - [self scrollRowToVisible:i]; - [self _noteSelectionDidChange]; - } - } + var i = [[self selectedRowIndexes] lastIndex]; + if(i<[self numberOfRows] - 1) + i++; //set index to the next row after the last row selected } + else + { + var extend = NO; + //no rows are currently selected + if([self numberOfRows] > 0) + var i = 0; //select the first row + } + + + if(_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldSelectRow_) + { + + while((![_delegate tableView:self shouldSelectRow:i]) && i<[self numberOfRows]) + { + //check to see if the row can be selected if it can't be then see if the next row can be selected + i++; + } + + //if the index still can be selected after the loop then just return + if(![_delegate tableView:self shouldSelectRow:i]) + return; + } + + [self selectRowIndexes:[CPIndexSet indexSetWithIndex:i] byExtendingSelection:extend]; + + if(i) + { + [self scrollRowToVisible:i]; + } +} + +- (void)moveUp:(id)sender +{ + if (_implementedDelegateMethods & CPTableViewDelegate_selectionShouldChangeInTableView_ && + ![_delegate selectionShouldChangeInTableView:self]) + return; + + var anEvent = [CPApp currentEvent]; + if([[self selectedRowIndexes] count] > 0) + { + var extend = NO; + + if(([anEvent modifierFlags] & CPShiftKeyMask) && _allowsMultipleSelection) + extend = YES; + + var i = [[self selectedRowIndexes] firstIndex]; + if(i > 0) + i--; //set index to the prev row before the first row selected + } + else + { + var extend = NO; + //no rows are currently selected + if([self numberOfRows] > 0) + var i = [self numberOfRows] - 1; //select the first row + } + + + if(_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldSelectRow_) + { + + while((![_delegate tableView:self shouldSelectRow:i]) && i > 0) + { + //check to see if the row can be selected if it can't be then see if the prev row can be selected + i--; + } + + //if the index still can be selected after the loop then just return + if(![_delegate tableView:self shouldSelectRow:i]) + return; + } + + [self selectRowIndexes:[CPIndexSet indexSetWithIndex:i] byExtendingSelection:extend]; + + if(i) + { + [self scrollRowToVisible:i]; + } +} + +- (void)deleteBackward:(id)sender +{ + if([_delegate respondsToSelector: @selector(tableViewDeleteKeyPressed:)]) + [_delegate tableViewDeleteKeyPressed:self]; } @end diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index e647e542f..c906e80ca 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -799,41 +799,50 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)copy:(id)sender { - var selectedRange = [self selectedRange]; + if (![CPPlatform isBrowser]) + { + var selectedRange = [self selectedRange]; - if (selectedRange.length < 1) - return; + if (selectedRange.length < 1) + return; - var pasteboard = [CPPasteboard generalPasteboard], - stringValue = [self stringValue], - stringForPasting = [stringValue substringWithRange:selectedRange]; + var pasteboard = [CPPasteboard generalPasteboard], + stringValue = [self stringValue], + stringForPasting = [stringValue substringWithRange:selectedRange]; - [pasteboard declareTypes:[CPStringPboardType] owner:nil]; - [pasteboard setString:stringForPasting forType:CPStringPboardType]; + [pasteboard declareTypes:[CPStringPboardType] owner:nil]; + [pasteboard setString:stringForPasting forType:CPStringPboardType]; + } } - (void)cut:(id)sender { - [self copy:sender]; - [self deleteBackwards:sender]; + if (![CPPlatform isBrowser]) + { + [self copy:sender]; + [self deleteBackwards:sender]; + } } - (void)paste:(id)sender { - var pasteboard = [CPPasteboard generalPasteboard]; - - if (![[pasteboard types] containsObject:CPStringPboardType]) - return; + if (![CPPlatform isBrowser]) + { + var pasteboard = [CPPasteboard generalPasteboard]; - [self deleteBackwards:sender]; + if (![[pasteboard types] containsObject:CPStringPboardType]) + return; - var selectedRange = [self selectedRange], - stringValue = [self stringValue], - pasteString = [pasteboard stringForType:CPStringPboardType], - newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString]; + [self deleteBackwards:sender]; - [self setStringValue:newValue]; - [self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)]; + var selectedRange = [self selectedRange], + stringValue = [self stringValue], + pasteString = [pasteboard stringForType:CPStringPboardType], + newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString]; + + [self setStringValue:newValue]; + [self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)]; + } } - (CPRange)selectedRange diff --git a/AppKit/CPViewAnimation.j b/AppKit/CPViewAnimation.j index 5950d9609..692523584 100644 --- a/AppKit/CPViewAnimation.j +++ b/AppKit/CPViewAnimation.j @@ -1,11 +1,25 @@ /* - * CPViewAnimation.j + * CPFlashView.j + * AppKit * * Created by Klaas Pieter Annema on September 3, 2009. * Copyright 2009, Sofa BV + * + * 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 */ - @import CPViewAnimationTargetKey = @"CPViewAnimationTarget"; @@ -18,167 +32,148 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut"; @implementation CPViewAnimation : CPAnimation { - CPArray _viewAnimations; + CPArray _viewAnimations; } - (id)initWithViewAnimations:(CPArray)viewAnimations { - if(self = [super initWithDuration:0.5 animationCurve:CPAnimationLinear]) - { - [self setViewAnimations:viewAnimations]; - } - return self; + if (self = [super initWithDuration:0.5 animationCurve:CPAnimationLinear]) + { + [self setViewAnimations:viewAnimations]; + } + + return self; } -// ============= -// = ANIMATION = -// ============= - (void)startAnimation { - var animationIndex = [_viewAnimations count]; - - while (animationIndex--) - { - var dictionary = [_viewAnimations objectAtIndex:animationIndex]; - - var view = [self _targetView:dictionary], - startFrame = [self _startFrame:dictionary]; - - [view setFrame:startFrame]; - - var effect = [self _effect:dictionary]; - - if (effect === CPViewAnimationFadeInEffect) - { - [view setAlphaValue:0.0]; - [view setHidden:NO]; - } - else if (effect === CPViewAnimationFadeOutEffect) - [view setAlphaValue:1.0]; - } - - [super startAnimation]; + var animationIndex = [_viewAnimations count]; + while (animationIndex--) + { + var dictionary = [_viewAnimations objectAtIndex:animationIndex], + view = [self _targetView:dictionary], + startFrame = [self _startFrame:dictionary]; + + [view setFrame:startFrame]; + + var effect = [self _effect:dictionary]; + if (effect === CPViewAnimationFadeInEffect) + { + [view setAlphaValue:0.0]; + [view setHidden:NO]; + } + else if (effect === CPViewAnimationFadeOutEffect) + [view setAlphaValue:1.0]; + } + + [super startAnimation]; } - (void)setCurrentProgress:(NSAnimationProgress)progress { - [super setCurrentProgress:progress]; - - var animationIndex = [_viewAnimations count]; - while (animationIndex--) - { - var dictionary = [_viewAnimations objectAtIndex:animationIndex]; - - // Update the view's frame - var view = [self _targetView:dictionary] - startFrame = [self _startFrame:dictionary] - endFrame = [self _endFrame:dictionary] - differenceFrame = CPRectMakeZero(); - - differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x; - differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y; - differenceFrame.size.width = endFrame.size.width - startFrame.size.width; - differenceFrame.size.height = endFrame.size.height - startFrame.size.height; - - var intermediateFrame = CPRectMakeZero(); - intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress; - intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress; - intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress; - intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * progress; - - [view setFrame:intermediateFrame]; - - // Update the view's alpha value - var effect = [self _effect:dictionary]; - - if (effect === CPViewAnimationFadeInEffect) - [view setAlphaValue:1.0 * progress]; - else if (effect === CPViewAnimationFadeOutEffect) - [view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress]; - - if (progress === 1.0) - [view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0]; - } + [super setCurrentProgress:progress]; + + var animationIndex = [_viewAnimations count]; + while (animationIndex--) + { + var dictionary = [_viewAnimations objectAtIndex:animationIndex], + view = [self _targetView:dictionary] + startFrame = [self _startFrame:dictionary] + endFrame = [self _endFrame:dictionary] + differenceFrame = CPRectMakeZero(); + + differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x; + differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y; + differenceFrame.size.width = endFrame.size.width - startFrame.size.width; + differenceFrame.size.height = endFrame.size.height - startFrame.size.height; + + var intermediateFrame = CPRectMakeZero(); + intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress; + intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress; + intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress; + intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * progress; + + [view setFrame:intermediateFrame]; + + // Update the view's alpha value + var effect = [self _effect:dictionary]; + if (effect === CPViewAnimationFadeInEffect) + [view setAlphaValue:1.0 * progress]; + else if (effect === CPViewAnimationFadeOutEffect) + [view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress]; + + if (progress === 1.0) + [view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0]; + } } - (void)stopAnimation { - var animationIndex = [_viewAnimations count]; - while (animationIndex--) - { - var dictionary = [_viewAnimations objectAtIndex:animationIndex]; - - var view = [self _targetView:dictionary], - endFrame = [self _endFrame:dictionary]; - - [view setFrame:endFrame]; - - var effect = [self _effect:dictionary]; - - if (effect === CPViewAnimationFadeInEffect) - [view setAlphaValue:1.0]; - else if (effect === CPViewAnimationFadeOutEffect) - [view setAlphaValue:0.0]; - - [view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0]; - } - - [super stopAnimation]; + var animationIndex = [_viewAnimations count]; + while (animationIndex--) + { + var dictionary = [_viewAnimations objectAtIndex:animationIndex], + view = [self _targetView:dictionary], + endFrame = [self _endFrame:dictionary]; + + [view setFrame:endFrame]; + + var effect = [self _effect:dictionary]; + if (effect === CPViewAnimationFadeInEffect) + [view setAlphaValue:1.0]; + else if (effect === CPViewAnimationFadeOutEffect) + [view setAlphaValue:0.0]; + + [view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0]; + } + + [super stopAnimation]; } -// =============== -// = CONVENIENCE = -// =============== - (id)_targetView:(CPDictionary)dictionary { - var targetView = [dictionary valueForKey:CPViewAnimationTargetKey]; - - if (!targetView) - [CPException raise:CPInternalInconsistencyException reason:[CPString stringWithFormat:@"view animation: %@ does not have a target view", [dictionary description]]]; - - return targetView; + var targetView = [dictionary valueForKey:CPViewAnimationTargetKey]; + if (!targetView) + [CPException raise:CPInternalInconsistencyException reason:[CPString stringWithFormat:@"view animation: %@ does not have a target view", [dictionary description]]]; + + return targetView; } - (CPRect)_startFrame:(CPDictionary)dictionary { - var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey]; - - if (!startFrame) - return [[self _targetView:dictionary] frame]; - - return startFrame; + var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey]; + if (!startFrame) + return [[self _targetView:dictionary] frame]; + + return startFrame; } - (CPRect)_endFrame:(CPDictionary)dictionary { - var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey]; - - if (!endFrame) - return [[self _targetView:dictionary] frame]; - - return endFrame; + var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey]; + if (!endFrame) + return [[self _targetView:dictionary] frame]; + + return endFrame; } - (CPString)_effect:(CPDictionary)dictionary { - return [dictionary valueForKey:CPViewAnimationEffectKey]; + return [dictionary valueForKey:CPViewAnimationEffectKey]; } -// ============= -// = ACCESSORS = -// ============= - (CPArray)viewAnimations { - return _viewAnimations; + return _viewAnimations; } - (void)setViewAnimations:(CPArray)viewAnimations { - if (viewAnimations != _viewAnimations) - { - [self stopAnimation]; - _viewAnimations = [viewAnimations copy]; - } + if (viewAnimations != _viewAnimations) + { + [self stopAnimation]; + _viewAnimations = [viewAnimations copy]; + } } @end diff --git a/AppKit/Platform/DOM/CPPlatform.j b/AppKit/Platform/DOM/CPPlatform.j index 535644ea2..47af4b175 100644 --- a/AppKit/Platform/DOM/CPPlatform.j +++ b/AppKit/Platform/DOM/CPPlatform.j @@ -44,7 +44,7 @@ var screenNeedsInitialization = NO, + (BOOL)supportsDragAndDrop { - return CPFeatureIsCompatible(CPHTMLDragAndDropFeature); + return CPFeatureIsCompatible(CPHTMLDragAndDropFeature) && ![self isBrowser]; } + (BOOL)supportsNativeMainMenu diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 152373698..5c73c69cc 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -462,9 +462,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _DOMWindow.cpSetShadowStyle(_shadowStyle); } - _DOMBodyElement.style.cursor = [[CPCursor currentCursor] _cssString]; - [self registerDOMWindow]; + + _DOMBodyElement.style.cursor = [[CPCursor currentCursor] _cssString]; } - (void)orderOut:(id)aSender diff --git a/AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted.png b/AppKit/Resources/tableview-headerview-highlighted.png similarity index 100% rename from AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted.png rename to AppKit/Resources/tableview-headerview-highlighted.png diff --git a/AppKit/Themes/Aristo/Resources/tableview-headerview.png b/AppKit/Resources/tableview-headerview.png similarity index 100% rename from AppKit/Themes/Aristo/Resources/tableview-headerview.png rename to AppKit/Resources/tableview-headerview.png diff --git a/Foundation/CPArray+KVO.j b/Foundation/CPArray+KVO.j index 1388f8a6e..4c56931a3 100644 --- a/Foundation/CPArray+KVO.j +++ b/Foundation/CPArray+KVO.j @@ -403,6 +403,9 @@ var kvoOperators = []; +// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior +var avgOperator, maxOperator, minOperator, countOperator, sumOperator; + kvoOperators["avg"] = function avgOperator(self, _cmd, param) { var objects = [self valueForKeyPath:param], diff --git a/Foundation/CPOperation.j b/Foundation/CPOperation.j index a4503f41a..e24617ae7 100644 --- a/Foundation/CPOperation.j +++ b/Foundation/CPOperation.j @@ -168,7 +168,7 @@ CPOperationQueuePriorityVeryHigh = 8; The JS function that should be run after the main method @return JS function */ -– (JSObject)completionFunction +- (JSObject)completionFunction { return _completionFunction; } @@ -290,4 +290,4 @@ CPOperationQueuePriorityVeryHigh = 8; } } -@end \ No newline at end of file +@end diff --git a/Jakefile b/Jakefile index 54161d8b7..1a53ee621 100644 --- a/Jakefile +++ b/Jakefile @@ -176,41 +176,55 @@ task("test-only", function() { var tests = new FileList('Tests/**/*Test.j'); var cmd = ["ojtest"].concat(tests.items()); - + var code = OS.system(cmd); if (code !== 0) OS.exit(code); }); -task("push-packages", ["CommonJS"], function() -{ +task("push-packages", ["CommonJS", "push-cappuccino", "push-objective-j"]); + +task("push-cappuccino", function() { pushPackage( - BUILD_CJS_CAPPUCCINO, + $BUILD_CJS_CAPPUCCINO, "git@github.com:280north/cappuccino-package.git" ); +}); + +task("push-objective-j", function() { pushPackage( - BUILD_CJS_OBJECTIVE_J, + $BUILD_CJS_OBJECTIVE_J, "git@github.com:280north/objective-j-package.git" ); }); function pushPackage(path, remote) { - // FIXME: this will probably fail next time... - var cmds = - [ - ["cd", path], - //["rm", "-rf", ".git*"], - ["git", "init"], + stream.print("Pushing \0blue(" + path + "\0) to \0blue(" + remote + "\0)"); + + FILE.mkdirs("push-package"); + + var pushPackageDir = FILE.join("push-package", remote.replace(/[^\w]/g, "_")); + + if (FILE.exists(pushPackageDir)) + OS.system(buildCommandString([["cd", pushPackageDir], ["git", "pull"]])); + else + OS.system(["git", "clone", remote, pushPackageDir]); + + OS.system("cd "+OS.enquote(pushPackageDir)+" && git rm --ignore-unmatch -r * && rm -rf *"); + OS.system("cp -R "+OS.enquote(path)+"/* "+OS.enquote(pushPackageDir)+"/."); + + OS.system(buildCommandString([ + ["cd", pushPackageDir], ["git", "add", "."], ["git", "commit", "-m", "Pushed on " + new Date()], - ["git", "remote", "add", "origin", remote], ["git", "push", "origin", "master"] - ]; - - var cmdString = cmds.map(function(cmd) { + ])); +} + +function buildCommandString(arrayOfCommands) +{ + return arrayOfCommands.map(function(cmd) { return cmd.map(OS.enquote).join(" "); }).join(" && "); - - OS.system(cmdString); } diff --git a/Objective-J/CommonJS/bin/cplutil b/Objective-J/CommonJS/bin/cplutil index 194095d2b..000e7d1be 100755 --- a/Objective-J/CommonJS/bin/cplutil +++ b/Objective-J/CommonJS/bin/cplutil @@ -1,79 +1,91 @@ #!/usr/bin/env narwhal var FILE = require("file"); +var SYSTEM = require("system"); +var OS = require("os"); +var OBJJ = require("objective-j"); +var parser = new (require("args").Parser)(); -function printUsage() -{ - print("this is where you say the usage"); -} +parser.usage("file..."); +parser.help("Cappuccino plist converter."); + +parser.option("-c", "--convert", "format") + .help("rewrite property list files in format") + .choices({ + "280north1" : OBJJ.kCFPropertyList280NorthFormat_v1_0, + "xml1": OBJJ.kCFPropertyListXMLFormat_v1_0 + }); + +parser.option("-l", "--lint", "lint") + .help("check the property list files for syntax errors") + .set(true); + +parser.option("-h", "--help") + .action(parser.printHelp); + +parser.option("-o", "outPath") + .help("specify alternate file path name for result;\n\ +the -o option is used with -convert, and is only\n\ +useful with one file argument (last file overwrites);\n\ +the path '-' means stdout.") + .set(); + +parser.option("-e", "outExtension") + .help("specify alternate extension for converted files") + .set(); + +parser.option("-s", "silent") + .help("be silent on success") + .set(true); exports.main = function(args) { - // TODO: args parser - args.shift(); + // HACK: add extra "-" to "-convert", etc, for plutil compatibility + var args = args.map(function(arg) { return arg.replace(/^(-[^-].+)$/, "-$1"); }); + var options = parser.parse(args); - if (args.length < 1) - return printUsage(); - - var allFiles = NO, - format = nil, - filePaths = [], - outPath = nil, - outExtension = nil; - - index = 0, - count = args.length; - - for (; index < count; ++index) + var ok = false; + + if (typeof options.format !== "undefined" || options.lint) { - var argument = args[index]; - - if (argument.charAt(0) === '-' && !allFiles) - { - if (filePaths.length > 0) - return printUsage(); - - else if (argument === "-convert") - format = args[++index]; - - else if (argument === "-o") - outPath = args[++index]; - - else if (argument === "-e") - outExtension = args[++index]; - - else if (argument === "--") - allFiles = YES; - - else if (argument === "-help") - return printUsage(); - } - else - filePaths.push(args[index]); + ok = true; + options.args.forEach(function(filePath) { + var data = new OBJJ.objj_data(); + data.string = FILE.read(filePath, { charset:"UTF-8" }); + + var plistObject = OBJJ.CPPropertyListCreateFromData(data); + if (!plistObject) + { + // FIXME: more useful error messages + SYSTEM.stderr.print(filePath + ": parse error"); + ok = false; + return; + } + + if (options.lint) + { + if (!options.silent) + SYSTEM.stderr.print(filePath + ": OK"); + } + else + { + data = OBJJ.CPPropertyListCreateData(plistObject, options.format); + + // outextension? + if (options.outPath === "-") + SYSTEM.stdout.write(data.string); + else + FILE.write(options.outPath || filePath, data.string, { charset:"UTF-8" }); + } + }); } - - index = 0; - count = filePaths.length; - - for (; index < count; ++index) + else { - var filePath = filePaths[index], - data = new objj_data(); - - data.string = FILE.read(filePaths[index], { charset:"UTF-8" }); - - var plistObject = new CPPropertyListCreateFromData(data); - - if (format === "280north1") - data = CPPropertyListCreate280NorthData(plistObject); - - else if (format === "xml1") - data = CPPropertyListCreateXMLData(plistObject); - - // outextension? - FILE.write(outPath || filePath, data.string, { charset:"UTF-8" }); + parser.printHelp(options); } + + OS.exit(ok ? 0 : 1); } if (require.main == module.id) diff --git a/Objective-J/CommonJS/lib/objective-j.js b/Objective-J/CommonJS/lib/objective-j.js index f0bf6b0a9..cc2fb248c 100644 --- a/Objective-J/CommonJS/lib/objective-j.js +++ b/Objective-J/CommonJS/lib/objective-j.js @@ -52,8 +52,8 @@ for (var name in catalog) } // push to the front of the array lowest priority first. -OBJJ_INCLUDE_PATHS.unshift.apply(OBJJ_INCLUDE_PATHS, exports.objj_debug_frameworks); OBJJ_INCLUDE_PATHS.unshift.apply(OBJJ_INCLUDE_PATHS, exports.objj_frameworks); +OBJJ_INCLUDE_PATHS.unshift.apply(OBJJ_INCLUDE_PATHS, exports.objj_debug_frameworks); if (system.env["OBJJ_INCLUDE_PATHS"]) OBJJ_INCLUDE_PATHS.unshift.apply(OBJJ_INCLUDE_PATHS, system.env["OBJJ_INCLUDE_PATHS"].split(":")); @@ -112,6 +112,13 @@ exports.run = function(args) { if (args && args.length > 1) { + // we expect args to be in the format: + // 1) "objj" path + // 2) optional "-I" args + // 3) real or "virtual" main.j + // 4) optional program arguments + + // copy the args since we're going to modify them var argv = args.slice(1); while (argv.length && argv[0].indexOf('-I') === 0) diff --git a/Objective-J/CommonJS/objj-executable b/Objective-J/CommonJS/objj-executable index 36a954d58..919302c11 100755 --- a/Objective-J/CommonJS/objj-executable +++ b/Objective-J/CommonJS/objj-executable @@ -1,15 +1,7 @@ #!/usr/bin/env narwhal -var FILE = require("file"); +var execPath = require("file").path(module.path); +var mainPath = execPath.dirname().dirname().join("lib", execPath.basename(), "main.j"); -var cappuccinoPackage = FILE.path(module.path).dirname().dirname(); -var mainPath = cappuccinoPackage.join("lib", FILE.basename(module.path), "main.j"); -var frameworksPath = cappuccinoPackage.join("Frameworks"); - -// TODO: is specifying the Frameworks necessary? -system.args.splice(1, 0, "-I"+frameworksPath, String(mainPath)); - -// HACK: remove use of SELF_HOME from capp gen -system.env["SELF_HOME"] = cappuccinoPackage; - -require("objective-j").run(system.args); +var args = ["objj", String(mainPath)].concat(system.args.slice(1)); +require("objective-j").run(args); diff --git a/Tests/Manual/TableTest/AppController.j b/Tests/Manual/TableTest/AppController.j index e4f58c534..f9fbb76bd 100644 --- a/Tests/Manual/TableTest/AppController.j +++ b/Tests/Manual/TableTest/AppController.j @@ -87,7 +87,7 @@ CPLogRegister(CPLogConsole); [tableView setColumnAutoresizingStyle:CPTableViewUniformColumnAutoresizingStyle]; - var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(100, 100, CGRectGetWidth([view bounds]), CGRectGetHeight([view bounds]))]; + var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([view bounds]), CGRectGetHeight([view bounds]))]; [tableView setRowHeight:22.0]; [scrollView setDocumentView:tableView]; [scrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; diff --git a/Tools/capp/Generate.j b/Tools/capp/Generate.j index ba10684f7..5e3e7b8e1 100644 --- a/Tools/capp/Generate.j +++ b/Tools/capp/Generate.j @@ -6,6 +6,8 @@ var OS = require("os"), FILE = require("file"), OBJJ = require("objective-j"); +// FIXME: better way to do this: +var CAPP_HOME = require("packages").catalog["cappuccino"].directory; function gen(/*va_args*/) { @@ -56,7 +58,7 @@ function gen(/*va_args*/) if (FILE.isAbsolute(template)) sourceTemplate = FILE.join(template); else - sourceTemplate = FILE.join(SYSTEM.env["SELF_HOME"], "lib", "capp", "Resources", "Templates", template); + sourceTemplate = FILE.join(CAPP_HOME, "lib", "capp", "Resources", "Templates", template); var configFile = FILE.join(sourceTemplate, "template.config"), config = {}; diff --git a/Tools/press/cib-analysis-tools.j b/Tools/press/cib-analysis-tools.j new file mode 100644 index 000000000..cab6a919a --- /dev/null +++ b/Tools/press/cib-analysis-tools.j @@ -0,0 +1,74 @@ +@import +@import + +function findCibClassDependencies(cibPath) { + var cib = [[CPCib alloc] initWithContentsOfURL:cibPath]; + + var dependencies = {}; + + var CPClassFromStringOriginal = CPClassFromString; + CPClassFromString = function(aClassName) { + var result = CPClassFromStringOriginal(aClassName); + + // print("CPClassFromString: " + Array.prototype.slice.call(arguments) + " => " + result); + dependencies[aClassName] = true; + + return result; + } + + // make sure CPApp is init'd + [CPApplication sharedApplication] + + try { + var x = [cib pressInstantiate]; + } catch (e) { + CPLog.warn("Exception thrown when instantiating " + cibPath + ": " + e); + } finally { + CPClassFromString = CPClassFromStringOriginal; + } + + return Object.keys(dependencies); +} +// this is copied from CPCib's "instantiateCibWithExternalNameTable:" +@implementation CPCib (Press) + +- (BOOL)pressInstantiate +{ + var bundle = _bundle, + owner = nil;//[anExternalNameTable objectForKey:CPCibOwner]; + + if (!bundle && owner) + bundle = [CPBundle bundleForClass:[owner class]]; + + var unarchiver = [[_CPCibKeyedUnarchiver alloc] initForReadingWithData:_data bundle:bundle awakenCustomResources:_awakenCustomResources], + replacementClasses = nil;//[anExternalNameTable objectForKey:CPCibReplacementClasses]; + + if (replacementClasses) + { + var key = nil, + keyEnumerator = [replacementClasses keyEnumerator]; + + while (key = [keyEnumerator nextObject]) + [unarchiver setClass:[replacementClasses objectForKey:key] forClassName:key]; + } + + [unarchiver setExternalObjectsForProxyIdentifiers:nil/*[anExternalNameTable objectForKey:CPCibExternalObjects]*/]; + + var objectData = [unarchiver decodeObjectForKey:"CPCibObjectDataKey"]; + + if (!objectData || ![objectData isKindOfClass:[_CPCibObjectData class]]) + return NO; + + var topLevelObjects = nil;//[anExternalNameTable objectForKey:CPCibTopLevelObjects]; + + [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects] + // [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects]; + // [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects]; + + // Display Visible Windows. + // [objectData displayVisibleWindows]; + + return YES; +} + +@end diff --git a/Tools/press/cib-dump b/Tools/press/cib-dump new file mode 100755 index 000000000..87fff35a5 --- /dev/null +++ b/Tools/press/cib-dump @@ -0,0 +1,18 @@ +#!/usr/bin/env objj + +@import +@import "cib-analysis-tools.j" + +var FILE = require("file"); + +CPLogRegister(CPLogPrint); + +function main(args) +{ + args.slice(1).forEach(function(path) { + var classes = findCibClassDependencies(FILE.absolute(path)); + + print(path+":"); + classes.sort().forEach(function(className) { print(" + " + className) }); + }); +} diff --git a/Tools/press/main.j b/Tools/press/main.j index f92270a50..f8f497823 100644 --- a/Tools/press/main.j +++ b/Tools/press/main.j @@ -1,18 +1,16 @@ -var OS = require("os"); -if (system.engine !== "rhino") { - system.args.splice(1,2); // remove library path and main.j - var cmd = "NARWHAL_ENGINE_HOME='' NARWHAL_ENGINE='rhino' " + system.args.map(OS.enquote).join(" "); - OS.exit(OS.system(cmd)); -} +require("narwhal").ensureEngine("rhino"); @import +@import @import "objj-analysis-tools.j" +@import "cib-analysis-tools.j" var ARGS = require("args"); var FILE = require("file"); var OS = require("os"); var DOM = require("browser/dom"); +var UTIL = require("util"); var INTERPRETER = require("interpreter"); var serializer = new DOM.XMLSerializer(); @@ -52,7 +50,7 @@ parser.option("-n", "--nostrip", "strip") .set(false) .help("Do not strip any files"); -parser.option("-p", "--pngcrush", "png") +parser.option("-p", "--pngcrush", "png") .def(false) .set(true) .help("Run pngcrush on all PNGs (pngcrush must be installed!)"); @@ -67,12 +65,12 @@ parser.helpful(); function main(args) { var options = parser.parse(args); - + if (options.args.length < 2) { parser.printUsage(options); return; } - + //if (options.verbose) CPLogRegister(CPLogPrint); //else @@ -98,63 +96,67 @@ function press(rootPath, outputPath, options) { CPLog.info("==========================================="); CPLog.info("Application root: " + rootPath); CPLog.info("Output directory: " + outputPath); - + var outputFiles = {}; - + // analyze and gather files for each environment: options.environments.forEach(function(environment) { pressEnvironment(rootPath, outputFiles, environment, options); }); - + // phase 4: copy everything and write out the new files CPLog.error("PHASE 4: copy to output ("+rootPath+" to "+outputPath+")"); - + FILE.copyTree(rootPath, outputPath); - + for (var path in outputFiles) { var file = outputPath.join(rootPath.relative(path)); - + var parent = file.dirname(); if (!parent.exists()) { CPLog.warn(parent + " doesn't exist, creating directories."); parent.mkdirs(); } - + if (typeof outputFiles[path] !== "string") outputFiles[path] = outputFiles[path].join(""); - + CPLog.info((file.exists() ? "Overwriting: " : "Writing: ") + file); FILE.write(file, outputFiles[path], { charset : "UTF-8" }); } - + // strip known unnecessary files // outputPath.glob("**/Frameworks/Debug").forEach(function(debugFramework) { // outputPath.join(debugFramework).rmtree(); // }); // outputPath.join("index-debug.html").remove(); - + if (options.png) { pngcrushDirectory(outputPath); } } function pressEnvironment(rootPath, outputFiles, environment, options) { - + var mainPath = String(rootPath.join(options.main)); var frameworks = options.frameworks.map(function(framework) { return rootPath.join(framework); }); - + CPLog.info("==========================================="); CPLog.info("Main file: " + mainPath) CPLog.info("Frameworks: " + frameworks); CPLog.info("Environment: " + environment); - + // get a Rhino context var context = new INTERPRETER.Context(); var scope = setupObjectiveJ(context); - + scope.OBJJ_INCLUDE_PATHS = frameworks; scope.OBJJ_ENVIRONMENTS = [environment, "ObjJ"]; - + + // build list of cibs to inspect for dependent classes + // FIXME: what's the best way to determine which cibs to look in? + var cibs = FILE.glob(rootPath.join("**", "*.cib")).filter(function(path) { return !(/Frameworks/).test(path); }); + // flattening bookkeeping. keep track of the bundles and evaled code (in the correct order!) var bundleArchiveResponses = []; var exectuableResponses = []; @@ -166,42 +168,42 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { success : aResponse.success, filePath : rootPath.relative(aResponse.filePath).toString() }; - + if (aResponse.success) { var xmlString = serializer.serializeToString(aResponse.xml); response.text = CPPropertyListCreate280NorthData(CPPropertyListCreateFromXMLData({ string: xmlString })).string; } - + bundleArchiveResponses.push(response); }); - + functionHookBefore(scope.objj_search.prototype, "didReceiveExecutableResponse", function(aResponse) { exectuableResponses.push(aResponse); }); - + // lets just use the Context object as our con context.rootPath = rootPath; context.scope = scope; - + // phase 1: get global defines CPLog.error("PHASE 1: Loading application..."); - + var globals = findGlobalDefines(context, mainPath, evaledFragments); - + // coalesce the results var dependencies = coalesceGlobalDefines(globals); - - // Log + + // log identifer => files defining CPLog.trace("Global defines:"); Object.keys(dependencies).sort().forEach(function(identifier) { CPLog.trace(" " + identifier + " => " + rootPath.relative(dependencies[identifier])); }); - + // 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..."); - + var requiredFiles = {}; - + if (options.nostrip) { // all files are required. no need for analysis @@ -214,18 +216,31 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { CPLog.error("Root file not loaded!"); return; } - + CPLog.warn("Analyzing dependencies..."); - + context.dependencies = dependencies; context.ignoreFrameworkImports = true; // ignores "XXX/XXX.j" imports context.importCallback = function(importing, imported) { requiredFiles[imported] = true; }; context.referenceCallback = function(referencing, referenced) { requiredFiles[referenced] = true; } - + requiredFiles[mainPath] = true; - + + // check the code traverseDependencies(context, scope.objj_files[mainPath]); - + + // check the cibs + cibs.forEach(function(cibPath) { + var cibClasses = findCibClassDependencies(cibPath); + CPLog.debug(cibPath + " => " + cibClasses); + + var referencedFiles = {}; + markFilesReferencedByTokens(cibClasses, context.dependencies, referencedFiles); + checkReferenced(context, null, referencedFiles); + + print(UTIL.repr(referencedFiles)); + }); + var count = 0, total = 0; for (var path in scope.objj_files) @@ -233,7 +248,7 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { // mark all ".keytheme"s as required if (/\.keyedtheme$/.test(path)) requiredFiles[path] = true; - + if (requiredFiles[path]) { CPLog.debug("Included: " + rootPath.relative(path)); @@ -242,30 +257,20 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { else { CPLog.info("Excluded: " + rootPath.relative(path)); - } + } 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.debug("Bundle images for " + i); - // for (var j in images) - // CPLog.trace(j + " = " + images[j]); - //} } - + if (options.flatten) { // phase 3a: build single Application.js file (and modified index.html) CPLog.error("PHASE 3a: Flattening..."); - + var applicationScriptName = "Application-"+environment+".js"; var indexHTMLName = "index-"+environment+".html"; - + // Shim for faking bundle responses. // We're just defining it here so we can serialize the function. It's not used within press. // ************************************************** @@ -303,9 +308,9 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { } } // ************************************************** - + var applicationScript = []; - + var URIMaps = {}; Object.keys(scope.objj_bundles).forEach(function(bundleName) { var bundle = scope.objj_bundles[bundleName]; @@ -332,7 +337,7 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { applicationScript.push(" var URIMaps = " + JSON.stringify(URIMaps) + ";"); applicationScript.push(" setupURIMaps(URIMaps);"); applicationScript.push("})();"); - + // add each fragment, wrapped in a function, along with OBJJ_CURRENT_BUNDLE bookkeeping evaledFragments.forEach(function(fragment) { if (requiredFiles[fragment.file.path]) @@ -346,13 +351,13 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { CPLog.info("Stripping " + rootPath.relative(fragment.file.path)); } }); - + // call main once the page has loaded. FIXME: assumes synchronous script loading? applicationScript.push("if (window.addEventListener)"); applicationScript.push(" window.addEventListener('load', main, false);") applicationScript.push("else if (window.attachEvent)") applicationScript.push(" window.attachEvent('onload', main);"); - + // MHTML // TODO: combine multiple MHTMLs exectuableResponses.forEach(function(aResponse) { @@ -362,15 +367,15 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { applicationScript.push(aResponse.text.slice(mhtmlStart, mhtmlEnd+2)); } }); - + var indexHTML = FILE.read(FILE.join(rootPath, "index.html"), { charset : "UTF-8" }); - + // comment out any OBJJ_MAIN_FILE defintions or objj_import() calls indexHTML = indexHTML.replace(/(\bOBJJ_MAIN_FILE\s*=|\bobjj_import\s*\()/g, '//$&'); - + // add a script tag for Application.js at the very end of the block indexHTML = indexHTML.replace(/([ \t]*)(<\/head>)/, '$1 \n$1$2'); - + // output Application.js and index.html outputFiles[rootPath.join(applicationScriptName)] = applicationScript.join("\n"); outputFiles[rootPath.join(indexHTMLName)] = indexHTML; @@ -423,7 +428,7 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { outputFiles[staticPath].push("p;"); outputFiles[staticPath].push(filename.length+";"); outputFiles[staticPath].push(filename); - + for (var i = 0; i < file.fragments.length; i++) { if (file.fragments[i].type & FRAGMENT_CODE) @@ -443,13 +448,13 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { ignoreFragment = true; } } - + if (!ignoreFragment) { if (file.fragments[i].type & FRAGMENT_LOCAL) { var relativePath = pathRelativeTo(file.fragments[i].info, directory) - + outputFiles[staticPath].push("i;"); outputFiles[staticPath].push(relativePath.length+";"); outputFiles[staticPath].push(relativePath); @@ -480,20 +485,20 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { // phase 3.5: fix bundle plists CPLog.error("PHASE 3.5: fix bundle plists"); - + for (var path in bundles) { var directory = FILE.dirname(path), dict = bundles[path].info, replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"]; - + CPLog.info("Modifying .sj: " + rootPath.relative(path)); - + if (replacedFiles) { var newReplacedFiles = []; [dict setObject:newReplacedFiles forKey:"CPBundleReplacedFiles"]; - + for (var i = 0; i < replacedFiles.length; i++) { var replacedFilePath = directory + "/" + replacedFiles[i] @@ -516,12 +521,12 @@ function pressEnvironment(rootPath, outputFiles, environment, options) { function pngcrushDirectory(directory) { var directoryPath = FILE.path(directory); var pngs = directoryPath.glob("**/*.png"); - + system.stderr.print("Running pngcrush on " + pngs.length + " pngs:"); pngs.forEach(function(dst) { var dstPath = directoryPath.join(dst); var tmpPath = FILE.path(dstPath+".tmp"); - + var p = OS.popen(["pngcrush", "-rem", "alla", "-reduce", /*"-brute",*/ dstPath, tmpPath]); if (p.wait()) { CPLog.warn("pngcrush failed. Ensure it's installed and on your PATH."); diff --git a/Tools/press/objj-analysis-tools.j b/Tools/press/objj-analysis-tools.j index 344148bc8..c45a7601b 100644 --- a/Tools/press/objj-analysis-tools.j +++ b/Tools/press/objj-analysis-tools.j @@ -48,28 +48,6 @@ function traverseDependencies(context, file) file.fragments = objj_preprocess(file.contents, file.bundle, file); } - // sprite: look for pngs in the Resources directory - if (!context.bundleImages) - context.bundleImages = {}; - - if (!context.bundleImages[file.bundle.path]) - { - var resourcesPath = FILE.path(file.bundle.path).dirname().join("/Resources"); - if (resourcesPath.exists()) - { - context.bundleImages[file.bundle.path] = {}; - - resourcesPath.glob("**/*.png").forEach(function(png) { - var pngPath = resourcesPath.join(png); - var relativePath = pathRelativeTo(pngPath.absolute(), resourcesPath.absolute()); - - // this is used as a bit mask, not a boolean - context.bundleImages[file.bundle.path][relativePath] = 1; - }); - } - } - var images = context.bundleImages[file.bundle.path]; - var referencedFiles = {}, importedFiles = {}; @@ -80,31 +58,9 @@ function traverseDependencies(context, file) if (fragment.type & FRAGMENT_CODE) { - var lexer = new objj_lexer(fragment.info, NULL); - - var token; - while (token = lexer.skip_whitespace()) - { - if (context.dependencies.hasOwnProperty(token)) - { - var files = context.dependencies[token]; - for (var j = 0; j < files.length; j++) - { - // don't record references to self - if (files[j] != file.path) - { - if (!referencedFiles[files[j]]) - referencedFiles[files[j]] = {}; - - referencedFiles[files[j]][token] = true; - } - } - } - - var matches = token.match(new RegExp("^['\"](.*)['\"]$")); - if (matches && images && images[matches[1]]) - images[matches[1]] = (images[matches[1]] | 2); - } + var referencedTokens = uniqueTokens(fragment.info); + + markFilesReferencedByTokens(referencedTokens, context.dependencies, referencedFiles); } else if (fragment.type & FRAGMENT_FILE) { @@ -130,12 +86,25 @@ function traverseDependencies(context, file) } // check each imported file + checkImported(context, file.path, importedFiles); + + if (context.importedFiles) + context.importedFiles[file.path] = importedFiles; + + // check each referenced file + checkReferenced(context, file.path, referencedFiles); + + if (context.referencedFiles) + context.referencedFiles[file.path] = referencedFiles; +} + +function checkImported(context, path, importedFiles) { for (var importedFile in importedFiles) { - if (importedFile != file.path) + if (importedFile != path) { if (context.importCallback) - context.importCallback(file.path, importedFile); + context.importCallback(path, importedFile); if (context.scope.objj_files[importedFile]) traverseDependencies(context, context.scope.objj_files[importedFile]); @@ -143,17 +112,15 @@ function traverseDependencies(context, file) CPLog.error("Missing imported file: " + importedFile); } } +} - if (context.importedFiles) - context.importedFiles[file.path] = importedFiles; - - // check each referenced file +function checkReferenced(context, path, referencedFiles) { for (var referencedFile in referencedFiles) { - if (referencedFile != file.path) + if (referencedFile != path) { if (context.referenceCallback) - context.referenceCallback(file.path, referencedFile, referencedFiles[referencedFile]); + context.referenceCallback(path, referencedFile, referencedFiles[referencedFile]); if (context.scope.objj_files.hasOwnProperty(referencedFile)) traverseDependencies(context, context.scope.objj_files[referencedFile]); @@ -161,9 +128,46 @@ function traverseDependencies(context, file) CPLog.error("Missing referenced file: " + referencedFile); } } +} - if (context.referencedFiles) - context.referencedFiles[file.path] = referencedFiles; +// returns a unique list of tokens for a piece of code. +// ideally this should return identifiers only +function uniqueTokens(code) { + // FIXME: this breaks for indentifiers containing "$" since it's considered a distinct token by the parser + var lexer = new objj_lexer(code, null); + + var token, tokens = {}; + while (token = lexer.skip_whitespace()) { + tokens[token] = true; + } + + return Object.keys(tokens); +} + +/* + params: + tokens (in): list of tokens to mark as required + tokenDependenciesMap (in): map from tokens to files which define those tokens + referencedFiles (out): map of required files (to map of tokens defined in that file) +*/ +function markFilesReferencedByTokens(tokens, tokenDependenciesMap, referencedFiles) { + tokens.forEach(function(token) { + if (tokenDependenciesMap.hasOwnProperty(token)) + { + var files = tokenDependenciesMap[token]; + for (var j = 0; j < files.length; j++) + { + // don't record references to self + if (files[j] != file.path) + { + if (!referencedFiles[files[j]]) + referencedFiles[files[j]] = {}; + + referencedFiles[files[j]][token] = true; + } + } + } + }); } function findImportInObjjFiles(scope, fragment) @@ -272,9 +276,9 @@ function findGlobalDefines(context, mainPath, evaledFragments, bundleCallback) bundlePaths = bundlePaths || []; // load default theme bundle - var themePath = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName]]; - var themeBundle = [[CPBundle alloc] initWithPath:themePath + "/Info.plist"]; - [themeBundle loadWithDelegate:bundleDelegate]; + // var themePath = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName]]; + // var themeBundle = [[CPBundle alloc] initWithPath:themePath + "/Info.plist"]; + // [themeBundle loadWithDelegate:bundleDelegate]; // load additional bundles bundlePaths.forEach(function(bundlePath) { diff --git a/bootstrap.sh b/bootstrap.sh index df2c06bb9..8d03401f5 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -24,7 +24,8 @@ function ask_remove_dir () { if [ -d "$dir" ]; then echo "================================================================================" echo "Found an existing Narwhal/Cappuccino installation, $dir. Remove it automatically now?" - echo "WARNING: custom modifications and installed packages in this installation WILL BE DELETED." + echo "WARNING: the ENTIRE directory, $dir, will be removed (i.e. 'rm -rf $dir')." + echo "Be sure this is correct. Custom modifications and installed packages WILL BE DELETED." if prompt; then rm -rf "$dir" fi @@ -33,7 +34,7 @@ function ask_remove_dir () { function ask_append_shell_config () { config_string="$1" - + shell_config_file="" # use order outlined by http://hayne.net/MacDev/Notes/unixFAQ.html#shellStartup if [ -f "$HOME/.bash_profile" ]; then @@ -60,6 +61,13 @@ function ask_append_shell_config () { return 1 } +function check_and_exit () { + if [ ! "$?" = "0" ]; then + echo "Error: problem running boostrap.sh. Exiting." + exit 1 + fi +} + if [ "--clone" = "$1" ]; then tusk_install_command="clone" git_clone=1 @@ -72,6 +80,8 @@ github_path=$(echo "$github_project" | tr '-' '/') install_directory="/usr/local/narwhal" tmp_zip="/tmp/narwhal.zip" +unset NARWHAL_ENGINE + PATH_SAVED="$PATH" ask_remove_dir "/usr/local/share/objj" @@ -109,22 +119,37 @@ if [ "$install_narwhal" ]; then install_directory="`cd \`dirname $input\`; pwd`/`basename $input`" fi + if [ -d "$install_directory" ]; then + echo "================================================================================" + echo "Directory exists at $install_directory. Delete it?" + if prompt; then + rm -rf "$install_directory" + fi + fi + if [ "$git_clone" ]; then git_repo="git://github.com/$github_path.git" echo "Cloning Narwhal from \"$git_repo\"..." git clone "$git_repo" "$install_directory" else zip_ball="http://github.com/$github_path/zipball/master" + echo "Downloading Narwhal from \"$zip_ball\"..." curl -L -o "$tmp_zip" "$zip_ball" + check_and_exit + echo "Installing Narwhal..." unzip "$tmp_zip" -d "$install_directory" + check_and_exit rm "$tmp_zip" + check_and_exit - mv $install_directory/$github_project-*/* $install_directory/. - rm -rf $install_directory/$github_project-* + mv "$install_directory/$github_project-"*/* "$install_directory/." + check_and_exit + rm -rf "$install_directory/$github_project-"* + check_and_exit fi - + export PATH="$install_directory/bin:$PATH" fi @@ -141,6 +166,14 @@ if ! prompt; then exit 1 fi +echo "================================================================================" +echo "Would you like to install the pre-built Objective-J and Cappuccino packages?" +echo "If you intend to build Cappuccino yourself this is not neccessary." +extra_packages="" +if prompt; then + extra_packages="objective-j cappuccino" +fi + echo "Installing necessary packages..." if ! tusk update; then @@ -148,7 +181,7 @@ if ! tusk update; then exit 1 fi -tusk $tusk_install_command browserjs jake +tusk $tusk_install_command browserjs jake $extra_packages if [ `uname` = "Darwin" ]; then echo "================================================================================" @@ -156,7 +189,7 @@ if [ `uname` = "Darwin" ]; then echo "This is optional but will make building and running Objective-J much faster." if prompt; then tusk $tusk_install_command narwhal-jsc - + if ! (cd "$install_directory/packages/narwhal-jsc" && make webkit); then echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo "WARNING: building narwhal-jsc failed. Hit enter to continue." @@ -175,9 +208,9 @@ export PATH="$PATH_SAVED" if ! which "narwhal" > /dev/null; then echo "================================================================================" echo "You must add Narwhal's \"bin\" directory to your PATH environment variable. Do this automatically now?" - + export_path_string="export PATH=\"$install_directory/bin:\$PATH\"" - + if ! ask_append_shell_config "$export_path_string"; then echo "Add \"$install_directory/bin\" to your PATH environment variable in your shell configuration file (e.x. .profile, .bashrc, .bash_profile)." echo "For example:" @@ -193,11 +226,12 @@ if [ "$CAPP_BUILD" ]; then rm -rf "$CAPP_BUILD" fi fi -else +else echo "================================================================================" echo "Before building Cappuccino we recommend you set the \$CAPP_BUILD environment variable to a path where you wish to build Cappuccino." - echo "If you have previously set \$CAPP_BUILD and built Cappuccino you may want to delete the directory before rebuilding." + echo "NOTE: If you have previously set \$CAPP_BUILD and built Cappuccino you may want to delete the directory before rebuilding." fi echo "================================================================================" -echo "Bootstrapping of Narwhal and other required tools is complete. You can now build Cappuccino." +echo "Bootstrapping of Narwhal and other required tools is complete." +echo "NOTE: any changes made to the shell configuration files won't take place until you restart the shell."