diff --git a/AppKit/AppKit.j b/AppKit/AppKit.j index def0987dd..1feb31525 100644 --- a/AppKit/AppKit.j +++ b/AppKit/AppKit.j @@ -76,6 +76,7 @@ @import "CPTabView.j" @import "CPTableColumn.j" @import "CPTableView.j" +@import "CPText.j" @import "CPTextField.j" @import "CPToolbar.j" @import "CPToolbarItem.j" diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 97a2f1518..2d1b11ea1 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -252,6 +252,9 @@ var CPAlertWarningImage, Buttons will be added starting from the right hand side of the \c CPAlert panel. The first button will have the index 0, the second button 1 and so on. + The first button will automatically be given a key equivalent of Return, + and any button titled "Cancel" will be given a key equivalent of Escape. + You really shouldn't need more than 3 buttons. */ - (void)addButtonWithTitle:(CPString)title @@ -271,6 +274,8 @@ var CPAlertWarningImage, if (_buttonCount == 0) [_alertPanel setDefaultButton:button]; + else if ([title lowercaseString] === "cancel") + [button setKeyEquivalent:CPEscapeFunctionKey]; _buttonCount++; [_buttons addObject:button]; diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index e23aab878..7958fc45f 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -325,7 +325,9 @@ CPRunContinuesResponse = -1002; applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"], copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"]; - var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"], + var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"], + aboutPanelController = [CPWindowController alloc], + aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController], aboutPanel = [aboutPanelController window], contentView = [aboutPanel contentView], imageView = [contentView viewWithTag:1], @@ -615,7 +617,11 @@ CPRunContinuesResponse = -1002; */ - (CPArray)orderedWindows { +#if PLATFORM(DOM) return CPWindowObjectList(); +#else + return []; +#endif } - (void)hide:(id)aSender diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j new file mode 100644 index 000000000..5fefb58c8 --- /dev/null +++ b/AppKit/CPArrayController.j @@ -0,0 +1,538 @@ + +/* + * CPArrayController.j + * AppKit + * + * Adapted from Cocotron, by Johannes Fortmann + * + * Created by Ross Boucher. + * Copyright 2009, 280 North, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +@import +@import + + +@implementation CPArrayController : CPObjectController +{ + BOOL _avoidsEmptySelection; + BOOL _clearsFilterPredicateOnInsertion; + BOOL _filterRestrictsInsertion; + BOOL _preservesSelection; + BOOL _selectsInsertedObjects; + BOOL _alwaysUsesMultipleValuesMarker; + + id _selectionIndexes; + id _sortDescriptors; + id _filterPredicate; + id _arrangedObjects; +} + ++ (void)initialize +{ + if (self !== [CPArrayController class]) + return; + + [self exposeBinding:@"contentArray"]; + [self exposeBinding:@"contentSet"]; +} + ++ (CPSet)keyPathsForValuesAffectingContentArray +{ + return [CPSet setWithObjects:"content"]; +} + ++ (CPSet)keyPathsForValuesAffectingArrangedObjects +{ + return [CPSet setWithObjects:"content", "contentArray", "contentSet", "filterPredicate", "sortDescriptors"]; +} + ++ (CPSet)keyPathsForValuesAffectingSelection +{ + return [CPSet setWithObjects:"content", "contentArray", "contentSet", "selectionIndexes"]; +} + ++ (CPSet)keyPathsForValuesAffectingSelectionIndex +{ + return [CPSet setWithObjects:"content", "contentArray", "contentSet", "selectionIndexes", "selection"]; +} + ++ (CPSet)keyPathsForValuesAffectingSelectedObjects +{ + return [CPSet setWithObjects:"content", "contentArray", "contentSet", "selectionIndexes", "selection"]; +} + ++ (CPSet)keyPathsForValuesAffectingCanRemove +{ + return [CPSet setWithObjects:"selectionIndexes"]; +} + ++ (CPSet)keyPathsForValuesAffectingCanSelectNext +{ + return [CPSet setWithObjects:"selectionIndexes"]; +} + ++ (CPSet)keyPathsForValuesAffectingCanSelectPrevious +{ + return [CPSet setWithObjects:"selectionIndexes"]; +} + ++ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey +{ + if (![super automaticallyNotifiesObserversForKey:aKey]) + return NO; + if (aKey === @"selectionIndexes") + return NO; + + return YES; +} + +- (id)init +{ + self = [super init]; + + if (self) + { + _selectionIndexes = [CPIndexSet indexSet]; + } + + return self; +} + +-(void)prepareContent +{ + [self _setContentArray:[[self newObject]]]; +} + +- (BOOL)preservesSelection +{ + return _preservesSelection; +} + +- (void)setPreservesSelection:(BOOL)value +{ + _preservesSelection = value; +} + +- (BOOL)selectsInsertedObjects +{ + return _selectsInsertedObjects; +} + +- (void)setSelectsInsertedObjects:(BOOL)value +{ + _selectsInsertedObjects = value; +} + +- (BOOL)avoidsEmptySelection +{ + return _avoidsEmptySelection; +} + +- (void)setAvoidsEmptySelection:(BOOL)value +{ + _avoidsEmptySelection = value; +} + +- (void)setContent:(id)value +{ + if(![value isKindOfClass:[CPArray class]]) + value = [value]; + + var oldSelection = nil, + oldSelectionIndexes = [[self selectionIndexes] copy]; + + if ([self preservesSelection]) + oldSelection = [self selectedObjects]; + + // Avoid out of bounds selections. + _selectionIndexes = [CPIndexSet indexSet]; + //FIXME: copy? + [super setContent:value]; + + if(_clearsFilterPredicateOnInsertion) + [self setFilterPredicate:nil]; + + [self rearrangeObjects]; + + if (oldSelection) + [self setSelectedObjects:oldSelection]; + else + [self setSelectionIndexes:oldSelectionIndexes]; +} + +- (void)_setContentArray:(id)anArray +{ + [self setContent:anArray]; +} + +- (void)_setContentSet:(id)aSet +{ + [self setContent:aSet]; +} + +- (id)contentArray +{ + return [self content]; +} + +- (id)contentSet +{ + return [self content]; +} + +- (CPArray)arrangeObjects:(CPArray)objects +{ + var sortedObjects = objects; + + if ([self filterPredicate]) + sortedObjects = [sortedObjects filteredArrayUsingPredicate:[self filterPredicate]]; + if ([self sortDescriptors]) + sortedObjects = [sortedObjects sortedArrayUsingDescriptors:[self sortDescriptors]]; + + return sortedObjects; +} + +- (void)rearrangeObjects +{ + // Rearranging reapplies the selection criteria and may cause objects to disappear, + // so take care of the selection. + // + // Sometimes rearrangeObjects is called by setContent which may cause two rounds of + // selection preservation. This is okay because setContent temporarily clears the + // selection and so this code below ends up preserving nothing in that case. + var oldSelection = nil, + oldSelectionIndexes = [[self selectionIndexes] copy]; + + if ([self preservesSelection]) + oldSelection = [self selectedObjects]; + + // Avoid out of bounds selections. + _selectionIndexes = [CPIndexSet indexSet]; + + [self _setArrangedObjects:[self arrangeObjects:[self contentArray]]]; + + if (oldSelection) + [self setSelectedObjects:oldSelection]; + else + [self setSelectionIndexes:oldSelectionIndexes]; +} + +- (void)_setArrangedObjects:(id)value +{ + if (_arrangedObjects === value) + return; + + _arrangedObjects = [[_CPObservableArray alloc] initWithArray:value]; +} + +- (id)arrangedObjects +{ + return _arrangedObjects; +} + + +- (CPArray)sortDescriptors +{ + return _sortDescriptors; +} + +- (void)setSortDescriptors:(CPArray)value +{ + if (_sortDescriptors === value) + return; + + _sortDescriptors = [value copy]; + [self rearrangeObjects]; +} + +- (CPPredicate)filterPredicate +{ + return _filterPredicate; +} + +- (void)setFilterPredicate:(CPPredicate)value +{ + if (_filterPredicate === value) + return; + + _filterPredicate = value; + [self rearrangeObjects]; +} + +- (BOOL)alwaysUsesMultipleValuesMarker +{ + return _alwaysUsesMultipleValuesMarker; +} + +//Selection + +- (unsigned)selectionIndex +{ + return [_selectionIndexes firstIndex]; +} + +- (BOOL)setSelectionIndex:(unsigned)index +{ + return [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; +} + +- (CPIndexSet)selectionIndexes +{ + return _selectionIndexes; +} + +- (BOOL)setSelectionIndexes:(CPIndexSet)indexes +{ + if ([_selectionIndexes isEqualToIndexSet:indexes]) + return NO; + + if (![indexes count]) + { + if(_avoidsEmptySelection && [[self arrangedObjects] count]) + indexes = [CPIndexSet indexSetWithIndex:0]; + } + else + { + var objectsCount = [[self arrangedObjects] count]; + // Remove out of bounds indexes. + [indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex]+1)]; + // When avoiding empty selection and the deleted selection was at the bottom, select the last item. + if(![indexes count] && _avoidsEmptySelection && objectsCount) + indexes = [CPIndexSet indexSetWithIndex:objectsCount-1]; + } + + [self willChangeValueForKey:@"selectionIndexes"]; + [self _selectionWillChange]; + + _selectionIndexes = [indexes copy]; + + [self _selectionDidChange]; + [self didChangeValueForKey:@"selectionIndexes"]; + + // Push back the new selection to the model for selectionIndexes if we have one. + // There won't be an infinite loop because of the equality check above. + [[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"]; + + return YES; +} + +- (CPArray)selectedObjects +{ + var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]; + + return objects || [_CPObservableArray array]; +} + +- (BOOL)setSelectedObjects:(CPArray)objects +{ + var set = [CPIndexSet indexSet], + count = [objects count], + arrangedObjects = [self arrangedObjects]; + + for (var i=0; i 0 +} + +-(BOOL)canSelectNext +{ + return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] -1; +} + +-(void)selectNext:(id)sender +{ + var index = [[self selectionIndexes] firstIndex] + 1 || 0; + + if (index < [[self arrangedObjects] count]) + [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; +} + +-(void)selectPrevious:(id)sender +{ + var index = [[self selectionIndexes] firstIndex] - 1 || [[self arrangedObjects] count] - 1; + + if (index >= 0) + [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; +} + +//Add/Remove + +- (void)addObject:(id)object +{ + if (![self canAdd]) + return; + + [self willChangeValueForKey:@"content"]; + [_contentObject addObject:object]; + [self didChangeValueForKey:@"content"]; + + if (_clearsFilterPredicateOnInsertion) + [self setFilterPredicate:nil]; + + if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object]) + { + var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors]; + + if (_selectsInsertedObjects) + { + [self setSelectionIndex:pos]; + } + else + { + [self willChangeValueForKey:@"selectionIndexes"]; + [_selectionIndexes shiftIndexesStartingAtIndex:pos by:1]; + [self didChangeValueForKey:@"selectionIndexes"]; + } + } + else + [self rearrangeObjects]; +} + +- (void)removeObject:(id)object +{ + if (![self canRemove]) + return; + + [self willChangeValueForKey:@"content"]; + [_contentObject removeObject:object]; + [self didChangeValueForKey:@"content"]; + + if ([_filterPredicate evaluateWithObject:object]) + { + [self willChangeValueForKey:@"selectionIndexes"]; + var pos = [_arrangedObjects indexOfObject:object]; + + [_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1]; + [self didChangeValueForKey:@"selectionIndexes"]; + } +} + +-(void)add:(id)sender +{ + if(![self canAdd]) + return; + + [self insert:sender]; +} + +- (void)insert:(id)sender +{ + if(![self canInsert]) + return; + + var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject]; + + [self addObject:newObject]; +} + +- (void)remove:(id)sender +{ + [self removeObjects:[[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]]; +} + +- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)indexes +{ + [self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]]; +} + + +- (void)addObjects:(CPArray)objects +{ + if(![self canAdd]) + return; + + var contentArray = [self contentArray], + count = [objects count]; + + for (var i=0; i= 0 && index < _items.length) - [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; + { + if (_allowsMultipleSelection && ([anEvent modifierFlags] & CPCommandKeyMask || [anEvent modifierFlags] & CPShiftKeyMask)) + { + var indexes = [_selectionIndexes copy]; + if ([indexes containsIndex:index]) + [indexes removeIndex:index]; + else + [indexes addIndex:index]; + } + else + indexes = [CPIndexSet indexSetWithIndex:index]; + + [self setSelectionIndexes:indexes]; + } else if (_allowsEmptySelection) [self setSelectionIndexes:[CPIndexSet indexSet]]; } @@ -623,8 +636,6 @@ [[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self]; - var point = [self convertPoint:[anEvent locationInWindow] fromView:nil]; - if (!_itemForDragging) _itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]]; else @@ -726,6 +737,25 @@ @end @implementation CPCollectionView (KeyboardInteraction) +- (CPIndexSet)_selectionForEvent:(CPEvent)anEvent withNewIndex:(int)anIndex direction:(int)aDirection +{ + if (_allowsMultipleSelection && [anEvent modifierFlags] & CPShiftKeyMask) + { + var indexes = [_selectionIndexes copy], + bottomAnchor = [indexes firstIndex], + topAnchor = [indexes lastIndex]; + + // if the direction is backward (-1) check with the bottom anchor + if (aDirection === -1) + [indexes addIndexesInRange:CPMakeRange(anIndex, bottomAnchor - anIndex + 1)]; + else + [indexes addIndexesInRange:CPMakeRange(topAnchor, anIndex - topAnchor + 1)]; + } + else + indexes = [CPIndexSet indexSetWithIndex:anIndex]; + + return indexes; +} - (void)_scrollToSelection { @@ -743,23 +773,23 @@ index = MAX(index - 1, 0); - [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; + [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]]; [self _scrollToSelection]; } - (void)moveRight:(id)sender { - var index = MIN([[self selectionIndexes] firstIndex] + 1, [[self items] count]-1); + var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1); - [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; + [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]]; [self _scrollToSelection]; } - (void)moveDown:(id)sender { - var index = MIN([[self selectionIndexes] firstIndex] + [self numberOfColumns], [[self items] count]-1); + var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1); - [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; + [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]]; [self _scrollToSelection]; } @@ -771,7 +801,7 @@ index = MAX(0, index - [self numberOfColumns]); - [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; + [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]]; [self _scrollToSelection]; } diff --git a/AppKit/CPColor.j b/AppKit/CPColor.j index b6eda360c..3203257bf 100644 --- a/AppKit/CPColor.j +++ b/AppKit/CPColor.j @@ -422,7 +422,7 @@ var cachedBlackColor, parseInt(parts[1], 10) / 255.0, parseInt(parts[2], 10) / 255.0, parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0 - ] + ]; _cssString = aString; diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index d8fc926f1..7de6719c4 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -23,6 +23,7 @@ @import "CPFont.j" @import "CPShadow.j" @import "CPView.j" +@import "CPKeyValueBinding.j" #include "CoreGraphics/CGGeometry.h" #include "Platform/Platform.h" @@ -75,7 +76,7 @@ CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotific var CPControlBlackColor = [CPColor blackColor]; -/*! +/*! @ingroup appkit @class CPControl @@ -84,7 +85,7 @@ var CPControlBlackColor = [CPColor blackColor]; @implementation CPControl : CPView { id _value; - + // Target-Action Support id _target; SEL _action; @@ -126,16 +127,46 @@ var CPControlBlackColor = [CPColor blackColor]; @"max-size"]]; } ++ (void)initialize +{ + if (self === [CPControl class]) + { + [self exposeBinding:@"value"]; + [self exposeBinding:@"objectValue"]; + [self exposeBinding:@"stringValue"]; + [self exposeBinding:@"integerValue"]; + [self exposeBinding:@"intValue"]; + [self exposeBinding:@"doubleValue"]; + [self exposeBinding:@"floatValue"]; + + [self exposeBinding:@"enabled"]; + } +} + +- (void)_reverseSetBinding +{ + var theBinding = [CPKeyValueBinding getBinding:CPValueBinding forObject:self]; + [theBinding reverseSetValueFor:@"objectValue"]; +} + +- (void)_replacementKeyPathForBinding:(CPString)aBinding +{ + if (aBinding === @"value") + return @"objectValue"; + + return [super _replacementKeyPathForBinding:aBinding]; +} + - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; - + if (self) { _sendActionOn = CPLeftMouseUpMask; _trackingMouseDownFlags = 0; } - + return self; } @@ -180,15 +211,16 @@ var CPControlBlackColor = [CPColor blackColor]; */ - (void)sendAction:(SEL)anAction to:(id)anObject { + [self _reverseSetBinding]; [CPApp sendAction:anAction to:anObject from:self]; } - (int)sendActionOn:(int)mask { var previousMask = _sendActionOn; - + _sendActionOn = mask; - + return previousMask; } @@ -201,7 +233,7 @@ var CPControlBlackColor = [CPColor blackColor]; { if (_toolTip == aToolTip) return; - + _toolTip = aToolTip; #if PLATFORM(DOM) @@ -236,7 +268,7 @@ var CPControlBlackColor = [CPColor blackColor]; // Some subclasses should redefine this with CPLeftMouseDraggedMask if (flag) _sendActionOn |= CPPeriodicMask; - else + else _sendActionOn &= ~CPPeriodicMask; } @@ -254,10 +286,10 @@ var CPControlBlackColor = [CPColor blackColor]; if (type === CPLeftMouseUp) { [self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES]; - + _trackingMouseDownFlags = 0; } - + else { if (type === CPLeftMouseDown) @@ -271,20 +303,20 @@ var CPControlBlackColor = [CPColor blackColor]; { if (!_trackingWasWithinFrame) _continuousTracking = [self startTrackingAt:currentLocation]; - + else if (_continuousTracking) _continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation]; } else [self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO]; } - + [CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; } - + if ((_sendActionOn & (1 << type)) && isWithinFrame) [self sendAction:_action to:_target]; - + _trackingWasWithinFrame = isWithinFrame; _previousTrackingLocation = currentLocation; } @@ -298,12 +330,15 @@ var CPControlBlackColor = [CPColor blackColor]; return 0; } -- (void)performClick:(id)sender +- (void)performClick:(id)sender { + if (![self isEnabled]) + return; + [self highlight:YES]; [self setState:[self nextState]]; [self sendAction:[self action] to:[self target]]; - + [CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO]; } @@ -320,7 +355,7 @@ var CPControlBlackColor = [CPColor blackColor]; - (BOOL)startTrackingAt:(CGPoint)aPoint { [self highlight:YES]; - + return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask); } @@ -338,7 +373,7 @@ var CPControlBlackColor = [CPColor blackColor]; { if (![self isEnabled]) return; - + [self trackMouse:anEvent]; } @@ -356,7 +391,7 @@ var CPControlBlackColor = [CPColor blackColor]; - (void)setObjectValue:(id)anObject { _value = anObject; - + [self setNeedsLayout]; [self setNeedsDisplay:YES]; } @@ -430,7 +465,7 @@ var CPControlBlackColor = [CPColor blackColor]; } /*! - Returns the receiver's int value + Returns the receiver's string value */ - (CPString)stringValue { @@ -438,7 +473,7 @@ var CPControlBlackColor = [CPColor blackColor]; } /*! - Set's the receiver's int value + Set's the receiver's string value */ - (void)setStringValue:(CPString)anObject { @@ -485,7 +520,7 @@ var CPControlBlackColor = [CPColor blackColor]; [self setStringValue:[sender stringValue]]; } -- (void)textDidBeginEditing:(CPNotification)note +- (void)textDidBeginEditing:(CPNotification)note { //this looks to prevent false propagation of notifications for other objects if([note object] != self) @@ -494,7 +529,7 @@ var CPControlBlackColor = [CPColor blackColor]; [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidBeginEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; } -- (void)textDidChange:(CPNotification)note +- (void)textDidChange:(CPNotification)note { //this looks to prevent false propagation of notifications for other objects if([note object] != self) @@ -503,12 +538,13 @@ var CPControlBlackColor = [CPColor blackColor]; [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidChangeNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; } -- (void)textDidEndEditing:(CPNotification)note +- (void)textDidEndEditing:(CPNotification)note { //this looks to prevent false propagation of notifications for other objects if([note object] != self) return; + [self _reverseSetBinding]; [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; } @@ -570,7 +606,7 @@ BRIDGE(ImageScaling, imageScaling, "image-scaling") var CPControlValueKey = "CPControlValueKey", CPControlControlStateKey = @"CPControlControlStateKey", CPControlIsEnabledKey = "CPControlIsEnabledKey", - + CPControlTargetKey = "CPControlTargetKey", CPControlActionKey = "CPControlActionKey", CPControlSendActionOnKey = "CPControlSendActionOnKey", @@ -600,7 +636,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey"; [self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]]; [self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]]; } - + return self; } @@ -636,7 +672,7 @@ var _CPControlSizeIdentifiers = [], _CPControlSizeIdentifiers[CPRegularControlSize] = "Regular"; _CPControlSizeIdentifiers[CPSmallControlSize] = "Small"; _CPControlSizeIdentifiers[CPMiniControlSize] = "Mini"; - + function _CPControlIdentifierForControlSize(aControlSize) { return _CPControlSizeIdentifiers[aControlSize]; @@ -647,21 +683,21 @@ function _CPControlColorWithPatternImage(sizes, aClassName) var index = 1, count = arguments.length, identifier = ""; - + for (; index < count; ++index) identifier += arguments[index]; - + var color = _CPControlCachedColorWithPatternImages[identifier]; - + if (!color) { var bundle = [CPBundle bundleForClass:[CPControl class]]; - + color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]]; _CPControlCachedColorWithPatternImages[identifier] = color; } - + return color; } @@ -670,17 +706,17 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName) var index = 2, count = arguments.length, identifier = ""; - + for (; index < count; ++index) identifier += arguments[index]; var color = _CPControlCachedThreePartImagePattern[identifier]; - + if (!color) { var bundle = [CPBundle bundleForClass:[CPControl class]], path = aClassName + "/" + identifier; - + sizes = sizes[identifier]; color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:[ @@ -688,9 +724,9 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName) [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "1.png"] size:sizes[1]], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]] ] isVertical:isVertical]]; - + _CPControlCachedThreePartImagePattern[identifier] = color; } - + return color; } diff --git a/AppKit/CPController.j b/AppKit/CPController.j new file mode 100644 index 000000000..a4edd6660 --- /dev/null +++ b/AppKit/CPController.j @@ -0,0 +1,86 @@ +// +// CPController.j +// AppKit +// +// Created by Ross Boucher 1/15/09 +// Copyright 280 North +// +// Adapted from GNUStep +// Copyright (C) 2007 Free Software Foundation, Inc +// Released under the LGPL. +// + + +var CPControllerDeclaredKeysKey = @"CPControllerDeclaredKeysKey"; + +@implementation CPController : CPObject +{ + CPArray _editors; + CPArray _declaredKeys; +} + +- (id)init +{ + self = [super init]; + + if (self) + { + _editors = []; + _declaredKeys = []; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + if ([_declaredKeys count] > 0) + [aCoder encodeObject:_declaredKeys forKey:CPControllerDeclaredKeysKey]; +} + +- (id)initWithCoder:(CPCoder)aDecoder +{ + self = [super init]; + + if (self) + { + _editors = []; + _declaredKeys = [aDecoder decodeObjectForKey:CPControllerDeclaredKeysKey] || []; + } + + return nil; +} + +- (BOOL)isEditing +{ + return [_editors count] > 0; +} + +- (BOOL)commitEditing +{ + var index = 0, + count = _editors.length; + + for (; index < count; ++index) + if (![[_editors objectAtIndex:i] commitEditing]) + return NO; + + return YES; +} + +- (void)discardEditing +{ + [_editors makeObjectsPerformSelector:@selector(discardEditing)]; +} + +- (void)objectDidBeginEditing:(id)anEditor +{ + [_editors addObject:anEditor]; +} + +- (void)objectDidEndEditing:(id)anEditor +{ + [_editors removeObject:anEditor]; +} + +@end diff --git a/AppKit/CPCursor.j b/AppKit/CPCursor.j index 95b1dc79a..d550fb10c 100755 --- a/AppKit/CPCursor.j +++ b/AppKit/CPCursor.j @@ -167,7 +167,9 @@ var currentCursor = nil, { if (CPBrowserIsEngine(CPWebKitBrowserEngine)) return [CPCursor cursorWithCSSString:@"-webkit-grab"]; - else if (CPBrowserIsEngine(CPGeckoBrowserEngine) || CPBrowserIsEngine(CPOperaBrowserEngine)) + else if (CPBrowserIsEngine(CPGeckoBrowserEngine)) + return [CPCursor cursorWithCSSString:@"-moz-grab"]; + else if (CPBrowserIsEngine(CPOperaBrowserEngine)) return [CPCursor cursorWithCSSString:@"move"]; return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera @@ -177,8 +179,10 @@ var currentCursor = nil, { if (CPBrowserIsEngine(CPWebKitBrowserEngine)) return [CPCursor cursorWithCSSString:@"-webkit-grabbing"]; + else if (CPBrowserIsEngine(CPGeckoBrowserEngine)) + return [CPCursor cursorWithCSSString:@"-moz-grabbing"]; - return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only + return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit || FF } + (CPCursor)disappearingItemCursor @@ -193,7 +197,7 @@ var currentCursor = nil, + (void)unhide { - [self _setCursorCSS:[currentCursor _cssString]] + [self _setCursorCSS:[currentCursor _cssString]]; } + (void)setHiddenUntilMouseMoves:(BOOL)flag diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index a60a05114..6c05c96d6 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -21,6 +21,7 @@ */ @import +@import "CPText.j" #include "CoreGraphics/CGGeometry.h" @@ -41,7 +42,7 @@ CPAppKitDefined = 13; CPSystemDefined = 14; CPApplicationDefined = 15; CPPeriodic = 16; -CPCursorUpdate = 17; +CPCursorUpdate = 17; CPScrollWheel = 22; CPOtherMouseDown = 25; CPOtherMouseUp = 26; @@ -52,8 +53,7 @@ CPTouchStart = 28; CPTouchMove = 29; CPTouchEnd = 30; CPTouchCancel = 31; - - + CPAlphaShiftKeyMask = 1 << 16; CPShiftKeyMask = 1 << 17; CPControlKeyMask = 1 << 18; @@ -87,26 +87,102 @@ CPPeriodicMask = 1 << CPPeriodic; CPScrollWheelMask = 1 << CPScrollWheel; CPAnyEventMask = 0xffffffff; -CPDOMEventDoubleClick = "dblclick", -CPDOMEventMouseDown = "mousedown", -CPDOMEventMouseUp = "mouseup", -CPDOMEventMouseMoved = "mousemove", -CPDOMEventMouseDragged = "mousedrag", -CPDOMEventKeyUp = "keyup", -CPDOMEventKeyDown = "keydown", -CPDOMEventKeyPress = "keypress"; -CPDOMEventCopy = "copy"; -CPDOMEventPaste = "paste"; -CPDOMEventScrollWheel = "mousewheel"; -CPDOMEventTouchStart = "touchstart"; -CPDOMEventTouchMove = "touchmove"; -CPDOMEventTouchEnd = "touchend"; -CPDOMEventTouchCancel = "touchcancel"; +CPUpArrowFunctionKey = "\uF700"; +CPDownArrowFunctionKey = "\uF701"; +CPLeftArrowFunctionKey = "\uF702"; +CPRightArrowFunctionKey = "\uF703"; +CPF1FunctionKey = "\uF704"; +CPF2FunctionKey = "\uF705"; +CPF3FunctionKey = "\uF706"; +CPF4FunctionKey = "\uF707"; +CPF5FunctionKey = "\uF708"; +CPF6FunctionKey = "\uF709"; +CPF7FunctionKey = "\uF70A"; +CPF8FunctionKey = "\uF70B"; +CPF9FunctionKey = "\uF70C"; +CPF10FunctionKey = "\uF70D"; +CPF11FunctionKey = "\uF70E"; +CPF12FunctionKey = "\uF70F"; +CPF13FunctionKey = "\uF710"; +CPF14FunctionKey = "\uF711"; +CPF15FunctionKey = "\uF712"; +CPF16FunctionKey = "\uF713"; +CPF17FunctionKey = "\uF714"; +CPF18FunctionKey = "\uF715"; +CPF19FunctionKey = "\uF716"; +CPF20FunctionKey = "\uF717"; +CPF21FunctionKey = "\uF718"; +CPF22FunctionKey = "\uF719"; +CPF23FunctionKey = "\uF71A"; +CPF24FunctionKey = "\uF71B"; +CPF25FunctionKey = "\uF71C"; +CPF26FunctionKey = "\uF71D"; +CPF27FunctionKey = "\uF71E"; +CPF28FunctionKey = "\uF71F"; +CPF29FunctionKey = "\uF720"; +CPF30FunctionKey = "\uF721"; +CPF31FunctionKey = "\uF722"; +CPF32FunctionKey = "\uF723"; +CPF33FunctionKey = "\uF724"; +CPF34FunctionKey = "\uF725"; +CPF35FunctionKey = "\uF726"; +CPInsertFunctionKey = "\uF727"; +CPDeleteFunctionKey = "\uF728"; +CPHomeFunctionKey = "\uF729"; +CPBeginFunctionKey = "\uF72A"; +CPEndFunctionKey = "\uF72B"; +CPPageUpFunctionKey = "\uF72C"; +CPPageDownFunctionKey = "\uF72D"; +CPPrintScreenFunctionKey = "\uF72E"; +CPScrollLockFunctionKey = "\uF72F"; +CPPauseFunctionKey = "\uF730"; +CPSysReqFunctionKey = "\uF731"; +CPBreakFunctionKey = "\uF732"; +CPResetFunctionKey = "\uF733"; +CPStopFunctionKey = "\uF734"; +CPMenuFunctionKey = "\uF735"; +CPUserFunctionKey = "\uF736"; +CPSystemFunctionKey = "\uF737"; +CPPrintFunctionKey = "\uF738"; +CPClearLineFunctionKey = "\uF739"; +CPClearDisplayFunctionKey = "\uF73A"; +CPInsertLineFunctionKey = "\uF73B"; +CPDeleteLineFunctionKey = "\uF73C"; +CPInsertCharFunctionKey = "\uF73D"; +CPDeleteCharFunctionKey = "\uF73E"; +CPPrevFunctionKey = "\uF73F"; +CPNextFunctionKey = "\uF740"; +CPSelectFunctionKey = "\uF741"; +CPExecuteFunctionKey = "\uF742"; +CPUndoFunctionKey = "\uF743"; +CPRedoFunctionKey = "\uF744"; +CPFindFunctionKey = "\uF745"; +CPHelpFunctionKey = "\uF746"; +CPModeSwitchFunctionKey = "\uF747"; +CPEscapeFunctionKey = "\u001B"; + + +CPDOMEventDoubleClick = "dblclick", +CPDOMEventMouseDown = "mousedown", +CPDOMEventMouseUp = "mouseup", +CPDOMEventMouseMoved = "mousemove", +CPDOMEventMouseDragged = "mousedrag", +CPDOMEventKeyUp = "keyup", +CPDOMEventKeyDown = "keydown", +CPDOMEventKeyPress = "keypress"; +CPDOMEventCopy = "copy"; +CPDOMEventPaste = "paste"; +CPDOMEventScrollWheel = "mousewheel"; +CPDOMEventTouchStart = "touchstart"; +CPDOMEventTouchMove = "touchmove"; +CPDOMEventTouchEnd = "touchend"; +CPDOMEventTouchCancel = "touchcancel"; var _CPEventPeriodicEventPeriod = 0, - _CPEventPeriodicEventTimer = nil; + _CPEventPeriodicEventTimer = nil, + _CPEventUpperCaseRegex = new RegExp("[A-Z]"); -/*! +/*! @ingroup appkit @class CPEvent CPEvent encapsulates the details of a Cappuccino keyboard or mouse event. @@ -155,7 +231,7 @@ var _CPEventPeriodicEventPeriod = 0, characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code { return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags - timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext + timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code]; } @@ -173,7 +249,7 @@ var _CPEventPeriodicEventPeriod = 0, @throws CPInternalInconsistencyException if an invalid event type is provided @return the new mouse event */ -+ (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags ++ (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure { @@ -204,12 +280,12 @@ var _CPEventPeriodicEventPeriod = 0, } /* @ignore */ -- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags +- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure { self = [super init]; - + if (self) { _type = anEventType; @@ -222,7 +298,7 @@ var _CPEventPeriodicEventPeriod = 0, _pressure = aPressure; _window = [CPApp windowWithWindowNumber:aWindowNumber]; } - + return self; } @@ -232,7 +308,7 @@ var _CPEventPeriodicEventPeriod = 0, characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code { self = [super init]; - + if (self) { _type = anEventType; @@ -246,7 +322,7 @@ var _CPEventPeriodicEventPeriod = 0, _keyCode = code; _windowNumber = aWindowNumber; } - + return self; } @@ -256,7 +332,7 @@ var _CPEventPeriodicEventPeriod = 0, subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2 { self = [super init]; - + if (self) { _type = anEventType; @@ -267,7 +343,7 @@ var _CPEventPeriodicEventPeriod = 0, _subtype = aSubtype; _data1 = aData1; _data2 = aData2; - } + } return self; } @@ -445,23 +521,76 @@ var _CPEventPeriodicEventPeriod = 0, return _deltaZ; } +- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask +{ + if (!aKeyEquivalent) + return NO; + + if (_CPEventUpperCaseRegex.test(aKeyEquivalent)) + aKeyEquivalentModifierMask |= CPShiftKeyMask; + + if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask)) + { + aKeyEquivalentModifierMask |= CPControlKeyMask; + aKeyEquivalentModifierMask &= ~CPCommandKeyMask; + } + + if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask) + return NO; + + // Treat \r and \n as the same key equivalent. See issue #710. + if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter) + return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent; + + return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame; +} + - (BOOL)_couldBeKeyEquivalent { + if (_type !== CPKeyDown) + return NO; + + var characterCount = _characters.length; + + if (!characterCount) + return NO; + + if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) + return YES; + + for(var i=0; i 0; + return NO; } /*! - Generates periodic events every \c aPeriod seconds. + Gene rates periodic events every \c aPeriod seconds. @param aDelay the number of seconds before the first event @param aPeriod the length of time in seconds between successive events */ + (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod { _CPEventPeriodicEventPeriod = aPeriod; - + // FIXME: OH TIMERS!!! _CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0); } @@ -473,9 +602,9 @@ var _CPEventPeriodicEventPeriod = 0, { if (_CPEventPeriodicEventTimer === nil) return; - + window.clearTimeout(_CPEventPeriodicEventTimer); - + _CPEventPeriodicEventTimer = nil; } diff --git a/AppKit/CPImageView.j b/AppKit/CPImageView.j index 7d365f71f..017b59ad3 100644 --- a/AppKit/CPImageView.j +++ b/AppKit/CPImageView.j @@ -35,6 +35,16 @@ CPScaleProportionally = 0; CPScaleToFit = 1; CPScaleNone = 2; +CPImageAlignCenter = 0; +CPImageAlignTop = 1; +CPImageAlignTopLeft = 2; +CPImageAlignTopRight = 3; +CPImageAlignLeft = 4; +CPImageAlignBottom = 5; +CPImageAlignBottomLeft = 6; +CPImageAlignBottomRight = 7; +CPImageAlignRight = 8; + var CPImageViewShadowBackgroundColor = nil; var LEFT_SHADOW_INSET = 3.0, @@ -52,14 +62,15 @@ var LEFT_SHADOW_INSET = 3.0, */ @implementation CPImageView : CPControl { - DOMElement _DOMImageElement; + DOMElement _DOMImageElement; - BOOL _hasShadow; - CPView _shadowView; + BOOL _hasShadow; + CPView _shadowView; - BOOL _isEditable; + BOOL _isEditable; - CGRect _imageRect; + CGRect _imageRect; + CPImageAlignment _imageAlignment; } - (id)initWithFrame:(CGRect)aFrame @@ -191,6 +202,30 @@ var LEFT_SHADOW_INSET = 3.0, [self hideOrDisplayContents]; } +/*! + Sets the type of image alignment that should be used to + render the image. + @param anImageAlignment the type of scaling to use +*/ +- (void)setImageAlignment:(CPImageAlignment)anImageAlignment +{ + if (_imageAlignment == anImageAlignment) + return; + + _imageAlignment = anImageAlignment; + + if (![self image]) + return; + + [self setNeedsLayout]; + [self setNeedsDisplay:YES]; +} + +- (unsigned)imageAlignment +{ + return _imageAlignment; +} + /*! Sets the type of image scaling that should be used to render the image. @@ -318,8 +353,45 @@ var LEFT_SHADOW_INSET = 3.0, #endif } - var x = (boundsWidth - width) / 2.0, - y = (boundsHeight - height) / 2.0; + var x, y; + + switch (_imageAlignment) + { + case CPImageAlignLeft: + case CPImageAlignTopLeft: + case CPImageAlignBottomLeft: + x = 0.0; + break; + + case CPImageAlignRight: + case CPImageAlignTopRight: + case CPImageAlignBottomRight: + x = boundsWidth - width; + break; + + default: + x = (boundsWidth - width) / 2.0; + break; + } + + switch (_imageAlignment) + { + case CPImageAlignTop: + case CPImageAlignTopLeft: + case CPImageAlignTopRight: + y = 0.0; + break; + + case CPImageAlignBottom: + case CPImageAlignBottomLeft: + case CPImageAlignBottomRight: + y = boundsHeight - height; + break; + + default: + y = (boundsHeight - height) / 2.0; + break; + } #if PLATFORM(DOM) CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y); @@ -380,10 +452,11 @@ var LEFT_SHADOW_INSET = 3.0, @end -var CPImageViewImageKey = @"CPImageViewImageKey", - CPImageViewImageScalingKey = @"CPImageViewImageScalingKey", - CPImageViewHasShadowKey = @"CPImageViewHasShadowKey", - CPImageViewIsEditableKey = @"CPImageViewIsEditableKey"; +var CPImageViewImageKey = @"CPImageViewImageKey", + CPImageViewImageScalingKey = @"CPImageViewImageScalingKey", + CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey", + CPImageViewHasShadowKey = @"CPImageViewHasShadowKey", + CPImageViewIsEditableKey = @"CPImageViewIsEditableKey"; @implementation CPImageView (CPCoding) @@ -416,6 +489,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey", #endif [self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]]; + [self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]]; if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO) [self setEditable:YES]; @@ -450,6 +524,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey", _subviews = actualSubviews; [aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey]; + [aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey]; if (_isEditable) [aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey]; diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j new file mode 100644 index 000000000..3aabc98a6 --- /dev/null +++ b/AppKit/CPKeyValueBinding.j @@ -0,0 +1,437 @@ +/* + * CPKeyValueBinding.j + * AppKit + * + * Created by Ross Boucher 1/13/09 + * Copyright 280 North, Inc. + * + * Adapted from GNUStep + * Released under the LGPL. + * + * 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 +@import +@import +@import + +var exposedBindingsMap = [CPDictionary new], + bindingsMap = [CPDictionary new]; + +var CPBindingOperationAnd = 0, + CPBindingOperationOr = 1; + +@implementation CPKeyValueBinding : CPObject +{ + CPDictionary _info; + id _source; +} + ++ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass +{ + var bindings = [exposedBindingsMap objectForKey:[aClass hash]]; + + if (!bindings) + { + bindings = []; + [exposedBindingsMap setObject:bindings forKey:[aClass hash]]; + } + + bindings.push(aBinding); +} + ++ (CPArray)exposedBindingsForClass:(Class)aClass +{ + return [[exposedBindingsMap objectForKey:[aClass hash]] copy]; +} + ++ (CPKeyValueBinding)getBinding:(CPString)aBinding forObject:(id)anObject +{ + return [[bindingsMap objectForKey:[anObject hash]] objectForKey:aBinding]; +} + ++ (CPDictionary)infoForBinding:(CPString)aBinding forObject:(id)anObject +{ + var theBinding = [self getBinding:aBinding forObject:anObject]; + + if (theBinding) + return theBinding._info; + + return nil; +} + ++ (CPDictionary)allBindingsForObject:(id)anObject +{ + return [bindingsMap objectForKey:[anObject hash]]; +} + ++ (void)unbind:(CPString)aBinding forObject:(id)anObject +{ + var bindings = [bindingsMap objectForKey:[anObject hash]]; + + if (!bindings) + return; + + var theBinding = [bindings objectForKey:aBinding]; + + if (!theBinding) + return; + + var infoDictionary = theBinding._info, + observedObject = [infoDictionary objectForKey:CPObservedObjectKey], + keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey]; + + [observedObject removeObserver:theBinding forKeyPath:keyPath]; + [bindings removeObjectForKey:aBinding]; +} + ++ (void)unbindAllForObject:(id)anObject +{ + var bindings = [bindingsMap objectForKey:[anObject hash]]; + if (!bindings) + return; + + var allKeys = [bindings allKeys], + count = allKeys.length; + + while (count--) + [anObject unbind:[bindings objectForKey:allKeys[count]]]; + + [bindingsMap removeObjectForKey:[anObject hash]]; +} + +- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource +{ + self = [super init]; + + if (self) + { + _source = aSource; + _info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]]; + + if (options) + [_info setObject:options forKey:CPOptionsKey]; + + [aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding]; + + var bindings = [bindingsMap objectForKey:[_source hash]]; + if (!bindings) + { + bindings = [CPDictionary new]; + [bindingsMap setObject:bindings forKey:[_source hash]]; + } + + [bindings setObject:self forKey:aName]; + [self setValueFor:aBinding]; + } + + return self; +} + +- (void)setValueFor:(CPString)aBinding +{ + var destination = [_info objectForKey:CPObservedObjectKey], + keyPath = [_info objectForKey:CPObservedKeyPathKey], + options = [_info objectForKey:CPOptionsKey], + newValue = [destination valueForKeyPath:keyPath]; + + newValue = [self transformValue:newValue withOptions:options]; + [_source setValue:newValue forKey:aBinding]; +} + +- (void)reverseSetValueFor:(CPString)aBinding +{ + var destination = [_info objectForKey:CPObservedObjectKey], + keyPath = [_info objectForKey:CPObservedKeyPathKey], + options = [_info objectForKey:CPOptionsKey], + newValue = [_source valueForKeyPath:aBinding]; + + newValue = [self reverseTransformValue:newValue withOptions:options]; + [destination setValue:newValue forKeyPath:keyPath]; +} + +- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context +{ + if (!changes) + return; + + [self setValueFor:context]; +} + +- (id)transformValue:(id)aValue withOptions:(CPDictionary)options +{ + var valueTransformerName, + valueTransformer, + placeholder; + + var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption], + valueTransformer; + + if (valueTransformerName) + valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName]; + else + valueTransformer = [options objectForKey:CPValueTransformerBindingOption]; + + if (valueTransformer) + aValue = [valueTransformer transformedValue:aValue]; + + switch (aValue) + { + case CPMultipleValuesMarker: return [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values"; + + case CPNoSelectionMarker: return [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection"; + + case CPNotApplicableMarker: if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption]) + [CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+aValue]; + + return [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable"; + + case nil: + case undefined: return [options objectForKey:CPNullPlaceholderBindingOption] || nil; + } + + return aValue; +} + +- (id)reverseTransformValue:(id)aValue withOptions: (CPDictionary)options +{ + var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption], + valueTransformer; + + if (valueTransformerName) + valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName]; + else + valueTransformer = [options objectForKey:CPValueTransformerBindingOption]; + + if (valueTransformer && [[valueTransformer class] allowsReverseTransformation]) + aValue = [valueTransformer transformedValue:aValue]; + + return aValue; +} + +@end + +@implementation CPObject (KeyValueBindingCreation) + ++ (void)exposeBinding:(CPString)aBinding +{ + [CPKeyValueBinding exposeBinding:aBinding forClass:[self class]]; +} + +- (CPArray)exposedBindings +{ + var exposedBindings = [], + theClass = [self class]; + + while(theClass) + { + var temp = [CPKeyValueBinding exposedBindingsForClass:theClass]; + + if (temp) + [exposedBindings addObjectsFromArray:temp]; + + theClass = [theClass superclass]; + } + + return exposedBindings; +} + +- (Class)valueClassForBinding:(CPString)binding +{ + return [CPString class]; +} + +- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options +{ + if (!anObject || !aKeyPath) + return CPLog.error("Invalid object or path on "+self+" for "+aBinding); + + //if (![[self exposedBindings] containsObject:aBinding]) + // CPLog.warn("No binding exposed on "+self+" for "+aBinding); + + [self unbind:aBinding]; + [[CPKeyValueBinding alloc] initWithBinding:[anObject _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self]; +} + +- (CPDictionary)infoForBinding:(CPString)aBinding +{ + return [CPKeyValueBinding infoForBinding:aBinding forObject:self]; +} + +- (void)unbind:(CPString)aBinding +{ + [CPKeyValueBinding unbind:aBinding forObject:self]; +} + +- (id)_replacementKeyPathForBinding:(CPString)binding +{ + return binding; +} + +@end + +@implementation _CPKeyValueOrBinding : CPKeyValueBinding +{ +} + +- (void)setValueFor:(CPString)aBinding +{ + var bindings = [bindingsMap valueForKey:[_source hash]]; + + if (!bindings) + return; + + [_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationOr) forKey:aBinding]; +} + +- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context +{ + [self setValueFor:context]; +} + +@end + +@implementation _CPKeyValueAndBinding : CPKeyValueBinding +{ +} + +- (void)setValueFor:(CPString)aBinding +{ + var bindings = [bindingsMap objectForKey:[_source hash]]; + + if (!bindings) + return; + + [_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationAnd) forKey:aBinding]; +} + +- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObejct change:(CPDictionary)changes context:(id)context +{ + [self setValueFor:context]; +} + +@end + +var resolveMultipleValues = function resolveMultipleValues(/*CPString*/key, /*CPDictionary*/bindings, /*GSBindingOperationKind*/operation) +{ + var bindingName = key, + theBinding, + count = 1; + + while (theBinding = [bindings objectForKey:bindingName]) + { + var infoDictionary = theBinding._info, + object = [infoDictionary objectForKey:CPObservedObjectKey], + keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey], + options = [infoDictionary objectForKey:CPOptionsKey]; + + var value = [theBinding transformValue:[object valueForKeyPath:keyPath] withOptions:options]; + + if (value == operation) + return operation; + + bindingName = [CPString stringWithFormat:@"%@%i", key, ++count]; + } + + return !operation; +} + +var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings) +{ + var theBinding = [bindings objectForKey:targetKey], + infoDictionary = theBinding._info, + + object = [infoDictionary objectForKey:CPObservedObjectKey], + keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey], + options = [infoDictionary objectForKey:CPOptionsKey], + + target = [object valueForKeyPath:keyPath], + selector = [options objectForKey:CPSelectorNameBindingOption]; + + if (!target || !selector) + return; + + var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]]; + [invocation setSelector:selector]; + + var bindingName = argumentKey + count = 1; + + while (theBinding = [bindings objectForKey:bindingName]) + { + infoDictionary = theBinding._info; + + keyPath = [infoDictionary objectForKey:CPObserverKeyPathKey]; + object = [[infoDictionary objectForKey:CPObservedObjectKey] valueForKeyPath:keyPath]; + + if (object) + [invocation setArgument:object atIndex:++count]; + + bindingName = [CPString stringWithFormat:@"%@%i", argumentKey, count]; + } + + [invocation invoke]; +} + +// Keys in options dictionary + +// Keys in dictionary returned by infoForBinding +CPObservedObjectKey = @"CPObservedObjectKey"; +CPObservedKeyPathKey = @"CPObservedKeyPathKey"; +CPOptionsKey = @"CPOptionsKey"; + +// special markers +CPMultipleValuesMarker = @"CPMultipleValuesMarker"; +CPNoSelectionMarker = @"CPNoSelectionMarker"; +CPNotApplicableMarker = @"CPNotApplicableMarker"; + +// Binding name constants +CPAlignmentBinding = @"CPAlignmentBinding"; +CPEditableBinding = @"CPEditableBinding"; +CPEnabledBinding = @"CPEnabledBinding"; +CPFontBinding = @"CPFontBinding"; +CPHiddenBinding = @"CPHiddenBinding"; +CPSelectedIndexBinding = @"CPSelectedIndexBinding"; +CPTextColorBinding = @"CPTextColorBinding"; +CPToolTipBinding = @"CPToolTipBinding"; +CPValueBinding = @"value"; + +//Binding options constants +CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelectionBindingOption"; +CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgumentBindingOption"; +CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditableBindingOption"; +CPConditionallySetsEnabledBindingOption = @"CPConditionallySetsEnabledBindingOption"; +CPConditionallySetsHiddenBindingOption = @"CPConditionallySetsHiddenBindingOption"; +CPContinuouslyUpdatesValueBindingOption = @"CPContinuouslyUpdatesValueBindingOption"; +CPCreatesSortDescriptorBindingOption = @"CPCreatesSortDescriptorBindingOption"; +CPDeletesObjectsOnRemoveBindingsOption = @"CPDeletesObjectsOnRemoveBindingsOption"; +CPDisplayNameBindingOption = @"CPDisplayNameBindingOption"; +CPDisplayPatternBindingOption = @"CPDisplayPatternBindingOption"; +CPHandlesContentAsCompoundValueBindingOption = @"CPHandlesContentAsCompoundValueBindingOption"; +CPInsertsNullPlaceholderBindingOption = @"CPInsertsNullPlaceholderBindingOption"; +CPInvokesSeparatelyWithArrayObjectsBindingOption = @"CPInvokesSeparatelyWithArrayObjectsBindingOption"; +CPMultipleValuesPlaceholderBindingOption = @"CPMultipleValuesPlaceholderBindingOption"; +CPNoSelectionPlaceholderBindingOption = @"CPNoSelectionPlaceholderBindingOption"; +CPNotApplicablePlaceholderBindingOption = @"CPNotApplicablePlaceholderBindingOption"; +CPNullPlaceholderBindingOption = @"CPNullPlaceholderBindingOption"; +CPPredicateFormatBindingOption = @"CPPredicateFormatBindingOption"; +CPRaisesForNotApplicableKeysBindingOption = @"CPRaisesForNotApplicableKeysBindingOption"; +CPSelectorNameBindingOption = @"CPSelectorNameBindingOption"; +CPSelectsAllWhenSettingContentBindingOption = @"CPSelectsAllWhenSettingContentBindingOption"; +CPValidatesImmediatelyBindingOption = @"CPValidatesImmediatelyBindingOption"; +CPValueTransformerNameBindingOption = @"CPValueTransformerNameBindingOption"; +CPValueTransformerBindingOption = @"CPValueTransformerBindingOption"; + diff --git a/AppKit/CPMenu/CPMenu.j b/AppKit/CPMenu/CPMenu.j index 687fb7045..39203dfa7 100644 --- a/AppKit/CPMenu/CPMenu.j +++ b/AppKit/CPMenu/CPMenu.j @@ -50,11 +50,11 @@ var _CPMenuBarVisible = NO, _CPMenuBarAttributes = nil, _CPMenuBarSharedWindow = nil; -/*! +/*! @ingroup appkit @class CPMenu - Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus + Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus and so a heirarchical structure appears. */ @implementation CPMenu : CPObject @@ -69,12 +69,12 @@ var _CPMenuBarVisible = NO, float _minimumWidth; CPMutableArray _items; - + BOOL _autoenablesItems; BOOL _showsStateColumn; id _delegate; - + CPMenuItem _highlightedIndex; _CPMenuWindow _menuWindow; } @@ -95,7 +95,7 @@ var _CPMenuBarVisible = NO, { if (_CPMenuBarVisible === menuBarShouldBeVisible) return; - + _CPMenuBarVisible = menuBarShouldBeVisible; if ([CPPlatform supportsNativeMainMenu]) @@ -105,13 +105,13 @@ var _CPMenuBarVisible = NO, { if (!_CPMenuBarSharedWindow) _CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init]; - + [_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]]; - + [_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle]; [_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage]; [_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue]; - + [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]]; [_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]]; [_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]]; @@ -120,12 +120,12 @@ var _CPMenuBarVisible = NO, [_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]]; [_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]]; [_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]]; - + [_CPMenuBarSharedWindow orderFront:self]; } else [_CPMenuBarSharedWindow orderOut:self]; - + // FIXME: There must be a better way to do this. #if PLATFORM(DOM) [[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil]; @@ -159,9 +159,9 @@ var _CPMenuBarVisible = NO, { if (_CPMenuBarAttributes == attributes) return; - + _CPMenuBarAttributes = [attributes copy]; - + var textColor = [attributes objectForKey:@"CPMenuBarTextColor"], titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"], textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"], @@ -169,40 +169,40 @@ var _CPMenuBarVisible = NO, highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"], highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"], highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]; - + if (!textColor && titleColor) [_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"]; - + else if (textColor && !titleColor) [_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"]; - + else if (!textColor && !titleColor) { [_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"]; [_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"]; } - + if (!textShadowColor && titleShadowColor) [_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"]; - + else if (textShadowColor && !titleShadowColor) [_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"]; - + else if (!textShadowColor && !titleShadowColor) { [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"]; [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"]; } - + if (!highlightColor) [_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"]; - + if (!highlightTextColor) [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"]; - + if (!highlightTextShadowColor) [_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"]; - + if (_CPMenuBarSharedWindow) { [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]]; @@ -231,7 +231,7 @@ var _CPMenuBarVisible = NO, { if (self === [CPApp mainMenu]) return MENUBAR_HEIGHT; - + return 0.0; } @@ -249,18 +249,18 @@ var _CPMenuBarVisible = NO, - (id)initWithTitle:(CPString)aTitle { self = [super init]; - + if (self) { _title = aTitle; _items = []; - + _autoenablesItems = YES; _showsStateColumn = YES; [self setMinimumWidth:0]; } - + return self; } @@ -287,7 +287,7 @@ var _CPMenuBarVisible = NO, [aMenuItem setMenu:self]; [_items insertObject:aMenuItem atIndex:anIndex]; - + [[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidAddItemNotification object:self @@ -306,7 +306,7 @@ var _CPMenuBarVisible = NO, - (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex { var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent]; - + [self insertItem:item atIndex:anIndex]; return item; @@ -351,10 +351,10 @@ var _CPMenuBarVisible = NO, { if (anIndex < 0 || anIndex >= _items.length) return; - + [_items[anIndex] setMenu:nil]; [_items removeObjectAtIndex:anIndex]; - + [[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidRemoveItemNotification object:self @@ -369,7 +369,7 @@ var _CPMenuBarVisible = NO, { if ([aMenuItem menu] != self) return; - + [[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidChangeItemNotification object:self @@ -385,10 +385,10 @@ var _CPMenuBarVisible = NO, - (CPMenuItem)itemWithTag:(int)aTag { var index = [self indexOfItemWithTag:aTag]; - + if (index == CPNotFound) return nil; - + return _items[index]; } @@ -400,10 +400,10 @@ var _CPMenuBarVisible = NO, - (CPMenuItem)itemWithTitle:(CPString)aTitle { var index = [self indexOfItemWithTitle:aTitle]; - + if (index == CPNotFound) return nil; - + return _items[index]; } @@ -442,7 +442,7 @@ var _CPMenuBarVisible = NO, { if ([aMenuItem menu] !== self) return CPNotFound; - + return [_items indexOfObjectIdenticalTo:aMenuItem]; } @@ -455,7 +455,7 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) if ([_items[index] title] === aTitle) return index; @@ -472,7 +472,7 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) if ([_items[index] tag] == aTag) return index; @@ -490,11 +490,11 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) { var item = _items[index]; - + if ([item target] == aTarget && (!anAction || [item action] == anAction)) return index; } @@ -511,7 +511,7 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) if ([[_items[index] representedObject] isEqual:anObject]) return index; @@ -528,7 +528,7 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) if ([_items[index] submenu] == aMenu) return index; @@ -546,7 +546,7 @@ var _CPMenuBarVisible = NO, { [aMenuItem setTarget:aMenuItem]; [aMenuItem setAction:@selector(submenuAction:)]; - + [aMenuItem setSubmenu:aMenu]; } @@ -683,7 +683,7 @@ var _CPMenuBarVisible = NO, itemIndex = [self indexOfItem:anItem]; if (itemIndex === CPNotFound) - throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " + + throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " + anItem + " is not present in menu " + self; } @@ -784,10 +784,10 @@ var _CPMenuBarVisible = NO, + (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont { var delegate = [aMenu delegate]; - + if ([delegate respondsToSelector:@selector(menuWillOpen:)]) [delegate menuWillOpen:aMenu]; - + if (!aFont) aFont = [CPFont systemFontOfSize:12.0]; @@ -938,17 +938,7 @@ var _CPMenuBarVisible = NO, var item = _items[index], modifierMask = [item keyEquivalentModifierMask]; - if ([item keyEquivalent] === [[item keyEquivalent] uppercaseString]) - modifierMask |= CPShiftKeyMask; - - if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask)) - { - modifierMask |= CPControlKeyMask; - modifierMask &= ~CPCommandKeyMask; - } - - if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask && - [characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame) + if ([anEvent _triggersKeyEquivalent:[item keyEquivalent] withModifierMask:[item keyEquivalentModifierMask]]) { if ([item isEnabled]) [self performActionForItemAtIndex:index]; @@ -956,7 +946,7 @@ var _CPMenuBarVisible = NO, { //beep? } - + return YES; } @@ -975,7 +965,7 @@ var _CPMenuBarVisible = NO, - (void)performActionForItemAtIndex:(unsigned)anIndex { var item = _items[anIndex]; - + [CPApp sendAction:[item action] to:[item target] from:item]; } @@ -1064,7 +1054,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey", - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) { _title = [aCoder decodeObjectForKey:CPMenuTitleKey]; @@ -1076,7 +1066,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey", [self setMinimumWidth:0]; } - + return self; } diff --git a/AppKit/CPMenu/_CPMenuManager.j b/AppKit/CPMenu/_CPMenuManager.j index e022f8ddc..18d1021e1 100644 --- a/AppKit/CPMenu/_CPMenuManager.j +++ b/AppKit/CPMenu/_CPMenuManager.j @@ -96,7 +96,7 @@ var SharedMenuManager = nil; // Close Menu Event. if (type === CPAppKitDefined) - return [self completeTracking] + return [self completeTracking]; [CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES]; diff --git a/AppKit/CPMenuItem/CPMenuItem.j b/AppKit/CPMenuItem/CPMenuItem.j index c8d84026e..fb352ed69 100644 --- a/AppKit/CPMenuItem/CPMenuItem.j +++ b/AppKit/CPMenuItem/CPMenuItem.j @@ -29,7 +29,7 @@ @import "CPView.j" @import "_CPMenuItemView.j" -/*! +/*! @ingroup appkit @class CPMenuItem @@ -43,39 +43,39 @@ CPString _title; //CPAttributedString _attributedTitle; - + CPFont _font; - + id _target; SEL _action; - + BOOL _isEnabled; BOOL _isHidden; - + int _tag; int _state; - + CPImage _image; CPImage _alternateImage; CPImage _onStateImage; CPImage _offStateImage; CPImage _mixedStateImage; - + CPMenu _submenu; CPMenu _menu; - + CPString _keyEquivalent; unsigned _keyEquivalentModifierMask; - + int _mnemonicLocation; - + BOOL _isAlternate; int _indentationLevel; - + CPString _toolTip; id _representedObject; CPView _view; - + _CPMenuItemView _menuItemView; } @@ -94,19 +94,19 @@ - (id)initWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent { self = [super init]; - + if (self) { _isSeparator = NO; _title = aTitle; _action = anAction; - + _isEnabled = YES; - + _tag = 0; _state = CPOffState; - + _keyEquivalent = aKeyEquivalent || @""; _keyEquivalentModifierMask = CPPlatformActionKeyMask; @@ -114,7 +114,7 @@ _mnemonicLocation = CPNotFound; } - + return self; } @@ -152,7 +152,7 @@ { if (_isHidden == isHidden) return; - + _isHidden = isHidden; [_menu itemChanged:self]; @@ -173,9 +173,9 @@ { if (_isHidden) return YES; - + var supermenu = [_menu supermenu]; - + if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor]) return YES; @@ -228,11 +228,11 @@ if (_title == aTitle) return; - + _title = aTitle; - + [_menuItemView setDirty]; - + [_menu itemChanged:self]; } @@ -260,11 +260,11 @@ { if (_font == aFont) return; - + _font = aFont; [_menu itemChanged:self]; - + [_menuItemView setDirty]; } @@ -316,9 +316,9 @@ CPOffState { if (_state == aState) return; - + _state = aState; - + [_menu itemChanged:self]; [_menuItemView setDirty]; @@ -346,11 +346,11 @@ CPOffState { if (_image == anImage) return; - + _image = anImage; [_menuItemView setDirty]; - + [_menu itemChanged:self]; } @@ -388,7 +388,7 @@ CPOffState { if (_onStateImage == anImage) return; - + _onStateImage = anImage; [_menu itemChanged:self]; } @@ -409,7 +409,7 @@ CPOffState { if (_offStateImage == anImage) return; - + _offStateImage = anImage; [_menu itemChanged:self]; } @@ -430,7 +430,7 @@ CPOffState { if (_mixedStateImage == anImage) return; - + _mixedStateImage = anImage; [_menu itemChanged:self]; } @@ -648,14 +648,14 @@ CPControlKeyMask - (void)setTitleWithMnemonicLocation:(CPString)aTitle { var location = [aTitle rangeOfString:@"&"].location; - + if (location == CPNotFound) [self setTitle:aTitle]; else { [self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]]; [self setMnemonicLocation:location]; - } + } } /*! @@ -696,7 +696,7 @@ CPControlKeyMask { if (aLevel < 0) [CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."]; - + _indentationLevel = MIN(15, aLevel); } @@ -755,11 +755,11 @@ CPControlKeyMask { if (_view === aView) return; - + _view = aView; - + [_menuItemView setDirty]; - + [_menu itemChanged:self]; } @@ -790,7 +790,7 @@ CPControlKeyMask { if (!_menuItemView) _menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self]; - + return _menuItemView; } @@ -844,15 +844,15 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey", - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) { _isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey]; _title = [aCoder decodeObjectForKey:CPMenuItemTitleKey]; - + // _font; - + _target = [aCoder decodeObjectForKey:CPMenuItemTargetKey]; _action = [aCoder decodeObjectForKey:CPMenuItemActionKey]; @@ -887,7 +887,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey", _representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil); _view = DEFAULT_VALUE(CPMenuItemViewKey, nil); } - + return self; } @@ -901,11 +901,11 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey", [aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey]; [aCoder encodeObject:_title forKey:CPMenuItemTitleKey]; - + [aCoder encodeObject:_target forKey:CPMenuItemTargetKey]; [aCoder encodeObject:_action forKey:CPMenuItemActionKey]; - ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES); + ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES); ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO); ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0); @@ -913,7 +913,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey", ENCODE_IFNOT(CPMenuItemImageKey, _image, nil); ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil); - + ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil); ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil); diff --git a/AppKit/CPMenuItem/_CPMenuItemStandardView.j b/AppKit/CPMenuItem/_CPMenuItemStandardView.j index db15e5417..63777e96f 100644 --- a/AppKit/CPMenuItem/_CPMenuItemStandardView.j +++ b/AppKit/CPMenuItem/_CPMenuItemStandardView.j @@ -39,7 +39,7 @@ var SUBMENU_INDICATOR_COLOR = nil, SUBMENU_INDICATOR_COLOR = [CPColor grayColor]; _CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0]; - _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0] + _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]; var bundle = [CPBundle bundleForClass:self]; diff --git a/AppKit/CPMenuItem/_CPMenuItemView.j b/AppKit/CPMenuItem/_CPMenuItemView.j index d4ef798f0..7b5438a17 100644 --- a/AppKit/CPMenuItem/_CPMenuItemView.j +++ b/AppKit/CPMenuItem/_CPMenuItemView.j @@ -43,7 +43,7 @@ var _CPMenuItemSelectionColor = nil, return; _CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0]; - _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0] + _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]; var bundle = [CPBundle bundleForClass:self]; diff --git a/AppKit/CPObjectController.j b/AppKit/CPObjectController.j new file mode 100644 index 000000000..65815caf2 --- /dev/null +++ b/AppKit/CPObjectController.j @@ -0,0 +1,614 @@ + +@import + +@import "CPController.j" + + +@implementation CPObjectController : CPController +{ + id _contentObject; + id _selection; + + Class _objectClass; + + BOOL _isEditable; + BOOL _automaticallyPreparesContent; + + CPCountedSet _observedKeys; +} + ++ (id)initialize +{ + [self exposeBinding:@"editable"]; + [self exposeBinding:@"contentObject"]; +} + ++ (CPSet)keyPathsForValuesAffectingContentObject +{ + return [CPSet setWithObjects:"content"]; +} + ++ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey +{ + if (aKey === @"contentObject") + return NO; + + return YES; +} + ++ (CPSet)keyPathsForValuesAffectingCanAdd +{ + return [CPSet setWithObject:"editable"]; +} + ++ (CPSet)keyPathsForValuesAffectingCanInsert +{ + return [CPSet setWithObject:"editable"]; +} + ++ (CPSet)keyPathsForValuesAffectingCanRemove +{ + return [CPSet setWithObjects:"editable", "selection"]; +} + +- (id)initWithContent:(id)aContent +{ + self = [super init]; + + if (self) + { + [self setContent:aContent]; + [self setEditable:YES]; + [self setObjectClass:[CPMutableDictionary class]]; + } + + return self; +} + +- (id)content +{ + return _contentObject; +} + +- (void)setContent:(id)aContent +{ + [self willChangeValueForKey:@"contentObject"]; + [self _selectionWillChange]; + + _contentObject = aContent; + + [self didChangeValueForKey:@"contentObject"]; + [self _selectionDidChange]; +} + +- (void)_setContentObject:(id)aContent +{ + [self setContent:aContent]; +} + +- (id)_contentObject +{ + return [self content]; +} + +- (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent +{ + _automaticallyPreparesContent = shouldAutomaticallyPrepareContent; +} + +- (BOOL)automaticallyPreparesContent +{ + return _automaticallyPreparesContent; +} + +- (void)prepareContent +{ + [self setContent:[self newObject]]; +} + +- (void)setObjectClass:(Class)aClass +{ + _objectClass = aClass; +} + +- (Class)objectClass +{ + return _objectClass; +} + +- (id)newObject +{ + return [[[self objectClass] alloc] init]; +} + +- (void)addObject:(id)anObject +{ + [self setContent:anObject]; + + [[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"]; +} + +- (void)removeObject:(id)anObject +{ + if ([self content] === anObject) + [self setContent:nil]; + + [[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"]; +} + +- (void)add:(id)aSender +{ + // FIXME: This should happen on the next run loop? + [self addObject:[self newObject]]; +} + +- (BOOL)canAdd +{ + return [self isEditable]; +} + +- (void)remove:(id)aSender +{ + // FIXME: This should happen on the next run loop? + [self removeObject:[self content]]; +} + +- (BOOL)canRemove +{ + return [self isEditable] && [[self selectedObjects] count]; +} + +- (void)setEditable:(BOOL)shouldBeEditable +{ + _isEditable = shouldBeEditable; +} + +- (BOOL)isEditable +{ + return _isEditable; +} + +- (CPArray)selectedObjects +{ + return [[_CPObservableArray alloc] initWithObjects:[_contentObject] count:1]; +} + +- (id)selection +{ + return _selection; +} + +- (void)_selectionWillChange +{ + [_selection controllerWillChange]; + [self willChangeValueForKey:@"selection"]; +} + +- (void)_selectionDidChange +{ + if (_selection === undefined || _selection === nil) + _selection = [[CPControllerSelectionProxy alloc] initWithController:self]; + + [_selection controllerDidChange]; + [self didChangeValueForKey:@"selection"]; +} + +- (id)observedKeys +{ + return _observedKeys; +} + +- (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context +{ + [_observedKeys addObject:aKeyPath]; + [super addObserver:anObserver forKeyPath:aKeyPath options:options context:context]; +} + +- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath +{ + [_observedKeys removeObject:aKeyPath]; + [super removeObserver:anObserver forKeyPath:aKeyPath]; +} + +@end + +var CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey", + CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey", + CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey"; + +@implementation CPObjectController (CPCoding) + +- (id)initWithCoder:(CPCoder)aCoder +{ + self = [super init]; + + if (self) + { + var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey], + objectClass = CPClassFromString(objectClassName); + + // FIXME: Error if objectClass === nil + + [self setObjectClass:objectClass]; + [self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]]; + [self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey] || NO]; + + _observedKeys = [[CPCountedSet alloc] init]; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [aCoder encodeObject:CPStringFromClass(objectClass) forKey:CPObjectControllerObjectClassNameKey]; + [aCoder encodeObject:[self isEditable] forKey:CPObjectControllerIsEditableKey]; + + if (![self automaticallyPreparesContent]) + [aCoder encodeBOOL:YES forKey:CPObjectControllerAutomaticallyPreparesContentKey]; +} + +@end + +@implementation _CPObservationProxy : CPObject +{ + id _keyPath; + id _observer; + id _object; + + BOOL _notifyObject; + + id _context; + int _options; +} + +- (id)initWithKeyPath:(id)aKeyPath observer:(id)anObserver object:(id)anObject +{ + if (self=[super init]) + { + _keyPath = aKeyPath; + _observer = anObserver; + _object = anObject; + } + + return self; +} + +- (id)observer +{ + return _observer; +} + +- (id)keyPath +{ + return _keyPath; +} + +- (id)context +{ + return _context; +} + +- (int)options +{ + return _options; +} + +- (void)setNotifyObject:(BOOL)notify +{ + _notifyObject = notify; +} + +- (BOOL)isEqual:(id)anObject +{ + if ([anObject class] === [self class]) + { + if (anObject._observer === _observer && [anObject._keyPath isEqual:_keyPath] && [anObject._object isEqual:_object]) + return YES; + } + + return NO; +} + +- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context +{ + if (_notifyObject) + [_object observeValueForKeyPath:_keyPath ofObject:_object change:change context:context]; + + [_observer observeValueForKeyPath:_keyPath ofObject:_object change:change context:context]; +} + +- (CPString)description +{ + return [super description] + [CPString stringWithFormat:@"observation proxy for %@ on key path %@", _observer, _keyPath]; +} + +@end + +@implementation _CPObservableArray : CPMutableArray +{ + CPArray _observationProxies; +} + ++ (id)alloc +{ + var a = []; + a.isa = self; + + var ivars = class_copyIvarList(self), + count = ivars.length; + + while (count--) + a[ivar_getName(ivars[count])] = nil; + + return a; +} + +- (CPString)description +{ + return "<_CPObservableArray: "+[super description]+" >"; +} + +- (id)initWithArray:(CPArray)anArray +{ + if (self = [super initWithArray:anArray]) + { + _observationProxies = []; + } + + return self; +} + +- (id)initWithObjects:(CPArray)objects count:(unsigned)count +{ + if (self = [super initWithObjects:objects count:count]) + { + _observationProxies = []; + } + + return self; +} + +-(void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context +{ + if (aKeyPath.indexOf("@") === 0) + { + var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self]; + + proxy._options = options; + proxy._context = context; + + [_observationProxies addObject:proxy]; + + var dotIndex = aKeyPath.indexOf("."), + remaining = aKeyPath.substring(dotIndex+1), + indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])]; + + [self addObserver:proxy toObjectsAtIndexes:indexes forKeyPath:remaining options:options context:context]; + } + else + { + var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])]; + [self addObserver:anObserver toObjectsAtIndexes:indexes forKeyPath:aKeyPath options:options context:context]; + } +} + +- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath +{ + if (aKeyPath.indexOf("@") === 0) + { + var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self], + index = [_observationProxies indexOfObject:proxy]; + + proxy = [_observationProxies objectAtIndex:index]; + + var dotIndex = aKeyPath.indexOf("."), + remaining = aKeyPath.substring(dotIndex+1), + indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])]; + + [self removeObserver:proxy fromObjectsAtIndexes:indexes forKeyPath:remaining]; + } + else + { + var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])]; + [self removeObserver:anObserver fromObjectsAtIndexes:indexes forKeyPath:aKeyPath]; + } +} + +- (void)insertObject:(id)anObject atIndex:(unsigned)anIndex +{ + for (var i=0, count=[_observationProxies count]; i)theInfo +- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation { if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_)) @@ -1069,14 +1109,14 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt } - (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id )theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation -{ +{ if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_)) return NO; var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil], parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location]; childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location]; - + _outlineView._retargetedItem = nil; _outlineView._shouldRetargetItem = NO; @@ -1106,15 +1146,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt - (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow { var dataView = nil; - + if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_)) - dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView - dataViewForTableColumn:theTableColumn + dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView + dataViewForTableColumn:theTableColumn item:[_outlineView itemAtRow:theRow]]; if (!dataView) - dataView = [theTableColumn dataViewForRow:theRow]; - + dataView = [theTableColumn dataViewForRow:theRow]; + return dataView; } @@ -1122,7 +1162,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt { if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_)) return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]]; - + return YES; } @@ -1205,13 +1245,34 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt CGContextAddLineToPoint(context, 9.0, 0.0); CGContextAddLineToPoint(context, 4.5, 8.0); CGContextAddLineToPoint(context, 0.0, 0.0); - - CGContextClosePath(context); - var isHighlighted = [self hasThemeState:CPThemeStateHighlighted]; - var color = [self hasThemeState:CPThemeStateSelected] ? (isHighlighted ? [CPColor lightGrayColor] : [CPColor whiteColor]) : (isHighlighted ? [CPColor blackColor] : [CPColor grayColor]); - CGContextSetFillColor(context, color); + CGContextClosePath(context); + CGContextSetFillColor(context, + colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected], + [self hasThemeState:CPThemeStateHighlighted])); CGContextFillPath(context); + + + CGContextBeginPath(context); + CGContextMoveToPoint(context, 0.0, 0.0); + if(_angle === 0.0) { + CGContextAddLineToPoint(context, 4.5, 8.0); + CGContextAddLineToPoint(context, 9.0, 0.0); + } else { + CGContextAddLineToPoint(context, 4.5, 8.0); + } + CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]); + CGContextStrokePath(context); } @end + +var colorForDisclosureTriangle = function(isSelected, isHighlighted) { + return isSelected + ? (isHighlighted + ? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0] + : [CPColor colorWithCalibratedWhite:1.0 alpha: 1.0]) + : (isHighlighted + ? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0] + : [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]); +} diff --git a/AppKit/CPPopUpButton.j b/AppKit/CPPopUpButton.j index 9913e8023..b5ac0e1e1 100644 --- a/AppKit/CPPopUpButton.j +++ b/AppKit/CPPopUpButton.j @@ -32,7 +32,7 @@ var VISIBLE_MARGIN = 7.0; CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); -/*! +/*! @ingroup appkit @class CPPopUpButton @@ -42,7 +42,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); { int _selectedIndex; CPRectEdge _preferredEdge; - + CPMenu _menu; } @@ -60,21 +60,21 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); - (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown { self = [super initWithFrame:aFrame]; - + if (self) { _selectedIndex = CPNotFound; _preferredEdge = CPMaxYEdge; - + [self setValue:CPImageLeft forThemeAttribute:@"image-position"]; [self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"]; [self setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"]; - + [self setMenu:[[CPMenu alloc] initWithTitle:@""]]; [self setPullsDown:shouldPullDown]; } - + return self; } @@ -145,7 +145,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); { var index = 0, count = [titles count]; - + for (; index < count; ++index) [self addItemWithTitle:titles[index]]; } @@ -159,11 +159,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); { var items = [self itemArray], count = [items count]; - + while (count--) if ([items[count] title] == aTitle) [self removeItemAtIndex:count]; - + [_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex]; } @@ -173,7 +173,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); - (void)removeAllItems { var count = [_menu numberOfItems]; - + while (count--) [_menu removeItemAtIndex:0]; } @@ -206,7 +206,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); { if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1) return nil; - + return [_menu itemAtIndex:_selectedIndex]; } @@ -253,15 +253,15 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); { if (_selectedIndex == anIndex) return; - + if (_selectedIndex >= 0 && ![self pullsDown]) [[self selectedItem] setState:CPOffState]; - + _selectedIndex = anIndex; if (_selectedIndex >= 0 && ![self pullsDown]) [[self selectedItem] setState:CPOnState]; - + [self synchronizeTitleAndSelectedItem]; } @@ -310,7 +310,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); return; var defaultCenter = [CPNotificationCenter defaultCenter]; - + if (_menu) { [defaultCenter @@ -330,7 +330,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); } _menu = aMenu; - + if (_menu) { [defaultCenter @@ -338,20 +338,20 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); selector:@selector(menuDidAddItem:) name:CPMenuDidAddItemNotification object:_menu]; - + [defaultCenter addObserver:self selector:@selector(menuDidChangeItem:) name:CPMenuDidChangeItemNotification object:_menu]; - + [defaultCenter addObserver:self selector:@selector(menuDidRemoveItem:) name:CPMenuDidRemoveItemNotification object:_menu]; } - + [self synchronizeTitleAndSelectedItem]; } @@ -396,12 +396,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); { var titles = [], items = [self itemArray], - index = 0, count = [items count]; - + for (; index < count; ++index) - items.push([items[index] title]); + titles.push([items[index] title]); + + return titles; } /*! @@ -519,14 +520,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); else { var index = [self indexOfItemWithTitle:aTitle]; - + if (index < 0) { [self addItemWithTitle:aTitle]; - + index = [self numberOfItems] - 1; } - + [self selectItemAtIndex:index]; } } @@ -554,7 +555,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); if ([self pullsDown]) { var items = [_menu itemArray]; - + if ([items count] > 0) item = items[0]; } @@ -573,22 +574,22 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); - (void)menuDidAddItem:(CPNotification)aNotification { var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"]; - + if (_selectedIndex < 0) [self selectItemAtIndex:0]; - + else if (index == _selectedIndex) [self synchronizeTitleAndSelectedItem]; - + else if (index < _selectedIndex) ++_selectedIndex; - + if (index == 0 && [self pullsDown]) { var items = [_menu itemArray]; - + [items[0] setHidden:YES]; - + if (items.length > 0) [items[1] setHidden:NO]; } @@ -613,10 +614,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); if ([self pullsDown] && index != 0) return; - + if (![self pullsDown] && index != _selectedIndex) return; - + [self synchronizeTitleAndSelectedItem]; } @@ -627,7 +628,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); - (void)menuDidRemoveItem:(CPNotification)aNotification { var numberOfItems = [self numberOfItems]; - + if (numberOfItems <= _selectedIndex && numberOfItems > 0) [self selectItemAtIndex:numberOfItems - 1]; else @@ -737,7 +738,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey", - (id)initWithCoder:(CPCoder)aCoder { self = [super initWithCoder:aCoder]; - + if (self) { // Nothing is currently selected @@ -746,7 +747,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey", [self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]]; [self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]]; } - + return self; } @@ -758,7 +759,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey", - (void)encodeWithCoder:(CPCoder)aCoder { [super encodeWithCoder:aCoder]; - + [aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey]; [aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey]; } diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 9e268e40f..4b81635d1 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -22,23 +22,23 @@ @import - -CPDeleteKeyCode = 8; -CPTabKeyCode = 9; -CPReturnKeyCode = 13; -CPEscapeKeyCode = 27; -CPSpaceKeyCode = 32; -CPPageUpKeyCode = 33; -CPPageDownKeyCode = 34; -CPLeftArrowKeyCode = 37; -CPUpArrowKeyCode = 38; -CPRightArrowKeyCode = 39; -CPDownArrowKeyCode = 40; +CPDeleteKeyCode = 8; +CPTabKeyCode = 9; +CPReturnKeyCode = 13; +CPEscapeKeyCode = 27; +CPSpaceKeyCode = 32; +CPPageUpKeyCode = 33; +CPPageDownKeyCode = 34; +CPLeftArrowKeyCode = 37; +CPUpArrowKeyCode = 38; +CPRightArrowKeyCode = 39; +CPDownArrowKeyCode = 40; +CPDeleteForwardKeyCode = 46; /*! @ingroup appkit @class CPResponder - + Subclasses of CPResonder can be part of the responder chain. */ @implementation CPResponder : CPObject @@ -106,39 +106,36 @@ CPDownArrowKeyCode = 40; { var event = events[index]; - switch([event keyCode]) + switch([[event characters] characterAtIndex:0]) { - case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)]; - break; - case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)]; - break; - case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)]; - break; - case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)]; - break; - case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)]; - break; - case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)]; - break; - case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)]; - break; - case CPReturnKeyCode: - case 3: [self doCommandBySelector:@selector(insertLineBreak:)]; - break; - - case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)]; - break; + case CPPageUpFunctionKey: [self doCommandBySelector:@selector(pageUp:)]; + break; + case CPPageDownFunctionKey: [self doCommandBySelector:@selector(pageDown:)]; + break; + case CPLeftArrowFunctionKey: [self doCommandBySelector:@selector(moveLeft:)]; + break; + case CPRightArrowFunctionKey: [self doCommandBySelector:@selector(moveRight:)]; + break; + case CPUpArrowFunctionKey: [self doCommandBySelector:@selector(moveUp:)]; + break; + case CPDownArrowFunctionKey: [self doCommandBySelector:@selector(moveDown:)]; + break; + case CPDeleteCharacter: [self doCommandBySelector:@selector(deleteBackward:)]; + break; + case CPCarriageReturnCharacter: + case CPNewlineCharacter: [self doCommandBySelector:@selector(insertLineBreak:)]; + break; - case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask; + case CPEscapeFunctionKey: [self doCommandBySelector:@selector(cancel:)]; + break; - if (!shift) - [self doCommandBySelector:@selector(insertTab:)]; - else - [self doCommandBySelector:@selector(insertBackTab:)]; + case CPTabCharacter: if (!([event modifierFlags] & CPShiftKeyMask)) + [self doCommandBySelector:@selector(insertTab:)]; + else + [self doCommandBySelector:@selector(insertBackTab:)]; + break; - break; - - default: [self insertText:[event characters]]; + default: [self insertText:[event characters]]; } } } @@ -315,7 +312,7 @@ CPDownArrowKeyCode = 40; if([self respondsToSelector:aSelector]) { [self performSelector:aSelector withObject:anObject]; - + return YES; } @@ -366,10 +363,10 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey"; - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) _nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey]; - + return self; } diff --git a/AppKit/CPScrollView.j b/AppKit/CPScrollView.j index 26b837414..051195b66 100644 --- a/AppKit/CPScrollView.j +++ b/AppKit/CPScrollView.j @@ -27,7 +27,7 @@ #include "CoreGraphics/CGGeometry.h" -/*! +/*! @ingroup appkit @class CPScrollView @@ -44,12 +44,12 @@ BOOL _hasVerticalScroller; BOOL _hasHorizontalScroller; BOOL _autohidesScrollers; - + CPScroller _verticalScroller; CPScroller _horizontalScroller; - + int _recursionCount; - + float _verticalLineScroll; float _verticalPageScroll; float _horizontalLineScroll; @@ -158,11 +158,11 @@ if (_recursionCount > 5) return; - + ++_recursionCount; var documentView = [self documentView]; - + if (!documentView) { if (_autohidesScrollers) @@ -250,7 +250,7 @@ [_verticalScroller setFloatValue:0.0]; [_verticalScroller setKnobProportion:1.0]; } - + if (shouldShowHorizontalScroller) { [_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width]; @@ -279,13 +279,13 @@ { if (_horizontalScroller === aScroller) return; - + [_horizontalScroller removeFromSuperview]; [_horizontalScroller setTarget:nil]; [_horizontalScroller setAction:nil]; - + _horizontalScroller = aScroller; - + [_horizontalScroller setTarget:self]; [_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)]; @@ -339,13 +339,13 @@ { if (_verticalScroller === aScroller) return; - + [_verticalScroller removeFromSuperview]; [_verticalScroller setTarget:nil]; [_verticalScroller setAction:nil]; - + _verticalScroller = aScroller; - + [_verticalScroller setTarget:self]; [_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)]; @@ -403,7 +403,7 @@ return; _autohidesScrollers = autohidesScrollers; - + [self reflectScrolledClipView:_contentView]; } @@ -480,30 +480,30 @@ /* @ignore */ - (void)_verticalScrollerDidScroll:(CPScroller)aScroller { - var value = [aScroller floatValue], - documentFrame = [[_contentView documentView] frame]; + var value = [aScroller floatValue], + documentFrame = [[_contentView documentView] frame], contentBounds = [_contentView bounds]; switch ([_verticalScroller hitPart]) { case CPScrollerDecrementLine: contentBounds.origin.y -= _verticalLineScroll; break; - + case CPScrollerIncrementLine: contentBounds.origin.y += _verticalLineScroll; break; - + case CPScrollerDecrementPage: contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll; break; - + case CPScrollerIncrementPage: contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll; break; - + case CPScrollerKnobSlot: case CPScrollerKnob: // We want integral bounds! default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds))); } - + [_contentView scrollToPoint:contentBounds.origin]; } @@ -513,21 +513,21 @@ var value = [aScroller floatValue], documentFrame = [[self documentView] frame], contentBounds = [_contentView bounds]; - + switch ([_horizontalScroller hitPart]) { case CPScrollerDecrementLine: contentBounds.origin.x -= _horizontalLineScroll; break; - + case CPScrollerIncrementLine: contentBounds.origin.x += _horizontalLineScroll; break; - + case CPScrollerDecrementPage: contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll; break; - + case CPScrollerIncrementPage: contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll; break; - + case CPScrollerKnobSlot: case CPScrollerKnob: // We want integral bounds! @@ -668,7 +668,7 @@ */ - (void)scrollWheel:(CPEvent)anEvent { - [self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] * _horizontalLineScroll + [self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] * _horizontalLineScroll deltaY:[anEvent deltaY] * _verticalLineScroll]; } @@ -771,7 +771,7 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView", _horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey]; _horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey]; - + _contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey]; _headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey]; @@ -793,25 +793,25 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView", // Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state. [[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]]; } - + return self; } - (void)encodeWithCoder:(CPCoder)aCoder { [super encodeWithCoder:aCoder]; - + [aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey]; [aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey]; [aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey]; [aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey]; - + [aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey]; [aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey]; [aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey]; [aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey]; - + [aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey]; [aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey]; [aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey]; diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index 50528fb0d..f5fdea74a 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -581,7 +581,7 @@ var CPSearchFieldSearchImage = nil, - (void)_sendPartialString { - [[self target] performSelector:[self action] withObject:self]; + [self _sendAction:self]; } - (void)_searchFieldCancel:(id)sender diff --git a/AppKit/CPSlider.j b/AppKit/CPSlider.j index bc46a56cf..b448becd0 100644 --- a/AppKit/CPSlider.j +++ b/AppKit/CPSlider.j @@ -362,14 +362,14 @@ CPCircularSlider = 1; [self setNeedsLayout]; [self setNeedsDisplay:YES]; - + return YES; } - (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint { [self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]]; - + return YES; } diff --git a/AppKit/CPSliderColorPicker.j b/AppKit/CPSliderColorPicker.j index 66267c647..6c02cfb16 100644 --- a/AppKit/CPSliderColorPicker.j +++ b/AppKit/CPSliderColorPicker.j @@ -22,6 +22,8 @@ @import "CPColorPicker.j" +#include "Platform/Platform.h" + /* @ignore */ diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j index 70f1a9282..4a90dcf99 100644 --- a/AppKit/CPSplitView.j +++ b/AppKit/CPSplitView.j @@ -152,7 +152,7 @@ var CPSplitViewHorizontalImage = nil, _isPaneSplitter = shouldBePaneSplitter; if(_DOMDividerElements[_drawingDivider]) - [self _setupDOMDivider] + [self _setupDOMDivider]; // The divider changes size when pane splitter mode is toggled, so the // subviews need to change size too. diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index 14f239484..91edc5d50 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -50,7 +50,7 @@ CPTableColumnUserResizingMask = 1 << 1; CPSortDescriptor _sortDescriptorPrototype; BOOL _isHidden; CPString _headerToolTip; - + BOOL _disableResizingPosting @accessors(property=disableResizingPosting); } @@ -72,18 +72,23 @@ CPTableColumnUserResizingMask = 1 << 1; _maxWidth = 1000000.0; _resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask; _disableResizingPosting = NO; - + [self setIdentifier:anIdentifier]; var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()]; [self setHeaderView:header]; - + var textDataView = [CPTextField new]; - [textDataView setLineBreakMode:CPLineBreakByTruncatingTail]; - [textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"]; + + [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 setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" 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]; } @@ -123,19 +128,19 @@ CPTableColumnUserResizingMask = 1 << 1; { var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self], dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex; - + if (dirtyTableColumnRangeIndex < 0) tableView._dirtyTableColumnRangeIndex = index; else tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex); - + var rows = tableView._exposedRows, - columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)]; - + columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)]; + // FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time. [tableView _layoutDataViewsInRows:rows columns:columns]; [tableView tile]; - + if (!_disableResizingPosting) [self _postDidResizeNotificationWithOldWidth:oldWidth]; } @@ -292,7 +297,7 @@ CPTableColumnUserResizingMask = 1 << 1; // unarchive the data view cache var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]]; newDataView.identifier = dataViewUID; - + return newDataView; } @@ -325,7 +330,7 @@ CPTableColumnUserResizingMask = 1 << 1; } /* - Returns YES if the user can edit cells associated with the receiver by double-clicking the + Returns YES if the user can edit cells associated with the receiver by double-clicking the column in the NSTableView, NO otherwise. */ - (BOOL)isEditable @@ -366,7 +371,7 @@ CPTableColumnUserResizingMask = 1 << 1; //Setting Tool Tips /* - Sets the tooltip string that is displayed when the cursor pauses over the + Sets the tooltip string that is displayed when the cursor pauses over the header cell of the receiver. */ - (void)setHeaderToolTip:(CPString)aToolTip @@ -389,6 +394,73 @@ CPTableColumnUserResizingMask = 1 << 1; @end +@implementation CPTableColumn (Bindings) + +- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options +{ + [super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options]; + + if (![aBinding isEqual:@"someListOfExceptedBindings(notAcceptedBindings)"]) + [[self tableView] _establishBindingsIfUnbound:anObject]; +} + +- (void)prepareDataView:(CPView)aDataView forRow:(unsigned)aRow +{ + var bindingsDictionary = [CPKeyValueBinding allBindingsForObject:self], + keys = [bindingsDictionary allKeys]; + + for (var i=0, count = [keys count]; i= [self numberOfRows])) return; @@ -912,7 +935,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var count = deselectRows.length; while (count--) [self _performSelection:NO forRow:deselectRows[count] context:dataViewsInTableColumn]; - + count = selectRows.length; while (count--) [self _performSelection:YES forRow:selectRows[count] context:dataViewsInTableColumn]; @@ -941,7 +964,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [deselectColumnIndexes getIndexes:deselectColumns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedLength)]; [selectColumnIndexes getIndexes:selectColumns maxCount:-1 inIndexRange:CPMakeRange(firstExposedColumn, exposedLength)]; [_exposedRows getIndexes:selectRows maxCount:-1 inIndexRange:nil]; - + var rowsCount = selectRows.length, count = deselectColumns.length; while (count--) @@ -949,14 +972,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var columnIndex = deselectColumns[count], identifier = [_tableColumns[columnIndex] UID], dataViewsInTableColumn = _dataViewsForTableColumns[identifier]; - + for (var i = 0; i < rowsCount; i++) { var rowIndex = selectRows[i], dataView = dataViewsInTableColumn[rowIndex]; [dataView unsetThemeState:CPThemeStateSelectedDataView]; } - + if (_headerView) { var headerView = [_tableColumns[columnIndex] headerView]; @@ -970,7 +993,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var columnIndex = selectColumns[count], identifier = [_tableColumns[columnIndex] UID], dataViewsInTableColumn = _dataViewsForTableColumns[identifier]; - + for (var i = 0; i < rowsCount; i++) { var rowIndex = selectRows[i], @@ -1073,10 +1096,23 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (int)numberOfRows { - if (!_dataSource) - return 0; + if (_numberOfRows) + return _numberOfRows; - return [_dataSource numberOfRowsInTableView:self]; + var contentBindingInfo = [self infoForBinding:@"content"]; + + if (contentBindingInfo) + { + var destination = [contentBindingInfo objectForKey:CPObservedObjectKey], + keyPath = [contentBindingInfo objectForKey:CPObservedKeyPathKey]; + + return [[destination valueForKeyPath:keyPath] count]; + } + + else if (_dataSource) + return [_dataSource numberOfRowsInTableView:self]; + + return 0; } //Displaying Cell @@ -1217,7 +1253,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (CGRect)rectOfColumn:(CPInteger)aColumnIndex { aColumnIndex = +aColumnIndex; - + var column = [[self tableColumns] objectAtIndex:aColumnIndex]; if ([column isHidden] || aColumnIndex < 0 || aColumnIndex >= NUMBER_OF_COLUMNS()) @@ -1435,18 +1471,18 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (void)_resizeAllColumnUniformlyWithOldSize:(CGSize)oldSize { var superview = [self superview]; - + if (!superview) return; var superviewSize = [superview bounds].size; - + if (_dirtyTableColumnRangeIndex !== CPNotFound) [self _recalculateTableColumnRanges];//UPDATE_COLUMN_RANGES_IF_NECESSARY(); var count = _tableColumns.length,//NUMBER_OF_COLUMNS(), visColumns = [[CPArray alloc] init], buffer = 0.0; - + // Fixme: cache resizable columns because they won't changes betwwen two calls to this method. for(var i=0; i < count; i++) { @@ -1463,15 +1499,15 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { var maxXofColumns = CGRectGetMaxX([self rectOfColumn:visColumns[count - 1]]); - // If the x value of the end of the last column is between the current bounds and the previous bounds we should snap. + // If the x value of the end of the last column is between the current bounds and the previous bounds we should snap. if (!_lastColumnShouldSnap && (maxXofColumns >= superviewSize.width && maxXofColumns <= oldSize.width || maxXofColumns <= superviewSize.width && maxXofColumns >= oldSize.width)) { //set the snap mask _lastColumnShouldSnap = YES; //then we need to make sure everything is set correctly. [self _resizeAllColumnUniformlyWithOldSize:CGSizeMake(maxXofColumns, 0)]; - } - + } + if(!_lastColumnShouldSnap) return; @@ -1506,8 +1542,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; /*! Sets the column autoresizing style of the receiver to a given style. - @param aStyle The column autoresizing style for the receiver. - CPTableViewNoColumnAutoresizing, CPTableViewUniformColumnAutoresizingStyle, + @param aStyle The column autoresizing style for the receiver. + CPTableViewNoColumnAutoresizing, CPTableViewUniformColumnAutoresizingStyle, CPTableViewLastColumnOnlyAutoresizingStyle, CPTableViewFirstColumnOnlyAutoresizingStyle */ - (void)setColumnAutoresizingStyle:(unsigned)style @@ -1559,9 +1595,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (void)noteNumberOfRowsChanged { - var oldNumberOfRows = _numberOfRows; + _numberOfRows = nil; + _numberOfRows = [self numberOfRows]; - _numberOfRows = [_dataSource numberOfRowsInTableView:self]; + var oldNumberOfRows = _numberOfRows; // remove row indexes from the selection if they no longer exist var hangingSelections = oldNumberOfRows - _numberOfRows; @@ -1790,7 +1827,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (void)_didClickTableColumn:(int)clickedColumn modifierFlags:(unsigned)modifierFlags { [self _sendDelegateDidClickColumn:clickedColumn]; - + if (_allowsColumnSelection) { [self _noteSelectionIsChanging]; @@ -1800,7 +1837,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self deselectColumn:clickedColumn]; else if ([self allowsMultipleSelection] == YES) [self selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:YES]; - + return; } else if (modifierFlags & CPShiftKeyMask) @@ -1808,60 +1845,60 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; // should be from clickedColumn to lastClickedColum with extending:(direction == previous selection) var startColumn = MIN(clickedColumn, [_selectedColumnIndexes lastIndex]), endColumn = MAX(clickedColumn, [_selectedColumnIndexes firstIndex]); - - [self selectColumnIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(startColumn, endColumn - startColumn + 1)] + + [self selectColumnIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(startColumn, endColumn - startColumn + 1)] byExtendingSelection:YES]; - + return; } else [self selectColumnIndexes:[CPIndexSet indexSetWithIndex:clickedColumn] byExtendingSelection:NO]; } - + [self _changeSortDescriptorsForClickOnColumn:clickedColumn]; } // From GNUSTEP - (void)_changeSortDescriptorsForClickOnColumn:(int)column { - var tableColumn = [_tableColumns objectAtIndex:column], + var tableColumn = [_tableColumns objectAtIndex:column], newMainSortDescriptor = [tableColumn sortDescriptorPrototype]; - + if (!newMainSortDescriptor) return; - - var oldMainSortDescriptor = nil, + + var oldMainSortDescriptor = nil, oldSortDescriptors = [self sortDescriptors], newSortDescriptors = [CPArray arrayWithArray:oldSortDescriptors], - + e = [newSortDescriptors objectEnumerator], descriptor = nil, outdatedDescriptors = [CPArray array]; if ([_sortDescriptors count] > 0) oldMainSortDescriptor = [[self sortDescriptors] objectAtIndex: 0]; - + // Remove every main descriptor equivalents (normally only one) while ((descriptor = [e nextObject]) != nil) { if ([[descriptor key] isEqual: [newMainSortDescriptor key]]) [outdatedDescriptors addObject:descriptor]; } - + // Invert the sort direction when the same column header is clicked twice if ([[newMainSortDescriptor key] isEqual:[oldMainSortDescriptor key]]) newMainSortDescriptor = [oldMainSortDescriptor reversedSortDescriptor]; - + [newSortDescriptors removeObjectsInArray:outdatedDescriptors]; [newSortDescriptors insertObject:newMainSortDescriptor atIndex:0]; - + // Update indicator image & highlighted column before - var image = [newMainSortDescriptor ascending] ? [CPTableView _defaultTableHeaderSortImage] : [CPTableView _defaultTableHeaderReverseSortImage]; + var image = [newMainSortDescriptor ascending] ? [CPTableView _defaultTableHeaderSortImage] : [CPTableView _defaultTableHeaderReverseSortImage]; [self setIndicatorImage:nil inTableColumn:_currentHighlightedTableColumn]; - [self setIndicatorImage:image inTableColumn:tableColumn]; + [self setIndicatorImage:image inTableColumn:tableColumn]; [self setHighlightedTableColumn:tableColumn]; - + [self setSortDescriptors:newSortDescriptors]; } @@ -1889,19 +1926,19 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } - (void)setHighlightedTableColumn:(CPTableColumn)aTableColumn -{ +{ if (_currentHighlightedTableColumn == aTableColumn) return; - + if (_headerView) { if (_currentHighlightedTableColumn != nil) [[_currentHighlightedTableColumn headerView] unsetThemeState:CPThemeStateSelected]; - + if (aTableColumn != nil) [[aTableColumn headerView] setThemeState:CPThemeStateSelected]; } - + _currentHighlightedTableColumn = aTableColumn; } @@ -1928,21 +1965,24 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [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 + // 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 columnIndex = [theTableColumns count]; - while (columnIndex--) + while (columnIndex--) { var tableColumn = [theTableColumns objectAtIndex:columnIndex], row = [theDraggedRows firstIndex]; while (row !== CPNotFound) - { + { var dataView = [self _newDataViewForRow:row tableColumn:tableColumn]; [dataView setFrame:[self frameOfDataViewAtColumn:columnIndex row:row]]; [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]]; + // If the column uses content bindings, allow them to override the objectValueForTableColumn. + [tableColumn prepareDataView:dataView forRow:row]; + [view addSubview:dataView]; row = [theDraggedRows indexGreaterThanIndex:row]; @@ -1959,7 +1999,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; /*! @ignore // Fetches all the data views (from the datasource) for the column and it's visible rows - // Copy the dataviews add them to a transparent drag view and use that drag view + // Copy the dataviews 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) */ - (CPView)_dragViewForColumn:(int)theColumnIndex event:(CPEvent)theDragEvent offset:(CPPointPointer)theDragViewOffset @@ -1969,39 +2009,39 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; bounds = CPRectMake(0.0, 0.0, [tableColumn width], CPRectGetHeight([self _exposedRect]) + 23.0), columnRect = [self rectOfColumn:theColumnIndex], headerView = [tableColumn headerView]; - + row = [_exposedRows firstIndex]; while (row !== CPNotFound) { var dataView = [self _newDataViewForRow:row tableColumn:tableColumn], dataViewFrame = [self frameOfDataViewAtColumn:theColumnIndex row:row]; - - // Only one column is ever dragged so we just place the view at + + // Only one column is ever dragged so we just place the view at dataViewFrame.origin.x = 0.0; - + // Offset by table header height - scroll position dataViewFrame.origin.y = ( CPRectGetMinY(dataViewFrame) - CPRectGetMinY([self _exposedRect]) ) + 23.0; [dataView setFrame:dataViewFrame]; - + [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]]; [dragView addSubview:dataView]; - + row = [_exposedRows indexGreaterThanIndex:row]; } - + // Add the column header view var headerFrame = [headerView frame]; headerFrame.origin = CPPointMakeZero(); - + columnHeaderView = [[_CPTableColumnHeaderView alloc] initWithFrame:headerFrame]; [columnHeaderView setStringValue:[headerView stringValue]]; [columnHeaderView setThemeState:[headerView themeState]]; [dragView addSubview:columnHeaderView]; - + [dragView setBackgroundColor:[CPColor whiteColor]]; [dragView setAlphaValue:0.7]; [dragView setFrame:bounds]; - + return dragView; } @@ -2021,12 +2061,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if(row > [self numberOfRows] && operation === CPTableViewDropOn) { var numberOfRows = [self numberOfRows] + 1; - var reason = @"Attempt to set dropRow=" + row + + var reason = @"Attempt to set dropRow=" + row + " dropOperation=CPTableViewDropOn when [0 - " + numberOfRows + "] is valid range of rows." [[CPException exceptionWithName:@"Error" reason:reason userInfo:nil] raise]; } - + _retargetedDropRow = row; _retargetedDropOperation = operation; @@ -2110,7 +2150,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var objectValue = tableColumnObjectValues[aRowIndex]; - if (objectValue === undefined) + // tableView:objectValueForTableColumn:row: is optional if content bindings are in place. + if (objectValue === undefined && (_implementedDataSourceMethods & CPTableViewDataSource_tableView_objectValueForTableColumn_row_)) { objectValue = [_dataSource tableView:self objectValueForTableColumn:aTableColumn row:aRowIndex]; tableColumnObjectValues[aRowIndex] = objectValue; @@ -2243,13 +2284,13 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; columnsCount = columnArray.length; for (; columnIndex < columnsCount; ++columnIndex) - { + { var column = columnArray[columnIndex], tableColumn = _tableColumns[column]; - + if ([tableColumn isHidden] || columnIndex === _draggedColumnIndex) continue; - + var tableColumnUID = [tableColumn UID]; if (!_dataViewsForTableColumns[tableColumnUID]) @@ -2269,6 +2310,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [dataView setFrame:[self frameOfDataViewAtColumn:column row:row]]; [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]]; + //This gives the table column an opportunity to apply the bindings. + //It will override the value set in the data source, if there is a data source. + //It will do nothing if there is no value binding set. + [tableColumn prepareDataView:dataView forRow:row]; + if (isColumnSelected || [self isRowSelected:row]) [dataView setThemeState:CPThemeStateSelectedDataView]; else @@ -2321,21 +2367,21 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; columnsCount = columnArray.length; for (; columnIndex < columnsCount; ++columnIndex) - { + { var column = columnArray[columnIndex], tableColumn = _tableColumns[column], tableColumnUID = [tableColumn UID], dataViewsForTableColumn = _dataViewsForTableColumns[tableColumnUID], columnRange = _tableColumnRanges[column]; - + var rowIndex = 0, - rowsCount = rowArray.length; + rowsCount = rowArray.length; for (; rowIndex < rowsCount; ++rowIndex) { var row = rowArray[rowIndex], - dataView = dataViewsForTableColumn[row]; - + dataView = dataViewsForTableColumn[row]; + [dataView setFrame:[self frameOfDataViewAtColumn:column row:row]]; } } @@ -2356,8 +2402,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var dataView = [_delegate tableView:self dataViewForTableColumn:aTableColumn row:aRow]; [aTableColumn setDataView:dataView]; } - - + + return [aTableColumn _newDataViewForRow:aRow]; } @@ -2365,7 +2411,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { if (!aDataView) return; - + // FIXME: yuck! var identifier = aDataView.identifier; @@ -2394,19 +2440,19 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } - (void)_drawRect:(CGRect)aRect -{ +{ // FIX ME: All three of these methods will likely need to be rewritten for 1.0 // We've got grid drawing in highlightSelection and crap everywhere. - + var exposedRect = [self _exposedRect]; [self drawBackgroundInClipRect:exposedRect]; [self drawGridInClipRect:exposedRect]; [self highlightSelectionInClipRect:exposedRect]; - + if (_draggedColumnIndex === -1) return; - + var context = [[CPGraphicsContext currentContext] graphicsPort], columnRect = [self rectOfColumn:_draggedColumnIndex]; @@ -2587,7 +2633,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!count) return; - + var drawGradient = (_selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList && [_selectedRowIndexes count] >= 1), deltaHeight = 0.5 * (_gridStyleMask & CPTableViewSolidHorizontalGridLineMask); @@ -2596,24 +2642,24 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { var rowRect = CGRectIntersection(objj_msgSend(self, rectSelector, indexes[count]), aRect); CGContextAddRect(context, rowRect); - + if (drawGradient) { var minX = _CGRectGetMinX(rowRect), minY = _CGRectGetMinY(rowRect), maxX = _CGRectGetMaxX(rowRect), maxY = _CGRectGetMaxY(rowRect) - deltaHeight; - + CGContextDrawLinearGradient(context, _sourceListActiveGradient, rowRect.origin, CGPointMake(minX, maxY), 0); CGContextClosePath(context); - + CGContextBeginPath(context); CGContextMoveToPoint(context, minX, minY); CGContextAddLineToPoint(context, maxX, minY); CGContextClosePath(context); CGContextSetStrokeColor(context, _sourceListActiveTopLineColor); CGContextStrokePath(context); - + CGContextBeginPath(context); CGContextMoveToPoint(context, minX, maxY); CGContextAddLineToPoint(context, maxX, maxY - 1); @@ -2622,15 +2668,15 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; CGContextStrokePath(context); } } - + CGContextClosePath(context); - + if (!drawGradient) { [_selectionHighlightColor setFill]; CGContextFillPath(context); } - + CGContextBeginPath(context); gridStyleMask = [self gridStyleMask]; for(var i=0; i < count2; i++) @@ -2649,7 +2695,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; exposedRange = CPMakeRange(firstExposedColumn, [exposedColumns lastIndex] - firstExposedColumn + 1); [exposedColumns getIndexes:exposedColumnIndexes maxCount:-1 inIndexRange:exposedRange]; var exposedColumnCount = [exposedColumnIndexes count]; - + for(var c = firstExposedColumn; c < exposedColumnCount; c++) { var colRect = [self rectOfColumn:exposedColumnIndexes[c]], @@ -2660,7 +2706,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } } - + //if the row after the current row is not selected then there is no need to draw the bottom grid line white. if([indexes containsObject:indexes[i]+1]) { @@ -2754,9 +2800,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; else _selectionAnchorRow = row; - - //set ivars for startTrackingPoint and time... - _startTrackingPoint = aPoint; + + //set ivars for startTrackingPoint and time... + _startTrackingPoint = aPoint; _startTrackingTimestamp = new Date(); if (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_) @@ -2793,11 +2839,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { var row = [self rowAtPoint:aPoint]; - // begin the drag is the datasource lets us, we've move at least +-3px vertical or horizontal, + // 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(!_isSelectingSession && _implementedDataSourceMethods & CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_) { - if (row >= 0 && (ABS(_startTrackingPoint.x - aPoint.x) > 3 || (_verticalMotionCanDrag && ABS(_startTrackingPoint.y - aPoint.y) > 3)) || + if (row >= 0 && (ABS(_startTrackingPoint.x - aPoint.x) > 3 || (_verticalMotionCanDrag && ABS(_startTrackingPoint.y - aPoint.y) > 3)) || ([_selectedRowIndexes containsIndex:row])) { if ([_selectedRowIndexes containsIndex:row]) @@ -2814,33 +2860,33 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; 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 + var view = [self dragViewForRowsWithIndexes:_draggedRowIndexes + tableColumns:tableColumns + event:currentEvent offset:offset]; - + if (!view) { - var image = [self dragImageForRowsWithIndexes:_draggedRowIndexes - tableColumns:tableColumns - event:currentEvent + 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]; _startTrackingPoint = nil; - + return NO; } - + // The delegate disallowed the drag so clear the dragged row indexes _draggedRowIndexes = [CPIndexSet indexSet]; } @@ -2926,8 +2972,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } //end of editing conditional //double click actions - if([[CPApp currentEvent] clickCount] === 2 && _doubleAction && _target) + if([[CPApp currentEvent] clickCount] === 2 && _doubleAction) + { + _clickedRow = [self rowAtPoint:aPoint]; [self sendAction:_doubleAction to:_target]; + } } /* @@ -2941,17 +2990,17 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if(_retargetedDropRow !== nil) row = _retargetedDropRow; - - var draggedTypes = [self registeredDraggedTypes], + + var draggedTypes = [self registeredDraggedTypes], count = [draggedTypes count], i = 0; - - for (; i < count; i++) - { - if ([[[sender draggingPasteboard] types] containsObject:[draggedTypes objectAtIndex: i]]) - return [self _validateDrop:sender proposedRow:row proposedDropOperation:dropOperation]; + + for (; i < count; i++) + { + if ([[[sender draggingPasteboard] types] containsObject:[draggedTypes objectAtIndex: i]]) + return [self _validateDrop:sender proposedRow:row proposedDropOperation:dropOperation]; } - + return CPDragOperationNone; } @@ -2991,7 +3040,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (CPTableViewDropOperation)_proposedDropOperationAtPoint:(CGPoint)theDragPoint { - if(_retargetedDropOperation !== nil) + if(_retargetedDropOperation !== nil) return _retargetedDropOperation; var row = [self _proposedRowAtPoint:theDragPoint], @@ -3001,13 +3050,13 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; // This probably doesn't work if the row height is smaller than or around 5.0 if ([self intercellSpacing].height < 5.0) rowRect = CPRectInset(rowRect, 0.0, 5.0 - [self intercellSpacing].height); - + // If the altered row rect contains the drag point we show the drop on - // We don't show the drop on indicator if we are dragging below the last row + // We don't show the drop on indicator if we are dragging below the last row // in that case we always want to show the drop above indicator - if (CGRectContainsPoint(rowRect, theDragPoint) && row < _numberOfRows) + if (CGRectContainsPoint(rowRect, theDragPoint) && row < _numberOfRows) return CPTableViewDropOn; - + return CPTableViewDropAbove; } @@ -3019,18 +3068,18 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; // We don't use rowAtPoint here because the drag indicator can appear below the last row // and rowAtPoint doesn't return rows that are larger than numberOfRows var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height )); - + // Determine if the mouse is currently closer to this row or the row below it var lowerRow = row + 1, rect = [self rectOfRow:row], lowerRect = [self rectOfRow:lowerRow]; - + if (ABS(CPRectGetMinY(lowerRect) - dragPoint.y) < ABS(dragPoint.y - CPRectGetMinY(rect))) row = lowerRow; if (row >= [self numberOfRows]) row = [self numberOfRows]; - + return row; } @@ -3046,7 +3095,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { if (theRowIndex >= [self numberOfRows]) theRowIndex = [self numberOfRows] - 1; - + return [self rectOfRow:theRowIndex]; } @@ -3067,25 +3116,25 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var row = [self _proposedRowAtPoint:location], dragOperation = [self _validateDrop:sender proposedRow:row proposedDropOperation:dropOperation]; exposedClipRect = [self exposedClipRect]; - + if(_retargetedDropRow !== nil) row = _retargetedDropRow; - + if (dropOperation === CPTableViewDropOn && row >= [self numberOfRows]) row = [self numberOfRows] - 1; var rect = CPRectMakeZero(); - + if (row === -1) rect = exposedClipRect; - + else if (dropOperation === CPTableViewDropAbove) rect = [self _rectForDropHighlightViewBetweenUpperRow:row - 1 andLowerRow:row offset:location]; - - else + + else rect = [self _rectForDropHighlightViewOnRow:row]; - + [_dropOperationFeedbackView setDropOperation:row !== -1 ? dropOperation : CPDragOperationNone]; [_dropOperationFeedbackView setHidden:(dragOperation == CPDragOperationNone)]; [_dropOperationFeedbackView setFrame:rect]; @@ -3144,7 +3193,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; we're using this because we drag views instead of images so we can get the rows themselves to actually drag */ - (void)draggedView:(CPImage)aView endedAt:(CGPoint)aLocation operation:(CPDragOperation)anOperation -{ +{ [self _draggingEnded]; [self draggedImage:aView endedAt:aLocation operation:anOperation]; } @@ -3181,7 +3230,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; else if (_allowsMultipleSelection) { newSelection = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(MIN(aRow, _selectionAnchorRow), ABS(aRow - _selectionAnchorRow) + 1)]; - shouldExtendSelection = [self mouseDownFlags] & CPShiftKeyMask && + shouldExtendSelection = [self mouseDownFlags] & CPShiftKeyMask && ((_lastSelectedRow == [_selectedRowIndexes lastIndex] && aRow > _lastSelectedRow) || (_lastSelectedRow == [_selectedRowIndexes firstIndex] && aRow < _lastSelectedRow)); } @@ -3218,9 +3267,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [newSelection removeIndex:index]; } } - + _lastSelectedRow = ([newSelection count] > 0) ? aRow : -1; - + // if empty selection is not allowed and the new selection has nothing selected, abort if (!_allowsEmptySelection && [newSelection count] === 0) return; @@ -3319,10 +3368,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; 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 @@ -3334,24 +3383,24 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; 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 >= 0) [self scrollRowToVisible:i]; } @@ -3364,6 +3413,25 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; @end +@implementation CPTableView (Bindings) + +- (void)_establishBindingsIfUnbound:(id)destination +{ + if ([[self infoForBinding:@"content"] objectForKey:CPObservedObjectKey] !== destination) + { + [self bind:@"content" toObject:destination withKeyPath:@"arrangedObjects" options:nil]; + //[self bind:@"sortDescriptors" toObject:destination withKeyPath:@"sortDescriptors" options:nil]; + //[self bind:@"selectionIndexes" toObject:destination withKeyPath:@"selectionIndexes" options:nil]; + } +} + +- (void)setContent:(CPArray)content +{ + [self reloadData]; +} + +@end + var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", CPTableViewDelegateKey = @"CPTableViewDelegateKey", CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey", @@ -3407,15 +3475,16 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", _rowHeight = [aCoder decodeFloatForKey:CPTableViewRowHeightKey]; else _rowHeight = 23.0; - + _intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey] || _CGSizeMake(0.0, 0.0); - + _gridColor = [aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor]; _gridStyleMask = [aCoder decodeIntForKey:CPTableViewGridStyleMaskKey] || CPTableViewGridNone; - _alternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewAlternatingRowColorsKey]; - _usesAlternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewUsesAlternatingBackgroundKey] - + _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]]; + _headerView = [aCoder decodeObjectForKey:CPTableViewHeaderViewKey]; _cornerView = [aCoder decodeObjectForKey:CPTableViewCornerViewKey]; @@ -3439,7 +3508,7 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", [aCoder encodeFloat:_rowHeight forKey:CPTableViewRowHeightKey]; [aCoder encodeSize:_intercellSpacing forKey:CPTableViewIntercellSpacingKey]; - + [aCoder encodeBool:_allowsMultipleSelection forKey:CPTableViewMultipleSelectionKey]; [aCoder encodeBool:_allowsEmptySelection forKey:CPTableViewEmptySelectionKey]; [aCoder encodeBool:_allowsColumnReordering forKey:CPTableViewColumnReorderingKey]; @@ -3447,10 +3516,10 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", [aCoder encodeBool:_allowsColumnSelection forKey:CPTableViewColumnSelectionKey]; [aCoder encodeObject:_tableColumns forKey:CPTableViewTableColumnsKey]; - + [aCoder encodeObject:_gridColor forKey:CPTableViewGridColorKey]; [aCoder encodeInt:_gridStyleMask forKey:CPTableViewGridStyleMaskKey]; - + [aCoder encodeBool:_usesAlternatingRowBackgroundColors forKey:CPTableViewUsesAlternatingBackgroundKey]; [aCoder encodeObject:_alternatingRowBackgroundColors forKey:CPTableViewAlternatingRowColorsKey] @@ -3495,17 +3564,17 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", { if(tableView._destinationDragStyle === CPTableViewDraggingDestinationFeedbackStyleNone || isBlinking) return; - + var context = [[CPGraphicsContext currentContext] graphicsPort]; CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"4886ca"]); CGContextSetLineWidth(context, 3); - + if (currentRow === -1) { CGContextStrokeRect(context, [self bounds]); } - + else if (dropOperation === CPTableViewDropOn) { //if row is selected don't fill and stroke white @@ -3524,7 +3593,7 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", } CGContextStrokeRoundedRectangleInRect(context, newRect, 8, YES, YES, YES, YES); - } + } else if (dropOperation === CPTableViewDropAbove) { //reposition the view up a tad diff --git a/AppKit/CPText.j b/AppKit/CPText.j new file mode 100644 index 000000000..4ac6354d4 --- /dev/null +++ b/AppKit/CPText.j @@ -0,0 +1,32 @@ +/* + * CPText.j + * AppKit + * + * Created by Alexander Ljungberg. + * Copyright 2010, WireLoad, LLC. + * + * 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 "CPView.j" + +CPEnterCharacter = "\u0003"; +CPBackspaceCharacter = "\u0008"; +CPTabCharacter = "\u0009"; +CPNewlineCharacter = "\u000a"; +CPFormFeedCharacter = "\u000c"; +CPCarriageReturnCharacter = "\u000d"; +CPBackTabCharacter = "\u0019"; +CPDeleteCharacter = "\u007f"; diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 346301121..d3873e524 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -536,12 +536,12 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); CPTextFieldInputIsActive = NO; if (document.attachEvent) - { - CPTextFieldCachedSelectStartFunction = nil; - CPTextFieldCachedDragFunction = nil; - + { [[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction; [[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction; + + CPTextFieldCachedSelectStartFunction = nil; + CPTextFieldCachedDragFunction = nil; } #endif @@ -574,20 +574,46 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); // Don't track! (ever?) if ([self isEditable] && [self isEnabled]) return [[self window] makeFirstResponder:self]; + else if ([self isSelectable]) + { + if (document.attachEvent) + { + CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart; + CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag; + + [[self window] platformWindow]._DOMBodyElement.ondrag = function () {}; + [[self window] platformWindow]._DOMBodyElement.onselectstart = function () {}; + } + return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES]; + } else return [[self nextResponder] mouseDown:anEvent]; } - (void)mouseUp:(CPEvent)anEvent { - if (![self isEditable] || ![self isEnabled]) + if (![self isSelectable] && (![self isEditable] || ![self isEnabled])) [[self nextResponder] mouseUp:anEvent]; + else if ([self isSelectable]) + { + if (document.attachEvent) + { + [[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction; + [[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction; + + CPTextFieldCachedSelectStartFunction = nil + CPTextFieldCachedDragFunction = nil; + } + return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES]; + } } - (void)mouseDragged:(CPEvent)anEvent { - if (![self isEditable] || ![self isEnabled]) + if (![self isSelectable] && (![self isEditable] || ![self isEnabled])) [[self nextResponder] mouseDragged:anEvent]; + else if ([self isSelectable]) + return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES]; } - (void)keyUp:(CPEvent)anEvent diff --git a/AppKit/CPToolbar.j b/AppKit/CPToolbar.j index f78f891b6..b45d70211 100644 --- a/AppKit/CPToolbar.j +++ b/AppKit/CPToolbar.j @@ -329,7 +329,11 @@ var CPToolbarConfigurationsByIdentifier = nil; return _itemsSortedByVisibilityPriority; } -- (void)validateVisibleToolbarItems +/*! + Validates the visible toolbar items by sending a validate message to + each visible toolbar item. +*/ +- (void)validateVisibleItems { var toolbarItems = [self visibleItems], count = [toolbarItems count]; diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 3085a06fe..56025cd47 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -1679,7 +1679,7 @@ setBoundsOrigin: var theWindow = [self window]; [theWindow _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; - [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes] + [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]; [theWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes]; _registeredDraggedTypesArray = nil; diff --git a/AppKit/CPViewAnimation.j b/AppKit/CPViewAnimation.j index b1bc4d414..594b638a2 100644 --- a/AppKit/CPViewAnimation.j +++ b/AppKit/CPViewAnimation.j @@ -79,9 +79,9 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut"; while (animationIndex--) { var dictionary = [_viewAnimations objectAtIndex:animationIndex], - view = [self _targetView:dictionary] - startFrame = [self _startFrame:dictionary] - endFrame = [self _endFrame:dictionary] + view = [self _targetView:dictionary], + startFrame = [self _startFrame:dictionary], + endFrame = [self _endFrame:dictionary], differenceFrame = _CGRectMakeZero(); differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index f06953ab1..caf713d63 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -194,13 +194,13 @@ var SHADOW_MARGIN_LEFT = 20.0, SHADOW_MARGIN_TOP = 10.0, SHADOW_MARGIN_BOTTOM = 10.0, SHADOW_DISTANCE = 5.0, - + _CPWindowShadowColor = nil; - + var CPWindowSaveImage = nil, CPWindowSavingImage = nil; -/*! +/*! @ingroup appkit @class CPWindow @@ -213,33 +213,33 @@ var CPWindowSaveImage = nil,

A window always contains a content view which is the highest level view available for public (application) use. This view fills the area of the window inside any decoration/border. This is the only part of the window that application programmers are allowed to draw in directly.

You can convert between view coordinates and window base coordinates using the [CPView -convertPoint:fromView:], [CPView -convertPoint:toView:], [CPView -convertRect:fromView:], and [CPView -convertRect:toView:] methods with a nil view argument. - + @par Delegate Methods - + @delegate -(void)windowDidResize:(CPNotification)notification; Sent from the notification center when the window has been resized. @param notification contains information about the resize event - + @delegate -(CPUndoManager)windowWillReturnUndoManager:(CPWindow)window; Called to obtain the undo manager for a window @param window the window for which to return the undo manager @return the window's undo manager - + @delegate -(void)windowDidBecomeMain:(CPNotification)notification; Sent from the notification center when the delegate's window becomes the main window. @param notification contains information about the event - + @delegate -(void)windowDidResignMain:(CPNotification)notification; Sent from the notification center when the delegate's window has resigned main window status. @param notification contains information about the event - + @delegate -(void)windowDidResignKey:(CPNotification)notification; Sent from the notification center when the delegate's window has resigned key window status. @param notification contains information about the event - + @delegate -(BOOL)windowShouldClose:(id)window; Called when the user tries to close the window. @param window the window to close @@ -311,12 +311,12 @@ var CPWindowSaveImage = nil, #endif unsigned _autoresizingMask; - + BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector; BOOL _isFullPlatformWindow; _CPWindowFullPlatformWindowSession _fullPlatformWindowSession; - + CPDictionary _sheetContext; CPWindow _parentView; BOOL _isSheet; @@ -330,9 +330,9 @@ var CPWindowSaveImage = nil, { if (self != [CPWindow class]) return; - + var bundle = [CPBundle bundleForClass:[CPWindow class]]; - + CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)] } @@ -359,7 +359,7 @@ CPTexturedBackgroundWindowMask - (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask { self = [super init]; - + if (self) { var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask]; @@ -393,7 +393,7 @@ CPTexturedBackgroundWindowMask // Set up our window number. _windowNumber = [CPApp._windows count]; CPApp._windows[_windowNumber] = self; - + _styleMask = aStyleMask; [self setLevel:CPNormalWindowLevel]; @@ -408,15 +408,15 @@ CPTexturedBackgroundWindowMask [_windowView setNextResponder:self]; [self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask]; - + // Create a generic content view. [self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]]; - + _firstResponder = self; #if PLATFORM(DOM) _DOMElement = document.createElement("div"); - + _DOMElement.style.position = "absolute"; _DOMElement.style.visibility = "visible"; _DOMElement.style.zIndex = 0; @@ -442,7 +442,7 @@ CPTexturedBackgroundWindowMask [self setShowsResizeIndicator:_styleMask & CPResizableWindowMask]; } - + return self; } @@ -660,7 +660,7 @@ CPTexturedBackgroundWindowMask if (shouldAnimate) { var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; - + [animation startAnimation]; } else @@ -742,8 +742,10 @@ CPTexturedBackgroundWindowMask */ - (void)orderFront:(id)aSender { +#if PLATFORM(DOM) [_platformWindow orderFront:self]; [_platformWindow order:CPWindowAbove window:self relativeTo:nil]; +#endif if (_firstResponder === self || !_firstResponder) [self makeFirstResponder:[self initialFirstResponder]]; @@ -771,13 +773,17 @@ CPTexturedBackgroundWindowMask */ - (void)orderOut:(id)aSender { +#if PLATFORM(DOM) if ([self _sharesChromeWithPlatformWindow]) [_platformWindow orderOut:self]; +#endif if ([_delegate respondsToSelector:@selector(windowWillClose:)]) [_delegate windowWillClose:self]; +#if PLATFORM(DOM) [_platformWindow order:CPWindowOut window:self relativeTo:nil]; +#endif [self _updateMainAndKeyWindows]; } @@ -789,7 +795,9 @@ CPTexturedBackgroundWindowMask */ - (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber { +#if PLATFORM(DOM) [_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]]; +#endif } /*! @@ -874,12 +882,12 @@ CPTexturedBackgroundWindowMask { if (_contentView) [_contentView removeFromSuperview]; - + var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)); - + _contentView = aView; [_contentView setFrame:[self contentRectForFrameRect:bounds]]; - + [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_windowView addSubview:_contentView]; } @@ -935,24 +943,24 @@ CPTexturedBackgroundWindowMask { if (CGSizeEqualToSize(_minSize, aSize)) return; - + _minSize = CGSizeCreateCopy(aSize); var size = CGSizeMakeCopy([self frame].size), needsFrameChange = NO; - + if (size.width < _minSize.width) { size.width = _minSize.width; needsFrameChange = YES; } - + if (size.height < _minSize.height) { size.height = _minSize.height; needsFrameChange = YES; } - + if (needsFrameChange) [self setFrameSize:size]; } @@ -975,24 +983,24 @@ CPTexturedBackgroundWindowMask { if (CGSizeEqualToSize(_maxSize, aSize)) return; - + _maxSize = CGSizeCreateCopy(aSize); var size = CGSizeMakeCopy([self frame].size), needsFrameChange = NO; - + if (size.width > _maxSize.width) { size.width = _maxSize.width; needsFrameChange = YES; } - + if (size.height > _maxSize.height) { size.height = _maxSize.height; needsFrameChange = YES; } - + if (needsFrameChange) [self setFrameSize:size]; } @@ -1033,10 +1041,10 @@ CPTexturedBackgroundWindowMask if (_hasShadow && !_shadowView) { var bounds = [_windowView bounds]; - - _shadowView = [[CPView alloc] initWithFrame:CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE, + + _shadowView = [[CPView alloc] initWithFrame:CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE, SHADOW_MARGIN_LEFT + CGRectGetWidth(bounds) + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_TOP + CGRectGetHeight(bounds) + SHADOW_MARGIN_BOTTOM)]; - + if (!_CPWindowShadowColor) { var bundle = [CPBundle bundleForClass:[CPWindow class]]; @@ -1059,7 +1067,7 @@ CPTexturedBackgroundWindowMask [_shadowView setBackgroundColor:_CPWindowShadowColor]; [_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; - + #if PLATFORM(DOM) CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement); #endif @@ -1125,7 +1133,7 @@ CPTexturedBackgroundWindowMask selector:@selector(windowDidBecomeKey:) name:CPWindowDidBecomeKeyNotification object:self]; - + if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)]) [defaultCenter addObserver:_delegate @@ -1221,7 +1229,7 @@ CPTexturedBackgroundWindowMask if(!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder]) { _firstResponder = self; - + return NO; } @@ -1274,9 +1282,9 @@ CPTexturedBackgroundWindowMask - (void)setTitle:(CPString)aTitle { _title = aTitle; - + [_windowView setTitle:aTitle]; - + [self _synchronizeMenuBarTitleWithWindowTitle]; } @@ -1528,7 +1536,7 @@ CPTexturedBackgroundWindowMask - (void)makeKeyAndOrderFront:(id)aSender { [self orderFront:self]; - + [self makeKeyWindow]; [self makeMainWindow]; } @@ -1592,7 +1600,7 @@ CPTexturedBackgroundWindowMask if (!pasteboardTypes) return; - [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes] + [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]; if ([_inclusiveRegisteredDraggedTypes count] === 0) _inclusiveRegisteredDraggedTypes = nil; @@ -1623,7 +1631,7 @@ CPTexturedBackgroundWindowMask return; [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; - [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes] + [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]; [self _noteRegisteredDraggedTypes:_registeredDraggedTypes]; _registeredDraggedTypesArray = nil; @@ -1636,7 +1644,7 @@ CPTexturedBackgroundWindowMask - (CPArray)registeredDraggedTypes { if (!_registeredDraggedTypesArray) - _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects] + _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]; return _registeredDraggedTypesArray; } @@ -1662,9 +1670,9 @@ CPTexturedBackgroundWindowMask { if (_isDocumentEdited == isDocumentEdited) return; - + _isDocumentEdited = isDocumentEdited; - + [CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0]; [_windowView setDocumentEdited:isDocumentEdited]; @@ -1682,11 +1690,11 @@ CPTexturedBackgroundWindowMask { if (_isDocumentSaving == isDocumentSaving) return; - + _isDocumentSaving = isDocumentSaving; - + [self _synchronizeSaveMenuWithDocumentSaving]; - + [_windowView windowDidChangeDocumentSaving]; } @@ -1703,16 +1711,16 @@ CPTexturedBackgroundWindowMask var mainMenu = [CPApp mainMenu], index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."]; - + if (index == CPNotFound) return; - + var item = [mainMenu itemAtIndex:index]; - + if (_isDocumentSaving) { CPWindowSaveImage = [item image]; - + [item setTitle:@"Saving..."]; [item setImage:CPWindowSavingImage]; [item setEnabled:NO]; @@ -1802,7 +1810,7 @@ CPTexturedBackgroundWindowMask if (![_delegate windowShouldClose:self]) return; } - + // Only check self is delegate does NOT implement this. This also ensures this when delegate == self (returns true). else if ([self respondsToSelector:@selector(windowShouldClose:)] && ![self windowShouldClose:self]) return; @@ -1812,8 +1820,8 @@ CPTexturedBackgroundWindowMask { var index = [documents indexOfObject:[_windowController document]]; - [documents[index] shouldCloseWindowController:_windowController - delegate:self + [documents[index] shouldCloseWindowController:_windowController + delegate:self shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) contextInfo:{documents:[documents copy], visited:0, index:index}]; } @@ -1837,8 +1845,8 @@ CPTexturedBackgroundWindowMask { [windowController setDocument:documents[index]]; - [documents[index] shouldCloseWindowController:_windowController - delegate:self + [documents[index] shouldCloseWindowController:_windowController + delegate:self shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) contextInfo:context]; } @@ -1875,7 +1883,7 @@ CPTexturedBackgroundWindowMask // FIXME: Also check if we can resize and titlebar. if ([self isVisible]) return YES; - + return NO; } @@ -1997,25 +2005,25 @@ CPTexturedBackgroundWindowMask { if (_toolbar === aToolbar) return; - + // If this has an owner, dump it! [[aToolbar _window] setToolbar:nil]; - + // This is no longer out toolbar. [_toolbar _setWindow:nil]; - + _toolbar = aToolbar; - + // THIS is our toolbar. [_toolbar _setWindow:self]; - + [self _noteToolbarChanged]; } - (void)toggleToolbarShown:(id)aSender { var toolbar = [self toolbar]; - + [toolbar setVisible:![toolbar isVisible]]; } @@ -2031,10 +2039,10 @@ CPTexturedBackgroundWindowMask else { newFrame = CGRectMakeCopy([self frame]); - + newFrame.origin = frame.origin; } - + [self setFrame:newFrame]; /* [_windowView setAnimatingToolbar:YES]; @@ -2060,7 +2068,7 @@ CPTexturedBackgroundWindowMask var attachedSheet = [self attachedSheet]; var contentRect = [[self contentView] frame], sheetFrame = CGRectMakeCopy([attachedSheet frame]); - + sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect); sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0); @@ -2072,8 +2080,8 @@ CPTexturedBackgroundWindowMask { var sheetFrame = [aSheet frame]; - _sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO}; - + _sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO}; + [self _attachSheetWindow:aSheet]; } @@ -2083,12 +2091,12 @@ CPTexturedBackgroundWindowMask var sheetFrame = [aSheet frame], frame = [self frame], sheetContent = [aSheet contentView]; - + [self _setUpMasksForView:sheetContent]; - + aSheet._isSheet = YES; aSheet._parentView = self; - + var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2), originy = frame.origin.y + [[self contentView] frame].origin.y, startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0), @@ -2096,7 +2104,7 @@ CPTexturedBackgroundWindowMask [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self]; [CPApp runModalForWindow:aSheet]; - + [aSheet orderFront:self]; [aSheet setFrame:startFrame display:YES animate:NO]; _sheetContext["opened"] = YES; @@ -2104,7 +2112,7 @@ CPTexturedBackgroundWindowMask [aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut]; // Should run the main loop here until _isAnimating = FALSE - [aSheet becomeKeyWindow]; + [aSheet becomeKeyWindow]; } /* @ignore */ @@ -2115,9 +2123,9 @@ CPTexturedBackgroundWindowMask endFrame = CGRectMakeCopy(startFrame); endFrame.size.height = 0; - + _sheetContext["frame"] = startFrame; - + var sheetContent = [sheet contentView]; [self _setUpMasksForView:sheetContent]; @@ -2133,27 +2141,27 @@ CPTexturedBackgroundWindowMask return; var sheetContent = [sheet contentView]; - + if (_sheetContext["opened"] === YES) { [self _restoreMasksForView:sheetContent]; return; } - - [CPApp stopModal]; + + [CPApp stopModal]; [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self]; [sheet orderOut:self]; var lastFrame = _sheetContext["frame"]; [sheet setFrame:lastFrame]; - + [self _restoreMasksForView:sheetContent]; var delegate = _sheetContext["modalDelegate"], endSelector = _sheetContext["endSelector"]; - if (delegate != nil && endSelector != nil) + if (delegate != nil && endSelector != nil) objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]); _sheetContext = nil; @@ -2165,7 +2173,7 @@ CPTexturedBackgroundWindowMask var views = [aView subviews]; [views addObject:aView]; - + for (var i = 0, count = [views count]; i < count; i++) { var view = [views objectAtIndex:i], @@ -2181,7 +2189,7 @@ CPTexturedBackgroundWindowMask var views = [aView subviews]; [views addObject:aView]; - + for (var i = 0, count = [views count]; i < count; i++) { var view = [views objectAtIndex:i], @@ -2199,7 +2207,7 @@ CPTexturedBackgroundWindowMask { if (_sheetContext === nil) return nil; - + return _sheetContext["sheet"]; } @@ -2280,7 +2288,7 @@ CPTexturedBackgroundWindowMask - (void)recalculateKeyViewLoop { var subviews = []; - + [self _appendSubviewsOf:_contentView toArray:subviews]; var keyViewOrder = [subviews sortedArrayUsingFunction:keyViewComparator context:_contentView], @@ -2288,7 +2296,7 @@ CPTexturedBackgroundWindowMask for (var i=0; i @import "CPEvent.j" +@import "CPText.j" @import "CPCompatibility.j" @import "CPDOMWindowLayer.j" @@ -138,10 +139,23 @@ var KeyCodesToPrevent = {}, MozKeyCodeToKeyCodeMap = { 61: 187, // =, equals 59: 186 // ;, semicolon - }; + }, + KeyCodesToFunctionUnicodeMap = {}; 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; + var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; @implementation CPPlatformWindow (DOM) @@ -306,11 +320,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; keyEventSelector = @selector(keyEvent:), keyEventImplementation = class_getMethodImplementation(theClass, keyEventSelector), keyEventCallback = function (anEvent) { keyEventImplementation(self, nil, anEvent); }, - + mouseEventSelector = @selector(mouseEvent:), mouseEventImplementation = class_getMethodImplementation(theClass, mouseEventSelector), mouseEventCallback = function (anEvent) { mouseEventImplementation(self, nil, anEvent); }, - + contextMenuEventSelector = @selector(contextMenuEvent:), contextMenuEventImplementation = class_getMethodImplementation(theClass, contextMenuEventSelector), contextMenuEventCallback = function (anEvent) { return contextMenuEventImplementation(self, nil, anEvent); }, @@ -318,7 +332,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; scrollEventSelector = @selector(scrollEvent:), scrollEventImplementation = class_getMethodImplementation(theClass, scrollEventSelector), scrollEventCallback = function (anEvent) { scrollEventImplementation(self, nil, anEvent); }, - + touchEventSelector = @selector(touchEvent:), touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector), touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); }; @@ -356,7 +370,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _DOMWindow.addEventListener("DOMMouseScroll", scrollEventCallback, NO); _DOMWindow.addEventListener("mousewheel", scrollEventCallback, NO); - _DOMWindow.addEventListener("resize", resizeEventCallback, NO); + _DOMWindow.addEventListener("resize", resizeEventCallback, NO); _DOMWindow.addEventListener("unload", function() { @@ -400,16 +414,16 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; theDocument.attachEvent("onmousemove", mouseEventCallback); theDocument.attachEvent("ondblclick", mouseEventCallback); theDocument.attachEvent("oncontextmenu", contextMenuEventCallback); - + theDocument.attachEvent("onkeyup", keyEventCallback); theDocument.attachEvent("onkeydown", keyEventCallback); theDocument.attachEvent("onkeypress", keyEventCallback); - + _DOMWindow.attachEvent("onresize", resizeEventCallback); - + _DOMWindow.onmousewheel = scrollEventCallback; theDocument.onmousewheel = scrollEventCallback; - + _DOMBodyElement.ondrag = function () { return NO; }; _DOMBodyElement.onselectstart = function () { return _DOMWindow.event.srcElement === _DOMPasteboardElement; }; @@ -596,12 +610,12 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), windowNumber = [[CPApp keyWindow] windowNumber], - modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | - (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | - (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | + modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | + (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | + (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | (aDOMEvent.metaKey ? CPCommandKeyMask : 0); - //We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist + //We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist StopDOMEventPropagation = !!(!(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) || CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] || KeyCodesToPrevent[aDOMEvent.keyCode]); @@ -618,7 +632,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; else _keyCode = aDOMEvent.keyCode; - var characters = String.fromCharCode(_keyCode).toLowerCase(); + var characters = KeyCodesToFunctionUnicodeMap[_keyCode] || String.fromCharCode(_keyCode).toLowerCase(); overrideCharacters = (modifierFlags & CPShiftKeyMask || _capsLockActive) ? characters.toUpperCase() : characters; // check for caps lock state @@ -633,7 +647,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; var eligibleForCopyPaste = [self _validateCopyCutOrPasteEvent:aDOMEvent flags:modifierFlags]; - // If this could be a native PASTE event, then we need to further examine it before + // If this could be a native PASTE event, then we need to further examine it before // sending a CPEvent. Select our element to see if anything gets pasted in it. if (characters === "v" && eligibleForCopyPaste) { @@ -646,7 +660,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; isNativePasteEvent = YES; } - // However, of this could be a native COPY event, we need to let the normal event-process take place so it + // However, of this could be a native COPY event, we need to let the normal event-process take place so it // can capture our internal Cappuccino pasteboard. else if ((characters == "c" || characters == "x") && eligibleForCopyPaste) { @@ -668,10 +682,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; //this branch is taken by "remedial" key events // In this state we continue to keypress and send the CPEvent } - + case "keypress": - // we unconditionally break on keypress events with modifiers, - // because we forced the event to be sent on the keydown + // we unconditionally break on keypress events with modifiers, + // because we forced the event to be sent on the keydown if (aDOMEvent.type === "keypress" && (modifierFlags & (CPControlKeyMask | CPCommandKeyMask))) break; @@ -682,7 +696,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _lastKey = keyCode; _charCodes[keyCode] = charCode; - var characters = overrideCharacters || String.fromCharCode(charCode), + var characters = overrideCharacters || KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), charactersIgnoringModifiers = characters.toLowerCase(); // Safari won't send proper capitalization during cmd-key events @@ -700,10 +714,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; } break; - + case "keyup": var keyCode = aDOMEvent.keyCode, charCode = _charCodes[keyCode]; - + _keyCode = -1; _lastKey = -1; _charCodes[keyCode] = nil; @@ -714,12 +728,12 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (keyCode === CPKeyCodes.CAPS_LOCK) _capsLockActive = NO; - var characters = String.fromCharCode(charCode), + var characters = KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), charactersIgnoringModifiers = characters.toLowerCase(); - + if (!(modifierFlags & CPShiftKeyMask) && (modifierFlags & CPCommandKeyMask) && !_capsLockActive) characters = charactersIgnoringModifiers; - + event = [CPEvent keyEventWithType:CPKeyUp location:location modifierFlags:modifierFlags timestamp: timestamp windowNumber:windowNumber context:nil characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:keyCode]; @@ -867,10 +881,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; { x += element.offsetLeft; y += element.offsetTop; - + } while (element = element.offsetParent); } - + location = _CGPointMake((x + ((aDOMEvent.clientX - 8) / 15)), (y + ((aDOMEvent.clientY - 8) / 15))); } else if (aDOMEvent._overrideLocation) @@ -882,9 +896,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; deltaY = 0.0, windowNumber = 0, timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), - modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | - (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | - (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | + modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | + (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | + (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | (aDOMEvent.metaKey ? CPCommandKeyMask : 0); StopDOMEventPropagation = YES; @@ -903,31 +917,31 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; deltaX = aDOMEvent.wheelDeltaX / 120.0; deltaY = aDOMEvent.wheelDeltaY / 120.0; } - + else if (aDOMEvent.wheelDelta) deltaY = aDOMEvent.wheelDelta / 120.0; - - else if (aDOMEvent.detail) + + else if (aDOMEvent.detail) deltaY = -aDOMEvent.detail / 3.0; - + else - return; + return; if(!CPFeatureIsCompatible(CPJavaScriptNegativeMouseWheelValues)) { deltaX = -deltaX; deltaY = -deltaY; } - + var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0 ]; - + event._DOMEvent = aDOMEvent; event._deltaX = deltaX; event._deltaY = deltaY; - + [CPApp sendEvent:event]; - + if (StopDOMEventPropagation) CPDOMEventStop(aDOMEvent, self); @@ -970,7 +984,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (aDOMEvent.touches && (aDOMEvent.touches.length == 1 || (aDOMEvent.touches.length == 0 && aDOMEvent.changedTouches.length == 1))) { var newEvent = {}; - + switch(aDOMEvent.type) { case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown; @@ -984,27 +998,27 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; } var touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0]; - + newEvent.clientX = touch.clientX; newEvent.clientY = touch.clientY; - + newEvent.timestamp = aDOMEvent.timestamp; newEvent.target = aDOMEvent.target; - + newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false; - + newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()}; newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()}; - + [self mouseEvent:newEvent]; - + return; } else { if (aDOMEvent.preventDefault) aDOMEvent.preventDefault(); - + if (aDOMEvent.stopPropagation) aDOMEvent.stopPropagation(); } @@ -1026,7 +1040,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _overriddenEventType = nil; - return; + return; } var event, @@ -1034,9 +1048,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), windowNumber = 0, - modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | - (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | - (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | + modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | + (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | + (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | (aDOMEvent.metaKey ? CPCommandKeyMask : 0); StopDOMEventPropagation = YES; @@ -1062,7 +1076,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if(_mouseIsDown) { event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0); - + _mouseIsDown = NO; _lastMouseUp = event; _mouseDownWindow = nil; @@ -1075,7 +1089,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; return; } } - + else if (type === "mousedown") { if (sourceElement.tagName === "INPUT" && sourceElement != _DOMFocusElement) @@ -1091,11 +1105,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; //fake a down and up event so that event tracking mode will work correctly [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:location modifierFlags:modifierFlags - timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 + timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]]; [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseUp location:location modifierFlags:modifierFlags - timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 + timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]]; return; @@ -1116,7 +1130,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _mouseIsDown = YES; _lastMouseDown = event; } - + else // if (type === "mousemove" || type === "drag") { if (_DOMEventMode) @@ -1130,7 +1144,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (event && (!isDragging || !supportsNativeDragAndDrop)) { event._DOMEvent = aDOMEvent; - + [CPApp sendEvent:event]; } @@ -1157,7 +1171,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (!layer) return []; - + return [layer orderedWindows]; } @@ -1170,19 +1184,19 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (!layer && aFlag) { layer = [[CPDOMWindowLayer alloc] initWithLevel:aLevel]; - + [_windowLayers setObject:layer forKey:aLevel]; - // Find the nearest layer. This is similar to a binary search, + // Find the nearest layer. This is similar to a binary search, // only we know we won't find the value. var low = 0, high = _windowLevels.length - 1, middle; - + while (low <= high) { middle = FLOOR((low + high) / 2); - + if (_windowLevels[middle] > aLevel) high = middle - 1; else @@ -1190,7 +1204,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; } var insertionIndex = 0; - if (middle !== undefined) + if (middle !== undefined) insertionIndex = _windowLevels[middle] > aLevel ? middle : middle + 1 [_windowLevels insertObject:aLevel atIndex:insertionIndex]; @@ -1198,7 +1212,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _DOMBodyElement.appendChild(layer._DOMElement); } - + return layer; } @@ -1206,11 +1220,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; { [CPPlatform initializeScreenIfNecessary]; - // Grab the appropriate level for the layer, and create it if + // Grab the appropriate level for the layer, and create it if // necessary (if we are not simply removing the window). var layer = [self layerAtLevel:[aWindow level] create:aPlace !== CPWindowOut]; - // Ignore otherWindow, simply remove this window from it's level. + // Ignore otherWindow, simply remove this window from it's level. // If layer is nil, this will be a no-op. if (aPlace === CPWindowOut) return [layer removeWindow:aWindow]; @@ -1263,10 +1277,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; // Skip any windows above or at the dragging level. if (levels[levelCount] >= CPDraggingWindowLevel) continue; - + var windows = [layers objectForKey:levels[levelCount]]._windows, windowCount = windows.length; - + while (windowCount--) { var theWindow = windows[windowCount]; @@ -1278,7 +1292,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; return [theWindow _dragHitTest:aPoint pasteboard:aPasteboard]; } } - + return nil; } @@ -1308,7 +1322,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; - (CPWindow)hitTest:(CPPoint)location { - if (self._only) + if (self._only) return self._only; var levels = _windowLevels, @@ -1324,7 +1338,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; while (windowCount-- && !theWindow) { var candidateWindow = windows[windowCount]; - + if (!candidateWindow._ignoresMouseEvents && [candidateWindow containsPoint:location]) theWindow = candidateWindow; } @@ -1334,10 +1348,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; } /*! - When using command (mac) or control (windows), keys are propagated to the browser by default. + When using command (mac) or control (windows), keys are propagated to the browser by default. To prevent a character key from propagating (to prevent its default action, and instead use it in your own application), use these methods. These methods are additive -- the list builds until you clear it. - + @param characters a list of characters to stop propagating keypresses to the browser. */ + (void)preventCharacterKeysFromPropagating:(CPArray)characters @@ -1418,11 +1432,11 @@ var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation) { if (!aComparisonEvent) return 1; - + var comparisonLocation = [aComparisonEvent locationInWindow]; - - return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA && - ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA && + + return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA && + ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA && ABS(comparisonLocation.y - aLocation.y) < CLICK_SPACE_DELTA) ? [aComparisonEvent clickCount] + 1 : 1; } diff --git a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-center.png b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-center.png index 6b3e348c1..cc9401c73 100644 Binary files a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-center.png and b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-disabled-center.png b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-disabled-center.png new file mode 100644 index 000000000..dd4ce2152 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-disabled-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-disabled-left.png b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-disabled-left.png new file mode 100644 index 000000000..a615b9382 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-disabled-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-disabled-right.png b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-disabled-right.png new file mode 100644 index 000000000..6f14f35d8 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-disabled-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-center.png b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-center.png index 0f35e8c4b..be25a32af 100644 Binary files a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-center.png and b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-left.png b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-left.png index fe9f27411..a4b766ac2 100644 Binary files a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-left.png and b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-right.png b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-right.png index 809339ae4..cd709f319 100644 Binary files a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-right.png and b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-highlighted-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-left.png b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-left.png index 6c10bf51e..674aacd37 100644 Binary files a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-left.png and b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-right.png b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-right.png index 91439ae90..88a8540cc 100644 Binary files a/AppKit/Themes/Aristo/Resources/HUD/button-bezel-right.png and b/AppKit/Themes/Aristo/Resources/HUD/button-bezel-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-center.png b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-center.png new file mode 100644 index 000000000..bc5b3a93b Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-disabled-center.png b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-disabled-center.png new file mode 100644 index 000000000..8289aed50 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-disabled-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-disabled-left.png b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-disabled-left.png new file mode 100644 index 000000000..b0e2c0ac5 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-disabled-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-disabled-right.png b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-disabled-right.png new file mode 100644 index 000000000..25dac55c3 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-disabled-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-highlighted-center.png b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-highlighted-center.png new file mode 100644 index 000000000..79e37a1a4 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-highlighted-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-highlighted-left.png b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-highlighted-left.png new file mode 100644 index 000000000..19b884419 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-highlighted-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-highlighted-right.png b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-highlighted-right.png new file mode 100644 index 000000000..da0cb9a8a Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-highlighted-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-left.png b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-left.png new file mode 100644 index 000000000..dd02f1725 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-right.png b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-right.png new file mode 100644 index 000000000..e32647f97 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/default-button-bezel-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-center.png b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-center.png new file mode 100644 index 000000000..b565d8e6a Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-disabled-center.png b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-disabled-center.png new file mode 100644 index 000000000..31da63ab7 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-disabled-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-disabled-left.png b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-disabled-left.png new file mode 100644 index 000000000..e395935df Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-disabled-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-disabled-right.png b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-disabled-right.png new file mode 100644 index 000000000..d752a54ec Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-disabled-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-left.png b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-left.png new file mode 100644 index 000000000..05ff0804e Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-right.png b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-right.png new file mode 100644 index 000000000..db4488023 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/horizontal-track-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/knob-disabled.png b/AppKit/Themes/Aristo/Resources/HUD/knob-disabled.png new file mode 100644 index 000000000..fc6e54041 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/knob-disabled.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/knob-highlighted.png b/AppKit/Themes/Aristo/Resources/HUD/knob-highlighted.png new file mode 100644 index 000000000..5c4387a55 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/knob-highlighted.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/knob.png b/AppKit/Themes/Aristo/Resources/HUD/knob.png new file mode 100755 index 000000000..bad25cf31 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/knob.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-center.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-center.png new file mode 100644 index 000000000..455b25dec Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-center.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-center.png new file mode 100644 index 000000000..a32359e5c Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-divider.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-divider.png new file mode 100644 index 000000000..a07b15d5c Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-divider.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-left.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-left.png new file mode 100644 index 000000000..cca119c66 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-right.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-right.png new file mode 100644 index 000000000..9f3a03b7d Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-disabled-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-divider.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-divider.png new file mode 100644 index 000000000..6811fc89a Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-divider.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-center.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-center.png new file mode 100644 index 000000000..ac04df7bb Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-center.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-center.png new file mode 100644 index 000000000..06105ca17 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-divider.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-divider.png new file mode 100644 index 000000000..513282884 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-divider.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-left.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-left.png new file mode 100644 index 000000000..e8bf1b6b0 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-right copy.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-right copy.png new file mode 100644 index 000000000..23587f095 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-right copy.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-right.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-right.png new file mode 100644 index 000000000..73880f0de Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-disabled-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-divider.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-divider.png new file mode 100644 index 000000000..6811fc89a Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-divider.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-left.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-left.png new file mode 100644 index 000000000..56ac58d65 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-right.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-right.png new file mode 100644 index 000000000..2941208e8 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-highlighted-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-left.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-left.png new file mode 100644 index 000000000..61b659212 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-center.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-center.png new file mode 100644 index 000000000..aa78a13bc Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-highlighted-center.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-highlighted-center.png new file mode 100644 index 000000000..dc64067fe Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-highlighted-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-highlighted-left.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-highlighted-left.png new file mode 100644 index 000000000..c81b5aba0 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-highlighted-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-highlighted-right.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-highlighted-right.png new file mode 100644 index 000000000..6eb94808d Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-highlighted-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-left.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-left.png new file mode 100644 index 000000000..a1c5e0323 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-left.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-right.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-right.png new file mode 100644 index 000000000..949864422 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-pushed-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-right.png b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-right.png new file mode 100644 index 000000000..12e90829c Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/segmented-control-bezel-right.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/slider-circular-bezel.png b/AppKit/Themes/Aristo/Resources/HUD/slider-circular-bezel.png new file mode 100644 index 000000000..69d5c29a9 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/slider-circular-bezel.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/slider-circular-disabled-bezel.png b/AppKit/Themes/Aristo/Resources/HUD/slider-circular-disabled-bezel.png new file mode 100644 index 000000000..9c54fa23e Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/slider-circular-disabled-bezel.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/slider-circular-disabled-knob.png b/AppKit/Themes/Aristo/Resources/HUD/slider-circular-disabled-knob.png new file mode 100644 index 000000000..5c0d8bd11 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/slider-circular-disabled-knob.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/slider-circular-knob.png b/AppKit/Themes/Aristo/Resources/HUD/slider-circular-knob.png new file mode 100644 index 000000000..050ffefe6 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/slider-circular-knob.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/vertical-track-bottom.png b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-bottom.png new file mode 100644 index 000000000..bdec63744 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-bottom.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/vertical-track-center.png b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-center.png new file mode 100644 index 000000000..2fbcce41e Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/vertical-track-disabled-bottom.png b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-disabled-bottom.png new file mode 100644 index 000000000..efc622a82 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-disabled-bottom.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/vertical-track-disabled-center.png b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-disabled-center.png new file mode 100644 index 000000000..25675211c Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-disabled-center.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/vertical-track-disabled-top.png b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-disabled-top.png new file mode 100644 index 000000000..12abe0927 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-disabled-top.png differ diff --git a/AppKit/Themes/Aristo/Resources/HUD/vertical-track-top.png b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-top.png new file mode 100644 index 000000000..a27c09e56 Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/HUD/vertical-track-top.png differ diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j old mode 100644 new mode 100755 index adc445107..d1d77ee49 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -788,38 +788,186 @@ return [CPColor blackColor]; } -+ (CPButton)themedButton ++ (CPPopUpButton)themedSegmentedControl { - var button = [[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 20.0)], + var segmentedControl = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 24.0)]; + + [segmentedControl setTrackingMode:CPSegmentSwitchTrackingSelectAny]; + [segmentedControl setSegmentCount:3]; + + [segmentedControl setWidth:40.0 forSegment:0]; + [segmentedControl setLabel:@"foo" forSegment:0]; + [segmentedControl setTag:1 forSegment:0]; + + [segmentedControl setWidth:60.0 forSegment:1]; + [segmentedControl setLabel:@"bar" forSegment:1]; + [segmentedControl setTag:2 forSegment:1]; + + [segmentedControl setWidth:35.0 forSegment:2]; + [segmentedControl setLabel:@"1" forSegment:2]; + [segmentedControl setTag:3 forSegment:2]; + + //various colors + var centerBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-center.png" size:CGSizeMake(1.0, 24.0)]), + dividerBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-divider.png" size:CGSizeMake(1.0, 24.0)]), + centerHighlightedBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)]), + dividerHighlightedBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-highlighted-divider.png" size:CGSizeMake(1.0, 24.0)]), + leftHighlightedBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-highlighted-left.png" size:CGSizeMake(4.0, 24.0)]), + rightHighlightedBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)]), + inactiveCenterBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-disabled-center.png" size:CGSizeMake(1.0, 24.0)]), + inactiveDividerBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-disabled-divider.png" size:CGSizeMake(1.0, 24.0)]), + inactiveLeftBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-disabled-left.png" size:CGSizeMake(4.0, 24.0)]), + inactiveRightBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-disabled-right.png" size:CGSizeMake(4.0, 24.0)]), + inactiveHighlightedCenterBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-highlighted-disabled-center.png" size:CGSizeMake(1.0, 24.0)]), + inactiveHighlightedDividerBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-highlighted-disabled-divider.png" size:CGSizeMake(1.0, 24.0)]), + inactiveHighlightedLeftBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-highlighted-disabled-left.png" size:CGSizeMake(4.0, 24.0)]), + inactiveHighlightedRightBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-highlighted-disabled-right.png" size:CGSizeMake(4.0, 24.0)]), + leftBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-left.png" size:CGSizeMake(4.0, 24.0)]), + rightBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-right.png" size:CGSizeMake(4.0, 24.0)]), + pushedCenterBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-pushed-center.png" size:CGSizeMake(1.0, 24.0)]), + pushedLeftBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-pushed-left.png" size:CGSizeMake(4.0, 24.0)]), + pushedRightBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-pushed-right.png" size:CGSizeMake(4.0, 24.0)]); + pushedHighlightedCenterBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-pushed-highlighted-center.png" size:CGSizeMake(1.0, 24.0)]), + pushedHighlightedLeftBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-pushed-highlighted-left.png" size:CGSizeMake(4.0, 24.0)]), + pushedHighlightedRightBezelColor = PatternColor([_CPCibCustomResource imageResourceWithName:@"HUD/segmented-control-bezel-pushed-highlighted-right.png" size:CGSizeMake(4.0, 24.0)]); + + [segmentedControl setValue:centerBezelColor forThemeAttribute:@"center-segment-bezel-color" inState:CPThemeStateNormal]; + [segmentedControl setValue:inactiveCenterBezelColor forThemeAttribute:@"center-segment-bezel-color" inState:CPThemeStateDisabled]; + [segmentedControl setValue:inactiveHighlightedCenterBezelColor forThemeAttribute:@"center-segment-bezel-color" inState:CPThemeStateSelected|CPThemeStateDisabled]; + [segmentedControl setValue:centerHighlightedBezelColor forThemeAttribute:@"center-segment-bezel-color" inState:CPThemeStateSelected]; + [segmentedControl setValue:pushedCenterBezelColor forThemeAttribute:@"center-segment-bezel-color" inState:CPThemeStateHighlighted]; + [segmentedControl setValue:pushedHighlightedCenterBezelColor forThemeAttribute:@"center-segment-bezel-color" inState:CPThemeStateHighlighted|CPThemeStateSelected]; + + [segmentedControl setValue:dividerBezelColor forThemeAttribute:@"divider-bezel-color" inState:CPThemeStateNormal]; + [segmentedControl setValue:inactiveDividerBezelColor forThemeAttribute:@"divider-bezel-color" inState:CPThemeStateDisabled]; + [segmentedControl setValue:inactiveHighlightedDividerBezelColor forThemeAttribute:@"divider-bezel-color" inState:CPThemeStateSelected|CPThemeStateDisabled]; + [segmentedControl setValue:dividerHighlightedBezelColor forThemeAttribute:@"divider-bezel-color" inState:CPThemeStateSelected]; + [segmentedControl setValue:dividerBezelColor forThemeAttribute:@"divider-bezel-color" inState:CPThemeStateHighlighted]; + + [segmentedControl setValue:rightBezelColor forThemeAttribute:@"right-segment-bezel-color" inState:CPThemeStateNormal]; + [segmentedControl setValue:inactiveRightBezelColor forThemeAttribute:@"right-segment-bezel-color" inState:CPThemeStateDisabled]; + [segmentedControl setValue:inactiveHighlightedRightBezelColor forThemeAttribute:@"right-segment-bezel-color" inState:CPThemeStateSelected|CPThemeStateDisabled]; + [segmentedControl setValue:rightHighlightedBezelColor forThemeAttribute:@"right-segment-bezel-color" inState:CPThemeStateSelected]; + [segmentedControl setValue:pushedRightBezelColor forThemeAttribute:@"right-segment-bezel-color" inState:CPThemeStateHighlighted]; + [segmentedControl setValue:pushedHighlightedRightBezelColor forThemeAttribute:@"right-segment-bezel-color" inState:CPThemeStateHighlighted|CPThemeStateSelected]; + + [segmentedControl setValue:leftBezelColor forThemeAttribute:@"left-segment-bezel-color" inState:CPThemeStateNormal]; + [segmentedControl setValue:inactiveLeftBezelColor forThemeAttribute:@"left-segment-bezel-color" inState:CPThemeStateDisabled]; + [segmentedControl setValue:inactiveHighlightedLeftBezelColor forThemeAttribute:@"left-segment-bezel-color" inState:CPThemeStateSelected|CPThemeStateDisabled]; + [segmentedControl setValue:leftHighlightedBezelColor forThemeAttribute:@"left-segment-bezel-color" inState:CPThemeStateSelected]; + [segmentedControl setValue:pushedLeftBezelColor forThemeAttribute:@"left-segment-bezel-color" inState:CPThemeStateHighlighted]; + [segmentedControl setValue:pushedHighlightedLeftBezelColor forThemeAttribute:@"left-segment-bezel-color" inState:CPThemeStateHighlighted|CPThemeStateSelected]; + + [segmentedControl setValue:CGInsetMake(0.0, 4.0, 0.0, 4.0) forThemeAttribute:@"content-inset" inState:CPThemeStateNormal]; + + [segmentedControl setValue:CGInsetMake(0.0, 0.0, 0.0, 0.0) forThemeAttribute:@"bezel-inset" inState:CPThemeStateNormal]; + + [segmentedControl setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font"]; + [segmentedControl setValue:[CPColor colorWithCalibratedWhite:255.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; + [segmentedControl setValue:[CPColor colorWithCalibratedWhite:0.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-shadow-color"]; + [segmentedControl setValue:CGSizeMake(-1.0, -1.0) forThemeAttribute:@"text-shadow-offset"]; + [segmentedControl setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"]; + + [segmentedControl setValue:1.0 forThemeAttribute:@"divider-thickness"]; + [segmentedControl setValue:24.0 forThemeAttribute:@"default-height"]; + + return segmentedControl; +} + ++ (CPButton)button +{ + var button = [[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 60.0, 24.0)], bezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: [ - [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-left.png" size:CGSizeMake(13.0, 20.0)], - [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-center.png" size:CGSizeMake(1.0, 20.0)], - [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-right.png" size:CGSizeMake(13.0, 20.0)] + [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-right.png" size:CGSizeMake(4.0, 24.0)] ] isVertical:NO]], highlightedBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: [ - [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-highlighted-left.png" size:CGSizeMake(13.0, 20.0)], - [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 20.0)], - [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-highlighted-right.png" size:CGSizeMake(13.0, 20.0)] + [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-highlighted-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]], + + defaultBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"HUD/default-button-bezel-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/default-button-bezel-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/default-button-bezel-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]], + + defaultHighlightedBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"HUD/default-button-bezel-highlighted-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/default-button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/default-button-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]], + + defaultDisabledBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"HUD/default-button-bezel-disabled-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/default-button-bezel-disabled-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/default-button-bezel-disabled-right.png" size:CGSizeMake(4.0, 24.0)] + ] + isVertical:NO]], + + disabledBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-disabled-left.png" size:CGSizeMake(4.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-disabled-center.png" size:CGSizeMake(1.0, 24.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/button-bezel-disabled-right.png" size:CGSizeMake(4.0, 24.0)] ] isVertical:NO]]; - [button setTitle:@"Cancel"]; + [button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered]; - [button setValue:[CPFont systemFontOfSize:11.0] forThemeAttribute:@"font" inState:CPThemeStateBordered]; - [button setValue:[CPColor whiteColor] forThemeAttribute:@"text-color"]; + [button setValue:[CPColor colorWithCalibratedWhite:255.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; + [button setValue:[CPColor colorWithCalibratedWhite:0.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateBordered]; + [button setValue:[CPColor colorWithCalibratedWhite:0.0 / 255.0 alpha:0.6] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateBordered|CPThemeStateDisabled]; + [button setValue:CGSizeMake(-1.0,-1.0) forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateBordered]; [button setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"]; - + [button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; [button setValue:highlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted]; - [button setValue:CGInsetMake(2.0, 5.0, 4.0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; + [button setValue:CGInsetMake(0.0, 5.0, 0.0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered]; - [button setValue:CGSizeMake(0.0, 20.0) forThemeAttribute:@"min-size"]; - [button setValue:CGSizeMake(-1.0, 20.0) forThemeAttribute:@"max-size"]; + [button setValue:[CPColor colorWithCalibratedWhite:0.97 alpha:1.0] forThemeAttribute:@"text-color" inState:CPThemeStateDisabled]; + [button setValue:disabledBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateDisabled]; + [button setValue:defaultDisabledBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateDefault|CPThemeStateDisabled]; + + [button setValue:defaultBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateDefault]; + [button setValue:defaultHighlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted|CPThemeStateDefault]; + [button setValue:[CPColor colorWithCalibratedRed:250.0/255.0 green:250.0/255.0 blue:250.0/255.0 alpha:1.0] forThemeAttribute:@"text-color" inState:CPThemeStateDefault]; + [button setValue:[CPColor colorWithCalibratedRed:250.0/255.0 green:250.0/255.0 blue:250.0/255.0 alpha:0.6] forThemeAttribute:@"text-color" inState:CPThemeStateDisabled|CPThemeStateDefault]; + + [button setValue:CGSizeMake(0.0, 24.0) forThemeAttribute:@"min-size"]; + [button setValue:CGSizeMake(-1.0, 24.0) forThemeAttribute:@"max-size"]; + + return button; +} + ++ (CPButton)themedStandardButton +{ + var button = [self button]; + + [button setTitle:@"Cancel"]; + + return button; +} + ++ (CPButton)themedDefaultButton +{ + var button = [self button]; + + [button setTitle:@"OK"]; + [button setDefaultButton:YES]; return button; } @@ -936,6 +1084,96 @@ return scroller; } ++ (CPSlider)themedHorizontalSlider +{ + var slider = [[CPSlider alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 24.0)], + trackColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"HUD/horizontal-track-left.png" size:CGSizeMake(4.0, 5.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/horizontal-track-center.png" size:CGSizeMake(1.0, 5.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/horizontal-track-right.png" size:CGSizeMake(4.0, 5.0)] + ] + isVertical:NO]], + + trackDisabledColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"HUD/horizontal-track-disabled-left.png" size:CGSizeMake(4.0, 5.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/horizontal-track-disabled-center.png" size:CGSizeMake(1.0, 5.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/horizontal-track-disabled-right.png" size:CGSizeMake(4.0, 5.0)] + ] + isVertical:NO]]; + + [slider setValue:5.0 forThemeAttribute:@"track-width"]; + [slider setValue:trackColor forThemeAttribute:@"track-color"]; + [slider setValue:trackDisabledColor forThemeAttribute:@"track-color" inState:CPThemeStateDisabled]; + + var knobColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"HUD/knob.png" size:CGSizeMake(23.0, 24.0)]], + knobHighlightedColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"HUD/knob-highlighted.png" size:CGSizeMake(23.0, 24.0)]], + knobDisabledColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"HUD/knob-disabled.png" size:CGSizeMake(23.0, 24.0)]]; + + [slider setValue:CGSizeMake(23.0, 24.0) forThemeAttribute:@"knob-size"]; + [slider setValue:knobColor forThemeAttribute:@"knob-color"]; + [slider setValue:knobHighlightedColor forThemeAttribute:@"knob-color" inState:CPThemeStateHighlighted]; + [slider setValue:knobDisabledColor forThemeAttribute:@"knob-color" inState:CPThemeStateDisabled]; + + return slider; +} + ++ (CPSlider)themedVerticalSlider +{ + var slider = [[CPSlider alloc] initWithFrame:CGRectMake(0.0, 0.0, 24.0, 50.0)], + trackColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"HUD/vertical-track-top.png" size:CGSizeMake(5.0, 6.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/vertical-track-center.png" size:CGSizeMake(5.0, 1.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/vertical-track-bottom.png" size:CGSizeMake(5.0, 4.0)] + ] + isVertical:YES]], + trackDisabledColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: + [ + [_CPCibCustomResource imageResourceWithName:"HUD/vertical-track-disabled-top.png" size:CGSizeMake(5.0, 6.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/vertical-track-disabled-center.png" size:CGSizeMake(5.0, 1.0)], + [_CPCibCustomResource imageResourceWithName:"HUD/vertical-track-disabled-bottom.png" size:CGSizeMake(5.0, 4.0)] + ] + isVertical:YES]]; + + [slider setValue:5.0 forThemeAttribute:@"track-width"]; + [slider setValue:trackColor forThemeAttribute:@"track-color" inState:CPThemeStateVertical]; + [slider setValue:trackDisabledColor forThemeAttribute:@"track-color" inState:CPThemeStateDisabled]; + + var knobColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"HUD/knob.png" size:CGSizeMake(23.0, 24.0)]], + knobHighlightedColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"HUD/knob-highlighted.png" size:CGSizeMake(23.0, 24.0)]], + knobDisabledColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"HUD/knob-disabled.png" size:CGSizeMake(23.0, 24.0)]]; + + [slider setValue:CGSizeMake(23.0, 24.0) forThemeAttribute:@"knob-size"]; + [slider setValue:knobColor forThemeAttribute:@"knob-color"]; + [slider setValue:knobHighlightedColor forThemeAttribute:@"knob-color" inState:CPThemeStateHighlighted]; + [slider setValue:knobDisabledColor forThemeAttribute:@"knob-color" inState:CPThemeStateDisabled]; + + return slider; +} ++ (CPSlider)themedCircularSlider +{ + var slider = [[CPSlider alloc] initWithFrame:CGRectMake(0.0, 0.0, 34.0, 34.0)], + trackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"HUD/slider-circular-bezel.png" size:CGSizeMake(34.0, 34.0)]), + trackDisabledColor = PatternColor([_CPCibCustomResource imageResourceWithName:"HUD/slider-circular-disabled-bezel.png" size:CGSizeMake(34.0, 34.0)]); + + [slider setSliderType:CPCircularSlider]; + [slider setValue:trackColor forThemeAttribute:@"track-color" inState:CPThemeStateCircular]; + [slider setValue:trackDisabledColor forThemeAttribute:@"track-color" inState:CPThemeStateDisabled|CPThemeStateCircular]; + + var knobColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"HUD/slider-circular-knob.png" size:CGSizeMake(5.0, 5.0)]], + knobDisabledColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"HUD/slider-circular-disabled-knob.png" size:CGSizeMake(5.0, 5.0)]], + knobHighlightedColor = knobColor; + + [slider setValue:CGSizeMake(5.0, 5.0) forThemeAttribute:@"knob-size" inState:CPThemeStateCircular]; + [slider setValue:knobColor forThemeAttribute:@"knob-color" inState:CPThemeStateCircular]; + [slider setValue:knobDisabledColor forThemeAttribute:@"knob-color" inState:CPThemeStateDisabled|CPThemeStateCircular]; + [slider setValue:knobHighlightedColor forThemeAttribute:@"knob-color" inState:CPThemeStateCircular|CPThemeStateHighlighted]; + + return slider; +} + @end function PatternColor(anImage) diff --git a/AppKit/_CPCornerView.j b/AppKit/_CPCornerView.j index 81c4a86e5..a5e4f9a65 100644 --- a/AppKit/_CPCornerView.j +++ b/AppKit/_CPCornerView.j @@ -20,20 +20,6 @@ return self; } -- (void)drawRect:(CGRect)aRect -{ - var context = [[CPGraphicsContext currentContext] graphicsPort]; - - CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"dce0e2"]); - - var points = [ - CGPointMake(aRect.origin.x, aRect.origin.y + 0.5), - CGPointMake(aRect.origin.x, aRect.origin.y + aRect.size.height) - ]; - - CGContextStrokeLineSegments(context, points, 2); -} - - (id)initWithCoder:(CPCoder)aCoder { self = [super initWithCoder:aCoder]; diff --git a/AppKit/_CPImageAndTextView.j b/AppKit/_CPImageAndTextView.j index cee931360..79a65f2ac 100644 --- a/AppKit/_CPImageAndTextView.j +++ b/AppKit/_CPImageAndTextView.j @@ -53,21 +53,21 @@ var HORIZONTAL_MARGIN = 3.0, { CPTextAlignment _alignment; CPVerticalTextAlignment _verticalAlignment; - + CPLineBreakMode _lineBreakMode; CPColor _textColor; CPFont _font; - + CPColor _textShadowColor; CGSize _textShadowOffset; - + CPCellImagePosition _imagePosition; CPImageScaling _imageScaling; BOOL _shouldDimImage; - + CPImage _image; CPString _text; - + CGRect _textSize; unsigned _flags; @@ -82,7 +82,7 @@ var HORIZONTAL_MARGIN = 3.0, - (id)initWithFrame:(CGRect)aFrame control:(CPControl)aControl { self = [super initWithFrame:aFrame]; - + if (self) { _textShadowOffset = _CGSizeMakeZero(); @@ -101,16 +101,16 @@ var HORIZONTAL_MARGIN = 3.0, else { [self setLineBreakMode:CPLineBreakByClipping]; - //[self setTextColor:[aControl textColor]]; + //[self setTextColor:[aControl textColor]]; [self setAlignment:CPCenterTextAlignment]; [self setFont:[CPFont systemFontOfSize:12.0]]; [self setImagePosition:CPNoImage]; [self setImageScaling:CPScaleNone]; } - + _textSize = NULL; } - + return self; } @@ -123,9 +123,9 @@ var HORIZONTAL_MARGIN = 3.0, { if (_alignment === anAlignment) return; - + _alignment = anAlignment; - + #if PLATFORM(DOM) switch (_alignment) { @@ -152,10 +152,10 @@ var HORIZONTAL_MARGIN = 3.0, { if (_verticalAlignment === anAlignment) return; - + _verticalAlignment = anAlignment; _flags |= _CPImageAndTextViewVerticalAlignmentChangedFlag; - + [self setNeedsLayout]; } @@ -168,10 +168,10 @@ var HORIZONTAL_MARGIN = 3.0, { if (_lineBreakMode === aLineBreakMode) return; - + _lineBreakMode = aLineBreakMode; _flags |= _CPImageAndTextViewLineBreakModeChangedFlag; - + [self setNeedsLayout]; } @@ -184,10 +184,10 @@ var HORIZONTAL_MARGIN = 3.0, { if (_imagePosition == anImagePosition) return; - + _imagePosition = anImagePosition; _flags |= _CPImageAndTextViewImagePositionChangedFlag; - + [self setNeedsLayout]; } @@ -200,7 +200,7 @@ var HORIZONTAL_MARGIN = 3.0, { if (_imageScaling == anImageScaling) return; - + _imageScaling = anImageScaling; _flags |= _CPImageAndTextViewImageScalingChangedFlag; @@ -212,13 +212,13 @@ var HORIZONTAL_MARGIN = 3.0, return _imageScaling; } -- (void)setDimsImage:(BOOL)shouldDim +- (void)setDimsImage:(BOOL)shouldDimImage { - var shouldDimImage = !!shouldDimImage; + shouldDimImage = !!shouldDimImage; if (_shouldDimImage !== shouldDimImage) { - _shouldDimImage = shouldDim; + _shouldDimImage = shouldDimImage; [self setNeedsLayout]; } } @@ -227,9 +227,9 @@ var HORIZONTAL_MARGIN = 3.0, { if (_textColor === aTextColor) return; - + _textColor = aTextColor; - + #if PLATFORM(DOM) _DOMElement.style.color = [_textColor cssString]; #endif @@ -244,11 +244,11 @@ var HORIZONTAL_MARGIN = 3.0, { if (_font === aFont) return; - + _font = aFont; - _flags |= _CPImageAndTextViewFontChangedFlag; + _flags |= _CPImageAndTextViewFontChangedFlag; _textSize = NULL; - + [self setNeedsLayout]; } @@ -261,10 +261,10 @@ var HORIZONTAL_MARGIN = 3.0, { if (_textShadowColor === aColor) return; - + _textShadowColor = aColor; _flags |= _CPImageAndTextViewTextShadowColorChangedFlag; - + [self setNeedsLayout]; } @@ -277,9 +277,9 @@ var HORIZONTAL_MARGIN = 3.0, { if (_CGSizeEqualToSize(_textShadowOffset, anOffset)) return; - + _textShadowOffset = _CGSizeMakeCopy(anOffset); - + [self setNeedsLayout]; } @@ -323,12 +323,12 @@ var HORIZONTAL_MARGIN = 3.0, { if (_text === text) return; - + _text = text; _flags |= _CPImageAndTextViewTextChangedFlag; - + _textSize = NULL; - + [self setNeedsLayout]; } @@ -342,62 +342,62 @@ var HORIZONTAL_MARGIN = 3.0, #if PLATFORM(DOM) var needsDOMTextElement = _imagePosition !== CPImageOnly && ([_text length] > 0), hasDOMTextElement = !!_DOMTextElement; - + // Create or destroy the DOM Text Element as necessary if (needsDOMTextElement !== hasDOMTextElement) { if (hasDOMTextElement) { _DOMElement.removeChild(_DOMTextElement); - + _DOMTextElement = NULL; - + hasDOMTextElement = NO; } - + else - { + { _DOMTextElement = document.createElement("div"); - + var textStyle = _DOMTextElement.style; - + textStyle.position = "absolute"; textStyle.whiteSpace = "pre"; textStyle.zIndex = 200; textStyle.overflow = "hidden"; - + _DOMElement.appendChild(_DOMTextElement); - + hasDOMTextElement = YES; - + // We have to set all these values now. _flags |= _CPImageAndTextViewTextChangedFlag | _CPImageAndTextViewFontChangedFlag | _CPImageAndTextViewLineBreakModeChangedFlag; } } - + var textStyle = hasDOMTextElement ? _DOMTextElement.style : nil; - + // Create or destroy the DOM Text Shadow element as necessary. var needsDOMTextShadowElement = hasDOMTextElement && !!_textShadowColor, hasDOMTextShadowElement = !!_DOMTextShadowElement; - + if (needsDOMTextShadowElement !== hasDOMTextShadowElement) { if (hasDOMTextShadowElement) { _DOMElement.removeChild(_DOMTextShadowElement); - + _DOMTextShadowElement = NULL; - + hasDOMTextShadowElement = NO; } else { _DOMTextShadowElement = document.createElement("div"); - + var shadowStyle = _DOMTextShadowElement.style; - + shadowStyle.font = [_font ? _font : [CPFont systemFontOfSize:12.0] cssString]; shadowStyle.position = "absolute"; shadowStyle.whiteSpace = textStyle.whiteSpace; @@ -406,7 +406,7 @@ var HORIZONTAL_MARGIN = 3.0, shadowStyle.zIndex = 150; shadowStyle.textOverflow = textStyle.textOverflow; - + if (document.attachEvent) { shadowStyle.overflow = textStyle.overflow; @@ -416,17 +416,17 @@ var HORIZONTAL_MARGIN = 3.0, shadowStyle.overflowX = textStyle.overflowX; shadowStyle.overflowY = textStyle.overflowY; } - + _DOMElement.appendChild(_DOMTextShadowElement); - + hasDOMTextShadowElement = YES; - + _flags |= _CPImageAndTextViewTextChangedFlag; //sigh... } } - + var shadowStyle = hasDOMTextShadowElement ? _DOMTextShadowElement.style : nil; - + if (hasDOMTextElement) { // Update the text contents if necessary. @@ -434,27 +434,27 @@ var HORIZONTAL_MARGIN = 3.0, if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature)) { _DOMTextElement.innerText = _text; - + if (_DOMTextShadowElement) _DOMTextShadowElement.innerText = _text; - } + } else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature)) { _DOMTextElement.textContent = _text; - + if (_DOMTextShadowElement) _DOMTextShadowElement.textContent = _text; } - + if (_flags & _CPImageAndTextViewFontChangedFlag) { var fontStyle = [_font ? _font : [CPFont systemFontOfSize:12.0] cssString]; textStyle.font = fontStyle; - + if (shadowStyle) shadowStyle.font = fontStyle; } - + // Update the line break mode if necessary. if (_flags & _CPImageAndTextViewLineBreakModeChangedFlag) { @@ -463,21 +463,21 @@ var HORIZONTAL_MARGIN = 3.0, case CPLineBreakByClipping: textStyle.overflow = "hidden"; textStyle.textOverflow = "clip"; textStyle.whiteSpace = "pre"; - textStyle.wordWrap = "normal"; - + textStyle.wordWrap = "normal"; + break; - + case CPLineBreakByTruncatingHead: case CPLineBreakByTruncatingMiddle: // Don't have support for these (yet?), so just degrade to truncating tail. - + case CPLineBreakByTruncatingTail: textStyle.textOverflow = "ellipsis"; textStyle.whiteSpace = "nowrap"; textStyle.overflow = "hidden"; - textStyle.wordWrap = "normal"; - + textStyle.wordWrap = "normal"; + break; - - case CPLineBreakByCharWrapping: + + case CPLineBreakByCharWrapping: case CPLineBreakByWordWrapping: textStyle.wordWrap = "break-word"; try { textStyle.whiteSpace = "pre"; @@ -490,13 +490,13 @@ var HORIZONTAL_MARGIN = 3.0, //internet explorer doesn't like these properties textStyle.whiteSpace = "pre"; } - + textStyle.overflow = "hidden"; textStyle.textOverflow = "clip"; - + break; } - + if (shadowStyle) { if (document.attachEvent) @@ -515,22 +515,22 @@ var HORIZONTAL_MARGIN = 3.0, } } } - + var needsDOMImageElement = _image !== nil && _imagePosition !== CPNoImage, hasDOMImageElement = !!_DOMImageElement; - // Create or destroy DOM Image element + // Create or destroy DOM Image element if (needsDOMImageElement !== hasDOMImageElement) { if (hasDOMImageElement) { _DOMElement.removeChild(_DOMImageElement); - + _DOMImageElement = NULL; - + hasDOMImageElement = NO; } - + else { _DOMImageElement = document.createElement("img"); @@ -549,7 +549,7 @@ var HORIZONTAL_MARGIN = 3.0, imageStyle.zIndex = 100; _DOMElement.appendChild(_DOMImageElement); - + hasDOMImageElement = YES; } } @@ -561,16 +561,16 @@ var HORIZONTAL_MARGIN = 3.0, { if (!imageStyle) var imageStyle = _DOMImageElement.style; - + if (_flags & _CPImageAndTextViewImageChangedFlag) _DOMImageElement.src = [_image filename]; - + var centerX = size.width / 2.0, centerY = size.height / 2.0, - imageSize = [_image size], + imageSize = [_image size], imageWidth = imageSize.width, imageHeight = imageSize.height; - + if (_imageScaling === CPScaleToFit) { imageWidth = size.width; @@ -579,7 +579,7 @@ var HORIZONTAL_MARGIN = 3.0, else if (_imageScaling === CPScaleProportionally) { var scale = MIN(MIN(size.width, imageWidth) / imageWidth, MIN(size.height, imageHeight) / imageHeight); - + imageWidth *= scale; imageHeight *= scale; } @@ -590,7 +590,7 @@ var HORIZONTAL_MARGIN = 3.0, imageStyle.opacity = _shouldDimImage ? 0.35 : 1.0; _DOMImageElement.width = imageWidth; - _DOMImageElement.height = imageHeight; + _DOMImageElement.height = imageHeight; imageStyle.width = MAX(imageWidth, 0) + "px"; imageStyle.height = MAX(imageHeight, 0) + "px"; @@ -604,7 +604,7 @@ var HORIZONTAL_MARGIN = 3.0, else if (_imagePosition === CPImageAbove) { CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, FLOOR(centerX - imageWidth / 2.0), 0); - + textRect.origin.y += imageHeight + VERTICAL_MARGIN; textRect.size.height = size.height - imageHeight - VERTICAL_MARGIN; } @@ -641,36 +641,36 @@ var HORIZONTAL_MARGIN = 3.0, { if (!_textSize) { - if (_lineBreakMode === CPLineBreakByCharWrapping || + if (_lineBreakMode === CPLineBreakByCharWrapping || _lineBreakMode === CPLineBreakByWordWrapping) _textSize = [_text sizeWithFont:_font inWidth:textRectWidth]; else _textSize = [_text sizeWithFont:_font]; } - + if (_verticalAlignment === CPCenterVerticalTextAlignment) { textRectY = textRectY + (textRectHeight - _textSize.height) / 2.0; textRectHeight = _textSize.height; } - + else //if (_verticalAlignment === CPBottomVerticalTextAlignment) - { + { textRectY = textRectY + textRectHeight - _textSize.height; textRectHeight = _textSize.height; } } - + textStyle.top = ROUND(textRectY) + "px"; textStyle.left = ROUND(textRectX) + "px"; textStyle.width = MAX(ROUND(textRectWidth), 0) + "px"; textStyle.height = MAX(ROUND(textRectHeight), 0) + "px"; - + if (shadowStyle) { if (_flags & _CPImageAndTextViewTextShadowColorChangedFlag) shadowStyle.color = [_textShadowColor cssString]; - + shadowStyle.top = ROUND(textRectY + _textShadowOffset.height) + "px"; shadowStyle.left = ROUND(textRectX + _textShadowOffset.width) + "px"; shadowStyle.width = MAX(ROUND(textRectWidth), 0) + "px"; @@ -685,15 +685,15 @@ var HORIZONTAL_MARGIN = 3.0, - (void)sizeToFit { var size = CGSizeMakeZero(); - + if ((_imagePosition !== CPNoImage) && _image) { var imageSize = [_image size]; - + size.width += imageSize.width; size.height += imageSize.height; } - + if ((_imagePosition !== CPImageOnly) && [_text length] > 0) { if (!_textSize) @@ -715,7 +715,7 @@ var HORIZONTAL_MARGIN = 3.0, size.height = MAX(size.height, _textSize.height); } } - + [self setFrameSize:size]; } diff --git a/CommonJS/lib/cappuccino/cib-analysis-tools.j b/CommonJS/lib/cappuccino/cib-analysis-tools.j index cab6a919a..2427987f8 100644 --- a/CommonJS/lib/cappuccino/cib-analysis-tools.j +++ b/CommonJS/lib/cappuccino/cib-analysis-tools.j @@ -17,7 +17,7 @@ function findCibClassDependencies(cibPath) { } // make sure CPApp is init'd - [CPApplication sharedApplication] + [CPApplication sharedApplication]; try { var x = [cib pressInstantiate]; @@ -61,7 +61,7 @@ function findCibClassDependencies(cibPath) { var topLevelObjects = nil;//[anExternalNameTable objectForKey:CPCibTopLevelObjects]; - [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects] + [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]; // [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects]; // [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects]; diff --git a/Foundation/CPArray+KVO.j b/Foundation/CPArray+KVO.j index e39536709..49ff5d621 100644 --- a/Foundation/CPArray+KVO.j +++ b/Foundation/CPArray+KVO.j @@ -23,6 +23,7 @@ @import "CPArray.j" @import "CPNull.j" + @implementation CPObject (CPArrayKVO) - (id)mutableArrayValueForKey:(id)aKey @@ -33,12 +34,12 @@ - (id)mutableArrayValueForKeyPath:(id)aKeyPath { var dotIndex = aKeyPath.indexOf("."); - + if (dotIndex < 0) return [self mutableArrayValueForKey:aKeyPath]; var firstPart = aKeyPath.substring(0, dotIndex), - lastPart = aKeyPath.substring(dotIndex+1); + lastPart = aKeyPath.substring(dotIndex + 1); return [[self valueForKeyPath:firstPart] valueForKeyPath:lastPart]; } @@ -49,34 +50,34 @@ { id _proxyObject; id _key; - + SEL _insertSEL; Function _insert; - + SEL _removeSEL; Function _remove; - + SEL _replaceSEL; Function _replace; - + SEL _insertManySEL; Function _insertMany; - + SEL _removeManySEL; Function _removeMany; - + SEL _replaceManySEL; Function _replaceMany; - + SEL _objectAtIndexSEL; Function _objectAtIndex; - + SEL _countSEL; Function _count; - + SEL _accessSEL; Function _access; - + SEL _setSEL; Function _set; } @@ -96,15 +97,15 @@ return array; } --(id)initWithKey:(id)aKey forProxyObject:(id)anObject +- (id)initWithKey:(id)aKey forProxyObject:(id)anObject { self = [super init]; _key = aKey; _proxyObject = anObject; - + var capitalizedKey = _key.charAt(0).toUpperCase() + _key.substring(1); - + _insertSEL = sel_getName(@"insertObject:in"+capitalizedKey+"AtIndex:"); if ([_proxyObject respondsToSelector:_insertSEL]) _insert = [_proxyObject methodForSelector:_insertSEL]; @@ -112,7 +113,7 @@ _removeSEL = sel_getName(@"removeObjectFrom"+capitalizedKey+"AtIndex:"); if ([_proxyObject respondsToSelector:_removeSEL]) _remove = [_proxyObject methodForSelector:_removeSEL]; - + _replaceSEL = sel_getName(@"replaceObjectFrom"+capitalizedKey+"AtIndex:withObject:"); if ([_proxyObject respondsToSelector:_replaceSEL]) _replace = [_proxyObject methodForSelector:_replaceSEL]; @@ -124,11 +125,11 @@ _removeManySEL = sel_getName(@"removeObjectsFrom"+capitalizedKey+"AtIndexes:"); if ([_proxyObject respondsToSelector:_removeManySEL]) _remove = [_proxyObject methodForSelector:_removeManySEL]; - + _replaceManySEL = sel_getName(@"replaceObjectsFrom"+capitalizedKey+"AtIndexes:withObjects:"); if ([_proxyObject respondsToSelector:_replaceManySEL]) _replace = [_proxyObject methodForSelector:_replaceManySEL]; - + _objectAtIndexSEL = sel_getName(@"objectIn"+capitalizedKey+"AtIndex:"); if ([_proxyObject respondsToSelector:_objectAtIndexSEL]) _objectAtIndex = [_proxyObject methodForSelector:_objectAtIndexSEL]; @@ -150,16 +151,17 @@ - (id)copy { - var theCopy = [], + var i = 0, + theCopy = [], count = [self count]; - for (var i=0; i= 0) { [self[index] addObserver:anObserver forKeyPath:aKeyPath options:options context:context]; @@ -483,7 +488,7 @@ kvoOperators["sum"] = function sumOperator(self, _cmd, param) - (void)removeObserver:(id)anObserver fromObjectsAtIndexes:(CPIndexSet)indexes forKeyPath:(CPString)aKeyPath { var index = [indexes firstIndex]; - + while (index >= 0) { [self[index] removeObserver:anObserver forKeyPath:aKeyPath]; @@ -492,7 +497,7 @@ kvoOperators["sum"] = function sumOperator(self, _cmd, param) } } --(void)addObserver:(id)observer forKeyPath:(CPString)aKeyPath options:(unsigned)options context:(id)context +- (void)addObserver:(id)observer forKeyPath:(CPString)aKeyPath options:(unsigned)options context:(id)context { if ([isa instanceMethodForSelector:_cmd] === [CPArray instanceMethodForSelector:_cmd]) [CPException raise:CPInvalidArgumentException reason:"Unsupported method on CPArray"]; diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 4e22b591a..27acbd1f2 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -20,11 +20,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +@import "CPEnumerator.j" +@import "CPException.j" @import "CPObject.j" @import "CPRange.j" -@import "CPEnumerator.j" @import "CPSortDescriptor.j" -@import "CPException.j" /* @ignore */ @@ -470,7 +470,7 @@ last = mid - 1; else { - while (mid < length - 1 && aFunction(anObject, self[mid+1], aContext) == CPOrderedSame) + while (mid < length - 1 && aFunction(anObject, self[mid + 1], aContext) == CPOrderedSame) mid++; return mid; @@ -505,6 +505,28 @@ }]; } +- (unsigned)insertObject:(id)anObject inArraySortedByDescriptors:(CPArray)descriptors +{ + var index = [self _insertObject:anObject sortedByFunction:function(lhs, rhs) + { + var i = 0, + count = [descriptors count], + result = CPOrderedSame; + + while (i < count) + if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame) + return result; + + return result; + } context:nil]; + + if (index < 0) + index = -result-1; + + [self insertObject:anObject atIndex:index]; + return index; +} + /*! Returns the last object in the array. If the array is empty, returns \c nil/ */ @@ -774,7 +796,7 @@ */ - (CPArray)sortedArrayUsingSelector:(SEL)aSelector { - var sorted = [self copy] + var sorted = [self copy]; [sorted sortUsingSelector:aSelector]; @@ -894,7 +916,7 @@ @end -@implementation CPArray(CPMutableArray) +@implementation CPArray (CPMutableArray) // Creating arrays /*! @@ -987,7 +1009,7 @@ } context:nil]; if (index < 0) - index = -index-1; + index = -index - 1; [self insertObject:anObject atIndex:index]; return index; diff --git a/Foundation/CPAttributedString.j b/Foundation/CPAttributedString.j index 82e7f93a7..f61b5c0e1 100644 --- a/Foundation/CPAttributedString.j +++ b/Foundation/CPAttributedString.j @@ -20,12 +20,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPObject.j" -@import "CPString.j" @import "CPDictionary.j" +@import "CPObject.j" @import "CPRange.j" +@import "CPString.j" -/*! + +/*! @class CPAttributedString @ingroup foundation @brief A mutable character string with attributes. @@ -62,13 +63,13 @@ Creates a new attributed string from an existing attributed string. @param aString is the attributed string to initialise from. @return a new CPAttributedString containing the string \c aString. -*/ +*/ - (id)initWithAttributedString:(CPAttributedString)aString { var string = [self initWithString:"" attributes:nil]; - + [string setAttributedString:aString]; - + return string; } @@ -79,16 +80,19 @@ @param attributes is a dictionary of string attributes. @return a new CPAttributedString containing the string \c aString with associated attributes, \c attributes. -*/ +*/ - (id)initWithString:(CPString)aString attributes:(CPDictionary)attributes { self = [super init]; - - if (!attributes) - attributes = [CPDictionary dictionary]; - _string = ""+aString; - _rangeEntries = [makeRangeEntry(CPMakeRange(0, _string.length), attributes)]; + if (self) + { + if (!attributes) + attributes = [CPDictionary dictionary]; + + _string = ""+aString; + _rangeEntries = [makeRangeEntry(CPMakeRange(0, _string.length), attributes)]; + } return self; } @@ -98,7 +102,7 @@ Returns a string containing the receiver's character data without attributes. @return a string of type CPString. -*/ +*/ - (CPString)string { return _string; @@ -108,17 +112,17 @@ Returns a string containing the receiver's character data without attributes. @return a string of type CPString. -*/ +*/ - (CPString)mutableString { return [self string]; -} +} /*! Get the length of the string. @return an unsigned integer equivalent to the number of characters in the string. -*/ +*/ - (unsigned)length { return _string.length; @@ -149,7 +153,7 @@ /*! Returns a dictionary of attributes for the character at a given index. The range in which this character resides in which the attributes are the - same, can be returned if desired. + same, can be returned if desired. @note there is no guarantee that the range returned is in fact the complete range of the particular attributes. To ensure this use \c attributesAtIndex:longestEffectiveRange:inRange: instead. Note @@ -160,10 +164,10 @@ that is set (upon return) to the range over which the attributes are the same as those at index, \c anIndex. If not required pass \c nil. - @return a CPDictionary containing the attributes associated with the + @return a CPDictionary containing the attributes associated with the character at index \c anIndex. Returns \c nil if index is out of bounds. -*/ +*/ - (CPDictionary)attributesAtIndex:(unsigned)anIndex effectiveRange:(CPRangePointer)aRange { //find the range entry that contains anIndex. @@ -178,7 +182,7 @@ aRange.location = matchingRange.range.location; aRange.length = matchingRange.range.length; } - + return matchingRange.attributes; } @@ -199,17 +203,17 @@ to the range over which the attributes apply. @param rangeLimit a range limiting the search for the attributes' applicable range. - @return a CPDictionary containing the attributes associated with the + @return a CPDictionary containing the attributes associated with the character at index \c anIndex. Returns \c nil if index is out of bounds. -*/ +*/ - (CPDictionary)attributesAtIndex:(unsigned)anIndex longestEffectiveRange:(CPRangePointer)aRange inRange:(CPRange)rangeLimit -{ +{ var startingEntryIndex = [self _indexOfEntryWithIndex:anIndex]; if (startingEntryIndex == CPNotFound) return nil; - + if (!aRange) return _rangeEntries[startingEntryIndex].attributes; @@ -217,7 +221,7 @@ { aRange.location = rangeLimit.location; aRange.length = rangeLimit.length; - + return _rangeEntries[startingEntryIndex].attributes; } @@ -257,7 +261,7 @@ else break; } - + aRange.length = MIN(CPMaxRange(currentEntry.range), CPMaxRange(rangeLimit)) - aRange.location; return comparisonDict; @@ -265,7 +269,7 @@ /*! Returns the specified named attribute for the given character index and, if - required, the range over which the attribute applies. + required, the range over which the attribute applies. @note there is no guarantee that the range returned is in fact the complete range of a particular attribute. To ensure this use \c -attribute:atIndex:longestEffectiveRange:inRange: instead but @@ -278,7 +282,7 @@ \c nil. @return the named attribute or \c nil is the attribute does not exist. -*/ +*/ - (id)attribute:(CPString)attribute atIndex:(unsigned)index effectiveRange:(CPRangePointer)aRange { if (!attribute) @@ -320,7 +324,7 @@ { //find the range entry that contains anIndex. var startingEntryIndex = [self _indexOfEntryWithIndex:anIndex]; - + if (startingEntryIndex == CPNotFound || !attribute) return nil; @@ -331,7 +335,7 @@ { aRange.location = rangeLimit.location; aRange.length = rangeLimit.length; - + return [_rangeEntries[startingEntryIndex].attributes objectForKey:attribute]; } @@ -371,7 +375,7 @@ else break; } - + aRange.length = MIN(CPMaxRange(currentEntry.range), CPMaxRange(rangeLimit)) - aRange.location; return comparisonAttribute; @@ -386,10 +390,10 @@ */ - (BOOL)isEqualToAttributedString:(CPAttributedString)aString { - if(!aString) + if (!aString) return NO; - if(_string != [aString string]) + if (_string != [aString string]) return NO; var myRange = CPMakeRange(), @@ -407,7 +411,7 @@ else comparisonAttributes = [aString attributesAtIndex:CPMaxRange(comparisonRange) effectiveRange:comparisonRange]; } - + return YES; } @@ -422,10 +426,10 @@ { if (anObject == self) return YES; - + if ([anObject isKindOfClass:[self class]]) return [self isEqualToAttributedString:anObject]; - + return NO; } @@ -440,7 +444,7 @@ - (CPAttributedString)attributedSubstringFromRange:(CPRange)aRange { if (!aRange || CPMaxRange(aRange) > _string.length || aRange.location < 0) - [CPException raise:CPRangeException + [CPException raise:CPRangeException reason:"tried to get attributedSubstring for an invalid range: "+(aRange?CPStringFromRange(aRange):"nil")]; var newString = [[CPAttributedString alloc] initWithString:_string.substring(aRange.location, CPMaxRange(aRange))], @@ -449,7 +453,7 @@ lastIndex = CPMaxRange(aRange); newString._rangeEntries = []; - + while (currentRangeEntry && CPMaxRange(currentRangeEntry.range) < lastIndex) { var newEntry = copyRangeEntry(currentRangeEntry); @@ -468,10 +472,10 @@ if (currentRangeEntry) { var newRangeEntry = copyRangeEntry(currentRangeEntry); - + newRangeEntry.range.length = CPMaxRange(aRange) - newRangeEntry.range.location; newRangeEntry.range.location -= aRange.location; - + if (newRangeEntry.range.location < 0) { newRangeEntry.range.length += newRangeEntry.range.location; @@ -480,12 +484,12 @@ newString._rangeEntries.push(newRangeEntry); } - + return newString; } //Changing Characters -/*! +/*! Replaces the characters in the receiver with those of the specified string over the range, \c aRange. If the range has a length of 0 then the specified string is inserted at the range location. The new characters @@ -505,10 +509,10 @@ if (!aString) aString = ""; - + var startingIndex = [self _indexOfEntryWithIndex:aRange.location], startingRangeEntry = _rangeEntries[startingIndex], - endingIndex = [self _indexOfEntryWithIndex:MAX(CPMaxRange(aRange)-1, 0)], + endingIndex = [self _indexOfEntryWithIndex:MAX(CPMaxRange(aRange) - 1, 0)], endingRangeEntry = _rangeEntries[endingIndex], additionalLength = aString.length - aRange.length; @@ -527,10 +531,10 @@ } endingIndex = startingIndex + 1; - + while(endingIndex < _rangeEntries.length) _rangeEntries[endingIndex++].range.location+=additionalLength; - + [self endEditing]; } @@ -545,9 +549,9 @@ //Changing Attributes /*! - Sets the attributes of the specified character range. + Sets the attributes of the specified character range. - @note This process removes the attributes already associated with the + @note This process removes the attributes already associated with the character range. If you wish to retain the current attributes use \c -addAttributes:range:. @param aDictionary a CPDictionary of attributes (names and values) to set @@ -576,11 +580,11 @@ } /*! - Add a collection of attributes to the specified character range. + Add a collection of attributes to the specified character range. @note Attributes currently associated with the characters in the range are untouched. To remove all previous attributes when adding use - \c -setAttributes:range:. + \c -setAttributes:range:. @param aDictionary a CPDictionary of attributes (names and values) to add. @param aRange a CPRange indicating the range of characters to add the attributes to. @@ -600,7 +604,7 @@ { var keys = [aDictionary allKeys], count = [keys count]; - + while (count--) [_rangeEntries[current].attributes setObject:[aDictionary objectForKey:keys[count]] forKey:keys[count]]; @@ -703,8 +707,8 @@ { var entryCopy = copyRangeEntry(otherRangeEntries[index++]); entryCopy.range.location += anIndex; - - _rangeEntries.splice(entryIndexOfNextEntry-1+index, 0, entryCopy); + + _rangeEntries.splice(entryIndexOfNextEntry - 1 + index, 0, entryCopy); } //necessary? @@ -724,10 +728,10 @@ - (void)replaceCharactersInRange:(CPRange)aRange withAttributedString:(CPAttributedString)aString { [self beginEditing]; - + [self deleteCharactersInRange:aRange]; [self insertAttributedString:aString atIndex:aRange.location]; - + [self endEditing]; } @@ -739,11 +743,14 @@ - (void)setAttributedString:(CPAttributedString)aString { [self beginEditing]; - + _string = aString._string; _rangeEntries = []; - - for (var i=0, count = aString._rangeEntries.length; i= _rangeEntries.length) - end = _rangeEntries.length -1; + end = _rangeEntries.length - 1; while (current < end) { var a = _rangeEntries[current], - b = _rangeEntries[current+1]; + b = _rangeEntries[current + 1]; if ([a.attributes isEqualToDictionary:b.attributes]) { a.range.length = CPMaxRange(b.range) - a.range.location; - _rangeEntries.splice(current+1, 1); + _rangeEntries.splice(current + 1, 1); end--; } else @@ -821,7 +828,8 @@ CPAttributedString already implements mutable methods and this class only exists for source compatability. */ -@implementation CPMutableAttributedString : CPAttributedString {} +@implementation CPMutableAttributedString : CPAttributedString + @end var isEqual = function isEqual(a, b) @@ -849,11 +857,11 @@ var splitRangeEntry = function splitRangeEntryAtIndex(/*RangeEntry*/aRangeEntry, { var newRangeEntry = copyRangeEntry(aRangeEntry), cachedIndex = CPMaxRange(aRangeEntry.range); - + aRangeEntry.range.length = anIndex - aRangeEntry.range.location; newRangeEntry.range.location = anIndex; newRangeEntry.range.length = cachedIndex - anIndex; newRangeEntry.attributes = [newRangeEntry.attributes copy]; - + return [aRangeEntry, newRangeEntry]; } diff --git a/Foundation/CPBundle.j b/Foundation/CPBundle.j index bef8fdb69..39aae0b29 100644 --- a/Foundation/CPBundle.j +++ b/Foundation/CPBundle.j @@ -20,8 +20,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPObject.j" @import "CPDictionary.j" +@import "CPObject.j" + /*! @class CPBundle diff --git a/Foundation/CPCoder.j b/Foundation/CPCoder.j index a9cd1bf97..0d8bc04da 100644 --- a/Foundation/CPCoder.j +++ b/Foundation/CPCoder.j @@ -20,28 +20,27 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPObject.j" @import "CPException.j" +@import "CPObject.j" -/*! +/*! @class CPCoder @ingroup foundation @brief Defines methods for use when archiving & restoring (enc/decoding). - Top-level class defining methods for use when archiving (encoding) objects to a byte array - or file, and when restoring (decoding) objects. + Top-level class defining methods for use when archiving (encoding) objects to a byte array + or file, and when restoring (decoding) objects. */ @implementation CPCoder : CPObject { - } /*! Returns a flag indicating whether the receiver supports keyed coding. The default implementation returns \c NO. Subclasses supporting keyed coding must override this to return \c YES. */ --(BOOL)allowsKeyedCoding +- (BOOL)allowsKeyedCoding { return NO; } @@ -53,7 +52,7 @@ @param aType the structure or object type @param anObject the object to be encoded */ --(void)encodeValueOfObjCType:(CPString)aType at:(id)anObject +- (void)encodeValueOfObjCType:(CPString)aType at:(id)anObject { CPInvalidAbstractInvocation(); } @@ -62,7 +61,7 @@ Encodes a data object. Subclasses must override this method. @param aData the object to be encoded. */ --(void)encodeDataObject:(CPData)aData +- (void)encodeDataObject:(CPData)aData { CPInvalidAbstractInvocation(); } @@ -71,7 +70,7 @@ Encodes an object. Subclasses must override this method. @param anObject the object to be encoded */ --(void)encodeObject:(id)anObject +- (void)encodeObject:(id)anObject { // [self encodeValueOfObjCType:@encode(id) at:object]; } @@ -110,7 +109,7 @@ Encodes a property list. Not yet implemented. @param aPropertyList the property list to be encoded */ --(void)encodePropertyList:(id)aPropertyList +- (void)encodePropertyList:(id)aPropertyList { // [self encodeValueOfObjCType:@encode(id) at:&propertyList]; } @@ -119,7 +118,7 @@ Encodes the root object of a group of Obj-J objects. @param rootObject the root object to be encoded. */ --(void)encodeRootObject:(id)anObject +- (void)encodeRootObject:(id)anObject { [self encodeObject:anObject]; } @@ -128,18 +127,18 @@ Encodes an object. @param anObject the object to be encoded. */ --(void)encodeBycopyObject:(id)anObject +- (void)encodeBycopyObject:(id)anObject { - [self encodeObject:object]; + [self encodeObject:anObject]; } /*! Encodes an object. @param anObject the object to be encoded. */ --(void)encodeConditionalObject:(id)anObject +- (void)encodeConditionalObject:(id)anObject { - [self encodeObject:object]; + [self encodeObject:anObject]; } @end diff --git a/Foundation/CPCountedSet.j b/Foundation/CPCountedSet.j index a99b94a98..86b4753af 100644 --- a/Foundation/CPCountedSet.j +++ b/Foundation/CPCountedSet.j @@ -22,7 +22,8 @@ @import "CPSet.j" -/*! + +/*! @class CPCountedSet @ingroup foundation @brief An mutable collection which may contain a specific object @@ -37,11 +38,11 @@ { if (!_counts) _counts = {}; - + [super addObject:anObject]; - + var UID = [anObject UID]; - + if (_counts[UID] === undefined) _counts[UID] = 1; else @@ -52,16 +53,16 @@ { if (!_counts) return; - + var UID = [anObject UID]; - + if (_counts[UID] === undefined) return; - + else { --_counts[UID]; - + if (_counts[UID] === 0) { delete _counts[UID]; @@ -84,17 +85,17 @@ { if (!_counts) _counts = {}; - + var UID = [anObject UID]; - + if (_counts[UID] === undefined) return 0; - + return _counts[UID]; } -/* +/* Eventually we should see what these are supposed to do, and then do that. diff --git a/Foundation/CPData.j b/Foundation/CPData.j index 2d73b5a42..0a75abd36 100644 --- a/Foundation/CPData.j +++ b/Foundation/CPData.j @@ -23,6 +23,7 @@ @import "CPObject.j" @import "CPString.j" + /*! @class CPData @ingroup foundation diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index e4bc13273..cba9ec382 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -24,7 +24,7 @@ @import "CPString.j" -var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); +var CPDateReferenceDate = new Date(Date.UTC(2001, 1, 1, 0, 0, 0, 0)); /*! @class CPDate @@ -64,12 +64,12 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); + (id)distantPast { - return new Date(-10000,1,1,0,0,0,0); + return new Date(-10000, 1, 1, 0, 0, 0, 0); } + (id)distantFuture { - return new Date(10000,1,1,0,0,0,0); + return new Date(10000, 1, 1, 0, 0, 0, 0); } - (id)initWithTimeIntervalSinceNow:(CPTimeInterval)seconds @@ -110,7 +110,7 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); [CPException raise:CPInvalidArgumentException reason:"initWithString: the string must be of YYYY-MM-DD HH:MM:SS ±HHMM format"]; - var date = new Date(d[1], d[2]-1, d[3]), + var date = new Date(d[1], d[2] - 1, d[3]), timeZoneOffset = (Number(d[8]) * 60 + Number(d[9])) * (d[7] === '-' ? -1 : 1); date.setHours(d[4]); @@ -177,10 +177,11 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0)); */ - (CPString)description { - var hours = Math.floor(self.getTimezoneOffset() / 60), + var positive = self.getTimezoneOffset() >= 0, + hours = FLOOR(self.getTimezoneOffset() / 60), minutes = self.getTimezoneOffset() - hours * 60; - return [CPString stringWithFormat:@"%04d-%02d-%02d %02d:%02d:%02d +%02d%02d", self.getFullYear(), self.getMonth()+1, self.getDate(), self.getHours(), self.getMinutes(), self.getSeconds(), hours, minutes]; + return [CPString stringWithFormat:@"%04d-%02d-%02d %02d:%02d:%02d %s%02d%02d", self.getFullYear(), self.getMonth()+1, self.getDate(), self.getHours(), self.getMinutes(), self.getSeconds(), positive ? "+" : "-", ABS(hours), ABS(minutes)]; } - (id)copy diff --git a/Foundation/CPDictionary.j b/Foundation/CPDictionary.j index f805282f2..4fd2d46d8 100755 --- a/Foundation/CPDictionary.j +++ b/Foundation/CPDictionary.j @@ -21,9 +21,9 @@ */ @import "CPArray.j" -@import "CPObject.j" @import "CPEnumerator.j" @import "CPException.j" +@import "CPObject.j" /* @ignore */ @@ -36,20 +36,20 @@ - (id)initWithDictionary:(CPDictionary)aDictionary { self = [super init]; - + if (self) { _keyEnumerator = [aDictionary keyEnumerator]; _dictionary = aDictionary; } - + return self; } - (id)nextObject { var key = [_keyEnumerator nextObject]; - + if (!key) return nil; @@ -58,7 +58,7 @@ @end -/*! +/*! @class CPDictionary @ingroup foundation @brief A mutable key-value pair collection. @@ -145,29 +145,33 @@ */ + (id)dictionaryWithJSObject:(JSObject)object recursively:(BOOL)recursively { - var dictionary = [[self alloc] init]; - - for (var key in object) + var key = "", + dictionary = [[self alloc] init]; + + for (key in object) { if (!object.hasOwnProperty(key)) continue; var value = object[key]; - + if (value === null) { [dictionary setObject:[CPNull null] forKey:key]; continue; } - + if (recursively) { if (value.constructor === Object) value = [CPDictionary dictionaryWithJSObject:value recursively:YES]; else if ([value isKindOfClass:CPArray]) { - var newValue = []; - for (var i = 0, count = value.length; i < count; i++) + var newValue = [], + i = 0, + count = value.length; + + for (; i < count; i++) { var thisValue = value[i]; @@ -183,7 +187,7 @@ [dictionary setObject:value forKey:key]; } - + return dictionary; } @@ -193,22 +197,22 @@ @param ... key for the first object and ongoing value-key pairs for more objects. @throws CPInvalidArgumentException if the number of objects and keys is different @return the new CPDictionary - + Assuming that there's no object retaining in Cappuccino, you can create dictionaries same way as with alloc and initWithObjectsAndKeys: var dict = [CPDictionary dictionaryWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2"]; - + Note, that there's no final nil like in Objective-C/Cocoa. - + @see [CPDictionary initWithObjectsAndKeys:] */ + (id)dictionaryWithObjectsAndKeys:(id)firstObject, ... { arguments[0] = [self alloc]; arguments[1] = @selector(initWithObjectsAndKeys:); - + return objj_msgSend.apply(this, arguments); } @@ -221,10 +225,10 @@ { var key = "", dictionary = [[CPDictionary alloc] init]; - + for (key in aDictionary._buckets) [dictionary setObject:[aDictionary objectForKey:key] forKey:key]; - + return dictionary; } @@ -240,16 +244,16 @@ self = [super init]; if ([objects count] != [keyArray count]) - [CPException raise:CPInvalidArgumentException reason:"Counts are different.("+[objects count]+"!="+[keyArray count]+")"]; + [CPException raise:CPInvalidArgumentException reason:"Counts are different.(" + [objects count] + "!=" + [keyArray count] + ")"]; if (self) { var i = [keyArray count]; - + while (i--) [self setObject:objects[i] forKey:keyArray[i]]; } - + return self; } @@ -259,29 +263,29 @@ @param ... key for the first object and ongoing value-key pairs for more objects. @throws CPInvalidArgumentException if the number of objects and keys is different @return the new CPDictionary - + You can create dictionaries this way: var dict = [[CPDictionary alloc] initWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2"]; - + Note, that there's no final nil like in Objective-C/Cocoa. */ - (id)initWithObjectsAndKeys:(id)firstObject, ... { var argCount = arguments.length; - + if (argCount % 2 !== 0) [CPException raise:CPInvalidArgumentException reason:"Key-value count is mismatched. (" + argCount + " arguments passed)"]; self = [super init]; - + if (self) { // The arguments array contains self and _cmd, so the first object is at position 2. var index = 2; - - for(; index < argCount; index += 2) + + for (; index < argCount; index += 2) { var value = arguments[index]; @@ -316,7 +320,7 @@ */ - (CPArray)allKeys { - return _keys; + return [_keys copy]; } /*! @@ -326,7 +330,7 @@ { var index = _keys.length, values = []; - + while (index--) values.push(self.valueForKey(_keys[index])); @@ -350,7 +354,7 @@ } /*! - Compare the receiver to this dictionary, and return whether or not they are equal. + Compare the receiver to this dictionary, and return whether or not they are equal. */ - (BOOL)isEqualToDictionary:(CPDictionary)aDictionary { @@ -372,10 +376,10 @@ if (lhsObject === rhsObject) continue; - + if (lhsObject && lhsObject.isa && rhsObject && rhsObject.isa && [lhsObject respondsToSelector:@selector(isEqual:)] && [lhsObject isEqual:rhsObject]) continue; - + return NO; } @@ -399,9 +403,9 @@ var i= 0, keys= CPArray.array(), count= this.count(); - - while((i= this._objects.indexOfObjectInRage(0, count-i))!=CPNotFound) keys.addObject(this._keys[i]); - + + while ((i= this._objects.indexOfObjectInRage(0, count-i))!=CPNotFound) keys.addObject(this._keys[i]); + return keys; } @@ -412,7 +416,7 @@ { return aSelector.apply(dictionary.objectForKey(this), [dictionary.objectForKey(rhs)]); }; - + return this._keys.sortedArrayUsingSelector(objectSelector); } */ @@ -424,7 +428,7 @@ - (id)objectForKey:(CPString)aKey { var object = _buckets[aKey]; - + return (object === undefined) ? nil : object; } /* @@ -432,20 +436,20 @@ { var i= keys.length, objects= CPArray.array(); - - while(i--) + + while (i--) { var object= this.objectForKey(keys[i]); objects.addObject(object==nil?aNotFoundMarker:object); } - + return objects; } - + Instance.valueForKey(aKey) { - if(aKey.length && aKey[0]=="@") return this.objectForKey(aKey.substr(1)); - + if (aKey.length && aKey[0]=="@") return this.objectForKey(aKey.substr(1)); + return base.valueForKey(aKey); } */ @@ -475,7 +479,7 @@ var index = keysForRemoval.length; while (index--) - self.removeValueForKey(keysForRemoval[index]); + [self removeObjectForKey:keysForRemoval[index]]; } /* @@ -483,11 +487,11 @@ { this._keys= CPArray.arrayWithArray(aDictionary.allKeys()); this._objects= CPArray.arrayWithArray(aDictionary.allValues()); - + this._dictionary= { }; - + var i= this._keys.count(); - while(i--) this._dictionary[this._keys[i]]= { object: this._objects[i], index: i }; + while (i--) this._dictionary[this._keys[i]]= { object: this._objects[i], index: i }; } */ /*! @@ -507,10 +511,10 @@ { if (!aDictionary) return; - + var keys = [aDictionary allKeys], index = [keys count]; - + while (index--) { var key = keys[index]; diff --git a/Foundation/CPEnumerator.j b/Foundation/CPEnumerator.j index 51d25b92a..50efcb571 100755 --- a/Foundation/CPEnumerator.j +++ b/Foundation/CPEnumerator.j @@ -22,15 +22,12 @@ @import "CPObject.j" -/*! - -*/ -/*! +/*! @class CPEnumerator @ingroup foundation @brief Defines an interface for enumerators. - + CPEnumerator is a superclass (with useless method bodies) that defines an interface for subclasses to follow. The purpose of an enumerator is to be a convenient system for traversing over the elements diff --git a/Foundation/CPException.j b/Foundation/CPException.j index 28abb60ec..770c6ad63 100755 --- a/Foundation/CPException.j +++ b/Foundation/CPException.j @@ -30,7 +30,7 @@ CPUnsupportedMethodException = "CPUnsupportedMethodException"; CPRangeException = "CPRangeException"; CPInternalInconsistencyException = "CPInternalInconsistencyException"; -/*! +/*! @class CPException @ingroup foundation @brief Used to implement exception handling (creating & raising). @@ -40,7 +40,7 @@ CPInternalInconsistencyException = "CPInternalInconsistencyException"; // some code here... if (input == nil) [CPException raise:"MyException" reason:"You didn't do something right."]; - + // code that gets executed if no exception was raised */ @@ -96,7 +96,7 @@ if (input == nil) message = aReason; _userInfo = aUserInfo; } - + return self; } @@ -165,14 +165,14 @@ var CPExceptionNameKey = "CPExceptionNameKey", - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) { name = [aCoder decodeObjectForKey:CPExceptionNameKey]; message = [aCoder decodeObjectForKey:CPExceptionReasonKey]; _userInfo = [aCoder decodeObjectForKey:CPExceptionUserInfoKey]; } - + return self; } diff --git a/Foundation/CPFunctionOperation.j b/Foundation/CPFunctionOperation.j index 795058737..f9f98c911 100644 --- a/Foundation/CPFunctionOperation.j +++ b/Foundation/CPFunctionOperation.j @@ -23,22 +23,24 @@ @import "CPOperation.j" -/*! +/*! @class CPFunctionOperation @brief Represents an operation using a JavaScript function that can be run in an CPOperationQueue */ -@implementation CPFunctionOperation : CPOperation +@implementation CPFunctionOperation : CPOperation { CPArray _functions; } -- (void)main +- (void)main { - if (_functions && [_functions count] > 0) + if (_functions && [_functions count] > 0) { - var i = 0; - for (i = 0; i < [_functions count]; i++) + var i = 0, + count = [_functions count]; + + for (; i < count; i++) { var func = [_functions objectAtIndex:i]; func(); @@ -46,9 +48,9 @@ } } -- (id)init +- (id)init { - if (self = [super init]) + if (self = [super init]) { _functions = []; } @@ -58,7 +60,7 @@ /*! Adds the specified JS function to the receiver’s list of functions to perform. */ -- (void)addExecutionFunction:(JSObject)jsFunction +- (void)addExecutionFunction:(JSObject)jsFunction { [_functions addObject:jsFunction]; } @@ -66,7 +68,7 @@ /*! Returns an array containing the functions associated with the receiver. */ -- (CPArray)executionFunctions +- (CPArray)executionFunctions { return _functions; } @@ -74,12 +76,12 @@ /*! Creates and returns an NSFunctionOperation object and adds the specified function to it. */ -+ (id)functionOperationWithFunction:(JSObject)jsFunction ++ (id)functionOperationWithFunction:(JSObject)jsFunction { functionOp = [[CPFunctionOperation alloc] init]; [functionOp addExecutionFunction:jsFunction]; - + return functionOp; } -@end \ No newline at end of file +@end diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 60e6736e9..266c7273e 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -20,14 +20,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPRange.j" @import "CPObject.j" +@import "CPRange.j" + #define _CPMaxRange(aRange) ((aRange).location + (aRange).length) #define _CPMakeRange(aLocation, aLength) { location:(aLocation), length:aLength } #define _CPMakeRangeCopy(aRange) { location:(aRange).location, length:(aRange).length } -/*! +/*! @class CPIndexSet @ingroup foundation @brief A collection of unique integers. @@ -179,7 +180,7 @@ return NO; // If we have less total indexes than aRange, we can't possibly contain aRange. - if(_count < aRange.length) + if (_count < aRange.length) return NO; // Search for first location @@ -203,7 +204,7 @@ { var otherCount = anIndexSet._count; - if(otherCount <= 0) + if (otherCount <= 0) return YES; // If we have less total indexes than anIndexSet, we can't possibly contain aRange. @@ -692,7 +693,7 @@ var i = _ranges.length - 1, shifted = CPMakeRange(CPNotFound, 0); - for(; i >= 0; --i) + for (; i >= 0; --i) { var range = _ranges[i], maximum = CPMaxRange(range); @@ -700,7 +701,7 @@ if (anIndex > maximum) break; - // If our index is within our range, but not the first index, + // If our index is within our range, but not the first index, // then this range will be split. if (anIndex > range.location && anIndex < maximum) { diff --git a/Foundation/CPInvocation.j b/Foundation/CPInvocation.j index 19e8c2cb1..da66a2a68 100644 --- a/Foundation/CPInvocation.j +++ b/Foundation/CPInvocation.j @@ -20,11 +20,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPObject.j" @import "CPException.j" +@import "CPObject.j" -/*! +/*! @class CPInvocation @ingroup foundation @brief An object representation of a message. @@ -57,13 +57,13 @@ - (id)initWithMethodSignature:(CPMethodSignature)aMethodSignature { self = [super init]; - + if (self) { _arguments = []; _methodSignature = aMethodSignature; } - + return self; } @@ -174,13 +174,13 @@ var CPInvocationArguments = @"CPInvocationArguments", - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) { _returnValue = [aCoder decodeObjectForKey:CPInvocationReturnValue]; _arguments = [aCoder decodeObjectForKey:CPInvocationArguments]; } - + return self; } diff --git a/Foundation/CPInvocationOperation.j b/Foundation/CPInvocationOperation.j index e98fc6c49..0c1bdfda6 100644 --- a/Foundation/CPInvocationOperation.j +++ b/Foundation/CPInvocationOperation.j @@ -19,32 +19,32 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import -@import +@import "CPInvocation.j" +@import "CPObject.j" @import "CPOperation.j" -/*! +/*! @class CPInvocationOperation @brief Represents an operation using an invocation that can be run in an CPOperationQueue */ -@implementation CPInvocationOperation : CPOperation +@implementation CPInvocationOperation : CPOperation { CPInvocation _invocation; } -- (void)main +- (void)main { - if (_invocation) + if (_invocation) { [_invocation invoke]; } } -- (id)init +- (id)init { - if (self = [super init]) + if (self = [super init]) { _invocation = nil; } @@ -55,13 +55,13 @@ Returns a CPInvocationOperation object initialized with the specified invocation object. @param inv the invocation */ -- (id)initWithInvocation:(CPInvocation)inv +- (id)initWithInvocation:(CPInvocation)inv { - if (self = [self init]) + if (self = [self init]) { _invocation = inv; } - + return self; } @@ -71,20 +71,20 @@ @param sel the selector that should be called on the target @param arg the arguments */ -- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg +- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg { var inv = [[CPInvocation alloc] initWithMethodSignature:nil]; [inv setTarget:target]; [inv setSelector:sel]; [inv setArgument:arg atIndex:2]; - + return [self initWithInvocation:inv]; } /*! Returns the receiver’s invocation object. */ -- (CPInvocation)invocation +- (CPInvocation)invocation { return _invocation; } @@ -92,16 +92,14 @@ /*! Returns the result of the invocation or method. */ -- (id)result +- (id)result { - if ([self isFinished] && _invocation) + if ([self isFinished] && _invocation) { return [_invocation returnValue]; } - + return nil; } - - -@end \ No newline at end of file +@end diff --git a/Foundation/CPJSONPConnection.j b/Foundation/CPJSONPConnection.j index 031ef7eb2..c95a362c5 100644 --- a/Foundation/CPJSONPConnection.j +++ b/Foundation/CPJSONPConnection.j @@ -19,15 +19,15 @@ * 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 + +@import "CPObject.j" CPJSONPConnectionCallbacks = {}; CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}"; -/*! +/*! @ingroup foundation @brief Allows cross domain connections using JSONP protocol. @@ -43,13 +43,13 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}"; { CPURLRequest _request; id _delegate; - + CPString _callbackParameter; DOMElement _scriptTag; } /*! @deprecated */ -+ (CPJSONPConnection)sendRequest:(CPURLRequest)aRequest callback:(CPString)callbackParameter delegate:(id)aDelegate ++ (CPJSONPConnection)sendRequest:(CPURLRequest)aRequest callback:(CPString)callbackParameter delegate:(id)aDelegate { return [self connectionWithRequest:aRequest callback:callbackParameter delegate:aDelegate]; } @@ -59,7 +59,7 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}"; return [[[self class] alloc] initWithRequest:aRequest callback:callbackParameter delegate:aDelegate startImmediately:YES]; } -- (id)initWithRequest:(CPURLRequest)aRequest callback:(CPString)aString delegate:(id)aDelegate +- (id)initWithRequest:(CPURLRequest)aRequest callback:(CPString)aString delegate:(id)aDelegate { return [self initWithRequest:aRequest callback:aString delegate:aDelegate startImmediately: NO]; } @@ -67,18 +67,18 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}"; - (id)initWithRequest:(CPURLRequest)aRequest callback:(CPString)aString delegate:(id)aDelegate startImmediately:(BOOL)shouldStartImmediately { self = [super init]; - + _request = aRequest; _delegate = aDelegate; - + _callbackParameter = aString; - + if (!_callbackParameter && [[_request URL] absoluteString].indexOf(CPJSONPCallbackReplacementString) < 0) [CPException raise:CPInvalidArgumentException reason:@"JSONP source specified without callback parameter or CPJSONPCallbackReplacementString in URL."]; - if(shouldStartImmediately) + if (shouldStartImmediately) [self start]; - + return self; } @@ -93,9 +93,9 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}"; if ([_delegate respondsToSelector:@selector(connectionDidFinishLoading:)]) [_delegate connectionDidFinishLoading:self]; - + [self removeScriptTag]; - + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; }; @@ -113,12 +113,12 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}"; } else return; - + _scriptTag = document.createElement("script"); _scriptTag.setAttribute("type", "text/javascript"); _scriptTag.setAttribute("charset", "utf-8"); _scriptTag.setAttribute("src", source); - + head.appendChild(_scriptTag); } catch (exception) @@ -133,12 +133,12 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}"; - (void)removeScriptTag { var head = document.getElementsByTagName("head").item(0); - + if(_scriptTag && _scriptTag.parentNode == head) head.removeChild(_scriptTag); - CPJSONPConnectionCallbacks["callback"+[self UID]] = nil; - delete CPJSONPConnectionCallbacks["callback"+[self UID]]; + CPJSONPConnectionCallbacks["callback" + [self UID]] = nil; + delete CPJSONPConnectionCallbacks["callback" + [self UID]]; } - (void)cancel diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j index 36ef5b48c..104a6931f 100644 --- a/Foundation/CPKeyValueCoding.j +++ b/Foundation/CPKeyValueCoding.j @@ -25,6 +25,7 @@ @import "CPNull.j" @import "CPObject.j" + var CPObjectAccessorsForClass = nil, CPObjectModifiersForClass = nil; @@ -44,41 +45,41 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; { if (!CPObjectAccessorsForClass) CPObjectAccessorsForClass = [CPDictionary dictionary]; - + var UID = [isa UID], selector = nil, accessors = [CPObjectAccessorsForClass objectForKey:UID]; - + if (accessors) { selector = [accessors objectForKey:aKey]; - + if (selector) return selector === [CPNull null] ? nil : selector; } else { accessors = [CPDictionary dictionary]; - + [CPObjectAccessorsForClass setObject:accessors forKey:UID]; } var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1); - - if ([self instancesRespondToSelector:selector = CPSelectorFromString("get" + capitalizedKey)] || - [self instancesRespondToSelector:selector = CPSelectorFromString(aKey)] || - [self instancesRespondToSelector:selector = CPSelectorFromString("is" + capitalizedKey)] || - [self instancesRespondToSelector:selector = CPSelectorFromString("_get" + capitalizedKey)] || - [self instancesRespondToSelector:selector = CPSelectorFromString("_" + aKey)] || + + if ([self instancesRespondToSelector:selector = CPSelectorFromString("get" + capitalizedKey)] || + [self instancesRespondToSelector:selector = CPSelectorFromString(aKey)] || + [self instancesRespondToSelector:selector = CPSelectorFromString("is" + capitalizedKey)] || + [self instancesRespondToSelector:selector = CPSelectorFromString("_get" + capitalizedKey)] || + [self instancesRespondToSelector:selector = CPSelectorFromString("_" + aKey)] || [self instancesRespondToSelector:selector = CPSelectorFromString("_is" + capitalizedKey)]) { [accessors setObject:selector forKey:aKey]; - + return selector; } - + [accessors setObject:[CPNull null] forKey:aKey]; - + return nil; } @@ -87,25 +88,25 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; { if (!CPObjectModifiersForClass) CPObjectModifiersForClass = [CPDictionary dictionary]; - + var UID = [isa UID], selector = nil, modifiers = [CPObjectModifiersForClass objectForKey:UID]; - + if (modifiers) { selector = [modifiers objectForKey:aKey]; - + if (selector) return selector === [CPNull null] ? nil : selector; } else { modifiers = [CPDictionary dictionary]; - + [CPObjectModifiersForClass setObject:modifiers forKey:UID]; } - + if (selector) return selector === [CPNull null] ? nil : selector; @@ -115,12 +116,12 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; [self instancesRespondToSelector:selector = CPSelectorFromString("_set" + capitalizedKey)]) { [modifiers setObject:selector forKey:aKey]; - + return selector; } - + [modifiers setObject:[CPNull null] forKey:aKey]; - + return nil; } @@ -128,30 +129,30 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; - (CPString)_ivarForKey:(CPString)aKey { var ivar = '_' + aKey; - + if (typeof self[ivar] != "undefined") return ivar; var isKey = "is" + aKey.charAt(0).toUpperCase() + aKey.substr(1); - ivar = '_' + isKey; - + ivar = '_' + isKey; + if (typeof self[ivar] != "undefined") return ivar; - + ivar = aKey; - + if (typeof self[ivar] != "undefined") return ivar; - + ivar = isKey; - + if (typeof self[ivar] != "undefined") return ivar; return nil; } - + - (id)valueForKey:(CPString)aKey { var theClass = [self class], @@ -159,18 +160,18 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; if (selector) return objj_msgSend(self, selector); - - if([theClass accessInstanceVariablesDirectly]) + + if ([theClass accessInstanceVariablesDirectly]) { var ivar = [self _ivarForKey:aKey]; - + if (ivar) return self[ivar]; } - + return [self valueForUndefinedKey:aKey]; } - + - (id)valueForKeyPath:(CPString)aKeyPath { var firstDotIndex = aKeyPath.indexOf("."); @@ -179,7 +180,7 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; return [self valueForKey:aKeyPath]; var firstKeyComponent = aKeyPath.substring(0, firstDotIndex), - remainingKeyPath = aKeyPath.substring(firstDotIndex+1), + remainingKeyPath = aKeyPath.substring(firstDotIndex + 1), value = [self valueForKey:firstKeyComponent]; return [value valueForKeyPath:remainingKeyPath]; @@ -190,7 +191,7 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; var index = 0, count = keys.length, dictionary = [CPDictionary dictionary]; - + for (; index < count; ++index) { var key = keys[index], @@ -201,7 +202,7 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; else [dictionary setObject:value forKey:key]; } - + return dictionary; } @@ -211,7 +212,7 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; reason:[self description] + " is not key value coding-compliant for the key " + aKey userInfo:[CPDictionary dictionaryWithObjects:[self, aKey] forKeys:[CPTargetObjectUserInfoKey, CPUnknownUserInfoKey]]] raise]; } - + - (void)setValue:(id)aValue forKeyPath:(CPString)aKeyPath { if (!aKeyPath) aKeyPath = "self"; @@ -221,12 +222,12 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; count = keys.length - 1, owner = self; - for(; i < count; ++i) + for (; i < count; ++i) owner = [owner valueForKey:keys[i]]; - + [owner setValue:aValue forKey:keys[i]]; } - + - (void)setValue:(id)aValue forKey:(CPString)aKey { var theClass = [self class], @@ -234,26 +235,26 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; if (selector) return objj_msgSend(self, selector, aValue); - - if([theClass accessInstanceVariablesDirectly]) + + if ([theClass accessInstanceVariablesDirectly]) { var ivar = [self _ivarForKey:aKey]; - + if (ivar) { [self willChangeValueForKey:aKey]; - + self[ivar] = aValue; - + [self didChangeValueForKey:aKey]; return; } } - + [self setValue:aValue forUndefinedKey:aKey]; } - + - (void)setValue:(id)aValue forUndefinedKey:(CPString)aKey { [[CPException exceptionWithName:CPUndefinedKeyException @@ -267,7 +268,10 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; - (id)valueForKey:(CPString)aKey { - return [self objectForKey:aKey]; + if ([aKey hasPrefix:@"@"]) + return [super valueForKey:aKey.substr(1)]; + + return [self objectForKey:aKey]; } - (void)setValue:(id)aValue forKey:(CPString)aKey diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 9662d5064..0ff9fdd26 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -50,7 +50,7 @@ { if (!anObserver || !aPath) return; - + //CPLog.warn(anObserver+" is adding itself as an observer to object: "+self+" forKeyPath: "+aPath+" context: "+aContext); [[_CPKVOProxy proxyForObject:self] _addObserver:anObserver forKeyPath:aPath options:options context:aContext]; } @@ -224,52 +224,69 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)_replaceClass { var currentClass = _nativeClass, - kvoClassName = "$KVO_"+class_getName(_nativeClass), + kvoClassName = "$KVO_" + class_getName(_nativeClass), existingKVOClass = objj_lookUpClass(kvoClassName); - + if (existingKVOClass) { _targetObject.isa = existingKVOClass; return; } - + var kvoClass = objj_allocateClassPair(currentClass, kvoClassName); - + objj_registerClassPair(kvoClass); - + //copy in the methods from our model subclass var methodList = _CPKVOModelSubclass.method_list, - count = methodList.length; + count = methodList.length, + i = 0; - for (var i=0; i O(N^2)), so to avoid it, - // we keep track of whether observers are added or removed, and only do our + // we keep track of whether observers are added or removed, and only do our // rigorous testing in those cases. var observerRemovalCount = _observerRemovalCount, object = [aNotification object], @@ -286,18 +286,18 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */ { var currentObservers = observers, count = observers.length; - + while (count--) { var observer = observers[count]; - - // if there wasn't removal of an observer during this posting, or there - // was but we are still in the observer list... + + // if there wasn't removal of an observer during this posting, or there + // was but we are still in the observer list... if ((observerRemovalCount === _observerRemovalCount) || [currentObservers indexOfObjectIdenticalTo:observer] !== CPNotFound) [observer postNotification:aNotification]; } } - + // Now do the same for the nil object observers... observers = [[_objectObservers objectForKey:[[CPNull null] UID]] copy]; @@ -312,8 +312,8 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */ { var observer = observers[count]; - // if there wasn't removal of an observer during this posting, or there - // was but we are still in the observer list... + // if there wasn't removal of an observer during this posting, or there + // was but we are still in the observer list... if ((observerRemovalCount === _observerRemovalCount) || [currentObservers indexOfObjectIdenticalTo:observer] !== CPNotFound) [observer postNotification:aNotification]; } @@ -349,7 +349,7 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */ return _observer; } --(void)postNotification:(CPNotification)aNotification +- (void)postNotification:(CPNotification)aNotification { [_observer performSelector:_selector withObject:aNotification]; } diff --git a/Foundation/CPNumber.j b/Foundation/CPNumber.j index 8712b2ac2..a0bbef39e 100644 --- a/Foundation/CPNumber.j +++ b/Foundation/CPNumber.j @@ -27,15 +27,15 @@ var __placeholder = new Number(), CPNumberUIDs = new CFMutableDictionary(); -/*! +/*! @class CPNumber @ingroup foundation @brief A bridged object to native Javascript numbers. This class primarily exists for source compatability. The JavaScript \c Number type can be changed on the fly based on context, - so there is no need to call any of these methods. - + so there is no need to call any of these methods. + In other words, native JavaScript numbers are bridged to CPNumber, so you can use them interchangeably (including operators and methods). */ @@ -93,7 +93,7 @@ var __placeholder = new Number(), { if (aChar.charCodeAt) return aChar.charCodeAt(0); - + return aChar; } @@ -126,7 +126,7 @@ var __placeholder = new Number(), { if (aChar.charCodeAt) return aChar.charCodeAt(0); - + return aChar; } @@ -164,7 +164,7 @@ var __placeholder = new Number(), { if (aChar.charCodeAt) return aChar.charCodeAt(0); - + return aChar; } @@ -223,7 +223,7 @@ FIXME: Do we need this? - (CPString)descriptionWithLocale:(CPDictionary)aDictionary { if (!aDictionary) return toString(); - + throw new Error("descriptionWithLocale: NOT YET IMPLEMENTED"); } @@ -273,7 +273,7 @@ FIXME: Do we need this? return toString(); } -- (unsigned char)unsignedCharValue +- (unsigned char)unsignedCharValue { return String.fromCharCode(self); } @@ -306,7 +306,7 @@ FIXME: Do we need this? { if (self > aNumber) return CPOrderedDescending; else if (self < aNumber) return CPOrderedAscending; - + return CPOrderedSame; } diff --git a/Foundation/CPObjJRuntime.j b/Foundation/CPObjJRuntime.j index 76cfb8f76..019888d19 100644 --- a/Foundation/CPObjJRuntime.j +++ b/Foundation/CPObjJRuntime.j @@ -20,8 +20,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPLog.j" - function CPStringFromSelector(aSelector) { @@ -44,7 +42,7 @@ function CPStringFromClass(aClass) } CPOrderedAscending = -1; -CPOrderedSame = 0; +CPOrderedSame = 0; CPOrderedDescending = 1; CPNotFound = -1; diff --git a/Foundation/CPObject.j b/Foundation/CPObject.j index b6c276ee6..34d023421 100644 --- a/Foundation/CPObject.j +++ b/Foundation/CPObject.j @@ -24,27 +24,27 @@ @class CPObject @ingroup foundation @brief The root class from which most classes are subclassed. - + CPObject is the root class for most Cappuccino classes. Like in Objective-C, you have to declare parent class explicitly in Objective-J, so your custom classes should almost always subclass CPObject or one of its children. - + CPObject provides facilities for class allocation and initialization, querying runtime about parent classes and available selectors, using KVC (key-value coding). - + When you subclass CPObject, most of the time you override one selector - init. It is called for default initialization of custom object. You must call parent class init in your overriden code:

- (id)init
 {
     self = [super init];
-    if(self) {
+    if (self) {
         ... provide default initialization code for your object ...
     }
     return self;
 }
- + One more useful thing to override is description(). This selector is used to provide developer-readable information about object. description selector is often used with CPLog debugging: @@ -58,7 +58,7 @@ CPLog(@"Got some class: %@", inst); would output: \c Got \c some \c class: \c - + @todo document KVC usage. */ @implementation CPObject @@ -164,11 +164,11 @@ CPLog(@"Got some class: %@", inst); + (BOOL)isSubclassOfClass:(Class)aClass { var theClass = self; - - for(; theClass; theClass = theClass.super_class) - if(theClass === aClass) + + for (; theClass; theClass = theClass.super_class) + if (theClass === aClass) return YES; - + return NO; } @@ -231,6 +231,23 @@ CPLog(@"Got some class: %@", inst); return !!class_getInstanceMethod(isa, aSelector); } +/*! + Tests whether the receiver implements to the provided selector regardless of inheritance. + @param aSelector the selector for which to test the receiver + @return \c YES if the receiver implements the selector +*/ +- (BOOL)implementsSelector:(SEL)aSelector +{ + var methods = class_copyMethodList(isa), + count = methods.length; + + while (count--) + if (method_getName(methods[count]) === aSelector) + return YES; + + return NO; +} + // Obtaining method information /*! @@ -332,25 +349,25 @@ CPLog(@"Got some class: %@", inst); - (void)forward:(SEL)aSelector :(marg_list)args { var signature = [self methodSignatureForSelector:aSelector]; - + if (signature) { invocation = [CPInvocation invocationWithMethodSignature:signature]; - + [invocation setTarget:self]; [invocation setSelector:aSelector]; - + var index = 2, count = args.length; - + for (; index < count; ++index) [invocation setArgument:args[index] atIndex:index]; - + [self forwardInvocation:invocation]; - + return [invocation returnValue]; } - + [self doesNotRecognizeSelector:aSelector]; } @@ -436,7 +453,7 @@ CPLog(@"Got some class: %@", inst); + (id)setVersion:(int)aVersion { version = aVersion; - + return self; } @@ -531,7 +548,7 @@ CPLog(@"Got some class: %@", inst); objj_class.prototype.toString = objj_object.prototype.toString = function() { if (this.isa && class_getInstanceMethod(this.isa, "description") != NULL) - return [this description] + return [this description]; else return String(this) + " (-description not implemented)"; } diff --git a/Foundation/CPOperation.j b/Foundation/CPOperation.j index e24617ae7..710dc5961 100644 --- a/Foundation/CPOperation.j +++ b/Foundation/CPOperation.j @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import +@import "CPObject.j" /*! Operations receive very low priority for execution. @@ -57,13 +57,13 @@ CPOperationQueuePriorityHigh = 4; CPOperationQueuePriorityVeryHigh = 8; -/*! +/*! @class CPOperation @brief Represents an operation that can be run in an CPOperationQueue It should be subclassed an the subclass should implement its own main method to do the actual work. */ -@implementation CPOperation : CPObject +@implementation CPOperation : CPObject { CPArray operations; BOOL _cancelled; @@ -75,15 +75,14 @@ CPOperationQueuePriorityVeryHigh = 8; CPArray _dependencies; } - -- (void)main +- (void)main { // should be overridden in child class } -- (id)init +- (id)init { - if (self = [super init]) + if (self = [super init]) { _cancelled = NO; _executing = NO; @@ -98,15 +97,15 @@ CPOperationQueuePriorityVeryHigh = 8; /*! Starts the operation (runs the main method), sets all the status flags and runs the completion function if it's set */ -- (void)start +- (void)start { - if (!_cancelled) + if (!_cancelled) { [self willChangeValueForKey:@"isExecuting"]; _executing = YES; [self didChangeValueForKey:@"isExecuting"]; [self main]; - if (_completionFunction) + if (_completionFunction) { _completionFunction(); } @@ -123,7 +122,7 @@ CPOperationQueuePriorityVeryHigh = 8; Indicates if this operation has been cancelled @return if this operation has been cancelled */ -- (BOOL)isCancelled +- (BOOL)isCancelled { return _cancelled; } @@ -132,7 +131,7 @@ CPOperationQueuePriorityVeryHigh = 8; Indicates if this operation is currently executing @return if this operation is currently executing */ -- (BOOL)isExecuting +- (BOOL)isExecuting { return _executing; } @@ -141,7 +140,7 @@ CPOperationQueuePriorityVeryHigh = 8; Indicates if this operation has finished running @return if this operation has finished running */ -- (BOOL)isFinished +- (BOOL)isFinished { return _finished; } @@ -150,7 +149,7 @@ CPOperationQueuePriorityVeryHigh = 8; Just added for Cocoa compatibility @return always false */ -- (BOOL)isConcurrent +- (BOOL)isConcurrent { return NO; } @@ -159,8 +158,8 @@ CPOperationQueuePriorityVeryHigh = 8; Indicates if this operation is ready to be executed. Takes the "isFinished" state of dependent operations into account @return if this operation is ready to run */ -- (BOOL)isReady -{ +- (BOOL)isReady +{ return _ready; } @@ -168,7 +167,7 @@ CPOperationQueuePriorityVeryHigh = 8; The JS function that should be run after the main method @return JS function */ -- (JSObject)completionFunction +- (JSObject)completionFunction { return _completionFunction; } @@ -176,7 +175,7 @@ CPOperationQueuePriorityVeryHigh = 8; /*! Sets the JS function that should be run after the main method */ -- (void)setCompletionFunction:(JSObject)aJavaScriptFunction +- (void)setCompletionFunction:(JSObject)aJavaScriptFunction { _completionFunction = aJavaScriptFunction; } @@ -185,7 +184,7 @@ CPOperationQueuePriorityVeryHigh = 8; Makes the receiver dependent on the completion of the specified operation. @param anOperation the operation that the receiver should depend on */ -- (void)addDependency:(CPOperation)anOperation +- (void)addDependency:(CPOperation)anOperation { [self willChangeValueForKey:@"dependencies"]; [anOperation addObserver:self @@ -201,12 +200,12 @@ CPOperationQueuePriorityVeryHigh = 8; Removes the receiver’s dependence on the specified operation. @param anOperation the operation that the receiver should no longer depend on */ -- (void)removeDependency:(CPOperation)anOperation +- (void)removeDependency:(CPOperation)anOperation { [self willChangeValueForKey:@"dependencies"]; [_dependencies removeObject:anOperation]; [anOperation removeObserver:self - forKeyPath:@"isFinished"]; + forKeyPath:@"isFinished"]; [self didChangeValueForKey:@"dependencies"]; [self _updateIsReadyState]; } @@ -215,7 +214,7 @@ CPOperationQueuePriorityVeryHigh = 8; The operations that the receiver depends on @return array of operations */ -- (CPArray)dependencies +- (CPArray)dependencies { return _dependencies; } @@ -223,14 +222,14 @@ CPOperationQueuePriorityVeryHigh = 8; /*! Just added for Cocoa compatibility, doesn't do anything */ -- (void)waitUntilFinished +- (void)waitUntilFinished { } /*! Advises the operation object that it should stop executing its task. */ -- (void)cancel +- (void)cancel { [self willChangeValueForKey:@"isCancelled"]; _cancelled = YES; @@ -241,7 +240,7 @@ CPOperationQueuePriorityVeryHigh = 8; Sets the priority of the operation when used in an operation queue. @param priority the priority */ -- (void)setQueuePriority:(int)priority +- (void)setQueuePriority:(int)priority { _queuePriority = priority; } @@ -250,7 +249,7 @@ CPOperationQueuePriorityVeryHigh = 8; The priority of the operation when used in an operation queue. @return the priority */ -- (int)queuePriority +- (int)queuePriority { return _queuePriority; } @@ -261,28 +260,28 @@ CPOperationQueuePriorityVeryHigh = 8; change:(CPDictionary)change context:(void)context { - if (keyPath == @"isFinished") + if (keyPath == @"isFinished") { [self _updateIsReadyState]; } } -- (void)_updateIsReadyState +- (void)_updateIsReadyState { var newReady = YES; - if (_dependencies && [_dependencies count] > 0) + if (_dependencies && [_dependencies count] > 0) { var i = 0; - for (i = 0; i < [_dependencies count]; i++) + for (i = 0; i < [_dependencies count]; i++) { - if (![[_dependencies objectAtIndex:i] isFinished]) + if (![[_dependencies objectAtIndex:i] isFinished]) { newReady = NO; } } } - - if (newReady != _ready) + + if (newReady != _ready) { [self willChangeValueForKey:@"isReady"]; _ready = newReady; diff --git a/Foundation/CPOperationQueue.j b/Foundation/CPOperationQueue.j index ac4e4842b..b849cdd43 100644 --- a/Foundation/CPOperationQueue.j +++ b/Foundation/CPOperationQueue.j @@ -19,29 +19,29 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import -@import "CPOperation.j" -@import "CPInvocationOperation.j" @import "CPFunctionOperation.j" +@import "CPInvocationOperation.j" +@import "CPObject.j" +@import "CPOperation.j" // the global queue (mainQueue) var cpOperationMainQueue = nil; -/*! +/*! @class CPOperationQueue @brief Represents an operation queue that can run CPOperations */ -@implementation CPOperationQueue : CPObject +@implementation CPOperationQueue : CPObject { CPArray _operations; BOOL _suspended; CPString _name @accessors(property=name); - CPTimer _timer; + CPTimer _timer; } -- (id)init +- (id)init { - if (self = [super init]) + if (self = [super init]) { _operations = [[CPArray alloc] init]; _suspended = NO; @@ -55,35 +55,37 @@ var cpOperationMainQueue = nil; return self; } -- (void)_runNextOpsInQueue +- (void)_runNextOpsInQueue { - if (!_suspended && [self operationCount] > 0) + if (!_suspended && [self operationCount] > 0) { - var i = 0; - for (i = 0; i < [_operations count]; i++) + var i = 0, + count = [_operations count]; + + for (; i < count; i++) { var op = [_operations objectAtIndex:i]; - if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting]) + if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting]) { [op start]; - } + } } } } -- (void)_enableTimer:(BOOL)enable +- (void)_enableTimer:(BOOL)enable { - if (!enable) + if (!enable) { - if (_timer) + if (_timer) { [_timer invalidate]; _timer = nil; } - } - else + } + else { - if (!_timer) + if (!_timer) { _timer = [CPTimer scheduledTimerWithTimeInterval:0.01 target:self @@ -98,7 +100,7 @@ var cpOperationMainQueue = nil; Adds the specified operation object to the receiver. @param anOperation the operation that should be scheduled for execution */ -- (void)addOperation:(CPOperation)anOperation +- (void)addOperation:(CPOperation)anOperation { [self willChangeValueForKey:@"operations"]; [self willChangeValueForKey:@"operationCount"]; @@ -112,70 +114,72 @@ var cpOperationMainQueue = nil; Adds the specified array of operations to the queue. @param ops The array of CPOperation objects that you want to add to the receiver. @param wait If YES, the method only returns once all of the specified operations finish executing. If NO, the operations are added to the queue and control returns immediately to the caller. -*/ -- (void)addOperations:(CPArray)ops waitUntilFinished:(BOOL)wait +*/ +- (void)addOperations:(CPArray)ops waitUntilFinished:(BOOL)wait { - if (ops) + if (ops) { - if (wait) + if (wait) { [self _sortOpsByPriority:ops]; [self _runOpsSynchronously:ops]; - } - + } + [_operations addObjectsFromArray:ops]; [self _sortOpsByPriority:_operations]; - } + } } /*! Wraps the given js function in a CPOperation and adds it to the queue @param aFunction the JS function to add */ -- (void)addOperationWithFunction:(JSObject)aFunction +- (void)addOperationWithFunction:(JSObject)aFunction { [self addOperation:[CPFunctionOperation functionOperationWithFunction:aFunction]]; } -- (CPArray)operations +- (CPArray)operations { return _operations; } -- (int)operationCount +- (int)operationCount { - if (_operations) + if (_operations) { return [_operations count]; } - + return 0; } /*! Cancels all queued and executing operations. */ -- (void)cancelAllOperations +- (void)cancelAllOperations { - if (_operations) + if (_operations) { - var i = 0; - for (i = 0; i < [_operations count]; i++) - { - [[_operations objectAtIndex:i] cancel]; - } + var i = 0, + count = [_operations count]; + + for (; i < count; i++) + { + [[_operations objectAtIndex:i] cancel]; + } } } /*! Blocks until all of the receiver’s queued and executing operations finish executing. */ -- (void)waitUntilAllOperationsAreFinished +- (void)waitUntilAllOperationsAreFinished { // lets first stop the timer so it won't interfere [self _enableTimer:NO]; [self _runOpsSynchronously:_operations]; - if (!_suspended) + if (!_suspended) { [self _enableTimer:YES]; } @@ -186,7 +190,7 @@ var cpOperationMainQueue = nil; Returns the maximum number of concurrent operations that the receiver can execute. Always returns 1 because JS doesn't have threads */ -- (int)maxConcurrentOperationCount +- (int)maxConcurrentOperationCount { return 1; } @@ -195,7 +199,7 @@ var cpOperationMainQueue = nil; Modifies the execution of pending operations @param suspend if YES, queue execution is suspended. If NO, it is resumed */ -- (void)setSuspended:(BOOL)suspend +- (void)setSuspended:(BOOL)suspend { _suspended = suspend; [self _enableTimer:!suspend]; @@ -204,62 +208,64 @@ var cpOperationMainQueue = nil; /*! Returns a Boolean value indicating whether the receiver is scheduling queued operations for execution. */ -- (BOOL)isSuspended +- (BOOL)isSuspended { return _suspended; } -- (void)_sortOpsByPriority:(CPArray)someOps +- (void)_sortOpsByPriority:(CPArray)someOps { - if (someOps) + if (someOps) { - [someOps sortUsingFunction:function(lhs, rhs) + [someOps sortUsingFunction:function(lhs, rhs) { - if ([lhs queuePriority] < [rhs queuePriority]) + if ([lhs queuePriority] < [rhs queuePriority]) { return 1; - } - else + } + else { - if ([lhs queuePriority] > [rhs queuePriority]) + if ([lhs queuePriority] > [rhs queuePriority]) { return -1; - } - else + } + else { return 0; } } - } + } context:nil]; } } -- (void)_runOpsSynchronously:(CPArray)ops +- (void)_runOpsSynchronously:(CPArray)ops { - if (ops) + if (ops) { var keepGoing = YES; - while (keepGoing) + while (keepGoing) { - var i = 0; + var i = 0, + count = [ops count]; + keepGoing = NO; - + // start the ones that are ready - for (i = 0; i < [ops count]; i++) + for (; i < count; i++) { var op = [ops objectAtIndex:i]; - if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting]) + if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting]) { [op start]; - } + } } - + // make sure they are all done - for (i = 0; i < [ops count]; i++) + for (i = 0; i < count; i++) { var op = [ops objectAtIndex:i]; - if (![op isFinished] && ![op isCancelled]) + if (![op isFinished] && ![op isCancelled]) { keepGoing = YES; } @@ -271,23 +277,23 @@ var cpOperationMainQueue = nil; /*! Convenience method for one system wide singelton queue. Returns the same queue as currentQueue. */ -+ (CPOperationQueue)mainQueue ++ (CPOperationQueue)mainQueue { - if (!cpOperationMainQueue) + if (!cpOperationMainQueue) { cpOperationMainQueue = [[CPOperationQueue alloc] init]; [cpOperationMainQueue setName:@"main"]; } - + return cpOperationMainQueue; } /*! Convenience method for one system wide singelton queue. Returns the same queue as mainQueue. */ -+ (CPOperationQueue)currentQueue ++ (CPOperationQueue)currentQueue { return [CPOperationQueue mainQueue]; } -@end \ No newline at end of file +@end diff --git a/Foundation/CPProxy.j b/Foundation/CPProxy.j index 2d5fba736..2b4054c83 100644 --- a/Foundation/CPProxy.j +++ b/Foundation/CPProxy.j @@ -133,7 +133,7 @@ return [invocation returnValue]; } --(BOOL)isMemberOfClass:(Class)aClass +- (BOOL)isMemberOfClass:(Class)aClass { var signature = [self methodSignatureForSelector:_cmd], invocation = [CPInvocation invocationWithMethodSignature:signature]; diff --git a/Foundation/CPRange.j b/Foundation/CPRange.j index 6a0b1b5ce..b91a878d3 100755 --- a/Foundation/CPRange.j +++ b/Foundation/CPRange.j @@ -105,7 +105,7 @@ function CPLocationInRange(aLocation, aRange) } /*! - Creates a new range with the minimum \c location and a \c length + Creates a new range with the minimum \c location and a \c length that extends to the maximum \c length. @param lhsRange the first CPRange @param rhsRange the second CPRange @@ -129,7 +129,7 @@ function CPIntersectionRange(lhsRange, rhsRange) { if(CPMaxRange(lhsRange) < rhsRange.location || CPMaxRange(rhsRange) < lhsRange.location) return CPMakeRange(0, 0); - + var location = MAX(lhsRange.location, rhsRange.location); return CPMakeRange(location, MIN(CPMaxRange(lhsRange), CPMaxRange(rhsRange)) - location); } @@ -166,10 +166,11 @@ function CPStringFromRange(aRange) function CPRangeFromString(aString) { var comma = aString.indexOf(','); - + return { location:parseInt(aString.substr(1, comma - 1)), length:parseInt(aString.substring(comma + 1, aString.length)) }; } /*! @} */ + diff --git a/Foundation/CPRunLoop.j b/Foundation/CPRunLoop.j index 95ea272bd..89ad9337a 100644 --- a/Foundation/CPRunLoop.j +++ b/Foundation/CPRunLoop.j @@ -20,8 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPObject.j" @import "CPArray.j" +@import "CPObject.j" @import "CPString.j" /*! @@ -53,7 +53,7 @@ var _CPRunLoopPerformPool = [], { if (!aPerform || _CPRunLoopPerformPool.length >= _CPRunLoopPerformPoolCapacity) return; - + _CPRunLoopPerformPool.push(aPerform); } @@ -62,24 +62,24 @@ var _CPRunLoopPerformPool = [], if (_CPRunLoopPerformPool.length) { var perform = _CPRunLoopPerformPool.pop(); - + perform._target = aTarget; perform._selector = aSelector; perform._argument = anArgument; perform._order = anOrder; perform._runLoopModes = modes; perform._isValid = YES; - + return perform; } - + return [[self alloc] initWithSelector:aSelector target:aTarget argument:anArgument order:anOrder modes:modes]; } - (id)initWithSelector:(SEL)aSelector target:(SEL)aTarget argument:(id)anArgument order:(unsigned)anOrder modes:(CPArray)modes { self = [super init]; - + if (self) { _selector = aSelector; @@ -89,7 +89,7 @@ var _CPRunLoopPerformPool = [], _runLoopModes = modes; _isValid = YES; } - + return self; } @@ -117,14 +117,14 @@ var _CPRunLoopPerformPool = [], { if (!_isValid) return YES; - + if ([_runLoopModes containsObject:aRunLoopMode]) { [_target performSelector:_selector withObject:_argument]; - + return YES; } - + return NO; } @@ -174,16 +174,16 @@ var CPRunLoopLastNativeRunLoop = 0; - (id)init { self = [super init]; - + if (self) { _orderedPerforms = []; - + _timersForModes = {}; _nativeTimersForModes = {}; _nextTimerFireDatesForModes = {}; } - + return self; } @@ -220,7 +220,7 @@ var CPRunLoopLastNativeRunLoop = 0; while (count--) if (anOrder < [_orderedPerforms[count] order]) break; - + _orderedPerforms.splice(count + 1, 0, perform); } @@ -233,11 +233,11 @@ var CPRunLoopLastNativeRunLoop = 0; - (void)cancelPerformSelector:(SEL)aSelector target:(id)aTarget argument:(id)anArgument { var count = _orderedPerforms.length; - + while (count--) { var perform = _orderedPerforms[count]; - + if ([perform selector] === aSelector && [perform target] == aTarget && [perform argument] == anArgument) [_orderedPerforms[count] invalidate]; } @@ -261,12 +261,12 @@ var CPRunLoopLastNativeRunLoop = 0; _timersForModes[aMode].push(aTimer); else _timersForModes[aMode] = [aTimer]; - + _didAddTimer = YES; - + if (!aTimer._lastNativeRunLoopsForModes) aTimer._lastNativeRunLoopsForModes = {}; - + aTimer._lastNativeRunLoopsForModes[aMode] = CPRunLoopLastNativeRunLoop; @@ -305,96 +305,96 @@ var CPRunLoopLastNativeRunLoop = 0; var now = _effectiveDate ? [_effectiveDate laterDate:[CPDate date]] : [CPDate date], nextFireDate = nil, nextTimerFireDate = _nextTimerFireDatesForModes[aMode]; - + // Perform Timers if necessary if (_didAddTimer || nextTimerFireDate && nextTimerFireDate <= now) { _didAddTimer = NO; - + // Cancel existing window.setTimeout if (_nativeTimersForModes[aMode] !== nil) { window.clearNativeTimeout(_nativeTimersForModes[aMode]); - + _nativeTimersForModes[aMode] = nil; } - + // Empty timers to avoid catastrophe if a timer is added during a timer fire. var timers = _timersForModes[aMode], index = timers.length; - + _timersForModes[aMode] = nil; - - // Loop through timers looking for ones that had fired + + // Loop through timers looking for ones that had fired while (index--) { var timer = timers[index]; - + if (timer._lastNativeRunLoopsForModes[aMode] < CPRunLoopLastNativeRunLoop && timer._isValid && timer._fireDate <= now) [timer fire]; - + // Timer may or may not still be valid if (timer._isValid) nextFireDate = (nextFireDate === nil) ? timer._fireDate : [nextFireDate earlierDate:timer._fireDate]; - + else { // FIXME: Is there an issue with reseting the fire date in -fire? or adding it back to the run loop?... timer._lastNativeRunLoopsForModes[aMode] = 0; - + timers.splice(index, 1); } } - + // Timers may have been added during the firing of timers - // They do NOT get a shot at firing, because they certainly + // They do NOT get a shot at firing, because they certainly // haven't gone through one native timer. var newTimers = _timersForModes[aMode]; - + if (newTimers && newTimers.length) { index = newTimers.length; - + while (index--) { var timer = newTimers[index]; - + if ([timer isValid]) nextFireDate = (nextFireDate === nil) ? timer._fireDate : [nextFireDate earlierDate:timer._fireDate]; else newTimers.splice(index, 1); } - + _timersForModes[aMode] = newTimers.concat(timers); } else _timersForModes[aMode] = timers; - + _nextTimerFireDatesForModes[aMode] = nextFireDate; - + //initiate a new window.setTimeout if there are any timers if (_nextTimerFireDatesForModes[aMode] !== nil) _nativeTimersForModes[aMode] = window.setNativeTimeout(function() { _effectiveDate = nextFireDate; _nativeTimersForModes[aMode] = nil; ++CPRunLoopLastNativeRunLoop; [self limitDateForMode:aMode]; _effectiveDate = nil; }, MAX(0, [nextFireDate timeIntervalSinceNow] * 1000)); } - + // Run loop performers var performs = _orderedPerforms, index = performs.length; - + _orderedPerforms = []; - + while (index--) { var perform = performs[index]; - + if ([perform fireInMode:CPDefaultRunLoopMode]) { [_CPRunLoopPerform _poolPerform:perform]; - + performs.splice(index, 1); } } - + if (_orderedPerforms.length) { _orderedPerforms = _orderedPerforms.concat(performs); @@ -402,9 +402,9 @@ var CPRunLoopLastNativeRunLoop = 0; } else _orderedPerforms = performs; - + _runLoopLock = NO; - + return nextFireDate; } diff --git a/Foundation/CPSet.j b/Foundation/CPSet.j index ad596c0fd..0a1e5f821 100644 --- a/Foundation/CPSet.j +++ b/Foundation/CPSet.j @@ -24,10 +24,10 @@ * TODO: Needs to implement CPCoding, CPCopying. */ -@import "CPObject.j" @import "CPArray.j" -@import "CPNumber.j" @import "CPEnumerator.j" +@import "CPNumber.j" +@import "CPObject.j" /*! @class CPSet @@ -87,7 +87,7 @@ argLength = arguments.length, i = 2; - for(; i < argLength && ((argument = arguments[i]) !== nil); ++i) + for (; i < argLength && ((argument = arguments[i]) !== nil); ++i) [set addObject:argument]; return set; @@ -155,7 +155,7 @@ var argLength = arguments.length, i = 2; - for(; i < argLength && (argument = arguments[i]) != nil; ++i) + for (; i < argLength && (argument = arguments[i]) != nil; ++i) [self addObject:argument]; } @@ -180,9 +180,10 @@ if (!aSet) return self; - var contents = aSet._contents; + var contents = aSet._contents, + property; - for (var property in contents) + for (property in contents) { if (contents.hasOwnProperty(property)) { @@ -201,9 +202,10 @@ */ - (CPArray)allObjects { - var array = []; + var array = [], + property; - for (var property in _contents) + for (property in _contents) { if (_contents.hasOwnProperty(property)) array.push(_contents[property]); @@ -217,7 +219,9 @@ */ - (id)anyObject { - for (var property in _contents) + var property; + + for (property in _contents) { if (_contents.hasOwnProperty(property)) return _contents[property]; @@ -288,8 +292,11 @@ */ - (BOOL)isSubsetOfSet:(CPSet)set { - var items = [self allObjects]; - for (var i = 0; i < items.length; i++) + var items = [self allObjects], + i = 0, + count = items.length; + + for (; i < count; i++) { // If at least one item is not in both sets, self isn't a subset if (![set containsObject:items[i]]) @@ -315,8 +322,11 @@ */ - (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)argument { - var items = [self allObjects]; - for (var i = 0; i < items.length; i++) + var items = [self allObjects], + i = 0, + count = items.length; + + for (; i < count; i++) { [items[i] performSelector:aSelector withObject:argument]; } @@ -432,8 +442,11 @@ */ - (void)intersectSet:(CPSet)set { - var items = [self allObjects]; - for (var i = 0, count = items.length; i < count; i++) + var items = [self allObjects], + i = 0, + count = items.length; + + for (; i < count; i++) { if (![set containsObject:items[i]]) [self removeObject:items[i]]; @@ -446,8 +459,11 @@ */ - (void)minusSet:(CPSet)set { - var items = [set allObjects]; - for (var i = 0; i < items.length; i++) + var items = [set allObjects], + i = 0, + count = items.length; + + for (; i < count; i++) { if ([self containsObject:items[i]]) [self removeObject:items[i]]; @@ -460,8 +476,11 @@ */ - (void)unionSet:(CPSet)set { - var items = [set allObjects]; - for (var i = 0, count = items.length; i < count; i++) + var items = [set allObjects], + i = 0, + count = items.length; + + for (; i < count; i++) { [self addObject:items[i]]; } @@ -514,5 +533,5 @@ var CPSetObjectsKey = @"CPSetObjectsKey"; */ @implementation CPMutableSet : CPSet -@end +@end diff --git a/Foundation/CPSortDescriptor.j b/Foundation/CPSortDescriptor.j index c7d29f16a..8c246bd4c 100755 --- a/Foundation/CPSortDescriptor.j +++ b/Foundation/CPSortDescriptor.j @@ -43,7 +43,7 @@ CPOrderedSame = 0; */ CPOrderedDescending = 1; -/*! +/*! @class CPSortDescriptor @ingroup foundation @brief Holds attributes necessary to describe how to sort a set of objects. @@ -85,20 +85,20 @@ CPOrderedDescending = 1; Initializes the sort descriptor @param aKey the property key path to sort @param isAscending the sort order - @param aSelector this method gets called to compare objects. The method will take one argument + @param aSelector this method gets called to compare objects. The method will take one argument (the object to compare against itself, and must return a CPComparisonResult. */ - (id)initWithKey:(CPString)aKey ascending:(BOOL)isAscending selector:(SEL)aSelector { self = [super init]; - + if (self) { _key = aKey; _ascending = isAscending; _selector = aSelector; } - + return self; } @@ -150,9 +150,9 @@ CPOrderedDescending = 1; @end -var CPSortDescriptorKeyKey = @"CPSortDescriptorKeyKey", // Don't you just love naming schemes ;) - CPSortDescriptorAscendingKey = @"CPSortDescriptorAscendingKey", - CPSortDescriptorSelectorKey = @"CPSortDescriptorSelectorKey"; +var CPSortDescriptorKeyKey = @"CPSortDescriptorKeyKey", // Don't you just love naming schemes ;) + CPSortDescriptorAscendingKey = @"CPSortDescriptorAscendingKey", + CPSortDescriptorSelectorKey = @"CPSortDescriptorSelectorKey"; @implementation CPSortDescriptor (CPCoding) @@ -164,7 +164,7 @@ var CPSortDescriptorKeyKey = @"CPSortDescriptorKeyKey", // Don't you just love n _ascending = [aCoder decodeBoolForKey:CPSortDescriptorAscendingKey]; _selector = CPSelectorFromString([aCoder decodeObjectForKey:CPSortDescriptorSelectorKey]); } - + return self; } @@ -176,4 +176,3 @@ var CPSortDescriptorKeyKey = @"CPSortDescriptorKeyKey", // Don't you just love n } @end - diff --git a/Foundation/CPString.j b/Foundation/CPString.j index 51154a43c..abbe70c2d 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -20,8 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPObject.j" @import "CPException.j" +@import "CPObject.j" @import "CPSortDescriptor.j" @import "CPValue.j" @@ -65,7 +65,7 @@ var CPStringRegexSpecialCharacters = [ CPStringRegexEscapeExpression = new RegExp("(\\" + CPStringRegexSpecialCharacters.join("|\\") + ")", 'g'), CPStringRegexTrimWhitespace = new RegExp("(^\\s+|\\s+$)", 'g'); -/*! +/*! @class CPString @ingroup foundation @brief An immutable string (collection of characters). @@ -103,7 +103,7 @@ var CPStringRegexSpecialCharacters = [ + (id)stringWithHash:(unsigned)aHash { var hashString = parseInt(aHash, 10).toString(16); - return "000000".substring(0, MAX(6-hashString.length, 0)) + hashString; + return "000000".substring(0, MAX(6 - hashString.length, 0)) + hashString; } /*! @@ -147,7 +147,7 @@ var CPStringRegexSpecialCharacters = [ } /*! - Creates a new string using C printf-style formatting. First argument should be a constant format string, + Creates a new string using C printf-style formatting. First argument should be a constant format string, like ' "float val = %f" ', remaining arguments should be the variables to print the values of, comma-separated. @param format the format to be used, printf-style @return the initialized CPString @@ -238,8 +238,8 @@ var CPStringRegexSpecialCharacters = [ while ((difference -= substring.length) >= 0) string += substring; - - if (-difference < substring.length) + + if (-difference < substring.length) string += substring.substring(0, -difference); return string; @@ -329,7 +329,7 @@ var CPStringRegexSpecialCharacters = [ /*! Finds the range of characters in the receiver - where the specified string exists in the given range + where the specified string exists in the given range of the receiver.The search is subject to the options specified in the specified mask which can be a combination of:
@@ -374,7 +374,7 @@ var CPStringRegexSpecialCharacters = [
 }
 
 /*!
-    Returns a new string in which all occurrences of a target string in the reciever are replaced by 
+    Returns a new string in which all occurrences of a target string in the reciever are replaced by
     another given string.
     @param target The string to replace.
     @param replacement the string with which to replace the \c target
@@ -403,7 +403,7 @@ var CPStringRegexSpecialCharacters = [
         regExp;
 
     if (options & CPCaseInsensitiveSearch)
-        regExp = new RegExp(target, "gi"); 
+        regExp = new RegExp(target, "gi");
     else
         regExp = new RegExp(target, "g");
 
@@ -411,7 +411,7 @@ var CPStringRegexSpecialCharacters = [
 }
 
 /*
-   Returns a new string in which the characters in a specified range of the receiver 
+   Returns a new string in which the characters in a specified range of the receiver
    are replaced by a given string.
    @param range A range of characters in the receiver.
    @param replacement The string with which to replace the characters in \c range.
@@ -442,7 +442,6 @@ var CPStringRegexSpecialCharacters = [
     return [self compare:aString options:nil];
 }
 
-
 /*
     Compares the receiver to the specified string.
     @param aString the string with which to compare
@@ -463,18 +462,18 @@ var CPStringRegexSpecialCharacters = [
 {
     var lhs = self,
         rhs = aString;
-    
+
     if (aMask & CPCaseInsensitiveSearch)
     {
         lhs = lhs.toLowerCase();
         rhs = rhs.toLowerCase();
     }
-    
+
     if (lhs < rhs)
         return CPOrderedAscending;
     else if (lhs > rhs)
         return CPOrderedDescending;
-    
+
     return CPOrderedSame;
 }
 
@@ -559,7 +558,7 @@ var CPStringRegexSpecialCharacters = [
         lhs = self,
         rhs = aString,
         min = MIN([lhs length], [rhs length]);
-    
+
     if (aMask & CPCaseInsensitiveSearch)
     {
         lhs = [lhs lowercaseString];
@@ -580,10 +579,13 @@ var CPStringRegexSpecialCharacters = [
 */
 - (CPString)capitalizedString
 {
-    var parts = self.split(/\b/g); // split on word boundaries
-    for (var i = 0; i < parts.length; i++)
+    var parts = self.split(/\b/g), // split on word boundaries
+        i = 0,
+        count = parts.length;
+
+    for (; i < count; i++)
     {
-        if (i == 0 || (/\s$/).test(parts[i-1])) // only capitalize if previous token was whitespace
+        if (i == 0 || (/\s$/).test(parts[i - 1])) // only capitalize if previous token was whitespace
             parts[i] = parts[i].substring(0, 1).toUpperCase() + parts[i].substring(1).toLowerCase();
         else
             parts[i] = parts[i].toLowerCase();
@@ -615,8 +617,8 @@ var CPStringRegexSpecialCharacters = [
     return parseFloat(self, 10);
 }
 /*!
-    Returns \c YES on encountering one of "Y", "y", "T", "t", or 
-    a digit 1-9. Returns \c NO otherwise. This method skips the initial 
+    Returns \c YES on encountering one of "Y", "y", "T", "t", or
+    a digit 1-9. Returns \c NO otherwise. This method skips the initial
     whitespace characters, +,- followed by Zeroes.
 */
 
@@ -678,7 +680,7 @@ var CPStringRegexSpecialCharacters = [
 - (CPString)lastPathComponent
 {
     var components = [self pathComponents];
-    return components[components.length -1];
+    return components[components.length - 1];
 }
 
 /*!
@@ -690,12 +692,12 @@ var CPStringRegexSpecialCharacters = [
 {
     var path = self,
         start = length - 1;
-    
+
     while (path.charAt(start) === '/')
         start--;
-    
+
     path = path.substr(0, path.lastIndexOf('/', start));
-    
+
     if (path === "" && charAt(0) === '/')
         return '/';
 
@@ -758,11 +760,12 @@ var CPStringRegexSpecialCharacters = [
 */
 + (CPString)UUID
 {
-    var g = @"";
-    
-    for(var i = 0; i < 32; i++)
+    var g = @"",
+        i = 0;
+
+    for (; i < 32; i++)
         g += FLOOR(RAND() * 0xF).toString(0xF);
-    
+
     return g;
 }
 
diff --git a/Foundation/CPTimer.j b/Foundation/CPTimer.j
index e1ec83ce5..5c25f1c59 100644
--- a/Foundation/CPTimer.j
+++ b/Foundation/CPTimer.j
@@ -20,13 +20,14 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-@import "CPObject.j"
-@import "CPInvocation.j"
 @import "CPDate.j"
+@import "CPInvocation.j"
+@import "CPObject.j"
 @import "CPRunLoop.j"
 
+
 /*!
-    @class CPTimer 
+    @class CPTimer
     @ingroup foundation
 
     @brief A timer object that can send a message after the given time interval.
@@ -36,7 +37,7 @@
     CPTimeInterval      _timeInterval;
     CPInvocation        _invocation;
     Function            _callback;
-    
+
     BOOL                _repeats;
     BOOL                _isValid;
     CPDate              _fireDate;
@@ -46,13 +47,13 @@
 /*!
     Returns a new NSTimer object and adds it to the current NSRunLoop object in the default mode.
 */
-+ (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat 
++ (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
 {
     var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:anInvocation repeats:shouldRepeat];
 
     //add to the runloop
     [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
-    
+
     return timer;
 }
 
@@ -61,31 +62,31 @@
 */
 + (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
 {
-    var timer =  [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat]
+    var timer =  [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat];
 
     //add to the runloop
     [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
-        
+
     return timer;
 }
 
 /*!
     Returns a new NSTimer object and adds it to the current NSRunLoop object in the default mode.
 */
-+ (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat 
++ (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
 {
     var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds callback:aFunction repeats:shouldRepeat];
 
     //add to the runloop
     [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
-    
+
     return timer;
 }
 
 /*!
     Returns a new NSTimer that, when added to a run loop, will fire after seconds.
 */
-+ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat 
++ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
 {
     return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:anInvocation repeats:shouldRepeat];
 }
@@ -101,7 +102,7 @@
 /*!
     Returns a new NSTimer that, when added to a run loop, will fire after seconds.
 */
-+ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat 
++ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
 {
     return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds callback:aFunction repeats:shouldRepeat];
 }
@@ -112,8 +113,8 @@
 - (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
 {
     self = [super init];
-    
-    if (self) 
+
+    if (self)
     {
         _timeInterval = seconds;
         _invocation = anInvocation;
@@ -121,7 +122,7 @@
         _isValid = YES;
         _fireDate = aDate;
     }
-    
+
     return self;
 }
 
@@ -131,16 +132,16 @@
 - (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
 {
     var invocation = [CPInvocation invocationWithMethodSignature:1];
-    
+
     [invocation setTarget:aTarget];
     [invocation setSelector:aSelector];
     [invocation setArgument:self atIndex:2];
-    
+
     self = [self initWithFireDate:aDate interval:seconds invocation:invocation repeats:shouldRepeat];
 
     if (self)
         _userInfo = userInfo;
-        
+
     return self;
 }
 
@@ -150,8 +151,8 @@
 - (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
 {
     self = [super init];
-    
-    if (self) 
+
+    if (self)
     {
         _timeInterval = seconds;
         _callback = aFunction;
@@ -159,14 +160,14 @@
         _isValid = YES;
         _fireDate = aDate;
     }
-    
+
     return self;
 }
 
 /*!
     Returns the receiver’s time interval.
 */
-- (CPTimeInterval)timeInterval 
+- (CPTimeInterval)timeInterval
 {
    return _timeInterval;
 }
@@ -174,15 +175,15 @@
 /*!
     Returns the date at which the receiver will fire.
 */
-- (CPDate)fireDate 
+- (CPDate)fireDate
 {
-   return _fireDate;  
+   return _fireDate;
 }
 
 /*!
     Resets the receiver to fire next at a given date.
 */
-- (void)setFireDate:(CPDate)aDate 
+- (void)setFireDate:(CPDate)aDate
 {
     _fireDate = aDate;
 }
@@ -205,7 +206,7 @@
 
     if (_repeats)
         _fireDate = [CPDate dateWithTimeIntervalSinceNow:_timeInterval];
-    
+
     else
         [self invalidate];
 }
@@ -213,7 +214,7 @@
 /*!
     Returns a Boolean value that indicates whether the receiver is currently valid.
 */
-- (BOOL)isValid 
+- (BOOL)isValid
 {
    return _isValid;
 }
@@ -221,7 +222,7 @@
 /*!
     Stops the receiver from ever firing again and requests its removal from its NSRunLoop object.
 */
-- (void)invalidate 
+- (void)invalidate
 {
    _isValid = NO;
    _userInfo = nil;
@@ -246,14 +247,14 @@ var _CPTimerBridgeTimer = function(codeOrFunction, aDelay, shouldRepeat, functio
 {
     var timeoutID = CPTimersTimeoutID++,
         theFunction = nil;
-        
+
     if (typeof codeOrFunction === "string")
         theFunction = function() { new Function(codeOrFunction)(); if (!shouldRepeat) CPTimersForTimeoutIDs[timeoutID] = nil; }
     else
     {
         if (!functionArgs)
             functionArgs = [];
-        
+
         theFunction = function() { codeOrFunction.apply(window, functionArgs); if (!shouldRepeat) CPTimersForTimeoutIDs[timeoutID] = nil; }
     }
 
@@ -270,10 +271,10 @@ window.setTimeout = function(codeOrFunction, aDelay)
 window.clearTimeout = function(aTimeoutID)
 {
     var timer = CPTimersForTimeoutIDs[aTimeoutID];
-    
+
     if (timer)
         [timer invalidate];
-        
+
     CPTimersForTimeoutIDs[aTimeoutID] = nil;
 }
 
diff --git a/Foundation/CPURL.j b/Foundation/CPURL.j
index 25dbb7d5a..1486baad3 100644
--- a/Foundation/CPURL.j
+++ b/Foundation/CPURL.j
@@ -1,5 +1,26 @@
+/*
+ * CPURL.j
+ * Foundation
+ *
+ * Created by Francisco Tolmasky.
+ * Copyright 2008, 280 North, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
 
-@import 
+@import "CPObject.j"
 
 CPURLNameKey                        = @"CPURLNameKey";
 CPURLLocalizedNameKey               = @"CPURLLocalizedNameKey";
@@ -44,7 +65,7 @@ CPURLCustomIconKey                  = @"CPURLCustomIconKey";
 - (id)initWithScheme:(CPString)aScheme host:(CPString)aHost path:(CPString)aPath
 {
     var URLString = (aScheme ? aScheme + ":" : "") + (aHost ? aHost + "//" : "") + (aPath || "");
-    
+
     return [self initWithString:URLString];
 }
 
@@ -94,6 +115,12 @@ CPURLCustomIconKey                  = @"CPURLCustomIconKey";
     return [self absoluteURL].path();
 }
 
+- (CPArray)pathComponents
+{
+    var path = self.pathComponents();
+    return [path copy];
+}
+
 // if absolute, returns the same as path
 - (CPString)relativePath
 {
diff --git a/Foundation/CPURLConnection.j b/Foundation/CPURLConnection.j
index 368173e34..d6f260226 100644
--- a/Foundation/CPURLConnection.j
+++ b/Foundation/CPURLConnection.j
@@ -31,45 +31,45 @@ var CPURLConnectionDelegate = nil;
 /*!
     @class CPURLConnection
     @ingroup foundation
-    @brief Provides loading of a URL request. 
+    @brief Provides loading of a URL request.
 
     An interface to downloading content at a specified URL. Using one of the
     class methods, you can obtain the data.
-    
+
     @delegate -(void)connection:(CPURLConnection)connection didFailWithError:(id)error;
     Called when the connection encounters an error.
     @param connection the connection that had an error
     @param error the error, which is either a javascript DOMException or an http
     status code (javascript number/CPNumber)
-    
+
     @delegate -(void)connection:(CPURLConnection)connection didReceiveResponse:(CPHTTPURLResponse)response;
     Called when the connection receives a response.
     @param connection the connection that received a response
     @param response the received response
-    
+
     @delegate -(void)connection:(CPURLConnection)connection didReceiveData:(CPString)data;
     Called when the connection has received data.
     @param connection the connection that received data
     @param data the received data
-    
+
     @delegate -(void)connectionDidFinishLoading:(CPURLConnection)connection;
     Called when the URL has finished loading.
     @param connection the connection that finished loading
-    
+
     Class Delegate Method:
-    
+
     @delegate -(void)connectionDidReceiveAuthenticationChallenge:(id)connection
     The class delegate allows you to set global behavior for when authentication challenges (401 status codes) are returned.
-    
+
     The recommended way to handle this method is to store a reference to the connection, and then use whatever
-    method you have to authenticate yourself.  Once you've authenticated yourself, you should cancel 
+    method you have to authenticate yourself.  Once you've authenticated yourself, you should cancel
     and then start the connection:
-    
+
 
 [connection cancel];
 [connection start];
 
- + @param connection the connection that received the authentication challenge. */ @implementation CPURLConnection : CPObject @@ -116,7 +116,7 @@ var CPURLConnectionDelegate = nil; catch (anException) { } - + return nil; } @@ -141,13 +141,13 @@ var CPURLConnectionDelegate = nil; - (id)initWithRequest:(CPURLRequest)aRequest delegate:(id)aDelegate startImmediately:(BOOL)shouldStartImmediately { self = [super init]; - + if (self) { _request = aRequest; _delegate = aDelegate; _isCanceled = NO; - + var URL = [_request URL], scheme = [URL scheme]; @@ -187,7 +187,7 @@ var CPURLConnectionDelegate = nil; _isCanceled = NO; try - { + { _HTTPRequest.open([_request HTTPMethod], [[_request URL] absoluteString], YES); _HTTPRequest.onreadystatechange = function() { [self _readyStateDidChange]; } @@ -214,7 +214,7 @@ var CPURLConnectionDelegate = nil; - (void)cancel { _isCanceled = YES; - + try { _HTTPRequest.abort(); @@ -240,10 +240,10 @@ var CPURLConnectionDelegate = nil; if (statusCode === 401 && [CPURLConnectionDelegate respondsToSelector:@selector(connectionDidReceiveAuthenticationChallenge:)]) [CPURLConnectionDelegate connectionDidReceiveAuthenticationChallenge:self]; - else + else { if ([_delegate respondsToSelector:@selector(connection:didReceiveResponse:)]) - { + { if (_isLocalFileConnection) [_delegate connection:self didReceiveResponse:[[CPURLResponse alloc] initWithURL:URL]]; else @@ -290,4 +290,4 @@ var CPURLConnectionDelegate = nil; return [self _HTTPRequest]; } -@end \ No newline at end of file +@end diff --git a/Foundation/CPURLRequest.j b/Foundation/CPURLRequest.j index b18b9bd81..28b4e4dc4 100644 --- a/Foundation/CPURLRequest.j +++ b/Foundation/CPURLRequest.j @@ -23,7 +23,7 @@ @import "CPObject.j" -/*! +/*! @class CPURLRequest @ingroup foundation @brief Contains data obtained during a request made with CPURLConnection. @@ -34,7 +34,7 @@ @implementation CPURLRequest : CPObject { CPURL _URL; - + // FIXME: this should be CPData CPString _HTTPBody; CPString _HTTPMethod; @@ -59,7 +59,7 @@ - (id)initWithURL:(CPURL)aURL { self = [super init]; - + if (self) { [self setURL:aURL]; @@ -67,12 +67,12 @@ _HTTPBody = @""; _HTTPMethod = @"GET"; _HTTPHeaderFields = [CPDictionary dictionary]; - + [self setValue:"Thu, 01 Jan 1970 00:00:00 GMT" forHTTPHeaderField:"If-Modified-Since"]; [self setValue:"no-cache" forHTTPHeaderField:"Cache-Control"]; [self setValue:"XMLHttpRequest" forHTTPHeaderField:"X-Requested-With"]; } - + return self; } diff --git a/Foundation/CPURLResponse.j b/Foundation/CPURLResponse.j index ed524d940..6d0c0bf5e 100644 --- a/Foundation/CPURLResponse.j +++ b/Foundation/CPURLResponse.j @@ -44,10 +44,10 @@ - (id)initWithURL:(CPURL)aURL { self = [super init]; - + if (self) _URL = aURL; - + return self; } @@ -57,13 +57,13 @@ } /* Creating a Response -initWithURL:MIMEType:expectedContentLength:textEncodingName: +initWithURL:MIMEType:expectedContentLength:textEncodingName: Getting the Response Properties -expectedContentLength -suggestedFilename -MIMEType -textEncodingName -URL +expectedContentLength +suggestedFilename +MIMEType +textEncodingName +URL */ @end diff --git a/Foundation/CPUndoManager.j b/Foundation/CPUndoManager.j index 94b9f6516..f07247589 100644 --- a/Foundation/CPUndoManager.j +++ b/Foundation/CPUndoManager.j @@ -20,15 +20,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPObject.j" @import "CPInvocation.j" +@import "CPObject.j" @import "CPProxy.j" var CPUndoManagerNormal = 0, CPUndoManagerUndoing = 1, CPUndoManagerRedoing = 2; - + CPUndoManagerCheckpointNotification = @"CPUndoManagerCheckpointNotification"; CPUndoManagerDidOpenUndoGroupNotification = @"CPUndoManagerDidOpenUndoGroupNotification"; CPUndoManagerDidRedoChangeNotification = @"CPUndoManagerDidRedoChangeNotification"; @@ -53,7 +53,7 @@ var _CPUndoGroupingPool = [], { if (!anUndoGrouping || _CPUndoGroupingPool.length >= _CPUndoGroupingPoolCapacity) return; - + _CPUndoGroupingPool.push(anUndoGrouping); } @@ -62,28 +62,28 @@ var _CPUndoGroupingPool = [], if (_CPUndoGroupingPool.length) { var grouping = _CPUndoGroupingPool.pop(); - + grouping._parent = anUndoGrouping; - + if (grouping._invocations.length) grouping._invocations = []; - + return grouping; } - + return [[self alloc] initWithParent:anUndoGrouping]; } - (id)initWithParent:(_CPUndoGrouping)anUndoGrouping { self = [super init]; - + if (self) { _parent = anUndoGrouping; _invocations = []; } - + return self; } @@ -134,13 +134,13 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey", - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) { _parent = [aCoder decodeObjectForKey:_CPUndoGroupingParentKey]; _invocations = [aCoder decodeObjectForKey:_CPUndoGroupingInvocationsKey]; } - + return self; } @@ -152,7 +152,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey", @end -/*! +/*! @class CPUndoManager @ingroup foundation @brief A general mechanism for user action "undo". @@ -193,21 +193,21 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey", - (id)init { self = [super init]; - + if (self) { _redoStack = []; _undoStack = []; - + _state = CPUndoManagerNormal; - + [self setRunLoopModes:[CPDefaultRunLoopMode]]; [self setGroupsByEvent:YES]; _undoManagerProxy = [_CPUndoManagerProxy alloc]; _undoManagerProxy._undoManager = self; } - + return self; } @@ -258,7 +258,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey", - (id)prepareWithInvocationTarget:(id)aTarget { _preparedTarget = aTarget; - + return _undoManagerProxy; } @@ -270,7 +270,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey", { if ([_preparedTarget respondsToSelector:aSelector]) return 1; - + return nil;//[_preparedTarget methodSignatureForSelector:selector]; } @@ -337,7 +337,7 @@ if (_currentGroup == nil) Performs an undo on the last undo group. */ - (void)undoNestedGroup -{ +{ if ([_undoStack count] <= 0) return; @@ -373,7 +373,7 @@ if (_currentGroup == nil) // Don't do anything if we have no redos. if ([_redoStack count] <= 0) return; - + /* if (_state == NSUndoManagerUndoing) [NSException raise:NSInternalInconsistencyException format:@"redo called while undoing"]; @@ -386,19 +386,19 @@ if (_currentGroup == nil) [defaultCenter postNotificationName:CPUndoManagerWillRedoChangeNotification object:self]; - + var oldUndoGrouping = _currentGrouping, undoGrouping = _redoStack.pop(); - + _currentGrouping = nil; _state = CPUndoManagerRedoing; [self _beginUndoGrouping]; [undoGrouping invoke]; [self endUndoGrouping]; - + [_CPUndoGrouping _poolUndoGrouping:undoGrouping]; - + _currentGrouping = oldUndoGrouping; _state = CPUndoManagerNormal; @@ -452,31 +452,31 @@ if (_currentGroup == nil) object:self]; var parent = [_currentGrouping parent]; - + if (!parent && [_currentGrouping invocations].length > 0) { [defaultCenter postNotificationName:CPUndoManagerWillCloseUndoGroupNotification object:self]; - + // Put this group on the redo stack if we are currently undoing, otherwise // put it on the undo stack. That way, "undos" become "redos". var stack = _state === CPUndoManagerUndoing ? _redoStack : _undoStack; - + stack.push(_currentGrouping); - + if (_levelsOfUndo > 0 && stack.length > _levelsOfUndo) - stack.splice(0, 1); + stack.splice(0, 1); } - + // Nested Undo Grouping else { [parent addInvocationsFromArray:[_currentGrouping invocations]]; - + [_CPUndoGrouping _poolUndoGrouping:_currentGrouping]; } - + _currentGrouping = parent; } @@ -491,7 +491,7 @@ if (_currentGroup == nil) if (_disableCount <= 0) [CPException raise:CPInternalInconsistencyException reason:"enableUndoRegistration. There are no disable messages in effect right now."]; - + _disableCount--; } @@ -527,10 +527,10 @@ if (_currentGroup == nil) { var grouping = _currentGrouping, level = _currentGrouping != nil; - + while (grouping = [grouping parent]) ++level; - + return level; } @@ -586,27 +586,27 @@ if (_currentGroup == nil) - (void)removeAllActionsWithTarget:(id)aTarget { [_currentGrouping removeInvocationsWithTarget:aTarget]; - + var index = _redoStack.length; - + while (index--) { var grouping = _redoStack[index]; - + [grouping removeInvocationsWithTarget:aTarget]; - + if (![grouping invocations].length) _redoStack.splice(index, 1); } index = _undoStack.length; - + while (index--) { var grouping = _undoStack[index]; - + [grouping removeInvocationsWithTarget:aTarget]; - + if (![grouping invocations].length) _undoStack.splice(index, 1); } @@ -739,7 +739,7 @@ var CPUndoManagerRedoStackKey = @"CPUndoManagerRedoStackKey", CPUndoManagerLevelsOfUndoKey = @"CPUndoManagerLevelsOfUndoKey"; CPUndoManagerActionNameKey = @"CPUndoManagerActionNameKey"; CPUndoManagerCurrentGroupingKey = @"CPUndoManagerCurrentGroupingKey"; - + CPUndoManagerRunLoopModesKey = @"CPUndoManagerRunLoopModesKey"; CPUndoManagerGroupsByEventKey = @"CPUndoManagerGroupsByEventKey"; @@ -748,22 +748,22 @@ var CPUndoManagerRedoStackKey = @"CPUndoManagerRedoStackKey", - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) { _redoStack = [aCoder decodeObjectForKey:CPUndoManagerRedoStackKey]; _undoStack = [aCoder decodeObjectForKey:CPUndoManagerUndoStackKey]; - + _levelsOfUndo = [aCoder decodeObjectForKey:CPUndoManagerLevelsOfUndoKey]; _actionName = [aCoder decodeObjectForKey:CPUndoManagerActionNameKey]; _currentGrouping = [aCoder decodeObjectForKey:CPUndoManagerCurrentGroupingKey]; - + _state = CPUndoManagerNormal; - + [self setRunLoopModes:[aCoder decodeObjectForKey:CPUndoManagerRunLoopModesKey]]; [self setGroupsByEvent:[aCoder decodeBoolForKey:CPUndoManagerGroupsByEventKey]]; } - + return self; } @@ -771,10 +771,10 @@ var CPUndoManagerRedoStackKey = @"CPUndoManagerRedoStackKey", { [aCoder encodeObject:_redoStack forKey:CPUndoManagerRedoStackKey]; [aCoder encodeObject:_undoStack forKey:CPUndoManagerUndoStackKey]; - + [aCoder encodeInt:_levelsOfUndo forKey:CPUndoManagerLevelsOfUndoKey]; [aCoder encodeObject:_actionName forKey:CPUndoManagerActionNameKey]; - + [aCoder encodeObject:_currentGrouping forKey:CPUndoManagerCurrentGroupingKey]; [aCoder encodeObject:_runLoopModes forKey:CPUndoManagerRunLoopModesKey]; diff --git a/Foundation/CPUserSessionManager.j b/Foundation/CPUserSessionManager.j index b15d1e916..5feca31ff 100644 --- a/Foundation/CPUserSessionManager.j +++ b/Foundation/CPUserSessionManager.j @@ -20,8 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import -@import +@import "CPObject.j" +@import "CPString.j" CPUserSessionUndeterminedStatus = 0; @@ -36,7 +36,7 @@ var CPDefaultUserSessionManager = nil; @implementation CPUserSessionManager : CPObject { CPUserSessionStatus _status; - + CPString _userIdentifier; } @@ -51,10 +51,10 @@ var CPDefaultUserSessionManager = nil; - (id)init { self = [super init]; - + if (self) _status = CPUserSessionUndeterminedStatus; - + return self; } @@ -67,9 +67,9 @@ var CPDefaultUserSessionManager = nil; { if (_status == aStatus) return; - + _status = aStatus; - + [[CPNotificationCenter defaultCenter] postNotificationName:CPUserSessionManagerStatusDidChangeNotification object:self]; @@ -87,9 +87,9 @@ var CPDefaultUserSessionManager = nil; { if (_userIdentifier == anIdentifier) return; - + _userIdentifier = anIdentifier; - + [[CPNotificationCenter defaultCenter] postNotificationName:CPUserSessionManagerUserIdentifierDidChangeNotification object:self]; diff --git a/Foundation/CPValue.j b/Foundation/CPValue.j index 1c6de7a92..70ea751ad 100644 --- a/Foundation/CPValue.j +++ b/Foundation/CPValue.j @@ -20,11 +20,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -@import "CPObject.j" @import "CPCoder.j" +@import "CPObject.j" -/*! +/*! @class CPValue @ingroup foundation @brief A generic "value". Can be subclassed to hold specific data types. @@ -54,10 +54,10 @@ - (id)initWithJSObject:(JSObject)aJSObject { self = [super init]; - + if (self) _JSObject = aJSObject; - + return self; } @@ -83,7 +83,7 @@ var CPValueValueKey = @"CPValueValueKey"; - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) _JSObject = JSON.parse([aCoder decodeObjectForKey:CPValueValueKey]); diff --git a/Foundation/CPValueTransformer.j b/Foundation/CPValueTransformer.j new file mode 100644 index 000000000..6ea38a7cc --- /dev/null +++ b/Foundation/CPValueTransformer.j @@ -0,0 +1,190 @@ +/* + * CPKeyValueBinding.j + * Foundation + * + * Created by Ross Boucher 2/15/09 + * Copyright 280 North, Inc. + * + * Adapted from GNUStep + * Released under the LGPL. + * + * 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 "CPObject.j" +@import "CPDictionary.j" + + +var transformerMap = [CPDictionary dictionary]; + + +@implementation CPValueTransformer : CPObject +{ + +} + ++ (void)initialize +{ + if (self !== [CPValueTransformer class]) + return; + + [CPValueTransformer setValueTransformer:[[CPNegateBooleanTransformer alloc] init] forName:CPNegateBooleanTransformerName]; + [CPValueTransformer setValueTransformer:[[CPIsNilTransformer alloc] init] forName:CPIsNilTransformerName]; + [CPValueTransformer setValueTransformer:[[CPIsNotNilTransformer alloc] init] forName:CPIsNotNilTransformerName]; + [CPValueTransformer setValueTransformer:[[CPUnarchiveFromDataTransformer alloc] init] forName:CPUnarchiveFromDataTransformerName]; +} + ++ (void)setValueTransformer:(CPValueTransformer)transformer forName:(CPString)aName +{ + [transformerMap setObject:transformer forKey:aName]; +} + ++ (CPValueTransformer)valueTransformerForName:(CPString)aName +{ + return [transformerMap objectForKey:aName]; +} + ++ (CPArray)valueTransformerNames +{ + return [transformerMap allKeys]; +} + ++ (BOOL)allowsReverseTransformation +{ + return NO; +} + ++ (Class)transformedValueClass +{ + return [CPObject class]; +} + +- (id)reverseTransformedValue:(id)aValue +{ + if ([[self class] allowsReverseTransformation]) + { + [CPException raise:CPInvalidArgumentException reason:(self+" is not reversible.")]; + } + + return [self transformedValue:aValue]; +} + +- (id)transformedValue:(id)aValue +{ + return nil; +} + +@end + +// builtin transformers + +@implementation CPNegateBooleanTransformer : CPValueTransformer +{ +} + ++ (BOOL)allowsReverseTransformation +{ + return YES; +} + ++ (Class)transformedValueClass +{ + return [CPNumber class]; +} + +- (id)reverseTransformedValue:(id)aValue +{ + return ![aValue boolValue]; +} + +- (id)transformedValue:(id)aValue +{ + return ![aValue boolValue]; +} + +@end + +@implementation CPIsNilTransformer : CPValueTransformer +{ +} + ++ (BOOL)allowsReverseTransformation +{ + return NO; +} + ++ (Class)transformedValueClass +{ + return [CPNumber class]; +} + +- (id)transformedValue:(id)aValue +{ + return aValue === nil || aValue === undefined; +} + +@end + +@implementation CPIsNotNilTransformer : CPValueTransformer +{ +} + ++ (BOOL)allowsReverseTransformation +{ + return NO; +} + ++ (Class)transformedValueClass +{ + return [CPNumber class]; +} + +- (id)transformedValue:(id)aValue +{ + return aValue !== nil && aValue !== undefined; +} + +@end + +@implementation CPUnarchiveFromDataTransformer : CPValueTransformer +{ +} + ++ (BOOL)allowsReverseTransformation +{ + return YES; +} + ++ (Class)transformedValueClass +{ + return [CPData class]; +} + +- (id)reverseTransformedValue:(id)aValue +{ + return [CPKeyedArchiver archivedDataWithRootObject:aValue]; +} + +- (id)transformedValue:(id)aValue +{ + return [CPKeyedUnarchiver unarchiveObjectWithData:aValue]; +} + +@end + +CPNegateBooleanTransformerName = @"CPNegateBooleanTransformerName"; +CPIsNilTransformerName = @"CPIsNilTransformerName"; +CPIsNotNilTransformerName = @"CPIsNotNilTransformerName"; +CPUnarchiveFromDataTransformerName = @"CPUnarchiveFromDataTransformerName"; diff --git a/Foundation/CPWebDAVManager.j b/Foundation/CPWebDAVManager.j index fb17b72a2..6b821fb08 100644 --- a/Foundation/CPWebDAVManager.j +++ b/Foundation/CPWebDAVManager.j @@ -1,3 +1,24 @@ +/* + * CPWebDAVManager.j + * Foundation + * + * Created by Francisco Tolmasky. + * Copyright 2008, 280 North, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ var setURLResourceValuesForKeysFromProperties = function(aURL, keys, properties) { diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j index 2d4fb3ebb..a49654dd4 100755 --- a/Foundation/Foundation.j +++ b/Foundation/Foundation.j @@ -35,7 +35,6 @@ @import "CPKeyedUnarchiver.j" @import "CPKeyValueCoding.j" @import "CPKeyValueObserving.j" -@import "CPLog.j" @import "CPNotification.j" @import "CPNotificationCenter.j" @import "CPNull.j" @@ -58,6 +57,7 @@ @import "CPURLResponse.j" @import "CPUserSessionManager.j" @import "CPValue.j" +@import "CPValueTransformer.j" /*! @mainpage Cappuccino is distributed under the @ref license "GNU LGPL". diff --git a/Objective-J/CFBundle.js b/Objective-J/CFBundle.js index 7f75d3d1d..8c7044e73 100644 --- a/Objective-J/CFBundle.js +++ b/Objective-J/CFBundle.js @@ -635,9 +635,9 @@ function decompileStaticFile(/*Bundle*/ aBundle, /*String*/ aString, /*String*/ if (CFBundleSupportedSpriteType === CFBundleMHTMLUncachedSpriteType) { - var exclamationIndex = URLString.indexOf("!"), - firstPart = URLString.substring(0, exclamationIndex), - lastPart = URLString.substring(exclamationIndex); + var exclamationIndex = mappedURLString.indexOf("!"), + firstPart = mappedURLString.substring(0, exclamationIndex), + lastPart = mappedURLString.substring(exclamationIndex); mappedURLString = firstPart + "?" + CFCacheBuster + lastPart; } diff --git a/Objective-J/CFData.js b/Objective-J/CFData.js index 51743a5a9..7898756f7 100644 --- a/Objective-J/CFData.js +++ b/Objective-J/CFData.js @@ -227,6 +227,11 @@ CFData.decodeBase64ToString = function(input, strip) return CFData.bytesToString(CFData.decodeBase64ToArray(input, strip)); } +CFData.decodeBase64ToUtf16String = function(input, strip) +{ + return CFData.bytesToUtf16String(CFData.decodeBase64ToArray(input, strip)); +} + CFData.bytesToString = function(bytes) { // This is relatively efficient, I think: @@ -242,3 +247,28 @@ CFData.encodeBase64String = function(input) return CFData.encodeBase64Array(temp); } + +CFData.bytesToUtf16String = function(bytes) +{ + // Strings are encoded with 16 bits per character. + var temp = []; + for (var i = 0; i < bytes.length; i+=2) + temp.push(bytes[i+1] << 8 | bytes[i]); + // This is relatively efficient, I think: + return String.fromCharCode.apply(NULL, temp); +} + + +CFData.encodeBase64Utf16String = function(input) +{ + // charCodeAt returns UTF-16. + var temp = []; + for (var i = 0; i < input.length; i++) + { + var c = input.charCodeAt(i); + temp.push(input.charCodeAt(i) & 0xFF); + temp.push((input.charCodeAt(i) & 0xFF00) >> 8); + } + + return CFData.encodeBase64Array(temp); +} diff --git a/Objective-J/CFDictionary.js b/Objective-J/CFDictionary.js index a9c0ccb74..8c10b7fdf 100644 --- a/Objective-J/CFDictionary.js +++ b/Objective-J/CFDictionary.js @@ -75,7 +75,7 @@ CFDictionary.prototype.containsValue = function(/*id*/ anObject) count = keys.length; for (; index < count; ++index) - if (buckets[keys] === anObject) + if (buckets[keys[index]] === anObject) return YES; return NO; @@ -106,8 +106,8 @@ CFDictionary.prototype.countOfValue = function(/*id*/ anObject) countOfValue = 0; for (; index < count; ++index) - if (buckets[keys] === anObject) - return ++countOfValue; + if (buckets[keys[index]] === anObject) + ++countOfValue; return countOfValue; } diff --git a/Objective-J/CFPropertyList.js b/Objective-J/CFPropertyList.js index 39ba97e13..5faeb473b 100644 --- a/Objective-J/CFPropertyList.js +++ b/Objective-J/CFPropertyList.js @@ -306,6 +306,8 @@ var XML_XML = "xml", #define PARENT_NODE(anXMLNode) (anXMLNode.parentNode) #define DOCUMENT_ELEMENT(aDocument) (aDocument.documentElement) +#define HAS_ATTRIBUTE_VALUE(anXMLNode, anAttributeName, aValue) (anXMLNode.getAttribute(anAttributeName) === aValue) + #define IS_OF_TYPE(anXMLNode, aType) (NODE_NAME(anXMLNode) === aType) #define IS_PLIST(anXMLNode) IS_OF_TYPE(anXMLNode, PLIST_PLIST) @@ -559,13 +561,17 @@ CFPropertyList.propertyListFromXML = function(/*String | XMLNode*/ aStringOrXMLN case PLIST_DICTIONARY: object = new CFMutableDictionary(); containers.push(object); break; - + case PLIST_NUMBER_REAL: object = parseFloat(CHILD_VALUE(XMLNode)); break; case PLIST_NUMBER_INTEGER: object = parseInt(CHILD_VALUE(XMLNode), 10); break; - - case PLIST_STRING: object = decodeHTMLComponent(FIRST_CHILD(XMLNode) ? CHILD_VALUE(XMLNode) : ""); + + case PLIST_STRING: if (HAS_ATTRIBUTE_VALUE(XMLNode, "type", "base64")) + object = FIRST_CHILD(XMLNode) ? CFData.decodeBase64ToString(CHILD_VALUE(XMLNode)) : ""; + else + object = decodeHTMLComponent(FIRST_CHILD(XMLNode) ? CHILD_VALUE(XMLNode) : ""); + break; case PLIST_BOOLEAN_TRUE: object = YES; diff --git a/Objective-J/CPLog.js b/Objective-J/CPLog.js index b4d69c84f..473ccfd88 100644 --- a/Objective-J/CPLog.js +++ b/Objective-J/CPLog.js @@ -105,7 +105,7 @@ var _CPFormatLogMessage = function(aString, aLevel, aTitle) if (typeof exports.sprintf == "function") return exports.sprintf("%4d-%02d-%02d %02d:%02d:%02d.%03d %s%s: %s", - now.getFullYear(), now.getMonth(), now.getDate(), + now.getFullYear(), now.getMonth() + 1, now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds(), aTitle, aLevel, aString); else diff --git a/Objective-J/Debug.js b/Objective-J/Debug.js index 9c1df6cd6..1df4bd179 100644 --- a/Objective-J/Debug.js +++ b/Objective-J/Debug.js @@ -93,7 +93,7 @@ GLOBAL(objj_backtrace_decorator) = function(msgSend) return function(aReceiverOrSuper, aSelector) { var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper); - + // push the receiver and selector onto the backtrace stack objj_backtrace.push({ receiver: aReceiver, selector : aSelector }); try @@ -105,6 +105,9 @@ GLOBAL(objj_backtrace_decorator) = function(msgSend) // print the exception and backtrace CPLog.warn("Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector)); objj_backtrace_print(CPLog.warn); + + // re-throw the exception + throw anException; } finally { @@ -114,6 +117,24 @@ GLOBAL(objj_backtrace_decorator) = function(msgSend) } } +GLOBAL(objj_supress_exceptions_decorator) = function(msgSend) +{ + return function(aReceiverOrSuper, aSelector) + { + var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper); + + try + { + return msgSend.apply(NULL, arguments); + } + catch (anException) + { + // print the exception and backtrace + CPLog.warn("Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector)); + } + } +} + // type checking decorator var objj_typechecks_reported = {}, diff --git a/Objective-J/Runtime.js b/Objective-J/Runtime.js index 1df7ab26f..7a88ebb9a 100644 --- a/Objective-J/Runtime.js +++ b/Objective-J/Runtime.js @@ -50,7 +50,7 @@ GLOBAL(objj_method) = function(/*String*/ aName, /*IMP*/ anImplementation, /*Str DISPLAY_NAME(objj_method); -GLOBAL(objj_class) = function() +GLOBAL(objj_class) = function(displayName) { this.isa = NULL; @@ -67,7 +67,14 @@ GLOBAL(objj_class) = function() this.method_store = function() { }; this.method_dtable = this.method_store.prototype; +#if DEBUG + // naming the allocator allows the WebKit heap snapshot tool to display object class names correctly + // HACK: displayName property is not respected so we must eval a function to name it + this.allocator = eval("(function " + (displayName || "OBJJ_OBJECT").replace(/\W/g, "_") + "() { })"); +#else this.allocator = function() { }; +#endif + this._UID = -1; } @@ -325,8 +332,8 @@ var REGISTERED_CLASSES = { }; GLOBAL(objj_allocateClassPair) = function(/*Class*/ superclass, /*String*/ aName) { - var classObject = new objj_class(), - metaClassObject = new objj_class(), + var classObject = new objj_class(aName), + metaClassObject = new objj_class(aName), rootClassObject = classObject; // If we don't have a superclass, we are the root class. diff --git a/Tests/AppKit/ArrayController1/AppController.j b/Tests/AppKit/ArrayController1/AppController.j new file mode 100644 index 000000000..cb9facb23 --- /dev/null +++ b/Tests/AppKit/ArrayController1/AppController.j @@ -0,0 +1,187 @@ +/* + * AppController.j + * ArrayController + * + * Created by __Me__ on __Date__. + * Copyright 2008 __MyCompanyName__. All rights reserved. + */ + +@import +@import + + +CPLogRegister(CPLogConsole); + +@implementation AppController : CPObject +{ + CPArray itemsArray; + CPWindow theWindow; + + CPTableView tableView; + //CPTextField selectedNameField; + //CPTextField selectedPriceField; + CPTextField totalCountField; + + CPArrayController arrayController; +} + +- (void)awakeFromCib +{ + var contentView = [theWindow contentView]; + + //create our non ui objects + + itemsArray = [[Item new]]; + + arrayController = [[CPArrayController alloc] init]; + + [arrayController setEditable:YES]; + [arrayController setObjectClass:Item]; + [arrayController setAutomaticallyPreparesContent:YES]; + + [arrayController setSelectsInsertedObjects:YES]; + [arrayController setAvoidsEmptySelection:YES]; + + //create our UI elements + + tableView = [[CPTableView alloc] initWithFrame:CGRectMake(0, 0, 400, 200)]; + //[tableView setCenter:[contentView center]]; + [tableView setBackgroundColor:[CPColor redColor]]; + + var column = [[CPTableColumn alloc] initWithIdentifier:@"name"]; + + [tableView addTableColumn:column]; + + column = [[CPTableColumn alloc] initWithIdentifier:@"price"]; + + [tableView addTableColumn:column]; + + //[tableView setDataSource:self]; + + [contentView addSubview:tableView]; + + //create our bindings + + [self createBindings]; + + //order front window + + [theWindow setFullBridge:YES]; + [theWindow orderFront:self]; +} +/* +- (int)numberOfRowsInTableView:(CPTableView)tableView +{ + return [itemsArray count]; +} + +- (id)tableView:(CPTableView)tableView objectValueForTableColumn:(CPTableColumn)tableColumn row:(int)row +{ + return "foo"; +} +*/ +- (void)add:(id)aSender +{ + [arrayController add:self]; +} + +- (void)remove:(id)aSender +{ + [arrayController remove:self]; +} + +- (void)createBindings +{ + // bind array controller to self's itemsArray + [arrayController bind:@"contentArray" toObject:self + withKeyPath:@"itemsArray" options:nil]; + + // bind the total field -- no options on this one + [totalCountField bind:CPValueBinding toObject:arrayController + withKeyPath:@"arrangedObjects.@sum.price" options:nil]; + + var bindingOptions = [CPDictionary dictionary]; + + // binding options for "name" + //[bindingOptions setObject:@"No Name" forKey:@"NSNullPlaceholder"]; + + // binding for selected "name" field + //[selectedNameField bind: @"value" toObject: arrayController + // withKeyPath:@"selection.name" options:bindingOptions]; + + // binding for "name" column + var tableColumn = [tableView tableColumnWithIdentifier:@"name"]; + + [tableColumn bind:@"value" toObject: arrayController + withKeyPath:@"arrangedObjects.name" options:bindingOptions]; + + + // binding options for "price" + // no need for placeholder as overridden by formatters + //[bindingOptions removeObjectForKey:@"NSNullPlaceholder"]; + + //[bindingOptions setObject:YES + // forKey:CPValidatesImmediatelyBindingOption]; + + // binding for selected "price" field + //[selectedPriceField bind: @"value" toObject: arrayController + // withKeyPath:@"selection.price" options:bindingOptions]; + + + // binding for "price" column + tableColumn = [tableView tableColumnWithIdentifier:@"price"]; + + [tableColumn bind:@"value" toObject: arrayController + withKeyPath:@"arrangedObjects.price" options:bindingOptions]; +} + +- (unsigned int)countOfItemsArray +{ + return [itemsArray count]; +} + +- (id)objectInItemsArrayAtIndex:(unsigned int)index +{ + return [itemsArray objectAtIndex:index]; +} + +- (void)insertObject:(id)anObject inItemsArrayAtIndex:(unsigned int)index +{ + [itemsArray insertObject:anObject atIndex:index]; +} + +- (void)removeObjectFromItemsArrayAtIndex:(unsigned int)index +{ + [itemsArray removeObjectAtIndex:index]; +} + +- (void)replaceObjectInItemsArrayAtIndex:(unsigned int)index withObject:(id)anObject +{ + [itemsArray replaceObjectAtIndex:index withObject:anObject]; +} + +@end + +@implementation Item : CPObject +{ + float price @accessors; + CPString name @accessors; +} + +- (id)init +{ + self = [super init]; + price = 7.0; + name = "bob"; + return self; +} + +- (BOOL)validatePrice:(id)value error:({CPError})error +{ + if ([value intValue] >= 0) + return YES; + + return NO; +} + +@end diff --git a/Tests/AppKit/ArrayController1/Info.plist b/Tests/AppKit/ArrayController1/Info.plist new file mode 100644 index 000000000..172435c5a --- /dev/null +++ b/Tests/AppKit/ArrayController1/Info.plist @@ -0,0 +1,12 @@ + + + + + Main cib file base name + MainMenu.cib + CPBundleName + ArrayController + CPPrincipalClass + CPApplication + + diff --git a/Tests/AppKit/ArrayController1/Resources/MainMenu.cib b/Tests/AppKit/ArrayController1/Resources/MainMenu.cib new file mode 100644 index 000000000..a26484e59 --- /dev/null +++ b/Tests/AppKit/ArrayController1/Resources/MainMenu.cib @@ -0,0 +1 @@ +280NPLIST;1.0;D;K;4;$topD;K;18;CPCibObjectDataKeyD;K;6;CP$UIDd;1;2E;K;21;CPCibObjectRecordsKeyD;K;6;CP$UIDd;1;4E;E;K;8;$objectsA;S;5;$nullD;K;10;$classnameS;16;_CPCibObjectDataK;8;$classesA;S;16;_CPCibObjectDataS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;1E;K;28;_CPCibObjectDataNamesKeysKeyD;K;6;CP$UIDd;1;5E;K;30;_CPCibObjectDataNamesValuesKeyD;K;6;CP$UIDd;1;6E;K;30;_CPCibObjectDataClassesKeysKeyD;K;6;CP$UIDd;1;7E;K;32;_CPCibObjectDataClassesValuesKeyD;K;6;CP$UIDd;1;8E;K;30;_CPCibObjectDataConnectionsKeyD;K;6;CP$UIDd;1;9E;K;28;_CPCibObjectDataFrameworkKeyD;K;6;CP$UIDd;2;10E;K;26;_CPCibObjectDataNextOidKeyD;K;6;CP$UIDd;2;11E;K;30;_CPCibObjectDataObjectsKeysKeyD;K;6;CP$UIDd;2;12E;K;32;_CPCibObjectDataObjectsValuesKeyD;K;6;CP$UIDd;2;13E;K;26;_CPCibObjectDataOidKeysKeyD;K;6;CP$UIDd;2;14E;K;28;_CPCibObjectDataOidValuesKeyD;K;6;CP$UIDd;2;15E;K;28;_CPCibObjectDataFileOwnerKeyD;K;6;CP$UIDd;2;17E;K;33;_CPCibObjectDataVisibleWindowsKeyD;K;6;CP$UIDd;2;19E;E;D;K;10;$classnameS;7;CPArrayK;8;$classesA;S;7;CPArrayS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;28E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;32E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;33E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;35E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;41E;E;E;S;16;IBCocoaFrameworkd;1;2D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;51E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;46E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;33E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;53E;E;E;D;K;10;$classnameS;18;_CPCibCustomObjectK;8;$classesA;S;18;_CPCibCustomObjectS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;16E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;54E;E;D;K;10;$classnameS;5;CPSetK;8;$classesA;S;5;CPSetS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;18E;K;15;CPSetObjectsKeyD;K;6;CP$UIDd;2;55E;E;D;K;10;$classnameS;15;CibObjectRecordK;8;$classesA;S;15;CibObjectRecordS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;56E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;57E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;58E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;59E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;60E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;61E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;62E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;63E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;64E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;46E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;65E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;51E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;66E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;46E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;67E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;49E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;68E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;46E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;69E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;48E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;68E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;57E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;70E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;44E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;71E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;43E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;72E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;46E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;73E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;57E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;74E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;43E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;75E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;57E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;76E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;17E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;71E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;57E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;77E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;33E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;35E;E;D;K;6;$classD;K;6;CP$UIDd;2;16E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;78E;E;S;12;File's OwnerS;11;ApplicationD;K;10;$classnameS;21;_CPCibOutletConnectorK;8;$classesA;S;21;_CPCibOutletConnectorS;15;_CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;36E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;44E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;51E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;79E;E;D;K;10;$classnameS;22;_CPCibControlConnectorK;8;$classesA;S;22;_CPCibControlConnectorS;15;_CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;38E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;48E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;44E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;80E;E;D;K;6;$classD;K;6;CP$UIDd;2;38E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;49E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;44E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;81E;E;D;K;6;$classD;K;6;CP$UIDd;2;36E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;44E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;43E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;82E;E;D;K;10;$classnameS;20;_CPCibWindowTemplateK;8;$classesA;S;20;_CPCibWindowTemplateS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;42E;K;32;_CPCibWindowTemplateViewClassKeyD;K;6;CP$UIDd;1;0E;K;34;_CPCibWindowTemplateWindowClassKeyD;K;6;CP$UIDd;2;83E;K;33;_CPCibWindowTemplateWindowRectKeyD;K;6;CP$UIDd;2;84E;K;30;_CPCibWindowTempatStyleMaskKeyD;K;6;CP$UIDd;2;85E;K;34;_CPCibWindowTemplateWindowTitleKeyD;K;6;CP$UIDd;2;75E;K;33;_CPCibWindowTemplateWindowViewKeyD;K;6;CP$UIDd;2;46E;K;41;_CPCibWindowTemplateWindowIsFullBridgeKeyD;K;6;CP$UIDd;2;86E;E;D;K;6;$classD;K;6;CP$UIDd;2;16E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;87E;E;D;K;10;$classnameS;6;CPViewK;8;$classesA;S;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;45E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;88E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;89E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;2;90E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;91E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;92E;E;D;K;10;$classnameS;8;CPButtonK;8;$classesA;S;8;CPButtonS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;47E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;46E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;93E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;94E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;46E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;95E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;96E;K;6;$afontD;K;6;CP$UIDd;2;98E;K;11;$aalignmentD;K;6;CP$UIDd;2;11E;K;17;CPControlValueKeyD;K;6;CP$UIDd;2;99E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;100E;K;16;CPButtonImageKeyD;K;6;CP$UIDd;1;0E;K;25;CPButtonAlternateImageKeyD;K;6;CP$UIDd;1;0E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;101E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;47E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;46E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;102E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;94E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;46E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;95E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;96E;K;6;$afontD;K;6;CP$UIDd;3;103E;K;11;$aalignmentD;K;6;CP$UIDd;2;11E;K;17;CPControlValueKeyD;K;6;CP$UIDd;2;99E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;100E;K;16;CPButtonImageKeyD;K;6;CP$UIDd;1;0E;K;25;CPButtonAlternateImageKeyD;K;6;CP$UIDd;1;0E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;104E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;11;CPTextFieldK;8;$classesA;S;11;CPTextFieldS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;50E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;46E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;105E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;106E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;46E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;95E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;92E;K;6;$afontD;K;6;CP$UIDd;3;107E;K;12;$atext-colorD;K;6;CP$UIDd;3;109E;K;11;$aalignmentD;K;6;CP$UIDd;3;100E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;110E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;111E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;2;86E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;2;86E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;3;112E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;d;1;1d;2;-3S;8;CPObjectD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;44E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;S;5;ArrayD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;51E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;51E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;51E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;S;10;Text fieldD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;S;6;ButtonD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;S;6;ObjectD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;51E;E;E;S;4;ViewD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;46E;E;E;S;6;WindowD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;S;13;CPApplicationS;15;totalCountFieldS;7;remove:S;4;add:S;9;theWindowS;8;CPWindowS;28;{{191.5, 185.5}, {396, 260}}d;2;15F;S;13;AppControllerS;21;{{0, 26}, {396, 260}}S;20;{{0, 0}, {396, 260}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;51E;E;E;d;2;18S;6;normalS;22;{{154, 150}, {98, 24}}S;18;{{0, 0}, {98, 24}}d;2;45S;8;borderedD;K;10;$classnameS;6;CPFontK;8;$classesA;S;6;CPFontS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;97E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;113E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;114E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;2;86E;E;d;1;0d;1;4S;6;RemoveS;22;{{155, 111}, {98, 24}}D;K;6;$classD;K;6;CP$UIDd;2;97E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;113E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;114E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;2;86E;E;S;3;AddS;21;{{157, 73}, {96, 25}}S;18;{{0, 0}, {96, 25}}D;K;6;$classD;K;6;CP$UIDd;2;97E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;113E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;114E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;2;86E;E;D;K;10;$classnameS;7;CPColorK;8;$classesA;S;7;CPColorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;108E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;115E;E;S;5;Labeld;4;3072D;K;6;$classD;K;6;CP$UIDd;3;108E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;116E;E;S;5;Ariald;2;13D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;2;52E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;117E;D;K;6;CP$UIDd;3;117E;D;K;6;CP$UIDd;3;117E;D;K;6;CP$UIDd;2;52E;E;E;f;10;0.66666669E;K;9;$archiverS;15;CPKeyedArchiverK;8;$versionS;6;100000E; \ No newline at end of file diff --git a/Tests/AppKit/ArrayController1/index-debug.html b/Tests/AppKit/ArrayController1/index-debug.html new file mode 100644 index 000000000..070d80375 --- /dev/null +++ b/Tests/AppKit/ArrayController1/index-debug.html @@ -0,0 +1,36 @@ + + + + + + + Hello World + + + + + + + + +
+
+ +
+
+ + + diff --git a/Tests/AppKit/ArrayController1/index.html b/Tests/AppKit/ArrayController1/index.html new file mode 100644 index 000000000..801edfb68 --- /dev/null +++ b/Tests/AppKit/ArrayController1/index.html @@ -0,0 +1,37 @@ + + + + + + + Hello World + + + + + + + + + +
+
+ +
+
+ + + + diff --git a/Tests/AppKit/ArrayController1/main.j b/Tests/AppKit/ArrayController1/main.j new file mode 100644 index 000000000..94bf98cc3 --- /dev/null +++ b/Tests/AppKit/ArrayController1/main.j @@ -0,0 +1,18 @@ +/* + * main.j + * ArrayController + * + * Created by __Me__ on __Date__. + * Copyright 2008 __MyCompanyName__. All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/Tests/AppKit/CPButtonTest.j b/Tests/AppKit/CPButtonTest.j index 998053007..e922c03b7 100644 --- a/Tests/AppKit/CPButtonTest.j +++ b/Tests/AppKit/CPButtonTest.j @@ -1,6 +1,7 @@ @import @import +@import [CPApplication sharedApplication] @@ -34,4 +35,71 @@ wasClicked = YES; } +- (void)testKeyEquivalent +{ + [button setTarget:self]; + [button setAction:@selector(clickMe:)]; + [button setKeyEquivalent:"a"]; + [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:"b" charactersIgnoringModifiers:"b" isARepeat:NO keyCode:0]]; + [self assertFalse:wasClicked]; + [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:"a" charactersIgnoringModifiers:"a" isARepeat:NO keyCode:0]]; + [self assertTrue:wasClicked]; +} + +- (void)testKeyEquivalentWithModifierMask +{ + [button setTarget:self]; + [button setAction:@selector(clickMe:)]; + [button setKeyEquivalent:"a"]; + [button setKeyEquivalentModifierMask:CPAlternateKeyMask]; + [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:"a" charactersIgnoringModifiers:"a" isARepeat:NO keyCode:0]]; + [self assertFalse:wasClicked]; + [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:CPAlternateKeyMask + timestamp:nil windowNumber:nil context:nil + characters:"a" charactersIgnoringModifiers:"a" isARepeat:NO keyCode:0]]; + [self assertTrue:wasClicked]; +} + +- (void)testKeyEquivalentWithShiftMask +{ + [button setTarget:self]; + [button setAction:@selector(clickMe:)]; + [button setKeyEquivalent:"A"]; + + [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:"a" charactersIgnoringModifiers:"a" isARepeat:NO keyCode:0]]; + [self assertFalse:wasClicked]; + + [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:CPShiftKeyMask + timestamp:nil windowNumber:nil context:nil + characters:"A" charactersIgnoringModifiers:"a" isARepeat:NO keyCode:0]]; + [self assertTrue:wasClicked]; +} + +- (void)testSpecialKeyEquivalent +{ + [button setTarget:self]; + [button setAction:@selector(clickMe:)]; + [button setKeyEquivalent:CPEscapeFunctionKey]; + [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:CPDeleteCharacter charactersIgnoringModifiers:CPDeleteCharacter isARepeat:NO keyCode:0]]; + [self assertFalse:wasClicked]; + [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:"a" charactersIgnoringModifiers:"a" isARepeat:NO keyCode:0]]; + [self assertFalse:wasClicked]; + [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:CPEscapeFunctionKey charactersIgnoringModifiers:CPEscapeFunctionKey isARepeat:NO keyCode:0]]; + [self assertTrue:wasClicked]; +} + @end diff --git a/Tests/AppKit/CPKeyEquivalentPerformance.j b/Tests/AppKit/CPKeyEquivalentPerformance.j new file mode 100644 index 000000000..a6a509437 --- /dev/null +++ b/Tests/AppKit/CPKeyEquivalentPerformance.j @@ -0,0 +1,76 @@ +@import +@import +@import +@import + +[CPApplication sharedApplication]; + +@implementation CPKeyEquivalentPerformance : OJTestCase + +- (void)testKeyEquivalentSpeed +{ + var REPEATS = 1000, + theWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(0,0,200,150) + styleMask:CPWindowNotSizable], + contentView = [theWindow contentView], + subView1 = [[CPView alloc] initWithFrame:CGRectMakeZero()], + subView2 = [[CPView alloc] initWithFrame:CGRectMakeZero()], + button1 = [CPButton buttonWithTitle:"when"], + button2 = [CPButton buttonWithTitle:"you have eliminated"], + button3 = [CPButton buttonWithTitle:"the impossible"]; + + [contentView addSubview:subView1]; + [contentView addSubview:subView2]; + [subView1 addSubview:button1]; + [subView2 addSubview:button2]; + [subView2 addSubview:button3]; + + [button1 setTarget:self]; + [button1 setAction:@selector(clicked:)]; + [button1 setKeyEquivalent:"a"]; + [button1 setKeyEquivalentModifierMask:CPControlKeyMask]; + button1.clicks = 0; + + [button2 setTarget:self]; + [button2 setAction:@selector(clicked:)]; + [button2 setKeyEquivalent:"a"]; + [button2 setKeyEquivalentModifierMask:CPAlternateKeyMask|CPCommandKeyMask]; + button2.clicks = 0; + + [button3 setTarget:self]; + [button3 setAction:@selector(clicked:)]; + [button3 setKeyEquivalent:"A"]; + [button3 setKeyEquivalentModifierMask:CPControlKeyMask]; + button3.clicks = 0; + + var start = (new Date).getTime(); + + for (var i=0; i +@import + +// FIXME These imports are needed to prevent the following two errors: +// error=ReferenceError: Can't find variable: CPTopVerticalTextAlignment +// error=ReferenceError: Can't find variable: CPImageLeft +// CPControl uses these but in ojtest runs the dependencies don't +// get imported for some reason. +@import +@import + +@import +@import +@import + +@implementation CPKeyValueBindingTest : OJTestCase +{ + id FOO; +} + +- (void)testExposingBindings +{ + [BindingTester exposeBinding:@"foo"]; + [BindingTester exposeBinding:@"bar"]; + [CPObject exposeBinding:@"zoo"]; + + [self assert:["foo", "bar", "zoo"] equals:[[BindingTester new] exposedBindings]]; +} + +- (void)testBindTo +{ + var binder = [BindingTester new]; + binder.cheese = "orange"; + + [CPKeyValueBindingTest exposeBinding:@"FOO"]; + + [self bind:"FOO" toObject:binder withKeyPath:"cheese" options:nil]; + + [binder setCheese:@"banana"]; + + [self assertTrue:[self valueForKey:@"FOO"]==="banana" message:"Bound value should have been updated to banana, was "+FOO]; +} + +- (void)testBindOptions +{ + + var bindTesterA = [BindingTestWithBool new], + bindTesterB = [BindingTestWithBool new]; + + [bindTesterB bind:@"stringValue" toObject:bindTesterA withKeyPath:@"stringValue" options:[CPDictionary dictionary]]; + [self assert:nil equals:[bindTesterA stringValue] message:"initial A value unchanged"]; + [self assert:nil equals:[bindTesterB stringValue] message:"initial B value unchanged"]; + + [bindTesterA setStringValue:@"My string"]; + [self assert:@"My string" equals:[bindTesterA stringValue] message:"A value set"]; + [self assert:@"My string" equals:[bindTesterB stringValue] message:"B value updated"]; + + [bindTesterA setStringValue:nil]; + [self assert:nil equals:[bindTesterA stringValue] message:"A value reset"]; + [self assert:nil equals:[bindTesterB stringValue] message:"B value updated with nil"]; + + [bindTesterA unbind:@"stringValue"]; + + [bindTesterB bind:@"boolValue" toObject:bindTesterA withKeyPath:@"stringValue" options:[CPDictionary dictionaryWithObject:CPIsNotNilTransformerName forKey:CPValueTransformerNameBindingOption]]; + [bindTesterB setBoolValue:YES]; + [bindTesterA setStringValue:nil]; + [self assert:nil equals:[bindTesterA stringValue] message:"A value reset"]; + [self assert:NO equals:[bindTesterB boolValue] message:"B value updated"]; + + [bindTesterB setBoolValue:NO]; + [bindTesterA setStringValue:@"My string"]; + [self assert:@"My string" equals:[bindTesterA stringValue] message:"A value updated"]; + [self assert:YES equals:[bindTesterB boolValue] message:"B value updated"]; + + [bindTesterB setBoolValue:NO]; + [bindTesterA setStringValue:@""]; + [self assert:@"" equals:[bindTesterA stringValue] message:"A value updated"]; + [self assert:YES equals:[bindTesterB boolValue] message:"B value updated"]; + + [bindTesterA unbind:@"boolValue"]; + + [bindTesterB bind:@"boolValue" toObject:bindTesterA withKeyPath:@"stringValue" options:[CPDictionary dictionaryWithObject:CPIsNilTransformerName forKey:CPValueTransformerNameBindingOption]]; + [bindTesterB setBoolValue:NO]; + [bindTesterA setStringValue:nil]; + [self assert:nil equals:[bindTesterA stringValue] message:"A value reset"]; + [self assert:YES equals:[bindTesterB boolValue] message:"B value updated"]; + + [bindTesterB setBoolValue:YES]; + [bindTesterA setStringValue:@"My string"]; + [self assert:@"My string" equals:[bindTesterA stringValue] message:"A value updated"]; + [self assert:NO equals:[bindTesterB boolValue] message:"B value updated"]; + + [bindTesterB setBoolValue:YES]; + [bindTesterA setStringValue:@""]; + [self assert:@"" equals:[bindTesterA stringValue] message:"A value updated"]; + [self assert:NO equals:[bindTesterB boolValue] message:"B value updated"]; + + [bindTesterA unbind:@"boolValue"]; + + + [bindTesterB bind:@"stringValue" toObject:bindTesterA withKeyPath:@"stringValue" options:[CPDictionary dictionaryWithObject:@"placeholder" forKey:CPNullPlaceholderBindingOption]]; + + [bindTesterA setStringValue:@""]; + [self assert:@"" equals:[bindTesterA stringValue] message:"A value set (placeholder)"]; + [self assert:@"" equals:[bindTesterB stringValue] message:"B value updated (placeholder)"]; + + [bindTesterA setStringValue:@"My string"]; + [self assert:@"My string" equals:[bindTesterA stringValue] message:"A value set (placeholder)"]; + [self assert:@"My string" equals:[bindTesterB stringValue] message:"B value updated (placeholder)"]; + + [bindTesterA setStringValue:nil]; + [self assert:nil equals:[bindTesterA stringValue] message:"A value reset (placeholder)"]; + [self assert:@"placeholder" equals:[bindTesterB stringValue] message:"B value updated (placeholder)"]; +} + +- (void)testControl +{ + FOO = "bingo"; + + var binder = [BindingTester new]; + binder.cheese = "yellow"; + + var control = [[CPTextField alloc] init]; + [control setStringValue:@"brown"]; + + [CPControl exposeBinding:CPValueBinding]; + [[self class] exposeBinding:@"FOO"]; + + //[control addObserver:self forKeyPath:CPValueBinding options:nil context:"testControl"]; + + [control bind:CPValueBinding toObject:self withKeyPath:@"FOO" options:nil]; + // Should this even work? It's a two way binding. Anyhow, it currently crashes + // objj disrupting the other unit tests, so commenting it out for now. + //[self bind:@"FOO" toObject:control withKeyPath:CPValueBinding options:nil]; + + [control setStringValue:@"banana"]; + [control setStringValue:@"grapefruit"]; + + [self setValue:@"BAR" forKey:@"FOO"]; + + [self assert:FOO equals:[control stringValue]]; + + [control setStringValue:@"pina colada"]; + + //[self assert:FOO equals:[control stringValue]]; +} + +- (void)testTableColumn +{ + var tableView = [CPTableView new], + tableColumn = [[CPTableColumn alloc] initWithIdentifier:"A Column"], + arrayController = [CPArrayController new]; + + [tableView addTableColumn:tableColumn]; + + content = [ + [AccessCounter counterWithValueA:"1" valueB:"2"], + [AccessCounter counterWithValueA:"3" valueB:"4"], + [AccessCounter counterWithValueA:"5" valueB:"6"], + ]; + [arrayController setContent:content]; + + [tableColumn bind:@"value" toObject:arrayController withKeyPath:@"arrangedObjects.valueA" options:nil]; + + // Reset these if they were read during initialization. + for(var i=0; i<[content count];i++) + [content[i] setAccesses:0]; + var testView = [DataViewTester new]; + [tableColumn prepareDataView:testView forRow:0]; + [self assert:'1' equals:testView.lastValue]; + [self assert:'value' equals:testView.lastKey]; + + [tableColumn prepareDataView:testView forRow:1]; + [self assert:'3' equals:testView.lastValue]; + [self assert:'value' equals:testView.lastKey]; + + // Test that CPTableColumn is optimized to only read one value per row. + [self assert:0 equals:[content[2] accesses] message:"row 2 used "+[content[2] accesses]+" accesses but was never prepared"]; + [self assert:1 equals:[content[0] accesses] message:"row 0 used "+[content[0] accesses]+" accesses to prepare"]; + [self assert:1 equals:[content[1] accesses] message:"row 1 used "+[content[1] accesses]+" accesses to prepare"]; + + // Try the case where a key path is not used. + content = ["plain", "old", "space crystals"]; + [tableColumn bind:@"value" toObject:arrayController withKeyPath:@"arrangedObjects" options:nil]; + [arrayController setContent:content]; + + [tableColumn prepareDataView:testView forRow:1]; + [self assert:'old' equals:testView.lastValue]; + [self assert:'value' equals:testView.lastKey]; +} + +- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)aContext +{ + CPLog(@"here: "+aKeyPath+" value: "+[anObject valueForKey:aKeyPath]); +} + +@end + +@implementation BindingTester : CPObject +{ + id cheese; +} + +- (void)setCheese:(id)aCheese +{ + cheese = aCheese; +} + +- (id)cheese +{ + return cheese; +} + +@end + +@implementation BindingTestWithBool : CPObject +{ + CPString stringValue @accessors; + BOOL boolValue @accessors; +} + +@end + +@implementation DataViewTester : CPObject +{ + id lastValue; + id lastKey; +} + +- (void)setValue:value forKey:aKey +{ + lastValue = value; + lastKey = aKey; +} +@end + +@implementation AccessCounter : CPObject +{ + id valueA @accessors; + id valueB @accessors; + CPNumber accesses @accessors; +} + ++ (AccessCounter) counterWithValueA:aValue valueB:anotherValue +{ + r = [self new]; + [r setValueA:aValue]; + [r setValueB:anotherValue]; + return r; +} + +- (id)valueA +{ + accesses++; + return valueA; +} + +- (id)valueB +{ + accesses++; + return valueB; +} + +@end diff --git a/Tests/AppKit/CPMenuTest.j b/Tests/AppKit/CPMenuTest.j new file mode 100644 index 000000000..8b15d0a87 --- /dev/null +++ b/Tests/AppKit/CPMenuTest.j @@ -0,0 +1,182 @@ + +@import +@import +@import +@import + +[CPApplication sharedApplication] + +@implementation CPMenuTest : OJTestCase +{ + CPMenu menu; + BOOL escapeWasCalled; + BOOL escapeNoModifierWasCalled; + BOOL openDocumentWasCalled; + BOOL saveDocumentWasCalled; + BOOL saveDocumentAsWasCalled; + BOOL undoWasCalled; +} + +- (void)setUp +{ + // Set up a fairly complete menu to have something to work with. + menu = [[CPMenu alloc] initWithTitle:@"MainMenu"]; + + var newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"]; + [menu addItem:newMenuItem]; + + var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"]; + [menu addItem:openMenuItem]; + + var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"], + saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil]; + // S + [saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]]; + // ...vs Shift-S + [saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:@"S"]]; + + + // Cmd-Escape + [saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Escape the monotonous" action:@selector(escape:) keyEquivalent:CPEscapeFunctionKey]]; + // Escape + var pureEscape = [[CPMenuItem alloc] initWithTitle:@"Escape the cruel" action:@selector(escapeNoModifier:) keyEquivalent:CPEscapeFunctionKey]; + [pureEscape setKeyEquivalentModifierMask:0]; + [saveMenu addItem:pureEscape]; + + [saveMenuItem setSubmenu:saveMenu]; + [menu addItem:saveMenuItem]; + + var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:nil], + editMenu = [[CPMenu alloc] initWithTitle:@"Edit"], + + undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent], + redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent]; + + [undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask]; + [redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask]; + + [editMenu addItem:undoMenuItem]; + [editMenu addItem:redoMenuItem]; + + [editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]], + [editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]], + [editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]]; + + [editMenuItem setSubmenu:editMenu]; + [editMenuItem setHidden:YES]; + + [menu addItem:editMenuItem]; + [menu addItem:[CPMenuItem separatorItem]]; +} + +- (void)_retarget:(CPMenuItem)aMenu +{ + if (!aMenu) + return; + + for(var i=0; i<[aMenu numberOfItems]; i++) + { + var item = [aMenu itemAtIndex:i]; + [item setTarget:self]; + [self _retarget:[item submenu]]; + } +} + +- (void)testKeyEquivalent +{ + [self _retarget:menu]; + + // Don't match anything. + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:"b" charactersIgnoringModifiers:"b" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled || undoWasCalled]; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:"o" charactersIgnoringModifiers:"o" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled || undoWasCalled]; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:"o" charactersIgnoringModifiers:"o" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || undoWasCalled]; + [self assertTrue:openDocumentWasCalled message:"expect openDocumentWasCalled"]; + + openDocumentWasCalled = NO; + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:CPUndoKeyEquivalent charactersIgnoringModifiers:CPUndoKeyEquivalent isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled]; + [self assertTrue:undoWasCalled]; +} + +- (void)testKeyEquivalentModifierMask +{ + [self _retarget:menu]; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:CPEscapeFunctionKey charactersIgnoringModifiers:CPEscapeFunctionKey isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || openDocumentWasCalled || undoWasCalled]; + [self assertTrue:escapeNoModifierWasCalled]; + + escapeNoModifierWasCalled = NO; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:CPEscapeFunctionKey charactersIgnoringModifiers:CPEscapeFunctionKey isARepeat:NO keyCode:0]]; + [self assertFalse:escapeNoModifierWasCalled || openDocumentWasCalled || undoWasCalled]; + [self assertTrue:escapeWasCalled]; +} + +- (void)testKeyEquivalentWithShiftMask +{ + [self _retarget:menu]; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:@"s" charactersIgnoringModifiers:@"s" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled || saveDocumentAsWasCalled || undoWasCalled]; + [self assertTrue:saveDocumentWasCalled message:"saveDocumentWasCalled"]; + + saveDocumentWasCalled = NO; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask|CPShiftKeyMask + timestamp:nil windowNumber:nil context:nil + characters:@"s" charactersIgnoringModifiers:@"s" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled || saveDocumentWasCalled || undoWasCalled]; + [self assertTrue:saveDocumentAsWasCalled message:"saveDocumentAsWasCalled"]; +} + +- (void)escape:(id)sender +{ + escapeWasCalled = YES; +} + +- (void)escapeNoModifier:(id)sender +{ + escapeNoModifierWasCalled = YES; +} + +- (void)openDocument:(id)sender +{ + openDocumentWasCalled = YES; +} + +- (void)saveDocument:(id)sender +{ + saveDocumentWasCalled = YES; +} + +- (void)saveDocumentAs:(id)sender +{ + saveDocumentAsWasCalled = YES; +} + +- (void)undo:(id)sender +{ + undoWasCalled = YES; +} + +@end diff --git a/Tests/AppKit/CPPopUpButtonTest.j b/Tests/AppKit/CPPopUpButtonTest.j new file mode 100644 index 000000000..c45085633 --- /dev/null +++ b/Tests/AppKit/CPPopUpButtonTest.j @@ -0,0 +1,23 @@ + +@import +@import + +@implementation CPPopUpButtonTest : OJTestCase +{ + CPPopUpButton button; +} + +- (void)setUp +{ + button = [CPPopUpButton new]; +} + +- (void)testItemTitles +{ + [self assert:[] equals:[button itemTitles]]; + [button addItem:[[CPMenuItem alloc] initWithTitle:"Option A" action:nil keyEquivalent:nil]]; + [button addItem:[[CPMenuItem alloc] initWithTitle:"Option B" action:nil keyEquivalent:nil]]; + [self assert:["Option A", "Option B"] equals:[button itemTitles]]; +} + +@end diff --git a/Tests/AppKit/CPResponderTest.j b/Tests/AppKit/CPResponderTest.j new file mode 100644 index 000000000..eab226833 --- /dev/null +++ b/Tests/AppKit/CPResponderTest.j @@ -0,0 +1,72 @@ +@import +@import +@import + +@import + +[CPApplication sharedApplication] + +@implementation CPResponderTest : OJTestCase +{ + CPWindow theWindow; + CPResponder responder; +} + +- (void)setUp +{ + responder = [TestResponder new]; + responder.doCommandCalls = []; +} + +- (void)testInterpretKeyEvents +{ + var tests = [ + CPKeyCodes.PAGE_UP, CPPageUpFunctionKey, @selector(pageUp:), + CPKeyCodes.PAGE_DOWN, CPPageDownFunctionKey, @selector(pageDown:), + CPKeyCodes.LEFT, CPLeftArrowFunctionKey, @selector(moveLeft:), + CPKeyCodes.RIGHT, CPRightArrowFunctionKey, @selector(moveRight:), + CPKeyCodes.UP, CPUpArrowFunctionKey, @selector(moveUp:), + CPKeyCodes.DOWN, CPDownArrowFunctionKey, @selector(moveDown:), + CPKeyCodes.BACKSPACE, CPDeleteCharacter, @selector(deleteBackward:), + CPKeyCodes.ENTER, CPCarriageReturnCharacter, @selector(insertLineBreak:), + 0, CPNewlineCharacter, @selector(insertLineBreak:), + CPKeyCodes.ESC, CPEscapeFunctionKey, @selector(cancel:), + CPKeyCodes.TAB, CPTabCharacter, @selector(insertTab:) + ]; + + for (var i=0; i= 0, offsetHours = Math.floor(date.getTimezoneOffset() / 60), offsetMinutes = date.getTimezoneOffset() - offsetHours * 60, - expectedString = [CPString stringWithFormat:"2009-02-13 %02d:%02d:30 +%02d%02d", expectedHour-offsetHours, expectedMinute-offsetMinutes, offsetHours, offsetMinutes]; + expectedString; + expectedHour -= offsetHours; + expectedMinute -= offsetMinutes; + if (expectedMinute < 0) + { + expectedMinute += 60; + expectedHour--; + } + else if (expectedMinute > 59) + { + expectedMinute -= 60; + expectedHour++; + } + if (expectedHour < 0) + { + expectedHour += 24; + expectedDay--; + } + else if (expectedHour > 23) + { + expectedHour -= 24; + expectedDay++; + } - [self assert:expectedString equals:[date description]]; + if (offsetPositive) + expectedString = [CPString stringWithFormat:"2009-02-%02d %02d:%02d:30 +%02d%02d", expectedDay, expectedHour, expectedMinute, offsetHours, offsetMinutes]; + else + expectedString = [CPString stringWithFormat:"2009-02-%02d %02d:%02d:30 -%02d%02d", expectedDay, expectedHour, expectedMinute, ABS(offsetHours), ABS(offsetMinutes)]; + + [self assert:expectedString equals: [date description]]; } - (void)testCopy diff --git a/Tests/Foundation/CPKVOTest.j b/Tests/Foundation/CPKVOTest.j index 01eb83205..52e093d05 100644 --- a/Tests/Foundation/CPKVOTest.j +++ b/Tests/Foundation/CPKVOTest.j @@ -122,6 +122,22 @@ } +- (void)testDictionary +{ + var dict = [[CPDictionary alloc] init]; + + [dict setObject:@"Bob Jones" forKey:@"dictionaryKey"]; + + [dict addObserver:self + forKeyPath:@"dictionaryKey" + options:nil + context:"testDictionary"]; + + [dict setObject:@"Jo Bob Ray" forKey:@"dictionaryKey"]; + + [self assertTrue: _sawObservation message:"Never recieved an observation"]; +} + - (void)testPriorObservationOption { _sawPriorObservation = NO; @@ -611,6 +627,12 @@ [self assert:anObject equals:bob]; break; + case "testDictionary": + [self assert:aKeyPath equals:"dictionaryKey"]; + [self assert:oldValue equals:"Bob Jones"]; + [self assert:newValue equals:"Jo Bob Ray"]; + break; + default: [self assertFalse:YES message:"unhandled observation, must be an error"]; return; diff --git a/Tests/Foundation/CPObjectTest.j b/Tests/Foundation/CPObjectTest.j new file mode 100644 index 000000000..729e01c9e --- /dev/null +++ b/Tests/Foundation/CPObjectTest.j @@ -0,0 +1,45 @@ +@import + +@implementation CPObjectTest : OJTestCase +{ +} + +- (void)testImplementsSelector +{ + var receiver = [[Receiver alloc] init]; + + [self assertTrue:[receiver implementsSelector:@selector(implementedInReceiverAndSuper)]]; + [self assertTrue:[receiver implementsSelector:@selector(implementedInReceiverOnly)]]; + + [self assertFalse:[receiver implementsSelector:@selector(implementedInSuperOnly)]]; + [self assertFalse:[receiver implementsSelector:@selector(notImplementedInSuperNorReceiver)]]; + +} + +@end + +@implementation SuperReceiver : CPObject +{ +} + +- (void)implementedInReceiverAndSuper +{ +} + +- (void)implementedInSuperOnly +{ +} +@end + +@implementation Receiver : SuperReceiver +{ +} + +- (void)implementedInReceiverAndSuper +{ +} + +- (void)implementedInReceiverOnly +{ +} +@end diff --git a/Tests/Manual/LoadTimeTest/AppController.j b/Tests/Manual/LoadTimeTest/AppController.j index 1638643a2..bdb9a6c30 100644 --- a/Tests/Manual/LoadTimeTest/AppController.j +++ b/Tests/Manual/LoadTimeTest/AppController.j @@ -48,7 +48,16 @@ loadStdev = Math.sqrt(loadStdev / data.length); launchStdev = Math.sqrt(launchStdev / data.length); - + + if (window.parent.BCOMM) { + window.parent.BCOMM.finishTest({ + loadAvg : loadAvg, + launchAvg : launchAvg, + loadStdev : loadStdev, + launchStdev : launchStdev + }); + } + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], contentView = [theWindow contentView]; diff --git a/Tests/Manual/SimpleBindings2/AppController.j b/Tests/Manual/SimpleBindings2/AppController.j new file mode 100644 index 000000000..301739ea3 --- /dev/null +++ b/Tests/Manual/SimpleBindings2/AppController.j @@ -0,0 +1,87 @@ +/* + * AppController.j + * + * Created by __Me__ on __Date__. + * Copyright 2008 __MyCompanyName__. All rights reserved. + */ + +CPLogRegister(CPLogConsole); + +@import +@import + +@implementation AppController : CPObject +{ + CPSlider slider; + CPTextField textField; + + Track track @accessors; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView]; + + textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; + + [textField setAlignment:CPCenterTextAlignment]; + [textField setStringValue:@"Hello World!"]; + [textField setFont:[CPFont boldSystemFontOfSize:24.0]]; + + [textField sizeToFit]; + + [textField setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin]; + [textField setFrameOrigin:CGPointMake((CGRectGetWidth([contentView bounds]) - CGRectGetWidth([textField frame])) / 2.0, (CGRectGetHeight([contentView bounds]) - CGRectGetHeight([textField frame])) / 2.0)]; + + [contentView addSubview:textField]; + + var textFrame = [textField frame]; + + slider = [[CPSlider alloc] initWithFrame:CGRectMake(CGRectGetMinX(textFrame), CGRectGetMaxY(textFrame)+10, CGRectGetWidth(textFrame), 12)]; + + [slider setContinuous:YES]; + + [contentView addSubview:slider]; + + var button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetMinX(textFrame)+25, CGRectGetMaxY(textFrame)+40, 100, 18)]; + + [button setTitle:@"mute"]; + + [button setTarget:self]; + [button setAction:@selector(muteTrack:)]; + + [contentView addSubview:button]; + + + track = [[Track alloc] init]; + [track setVolume:5.0]; + + + //SET UP AN OBJECT CONTROLLER + + var controller = [[CPObjectController alloc] init]; + [controller bind:@"contentObject" toObject:self withKeyPath:@"track" options:nil]; + + [textField bind:CPValueBinding toObject:controller withKeyPath:@"selection.volume" options:nil]; + [slider bind:CPValueBinding toObject:controller withKeyPath:@"selection.volume" options:nil]; + + [theWindow orderFront:self]; +} + +- (IBAction)muteTrack:(id)sender +{ + [track setVolume:0.0]; +} + + +@end + + +@implementation Track : CPObject +{ + float volume @accessors; + CPString title @accessors; +} + +@end diff --git a/Tests/Manual/SimpleBindings2/Info.plist b/Tests/Manual/SimpleBindings2/Info.plist new file mode 100644 index 000000000..92ab8b53d --- /dev/null +++ b/Tests/Manual/SimpleBindings2/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + Hello World + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/SimpleBindings2/index-debug.html b/Tests/Manual/SimpleBindings2/index-debug.html new file mode 100644 index 000000000..392b37a8f --- /dev/null +++ b/Tests/Manual/SimpleBindings2/index-debug.html @@ -0,0 +1,35 @@ + + + + + + + Hello World + + + + + + + + +
+
+ +
+
+ + + diff --git a/Tests/Manual/SimpleBindings2/index.html b/Tests/Manual/SimpleBindings2/index.html new file mode 100644 index 000000000..fbcf5a9bc --- /dev/null +++ b/Tests/Manual/SimpleBindings2/index.html @@ -0,0 +1,36 @@ + + + + + + + Hello World + + + + + + + + + +
+
+ +
+
+ + + + diff --git a/Tests/Manual/SimpleBindings2/main.j b/Tests/Manual/SimpleBindings2/main.j new file mode 100644 index 000000000..b82bd4e3c --- /dev/null +++ b/Tests/Manual/SimpleBindings2/main.j @@ -0,0 +1,17 @@ +/* + * main.j + * + * Created by __Me__ on __Date__. + * Copyright 2008 __MyCompanyName__. All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/Tests/Manual/TableCibTest/Resources/MainMenu.cib b/Tests/Manual/TableCibTest/Resources/MainMenu.cib index 94613c585..b13ff6731 100644 --- a/Tests/Manual/TableCibTest/Resources/MainMenu.cib +++ b/Tests/Manual/TableCibTest/Resources/MainMenu.cib @@ -1 +1 @@ -280NPLIST;1.0;D;K;4;$topD;K;18;CPCibObjectDataKeyD;K;6;CP$UIDd;1;2E;E;K;8;$objectsA;S;5;$nullD;K;10;$classnameS;16;_CPCibObjectDataK;8;$classesA;S;16;_CPCibObjectDataS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;1E;K;28;_CPCibObjectDataNamesKeysKeyD;K;6;CP$UIDd;1;4E;K;30;_CPCibObjectDataNamesValuesKeyD;K;6;CP$UIDd;1;5E;K;30;_CPCibObjectDataClassesKeysKeyD;K;6;CP$UIDd;1;6E;K;32;_CPCibObjectDataClassesValuesKeyD;K;6;CP$UIDd;1;7E;K;30;_CPCibObjectDataConnectionsKeyD;K;6;CP$UIDd;1;8E;K;28;_CPCibObjectDataFrameworkKeyD;K;6;CP$UIDd;1;9E;K;26;_CPCibObjectDataNextOidKeyD;K;6;CP$UIDd;2;10E;K;30;_CPCibObjectDataObjectsKeysKeyD;K;6;CP$UIDd;2;11E;K;32;_CPCibObjectDataObjectsValuesKeyD;K;6;CP$UIDd;2;12E;K;26;_CPCibObjectDataOidKeysKeyD;K;6;CP$UIDd;2;13E;K;28;_CPCibObjectDataOidValuesKeyD;K;6;CP$UIDd;2;14E;K;28;_CPCibObjectDataFileOwnerKeyD;K;6;CP$UIDd;2;16E;K;33;_CPCibObjectDataVisibleWindowsKeyD;K;6;CP$UIDd;2;18E;E;D;K;10;$classnameS;7;CPArrayK;8;$classesA;S;7;CPArrayS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;37E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;50E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;53E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;57E;E;E;S;16;IBCocoaFrameworkD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;37E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;16E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;10;$classnameS;18;_CPCibCustomObjectK;8;$classesA;S;18;_CPCibCustomObjectS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;58E;E;D;K;10;$classnameS;5;CPSetK;8;$classesA;S;5;CPSetS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;17E;K;15;CPSetObjectsKeyD;K;6;CP$UIDd;2;59E;E;D;K;10;$classnameS;13;CPTableColumnK;8;$classesA;S;13;CPTableColumnS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;2;60E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;2;61E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;2;62E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;2;63E;K;26;CPTableColumnHeaderViewKeyD;K;6;CP$UIDd;2;65E;K;24;CPTableColumnDataViewKeyD;K;6;CP$UIDd;2;67E;K;28;CPTableColumnResizingMaskKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;17;CPTableHeaderViewK;8;$classesA;S;17;CPTableHeaderViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;68E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;69E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;69E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;68E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;K;29;CPTableHeaderViewTableViewKeyD;K;6;CP$UIDd;2;35E;E;D;K;10;$classnameS;6;CPViewK;8;$classesA;S;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;23E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;71E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;71E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;2;72E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;E;D;K;10;$classnameS;12;CPScrollViewK;8;$classesA;S;12;CPScrollViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;25E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;24E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;73E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;74E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;2;75E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;24E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;76E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;K;23;CPScrollViewContentViewD;K;6;CP$UIDd;2;78E;K;29;CPScrollViewHeaderClipViewKeyD;K;6;CP$UIDd;2;68E;K;21;CPScrollViewVScrollerD;K;6;CP$UIDd;2;32E;K;21;CPScrollViewHScrollerD;K;6;CP$UIDd;2;29E;K;23;CPScrollViewVLineScrollD;K;6;CP$UIDd;2;79E;K;23;CPScrollViewVPageScrollD;K;6;CP$UIDd;2;79E;K;23;CPScrollViewHLineScrollD;K;6;CP$UIDd;2;79E;K;23;CPScrollViewHPageScrollD;K;6;CP$UIDd;2;79E;K;24;CPScrollViewHasVScrollerD;K;6;CP$UIDd;2;80E;K;24;CPScrollViewHasHScrollerD;K;6;CP$UIDd;2;80E;K;29;CPScrollViewAutohidesScrollerD;K;6;CP$UIDd;2;80E;K;25;CPScrollViewCornerViewKeyD;K;6;CP$UIDd;2;82E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;2;83E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;2;84E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;2;79E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;2;85E;K;26;CPTableColumnHeaderViewKeyD;K;6;CP$UIDd;2;86E;K;24;CPTableColumnDataViewKeyD;K;6;CP$UIDd;2;87E;K;28;CPTableColumnResizingMaskKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;10;CPScrollerK;8;$classesA;S;10;CPScrollerS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;28E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;26E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;88E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;89E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;26E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;91E;K;17;CPControlValueKeyD;K;6;CP$UIDd;2;92E;K;18;CPControlTargetKeyD;K;6;CP$UIDd;2;26E;K;18;CPControlActionKeyD;K;6;CP$UIDd;2;93E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;94E;K;21;CPScrollerControlSizeD;K;6;CP$UIDd;2;95E;K;24;CPScrollerKnobProportionD;K;6;CP$UIDd;2;96E;E;D;K;10;$classnameS;20;_CPCibWindowTemplateK;8;$classesA;S;20;_CPCibWindowTemplateS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;30E;K;30;_CPCibWindowTemplateMaxSizeKeyD;K;6;CP$UIDd;2;97E;K;32;_CPCibWindowTemplateViewClassKeyD;K;6;CP$UIDd;1;0E;K;34;_CPCibWindowTemplateWindowClassKeyD;K;6;CP$UIDd;2;98E;K;33;_CPCibWindowTemplateWindowRectKeyD;K;6;CP$UIDd;2;99E;K;30;_CPCibWindowTempatStyleMaskKeyD;K;6;CP$UIDd;3;100E;K;34;_CPCibWindowTemplateWindowTitleKeyD;K;6;CP$UIDd;3;101E;K;33;_CPCibWindowTemplateWindowViewKeyD;K;6;CP$UIDd;2;24E;E;D;K;6;$classD;K;6;CP$UIDd;2;28E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;26E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;102E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;103E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;26E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;104E;K;17;CPControlValueKeyD;K;6;CP$UIDd;2;95E;K;18;CPControlTargetKeyD;K;6;CP$UIDd;2;26E;K;18;CPControlActionKeyD;K;6;CP$UIDd;3;105E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;94E;K;21;CPScrollerControlSizeD;K;6;CP$UIDd;2;95E;K;24;CPScrollerKnobProportionD;K;6;CP$UIDd;3;106E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;107E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;108E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;2;62E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;2;63E;K;26;CPTableColumnHeaderViewKeyD;K;6;CP$UIDd;3;109E;K;24;CPTableColumnDataViewKeyD;K;6;CP$UIDd;3;110E;K;28;CPTableColumnResizingMaskKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;11;CPTableViewK;8;$classesA;S;11;CPTableViewS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;34E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;78E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;111E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;111E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;78E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;94E;K;24;CPTableViewDataSourceKeyD;K;6;CP$UIDd;1;0E;K;22;CPTableViewDelegateKeyD;K;6;CP$UIDd;1;0E;K;23;CPTableViewRowHeightKeyD;K;6;CP$UIDd;3;112E;K;30;CPTableViewIntercellSpacingKeyD;K;6;CP$UIDd;3;113E;K;31;CPTableViewMultipleSelectionKeyD;K;6;CP$UIDd;3;114E;K;28;CPTableViewEmptySelectionKeyD;K;6;CP$UIDd;2;80E;K;30;CPTableViewColumnReorderingKeyD;K;6;CP$UIDd;2;80E;K;28;CPTableViewColumnResizingKeyD;K;6;CP$UIDd;2;80E;K;29;CPTableViewColumnSelectionKeyD;K;6;CP$UIDd;2;80E;K;26;CPTableViewTableColumnsKeyD;K;6;CP$UIDd;3;115E;K;23;CPTableViewGridColorKeyD;K;6;CP$UIDd;3;117E;K;27;CPTableViewGridStyleMaskKeyD;K;6;CP$UIDd;1;0E;K;39;CPTableViewUsesAlternatingBackgroundKeyD;K;6;CP$UIDd;2;80E;K;34;CPTableViewAlternatingRowColorsKeyD;K;6;CP$UIDd;3;118E;K;24;CPTableViewCornerViewKeyD;K;6;CP$UIDd;2;82E;K;24;CPTableViewHeaderViewKeyD;K;6;CP$UIDd;2;22E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;58E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;3;119E;E;S;16;Table Column (2)S;12;File's OwnerS;17;Table Header ViewS;12;Content ViewS;33;Bordered Scroll View (Table View)S;16;Table Column (3)S;19;Horizontal ScrollerS;15;Window (Window)S;29;Text Field Cell (Text Cell)-1S;29;Text Field Cell (Text Cell)-2S;27;Text Field Cell (Text Cell)S;17;Vertical ScrollerS;16;Table Column (1)S;29;Table View (Column 1, Two, 3)S;11;ApplicationS;14;App ControllerD;K;10;$classnameS;20;CPCibOutletConnectorK;8;$classesA;S;20;CPCibOutletConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;54E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;16E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;37E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;120E;E;D;K;6;$classD;K;6;CP$UIDd;2;54E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;37E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;31E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;121E;E;D;K;6;$classD;K;6;CP$UIDd;2;54E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;35E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;37E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;122E;E;S;13;CPApplicationD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;31E;E;E;S;1;2d;3;154d;2;40d;4;1000D;K;10;$classnameS;24;_CPTableColumnHeaderViewK;8;$classesA;S;24;_CPTableColumnHeaderViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;64E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;123E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;123E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;124E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;K;38;_CPTableColumnHeaderViewStringValueKeyD;K;6;CP$UIDd;3;125E;K;32;_CPTableColumnHeaderViewImageKeyD;K;6;CP$UIDd;1;0E;K;31;_CPTableColumnHeaderViewFontKeyD;K;6;CP$UIDd;3;127E;E;D;K;10;$classnameS;11;CPTextFieldK;8;$classesA;S;11;CPTextFieldS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;66E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;123E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;123E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;12;$atext-colorD;K;6;CP$UIDd;3;130E;K;11;$aalignmentD;K;6;CP$UIDd;2;95E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;131E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;1;0E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;131E;E;D;K;6;$classD;K;6;CP$UIDd;2;77E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;26E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;136E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;137E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;138E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;26E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;21;CPViewBackgroundColorD;K;6;CP$UIDd;3;135E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;K;24;CPScrollViewDocumentViewD;K;6;CP$UIDd;2;22E;E;S;19;{{0, 0}, {516, 23}}S;6;normalS;20;{{0, 0}, {558, 348}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;26E;E;E;S;22;{{20, 20}, {518, 308}}S;20;{{0, 0}, {518, 308}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;78E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;68E;D;K;6;CP$UIDd;2;82E;E;E;d;2;36D;K;10;$classnameS;10;CPClipViewK;8;$classesA;S;10;CPClipViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;77E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;26E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;133E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;111E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;134E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;26E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;21;CPViewBackgroundColorD;K;6;CP$UIDd;3;135E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;K;24;CPScrollViewDocumentViewD;K;6;CP$UIDd;2;35E;E;d;2;10T;D;K;10;$classnameS;13;_CPCornerViewK;8;$classesA;S;13;_CPCornerViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;81E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;26E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;139E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;140E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;26E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;21;CPViewBackgroundColorD;K;6;CP$UIDd;3;141E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;E;S;1;3d;3;188d;22;3.4028234663852886e+38D;K;6;$classD;K;6;CP$UIDd;2;64E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;123E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;123E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;142E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;K;38;_CPTableColumnHeaderViewStringValueKeyD;K;6;CP$UIDd;2;83E;K;32;_CPTableColumnHeaderViewImageKeyD;K;6;CP$UIDd;1;0E;K;31;_CPTableColumnHeaderViewFontKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;66E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;123E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;123E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;12;$atext-colorD;K;6;CP$UIDd;3;143E;K;11;$aalignmentD;K;6;CP$UIDd;2;95E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;131E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;1;0E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;131E;E;S;19;{{1, 1}, {516, 15}}S;19;{{0, 0}, {516, 15}}d;1;8S;8;disabledd;1;1S;29;_horizontalScrollerDidScroll:d;1;4d;1;0f;18;0.9866156787762906S;28;{1.79769e+308, 1.79769e+308}S;8;CPWindowS;24;{{335, 128}, {558, 348}}d;1;7S;6;WindowS;22;{{502, 16}, {15, 275}}S;19;{{0, 0}, {15, 275}}S;17;disabled+verticalS;27;_verticalScrollerDidScroll:f;18;0.9482758620689655S;1;1d;3;101D;K;6;$classD;K;6;CP$UIDd;2;64E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;123E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;123E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;144E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;K;38;_CPTableColumnHeaderViewStringValueKeyD;K;6;CP$UIDd;3;145E;K;32;_CPTableColumnHeaderViewImageKeyD;K;6;CP$UIDd;1;0E;K;31;_CPTableColumnHeaderViewFontKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;66E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;123E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;123E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;12;$atext-colorD;K;6;CP$UIDd;3;146E;K;11;$aalignmentD;K;6;CP$UIDd;2;95E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;131E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;1;0E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;131E;E;S;20;{{0, 0}, {516, 290}}d;2;23S;6;{0, 0}F;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;27E;E;E;D;K;10;$classnameS;7;CPColorK;8;$classesA;S;7;CPColorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;116E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;147E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;135E;D;K;6;CP$UIDd;3;148E;E;E;S;13;AppControllerS;8;delegateS;9;theWindowS;10;dataSourceS;16;{{0, 0}, {0, 0}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;150E;E;E;S;3;TwoD;K;10;$classnameS;6;CPFontK;8;$classesA;S;6;CPFontS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;126E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;151E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;152E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;3;114E;E;S;11;placeholderD;K;10;$classnameS;17;_CPThemeAttributeK;8;$classesA;S;17;_CPThemeAttributeS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;129E;K;4;nameD;K;6;CP$UIDd;3;153E;K;5;stateD;K;6;CP$UIDd;3;154E;K;5;valueD;K;6;CP$UIDd;3;135E;E;S;0;d;4;3072S;20;{{1, 1}, {516, 290}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;35E;E;E;D;K;6;$classD;K;6;CP$UIDd;3;116E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;155E;E;S;21;{{1, 291}, {516, 17}}S;19;{{0, 0}, {516, 17}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;22E;E;E;S;22;{{502, 285}, {16, 23}}S;18;{{0, 0}, {16, 23}}D;K;6;$classD;K;6;CP$UIDd;3;116E;K;22;CPColorPatternImageKeyD;K;6;CP$UIDd;3;157E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;158E;E;E;D;K;6;$classD;K;6;CP$UIDd;3;129E;K;4;nameD;K;6;CP$UIDd;3;153E;K;5;stateD;K;6;CP$UIDd;3;154E;K;5;valueD;K;6;CP$UIDd;3;135E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;159E;E;E;S;8;Column 1D;K;6;$classD;K;6;CP$UIDd;3;129E;K;4;nameD;K;6;CP$UIDd;3;153E;K;5;stateD;K;6;CP$UIDd;3;154E;K;5;valueD;K;6;CP$UIDd;3;135E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;160E;D;K;6;CP$UIDd;3;160E;D;K;6;CP$UIDd;3;160E;D;K;6;CP$UIDd;2;92E;E;E;D;K;6;$classD;K;6;CP$UIDd;3;116E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;161E;E;D;K;10;$classnameS;19;_CPImageAndTextViewK;8;$classesA;S;19;_CPImageAndTextViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;149E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;65E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;162E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;163E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;65E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;164E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;E;S;5;Ariald;2;11S;10;text-colorS;8;selectedD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;92E;E;E;D;K;10;$classnameS;7;CPImageK;8;$classesA;S;7;CPImageS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;156E;K;10;CPFilenameD;K;6;CP$UIDd;3;165E;K;6;CPSizeD;K;6;CP$UIDd;3;166E;E;D;K;6;$classD;K;6;CP$UIDd;3;149E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;86E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;162E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;163E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;86E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;164E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;E;D;K;6;$classD;K;6;CP$UIDd;3;149E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;3;109E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;162E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;163E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;3;109E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;164E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;70E;E;f;3;0.5D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;167E;D;K;6;CP$UIDd;3;168E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;92E;E;E;S;19;{{5, 1}, {-10, -1}}S;19;{{0, 0}, {-10, -1}}d;2;18S;102;file:/usr/local/narwhal/packages/cappuccino/Frameworks/Debug/AppKit/Resources/tableview-headerview.pngS;7;{1, 23}f;18;0.8941176470588236f;18;0.9058823529411765E;K;9;$archiverS;15;CPKeyedArchiverK;8;$versionS;6;100000E; \ No newline at end of file +280NPLIST;1.0;D;K;4;$topD;K;18;CPCibObjectDataKeyD;K;6;CP$UIDd;1;2E;E;K;8;$objectsA;S;5;$nullD;K;10;$classnameS;16;_CPCibObjectDataK;8;$classesA;S;16;_CPCibObjectDataS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;1E;K;28;_CPCibObjectDataNamesKeysKeyD;K;6;CP$UIDd;1;4E;K;30;_CPCibObjectDataNamesValuesKeyD;K;6;CP$UIDd;1;5E;K;30;_CPCibObjectDataClassesKeysKeyD;K;6;CP$UIDd;1;6E;K;32;_CPCibObjectDataClassesValuesKeyD;K;6;CP$UIDd;1;7E;K;30;_CPCibObjectDataConnectionsKeyD;K;6;CP$UIDd;1;8E;K;28;_CPCibObjectDataFrameworkKeyD;K;6;CP$UIDd;1;9E;K;26;_CPCibObjectDataNextOidKeyD;K;6;CP$UIDd;2;10E;K;30;_CPCibObjectDataObjectsKeysKeyD;K;6;CP$UIDd;2;11E;K;32;_CPCibObjectDataObjectsValuesKeyD;K;6;CP$UIDd;2;12E;K;26;_CPCibObjectDataOidKeysKeyD;K;6;CP$UIDd;2;13E;K;28;_CPCibObjectDataOidValuesKeyD;K;6;CP$UIDd;2;14E;K;28;_CPCibObjectDataFileOwnerKeyD;K;6;CP$UIDd;2;16E;K;33;_CPCibObjectDataVisibleWindowsKeyD;K;6;CP$UIDd;2;18E;E;D;K;10;$classnameS;7;CPArrayK;8;$classesA;S;7;CPArrayS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;19E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;37E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;50E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;53E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;57E;E;E;S;16;IBCocoaFrameworkD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;19E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;37E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;23E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;10;$classnameS;18;_CPCibCustomObjectK;8;$classesA;S;18;_CPCibCustomObjectS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;58E;E;D;K;10;$classnameS;5;CPSetK;8;$classesA;S;5;CPSetS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;17E;K;15;CPSetObjectsKeyD;K;6;CP$UIDd;2;59E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;60E;E;D;K;10;$classnameS;13;CPTableColumnK;8;$classesA;S;13;CPTableColumnS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;2;61E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;2;62E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;2;63E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;2;64E;K;26;CPTableColumnHeaderViewKeyD;K;6;CP$UIDd;2;66E;K;24;CPTableColumnDataViewKeyD;K;6;CP$UIDd;2;68E;K;28;CPTableColumnResizingMaskKeyD;K;6;CP$UIDd;2;69E;K;24;CPTableColumnIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;28;CPSortDescriptorPrototypeKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;12;CPScrollViewK;8;$classesA;S;12;CPScrollViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;22E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;27E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;70E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;71E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;2;72E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;27E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;73E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;K;23;CPScrollViewContentViewD;K;6;CP$UIDd;2;76E;K;29;CPScrollViewHeaderClipViewKeyD;K;6;CP$UIDd;2;77E;K;21;CPScrollViewVScrollerD;K;6;CP$UIDd;2;34E;K;21;CPScrollViewHScrollerD;K;6;CP$UIDd;2;31E;K;23;CPScrollViewVLineScrollD;K;6;CP$UIDd;2;63E;K;23;CPScrollViewVPageScrollD;K;6;CP$UIDd;2;63E;K;23;CPScrollViewHLineScrollD;K;6;CP$UIDd;2;63E;K;23;CPScrollViewHPageScrollD;K;6;CP$UIDd;2;63E;K;24;CPScrollViewHasVScrollerD;K;6;CP$UIDd;2;78E;K;24;CPScrollViewHasHScrollerD;K;6;CP$UIDd;2;78E;K;29;CPScrollViewAutohidesScrollerD;K;6;CP$UIDd;2;78E;K;25;CPScrollViewCornerViewKeyD;K;6;CP$UIDd;2;80E;E;D;K;10;$classnameS;20;_CPCibWindowTemplateK;8;$classesA;S;20;_CPCibWindowTemplateS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;30;_CPCibWindowTemplateMaxSizeKeyD;K;6;CP$UIDd;2;81E;K;32;_CPCibWindowTemplateViewClassKeyD;K;6;CP$UIDd;1;0E;K;34;_CPCibWindowTemplateWindowClassKeyD;K;6;CP$UIDd;2;82E;K;33;_CPCibWindowTemplateWindowRectKeyD;K;6;CP$UIDd;2;83E;K;30;_CPCibWindowTempatStyleMaskKeyD;K;6;CP$UIDd;2;84E;K;34;_CPCibWindowTemplateWindowTitleKeyD;K;6;CP$UIDd;2;85E;K;33;_CPCibWindowTemplateWindowViewKeyD;K;6;CP$UIDd;2;27E;E;D;K;10;$classnameS;6;CPViewK;8;$classesA;S;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;26E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;86E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;86E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;2;87E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;E;D;K;10;$classnameS;11;CPTableViewK;8;$classesA;S;11;CPTableViewS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;28E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;76E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;88E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;88E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;76E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;89E;K;24;CPTableViewDataSourceKeyD;K;6;CP$UIDd;1;0E;K;22;CPTableViewDelegateKeyD;K;6;CP$UIDd;1;0E;K;23;CPTableViewRowHeightKeyD;K;6;CP$UIDd;2;90E;K;30;CPTableViewIntercellSpacingKeyD;K;6;CP$UIDd;2;91E;K;31;CPTableViewMultipleSelectionKeyD;K;6;CP$UIDd;2;92E;K;28;CPTableViewEmptySelectionKeyD;K;6;CP$UIDd;2;78E;K;30;CPTableViewColumnReorderingKeyD;K;6;CP$UIDd;2;78E;K;28;CPTableViewColumnResizingKeyD;K;6;CP$UIDd;2;78E;K;29;CPTableViewColumnSelectionKeyD;K;6;CP$UIDd;2;78E;K;26;CPTableViewTableColumnsKeyD;K;6;CP$UIDd;2;93E;K;23;CPTableViewGridColorKeyD;K;6;CP$UIDd;2;95E;K;27;CPTableViewGridStyleMaskKeyD;K;6;CP$UIDd;2;96E;K;39;CPTableViewUsesAlternatingBackgroundKeyD;K;6;CP$UIDd;2;78E;K;34;CPTableViewAlternatingRowColorsKeyD;K;6;CP$UIDd;2;97E;K;24;CPTableViewCornerViewKeyD;K;6;CP$UIDd;2;80E;K;24;CPTableViewHeaderViewKeyD;K;6;CP$UIDd;2;37E;E;D;K;10;$classnameS;10;CPScrollerK;8;$classesA;S;10;CPScrollerS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;30E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;23E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;98E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;99E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;23E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;100E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;101E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;102E;K;18;CPControlTargetKeyD;K;6;CP$UIDd;2;23E;K;18;CPControlActionKeyD;K;6;CP$UIDd;3;103E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;89E;K;21;CPScrollerControlSizeD;K;6;CP$UIDd;3;104E;K;24;CPScrollerKnobProportionD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;106E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;107E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;108E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;109E;K;26;CPTableColumnHeaderViewKeyD;K;6;CP$UIDd;3;110E;K;24;CPTableColumnDataViewKeyD;K;6;CP$UIDd;3;111E;K;28;CPTableColumnResizingMaskKeyD;K;6;CP$UIDd;2;69E;K;24;CPTableColumnIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;28;CPSortDescriptorPrototypeKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;58E;E;D;K;6;$classD;K;6;CP$UIDd;2;30E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;23E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;112E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;113E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;23E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;100E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;114E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;104E;K;18;CPControlTargetKeyD;K;6;CP$UIDd;2;23E;K;18;CPControlActionKeyD;K;6;CP$UIDd;3;115E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;89E;K;21;CPScrollerControlSizeD;K;6;CP$UIDd;3;104E;K;24;CPScrollerKnobProportionD;K;6;CP$UIDd;3;116E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;117E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;118E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;108E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;109E;K;26;CPTableColumnHeaderViewKeyD;K;6;CP$UIDd;3;119E;K;24;CPTableColumnDataViewKeyD;K;6;CP$UIDd;3;120E;K;28;CPTableColumnResizingMaskKeyD;K;6;CP$UIDd;2;69E;K;24;CPTableColumnIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;28;CPSortDescriptorPrototypeKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;17;CPTableHeaderViewK;8;$classesA;S;17;CPTableHeaderViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;36E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;77E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;121E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;121E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;77E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;K;29;CPTableHeaderViewTableViewKeyD;K;6;CP$UIDd;2;29E;E;S;14;App ControllerS;12;File's OwnerS;16;Table Column (3)S;33;Bordered Scroll View (Table View)S;15;Window (Window)S;12;Content ViewS;29;Table View (Column 1, Two, 3)S;19;Horizontal ScrollerS;29;Text Field Cell (Text Cell)-2S;29;Text Field Cell (Text Cell)-1S;16;Table Column (1)S;27;Text Field Cell (Text Cell)S;11;ApplicationS;17;Vertical ScrollerS;16;Table Column (2)S;17;Table Header ViewD;K;10;$classnameS;20;CPCibOutletConnectorK;8;$classesA;S;20;CPCibOutletConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;54E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;16E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;19E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;122E;E;D;K;6;$classD;K;6;CP$UIDd;2;54E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;19E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;25E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;123E;E;D;K;6;$classD;K;6;CP$UIDd;2;54E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;29E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;19E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;124E;E;S;13;CPApplicationD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;25E;E;E;S;13;AppControllerS;1;3d;3;188d;2;10d;22;3.4028234663852886e+38D;K;10;$classnameS;24;_CPTableColumnHeaderViewK;8;$classesA;S;24;_CPTableColumnHeaderViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;65E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;125E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;125E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;K;38;_CPTableColumnHeaderViewStringValueKeyD;K;6;CP$UIDd;2;61E;K;32;_CPTableColumnHeaderViewImageKeyD;K;6;CP$UIDd;1;0E;K;31;_CPTableColumnHeaderViewFontKeyD;K;6;CP$UIDd;3;128E;E;D;K;10;$classnameS;11;CPTextFieldK;8;$classesA;S;11;CPTextFieldS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;67E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;125E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;125E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;129E;K;6;$afontD;K;6;CP$UIDd;3;131E;K;12;$atext-colorD;K;6;CP$UIDd;3;132E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;89E;K;20;$avertical-alignmentD;K;6;CP$UIDd;2;69E;K;11;$aalignmentD;K;6;CP$UIDd;3;104E;K;15;$acontent-insetD;K;6;CP$UIDd;3;134E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;135E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;136E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;1;0E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;135E;E;d;1;2S;22;{{20, 20}, {518, 308}}S;20;{{0, 0}, {518, 308}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;76E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;77E;D;K;6;CP$UIDd;2;80E;E;E;d;2;36S;6;normalD;K;10;$classnameS;10;CPClipViewK;8;$classesA;S;10;CPClipViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;75E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;23E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;137E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;88E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;138E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;23E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;100E;K;21;CPViewBackgroundColorD;K;6;CP$UIDd;3;139E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;K;24;CPScrollViewDocumentViewD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;75E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;23E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;140E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;141E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;142E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;23E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;100E;K;21;CPViewBackgroundColorD;K;6;CP$UIDd;3;139E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;K;24;CPScrollViewDocumentViewD;K;6;CP$UIDd;2;37E;E;T;D;K;10;$classnameS;13;_CPCornerViewK;8;$classesA;S;13;_CPCornerViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;79E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;23E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;143E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;144E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;23E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;100E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;E;S;28;{1.79769e+308, 1.79769e+308}S;8;CPWindowS;24;{{335, 128}, {558, 348}}d;1;7S;6;WindowS;20;{{0, 0}, {558, 348}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;23E;E;E;S;20;{{0, 0}, {516, 290}}d;1;4d;2;23S;6;{0, 0}F;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;21E;E;E;D;K;10;$classnameS;7;CPColorK;8;$classesA;S;7;CPColorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;94E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;145E;E;d;1;3D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;139E;D;K;6;CP$UIDd;3;146E;E;E;S;19;{{1, 1}, {516, 15}}S;19;{{0, 0}, {516, 15}}d;1;8S;8;disabledd;1;1S;29;_horizontalScrollerDidScroll:d;1;0f;18;0.9866156787762906S;1;1d;3;101d;2;40d;4;1000D;K;6;$classD;K;6;CP$UIDd;2;65E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;125E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;125E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;147E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;K;38;_CPTableColumnHeaderViewStringValueKeyD;K;6;CP$UIDd;3;148E;K;32;_CPTableColumnHeaderViewImageKeyD;K;6;CP$UIDd;1;0E;K;31;_CPTableColumnHeaderViewFontKeyD;K;6;CP$UIDd;3;128E;E;D;K;6;$classD;K;6;CP$UIDd;2;67E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;125E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;125E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;129E;K;6;$afontD;K;6;CP$UIDd;3;149E;K;12;$atext-colorD;K;6;CP$UIDd;3;150E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;89E;K;20;$avertical-alignmentD;K;6;CP$UIDd;2;69E;K;11;$aalignmentD;K;6;CP$UIDd;3;104E;K;15;$acontent-insetD;K;6;CP$UIDd;3;151E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;135E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;136E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;1;0E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;135E;E;S;22;{{502, 16}, {15, 275}}S;19;{{0, 0}, {15, 275}}S;17;disabled+verticalS;27;_verticalScrollerDidScroll:f;18;0.9482758620689655S;1;2d;3;154D;K;6;$classD;K;6;CP$UIDd;2;65E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;125E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;125E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;152E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;K;38;_CPTableColumnHeaderViewStringValueKeyD;K;6;CP$UIDd;3;153E;K;32;_CPTableColumnHeaderViewImageKeyD;K;6;CP$UIDd;1;0E;K;31;_CPTableColumnHeaderViewFontKeyD;K;6;CP$UIDd;3;128E;E;D;K;6;$classD;K;6;CP$UIDd;2;67E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;125E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;125E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;129E;K;6;$afontD;K;6;CP$UIDd;3;154E;K;12;$atext-colorD;K;6;CP$UIDd;3;155E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;89E;K;20;$avertical-alignmentD;K;6;CP$UIDd;2;69E;K;11;$aalignmentD;K;6;CP$UIDd;3;104E;K;15;$acontent-insetD;K;6;CP$UIDd;3;156E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;135E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;136E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;1;0E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;135E;E;S;19;{{0, 0}, {516, 23}}S;8;delegateS;9;theWindowS;10;dataSourceS;16;{{0, 0}, {0, 0}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;158E;E;E;D;K;10;$classnameS;6;CPFontK;8;$classesA;S;6;CPFontS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;127E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;159E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;160E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;2;78E;E;S;11;placeholderD;K;10;$classnameS;17;_CPThemeAttributeK;8;$classesA;S;17;_CPThemeAttributeS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;130E;K;4;nameD;K;6;CP$UIDd;3;161E;K;5;stateD;K;6;CP$UIDd;3;162E;K;5;valueD;K;6;CP$UIDd;3;128E;E;D;K;6;$classD;K;6;CP$UIDd;3;130E;K;4;nameD;K;6;CP$UIDd;3;163E;K;6;valuesD;K;6;CP$UIDd;3;165E;E;D;K;10;$classnameS;21;_CPKeyedArchiverValueK;8;$classesA;S;21;_CPKeyedArchiverValueS;7;CPValueS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;133E;K;15;CPValueValueKeyD;K;6;CP$UIDd;3;166E;E;S;0;d;4;3072S;20;{{1, 1}, {516, 290}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;29E;E;E;D;K;6;$classD;K;6;CP$UIDd;2;94E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;167E;E;S;21;{{1, 291}, {516, 17}}S;19;{{0, 0}, {516, 17}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;37E;E;E;S;22;{{502, 285}, {16, 23}}S;18;{{0, 0}, {16, 23}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;168E;D;K;6;CP$UIDd;3;168E;D;K;6;CP$UIDd;3;168E;D;K;6;CP$UIDd;3;102E;E;E;D;K;6;$classD;K;6;CP$UIDd;2;94E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;169E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;170E;E;E;S;8;Column 1D;K;6;$classD;K;6;CP$UIDd;3;130E;K;4;nameD;K;6;CP$UIDd;3;161E;K;5;stateD;K;6;CP$UIDd;3;162E;K;5;valueD;K;6;CP$UIDd;3;128E;E;D;K;6;$classD;K;6;CP$UIDd;3;130E;K;4;nameD;K;6;CP$UIDd;3;163E;K;6;valuesD;K;6;CP$UIDd;3;171E;E;D;K;6;$classD;K;6;CP$UIDd;3;133E;K;15;CPValueValueKeyD;K;6;CP$UIDd;3;166E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;172E;E;E;S;3;TwoD;K;6;$classD;K;6;CP$UIDd;3;130E;K;4;nameD;K;6;CP$UIDd;3;161E;K;5;stateD;K;6;CP$UIDd;3;162E;K;5;valueD;K;6;CP$UIDd;3;128E;E;D;K;6;$classD;K;6;CP$UIDd;3;130E;K;4;nameD;K;6;CP$UIDd;3;163E;K;6;valuesD;K;6;CP$UIDd;3;173E;E;D;K;6;$classD;K;6;CP$UIDd;3;133E;K;15;CPValueValueKeyD;K;6;CP$UIDd;3;166E;E;D;K;10;$classnameS;19;_CPImageAndTextViewK;8;$classesA;S;19;_CPImageAndTextViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;157E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;66E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;174E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;66E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;176E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;E;S;17;Arial, sans-serifd;2;12S;4;fontS;16;selectedDataViewS;10;text-colorD;K;10;$classnameS;19;CPMutableDictionaryK;8;$classesA;S;19;CPMutableDictionaryS;12;CPDictionaryS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;164E;K;10;CP.objectsD;K;16;selectedDataViewD;K;6;CP$UIDd;3;139E;K;6;normalD;K;6;CP$UIDd;3;177E;E;E;S;39;{"top":0,"right":0,"bottom":0,"left":5}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;102E;E;E;f;18;0.8980392156862745D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;178E;D;K;6;CP$UIDd;3;179E;D;K;6;CP$UIDd;3;180E;D;K;6;CP$UIDd;3;102E;E;E;D;K;6;$classD;K;6;CP$UIDd;3;157E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;3;110E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;174E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;3;110E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;176E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;E;D;K;6;$classD;K;6;CP$UIDd;3;164E;K;10;CP.objectsD;K;16;selectedDataViewD;K;6;CP$UIDd;3;139E;K;6;normalD;K;6;CP$UIDd;3;181E;E;E;D;K;6;$classD;K;6;CP$UIDd;3;157E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;3;119E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;174E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;3;119E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;176E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;74E;E;D;K;6;$classD;K;6;CP$UIDd;3;164E;K;10;CP.objectsD;K;16;selectedDataViewD;K;6;CP$UIDd;3;139E;K;6;normalD;K;6;CP$UIDd;3;182E;E;E;S;18;{{5, 0}, {-10, 0}}S;18;{{0, 0}, {-10, 0}}d;2;18D;K;6;$classD;K;6;CP$UIDd;2;94E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;183E;E;f;18;0.9607843137254902f;18;0.9764705882352941f;18;0.9882352941176471D;K;6;$classD;K;6;CP$UIDd;2;94E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;184E;E;D;K;6;$classD;K;6;CP$UIDd;2;94E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;185E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;102E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;102E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;102E;E;E;f;3;0.2E;K;9;$archiverS;15;CPKeyedArchiverK;8;$versionS;6;100000E; \ No newline at end of file diff --git a/Tests/Manual/TableCibTest/Resources/MainMenu.xib b/Tests/Manual/TableCibTest/Resources/MainMenu.xib index 01d7aae19..42934a3ea 100644 --- a/Tests/Manual/TableCibTest/Resources/MainMenu.xib +++ b/Tests/Manual/TableCibTest/Resources/MainMenu.xib @@ -2,17 +2,17 @@ 1050 - 10C540 - 740 - 1038.25 - 458.00 + 10D573 + 759 + 1038.29 + 460.00 com.apple.InterfaceBuilder.CocoaPlugin - 740 + 759 YES - + YES @@ -218,9 +218,10 @@ 23 - -694157312 + -157286400 + 3 4 15 0 @@ -531,6 +532,7 @@ 0 + IBCocoaFramework com.apple.InterfaceBuilder.CocoaPlugin.macosx diff --git a/Tests/Objective-J/CFDictionaryTest.j b/Tests/Objective-J/CFDictionaryTest.j new file mode 100644 index 000000000..924d209fe --- /dev/null +++ b/Tests/Objective-J/CFDictionaryTest.j @@ -0,0 +1,31 @@ + +@implementation CFDictionaryTest : OJTestCase + +- (void)testContainsValue +{ + var dict = new CFMutableDictionary(); + [self assert:NO equals:dict.containsValue(@"123")]; + [self assert:NO equals:dict.containsValue(@"abc")]; + + dict.setValueForKey(@"abc", @"123"); + [self assert:YES equals:dict.containsValue(@"123")]; + [self assert:NO equals:dict.containsValue(@"abc")]; + + dict.setValueForKey(@"def", @"123"); + [self assert:YES equals:dict.containsValue(@"123")]; + [self assert:NO equals:dict.containsValue(@"abc")]; +} + +- (void)testCountOfValue +{ + var dict = new CFMutableDictionary(); + [self assert:0 equals:dict.countOfValue(@"123")]; + + dict.setValueForKey(@"abc", @"123"); + [self assert:1 equals:dict.countOfValue(@"123")]; + + dict.setValueForKey(@"def", @"123"); + [self assert:2 equals:dict.countOfValue(@"123")]; +} + +@end diff --git a/Tests/Objective-J/base64Test.j b/Tests/Objective-J/base64Test.j index 43186ff9b..bce099d2c 100644 --- a/Tests/Objective-J/base64Test.j +++ b/Tests/Objective-J/base64Test.j @@ -42,10 +42,16 @@ var base64TestStrings = [ { var result = CFData.decodeBase64ToArray(base64TestStrings[i][1]), expected = base64TestStrings[i][0]; - + for (var j = 0; j < expected.length || j < result.length; j++) [self assert:result[j] equals:expected.charCodeAt(j)]; } } +- (void)test_CFData_encodeUtfString +{ + var utfTest = "\uF728"; // A common key equivalent. + [self assert:CFData.decodeBase64ToUtf16String(CFData.encodeBase64Utf16String(utfTest)) equals:utfTest]; +} + @end diff --git a/Tests/Tools/ToolsTest.j b/Tests/Tools/ToolsTest.j index 6705affee..b44cd234b 100644 --- a/Tests/Tools/ToolsTest.j +++ b/Tests/Tools/ToolsTest.j @@ -21,13 +21,13 @@ function cleanup() { { var status; - status = OS.system(["capp", "gen", "ToolsTestApp"]); + status = OS.system(["capp", "gen", "ToolsTestApp"].map(OS.enquote).join(" ") + " > /dev/null"); [self assert:status equals:0 message:"capp gen failed"]; - status = OS.system(["press", "-f", "ToolsTestApp", "PressTestApp"]); + status = OS.system(["press", "-f", "ToolsTestApp", "PressTestApp"].map(OS.enquote).join(" ") + " > /dev/null"); [self assert:status equals:0 message:"press failed"]; - status = OS.system(["flatten", "-f", "ToolsTestApp", "FlattenTestApp"]); + status = OS.system(["flatten", "-f", "ToolsTestApp", "FlattenTestApp"].map(OS.enquote).join(" ") + " > /dev/null"); [self assert:status equals:0 message:"flatten failed"]; } diff --git a/Tools/capp/Resources/Templates/Application/index-debug.html b/Tools/capp/Resources/Templates/Application/index-debug.html index efc533581..644616e6d 100644 --- a/Tools/capp/Resources/Templates/Application/index-debug.html +++ b/Tools/capp/Resources/Templates/Application/index-debug.html @@ -37,6 +37,9 @@ // Uncomment to enable printing of backtraces on exceptions: //objj_msgSend_decorate(objj_backtrace_decorator); + + // Uncomment to supress exceptions that take place inside a message + //objj_msgSend_decorate(objj_supress_exceptions_decorator) // Uncomment to enable runtime type checking: //objj_msgSend_decorate(objj_typecheck_decorator); diff --git a/Tools/capp/Resources/Templates/NibApplication/index-debug.html b/Tools/capp/Resources/Templates/NibApplication/index-debug.html index b5e9fc417..78c59cd69 100644 --- a/Tools/capp/Resources/Templates/NibApplication/index-debug.html +++ b/Tools/capp/Resources/Templates/NibApplication/index-debug.html @@ -37,6 +37,9 @@ // Uncomment to enable printing of backtraces on exceptions: //objj_msgSend_decorate(objj_backtrace_decorator); + + // Uncomment to supress exceptions that take place inside a message + //objj_msgSend_decorate(objj_supress_exceptions_decorator) // Uncomment to enable runtime type checking: //objj_msgSend_decorate(objj_typecheck_decorator); @@ -51,7 +54,7 @@ //CPLogRegister(CPLogConsole); //CPLogRegister(CPLogPopup); - +