diff --git a/AppKit/AppKit.j b/AppKit/AppKit.j index 9c820be65..95bbe6201 100644 --- a/AppKit/AppKit.j +++ b/AppKit/AppKit.j @@ -88,3 +88,4 @@ @import "CPWebView.j" @import "CPWindow.j" @import "CPWindowController.j" +@import "CPArrayController.j" diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index fed04b4b1..a799b296d 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -154,7 +154,7 @@ value = [value]; var oldSelection = nil, - oldSelectionIndexes = [[self selectionIndexes] copy]; + oldSelectionIndexes = [self selectionIndexes]; if ([self preservesSelection]) oldSelection = [self selectedObjects]; diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 3bc21844b..c2f212644 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -574,7 +574,7 @@ CPButtonStateMixed = CPThemeState("mixed"); if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter) [[self window] setDefaultButton:self]; else if ([[self window] defaultButton] === self) - [[self window] setDefaultButton:NO]; + [[self window] setDefaultButton:nil]; _keyEquivalent = aString || @""; } diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 7de6719c4..db8a22cd9 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -545,6 +545,7 @@ var CPControlBlackColor = [CPColor blackColor]; return; [self _reverseSetBinding]; + [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; } diff --git a/AppKit/CPMenuItem/CPMenuItem.j b/AppKit/CPMenuItem/CPMenuItem.j index fb352ed69..1e14e2f17 100644 --- a/AppKit/CPMenuItem/CPMenuItem.j +++ b/AppKit/CPMenuItem/CPMenuItem.j @@ -591,7 +591,8 @@ CPControlKeyMask return @""; var string = _keyEquivalent.toUpperCase(), - needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent; + needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || + (string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase()); if (CPBrowserIsOperatingSystem(CPMacOperatingSystem)) { diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index 91edc5d50..59b44e97e 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -78,18 +78,7 @@ CPTableColumnUserResizingMask = 1 << 1; var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()]; [self setHeaderView:header]; - var textDataView = [CPTextField new]; - - [textDataView setValue:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0] - forThemeAttribute:"text-color"]; - - [textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateSelectedDataView]; - [textDataView setLineBreakMode:CPLineBreakByTruncatingTail]; - [textDataView setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateSelectedDataView]; - [textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"]; - [textDataView setValue:CGInsetMake(0.0, 0.0, 0.0, 5.0) forThemeAttribute:@"content-inset"]; - - [self setDataView:textDataView]; + [self setDataView:[CPTextField new]]; } return self; @@ -259,6 +248,8 @@ CPTableColumnUserResizingMask = 1 << 1; if (_dataView) _dataViewData[[_dataView UID]] = nil; + [aView setThemeState:CPThemeStateTableDataView]; + _dataView = aView; _dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView]; } diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index 76f71f426..be8d64798 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -23,53 +23,60 @@ @import "CPTableColumn.j" @import "CPTableView.j" @import "CPView.j" + +#include "CoreGraphics/CGGeometry.h" @implementation _CPTableColumnHeaderView : CPView { _CPImageAndTextView _textField; } ++ (CPString)themeClass +{ + return @"columnHeader"; +} + ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()] + forKeys:[@"background-color", @"text-alignment", @"text-inset", @"text-color", @"text-font", @"text-shadow-color", @"text-shadow-offset"]]; +} + - (void)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) - { [self _init]; - } return self; } - (void)_init { - _textField = [[_CPImageAndTextView alloc] initWithFrame: - CGRectMake(5.0, 0.0, CGRectGetWidth([self bounds]) - 10.0, CGRectGetHeight([self bounds]))]; - + _textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()]; + [_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_textField setLineBreakMode:CPLineBreakByTruncatingTail]; - [_textField setTextColor:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0]]; - [_textField setFont:[CPFont boldSystemFontOfSize:12.0]]; [_textField setAlignment:CPLeftTextAlignment]; [_textField setVerticalAlignment:CPCenterVerticalTextAlignment]; - [_textField setTextShadowColor:[CPColor whiteColor]]; - [_textField setTextShadowOffset:CGSizeMake(0,1)]; [self addSubview:_textField]; } - (void)layoutSubviews { - var themeState = [self themeState]; + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; - if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted) - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 23.0))]]; - else if (themeState & CPThemeStateSelected) - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 23.0))]]; - else if (themeState & CPThemeStateHighlighted) - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 23.0))]]; - else - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]]; + var inset = [self currentValueForThemeAttribute:@"text-inset"], + bounds = [self bounds]; + + [_textField setFrame:CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)]; + [_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]]; + [_textField setFont:[self currentValueForThemeAttribute:@"text-font"]]; + [_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]]; + [_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]]; + [_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]]; } - (void)setStringValue:(CPString)string @@ -97,11 +104,6 @@ [_textField setFont:aFont]; } -- (void)setValue:(id)aValue forThemeAttribute:(id)aKey -{ - [_textField setValue:aValue forThemeAttribute:aKey]; -} - - (void)_setIndicatorImage:(CPImage)anImage { if (anImage) @@ -157,12 +159,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal BOOL _isResizing; BOOL _isDragging; BOOL _isTrackingColumn; + BOOL _drawsColumnLines; float _columnOldWidth; CPTableView _tableView @accessors(property=tableView); } ++ (CPString)themeClass +{ + return @"tableHeaderRow"; +} + ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObjects:[[CPNull null]] + forKeys:[@"background-color"]]; +} + - (void)_init { _mouseDownLocation = CPPointMakeZero(); @@ -176,7 +190,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal _columnOldWidth = 0.0; - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]]; + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; } - (id)initWithFrame:(CGRect)aFrame @@ -205,6 +219,16 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal return headerRect; } +- (void)setDrawsColumnLines:(BOOL)aFlag +{ + _drawsColumnLines = aFlag; +} + +- (BOOL)drawsColumnLines +{ + return _drawsColumnLines; +} + - (CGRect)_cursorRectForColumn:(int)column { if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask)) @@ -581,11 +605,13 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal if([headerView superview] != self) [self addSubview:headerView]; } + + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; } - (void)drawRect:(CGRect)aRect { - if (!_tableView) + if (!_tableView || ![self drawsColumnLines]) return; var context = [[CPGraphicsContext currentContext] graphicsPort], diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 465fe7f84..24c961792 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -165,6 +165,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; BOOL _allowsEmptySelection; CPArray _sortDescriptors; + //Setting Display Attributes CGSize _intercellSpacing; float _rowHeight; @@ -174,9 +175,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; unsigned _selectionHighlightStyle; CPTableColumn _currentHighlightedTableColumn; - CPColor _selectionHighlightColor; unsigned _gridStyleMask; - CPColor _gridColor; unsigned _numberOfRows; @@ -215,11 +214,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing); BOOL _lastColumnShouldSnap; - CPGradient _sourceListActiveGradient; - CPColor _sourceListActiveTopLineColor; - CPColor _sourceListActiveBottomLineColor; - int _draggedColumnIndex; + CPArray _differedColumnDataToRemove; /* CPGradient _sourceListInactiveGradient; @@ -228,6 +224,17 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ } ++ (CPString)themeClass +{ + return @"tableview"; +} + ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null]] + forKeys:["alternating-row-colors", "grid-color", "highlighted-grid-color", "selection-color", "sourcelist-selection-color", "sort-image", "sort-image-reversed"]]; +} + - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; @@ -340,6 +347,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _sourceListInactiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [168.0/255.0,183.0/255.0,205.0/255.0,1.0,157.0/255.0,174.0/255.0,199.0/255.0,1.0], [0,1], 2); _sourceListInactiveTopLineColor = [CPColor colorWithCalibratedRed:(173.0/255.0) green:(187.0/255.0) blue:(209.0/255.0) alpha:1.0]; _sourceListInactiveBottomLineColor = [CPColor colorWithCalibratedRed:(150.0/255.0) green:(161.0/255.0) blue:(183.0/255.0) alpha:1.0];*/ + _differedColumnDataToRemove = [ ]; } /*! @@ -586,17 +594,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (void)setAlternatingRowBackgroundColors:(CPArray)alternatingRowBackgroundColors { - if ([_alternatingRowBackgroundColors isEqual:alternatingRowBackgroundColors]) - return; - - _alternatingRowBackgroundColors = alternatingRowBackgroundColors; + [self setValue:alternatingRowBackgroundColors forThemeAttribute:"alternating-row-colors"]; [self setNeedsDisplay:YES]; } - (CPArray)alternatingRowBackgroundColors { - return _alternatingRowBackgroundColors; + return [self currentValueForThemeAttribute:@"alternating-row-colors"]; } - (unsigned)selectionHighlightStyle @@ -625,10 +630,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (void)setSelectionHighlightColor:(CPColor)aColor { - if (aColor === _selectionHighlightColor) - return; + [self setValue:aColor forThemeAttribute:"selection-color"]; - _selectionHighlightColor = aColor; [self setNeedsDisplay:YES]; } @@ -637,7 +640,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (CPColor)selectionHighlightColor { - return _selectionHighlightColor; + return [self currentValueForThemeAttribute:@"selection-color"]; } /*! @@ -650,12 +653,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (void)setSelectionGradientColors:(CPDictionary)aDictionary { - if ([aDictionary valueForKey:"CPSourceListGradient"] === _sourceListActiveGradient && [aDictionary valueForKey:"CPSourceListTopLineColor"] === _sourceListActiveTopLineColor && [aDictionary valueForKey:"CPSourceListBottomLineColor"] === _sourceListActiveBottomLineColor) - return; + [self setValue:aDictionary forThemeAttribute:"sourcelist-selection-color"]; - _sourceListActiveGradient = [aDictionary valueForKey:CPSourceListGradient]; - _sourceListActiveTopLineColor = [aDictionary valueForKey:CPSourceListTopLineColor]; - _sourceListActiveBottomLineColor = [aDictionary valueForKey:CPSourceListBottomLineColor]; [self setNeedsDisplay:YES]; } @@ -667,7 +666,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (CPDictionary)selectionGradientColors { - return [CPDictionary dictionaryWithObjects:[_sourceListActiveGradient, _sourceListActiveTopLineColor, _sourceListActiveBottomLineColor] forKeys:[CPSourceListGradient, CPSourceListTopLineColor, CPSourceListBottomLineColor]]; + return [self currentValueForThemeAttribute:@"sourcelist-selection-color"]; } /*! @@ -676,17 +675,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (void)setGridColor:(CPColor)aColor { - if (_gridColor === aColor) - return; - - _gridColor = aColor; + [self setValue:aColor forThemeAttribute:"grid-color"]; [self setNeedsDisplay:YES]; } - (CPColor)gridColor { - return _gridColor; + return [self currentValueForThemeAttribute:@"grid-color"];; } /*! @@ -725,6 +721,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; else _dirtyTableColumnRangeIndex = MIN(NUMBER_OF_COLUMNS() - 1, _dirtyTableColumnRangeIndex); + [self tile]; [self setNeedsLayout]; } @@ -742,8 +739,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (index === CPNotFound) return; + // we differ the actual removal until the end of the runloop in order to keep a reference to the column. + [_differedColumnDataToRemove addObject:{"column":aTableColumn, "shouldBeHidden": [aTableColumn isHidden]}]; + + [aTableColumn setHidden:YES]; [aTableColumn setTableView:nil]; - [_tableColumns removeObjectAtIndex:index]; var tableColumnUID = [aTableColumn UID]; @@ -874,7 +874,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _selectedColumnIndexes = [columns copy]; [self _updateHighlightWithOldColumns:previousSelectedIndexes newColumns:_selectedColumnIndexes]; - [_tableDrawView display]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected columns + [self setNeedsDisplay:YES]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected columns // but currently -drawRect: is not implemented here if (_headerView) [_headerView setNeedsDisplay:YES]; @@ -890,7 +890,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _selectedRowIndexes = [rows copy]; [self _updateHighlightWithOldRows:previousSelectedIndexes newRows:_selectedRowIndexes]; - [_tableDrawView display]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected rows + [self setNeedsDisplay:YES]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected rows // but currently -drawRect: is not implemented here [[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectedRowIndexes"]; @@ -1908,7 +1908,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [newSortDescriptors insertObject:newMainSortDescriptor atIndex:0]; // Update indicator image & highlighted column before - var image = [newMainSortDescriptor ascending] ? [CPTableView _defaultTableHeaderSortImage] : [CPTableView _defaultTableHeaderReverseSortImage]; + var image = [newMainSortDescriptor ascending] ? [self _tableHeaderSortImage] : [self _tableHeaderReverseSortImage]; [self setIndicatorImage:nil inTableColumn:_currentHighlightedTableColumn]; [self setIndicatorImage:image inTableColumn:tableColumn]; @@ -1923,14 +1923,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [[aTableColumn headerView] _setIndicatorImage:anImage]; } -+ (CPImage)_defaultTableHeaderSortImage +- (CPImage)_tableHeaderSortImage { - return CPAppKitImage("tableview-headerview-ascending.png", CGSizeMake(9.0, 8.0)); + return [self currentValueForThemeAttribute:"sort-image"]; } -+ (CPImage)_defaultTableHeaderReverseSortImage +- (CPImage)_tableHeaderReverseSortImage { - return CPAppKitImage("tableview-headerview-descending.png", CGSizeMake(9.0, 8.0)); + return [self currentValueForThemeAttribute:"sort-image-reversed"]; } //Highlightable Column Headers @@ -2231,7 +2231,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [_tableDrawView setFrame:exposedRect]; - [_tableDrawView display]; + [self setNeedsDisplay:YES]; // Now clear all the leftovers // FIXME: this could be faster! @@ -2244,6 +2244,20 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [dataViews[count] removeFromSuperview]; } + // if we have any columns to remove do that here + if ([_differedColumnDataToRemove count]) + { + for (var i = 0; i < _differedColumnDataToRemove.length; i++) + { + var data = _differedColumnDataToRemove[i], + column = data.column; + + [column setHidden:data.shouldBeHidden]; + [_tableColumns removeObject:column]; + } + [_differedColumnDataToRemove removeAllObjects]; + } + } - (void)_unloadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns @@ -2454,6 +2468,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return [self convertRect:CGRectIntersection([superview bounds], [self frame]) fromView:superview]; } +- (void)setNeedsDisplay:(BOOL)aFlag +{ + [super setNeedsDisplay:aFlag]; + [_tableDrawView setNeedsDisplay:aFlag]; +} + - (void)_drawRect:(CGRect)aRect { // FIX ME: All three of these methods will likely need to be rewritten for 1.0 @@ -2610,7 +2630,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } CGContextClosePath(context); - CGContextSetStrokeColor(context, _gridColor); + CGContextSetStrokeColor(context, [self gridColor]); CGContextStrokePath(context); } @@ -2653,6 +2673,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; deltaHeight = 0.5 * (_gridStyleMask & CPTableViewSolidHorizontalGridLineMask); CGContextBeginPath(context); + + var gradientCache = [self selectionGradientColors], + topLineColor = [gradientCache objectForKey:CPSourceListTopLineColor], + bottomLineColor = [gradientCache objectForKey:CPSourceListBottomLineColor], + gradientColor = [gradientCache objectForKey:CPSourceListGradient]; + while (count--) { var rowRect = CGRectIntersection(objj_msgSend(self, rectSelector, indexes[count]), aRect); @@ -2665,21 +2691,21 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; maxX = _CGRectGetMaxX(rowRect), maxY = _CGRectGetMaxY(rowRect) - deltaHeight; - CGContextDrawLinearGradient(context, _sourceListActiveGradient, rowRect.origin, CGPointMake(minX, maxY), 0); + CGContextDrawLinearGradient(context, gradientColor, rowRect.origin, CGPointMake(minX, maxY), 0); CGContextClosePath(context); CGContextBeginPath(context); CGContextMoveToPoint(context, minX, minY); CGContextAddLineToPoint(context, maxX, minY); CGContextClosePath(context); - CGContextSetStrokeColor(context, _sourceListActiveTopLineColor); + CGContextSetStrokeColor(context, topLineColor); CGContextStrokePath(context); CGContextBeginPath(context); CGContextMoveToPoint(context, minX, maxY); CGContextAddLineToPoint(context, maxX, maxY - 1); CGContextClosePath(context); - CGContextSetStrokeColor(context, _sourceListActiveBottomLineColor); + CGContextSetStrokeColor(context, bottomLineColor); CGContextStrokePath(context); } } @@ -2688,7 +2714,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!drawGradient) { - [_selectionHighlightColor setFill]; + [[self selectionHighlightColor] setFill]; CGContextFillPath(context); } @@ -2731,7 +2757,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } CGContextClosePath(context); - CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"e5e5e5"]); + CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:"highlighted-grid-color"]); CGContextStrokePath(context); } @@ -3511,12 +3537,11 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", _intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey] || _CGSizeMake(0.0, 0.0); - _gridColor = [aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor]; + [self setGridColor:[aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor]]; _gridStyleMask = [aCoder decodeIntForKey:CPTableViewGridStyleMaskKey] || CPTableViewGridNone; _usesAlternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewUsesAlternatingBackgroundKey]; - _alternatingRowBackgroundColors = - [[CPColor whiteColor], [CPColor colorWithRed:245.0 / 255.0 green:249.0 / 255.0 blue:252.0 / 255.0 alpha:1.0]]; + [self setAlternatingRowBackgroundColors:[aCoder decodeObjectForKey:CPTableViewAlternatingRowColorsKey]]; _headerView = [aCoder decodeObjectForKey:CPTableViewHeaderViewKey]; _cornerView = [aCoder decodeObjectForKey:CPTableViewCornerViewKey]; @@ -3550,11 +3575,11 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", [aCoder encodeObject:_tableColumns forKey:CPTableViewTableColumnsKey]; - [aCoder encodeObject:_gridColor forKey:CPTableViewGridColorKey]; + [aCoder encodeObject:[self gridColor] forKey:CPTableViewGridColorKey]; [aCoder encodeInt:_gridStyleMask forKey:CPTableViewGridStyleMaskKey]; [aCoder encodeBool:_usesAlternatingRowBackgroundColors forKey:CPTableViewUsesAlternatingBackgroundKey]; - [aCoder encodeObject:_alternatingRowBackgroundColors forKey:CPTableViewAlternatingRowColorsKey] + [aCoder encodeObject:[self alternatingRowBackgroundColors] forKey:CPTableViewAlternatingRowColorsKey] [aCoder encodeObject:_cornerView forKey:CPTableViewCornerViewKey]; [aCoder encodeObject:_headerView forKey:CPTableViewHeaderViewKey]; diff --git a/AppKit/CPTheme.j b/AppKit/CPTheme.j index 4b37e6d7a..a1d27c8e5 100644 --- a/AppKit/CPTheme.j +++ b/AppKit/CPTheme.j @@ -242,7 +242,8 @@ CPThemeStateNormal = CPThemeStates["normal"] = 0; CPThemeStateDisabled = CPThemeState("disabled"); CPThemeStateHighlighted = CPThemeState("highlighted"); CPThemeStateSelected = CPThemeState("selected"); -CPThemeStateSelectedDataView = CPThemeState("selectedDataView"); +CPThemeStateTableDataView = CPThemeState("tableDataView"); +CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView"); CPThemeStateBezeled = CPThemeState("bezeled"); CPThemeStateBordered = CPThemeState("bordered"); CPThemeStateEditable = CPThemeState("editable"); diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 51356c8d2..7b1c193d6 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -1364,6 +1364,9 @@ var CPViewFlags = { }, if (_backgroundColor == aColor) return; + if (aColor == [CPNull null]) + aColor = nil; + _backgroundColor = aColor; #if PLATFORM(DOM) diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 0a51a76a0..7af9e9888 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -140,21 +140,32 @@ var KeyCodesToPrevent = {}, 61: 187, // =, equals 59: 186 // ;, semicolon }, - KeyCodesToFunctionUnicodeMap = {}; + KeyCodesToUnicodeMap = {}; KeyCodesToPrevent[CPKeyCodes.A] = YES; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.BACKSPACE] = CPDeleteCharacter; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.DELETE] = CPDeleteFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_UP] = CPPageUpFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_DOWN] = CPPageDownFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.LEFT] = CPLeftArrowFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.BACKSPACE] = CPDeleteCharacter; +KeyCodesToUnicodeMap[CPKeyCodes.DELETE] = CPDeleteFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter; +KeyCodesToUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter; +KeyCodesToUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.PAGE_UP] = CPPageUpFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.PAGE_DOWN] = CPPageDownFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.LEFT] = CPLeftArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.SEMICOLON] = ";"; +KeyCodesToUnicodeMap[CPKeyCodes.DASH] = "-"; +KeyCodesToUnicodeMap[CPKeyCodes.EQUALS] = "="; +KeyCodesToUnicodeMap[CPKeyCodes.COMMA] = ","; +KeyCodesToUnicodeMap[CPKeyCodes.PERIOD] = "."; +KeyCodesToUnicodeMap[CPKeyCodes.SLASH] = "/"; +KeyCodesToUnicodeMap[CPKeyCodes.APOSTROPHE] = "`"; +KeyCodesToUnicodeMap[CPKeyCodes.SINGLE_QUOTE] = "'"; +KeyCodesToUnicodeMap[CPKeyCodes.OPEN_SQUARE_BRACKET] = "["; +KeyCodesToUnicodeMap[CPKeyCodes.BACKSLASH] = "\\"; +KeyCodesToUnicodeMap[CPKeyCodes.CLOSE_SQUARE_BRACKET] = "]"; var ModifierKeyCodes = [ CPKeyCodes.META, @@ -642,9 +653,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; var characters; - // Is this a special key? + // Handle key codes for which String.fromCharCode won't work. if (aDOMEvent.which === 0 || aDOMEvent.charCode === 0) - characters = KeyCodesToFunctionUnicodeMap[_keyCode]; + characters = KeyCodesToUnicodeMap[_keyCode]; if (!characters) characters = String.fromCharCode(_keyCode).toLowerCase(); @@ -724,7 +735,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; var characters = overrideCharacters; // Is this a special key? if (!characters && (aDOMEvent.which === 0 || aDOMEvent.charCode === 0)) - characters = KeyCodesToFunctionUnicodeMap[charCode]; + characters = KeyCodesToUnicodeMap[charCode]; if (!characters) characters = String.fromCharCode(charCode); @@ -763,7 +774,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if ([ModifierKeyCodes containsObject:keyCode]) break; - var characters = KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), + var characters = KeyCodesToUnicodeMap[charCode] || String.fromCharCode(charCode), charactersIgnoringModifiers = characters.toLowerCase(); if (!(modifierFlags & CPShiftKeyMask) && (modifierFlags & CPCommandKeyMask) && !_capsLockActive) diff --git a/AppKit/Resources/tableview-headerview-ascending.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-ascending.png similarity index 100% rename from AppKit/Resources/tableview-headerview-ascending.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-ascending.png diff --git a/AppKit/Resources/tableview-headerview-descending.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-descending.png similarity index 100% rename from AppKit/Resources/tableview-headerview-descending.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-descending.png diff --git a/AppKit/Resources/tableview-headerview-highlighted-pressed.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted-pressed.png similarity index 100% rename from AppKit/Resources/tableview-headerview-highlighted-pressed.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted-pressed.png diff --git a/AppKit/Resources/tableview-headerview-highlighted.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted.png similarity index 100% rename from AppKit/Resources/tableview-headerview-highlighted.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted.png diff --git a/AppKit/Resources/tableview-headerview-pressed.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-pressed.png similarity index 100% rename from AppKit/Resources/tableview-headerview-pressed.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-pressed.png diff --git a/AppKit/Resources/tableview-headerview.png b/AppKit/Themes/Aristo/Resources/tableview-headerview.png similarity index 100% rename from AppKit/Resources/tableview-headerview.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview.png diff --git a/AppKit/Themes/Aristo/Resources/tableviewselection.png b/AppKit/Themes/Aristo/Resources/tableviewselection.png new file mode 100644 index 000000000..990a98983 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/tableviewselection.png differ diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j index d1d77ee49..ec1245de8 100755 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -8,6 +8,7 @@ @import @import +@import @implementation AristoThemeDescriptor : BKThemeDescriptor @@ -355,6 +356,16 @@ [textfield setStringValue:""]; [textfield setEditable:YES]; + + // tableview dataview stuff + [textfield setValue:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0] forThemeAttribute:"text-color" inState:CPThemeStateTableDataView]; + [textfield setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode" inState:CPThemeStateTableDataView|CPThemeStateTableDataView]; + [textfield setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment" inState:CPThemeStateTableDataView|CPThemeStateTableDataView]; + [textfield setValue:CGInsetMake(0.0, 0.0, 0.0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateTableDataView|CPThemeStateTableDataView]; + [textfield setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateTableDataView|CPThemeStateSelectedTableDataView]; + [textfield setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateTableDataView|CPThemeStateSelectedTableDataView]; + + return textfield; } @@ -772,6 +783,92 @@ return buttonBar; } ++ (_CPTableColumnHeaderView)themedColumnHeader +{ + var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMake(0,0,50,24)], + highlightedPressed = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview-highlighted-pressed.png" size:CGSizeMake(1.0, 23.0)]], + highlighted = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview-highlighted.png" size:CGSizeMake(1.0, 23.0)]], + pressed = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview-pressed.png" size:CGSizeMake(1.0, 23.0)]], + normal = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview.png" size:CGSizeMake(1.0, 23.0)]]; + + + [header setStringValue:@"Table Header"]; + + [header setValue:normal forThemeAttribute:@"background-color"]; + [header setValue:CGInsetMake(0, 5, 0, 5) forThemeAttribute:@"text-inset"]; + [header setValue:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; + [header setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"text-font"]; + [header setValue:[CPColor whiteColor] forThemeAttribute:@"text-shadow-color"]; + [header setValue:CGSizeMake(0,1) forThemeAttribute:@"text-shadow-offset"]; + [header setValue:CPLeftTextAlignment forThemeAttribute:@"text-alignment"]; + + [header setValue:pressed forThemeAttribute:@"background-color" inState:CPThemeStateHighlighted]; + [header setValue:highlighted forThemeAttribute:@"background-color" inState:CPThemeStateSelected]; + [header setValue:highlightedPressed forThemeAttribute:@"background-color" inState:CPThemeStateHighlighted|CPThemeStateSelected]; + + return header; +} + ++ (CPTableHeaderView)themedTableHeaderRow +{ + var header = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0,0,50,24)], + normal = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview.png" size:CGSizeMake(1.0, 23.0)]]; + + [header setValue:normal forThemeAttribute:@"background-color"]; + + return header; +} + ++ (_CPCornerView)themedCornerview +{ + var corner = [[_CPCornerView alloc] initWithFrame:CGRectMake(0,0,25, 23)], + normal = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview.png" size:CGSizeMake(1.0, 23.0)]]; + + [corner setValue:normal forThemeAttribute:"background-color"]; + + return corner; +} + ++ (CPTableView)themedTableView +{ + // This is a bit more complicated than the rest because we actually set theme values for several different (table related) controls in this method + + var tableview = [[CPTableView alloc] initWithFrame:CGRectMake(0,0,200,200)]; + + // Now theme the tableview + var sortImage = [_CPCibCustomResource imageResourceWithName:"tableview-headerview-ascending.png" size:CGSizeMake(9.0, 8.0)], + sortImageReversed = [_CPCibCustomResource imageResourceWithName:"tableview-headerview-descending.png" size:CGSizeMake(9.0, 8.0)], + alternatingRowColors = [[CPColor whiteColor], [CPColor colorWithRed:245.0 / 255.0 green:249.0 / 255.0 blue:252.0 / 255.0 alpha:1.0]], + gridColor = [CPColor colorWithHexString:@"dce0e2"], + selectionColor = [CPColor colorWithHexString:@"5f83b9"], + sourceListSelectionColor = [CPDictionary dictionaryWithObjects: [ CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [89.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2), + [CPColor colorWithCalibratedRed:(61.0/255.0) green:(123.0/255.0) blue:(218.0/255.0) alpha:1.0], + [CPColor colorWithCalibratedRed:(31.0/255.0) green:(92.0/255.0) blue:(207.0/255.0) alpha:1.0] + ] + forKeys: [CPSourceListGradient, CPSourceListTopLineColor, CPSourceListBottomLineColor]]; + + [tableview setValue:alternatingRowColors forThemeAttribute:"alternating-row-colors"]; + [tableview setValue:gridColor forThemeAttribute:"grid-color"]; + [tableview setValue:[CPColor whiteColor] forThemeAttribute:"highlighted-grid-color"]; + [tableview setValue:selectionColor forThemeAttribute:"selection-color"]; + [tableview setValue:sourceListSelectionColor forThemeAttribute:"sourcelist-selection-color"]; + [tableview setValue:sortImage forThemeAttribute:"sort-image"]; + [tableview setValue:sortImageReversed forThemeAttribute:"sort-image-reversed"]; + + return tableview; +} + ++ (CPTextField)themedTableDataView +{ + var view = [self themedStandardTextField]; + + [view setBezeled:NO]; + [view setEditable:NO]; + [view setThemeState:CPThemeStateTableDataView]; + + return view; +} + @end @implementation AristoHUDThemeDescriptor : BKThemeDescriptor @@ -1179,4 +1276,4 @@ function PatternColor(anImage) { return [CPColor colorWithPatternImage:anImage]; -} +} \ No newline at end of file diff --git a/AppKit/_CPCornerView.j b/AppKit/_CPCornerView.j index a5e4f9a65..33925e5c2 100644 --- a/AppKit/_CPCornerView.j +++ b/AppKit/_CPCornerView.j @@ -1,21 +1,36 @@ - @import "CPView.j" @implementation _CPCornerView : CPView { } ++ (CPString)themeClass +{ + return @"cornerview"; +} + ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObjects:[[CPNull null]] + forKeys:[@"background-color"]]; +} + +- (void)layoutSubviews +{ + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; +} + - (void)_init { - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]]; + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; } - (id)initWithFrame:(CGRect)aFrame { - if (self = [super initWithFrame:aFrame]) - { + self = [super initWithFrame:aFrame] + + if (self) [self _init]; - } return self; } @@ -23,9 +38,9 @@ - (id)initWithCoder:(CPCoder)aCoder { self = [super initWithCoder:aCoder]; - { + + if (self) [self _init]; - } return self; } diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index cba9ec382..3ecdd21a4 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -148,12 +148,21 @@ var CPDateReferenceDate = new Date(Date.UTC(2001, 1, 1, 0, 0, 0, 0)); - (BOOL)isEqual:(CPDate)aDate { + if (self === aDate) + return YES; + + if (!aDate || ![aDate isKindOfClass:[CPDate class]]) + return NO; + return [self isEqualToDate:aDate]; } -- (BOOL)isEqualToDate:(CPDate)anotherDate +- (BOOL)isEqualToDate:(CPDate)aDate { - return self === anotherDate || (anotherDate !== nil && anotherDate.isa && [anotherDate isKindOfClass:CPDate] && !(self < anotherDate || self > anotherDate)); + if (!aDate) + return NO; + + return !(self < aDate || self > aDate); } - (CPComparisonResult)compare:(CPDate)anotherDate diff --git a/Foundation/CPFormatter.j b/Foundation/CPFormatter.j index a58f6cdc2..a5465aed8 100644 --- a/Foundation/CPFormatter.j +++ b/Foundation/CPFormatter.j @@ -151,7 +151,7 @@ - (BOOL)isPartialStringValue:(CPString)aPartialString proposedSelectedRange:(CPRange)aProposedSelectedRange originalString:(CPString)originalString originalSelectedRange:(CPRange)originalSelectedRange errorDescription:(CPString)anError { _CPRaiseInvalidAbstractInvocation(self, @selector(isPartialStringValue:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:)); - return nil; + return NO; } - (id)initWithCoder:(CPCoder)aCoder diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j index 104a6931f..1449899e4 100644 --- a/Foundation/CPKeyValueCoding.j +++ b/Foundation/CPKeyValueCoding.j @@ -33,6 +33,9 @@ CPUndefinedKeyException = @"CPUndefinedKeyException"; CPTargetObjectUserInfoKey = @"CPTargetObjectUserInfoKey"; CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; +var CPObjectAccessorsForClassKey = @"$CPObjectAccessorsForClassKey", + CPObjectModifiersForClassKey = @"$CPObjectModifiersForClassKey"; + @implementation CPObject (CPKeyValueCoding) + (BOOL)accessInstanceVariablesDirectly @@ -43,26 +46,18 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; /* @ignore */ + (SEL)_accessorForKey:(CPString)aKey { - if (!CPObjectAccessorsForClass) - CPObjectAccessorsForClass = [CPDictionary dictionary]; - - var UID = [isa UID], - selector = nil, - accessors = [CPObjectAccessorsForClass objectForKey:UID]; + var selector = nil, + accessors = isa[CPObjectAccessorsForClassKey]; if (accessors) { - selector = [accessors objectForKey:aKey]; + selector = accessors[aKey]; if (selector) return selector === [CPNull null] ? nil : selector; } else - { - accessors = [CPDictionary dictionary]; - - [CPObjectAccessorsForClass setObject:accessors forKey:UID]; - } + accessors = isa[CPObjectAccessorsForClassKey] = {}; var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1); @@ -73,12 +68,12 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; [self instancesRespondToSelector:selector = CPSelectorFromString("_" + aKey)] || [self instancesRespondToSelector:selector = CPSelectorFromString("_is" + capitalizedKey)]) { - [accessors setObject:selector forKey:aKey]; + accessors[aKey] = selector; return selector; } - [accessors setObject:[CPNull null] forKey:aKey]; + accessors[aKey] = [CPNull null]; return nil; } @@ -156,7 +151,7 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; - (id)valueForKey:(CPString)aKey { var theClass = [self class], - selector = [theClass _accessorForKey:aKey]; + selector = _accessorForKey(theClass, aKey); if (selector) return objj_msgSend(self, selector); @@ -264,6 +259,41 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; @end +var Null = [CPNull null]; +var _accessorForKey = function(theClass, aKey) +{ + var selector = nil, + accessors = theClass.isa[CPObjectAccessorsForClassKey]; + + if (accessors) + { + selector = accessors[aKey]; + + if (selector) + return selector === Null ? nil : selector; + } + else + accessors = theClass.isa[CPObjectAccessorsForClassKey] = {}; + + var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1); + + if ([theClass instancesRespondToSelector:selector = CPSelectorFromString("get" + capitalizedKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString(aKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString("is" + capitalizedKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_get" + capitalizedKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_" + aKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_is" + capitalizedKey)]) + { + accessors[aKey] = selector; + + return selector; + } + + accessors[aKey] = Null; + + return nil; +} + @implementation CPDictionary (KeyValueCoding) - (id)valueForKey:(CPString)aKey diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 0ff9fdd26..6ea9c9a42 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -213,7 +213,6 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, _targetObject = aTarget; _nativeClass = [aTarget class]; - _replacedKeys = [CPSet set]; _observersForKey = {}; _changesForKey = {}; _observersForKeyLength = 0; @@ -230,6 +229,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, if (existingKVOClass) { _targetObject.isa = existingKVOClass; + _replacedKeys = existingKVOClass._replacedKeys; return; } @@ -237,6 +237,9 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, objj_registerClassPair(kvoClass); + _replacedKeys = [CPSet set]; + kvoClass._replacedKeys = _replacedKeys; + //copy in the methods from our model subclass var methodList = _CPKVOModelSubclass.method_list, count = methodList.length, @@ -293,6 +296,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, var theMethod = class_getInstanceMethod(_nativeClass, theSelector); class_addMethod(_targetObject.isa, theSelector, theReplacementMethod(aKey, theMethod), ""); + [_replacedKeys addObject:aKey]; } } diff --git a/Foundation/CPString.j b/Foundation/CPString.j index abbe70c2d..877604f4c 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -512,6 +512,18 @@ var CPStringRegexSpecialCharacters = [ return aString && aString != "" && length >= aString.length && lastIndexOf(aString) == (length - aString.length); } +- (BOOL)isEqual:(id)anObject +{ + if (self === anObject) + return YES; + + if (!anObject || ![anObject isKindOfClass:[CPString class]]) + return NO; + + return [self isEqualToString:anObject]; +} + + /*! Returns \c YES if the specified string contains the same characters as the receiver. */ diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j index a49654dd4..f7a65ae8f 100755 --- a/Foundation/Foundation.j +++ b/Foundation/Foundation.j @@ -28,6 +28,7 @@ @import "CPDictionary.j" @import "CPEnumerator.j" @import "CPException.j" +@import "CPFormatter.j" @import "CPIndexSet.j" @import "CPInvocation.j" @import "CPJSONPConnection.j" diff --git a/Tests/Foundation/CPFormatterTest.j b/Tests/Foundation/CPFormatterTest.j new file mode 100644 index 000000000..232d23645 --- /dev/null +++ b/Tests/Foundation/CPFormatterTest.j @@ -0,0 +1,44 @@ +@import + +@implementation CPFormatterTest : OJTestCase + +- (void)testThatCPFormatterIsConstructed +{ + [self assertNotNull:[[CPFormatter alloc] init]]; +} + +- (void)testStringForObjectValue +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter stringForObjectValue:@"Hello World"]; }]; +} + +- (void)testEditingStringForObjectValue +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter editingStringForObjectValue:@"Hello Wolrd"]; }]; +} + +- (void)testGetObjectValueForString +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter getObjectValue:@"Hello World" forString:@"Hello World" errorDescription:nil]; }]; +} + +- (void)testIsPartialStringValidNewEditingString +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter isPartialStringValid:@"Hello Wolrd" newEditingString:@"Hello World" errorDescription:nil]; }]; +} + +- (void)testIsPartialStringValueProposedSelectedRange +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter isPartialStringValue:@"Hello Wolrd" proposedSelectedRange:CPRangeMake(3,5) originalString:@"Hello World" originalSelectedRange:nil errorDescription:nil]; }]; +} +@end \ No newline at end of file diff --git a/Tests/Manual/KeyEquivalents/AppController.j b/Tests/Manual/KeyEquivalents/AppController.j new file mode 100644 index 000000000..8dcc6c177 --- /dev/null +++ b/Tests/Manual/KeyEquivalents/AppController.j @@ -0,0 +1,78 @@ +/* + * AppController.j + * cappuccino-keyequivalents + * + * Created by Alexander Ljungberg on July 20, 2010. + * Copyright 2010, WireLoad, LLC 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:@"Press Cmd-X on the keyboard for each button and verify that it reacts."]; + [label setFont:[CPFont boldSystemFontOfSize:24.0]]; + + [label sizeToFit]; + + [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin]; + [label setFrameOrigin:CGPointMake(10, 10)]; + + [contentView addSubview:label]; + + var keysToTest = [ + "a", + ";", + "-", + "=", + ",", + ".", + "/", + "`", + "'", + "[", + "\\", + "]" + ]; + + for (var i=0; i + + + + CPApplicationDelegateClass + AppController + CPBundleName + cappuccino-keyequivalents + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/KeyEquivalents/Jakefile b/Tests/Manual/KeyEquivalents/Jakefile new file mode 100644 index 000000000..8fea6e453 --- /dev/null +++ b/Tests/Manual/KeyEquivalents/Jakefile @@ -0,0 +1,93 @@ +/* + * Jakefile + * cappuccino-keyequivalents + * + * Created by Alexander Ljungberg on July 20, 2010. + * Copyright 2010, WireLoad, LLC All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + JAKE = require("jake"), + task = JAKE.task, + FileList = JAKE.FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug", + OS = require("os"); + +app ("cappuccinoKeyequivalents", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "cappuccinoKeyequivalents.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("cappuccino-keyequivalents"); + task.setIdentifier("com.yourcompany.cappuccinoKeyequivalents"); + task.setVersion("1.0"); + task.setAuthor("WireLoad, LLC"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("cappuccino-keyequivalents"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["cappuccinoKeyequivalents"], function() +{ + printResults(configuration); +}); + +task ("build", ["default"]); + +task ("debug", function() +{ + ENV["CONFIGURATION"] = "Debug"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("release", function() +{ + ENV["CONFIGURATION"] = "Release"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("run", ["debug"], function() +{ + OS.system(["open", FILE.join("Build", "Debug", "cappuccinoKeyequivalents", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "cappuccinoKeyequivalents", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "cappuccinoKeyequivalents")); + OS.system(["press", "-f", FILE.join("Build", "Release", "cappuccinoKeyequivalents"), FILE.join("Build", "Deployment", "cappuccinoKeyequivalents")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "cappuccinoKeyequivalents")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "cappuccinoKeyequivalents"), FILE.join("Build", "Desktop", "cappuccinoKeyequivalents", "cappuccinoKeyequivalents.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "cappuccinoKeyequivalents", "cappuccinoKeyequivalents.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "cappuccinoKeyequivalents")); + print("----------------------------"); +} diff --git a/Tests/Manual/KeyEquivalents/Resources/spinner.gif b/Tests/Manual/KeyEquivalents/Resources/spinner.gif new file mode 100644 index 000000000..06dbc2bc2 Binary files /dev/null and b/Tests/Manual/KeyEquivalents/Resources/spinner.gif differ diff --git a/Tests/Manual/KeyEquivalents/index-debug.html b/Tests/Manual/KeyEquivalents/index-debug.html new file mode 100644 index 000000000..cb9946076 --- /dev/null +++ b/Tests/Manual/KeyEquivalents/index-debug.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + cappuccino-keyequivalents + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/KeyEquivalents/index.html b/Tests/Manual/KeyEquivalents/index.html new file mode 100644 index 000000000..2519046d2 --- /dev/null +++ b/Tests/Manual/KeyEquivalents/index.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + cappuccino-keyequivalents + + + + + + + + + + + + +
+
+ + + +
+
+ + + + diff --git a/Tests/Manual/KeyEquivalents/main.j b/Tests/Manual/KeyEquivalents/main.j new file mode 100644 index 000000000..59e978a1b --- /dev/null +++ b/Tests/Manual/KeyEquivalents/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * cappuccino-keyequivalents + * + * Created by Alexander Ljungberg on July 20, 2010. + * Copyright 2010, WireLoad, LLC All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/Tests/Manual/TableTest/AppController.j b/Tests/Manual/TableTest/AppController.j index f383bcc8a..2c0d275f1 100644 --- a/Tests/Manual/TableTest/AppController.j +++ b/Tests/Manual/TableTest/AppController.j @@ -10,6 +10,8 @@ tableTestDragType = @"CPTableViewTestDragType"; CPImage iconImage; CPArray dataSet1; CPArray dataSet2; + + CPTableColumn randomColumn; } - (void)applicationDidFinishLaunching:(CPNotification)aNotification @@ -68,6 +70,9 @@ tableTestDragType = @"CPTableViewTestDragType"; [column setEditable:YES]; [tableView addTableColumn:column]; + + if (i === 2) + randomColumn = column; } // we offset this scrollview to make sure all the coordinates are calculated correctly @@ -95,16 +100,34 @@ tableTestDragType = @"CPTableViewTestDragType"; [button setAction:@selector(addRow:)]; [contentView addSubview:button]; - var sourceListActiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [255.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2), - sourceListActiveTopLineColor = [CPColor colorWithCalibratedRed:(255.0/255.0) green:(123.0/255.0) blue:(218.0/255.0) alpha:1.0], - sourceListActiveBottomLineColor = [CPColor colorWithCalibratedRed:(255.0/255.0) green:(92.0/255.0) blue:(207.0/255.0) alpha:1.0]; - [tableView setSelectionGradientColors:[CPDictionary dictionaryWithObjects:[sourceListActiveGradient, sourceListActiveTopLineColor, sourceListActiveBottomLineColor] forKeys:[CPSourceListGradient, CPSourceListTopLineColor, CPSourceListBottomLineColor]]]; - var button = [[CPButton alloc] initWithFrame:CGRectMake(10,70,100, 24)]; [button setTitle:@"Switch Highlight"]; [button setTarget:self]; [button setAction:@selector(switchSelectionHighlightType:)]; [contentView addSubview:button]; + + var button = [[CPButton alloc] initWithFrame:CGRectMake(10,100,100, 24)]; + [button setTitle:@"Hide Column"]; + [button setTarget:self]; + [button setAction:@selector(hideColumn:)]; + [contentView addSubview:button]; + + var button = [[CPButton alloc] initWithFrame:CGRectMake(10,130,100, 24)]; + [button setTitle:@"Remove Column"]; + [button setTarget:self]; + [button setAction:@selector(removeColumn:)]; + [contentView addSubview:button]; + + var button = [[CPButton alloc] initWithFrame:CGRectMake(10,160,100, 24)]; + [button setTitle:@"Add Column"]; + [button setTarget:self]; + [button setAction:@selector(addColumn:)]; + [contentView addSubview:button]; + + var sourceListActiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [255.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2), + sourceListActiveTopLineColor = [CPColor colorWithCalibratedRed:(255.0/255.0) green:(123.0/255.0) blue:(218.0/255.0) alpha:1.0], + sourceListActiveBottomLineColor = [CPColor colorWithCalibratedRed:(255.0/255.0) green:(92.0/255.0) blue:(207.0/255.0) alpha:1.0]; + [tableView setSelectionGradientColors:[CPDictionary dictionaryWithObjects:[sourceListActiveGradient, sourceListActiveTopLineColor, sourceListActiveBottomLineColor] forKeys:[CPSourceListGradient, CPSourceListTopLineColor, CPSourceListBottomLineColor]]]; } - (void)switchSelectionHighlightType:(id)sender @@ -124,6 +147,31 @@ tableTestDragType = @"CPTableViewTestDragType"; [tableView reloadData]; } +- (void)hideColumn:(id)sender +{ + [randomColumn setHidden:![randomColumn isHidden]]; +} + +- (void)removeColumn:(id)sender +{ + // if ([[tableView tableColumns] containsObject:randomColumn]) + [tableView removeTableColumn:randomColumn]; + //else + // [tableView addTableColumn:randomColumn]; +} + +- (void)addColumn:(id)sender +{ + var column = [[CPTableColumn alloc] initWithIdentifier:"NewColumn"]; + [[column headerView] setStringValue:"New Column"]; + + [column setMinWidth:50.0]; + [column setMaxWidth:500.0]; + [column setWidth:75.0]; + + [tableView addTableColumn:column]; +} + - (void)newWindow { @@ -237,7 +285,7 @@ tableTestDragType = @"CPTableViewTestDragType"; return iconImage; if (aTableView === tableView) - return String(dataSet1[aRow]); + return String(dataSet1[aRow]* ([[aTableView tableColumns] indexOfObject:aColumn] + 1)); else if (aTableView === tableView2) return String(dataSet2[aRow]); else if(aTableView === tableView3) @@ -246,7 +294,7 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors { - CPLogConsole(_cmd + [oldDescriptors description]); + //CPLogConsole(_cmd + [oldDescriptors description]); var newDescriptors = [aTableView sortDescriptors]; @@ -257,39 +305,39 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableViewSelectionIsChanging:(CPNotification)aNotification { - CPLog.debug(@"changing! %@", [aNotification description]); + //CPLog.debug(@"changing! %@", [aNotification description]); } - (void)tableViewSelectionDidChange:(CPNotification)aNotification { - CPLog.debug(@"did change! %@", [aNotification description]); + //CPLog.debug(@"did change! %@", [aNotification description]); } - (BOOL)tableView:(CPTableView)aTableView shouldSelectRow:(int)rowIndex { - CPLog.debug(@"tableView:shouldSelectRow"); + //CPLog.debug(@"tableView:shouldSelectRow"); return true; } - (BOOL)selectionShouldChangeInTableView:(CPTableView)aTableView { - CPLog.debug(@"selectionShouldChangeInTableView"); + //CPLog.debug(@"selectionShouldChangeInTableView"); return YES; } - (void)tableViewSelectionDidChange:(id)notification { - CPLogConsole(_cmd + [notification description]); + //CPLogConsole(_cmd + [notification description]); } - (void)tableViewSelectionIsChanging:(id)notification { - CPLogConsole(_cmd + [notification description]); + //CPLogConsole(_cmd + [notification description]); } - (void)_tableViewColumnDidResize:(id)notification { - CPLogConsole(_cmd + [notification description]); + //CPLogConsole(_cmd + [notification description]); } - (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)tableColumn row:(int)row { @@ -301,7 +349,7 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableView:(CPTableView)aTableView willDisplayView:(CPView)aView forTableColumn:(CPTableColumn)tableColumn row:(int)row { - CPLogConsole(_cmd + " column: " + [tableColumn identifier] + " row:" + row) + //CPLogConsole(_cmd + " column: " + [tableColumn identifier] + " row:" + row) } - (void)tableView:(CPTableView)aTableView setObjectValue:(id)aValue forTableColumn:(CPTableColumn)tableColumn row:(int)row @@ -312,7 +360,7 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors { - CPLogConsole(_cmd + [oldDescriptors description]); + //CPLogConsole(_cmd + [oldDescriptors description]); var newDescriptors = [aTableView sortDescriptors]; @@ -403,13 +451,12 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableView:(CPTableView)aTableView didClickTableColumn:(CPTableColumn)aColumn { - CPLog.debug("table: "+aTableView+" clicked column: "+aColumn); + //CPLog.debug("table: "+aTableView+" clicked column: "+aColumn); } @end @implementation CPArray (MoveIndexes) - - (void)moveIndexes:(CPIndexSet)indexes toIndex:(int)insertIndex { var aboveCount = 0,