diff --git a/AppKit/CPAnimation.j b/AppKit/CPAnimation.j index c8321ab7b..148db1f6f 100644 --- a/AppKit/CPAnimation.j +++ b/AppKit/CPAnimation.j @@ -122,6 +122,7 @@ ACTUAL_FRAME_RATE = 0; */ - (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve { + var timingFunctionName; switch (anAnimationCurve) { case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut; diff --git a/AppKit/CPCheckBox.j b/AppKit/CPCheckBox.j index d58c49402..c13c3b5cc 100644 --- a/AppKit/CPCheckBox.j +++ b/AppKit/CPCheckBox.j @@ -110,40 +110,15 @@ CPCheckBoxImageOffset = 4.0; [self _setPlaceholder:CPOffState forMarker:CPNullMarker isDefault:YES]; } -- (void)setValueFor:(CPString)theBinding +- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding { - var destination = [_info objectForKey:CPObservedObjectKey], - keyPath = [_info objectForKey:CPObservedKeyPathKey], - options = [_info objectForKey:CPOptionsKey], - newValue = [destination valueForKeyPath:keyPath], - isPlaceholder = CPIsControllerMarker(newValue); + [_source setAllowsMixedState:(aValue === CPMixedState)]; + [_source setState:aValue]; +} - if (isPlaceholder) - { - if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption]) - { - [CPException raise:CPGenericException - reason:@"can't transform non applicable key on: " + _source + " value: " + newValue]; - } - - newValue = [self _placeholderForMarker:newValue]; - - if (newValue === CPMixedState) - { - [_source setAllowsMixedState:YES]; - } - else - { - // Cocoa will always set allowsMixedState to NO - // This behavior will be fine for Cappuccino as well if we (like Cocoa) - // default the CPConditionallySetsEnabledBindingOption to YES - [_source setAllowsMixedState:NO]; - } - } - else - newValue = [self transformValue:newValue withOptions:options]; - - [_source setState:newValue]; +- (void)setValue:(id)aValue forBinding:(CPString)aBinding +{ + [_source setState:aValue]; } @end diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j index 89b4214e2..a7aeff913 100644 --- a/AppKit/CPKeyValueBinding.j +++ b/AppKit/CPKeyValueBinding.j @@ -149,15 +149,40 @@ var CPBindingOperationAnd = 0, return self; } -- (void)setValueFor:(CPString)aBinding +- (void)setValueFor:(CPString)theBinding { var destination = [_info objectForKey:CPObservedObjectKey], keyPath = [_info objectForKey:CPObservedKeyPathKey], options = [_info objectForKey:CPOptionsKey], - newValue = [destination valueForKeyPath:keyPath]; + newValue = [destination valueForKeyPath:keyPath], + isPlaceholder = CPIsControllerMarker(newValue); - newValue = [self transformValue:newValue withOptions:options]; - [_source setValue:newValue forKey:aBinding]; + if (isPlaceholder) + { + if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption]) + { + [CPException raise:CPGenericException + reason:@"Cannot transform non-applicable key on: " + _source + " key path: " + keyPath + " value: " + newValue]; + } + + var value = [self _placeholderForMarker:newValue]; + [self setPlaceholderValue:value withMarker:newValue forBinding:theBinding]; + } + else + { + var value = [self transformValue:newValue withOptions:options]; + [self setValue:value forBinding:theBinding]; + } +} + +- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding +{ + [_source setValue:aValue forKey:aBinding]; +} + +- (void)setValue:(id)aValue forBinding:(CPString)aBinding +{ + [_source setValue:aValue forKey:aBinding]; } - (void)reverseSetValueFor:(CPString)aBinding @@ -168,7 +193,10 @@ var CPBindingOperationAnd = 0, newValue = [_source valueForKeyPath:aBinding]; newValue = [self reverseTransformValue:newValue withOptions:options]; + + [self suppressSpecificNotificationFromObject:destination keyPath:keyPath]; [destination setValue:newValue forKeyPath:keyPath]; + [self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath]; } - (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context @@ -443,7 +471,7 @@ var CPBindingOperationAnd = 0, @end -var resolveMultipleValues = function resolveMultipleValues(/*CPString*/key, /*CPDictionary*/bindings, /*GSBindingOperationKind*/operation) +var resolveMultipleValues = function(/*CPString*/key, /*CPDictionary*/bindings, /*GSBindingOperationKind*/operation) { var bindingName = key, theBinding, @@ -467,7 +495,7 @@ var resolveMultipleValues = function resolveMultipleValues(/*CPString*/key, /*CP return !operation; }; -var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings) +var invokeAction = function(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings) { var theBinding = [bindings objectForKey:targetKey], infoDictionary = theBinding._info, diff --git a/AppKit/CPMenuItem/_CPMenuItemMenuBarView.j b/AppKit/CPMenuItem/_CPMenuItemMenuBarView.j index 06ee3eb29..179c084e9 100644 --- a/AppKit/CPMenuItem/_CPMenuItemMenuBarView.j +++ b/AppKit/CPMenuItem/_CPMenuItemMenuBarView.j @@ -148,10 +148,8 @@ var SelectionColor = nil, [_submenuIndicatorView setFrame:submenuViewFrame]; } - _minSize = CGSizeMake(x + HORIZONTAL_MARGIN, height); - [self setAutoresizesSubviews:NO]; - [self setFrameSize:_minSize]; + [self setFrameSize:CGSizeMake(x + HORIZONTAL_MARGIN, height)]; [self setAutoresizesSubviews:YES]; } diff --git a/AppKit/CPOutlineView.j b/AppKit/CPOutlineView.j index 20fd434fd..1a9dbcb4a 100644 --- a/AppKit/CPOutlineView.j +++ b/AppKit/CPOutlineView.j @@ -151,7 +151,6 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0, _retargedChildIndex = nil; _shouldRetargetChildIndex = NO; - _startHoverTime = nil; [self setIndentationPerLevel:16.0]; [self setIndentationMarkerFollowsDataView:YES]; @@ -1365,7 +1364,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0, [self collapseItem:item]; else - [self expandItem:item]; + [self expandItem:item expandChildren:([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask)]; } /*! diff --git a/AppKit/CPRuleEditor/CPPredicateEditor.j b/AppKit/CPRuleEditor/CPPredicateEditor.j index 61b5ee498..5c4aadb64 100644 --- a/AppKit/CPRuleEditor/CPPredicateEditor.j +++ b/AppKit/CPRuleEditor/CPPredicateEditor.j @@ -345,7 +345,8 @@ { var rootRowsArray = [super _rootRowsArray], subpredicates = [CPMutableArray array], - count = count2 = [rootRowsArray count], + count, + count2 = count = [rootRowsArray count], predicate; while (count--) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 5898b759e..5191d2443 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -321,7 +321,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (void)_init { - _tableViewFlags = 0; _lastSelectedRow = -1; _selectedColumnIndexes = [CPIndexSet indexSet]; @@ -335,15 +334,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!_alternatingRowBackgroundColors) _alternatingRowBackgroundColors = [[CPColor whiteColor], [CPColor colorWithHexString:@"e4e7ff"]]; - _selectionHighlightColor = [CPColor colorWithHexString:@"5f83b9"]; - _tableColumnRanges = []; _dirtyTableColumnRangeIndex = 0; _numberOfHiddenColumns = 0; _objectValues = { }; _dataViewsForTableColumns = { }; - _dataViews = []; _numberOfRows = 0; _exposedRows = [CPIndexSet indexSet]; _exposedColumns = [CPIndexSet indexSet]; @@ -3696,7 +3692,8 @@ Your delegate can implement this method to avoid subclassing the tableview to ad [_selectedColumnIndexes getIndexes:indexes maxCount:-1 inIndexRange:exposedRange]; } - var count = count2 = [indexes count]; + var count, + count2 = count = [indexes count]; if (!count) return; @@ -4852,9 +4849,8 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", while (index != CPNotFound) { - var indexSet = (switchFlag) ? otherSet : self; - - otherIndex = [indexSet indexGreaterThanOrEqualToIndex:index]; + var indexSet = (switchFlag) ? otherSet : self, + otherIndex = [indexSet indexGreaterThanOrEqualToIndex:index]; if (otherIndex == index) { diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 5f3197720..0145649c2 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -1521,32 +1521,15 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey", [self _setPlaceholder:@"" forMarker:CPNullMarker isDefault:YES]; } -- (void)setValueFor:(CPString)theBinding +- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding { - var destination = [_info objectForKey:CPObservedObjectKey], - keyPath = [_info objectForKey:CPObservedKeyPathKey], - options = [_info objectForKey:CPOptionsKey], - newValue = [destination valueForKeyPath:keyPath], - isPlaceholder = CPIsControllerMarker(newValue); + [_source setPlaceholderString:aValue]; + [_source setObjectValue:nil]; +} - if (isPlaceholder) - { - if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption]) - { - [CPException raise:CPGenericException - reason:@"can't transform non applicable key on: " + _source + " value: " + newValue]; - } - - newValue = [self _placeholderForMarker:newValue]; - - [_source setPlaceholderString:newValue]; - [_source setObjectValue:nil]; - } - else - { - newValue = [self transformValue:newValue withOptions:options]; - [_source setObjectValue:newValue]; - } +- (void)setValue:(id)aValue forBinding:(CPString)aBinding +{ + [_source setObjectValue:aValue]; } @end diff --git a/AppKit/CPWindow/_CPHUDWindowView.j b/AppKit/CPWindow/_CPHUDWindowView.j index 1f3a391bf..b668e865f 100644 --- a/AppKit/CPWindow/_CPHUDWindowView.j +++ b/AppKit/CPWindow/_CPHUDWindowView.j @@ -105,7 +105,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0; if ([[[self window] toolbar] isVisible]) { - toolbarHeight = CGRectGetHeight([[self toolbarView] frame]); + var toolbarHeight = CGRectGetHeight([[self toolbarView] frame]); frameRect.origin.y -= toolbarHeight; frameRect.size.height += toolbarHeight; diff --git a/AppKit/CPWindow/_CPStandardWindowView.j b/AppKit/CPWindow/_CPStandardWindowView.j index 03c44a6c0..47cf61ddb 100644 --- a/AppKit/CPWindow/_CPStandardWindowView.j +++ b/AppKit/CPWindow/_CPStandardWindowView.j @@ -197,7 +197,7 @@ var STANDARD_GRADIENT_HEIGHT = 41.0, if ([theToolbar isVisible]) { - toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]); + var toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]); frameRect.origin.y -= toolbarHeight; frameRect.size.height += toolbarHeight; diff --git a/Foundation/CPArray/CPArray.j b/Foundation/CPArray/CPArray.j index 5a27eca97..78c462aae 100755 --- a/Foundation/CPArray/CPArray.j +++ b/Foundation/CPArray/CPArray.j @@ -522,7 +522,7 @@ var concat = Array.prototype.concat, if ([objects count]) { - argumentsArray = [[nil, aSelector] arrayByAddingObjectsFromArray:objects]; + var argumentsArray = [[nil, aSelector] arrayByAddingObjectsFromArray:objects]; for (; index < count; ++index) { diff --git a/Foundation/CPArray/_CPJavaScriptArray.j b/Foundation/CPArray/_CPJavaScriptArray.j index 2cadc2113..7860a9adc 100644 --- a/Foundation/CPArray/_CPJavaScriptArray.j +++ b/Foundation/CPArray/_CPJavaScriptArray.j @@ -163,7 +163,7 @@ var concat = Array.prototype.concat, if ([objects count]) { - argumentsArray = [[nil, aSelector] arrayByAddingObjectsFromArray:objects]; + var argumentsArray = [[nil, aSelector] arrayByAddingObjectsFromArray:objects]; for (; index < count; ++index) { diff --git a/Tests/AppKit/CPKeyValueBindingTest.j b/Tests/AppKit/CPKeyValueBindingTest.j index 3886e7512..9f2860a91 100644 --- a/Tests/AppKit/CPKeyValueBindingTest.j +++ b/Tests/AppKit/CPKeyValueBindingTest.j @@ -297,6 +297,36 @@ [self assert:@"octarine" equals:[control stringValue] message:@"binding update no longer suppressed"]; } +- (void)testReverseSetValueForDoesNotSetObjectValueOnSource +{ + var control = [[TextField alloc] init]; + [control setStringValue:@"brown"]; + + var oc = [[CPObjectController alloc] initWithContent:[CPDictionary dictionaryWithObject:@"toto" forKey:@"foo"]]; + [oc setAutomaticallyPreparesContent:YES]; + + [control bind:CPValueBinding toObject:oc withKeyPath:@"selection.foo" options:nil]; + + [control setObjectValueSetterCount:0]; + // This will force a binding update -reverseSetValueFor: + [control sendAction:nil to:nil]; + + [self assert:0 equals:[control objectValueSetterCount] message:@"-setObjectValue should not be called"]; +} + +@end + +@implementation TextField : CPTextField +{ + CPInteger objectValueSetterCount @accessors; +} + +- (void)setObjectValue:(id)aValue +{ + objectValueSetterCount++; + [super setObjectValue:aValue]; +} + @end @implementation BindingTester : CPObject @@ -371,4 +401,4 @@ return valueB; } -@end +@end \ No newline at end of file diff --git a/Tests/Manual/CPBinder-echo-bug/AppController.j b/Tests/Manual/CPBinder-echo-bug/AppController.j new file mode 100644 index 000000000..1d6682e60 --- /dev/null +++ b/Tests/Manual/CPBinder-echo-bug/AppController.j @@ -0,0 +1,65 @@ +/* + * AppController.j + * CPBinder-echo-bug + * + * Created by You on March 29, 2012. + * Copyright 2012, Your Company All rights reserved. + */ + +@import + + +@implementation AppController : CPObject +{ +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView]; + + var message = [[CPTextField alloc] initWithFrame:CGRectMake(10,10,1000,32)]; + [message setFont:[CPFont boldSystemFontOfSize:16.0]]; + [message setStringValue:@"Type some text in the text field and press enter. You should NOT see any new call to -setObjectValue: in the console"]; + [contentView addSubview:message]; + + var label = [[TextField alloc] initWithFrame:CGRectMake(0,0,400,22)]; + [label setPlaceholderString:@"Type some text and hit enter"]; + [label setBezeled:YES]; + [label setBezelStyle:CPTextFieldSquareBezel]; + [label setBordered:YES]; + [label setEditable:YES]; + + var oc = [[CPObjectController alloc] initWithContent:[CPDictionary dictionaryWithObject:@"" forKey:@"foo"]]; + [oc setAutomaticallyPreparesContent:YES]; + + [label bind:CPValueBinding toObject:oc withKeyPath:@"selection.foo" options:nil]; + [label setFont:[CPFont boldSystemFontOfSize:24.0]]; + [label setBackgroundColor:[CPColor greenColor]]; + [label sizeToFit]; + + [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin]; + [label setCenter:[contentView center]]; + + [contentView addSubview:label]; + + [theWindow orderFront:self]; + + // Uncomment the following line to turn on the standard menu bar. + //[CPMenu setMenuBarVisible:YES]; +} + +@end + +@implementation TextField : CPTextField +{ +} + +- (void)setObjectValue:(id)aValue +{ + CPLogConsole(_cmd + [super objectValue] + " > " + aValue); + [self setBackgroundColor:[CPColor redColor]]; + [super setObjectValue:aValue]; +} + +@end diff --git a/Tests/Manual/CPBinder-echo-bug/Info.plist b/Tests/Manual/CPBinder-echo-bug/Info.plist new file mode 100644 index 000000000..6937aee46 --- /dev/null +++ b/Tests/Manual/CPBinder-echo-bug/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + CPBinder-echo-bug + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/CPBinder-echo-bug/Jakefile b/Tests/Manual/CPBinder-echo-bug/Jakefile new file mode 100644 index 000000000..eb1b44f6f --- /dev/null +++ b/Tests/Manual/CPBinder-echo-bug/Jakefile @@ -0,0 +1,93 @@ +/* + * Jakefile + * CPBinder-echo-bug + * + * Created by You on March 29, 2012. + * Copyright 2012, Your Company All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + JAKE = require("jake"), + task = JAKE.task, + FileList = JAKE.FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug", + OS = require("os"); + +app ("CPBinderEchoBug", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "CPBinderEchoBug.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("CPBinder-echo-bug"); + task.setIdentifier("com.yourcompany.CPBinderEchoBug"); + task.setVersion("1.0"); + task.setAuthor("Your Company"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("CPBinder-echo-bug"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["CPBinderEchoBug"], function() +{ + printResults(configuration); +}); + +task ("build", ["default"]); + +task ("debug", function() +{ + ENV["CONFIGURATION"] = "Debug"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("release", function() +{ + ENV["CONFIGURATION"] = "Release"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("run", ["debug"], function() +{ + OS.system(["open", FILE.join("Build", "Debug", "CPBinderEchoBug", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "CPBinderEchoBug", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "CPBinderEchoBug")); + OS.system(["press", "-f", FILE.join("Build", "Release", "CPBinderEchoBug"), FILE.join("Build", "Deployment", "CPBinderEchoBug")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "CPBinderEchoBug")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "CPBinderEchoBug"), FILE.join("Build", "Desktop", "CPBinderEchoBug", "CPBinderEchoBug.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "CPBinderEchoBug", "CPBinderEchoBug.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "CPBinderEchoBug")); + print("----------------------------"); +} diff --git a/Tests/Manual/CPBinder-echo-bug/Resources/spinner.gif b/Tests/Manual/CPBinder-echo-bug/Resources/spinner.gif new file mode 100644 index 000000000..06dbc2bc2 Binary files /dev/null and b/Tests/Manual/CPBinder-echo-bug/Resources/spinner.gif differ diff --git a/Tests/Manual/CPBinder-echo-bug/index-debug.html b/Tests/Manual/CPBinder-echo-bug/index-debug.html new file mode 100644 index 000000000..2f3319b88 --- /dev/null +++ b/Tests/Manual/CPBinder-echo-bug/index-debug.html @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + CPBinder-echo-bug + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/CPBinder-echo-bug/index.html b/Tests/Manual/CPBinder-echo-bug/index.html new file mode 100644 index 000000000..2d67d3934 --- /dev/null +++ b/Tests/Manual/CPBinder-echo-bug/index.html @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + CPBinder-echo-bug + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/CPBinder-echo-bug/main.j b/Tests/Manual/CPBinder-echo-bug/main.j new file mode 100644 index 000000000..e91513816 --- /dev/null +++ b/Tests/Manual/CPBinder-echo-bug/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * CPBinder-echo-bug + * + * Created by You on March 29, 2012. + * Copyright 2012, Your Company All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/common.jake b/common.jake index 7c7f18dc3..720f7d923 100644 --- a/common.jake +++ b/common.jake @@ -488,14 +488,11 @@ global.copyManPage = function(/*String*/ name, /*int*/ section) { if (!FILE.isDirectory(manDir)) { - if (!sudo(["mkdir", "-p", "-m", "0755", manDir])) - { + if (sudo(["mkdir", "-p", "-m", "0755", manDir])) stream.print("\0red(Unable to create the man directory.\0)"); - OS.exit(1); - } } - if (!sudo(["cp", "-f", pageFile, manDir])) + if (sudo(["cp", "-f", pageFile, manDir])) stream.print("\0red(Unable to copy the man file.\0)"); } }