Compare commits

...
45 Commits
Author SHA1 Message Date
Francisco Ryan Tolmasky I 9796f5d5d7 Fix CPPopUpButton menu support.
- Added enumerateObjectsUsingBlock: to CPArray
- Fixed a remaining case of [] being used instead of objectAtIndex: in CPMutableArray.
- Added KVO support for menu items array in menus.
- Changed CPPopUpButton to use KVO to sync up with menu instead of notifications.
- Removed extra menu encoding in CPPopUpButton.
- Removed extra mainMenu object from CPApplication.
- Use setters in CPResponder instead of direct ivar access in initWithCoder:.

Closes #298.
Closes $1059.

Reviewed by me.
2011-01-17 01:31:15 -08:00
Randall Luecke 8720a952b0 Fix for scrollview flashing while uniformly resizing columns. Closes #1075 2011-01-16 00:23:14 -05:00
Randall Luecke bf4724d401 Fix for textfield jumping when textfield wasn't the right size or the vertical alignment was something other than center. 2011-01-15 23:15:55 -05:00
Randall Luecke c73e2e1a91 Fix for nib2cib'd textfields jumping when editing 2011-01-15 21:45:37 -05:00
Randall Luecke 630cd121a6 Typo in docs 2011-01-15 20:40:24 -05:00
Randall Luecke 5d88ffbe66 Merge branch 'decimal' of https://github.com/stevegeek/cappuccino into stevegeek-decimal 2011-01-15 20:32:24 -05:00
Randall Luecke bd5aa1c959 Merge branch 'CPPredicate' of https://github.com/cacaodev/cappuccino into cacaodev-CPPredicate 2011-01-15 18:50:12 -05:00
Stephen Ierodiaconou c65bfd22a2 Use native javascript array for mantissa for big performance increase 2011-01-16 01:47:14 +02:00
Randall Luecke e656e0561b removeTableColumn: on the outlineview shouldn't allow removal of outlineTableColumn per cocoa. 2011-01-15 18:31:41 -05:00
Randall Luecke ddbba22533 Only set the outlineview column if it's the first column added. 2011-01-15 18:10:28 -05:00
Randall Luecke 91b5596034 Merge branch 'cacaodev-CPOutlineView' 2011-01-15 17:59:13 -05:00
Stephen Ierodiaconou e0185a0eff Documentation for CPDecimalNumber 2011-01-15 21:58:47 +02:00
Stephen Ierodiaconou 2fe8845842 CPDecimalString returns NaN for a NaN and Fix Compare of NaNs and Cocoa compatable handling of overflow/underflows when no exception 2011-01-15 19:29:55 +02:00
Stephen Ierodiaconou c02128a1fd Instantiate default number handler lazily and fix CPDecimalNumberHandler initialisers and CPDecimalNumberHandler docs 2011-01-15 18:50:47 +02:00
Stephen Ierodiaconou 27ad98e160 Initialiser fixes and docs
Fix tests for new initialisers
2011-01-15 16:40:11 +02:00
Stephen Ierodiaconou fc746db70f Cocoa compatible constructors for CPDecimals 2011-01-15 16:12:06 +02:00
Stephen Ierodiaconou 6a6256bdb4 CPCoding support for CPDecimalNumber and test 2011-01-15 14:15:31 +02:00
Stephen Ierodiaconou 5a0cfc1595 Make default number hanler file global only and Improvements and optimisations for CPDecimalNumber 2011-01-15 11:49:20 +02:00
Stephen Ierodiaconou 32107ab650 Improvements to CPDecimalNumberHandler including docs and archiving/unarchiving and associated test. 2011-01-15 09:38:31 +02:00
Francisco Ryan Tolmasky I 5c2ebd546c Don't include a delegate class entry in Info.plist for nib application templates.
Reviewed by me.
2011-01-14 15:42:23 -08:00
cacaodev 72b8ed2faf CPOutlineView: If nil, set outlineTableColumn when the first column is added.
nib2cib: handle indentationPerLevel when the key is not in the xib.
CPoutlineViewCibTest
2011-01-15 00:39:38 +01:00
Alexander Ljungberg 6b8c85df7c Additional testing for outline view archiving. 2011-01-14 19:59:25 -03:00
Alexander Ljungberg cce4e3ded8 Fixed: manual CPBrowser test's click handler threw an exception. 2011-01-14 14:46:37 -03:00
Alexander Ljungberg 0240c648aa Encode delegate when archiving CPBrowser. 2011-01-14 14:36:57 -03:00
Alexander Ljungberg 6019ff9107 Fixed: archiving 'undefined' would cause an exception. 2011-01-14 14:25:11 -03:00
Alexander Ljungberg c4ee83e4c1 Basic CPBrowser CPCoding support. 2011-01-14 13:34:18 -03:00
Alexander Ljungberg 61b0cbb1af Test CPBrowser data loading. 2011-01-14 12:42:38 -03:00
Alexander Ljungberg af30e96b7b Cleanup. 2011-01-14 12:16:51 -03:00
Alexander Ljungberg b7bdec189a Fixed: when an outline view node was expanded, selections below it would not stick to their items if the newly expanded node also had previously expanded children. 2011-01-14 12:10:52 -03:00
Alexander Ljungberg 2a27a87ae6 Fixed: CPOutlineView could not be archived with CPCoding. Closes #1093.
This fixes the exception "[_CPOutlineViewTableViewDataSource encodeWithCoder:] unrecognized selector sent to instance".
2011-01-13 22:18:05 -03:00
Alexander Ljungberg 31ac84f683 Fix non ASCII codes in documentation. 2011-01-13 20:59:28 -03:00
Alexander Ljungberg c41defe864 Merge branch 'master' of github.com:280north/cappuccino 2011-01-13 20:56:58 -03:00
Alexander Ljungberg 6bc109f7fc Optimised: outline view expandItem:expandChildren:YES sent repeated selection change notifications. 2011-01-13 20:51:43 -03:00
Alexander Ljungberg 2d603df83c Fixed: outline view's collapseItem sent up selection notifications in triplicate, each of them at the wrong time. 2011-01-13 20:03:06 -03:00
Alexander Ljungberg dcf440396d Fixed: the outline view was temporarily inconsistent to outside observers while expanding a node.
In particular, a selection did change notification was sent before the rows the selection referred to had had a chance to be loaded.
2011-01-13 18:57:36 -03:00
Randall Luecke 1dc10440b7 Documentaion of CPObjectController. 2011-01-13 00:57:07 -05:00
Randall Luecke 0ef2557ec3 Documentation of CPArrayController. 2011-01-13 00:30:50 -05:00
Randall Luecke 05e69c85c7 More documentation of the tableview, outlineview, and table columns. Wrapped formatted documenation in <pre> tags and added sample code for using custom dataviews 2011-01-12 23:40:28 -05:00
cacaodev 9c6476615d Allow parsing of functions with multiple arguments like multiply:by:(5,2) or FUNCTION('method:arg:', arg1, arg2)
Added a missing CPDate.j import in CPExpression_function that was causing an 'unknown variable CPDate' error in deploy builds.
Added documentation for +expressionForSubquery:...
Added licence headers with credits.
2011-01-12 18:43:09 +01:00
Randall Luecke b393d0597f If selectedRow no longer exists when numberOfRows change reset it to CPNotFound. Closes #1089. 2011-01-12 11:49:36 -05:00
Francisco Ryan Tolmasky I f69e2e8d8f Merge branch 'master' of github.com:280north/cappuccino 2011-01-12 08:41:26 -08:00
Francisco Ryan Tolmasky I 5fd470acea Fix for adding a js object to a CPArray and associated tests.
Reviewed by me.
2011-01-12 08:41:02 -08:00
Alexander Ljungberg 28e660c295 Merge branch 'master' of github.com:280north/cappuccino 2011-01-12 11:02:33 -03:00
Alexander Ljungberg 9a76b4451f Cleanup. 2011-01-12 10:54:47 -03:00
Alexander Ljungberg b50f955cfd Standardise source file header. 2011-01-12 10:52:35 -03:00
63 changed files with 6249 additions and 642 deletions
+10 -6
View File
@@ -90,7 +90,6 @@ CPRunContinuesResponse = -1002;
CPWindow _previousKeyWindow;
CPWindow _previousMainWindow;
CPMenu _mainMenu;
CPDocumentController _documentController;
CPModalSession _currentSession;
@@ -530,7 +529,7 @@ CPRunContinuesResponse = -1002;
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
{
return [[self keyWindow] performKeyEquivalent:anEvent] ||
[_mainMenu performKeyEquivalent:anEvent];
[[self mainMenu] performKeyEquivalent:anEvent];
}
/*!
@@ -637,7 +636,7 @@ CPRunContinuesResponse = -1002;
*/
- (CPMenu)mainMenu
{
return _mainMenu;
return [self menu];
}
/*!
@@ -645,16 +644,21 @@ CPRunContinuesResponse = -1002;
@param aMenu the menu to set for the application
*/
- (void)setMainMenu:(CPMenu)aMenu
{
[self setMenu:aMenu];
}
- (void)setMenu:(CPMenu)aMenu
{
if ([aMenu _menuName] === "CPMainMenu")
{
if (_mainMenu === aMenu)
if ([self menu] === aMenu)
return;
_mainMenu = aMenu;
[super setMenu:aMenu];
if ([CPPlatform supportsNativeMainMenu])
window.cpSetMainMenu(_mainMenu);
window.cpSetMainMenu([self menu]);
}
else
[aMenu _setMenuName:@"CPMainMenu"];
+188 -2
View File
@@ -29,7 +29,14 @@
@import "CPObjectController.j"
@import "CPKeyValueBinding.j"
/*!
@class CPArrayController
CPArrayController is a bindings compatible class that manages an array.
CPArrayController also provides selection management and sorting capabilities.
*/
@implementation CPArrayController : CPObjectController
{
BOOL _avoidsEmptySelection;
@@ -102,6 +109,7 @@
return [CPSet setWithObjects:"selectionIndexes"];
}
- (id)init
{
self = [super init];
@@ -119,37 +127,64 @@
{
[self _setContentArray:[[self newObject]]];
}
/*!
Returns YES if the selection should try to be preserved when the content changes, otherwise NO.
@return BOOL YES if the selection is preserved, otherwise NO.
*/
- (BOOL)preservesSelection
{
return _preservesSelection;
}
/*!
Sets whether the selection is kept when the content changes.
@param BOOL aFlag - YES if the selection should be kept, otherwise NO.
*/
- (void)setPreservesSelection:(BOOL)value
{
_preservesSelection = value;
}
/*!
@return BOOL - Returns YES if new objects are automatically selected, otherwise NO.
*/
- (BOOL)selectsInsertedObjects
{
return _selectsInsertedObjects;
}
/*!
Sets whether the controller will automatically select objects as they are inserted.
@return BOOL aFlag - YES if new objects are selected, otherwise NO.
*/
- (void)setSelectsInsertedObjects:(BOOL)value
{
_selectsInsertedObjects = value;
}
/*!
@return BOOL aFlag - Returns YES if the controller should try to avoid an empty selection otherwise NO.
*/
- (BOOL)avoidsEmptySelection
{
return _avoidsEmptySelection;
}
/*!
Sets whether the controller should try to avoid an empty selection.
@param BOOL aFlag - YES if the reciver should attempt to avoid an empty selection, otherwise NO.
*/
- (void)setAvoidsEmptySelection:(BOOL)value
{
_avoidsEmptySelection = value;
}
/*!
Sets the controller's content object.
@param id value - the content object of the controller.
*/
- (void)setContent:(id)value
{
if (value === nil)
@@ -199,26 +234,47 @@
[self didChangeValueForKey:@"filterPredicate"];
}
/*!
@ignore
*/
- (void)_setContentArray:(id)anArray
{
[self setContent:anArray];
}
/*!
@ignore
*/
- (void)_setContentSet:(id)aSet
{
[self setContent:[aSet allObjects]];
}
/*!
Returns the content array of the controller.
@return id the content array of the reciever
*/
- (id)contentArray
{
return [self content];
}
/*!
Returns the content of the reciever as a CPSet.
@return id - the content of the controller as a set.
*/
- (id)contentSet
{
return [CPSet setWithArray:[self content]];
}
/*!
Sorts and filters a given array and returns it.
@param CPArray anArray - an array of objects.
@return CPArray - the array of sorted objects.
*/
- (CPArray)arrangeObjects:(CPArray)objects
{
var filterPredicate = [self filterPredicate],
@@ -238,6 +294,9 @@
return [objects copy];
}
/*!
Triggers the filtering of the objects in the controller.
*/
- (void)rearrangeObjects
{
[self willChangeValueForKey:@"arrangedObjects"];
@@ -271,6 +330,9 @@
[self __setSelectionIndexes:oldSelectionIndexes];
}
/*!
@ignore
*/
- (void)__setArrangedObjects:(id)value
{
if (_arrangedObjects === value)
@@ -279,16 +341,29 @@
_arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
}
/*!
Returns an array of the controller's objects sorted and filtered.
@return - array of objects
*/
- (id)arrangedObjects
{
return _arrangedObjects;
}
/*!
Returns the receiver's array of sort descriptors.
@return CPArray an array of sort descriptors
*/
- (CPArray)sortDescriptors
{
return _sortDescriptors;
}
/*!
Sets the sort descriptors for the controller.
@param CPArray descriptors - the new sort descriptors.
*/
- (void)setSortDescriptors:(CPArray)value
{
if (_sortDescriptors === value)
@@ -300,11 +375,23 @@
[self _rearrangeObjects];
}
/*!
Returns the predicate used by the controller to filter the contents of the reciever.
If no predicate is set nil is returned.
@return CPPredicate the predicate used by the controller
*/
- (CPPredicate)filterPredicate
{
return _filterPredicate;
}
/*!
Sets the predicate for the controller to filter the content.
Passing nil will remove an existing prediate.
@param CPPrediate aPredicate - the new predicate.
*/
- (void)setFilterPredicate:(CPPredicate)value
{
[self __setFilterPredicate:value];
@@ -325,28 +412,52 @@
[self _rearrangeObjects];
}
/*!
Returns a BOOL indicating whether the receiver always returns the multiple values marker when multiple objects are selected.
@return BOOL YES is the controller always uses multiple value markers, otherwise NO.
*/
- (BOOL)alwaysUsesMultipleValuesMarker
{
return _alwaysUsesMultipleValuesMarker;
}
//Selection
/*!
Returns the index of the first object in the controller's selection.
@return unsigned - Index of the first selected object.
*/
- (unsigned)selectionIndex
{
return [_selectionIndexes firstIndex];
}
/*!
Sets the selected index
@param unsided anIndex - the new index to select
@return BOOL - Returns YES if the selection was changed, otherwise NO.
*/
- (BOOL)setSelectionIndex:(unsigned)index
{
return [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
/*!
Returns an index set of the selected indexes.
@return CPIndexSet - The selected indexes.
*/
- (CPIndexSet)selectionIndexes
{
return _selectionIndexes;
}
/*!
Sets the selection indexes of the controller.
@param CPIndexSet indexes - the indexes to select
@return BOOL - Returns YES if the selection changed, otherwise NO.
*/
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
{
[self _selectionWillChange]
@@ -400,6 +511,10 @@
return YES;
}
/*!
Returns an array of the selected objects.
@return CPArray - the selected objects.
*/
- (CPArray)selectedObjects
{
var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]];
@@ -407,6 +522,12 @@
return [_CPObservableArray arrayWithArray:(objects || [])];
}
/*!
Sets the selected objects of the controller.
@param CPArray anArray - the objects to select
@return BOOL - Returns YES if the selection was changed, otherwise NO.
*/
- (BOOL)setSelectedObjects:(CPArray)objects
{
[self willChangeValueForKey:@"selectionIndexes"];
@@ -441,12 +562,20 @@
}
//Moving selection
/*!
Returns YES if the previous object, relative to the current selection, in the controller's content array can be selected.
@return BOOL - YES if the object can be selected, otherwise NO.
*/
- (BOOL)canSelectPrevious
{
return [[self selectionIndexes] firstIndex] > 0
}
/*!
Selects the previous object, relative to the current selection, in the controllers arranged content.
@param id sender - the sender of the message.
*/
- (void)selectPrevious:(id)sender
{
var index = [[self selectionIndexes] firstIndex] - 1;
@@ -455,11 +584,20 @@
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
/*!
Returns YES if the next object, relative to the current selection, in the controller's content array can be selected.
@return BOOL - YES if the object can be selected, otherwise NO.
*/
- (BOOL)canSelectNext
{
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1;
}
/*!
Selects the next object, relative to the current selection, in the controllers arranged content.
@param id sender - the sender of the message.
*/
- (void)selectNext:(id)sender
{
var index = [[self selectionIndexes] firstIndex] + 1;
@@ -470,6 +608,11 @@
//Add/Remove
/*!
Adds object to the receiver's content collection and the arranged objects array.
@param id anObject - the object to add the controller.
*/
- (void)addObject:(id)object
{
if (![self canAdd])
@@ -503,6 +646,12 @@
[self didChangeValueForKey:@"filterPredicate"];
}
/*!
Adds an object at a given index to the reciever's collection.
@param id anObject - The object to add to the collection.
@param int anIndex - The index to insert the object at.
*/
- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex
{
if (![self canAdd])
@@ -534,6 +683,11 @@
[self didChangeValueForKey:@"filterPredicate"];
}
/*!
Removes a given object from the reciever's collection.
@param id anObject - The object to remove from the collection.
*/
- (void)removeObject:(id)object
{
[self willChangeValueForKey:@"content"];
@@ -552,6 +706,11 @@
[self didChangeValueForKey:@"content"];
}
/*!
Creates and adds a new object to the receiver's content and arranged objects.
@param id sender - The sender of the message.
*/
- (void)add:(id)sender
{
if (![self canAdd])
@@ -560,6 +719,10 @@
[self insert:sender];
}
/*!
Creates a new object and inserts it into the receiver's content array.
@param id sender - The sender of the message.
*/
- (void)insert:(id)sender
{
if (![self canInsert])
@@ -570,17 +733,29 @@
[self addObject:newObject];
}
/*!
Removes the controller's selected objects from the controller's collection.
@param id sender - The sender of the message.
*/
- (void)remove:(id)sender
{
[self removeObjects:[[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]];
}
/*!
Removes the objects at the specified indexes in the controller's arranged objects from the content array.
@param CPIndexSet indexes - indexes of the objects to remove.
*/
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)indexes
{
[self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]];
}
/*!
Adds an array of objects to the controller's collection.
@param CPArray anArray - The array of objects to add to the collection.
*/
- (void)addObjects:(CPArray)objects
{
if (![self canAdd])
@@ -595,11 +770,18 @@
[self setContent:contentArray];
}
/*!
Removes an array of objects from the collection.
@param CPArray anArray - The array of objects to remove
*/
- (void)removeObjects:(CPArray)objects
{
[self _removeObjects:objects];
}
/*!
@ignore
*/
- (void)_removeObjects:(CPArray)objects
{
[self willChangeValueForKey:@"content"];
@@ -631,6 +813,10 @@
[self didChangeValueForKey:@"content"];
}
/*!
Returns a BOOL indicating whether an object can be inserted into the controller's collection.
@return BOOL - YES if an object can be inserted, otherwise NO.
*/
- (BOOL)canInsert
{
return [self isEditable];
+83 -31
View File
@@ -83,42 +83,47 @@
{
if (self = [super initWithFrame:aFrame])
{
_rowHeight = 23.0;
_defaultColumnWidth = 140.0;
_minColumnWidth = 80.0;
_imageWidth = 23.0;
_leafWidth = 13.0;
_columnWidths = [];
_pathSeparator = "/";
_tableViews = [];
_tableDelegates = [];
_allowsMultipleSelection = YES;
_allowsEmptySelection = YES;
_tableViewClass = [_CPBrowserTableView class];
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView];
[self _init];
}
return self;
}
- (void)_init
{
_rowHeight = 23.0;
_defaultColumnWidth = 140.0;
_minColumnWidth = 80.0;
_imageWidth = 23.0;
_leafWidth = 13.0;
_columnWidths = [];
_pathSeparator = "/";
_tableViews = [];
_tableDelegates = [];
_allowsMultipleSelection = YES;
_allowsEmptySelection = YES;
_tableViewClass = [_CPBrowserTableView class];
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView];
}
- (void)setPrototypeView:(CPView)aPrototypeView
{
_prototypeView = [CPKeyedUnarchiver unarchiveObjectWithData:
@@ -650,6 +655,53 @@
@end
@implementation CPBrowser (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
[self _init];
_allowsEmptySelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsEmptySelectionKey"];
_allowsMultipleSelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsMultipleSelectionKey"];
_prototypeView = [aCoder decodeObjectForKey:@"CPBrowserPrototypeViewKey"];
_rowHeight = [aCoder decodeFloatForKey:@"CPBrowserRowHeightKey"];
_imageWidth = [aCoder decodeFloatForKey:@"CPBrowserImageWidthKey"];
_minColumnWidth = [aCoder decodeFloatForKey:@"CPBrowserMinColumnWidthKey"];
_columnWidths = [aCoder decodeObjectForKey:@"CPBrowserColumnWidthsKey"];
[self setDelegate:[aCoder decodeObjectForKey:@"CPBrowserDelegateKey"]];
[self setAutohidesScroller:[aCoder decodeBoolForKey:@"CPBrowserAutohidesScrollerKey"]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
// Don't encode the subviews, they're transient and will be recreated from data.
var actualSubviews = _subviews;
_subviews = [];
[super encodeWithCoder:aCoder];
_subviews = actualSubviews;
[aCoder encodeBool:[self autohidesScroller] forKey:@"CPBrowserAutohidesScrollerKey"];
[aCoder encodeBool:_allowsEmptySelection forKey:@"CPBrowserAllowsEmptySelectionKey"];
[aCoder encodeBool:_allowsMultipleSelection forKey:@"CPBrowserAllowsMultipleSelectionKey"];
[aCoder encodeObject:_delegate forKey:@"CPBrowserDelegateKey"];
[aCoder encodeObject:_prototypeView forKey:@"CPBrowserPrototypeViewKey"];
[aCoder encodeFloat:_rowHeight forKey:@"CPBrowserRowHeightKey"];
[aCoder encodeFloat:_imageWidth forKey:@"CPBrowserImageWidthKey"];
[aCoder encodeFloat:_minColumnWidth forKey:@"CPBrowserMinColumnWidthKey"];
[aCoder encodeObject:_columnWidths forKey:@"CPBrowserColumnWidthsKey"];
}
@end
var _CPBrowserResizeControlBackgroundImage = nil;
@implementation _CPBrowserResizeControl : CPView
+60 -27
View File
@@ -274,22 +274,7 @@ var _CPMenuBarVisible = NO,
*/
- (void)insertItem:(CPMenuItem)aMenuItem atIndex:(unsigned)anIndex
{
var menu = [aMenuItem menu];
if (menu)
if (menu !== self)
[CPException raise:CPInternalInconsistencyException reason:@"Attempted to insert item into menu that was already in another menu."];
else
return;
[aMenuItem setMenu:self];
[_items insertObject:aMenuItem atIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidAddItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
[self insertObject:aMenuItem inItemsAtIndex:anIndex];
}
/*!
@@ -346,16 +331,7 @@ var _CPMenuBarVisible = NO,
*/
- (void)removeItemAtIndex:(unsigned)anIndex
{
if (anIndex < 0 || anIndex >= _items.length)
return;
[_items[anIndex] setMenu:nil];
[_items removeObjectAtIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidRemoveItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
[self removeObjectFromItemsAtIndex:anIndex];
}
/*!
@@ -364,9 +340,11 @@ var _CPMenuBarVisible = NO,
*/
- (void)itemChanged:(CPMenuItem)aMenuItem
{
if ([aMenuItem menu] != self)
if ([aMenuItem menu] !== self)
return;
[aMenuItem setValue:[aMenuItem valueForKey:@"changeCount"] + 1 forKey:@"changeCount"];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidChangeItemNotification
object:self
@@ -1035,6 +1013,61 @@ var _CPMenuBarVisible = NO,
@end
@implementation CPMenu (CPKeyValueCoding)
- (CPUInteger)countOfItems
{
return [_items count];
}
- (CPMenuItem)objectInItemsAtIndex:(CPUInteger)anIndex
{
return [_items objectAtIndex:anIndex];
}
- (CPArray)itemsAtIndexes:(CPIndexSet)indexes
{
return [_items objectsAtIndexes:indexes];
}
@end
@implementation CPMenu (CPKeyValueObserving)
- (void)insertObject:(CPMenuItem)aMenuItem inItemsAtIndex:(CPUInteger)anIndex
{
var menu = [aMenuItem menu];
if (menu)
if (menu !== self)
[CPException raise:CPInternalInconsistencyException reason:@"Attempted to insert item into menu that was already in another menu."];
else
return;
[aMenuItem setMenu:self];
[_items insertObject:aMenuItem atIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidAddItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
}
- (void)removeObjectFromItemsAtIndex:(CPUInteger)anIndex
{
if (anIndex < 0 || anIndex >= [_items count])
return;
[[_items objectAtIndex:anIndex] setMenu:nil];
[_items removeObjectAtIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidRemoveItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
}
@end
var CPMenuTitleKey = @"CPMenuTitleKey",
CPMenuNameKey = @"CPMenuNameKey",
+5
View File
@@ -77,6 +77,8 @@
id _representedObject;
CPView _view;
int _changeCount;
_CPMenuItemView _menuItemView;
}
@@ -98,12 +100,14 @@
if (self)
{
_changeCount = 0;
_isSeparator = NO;
_title = aTitle;
_action = anAction;
_isEnabled = YES;
_isHidden = NO;
_tag = 0;
_state = CPOffState;
@@ -890,6 +894,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
if (self)
{
_changeCount = 0;
_isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey];
_title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
+106
View File
@@ -4,7 +4,16 @@
@import "CPController.j"
/*!
@class
CPObjectController is a bindings-compatible controller class.
Properties of the content object of an object of this class can be bound to user interface elements to change and access their values.
The content of an CPObjectController instance is an CPMutableDictionary object by default.
This allows a single CPObjectController instance to be used to manage several properties accessed by key value paths.
The default content object class can be changed by calling setObjectClass:, which a subclass must override.
*/
@implementation CPObjectController : CPController
{
id _contentObject;
@@ -53,11 +62,20 @@
return [CPSet setWithObjects:"editable", "selection"];
}
/*!
@ignore
*/
- (id)init
{
return [self initWithContent:nil];
}
/*!
Inits and returns a CPObjectController object with the given content.
@param id aContent - The object the conroller will use.
@return id the CPObjectConroller instance.
*/
- (id)initWithContent:(id)aContent
{
if (self = [super init])
@@ -72,11 +90,19 @@
return self;
}
/*!
Returns the controller's content object.
@return id - The content object of the controller.
*/
- (id)content
{
return _contentObject;
}
/*!
Sets the content object for the controller.
@param id aContent - The new content object for the controller.
*/
- (void)setContent:(id)aContent
{
[self willChangeValueForKey:@"contentObject"];
@@ -88,51 +114,91 @@
[self _selectionDidChange];
}
/*!
@ignore
*/
- (void)_setContentObject:(id)aContent
{
[self setContent:aContent];
}
/*!
@ignore
*/
- (id)_contentObject
{
return [self content];
}
/*!
Sets whether the controller automatically creates and inserts new content objects automatically when loading from a cib file.
If you pass YES and the controller uses prepareContent to create the content object.
The default is NO.
@param BOOL shouldAutomaticallyPrepareContent - YES if the content should be prepared, otherwise NO.
*/
- (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent
{
_automaticallyPreparesContent = shouldAutomaticallyPrepareContent;
}
/*!
Returns if the controller prepares the content automatically.
@return BOOL - YES if the content is prepared, otherwise NO.
*/
- (BOOL)automaticallyPreparesContent
{
return _automaticallyPreparesContent;
}
/*!
Overridden by a subclass that require control over the creation of new objects.
*/
- (void)prepareContent
{
[self setContent:[self newObject]];
}
/*!
Sets the object class when creating new objects.
@param Class - the class of new objects that will be created.
*/
- (void)setObjectClass:(Class)aClass
{
_objectClass = aClass;
}
/*!
Returns the class of what new objects will be when they are created.
@return Class - The class of new objects.
*/
- (Class)objectClass
{
return _objectClass;
}
/*!
@ignore
*/
- (id)_defaultNewObject
{
return [[[self objectClass] alloc] init];
}
/*!
Creates and returns a new object of the appropriate class.
@return id - The object created.
*/
- (id)newObject
{
return [self _defaultNewObject];
}
/*!
Sets the controller's content object.
@param id anObject - The object to set for the controller.
*/
- (void)addObject:(id)anObject
{
[self setContent:anObject];
@@ -141,6 +207,10 @@
[[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
/*!
Removes a given object from the controller.
@param id anObject - The object to remove from the reciver.
*/
- (void)removeObject:(id)anObject
{
if ([self content] === anObject)
@@ -150,54 +220,87 @@
[[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
/*!
Creates and adds a sets the object as the controller's content.
@param id aSender - The sender of the message.
*/
- (void)add:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self addObject:[self newObject]];
}
/*!
@return BOOL - YES if you can added to the controller using add:
*/
- (BOOL)canAdd
{
return [self isEditable];
}
/*!
Removes the content object from the controller.
@param id aSender - The sender of the message.
*/
- (void)remove:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self removeObject:[self content]];
}
/*!
@return BOOL - Returns YES if you can remove the controller's content using remove:
*/
- (BOOL)canRemove
{
return [self isEditable] && [[self selectedObjects] count];
}
/*!
Sets whether the controller allows for the editing of the content.
@param BOOL shouldBeEditable - YES if the content should be editable, otherwise NO.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
_isEditable = shouldBeEditable;
}
/*!
@return BOOL - Returns YES if the content of the controller is editable, otherwise NO.
*/
- (BOOL)isEditable
{
return _isEditable;
}
/*!
@return CPArray - Returns an array of all objects to be affected by editing.
*/
- (CPArray)selectedObjects
{
return [[_CPObservableArray alloc] initWithArray:[_contentObject]];
}
/*!
Returns a proxy object representing the controller's selection.
*/
- (id)selection
{
return _selection;
}
/*!
@ignore
*/
- (void)_selectionWillChange
{
[_selection controllerWillChange];
[self willChangeValueForKey:@"selection"];
}
/*!
@ignore
*/
- (void)_selectionDidChange
{
if (_selection === undefined || _selection === nil)
@@ -207,6 +310,9 @@
[self didChangeValueForKey:@"selection"];
}
/*!
@return id - Returns the keys which are being observed.
*/
- (id)observedKeys
{
return _observedKeys;
+108 -34
View File
@@ -75,6 +75,10 @@ var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_
CPOutlineViewDropOnItemIndex = -1;
var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
CPOutlineViewCoalesceSelectionNotificationStateOn = 1,
CPOutlineViewCoalesceSelectionNotificationStateDid = 2;
/*!
@ingroup appkit
@class CPOutlineView
@@ -84,6 +88,7 @@ CPOutlineViewDropOnItemIndex = -1;
Like the tableview, an outlineview uses a data source to supply its data. For this reason you must implement a couple data source methods (documented in setDataSource:)
Theme states for custom data views are documented in CPTableView
*/
@implementation CPOutlineView : CPTableView
{
@@ -113,6 +118,8 @@ CPOutlineViewDropOnItemIndex = -1;
CPInteger _retargedChildIndex;
CPTimer _dragHoverTimer;
id _dropItem;
BOOL _coalesceSelectionNotificationState;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -121,7 +128,6 @@ CPOutlineViewDropOnItemIndex = -1;
if (self)
{
_selectionHighlightStyle = CPTableViewSelectionHighlightStyleSourceList;
// The root item has weight "0", thus represents the weight solely of its descendants.
@@ -150,6 +156,7 @@ CPOutlineViewDropOnItemIndex = -1;
return self;
}
/*!
<pre>
In addition to standard delegation, the outline view also supports data source delegation. This method sets the data source object.
Just like the TableView you have CPTableColumns but instead of rows you deal with items.
@@ -195,7 +202,7 @@ CPOutlineViewDropOnItemIndex = -1;
Returns YES if the drop operation is allowed otherwise NO.
This method is invoked by the outlineview after a drag should begin, but before it is started. If you dont want the drag to being return NO.
If you want the drag to begin you should return YES and place the drag data on the pboard.
</pre>
*/
- (void)setDataSource:(id)aDataSource
{
@@ -327,14 +334,31 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo)
return;
// When shouldExpandChildren is YES, we need to make sure we're collecting
// selection notifications so that exactly one IsChanging and one DidChange
// is sent as needed, for the totallity of the operation.
var isTopLevel = NO;
if (!_coalesceSelectionNotificationState)
{
isTopLevel = YES;
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateOn;
}
// to prevent items which are already expanded from firing notifications
if (!itemInfo.isExpanded)
{
[self _noteItemWillExpand:anItem];
var previousRowCount = [self numberOfRows];
itemInfo.isExpanded = YES;
// XXX Shouldn't the items reload before the notification is sent?
[self _noteItemDidExpand:anItem];
[self reloadItem:anItem reloadChildren:YES];
// Shift selection indexes below so that the same items remain selected.
var newRowCount = [_outlineViewDataSource outlineView:self numberOfChildrenOfItem:anItem];
if (newRowCount)
var rowCountDelta = [self numberOfRows] - previousRowCount;
if (rowCountDelta)
{
var selection = [self selectedRowIndexes],
expandIndex = [self rowForItem:anItem] + 1;
@@ -342,14 +366,10 @@ CPOutlineViewDropOnItemIndex = -1;
if ([selection intersectsIndexesInRange:CPMakeRange(expandIndex, _itemsForRows.length)])
{
[self _noteSelectionIsChanging];
[selection shiftIndexesStartingAtIndex:expandIndex by:newRowCount];
[self _setSelectedRowIndexes:selection];
[selection shiftIndexesStartingAtIndex:expandIndex by:rowCountDelta];
[self _setSelectedRowIndexes:selection]; // _noteSelectionDidChange will be suppressed.
}
}
itemInfo.isExpanded = YES;
[self _noteItemDidExpand:anItem];
[self reloadItem:anItem reloadChildren:YES];
}
if (shouldExpandChildren)
@@ -360,6 +380,14 @@ CPOutlineViewDropOnItemIndex = -1;
while (childIndex--)
[self expandItem:children[childIndex] expandChildren:YES];
}
if (isTopLevel)
{
var r = _coalesceSelectionNotificationState;
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateOff;
if (r === CPOutlineViewCoalesceSelectionNotificationStateDid)
[self _noteSelectionDidChange];
}
}
/*!
@@ -380,6 +408,9 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo.isExpanded)
return;
// Don't spam notifications.
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateOn;
[self _noteItemWillCollapse:anItem];
// Update selections:
// * Deselect items inside the collapsed item.
@@ -392,39 +423,38 @@ CPOutlineViewDropOnItemIndex = -1;
collapseEndIndex++;
var collapseRange = CPMakeRange(collapseTopIndex + 1, collapseEndIndex - collapseTopIndex);
if (collapseRange.length)
{
var selection = [self selectedRowIndexes],
didChange = NO;
var selection = [self selectedRowIndexes];
if ([selection intersectsIndexesInRange:collapseRange])
{
[selection removeIndexesInRange:collapseRange];
[self _noteSelectionIsChanging];
didChange = YES;
// Will call _noteSelectionDidChange
[self _setSelectedRowIndexes:selection];
[selection removeIndexesInRange:collapseRange];
[self _setSelectedRowIndexes:selection]; // _noteSelectionDidChange will be suppressed.
}
// Shift any selected rows below upwards.
if ([selection intersectsIndexesInRange:CPMakeRange(collapseEndIndex + 1, _itemsForRows.length)])
{
// Notify if that wasn't already done above.
if (!didChange)
[self _noteSelectionIsChanging];
didChange = YES;
[self _noteSelectionIsChanging];
[selection shiftIndexesStartingAtIndex:collapseEndIndex + 1 by:-collapseRange.length];
[self _setSelectedRowIndexes:selection]; // _noteSelectionDidChange will be suppressed.
}
if (didChange)
[self _setSelectedRowIndexes:selection];
}
itemInfo.isExpanded = NO;
// XXX Shouldn't the items reload before the notification is sent?
[self _noteItemDidCollapse:anItem];
[self reloadItem:anItem reloadChildren:YES];
// Send selection notifications only after the items have loaded so that
// the new selection is consistent with the actual rows for any observers.
var r = _coalesceSelectionNotificationState;
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateOff;
if (r === CPOutlineViewCoalesceSelectionNotificationStateDid)
[self _noteSelectionDidChange];
}
/*!
@@ -485,7 +515,7 @@ CPOutlineViewDropOnItemIndex = -1;
/*!
Sets the table column you want to display the disclosure button in.
If you do not want an outline column pass nil.
@param aTableColumn - The CPTableColumn you want to use for hierarchical data.
*/
- (void)setOutlineTableColumn:(CPTableColumn)aTableColumn
@@ -667,6 +697,7 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
<pre>
Sets the delegate for the outlineview.
The following methods can be implemented:
@@ -727,6 +758,7 @@ CPOutlineViewDropOnItemIndex = -1;
Return YES if the item is a group item, otherwise NO.
@param aDelegate - the delegate object you wish to set for the reciever.
<pre>
*/
- (void)setDelegate:(id)aDelegate
{
@@ -922,6 +954,29 @@ CPOutlineViewDropOnItemIndex = -1;
[self reloadItem:nil reloadChildren:YES];
}
/*!
Adds a new table column to the reciever. If this is the first column added it will automatically be set to the outline column.
Also see -setOutlineTableColumn:
NOTE: This behavior deviates from cocoa slightly.
@param CPTableColumn aTableColumn - The table column to add.
*/
- (void)addTableColumn:(CPTableColumn)aTableColumn
{
[super addTableColumn:aTableColumn];
if ([self numberOfColumns] === 1)
_outlineTableColumn = aTableColumn;
}
/*!
@ignore
*/
- (void)removeTableColumn:(CPTableColumn)aTableColumn
{
if (aTableColumn === [self outlineTableColumn])
CPLog("CPOutlineView cannot remove outlineTableColumn with removeTableColumn:. User setOutlineTableColumn: instead.");
else
[super removeTableColumn:aTableColumn];
}
/*!
@ignore
We overide this because we need a special behaviour for the outline column
@@ -1277,10 +1332,16 @@ CPOutlineViewDropOnItemIndex = -1;
*/
- (void)_noteSelectionIsChanging
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewSelectionIsChangingNotification
object:self
userInfo:nil];
if (!_coalesceSelectionNotificationState || _coalesceSelectionNotificationState === CPOutlineViewCoalesceSelectionNotificationStateOn)
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewSelectionIsChangingNotification
object:self
userInfo:nil];
}
if (_coalesceSelectionNotificationState === CPOutlineViewCoalesceSelectionNotificationStateOn)
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateDid;
}
/*!
@@ -1288,10 +1349,16 @@ CPOutlineViewDropOnItemIndex = -1;
*/
- (void)_noteSelectionDidChange
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewSelectionDidChangeNotification
object:self
userInfo:nil];
if (!_coalesceSelectionNotificationState)
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewSelectionDidChangeNotification
object:self
userInfo:nil];
}
if (_coalesceSelectionNotificationState === CPOutlineViewCoalesceSelectionNotificationStateOn)
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateDid;
}
/*!
@@ -1787,7 +1854,14 @@ var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey"
- (void)encodeWithCoder:(CPCoder)aCoder
{
// Make sure we don't encode our internal delegate and data source.
var internalDelegate = _delegate,
internalDataSource = _dataSource;
_delegate = nil;
_dataSource = nil;
[super encodeWithCoder:aCoder];
_delegate = internalDelegate;
_dataSource = internalDataSource;
[aCoder encodeObject:_outlineTableColumn forKey:CPOutlineViewOutlineTableColumnKey];
[aCoder encodeFloat:_indentationPerLevel forKey:CPOutlineViewIndentationPerLevelKey];
+1 -1
View File
@@ -26,7 +26,7 @@
CPOKButton = 1;
CPCancelButton = 0;
/*!
/*!
@ingroup appkit
@class CPPanel
+165 -152
View File
@@ -38,10 +38,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
@implementation CPPopUpButton : CPButton
{
int _selectedIndex;
CPUInteger _selectedIndex;
CPRectEdge _preferredEdge;
CPMenu _menu;
}
+ (CPString)defaultThemeClass
@@ -76,6 +74,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self setMenu:[[CPMenu alloc] initWithTitle:@""]];
[self setPullsDown:shouldPullDown];
var options = CPKeyValueObservingOptionNew |
CPKeyValueObservingOptionOld;/* |
CPKeyValueObservingOptionInitial;
*/
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
}
return self;
@@ -103,7 +109,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if (!changed)
return;
var items = [_menu itemArray];
var items = [[self menu] itemArray];
if ([items count] <= 0)
return;
@@ -128,7 +134,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)addItem:(CPMenuItem)anItem
{
[_menu addItem:anItem];
[[self menu] addItem:anItem];
}
/*!
@@ -137,7 +143,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)addItemWithTitle:(CPString)aTitle
{
[_menu addItemWithTitle:aTitle action:NULL keyEquivalent:nil];
[[self menu] addItemWithTitle:aTitle action:NULL keyEquivalent:nil];
}
/*!
@@ -167,7 +173,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([items[count] title] == aTitle)
[self removeItemAtIndex:count];
[_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
[[self menu] insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
}
/*!
@@ -175,10 +181,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeAllItems
{
var count = [_menu numberOfItems];
var menu = [self menu],
count = [menu numberOfItems];
while (count--)
[_menu removeItemAtIndex:0];
[menu removeItemAtIndex:0];
}
/*!
@@ -197,7 +204,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeItemAtIndex:(int)anIndex
{
[_menu removeItemAtIndex:anIndex];
[[self menu] removeItemAtIndex:anIndex];
[self synchronizeTitleAndSelectedItem];
}
@@ -207,10 +214,12 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)selectedItem
{
if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1)
var indexOfSelectedItem = [self indexOfSelectedItem];
if (indexOfSelectedItem < 0 || indexOfSelectedItem > [self numberOfItems] - 1)
return nil;
return [_menu itemAtIndex:_selectedIndex];
return [[self menu] itemAtIndex:indexOfSelectedItem];
}
/*!
@@ -270,7 +279,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)selectItemAtIndex:(int)anIndex
{
if (_selectedIndex == anIndex)
anIndex = +anIndex;
if (_selectedIndex === anIndex)
return;
[self willChangeValueForKey:@"selectedIndex"];
@@ -316,74 +327,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
}
// Getting Menu Items
/*!
Returns the button's menu of items.
*/
- (CPMenu)menu
{
return _menu;
}
/*!
Sets the menu for the button
*/
- (void)setMenu:(CPMenu)aMenu
{
if (_menu === aMenu)
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_menu)
{
[defaultCenter
removeObserver:self
name:CPMenuDidAddItemNotification
object:_menu];
[defaultCenter
removeObserver:self
name:CPMenuDidChangeItemNotification
object:_menu];
[defaultCenter
removeObserver:self
name:CPMenuDidRemoveItemNotification
object:_menu];
}
_menu = aMenu;
if (_menu)
{
[defaultCenter
addObserver:self
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];
}
/*!
Returns a count of the number of items in the button's menu.
*/
- (int)numberOfItems
{
return [_menu numberOfItems];
return [[self menu] numberOfItems];
}
/*!
@@ -391,7 +341,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPArray)itemArray
{
return [_menu itemArray];
return [[self menu] itemArray];
}
/*!
@@ -400,7 +350,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)itemAtIndex:(unsigned)anIndex
{
return [_menu itemAtIndex:anIndex];
return [[self menu] itemAtIndex:anIndex];
}
/*!
@@ -409,7 +359,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPString)itemTitleAtIndex:(unsigned)anIndex
{
return [[_menu itemAtIndex:anIndex] title];
return [[[self menu] itemAtIndex:anIndex] title];
}
/*!
@@ -434,7 +384,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)itemWithTitle:(CPString)aTitle
{
return [_menu itemAtIndex:[_menu indexOfItemWithTitle:aTitle]];
var menu = [self menu];
return [menu itemAtIndex:[menu indexOfItemWithTitle:aTitle]];
}
/*!
@@ -442,7 +394,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)lastItem
{
return [[_menu itemArray] lastObject];
return [[[self menu] itemArray] lastObject];
}
// Getting the Indices of Menu Items
@@ -452,7 +404,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItem:(CPMenuItem)aMenuItem
{
return [_menu indexOfItem:aMenuItem];
return [[self menu] indexOfItem:aMenuItem];
}
/*!
@@ -461,7 +413,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithTag:(int)aTag
{
return [_menu indexOfItemWithTag:aTag];
return [[self menu] indexOfItemWithTag:aTag];
}
/*!
@@ -470,7 +422,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithTitle:(CPString)aTitle
{
return [_menu indexOfItemWithTitle:aTitle];
return [[self menu] indexOfItemWithTitle:aTitle];
}
/*!
@@ -481,7 +433,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithRepresentedObject:(id)anObject
{
return [_menu indexOfItemWithRepresentedObject:anObject];
return [[self menu] indexOfItemWithRepresentedObject:anObject];
}
/*!
@@ -493,7 +445,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithTarget:(id)aTarget action:(SEL)anAction
{
return [_menu indexOfItemWithTarget:aTarget action:anAction];
return [[self menu] indexOfItemWithTarget:aTarget action:anAction];
}
// Setting the Cell Edge to Pop out in Restricted Situations
@@ -529,7 +481,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown])
{
var items = [_menu itemArray];
var items = [[self menu] itemArray];
if ([items count] <= 0)
[self addItemWithTitle:aTitle];
@@ -577,7 +529,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown])
{
var items = [_menu itemArray];
var items = [[self menu] itemArray];
if ([items count] > 0)
item = items[0];
@@ -589,73 +541,117 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[super setTitle:[item title]];
}
//
/*!
Called when the menu has a new item added to it.
@param aNotification information about the event
*/
- (void)menuDidAddItem:(CPNotification)aNotification
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)aContext
{
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
var pullsDown = [self pullsDown];
if (_selectedIndex < 0)
[self selectItemAtIndex:0];
else if (index == _selectedIndex)
if (!pullsDown && aKeyPath === @"selectedItem.changeCount" ||
pullsDown && (aKeyPath === @"_firstItem" || aKeyPath === @"_firstItem.changeCount"))
[self synchronizeTitleAndSelectedItem];
else if (index < _selectedIndex)
++_selectedIndex;
if (index == 0 && [self pullsDown])
// FIXME: This is due to a bug in KVO, we should never get it for "menu".
if (aKeyPath === @"menu")
{
var items = [_menu itemArray];
aKeyPath = @"menu.items";
[items[0] setHidden:YES];
if (items.length > 0)
[items[1] setHidden:NO];
[changes setObject:CPKeyValueChangeSetting forKey:CPKeyValueChangeKindKey];
[changes setObject:[[self menu] itemArray] forKey:CPKeyValueChangeNewKey];
}
var item = [_menu itemArray][index],
action = [item action];
if (!action || (action === @selector(_popUpItemAction:)))
if (aKeyPath === @"menu.items")
{
[item setTarget:self];
[item setAction:@selector(_popUpItemAction:)];
var changeKind = [changes objectForKey:CPKeyValueChangeKindKey],
indexOfSelectedItem = [self indexOfSelectedItem];
if (changeKind === CPKeyValueChangeRemoval)
{
var index = CPNotFound,
indexes = [changes objectForKey:CPKeyValueChangeIndexesKey];
if ([indexes containsIndex:0] && [self pullsDown])
[self _firstItemDidChange];
// See whether the index has changed, despite the actual item not changing.
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
index <= indexOfSelectedItem)
--indexOfSelectedItem;
[self selectItemAtIndex:indexOfSelectedItem];
}
else if (changeKind === CPKeyValueChangeReplacement)
{
var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey];
if (pullsDown && [indexes containsIndex:0] ||
!pullsDown && [indexes containsIndex:indexOfSelectedItem])
[self synchronizeTitleAndSelectedItem];
}
else
{
// No matter what, we want to prepare the new items.
var newItems = [changes objectForKey:CPKeyValueChangeNewKey];
[newItems enumerateObjectsUsingBlock:function(aMenuItem)
{
var action = [aMenuItem action];
if (!action)
[aMenuItem setAction:action = @selector(_popUpItemAction:)];
if (action === @selector(_popUpItemAction:))
[aMenuItem setTarget:self];
}];
if (changeKind === CPKeyValueChangeSetting)
{
[self _firstItemDidChange];
_selectedIndex = -2;
[self selectItemAtIndex:MIN([newItems count] - 1, indexOfSelectedItem)];
}
else //if (changeKind === CPKeyValueChangeInsertion)
{
var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey];
if ([self pullsDown] && [indexes containsIndex:0])
{
[self _firstItemDidChange];
if ([self numberOfItems] > 1)
{
var index = CPNotFound,
originalIndex = 0;
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
index <= originalIndex)
++originalIndex;
[[self itemAtIndex:originalIndex] setHidden:NO];
}
}
if (indexOfSelectedItem < 0)
[self selectItemAtIndex:0];
else
{
var index = CPNotFound;
// See whether the index has changed, despite the actual item not changing.
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
index <= indexOfSelectedItem)
++indexOfSelectedItem;
[self selectItemAtIndex:indexOfSelectedItem];
}
}
}
}
}
/*!
Called when a menu item has changed.
@param aNotification information about the event
*/
- (void)menuDidChangeItem:(CPNotification)aNotification
{
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
if ([self pullsDown] && index != 0)
return;
if (![self pullsDown] && index != _selectedIndex)
return;
[self synchronizeTitleAndSelectedItem];
}
/*!
Called when an item was removed from the menu.
@param aNotification information about the event
*/
- (void)menuDidRemoveItem:(CPNotification)aNotification
{
var numberOfItems = [self numberOfItems];
if (numberOfItems <= _selectedIndex && numberOfItems > 0)
[self selectItemAtIndex:numberOfItems - 1];
else
[self synchronizeTitleAndSelectedItem];
// [super observeValueForKeyPath:aKeyPath ofObject:anObject change:changes context:aContext];
}
- (void)mouseDown:(CPEvent)anEvent
@@ -735,6 +731,22 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self sendAction:[self action] to:[self target]];
}
- (void)_firstItemDidChange
{
[self willChangeValueForKey:@"_firstItem"];
[self didChangeValueForKey:@"_firstItem"];
[[self _firstItem] setHidden:YES];
}
- (CPMenuItem)_firstItem
{
if ([self numberOfItems] <= 0)
return nil;
return [[self menu] itemAtIndex:0];
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
@@ -744,18 +756,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self setEnabled:YES];
while (count-- > 1)
{
if (value !== [objects[count] valueForKeyPath:aKeyPath])
{
[[self selectedItem] setState:CPOffState];
}
}
}
@end
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey",
var CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey",
CPPopUpButtonPullsDownKey = @"CPPopUpButtonPullsDownKey";
@implementation CPPopUpButton (CPCoding)
@@ -773,10 +780,17 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
if (self)
{
// Nothing is currently selected
_selectedIndex = -1;
_selectedIndex = CPNotFound;
[self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]];
[self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]];
var options = CPKeyValueObservingOptionNew |
CPKeyValueObservingOptionOld;/* |
CPKeyValueObservingOptionInitial;
*/
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
}
return self;
@@ -791,7 +805,6 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey];
[aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey];
}
+2 -2
View File
@@ -358,8 +358,8 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
if (self)
{
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
_menu = [aCoder decodeObjectForKey:CPResponderMenuKey];
[self setNextResponder:[aCoder decodeObjectForKey:CPResponderNextResponderKey]];
[self setMenu:[aCoder decodeObjectForKey:CPResponderMenuKey]];
}
return self;
+4 -4
View File
@@ -65,7 +65,7 @@
- (id)initView
{
aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
_contentView = [[CPView alloc] initWithFrame:aFrame];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
@@ -240,7 +240,7 @@
return (mode == CPSliderColorPickerMode) ? YES : NO;
}
-(void)sliderChanged:(id)sender
- (void)sliderChanged:(id)sender
{
var newColor,
colorPanel = [self colorPanel],
@@ -274,7 +274,7 @@
[colorPanel setColor: newColor];
}
-(void)setColor:(CPColor)aColor
- (void)setColor:(CPColor)aColor
{
[self updateRGBSliders: aColor];
[self updateHSBSliders: aColor];
@@ -282,7 +282,7 @@
[self updateLabels];
}
-(void)updateHSBSliders:(CPColor)aColor
- (void)updateHSBSliders:(CPColor)aColor
{
var hsb = [aColor hsbComponents];
+2 -2
View File
@@ -85,7 +85,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
[self _updateItems];
[self _repositionTabs];
[aTabViewItem _setTabView:self];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
@@ -110,7 +110,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
[self _updateItems];
[self _repositionTabs];
[aTabViewItem _setTabView:nil];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
+48 -8
View File
@@ -39,7 +39,7 @@ CPTableColumnUserResizingMask = 1 << 1;
A CPTableColumn contains a dataview to display for its column of the CPTableView.
A CPTableColumn determines its own size constrains and resizing behaviour.
The default dataview is a CPTextField but you can set it to any view you'd like. See -setDataView:
The default dataview is a CPTextField but you can set it to any view you'd like. See -setDataView: for documentaion including theme states.
*/
@implementation CPTableColumn : CPObject
{
@@ -253,6 +253,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
<pre>
Set the resizing mask of the column.
By default the column can be resized automatically with the tableview and manaully by the user
@@ -260,6 +261,7 @@ CPTableColumnUserResizingMask = 1 << 1;
CPTableColumnNoResizing
CPTableColumnAutoresizingMask
CPTableColumnUserResizingMask
</pre>
*/
- (void)setResizingMask:(unsigned)aResizingMask
{
@@ -318,11 +320,19 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
<pre>
This method sets the "prototype" view which will be used to create all table cells in this column.
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
When you set a dataview and it is added to the tableview the theme state will be set to CPThemeStateTableDataView
When the dataview becomes selected the theme state will be set to CPThemeStateSelectedDataView.
If the dataview shows up in a group row of the tablview the theme state will be set to CPThemeStateGroupRow.
You should overide setThemeState: and unsetThemeState: to handle these theme state changes in your dataview.
Example:
[tableColumn setDataView:someView]; // snapshot taken
@@ -333,7 +343,37 @@ CPTableColumnUserResizingMask = 1 << 1;
[someView setSomething:x];
[tableColumn setDataView:someView];
REMEMBER: you should implement CPKeyedArchiving otherwise you might see unexpected results
REMEMBER: you should implement CPKeyedArchiving otherwise you might see unexpected results.
This is done by adding the following methods to your class:
- (id)initWithCoder(CPCoder)aCoder;
- (void)encodeWithCoder:(CPCoder)aCoder;
Example:
Say you have two instance variables in your object that need to be set up each time an object is create.
We will call these instance variables "image" and "text".
Your CPCoding methods will look like the following:
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
image = [aCoder decodeObjectForKey:"MyDataViewImage"];
text = [aCoder decodeObjectForKey:"MyDataViewText"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:image forKey:"MyDataViewImage"];
[aCoder encodeObject:text forKey:"MyDataViewText"];
}
</pre>
*/
- (void)setDataView:(CPView)aView
{
@@ -355,7 +395,7 @@ CPTableColumnUserResizingMask = 1 << 1;
Returns the CPView object used by the CPTableView to draw values for the receiver.
By default, this method just calls dataView. Subclassers can override if they need to
potentially use different cells for different rows. Subclasses should expect this method
potentially use different "cells" or dataViews for different rows. Subclasses should expect this method
to be invoked with row equal to -1 in cases where no actual row is involved but the table
view needs to get some generic cell info.
*/
@@ -392,7 +432,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Setting the Identifier
/*
/*!
Sets the receiver identifier to anIdentifier.
*/
- (void)setIdentifier:(id)anIdentifier
@@ -400,7 +440,7 @@ CPTableColumnUserResizingMask = 1 << 1;
_identifier = anIdentifier;
}
/*
/*!
Returns the object used by the data source to identify the attribute corresponding to the receiver.
*/
- (id)identifier
@@ -410,7 +450,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Controlling Editability
/*
/*!
Controls whether the user can edit cells in the receiver by double-clicking them.
*/
- (void)setEditable:(BOOL)shouldBeEditable
@@ -418,7 +458,7 @@ CPTableColumnUserResizingMask = 1 << 1;
_isEditable = shouldBeEditable;
}
/*
/*!
Returns YES if the user can edit cells associated with the receiver by double-clicking the
column in the NSTableView, NO otherwise.
*/
@@ -469,7 +509,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Setting Tool Tips
/*
/*!
Sets the tooltip string that is displayed when the cursor pauses over the
header cell of the receiver.
*/
+1 -1
View File
@@ -604,7 +604,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[headerView setFrame:frame];
if([headerView superview] != self)
if ([headerView superview] != self)
[self addSubview:headerView];
}
+30 -3
View File
@@ -147,7 +147,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
All delegate and data source methods are documented in the setDataSource: and setDelegate: methods.
If you want to display something other than just text in the table you should call setDataView: on CPColumn. More documentation in that class.
If you want to display something other than just text in the table you should call setDataView: on a CPColumn object. More documentation in that class including theme states.
*/
@implementation CPTableView : CPControl
{
@@ -378,6 +378,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Sets the receiver's data source to a given object.
The data source implements various methods for handeling the tableview's data when bindings are not used.
@@ -416,7 +417,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
- (CPArray)tableView:(CPTableView)aTableView namesOfPromisedFilesDroppedAtDestination:(CPURL)dropDestination forDraggedRowsWithIndexes:(CPIndexSet)indexSet;
NOT YET IMPLEMENTED
</pre>
@param anObject The data source for the receiver. This object must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
*/
- (void)setDataSource:(id)aDataSource
@@ -722,11 +723,13 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Returns an enumerated value for the selection highlight style.
<pre>
Valid values are:
CPTableViewSelectionHighlightStyleNone
CPTableViewSelectionHighlightStyleRegular
CPTableViewSelectionHighlightStyleSourceList
</pre>
*/
- (unsigned)selectionHighlightStyle
{
@@ -734,6 +737,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Sets the selection highlight style to an enumerated value.
This value can also affect the way the tableview draws feedback when the user is dragging.
@@ -741,6 +745,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
CPTableViewSelectionHighlightStyleNone
CPTableViewSelectionHighlightStyleRegular
CPTableViewSelectionHighlightStyleSourceList
</pre>
*/
- (void)setSelectionHighlightStyle:(unsigned)aSelectionHighlightStyle
{
@@ -778,12 +783,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Sets the highlight gradient for a row or column selection
This is specific to the
@param aDictionary a CPDictionary expects three keys to be set:
CPSourceListGradient which is a CGGradient
CPSourceListTopLineColor which is a CPColor
CPSourceListBottomLineColor which is a CPColor
</pre>
*/
- (void)setSelectionGradientColors:(CPDictionary)aDictionary
{
@@ -793,10 +800,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Returns a dictionary of containing the keys:
CPSourceListGradient
CPSourceListTopLineColor
CPSourceListBottomLineColor
</pre>
*/
- (CPDictionary)selectionGradientColors
{
@@ -1924,9 +1933,17 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
}
}
// now that we've reached the end we know there are likely rounding errors
// so we should size the last resized to fit
var delta = superviewWidth - _CGRectGetMaxX([self rectOfColumn:[self numberOfColumns] - 1]),
newSize = [item width] + delta;
[item _tryToResizeToWidth:newSize];
}
/*!
<pre>
Sets the column autoresizing style of the receiver to a given style.
@param aStyle the column autoresizing style for the receiver. Valid values are:
@@ -1934,6 +1951,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
CPTableViewUniformColumnAutoresizingStyle
CPTableViewLastColumnOnlyAutoresizingStyle
CPTableViewFirstColumnOnlyAutoresizingStyle
</pre>
*/
- (void)setColumnAutoresizingStyle:(unsigned)style
{
@@ -2002,9 +2020,13 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
if (hangingSelections > 0)
{
var previousSelectionCount = [_selectedRowIndexes count];
[_selectedRowIndexes removeIndexesInRange:CPMakeRange(_numberOfRows, hangingSelections)];
if (![_selectedRowIndexes containsIndex:[self selectedRow]])
_lastSelectedRow = CPNotFound;
// For optimal performance, only send a notification if indices were actually removed.
if (previousSelectionCount > [_selectedRowIndexes count])
[self _noteSelectionDidChange];
@@ -2233,6 +2255,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
<pre>
Sets the delegate of the receiver. The delegate can implement the following methods:
Displaying Cells
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
@@ -2298,7 +2321,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aColumn row:(int)aRow
Called when the user right clicks on the tableview. -1 is passed for the row or column if the user doesn't right click on a real row or column
Return a CPMenu that should be displayed if the user right clicks. If you do not implement this the tableview will just call super on menuForEvent
</pre>
@param aDelegate the delegate object for the tableview.
*/
@@ -2778,11 +2801,13 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Sets the feedback style for when the table is the destination of a drag operation.
Can be:
CPTableViewDraggingDestinationFeedbackStyleNone
CPTableViewDraggingDestinationFeedbackStyleRegular
CPTableViewDraggingDestinationFeedbackStyleSourceList
</pre>
*/
- (void)setDraggingDestinationFeedbackStyle:(CPTableViewDraggingDestinationFeedbackStyle)aStyle
{
@@ -2791,12 +2816,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Returns the tableview dragging destination feedback style.
Can be:
CPTableViewDraggingDestinationFeedbackStyleNone
CPTableViewDraggingDestinationFeedbackStyleRegular
CPTableViewDraggingDestinationFeedbackStyleSourceList
</pre>
*/
- (CPTableViewDraggingDestinationFeedbackStyle)draggingDestinationFeedbackStyle
{
+29 -5
View File
@@ -486,11 +486,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
#if PLATFORM(DOM)
var string = [self stringValue],
element = [self _inputElement];
element = [self _inputElement],
font = [self currentValueForThemeAttribute:@"font"];
// generate the font metric
[font _getMetrics];
element.value = string;
element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
element.style.font = [[self currentValueForThemeAttribute:@"font"] cssString];
element.style.font = [font cssString];
element.style.zIndex = 1000;
switch ([self alignment])
@@ -502,12 +506,32 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
default: element.style.textAlign = "left";
}
var contentRect = [self contentRectForBounds:[self bounds]];
var contentRect = [self contentRectForBounds:[self bounds]],
verticalAlign = [self currentValueForThemeAttribute:"vertical-alignment"];
element.style.top = _CGRectGetMinY(contentRect) + "px";
switch(verticalAlign)
{
case CPTopVerticalTextAlignment:
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px"; // for the same reason we have a -1 for the left, we also have a + 1 here
break;
case CPCenterVerticalTextAlignment:
var topPoint = (_CGRectGetMidY(contentRect) - (font._lineHeight / 2) + 1) + "px";
break;
case CPBottomVerticalTextAlignment:
var topPoint = (_CGRectGetMaxY(contentRect) - font._lineHeight) + "px";
break;
default:
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px";
break;
}
element.style.top = topPoint;
element.style.left = (_CGRectGetMinX(contentRect) - 1) + "px"; // why -1?
element.style.width = _CGRectGetWidth(contentRect) + "px";
element.style.height = _CGRectGetHeight(contentRect) + "px";
element.style.height = font._lineHeight + "px"; // private ivar for the line height of the DOM text at this particaulr size
_DOMElement.appendChild(element);
+2 -2
View File
@@ -50,8 +50,8 @@ CPToolbarDisplayModeIconOnly = 2;
*/
CPToolbarDisplayModeLabelOnly = 3;
var CPToolbarsByIdentifier = nil;
var CPToolbarConfigurationsByIdentifier = nil;
var CPToolbarsByIdentifier = nil,
CPToolbarConfigurationsByIdentifier = nil;
/*!
@ingroup appkit
+4 -4
View File
@@ -163,7 +163,7 @@ var CPViewControllerCachedCibs;
if (_view === nil && [cibOwner isKindOfClass:[CPDocument class]])
[self setView:[cibOwner valueForKey:@"view"]];
if (!_view)
if (!_view)
{
var reason = [CPString stringWithFormat:@"View for %@ could not be loaded from Cib or no view specified. Override loadView to load the view manually.", self];
@@ -182,13 +182,13 @@ var CPViewControllerCachedCibs;
/*!
This method is called after the view controller has loaded its associated views into memory.
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
This method is called after the view controller has loaded its associated views into memory.
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
*/
- (void)viewDidLoad
{
}
+5 -5
View File
@@ -84,7 +84,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
{
#if DEBUG
CPLog("Unknown class \"" + _className + "\" in cib file, using CPView instead.");
#endif
#endif
theClass = [CPView class];
}
@@ -97,16 +97,16 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
}
var view = [[theClass alloc] initWithFrame:[self frame]];
if (view)
{
[view setBounds:[self bounds]];
// Since the object replacement logic hasn't had a chance to kick in yet, we need to do it manually:
var subviews = [self subviews],
index = 0,
count = subviews.length;
for (; index < count; ++index)
[view addSubview:subviews[index]];
@@ -116,7 +116,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
[view setHitTests:[self hitTests]];
[view setHidden:[self isHidden]];
[view setAlphaValue:[self alphaValue]];
[_superview replaceSubview:self with:view];
[view setBackgroundColor:[self backgroundColor]];
+1
View File
@@ -804,6 +804,7 @@ var themedButtonValues = nil,
// Global for reuse by CPTokenField.
themedTextFieldValues =
[
[@"vertical-alignment", CPTopVerticalTextAlignment, CPThemeStateBezeled],
[@"bezel-color", bezelColor, CPThemeStateBezeled],
[@"bezel-color", bezelFocusedColor, CPThemeStateBezeled | CPThemeStateEditing],
[@"bezel-color", bezelDisabledColor, CPThemeStateBezeled | CPThemeStateDisabled],
+8
View File
@@ -517,6 +517,14 @@ var concat = Array.prototype.concat,
objj_msgSend([self objectAtIndex:index], aSelector);
}
- (void)enumerateObjectsUsingBlock:(Function)aFunction
{
var index = 0,
count = [self count];
for (; index < count; ++index)
aFunction([self objectAtIndex:index], index);
}
// Comparing arrays
/*!
+4 -4
View File
@@ -136,15 +136,15 @@
@param anIndexSet the set of indices to array positions that will be replaced
@param objects the array of objects to place in the specified indices
*/
- (void)replaceObjectsAtIndexes:(CPIndexSet)anIndexSet withObjects:(CPArray)objects
- (void)replaceObjectsAtIndexes:(CPIndexSet)indexes withObjects:(CPArray)objects
{
var i = 0,
index = [anIndexSet firstIndex];
index = [indexes firstIndex];
while (index !== CPNotFound)
{
[self replaceObjectAtIndex:index withObject:objects[i++]];
index = [anIndexSet indexGreaterThanIndex:index];
[self replaceObjectAtIndex:index withObject:[objects objectAtIndex:i++]];
index = [indexes indexGreaterThanIndex:index];
}
}
+7 -7
View File
@@ -41,14 +41,14 @@ var concat = Array.prototype.concat,
- (id)initWithArray:(CPArray)anArray copyItems:(BOOL)shouldCopyItems
{
if (!shouldCopyItems && anArray.isa === _CPJavaScriptArray)
if (!shouldCopyItems && [anArray isKindOfClass:_CPJavaScriptArray])
return slice.call(anArray, 0);
self = [super init];
var index = 0;
if (anArray.isa === _CPJavaScriptArray)
if ([anArray isKindOfClass:_CPJavaScriptArray])
{
// If we're this far, shouldCopyItems must be YES.
var count = anArray.length;
@@ -90,7 +90,7 @@ var concat = Array.prototype.concat,
- (id)initWithObjects:(CPArray)objects count:(CPUInteger)aCount
{
if (objects.isa === _CPJavaScriptArray)
if ([objects isKindOfClass:_CPJavaScriptArray])
return slice.call(objects, 0);
var array = [],
@@ -176,7 +176,7 @@ var concat = Array.prototype.concat,
- (CPArray)arrayByAddingObject:(id)anObject
{
// concat flattens arrays, so wrap it in an *additional* array if anObject is an array itself.
if ([anObject isKindOfClass:CPArray])
if (anObject && anObject.isa && [anObject isKindOfClass:_CPJavaScriptArray])
return concat.call(self, [anObject]);
return concat.call(self, anObject);
@@ -187,7 +187,7 @@ var concat = Array.prototype.concat,
if (!anArray)
return [self copy];
return concat.call(self, anArray.isa === _CPJavaScriptArray ? anArray : [anArray _javaScriptArrayCopy]);
return concat.call(self, [anArray isKindOfClass:_CPJavaScriptArray] ? anArray : [anArray _javaScriptArrayCopy]);
}
- (CPArray)subarrayWithRange:(CPRange)aRange
@@ -251,7 +251,7 @@ var concat = Array.prototype.concat,
- (void)setArray:(CPArray)anArray
{
if (anArray.isa === _CPJavaScriptArray)
if ([anArray isKindOfClass:_CPJavaScriptArray])
splice.apply(self, [0, self.length].concat(anArray));
else
@@ -260,7 +260,7 @@ var concat = Array.prototype.concat,
- (void)addObjectsFromArray:(CPArray)anArray
{
if (anArray.isa === _CPJavaScriptArray)
if ([anArray isKindOfClass:_CPJavaScriptArray])
splice.apply(self, [self.length, 0].concat(anArray));
else
+93 -64
View File
@@ -102,7 +102,7 @@ CPDecimal format:
function CPDecimalMakeWithString(string, locale)
{
if (!string)
return CPDecimalMakeZero();
return CPDecimalMakeNaN();
// Regexp solution as found in JSON spec, with working regexp (I added groupings)
// Test here: http://www.regexplanet.com/simple/index.html
@@ -116,7 +116,7 @@ function CPDecimalMakeWithString(string, locale)
// If yes simply add '?' after integer part group, ie ([+\-]?)((?:0|[1-9]\d*)?)
var matches = string.match(/^([+\-]?)((?:0|[1-9]\d*))(?:\.(\d*))?(?:[eE]([+\-]?)(\d+))?$/);
if (!matches)
return nil;
return CPDecimalMakeNaN();
var ds = matches[1],
intpart = matches[2],
@@ -143,23 +143,23 @@ function CPDecimalMakeWithString(string, locale)
}
if (exponent > CPDecimalMaxExponent || exponent < CPDecimalMinExponent)
return nil;
return CPDecimalMakeNaN();
// Representation internally starts at most significant digit
var m = [CPArray array],
var m = [],
i = 0;
for (; i < (intpart?intpart.length:0); i++)
{
if (i >= CPDecimalMaxDigits)
break; // truncate
[m addObject:parseInt(intpart.charAt(i))];
Array.prototype.push.call(m, parseInt(intpart.charAt(i)));
}
var j = 0;
for (; j < (decpart?decpart.length:0); j++)
{
if ((i + j) >= CPDecimalMaxDigits)
break; // truncate
[m addObject:parseInt(decpart.charAt(j))];
Array.prototype.push.call(m, parseInt(decpart.charAt(j)));
}
var dcm = {_exponent:exponent, _isNegative:isNegative, _isCompact:NO, _isNaN:NO, _mantissa:m};
@@ -177,7 +177,7 @@ function CPDecimalMakeWithString(string, locale)
*/
function CPDecimalMakeWithParts(mantissa, exponent)
{
var m = [CPArray array],
var m = [],
isNegative = NO;
if (mantissa < 0 )
@@ -187,15 +187,15 @@ function CPDecimalMakeWithParts(mantissa, exponent)
}
if (mantissa == 0)
[m addObject: 0];
Array.prototype.push.call(m, 0);
if (exponent > CPDecimalMaxExponent || exponent < CPDecimalMinExponent)
return nil;
return CPDecimalMakeNaN();
// remaining digits are disposed of via truncation
while ((mantissa > 0) && ([m count] < CPDecimalMaxDigits)) // count selector here could be optimised away
while ((mantissa > 0) && (m.length < CPDecimalMaxDigits)) // count selector here could be optimised away
{
[m insertObject:parseInt(mantissa % 10) atIndex:0];
Array.prototype.unshift.call(m, parseInt(mantissa % 10));
mantissa = FLOOR(mantissa / 10);
}
@@ -239,6 +239,27 @@ function CPDecimalMakeNaN()
return d;
}
// private methods
function _CPDecimalMakeMaximum()
{
var s = @"",
i = 0;
for (; i < CPDecimalMaxDigits; i++)
s += "9";
s += "e" + CPDecimalMaxExponent;
return CPDecimalMakeWithString(s);
}
function _CPDecimalMakeMinimum()
{
var s = @"-",
i = 0;
for (; i < CPDecimalMaxDigits; i++)
s += "9";
s += "e" + CPDecimalMaxExponent;
return CPDecimalMakeWithString(s);
}
/*!
@ingroup foundation
Checks to see if a CPDecimal is zero. Can handle uncompacted strings.
@@ -270,7 +291,7 @@ function CPDecimalIsOne(dcm)
// exponent doesnt matter as long as mantissa = 0
if (!dcm._isNaN)
{
if (dcm._mantissa && ([dcm._mantissa count] == 1) && (dcm._mantissa[0] == 1))
if (dcm._mantissa && (dcm._mantissa.length == 1) && (dcm._mantissa[0] == 1))
return YES;
}
return NO;
@@ -284,12 +305,12 @@ function _CPDecimalSet(t,s)
t._isNegative = s._isNegative;
t._isCompact = s._isCompact;
t._isNaN = s._isNaN;
t._mantissa = [s._mantissa copy];
t._mantissa = Array.prototype.slice.call(s._mantissa, 0);
}
function _CPDecimalSetZero(result)
{
result._mantissa = [CPArray arrayWithObject:0];
result._mantissa = [0];
result._exponent = 0;
result._isNegative = NO;
result._isCompact = YES;
@@ -298,7 +319,7 @@ function _CPDecimalSetZero(result)
function _CPDecimalSetOne(result)
{
result._mantissa = [CPArray arrayWithObject:1];
result._mantissa = [1];
result._exponent = 0;
result._isNegative = NO;
result._isCompact = YES;
@@ -327,7 +348,7 @@ function CPDecimalCopy(dcm)
_isNegative:dcm._isNegative,
_isCompact:dcm._isCompact,
_isNaN:dcm._isNaN,
_mantissa:[dcm._mantissa copy]
_mantissa:Array.prototype.slice.call(dcm._mantissa, 0)
};
}
@@ -341,6 +362,9 @@ function CPDecimalCopy(dcm)
*/
function CPDecimalCompare(leftOperand, rightOperand)
{
if (leftOperand._isNaN && rightOperand._isNaN)
return CPOrderedSame;
if (leftOperand._isNegative != rightOperand._isNegative)
{
if (rightOperand._isNegative)
@@ -349,8 +373,8 @@ function CPDecimalCompare(leftOperand, rightOperand)
return CPOrderedAscending;
}
var s1 = leftOperand._exponent + [leftOperand._mantissa count],
s2 = rightOperand._exponent + [rightOperand._mantissa count];
var s1 = leftOperand._exponent + leftOperand._mantissa.length,
s2 = rightOperand._exponent + rightOperand._mantissa.length;
// Sign is the same, quick check size (length + exp)
if (s1 < s2)
@@ -369,7 +393,7 @@ function CPDecimalCompare(leftOperand, rightOperand)
}
// Same size, so check mantissa
var l = MIN([leftOperand._mantissa count], [rightOperand._mantissa count]),
var l = MIN(leftOperand._mantissa.length, rightOperand._mantissa.length),
i = 0;
for (; i < l; i++)
@@ -393,14 +417,14 @@ function CPDecimalCompare(leftOperand, rightOperand)
}
// Same digits, check length
if ([leftOperand._mantissa count] > [rightOperand._mantissa count])
if (leftOperand._mantissa.length > rightOperand._mantissa.length)
{
if (rightOperand._isNegative)
return CPOrderedAscending;
else
return CPOrderedDescending;
}
if ([leftOperand._mantissa count] < [rightOperand._mantissa count])
if (leftOperand._mantissa.length < rightOperand._mantissa.length)
{
if (rightOperand._isNegative)
return CPOrderedDescending;
@@ -420,8 +444,8 @@ function _SimpleAdd(result, leftOperand, rightOperand, roundingMode, longMode)
_CPDecimalSet(result, leftOperand);
var j = [leftOperand._mantissa count] - [rightOperand._mantissa count],
l = [rightOperand._mantissa count],
var j = leftOperand._mantissa.length - rightOperand._mantissa.length,
l = rightOperand._mantissa.length,
i = l - 1,
carry = 0,
error = CPCalculationNoError;
@@ -443,7 +467,7 @@ function _SimpleAdd(result, leftOperand, rightOperand, roundingMode, longMode)
if (carry)
{
for (i = j-1; i >= 0; i--)
for (i = j - 1; i >= 0; i--)
{
if (result._mantissa[i] != 9)
{
@@ -456,13 +480,13 @@ function _SimpleAdd(result, leftOperand, rightOperand, roundingMode, longMode)
if (carry)
{
[result._mantissa insertObject:1 atIndex:0];
Array.prototype.splice.call(result._mantissa, 0, 0, 1);
// The number must be shifted to the right
if ((CPDecimalMaxDigits * factor) == [leftOperand._mantissa count])
if ((CPDecimalMaxDigits * factor) == leftOperand._mantissa.length)
{
var scale = - result._exponent - 1;
CPDecimalRound(result, result,scale,roundingMode);
CPDecimalRound(result, result, scale, roundingMode);
}
if (CPDecimalMaxExponent < result._exponent)
@@ -526,8 +550,8 @@ function CPDecimalAdd(result, leftOperand, rightOperand, roundingMode, longMode)
// below is equiv of simple compare
var comp = 0,
ll = [n1._mantissa count],
lr = [n2._mantissa count];
ll = n1._mantissa.length,
lr = n2._mantissa.length;
if (ll == lr)
comp = CPOrderedSame;
else if (ll > lr)
@@ -581,8 +605,8 @@ function _SimpleSubtract(result, leftOperand, rightOperand, roundingMode)
{
var error = CPCalculationNoError,
borrow = 0,
l = [rightOperand._mantissa count],
j = [leftOperand._mantissa count] - l,
l = rightOperand._mantissa.length,
j = leftOperand._mantissa.length - l,
i = l - 1;
_CPDecimalSet(result, leftOperand);
@@ -604,7 +628,7 @@ function _SimpleSubtract(result, leftOperand, rightOperand, roundingMode)
if (borrow)
{
for (i = j-1; i >= 0; i--)
for (i = j - 1; i >= 0; i--)
{
if (result._mantissa[i] != 0)
{
@@ -735,10 +759,10 @@ function _SimpleDivide(result, leftOperand, rightOperand, roundingMode)
_CPDecimalSetZero(result);
n1._mantissa = [CPArray array];
n1._mantissa = [];
while ((k < [leftOperand._mantissa count]) || ([n1._mantissa count]
&& !(([n1._mantissa count] == 1) && (n1._mantissa[0] == 0))))
while ((k < leftOperand._mantissa.length) || (n1._mantissa.length
&& !((n1._mantissa.length == 1) && (n1._mantissa[0] == 0))))
{
while (CPOrderedAscending == CPDecimalCompare(n1, rightOperand))
{
@@ -747,19 +771,19 @@ function _SimpleDivide(result, leftOperand, rightOperand, roundingMode)
if (n1._exponent)
{
// Put back zeros removed by compacting
[n1._mantissa addObject:0];
Array.prototype.push.call(n1._mantissa, 0);
n1._exponent--;
n1._isCompact = NO;
}
else
{
if (used < [leftOperand._mantissa count])
if (used < leftOperand._mantissa.length)
{
// Fill up with own digits
if ([n1._mantissa count] || leftOperand._mantissa[used])
if (n1._mantissa.length || leftOperand._mantissa[used])
{
// only add 0 if there is already something
[n1._mantissa addObject:(leftOperand._mantissa[used])];
Array.prototype.push.call(n1._mantissa, (leftOperand._mantissa[used]));
n1._isCompact = NO;
}
used++;
@@ -773,7 +797,7 @@ function _SimpleDivide(result, leftOperand, rightOperand, roundingMode)
break;
}
// Borrow one digit
[n1._mantissa addObject:0];
Array.prototype.push.call(n1._mantissa, 0);
result._exponent--;
}
@@ -898,11 +922,11 @@ function _SimpleMultiply(result, leftOperand, rightOperand, roundingMode, powerM
// Do every digit of the second number
var i = 0;
for (; i < [rightOperand._mantissa count]; i++)
for (; i < rightOperand._mantissa.length; i++)
{
_CPDecimalSetZero(n);
n._exponent = [rightOperand._mantissa count] - i - 1;
n._exponent = rightOperand._mantissa.length - i - 1;
carry = 0;
d = rightOperand._mantissa[i];
@@ -910,7 +934,7 @@ function _SimpleMultiply(result, leftOperand, rightOperand, roundingMode, powerM
continue;
var j = 0;
for (j = [leftOperand._mantissa count]-1; j >= 0; j--)
for (j = leftOperand._mantissa.length - 1; j >= 0; j--)
{
e = leftOperand._mantissa[j] * d + carry;
if (e >= 10)
@@ -943,11 +967,11 @@ function _SimpleMultiply(result, leftOperand, rightOperand, roundingMode, powerM
result._exponent += exp;
// perform round to CPDecimalMaxDigits
if ([result._mantissa count] > CPDecimalMaxDigits && !powerMode)
if (result._mantissa.length > CPDecimalMaxDigits && !powerMode)
{
result._isCompact = NO;
var scale = CPDecimalMaxDigits - ([result._mantissa count] + result._exponent);
CPDecimalRound(result, result, scale ,roundingMode); // calls compact
var scale = CPDecimalMaxDigits - (result._mantissa.length + result._exponent);
CPDecimalRound(result, result, scale, roundingMode); // calls compact
error = CPCalculationLossOfPrecision;
}
@@ -1003,8 +1027,8 @@ function CPDecimalMultiply(result, leftOperand, rightOperand, roundingMode, powe
// below is equiv of simple compare
var comp = 0,
ll = [n1._mantissa count],
lr = [n2._mantissa count];
ll = n1._mantissa.length,
lr = n2._mantissa.length;
if (ll == lr)
comp = CPOrderedSame;
else if (ll > lr)
@@ -1159,8 +1183,8 @@ function CPDecimalNormalize(dcm1, dcm2, roundingMode, longMode)
e2 = dcm2._exponent;
// Add zeros
var l2 = [dcm2._mantissa count],
l1 = [dcm1._mantissa count],
var l2 = dcm2._mantissa.length,
l1 = dcm1._mantissa.length,
l = 0;
var e = 0;
@@ -1178,16 +1202,16 @@ function CPDecimalNormalize(dcm1, dcm2, roundingMode, longMode)
e = e1 - e2;
if (e2 > e1)
l = MIN((CPDecimalMaxDigits*factor) - l2, e); //(e2 - e1));
l = MIN((CPDecimalMaxDigits * factor) - l2, e); //(e2 - e1));
else
l = MIN((CPDecimalMaxDigits*factor) - l1, e); //(e1 - e2));
l = MIN((CPDecimalMaxDigits * factor) - l1, e); //(e1 - e2));
for (var i = 0; i < l; i++)
{
if (e2 > e1)
[dcm2._mantissa addObject:0]; //dcm2._mantissa[i + l2] = 0;
Array.prototype.push.call(dcm2._mantissa, 0); //dcm2._mantissa[i + l2] = 0;
else
[dcm1._mantissa addObject:0];
Array.prototype.push.call(dcm1._mantissa, 0);
}
if (e2 > e1)
{
@@ -1222,7 +1246,7 @@ function CPDecimalNormalize(dcm1, dcm2, roundingMode, longMode)
// Some zeros where cut of again by compacting
if (e2 > e1)
{
l1 = [dcm1._mantissa count];
l1 = dcm1._mantissa.length;
l = MIN((CPDecimalMaxDigits * factor) - l1, ABS(dcm1._exponent - dcm2._exponent));
for (var i = 0; i < l; i++)
{
@@ -1233,7 +1257,7 @@ function CPDecimalNormalize(dcm1, dcm2, roundingMode, longMode)
}
else
{
l2 = [dcm2._mantissa count];
l2 = dcm2._mantissa.length;
l = MIN((CPDecimalMaxDigits * factor) - l2, ABS(dcm2._exponent - dcm1._exponent));
for (var i = 0; i < l; i++)
{
@@ -1277,7 +1301,7 @@ function CPDecimalRound(result, dcm, scale ,roundingMode)
_CPDecimalSet(result,dcm);
var mc = [result._mantissa count],
var mc = result._mantissa.length,
l = mc + scale + result._exponent;
if (mc <= l)
@@ -1326,7 +1350,7 @@ function CPDecimalRound(result, dcm, scale ,roundingMode)
break;
}
// cut mantissa
result._mantissa = [result._mantissa subarrayWithRange:CPMakeRange(0, l)];
result._mantissa = Array.prototype.slice.call(result._mantissa, 0, l);
if (up)
{
@@ -1349,7 +1373,7 @@ function CPDecimalRound(result, dcm, scale ,roundingMode)
// Overflow in rounding.
// Add one zero add the end. There must be space as
// we just cut off some digits.
[result._mantissa addObject:0];
Array.prototype.push.call(result._mantissa, 0);
}
else
result._exponent++;
@@ -1368,7 +1392,7 @@ function CPDecimalRound(result, dcm, scale ,roundingMode)
function CPDecimalCompact(dcm)
{
// if positive or zero exp leading zeros simply delete, trailing ones u need to increment exponent
if (!dcm || [dcm._mantissa count] == 0 || CPDecimalIsNotANumber(dcm) )
if (!dcm || dcm._mantissa.length == 0 || CPDecimalIsNotANumber(dcm) )
return;
@@ -1382,12 +1406,12 @@ function CPDecimalCompact(dcm)
// if exp is zero does it make sense to have them? dont think so so delete them
while (dcm._mantissa[0] === 0)
{
[dcm._mantissa removeObjectAtIndex:0];
Array.prototype.shift.call(dcm._mantissa);
}
// trailing zeros, strip them
while ([dcm._mantissa lastObject] === 0)
while (dcm._mantissa[dcm._mantissa.length - 1] === 0)
{
[dcm._mantissa removeLastObject];
Array.prototype.pop.call(dcm._mantissa);
dcm._exponent++;
if (dcm._exponent + 1 > CPDecimalMaxExponent)
{
@@ -1411,13 +1435,18 @@ function CPDecimalString(dcm, locale)
{
// Cocoa seems to just add all the zeros... this maybe controlled by locale,
// will check.
if (dcm._isNaN)
return @"NaN";
var string = @"",
i = 0;
if (dcm._isNegative)
string += "-";
var k = [dcm._mantissa count],
var k = dcm._mantissa.length,
l = ((dcm._exponent < 0) ? dcm._exponent : 0) + k;
if (l < 0)
{
// add leading zeros
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -476,7 +476,7 @@ var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
// We wrap primitive JavaScript objects in a unique subclass of CPValue.
// This way, when we unarchive, we know to unwrap it, since
// _CPKeyedArchiverValue should not be used anywhere else.
if (anObject !== nil && !anObject.isa)
if (anObject !== nil && anObject !== undefined && !anObject.isa)
anObject = [_CPKeyedArchiverValue valueWithJSObject:anObject];
// Get the proper replacement object
@@ -1,3 +1,26 @@
/*
* CPComparisonPredicate.j
*
* Portions based on NSComparisonPredicate.m in Cocotron (http://www.cocotron.org/)
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPArray.j"
@import "CPNull.j"
@@ -1,3 +1,26 @@
/*
* CPCompoundPredicate.j
*
* Portions based on NSCompoundPredicate.m in Cocotron (http://www.cocotron.org/)
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPPredicate.j"
+34 -16
View File
@@ -1,3 +1,23 @@
/*
* CPExpression.j
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPString.j"
@import "CPArray.j"
@@ -113,7 +133,6 @@ CPMinusSetExpressionType = 9;
return [[CPExpression_keypath alloc] initWithKeyPath:keyPath];
}
//Creating a Collection Expression
/*!
Returns a new aggregate expression for a given collection.
@param collection A collection object (an instance of CPArray, CPSet, or CPDictionary) that contains further expressions.
@@ -126,7 +145,7 @@ CPMinusSetExpressionType = 9;
/*!
Returns a new CPExpression object that represent the union of a given set and collection.
@param left An expression that evaluates to an CPSet object.
@param left An expression that evaluates to a CPSet object.
@param right An expression that evaluates to a collection object (an instance of CPArray, CPSet, or CPDictionary).
@return A new CPExpression object that represents the union of left and right.
*/
@@ -137,7 +156,7 @@ CPMinusSetExpressionType = 9;
/*!
Returns a new CPExpression object that represent the intersection of a given set and collection.
@param left An expression that evaluates to an CPSet object.
@param left An expression that evaluates to a CPSet object.
@param right An expression that evaluates to a collection object (an instance of CPArray, CPSet, or CPDictionary).
@return A new CPExpression object that represents the intersection of left and right.
*/
@@ -148,7 +167,7 @@ CPMinusSetExpressionType = 9;
/*!
Returns a new CPExpression object that represent the subtraction of a given collection from a given set.
@param left An expression that evaluates to an CPSet object.
@param left An expression that evaluates to a CPSet object.
@param left An expression that evaluates to a collection object (an instance of CPArray, CPSet, or CPDictionary).
@return A new CPExpression object that represents the subtraction of right from left.
*/
@@ -196,16 +215,8 @@ CPMinusSetExpressionType = 9;
trunc: one CPExpression instance representing a number CPNumber
uppercase: one CPExpression instance representing a string CPString
lowercase: one CPExpression instance representing a string CPString
random none CPNumber (integer)
random: one CPExpression instance representing a number CPNumber (integer) such that 0 <= rand < param
now none [CPDate now]
bitwiseAnd:with: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger)
bitwiseOr:with: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger)
bitwiseXor:with: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger)
leftshift:by: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger)
rightshift:by: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger)
onesComplement: one CPExpression instance representing a numbers CPNumber (numbers will be treated as CPInteger)
@endverbatim
now: none [CPDate now]
This method raises an exception immediately if the selector is invalid; it raises an exception at runtime if the parameters are incorrect.
*/
@@ -217,16 +228,23 @@ CPMinusSetExpressionType = 9;
/*!
Returns an expression which will return the result of invoking on a given target a selector with a given name using given arguments.
@param target A CPExpression object which will evaluate an object on which the selector identified by name may be invoked.
@param function_name The name of the method to be invoked.
@param selectorName The name of the method to be invoked.
@param parameters An array containing CPExpression objects which can be evaluated to provide parameters for the method specified by name.
@return An expression which will return the result of invoking the selector named name on the result of evaluating the target expression with the parameters specified by evaluating the elements of parameters.
See the description of expressionForFunction:arguments: for examples of how to construct the parameter array.
*/
+ (CPExpression)expressionForFunction:(CPExpression)target selectorName:(CPString)function_name arguments:(CPArray)parameters
+ (CPExpression)expressionForFunction:(CPExpression)target selectorName:(CPString)selectorName arguments:(CPArray)parameters
{
return [[CPExpression_function alloc] initWithTarget:target selector:CPSelectorFromString(function_name) arguments:parameters];
return [[CPExpression_function alloc] initWithTarget:target selector:CPSelectorFromString(selectorName) arguments:parameters];
}
/*!
Returns an expression that filters a collection by storing elements in the collection in a given variable and keeping the elements for which qualifier returns true.
@param expression A CPExpression that evaluates to a collection.
@param variable Used as a local variable, and will shadow any instances of variable in the bindings dictionary. The variable is removed or the old value replaced once evaluation completes.
@param predicate The predicate used to determine whether the element belongs in the result collection.
@return An expression that filters a collection by storing elements in the collection in the variable variable and keeping the elements for which qualifier returns true.
*/
+ (CPExpression)expressionForSubquery:(CPExpression)expression usingIteratorVariable:(CPString)variable predicate:(CPPredicate)predicate
{
return [[CPExpression_subquery alloc] initWithExpression:expression usingIteratorVariable:variable predicate:predicate];
@@ -1,3 +1,23 @@
/*
* CPExpression_aggregate.j
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPExpression.j"
@import "CPArray.j"
@@ -1,3 +1,26 @@
/*
* CPExpression_constant.j
*
* Portions based on NSExpression_constant.m in Cocotron (http://www.cocotron.org/)
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPExpression.j"
@import "CPDictionary.j"
+22 -1
View File
@@ -1,8 +1,29 @@
/*
* CPExpression_function.j
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPExpression.j"
@import "CPString.j"
@import "CPArray.j"
@import "CPDictionary.j"
@import "CPDate.j"
@implementation CPExpression_function : CPExpression
{
@@ -247,7 +268,7 @@ var CPSelectorNameKey = @"CPSelectorName",
return ABS(num);
}
+ (CPDate)now
+ (CPDate)now:(id)_
{
return [CPDate date];
}
@@ -1,3 +1,26 @@
/*
* CPExpression_keypath.j
*
* Portions based on NSExpression_keypath.m in Cocotron (http://www.cocotron.org/)
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPExpression.j"
@import "CPExpression_function.j"
@@ -1,3 +1,23 @@
/*
* CPExpression_self.j
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPExpression.j"
@import "CPString.j"
+20
View File
@@ -1,3 +1,23 @@
/*
* CPExpression_set.j
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPExpression.j"
@@ -1,3 +1,23 @@
/*
* CPExpression_subquery.j
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPExpression.j"
@@ -1,3 +1,26 @@
/*
* CPExpression_variable.j
*
* Portions based on NSExpression_variable.m in Cocotron (http://www.cocotron.org/)
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPExpression.j"
@import "CPString.j"
+41 -4
View File
@@ -1,6 +1,29 @@
/*
* CPPredicate.j
*
* CPPredicate parsing based on NSPredicate.m in GNUStep Base Library (http://www.gnustep.org/)
* Copyright (c) 2005 Free Software Foundation.
*
* Created by cacaodev.
* Copyright 2010.
*
* 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 "CPValue.j"
@import "CPArray.j"
@import "CPDictionary.j"
@import "CPSet.j"
@import "CPNull.j"
@import "CPScanner.j"
@@ -776,15 +799,28 @@ function(newValue)\
if (![self scanString:@"]" intoString:NULL])
CPRaiseParseError(self, @"expression");
}
else if ([self scanString:@":(" intoString:NULL])
else if ([self scanString:@":" intoString:NULL])
{
// function - this parser allows for (max)(a, b, c) to be properly
// recognized and even (%K)(a, b, c) if %K evaluates to "max"
var args = [];
if (![left keyPath])
CPRaiseParseError(self, @"expression");
var selector = [left keyPath] + @":",
args = [];
if (![self scanString:@"(" intoString:NULL])
{
var str;
[self scanCharactersFromSet:[CPCharacterSet lowercaseLetterCharacterSet] intoString:REFERENCE(str)];
if (![self scanString:@":(" intoString:NULL])
CPRaiseParseError(self, @"expression");
selector += str + @":";
}
if (![self scanString:@")" intoString:NULL])
{
[args addObject:[self parseExpression]];
@@ -794,7 +830,8 @@ function(newValue)\
if (![self scanString:@")" intoString:NULL])
CPRaiseParseError(self, @"expression");
}
left = [CPExpression expressionForFunction:([left keyPath] + ":") arguments:args];
left = [CPExpression expressionForFunction:selector arguments:args];
}
else if ([self scanString:@"UNION" intoString:NULL])
{
+21 -6
View File
@@ -1,9 +1,24 @@
// CPScanner.j
// © Emanuele Vulcano, 2008.
//
// Licensed under the terms of Cappuccino's license
// (the GNU Lesser General Public License, version 2.1).
// Please see Cappuccino's LICENSE file for details.
/*
* CPScanner.j
* Foundation
*
* Created by Emanuele Vulcano.
* Copyright 2008, Emanuele Vulcano.
*
* 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 <Foundation/CPCharacterSet.j>
+4 -4
View File
@@ -138,7 +138,7 @@ var CPStringRegexSpecialCharacters = [
*/
- (id)initWithString:(CPString)aString
{
if ([self class] === CPString)
if ([self class] === CPString)
return String(aString);
var result = new String(aString);
@@ -807,10 +807,10 @@ var CPStringRegexSpecialCharacters = [
@end
var diacritics = [[192,198],[224,230],[231,231],[232,235],[236,239],[242,246],[249,252]]; // Basic Latin ; Latin-1 Supplement.
var normalized = [65,97,99,101,105,111,117];
var diacritics = [[192,198],[224,230],[231,231],[232,235],[236,239],[242,246],[249,252]], // Basic Latin ; Latin-1 Supplement.
normalized = [65,97,99,101,105,111,117];
String.prototype.stripDiacritics = function ()
String.prototype.stripDiacritics = function()
{
var output = "";
for (var indexSource = 0; indexSource < this.length; indexSource++)
+104
View File
@@ -0,0 +1,104 @@
@import <AppKit/AppKit.j>
@implementation CPBrowserTest : OJTestCase
{
CPBrowser browser;
CPBrowserDelegate delegate;
}
- (void)setUp
{
browser = [[CPBrowser alloc] initWithFrame:CGRectMake(0, 0, 500, 300)];
delegate = [CPBrowserDelegate new];
[delegate setEntries:[".1", ".1.1", ".1.2", ".1.2.1", ".1.2.2", ".2", ".3", ".3.1"]];
[browser setDelegate:delegate];
}
/*!
Verify that the items are loaded into rows in their proper columns.
*/
- (void)testRows
{
[self assert:".1" equals:[browser itemAtRow:0 inColumn:0]];
[self assert:".2" equals:[browser itemAtRow:1 inColumn:0]];
[self assert:".3" equals:[browser itemAtRow:2 inColumn:0]];
// Only one column so far.
[self assert:nil equals:[browser itemAtRow:0 inColumn:1]];
// Drill down.
[browser selectRowIndexes:[CPIndexSet indexSetWithIndex:0] inColumn:0];
[browser addColumn];
[self assert:".1.1" equals:[browser itemAtRow:0 inColumn:1]];
[self assert:".1.2" equals:[browser itemAtRow:1 inColumn:1]];
}
- (void)testCoding
{
// This should preferably not crash.
var decoded = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:browser]];
// This basic test will serve to verify that the decoded object is not broken.
browser = decoded;
[self testRows];
}
@end
@implementation CPBrowserDelegate : CPObject
{
CPArray entries @accessors;
}
- (CPArray)childrenOfPrefix:(CPString)theItem
{
if (!theItem)
theItem = "";
var matcher = new RegExp("^" + theItem + "\\.\\d$"),
children = [];
for (var i = 0; i < entries.length; i++)
if (matcher.exec(entries[i]))
children.push(entries[i]);
return children;
}
- (id)browser:(id)aBrowser numberOfChildrenOfItem:(id)theItem
{
return [[self childrenOfPrefix:theItem] count];
}
- (id)browser:(id)aBrowser child:(int)theIndex ofItem:(id)theItem
{
return [self childrenOfPrefix:theItem][theIndex];
}
- (id)browser:(id)aBrowser objectValueForItem:(id)theItem
{
return theItem;
}
- (id)browser:(id)aBrowser isLeafItem:(id)theItem
{
return ![[self childrenOfPrefix:theItem] count];
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
entries = [aCoder decodeObjectForKey:"entries"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:entries forKey:"entries"];
}
@end
+109 -6
View File
@@ -93,13 +93,19 @@
[outlineView selectRowIndexes:preSelection byExtendingSelection:NO];
// Test that by the time the selection notification is sent out, rows have
// updated so that the selection matches the right items in the outline view.
var delegate = [TestNotificationsDelegate new];
[delegate setTester:self];
[delegate setExpectedSelectedItems:[".3", ]];
[outlineView setDelegate:delegate];
[outlineView collapseItem:".1"];
afterSelection = [outlineView selectedRowIndexes];
[self assert:1 equals:[afterSelection count] message:"1 selection should disappear"];
[self assert:".3" equals:[outlineView itemAtRow:[afterSelection firstIndex]] message:".3 selection should remain"];
[self assert:1 equals:[delegate selectionChangeCount] message:"selection notifications during collapseItem"];
}
/*!
@@ -112,17 +118,61 @@
var preSelection = [CPIndexSet indexSet];
[preSelection addIndex:[outlineView rowForItem:".1.1"]];
[preSelection addIndex:[outlineView rowForItem:".2"]];
[preSelection addIndex:[outlineView rowForItem:".3.1"]];
[outlineView selectRowIndexes:preSelection byExtendingSelection:NO];
[outlineView expandItem:".1.2"];
afterSelection = [outlineView selectedRowIndexes];
// Test that by the time the selection notification is sent out, rows have
// been expanded. E.g. the outline view is made consistent before notifying.
var delegate = [TestNotificationsDelegate new];
[delegate setTester:self];
[outlineView setDelegate:delegate];
[outlineView expandItem:".1.2"];
afterSelection = [outlineView selectedRowIndexes];
[self assert:2 equals:[afterSelection count] message:"selections should remain"];
[self assert:".1.1" equals:[outlineView itemAtRow:[afterSelection firstIndex]] message:".1.1 selection should remain"];
[self assert:".2" equals:[outlineView itemAtRow:[afterSelection lastIndex]] message:".2 selection should remain"];
[self assert:".3.1" equals:[outlineView itemAtRow:[afterSelection lastIndex]] message:".3.1 selection should remain"];
[self assert:1 equals:[delegate selectionChangeCount] message:"selection notifications during expandItem"];
}
/*!
Test selection updates when an expanded node has pre-expanded children.
*/
- (void)testExpandWithSelectionBelowAndExpandedChildren
{
// [".1", ".1.1", ".1.2", ".1.2.1", ".1.2.2", ".2", ".3", ".3.1"]
[outlineView collapseItem:".1"];
var preSelection = [CPIndexSet indexSet];
[preSelection addIndex:[outlineView rowForItem:".2"]];
[preSelection addIndex:[outlineView rowForItem:".3.1"]];
[outlineView selectRowIndexes:preSelection byExtendingSelection:NO];
var delegate = [TestNotificationsDelegate new];
[delegate setTester:self];
[delegate setExpectedSelectedItems:[".2", ".3.1"]];
[outlineView setDelegate:delegate];
[outlineView expandItem:".1"];
// The delegate will check the selection update but not the count.
[self assert:2 equals:[[outlineView selectedRowIndexes] count] message:"selections should remain"];
}
/*!
Test that the outline view archives properly.
*/
- (void)testCoding
{
var decoded = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:outlineView]];
outlineView = decoded;
// Expansion state does not archive.
[outlineView expandItem:nil expandChildren:YES];
// While not exhaustive, if this test works nothing is majorly broken with the unarchived outline view.
[self testCollapse];
}
@end
@@ -166,4 +216,57 @@
return theItem;
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
entries = [aCoder decodeObjectForKey:"entries"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:entries forKey:"entries"];
}
@end
@implementation TestNotificationsDelegate : CPObject
{
id tester @accessors;
CPArray expectedSelectedItems @accessors;
int selectionChangeCount @accessors;
}
- (id)init
{
if (self = [super init])
selectionChangeCount = 0;
return self;
}
- (void)outlineViewSelectionDidChange:(CPNotification)aNotification
{
selectionChangeCount++;
// Verify that the state is consistent - every selected row has been loaded.
var anOutlineView = [aNotification object],
selection = [anOutlineView selectedRowIndexes],
rows = [];
[selection getIndexes:rows maxCount:-1 inIndexRange:nil];
for (var i = 0, count = [rows count]; i < count; i++)
{
var item = [anOutlineView itemAtRow:rows[i]];
[tester assertTrue: item !== nil message:"selected row #" + i + " should exist"];
if (expectedSelectedItems)
[tester assert:expectedSelectedItems[i] equals:item message:"in notification selected row #" + i];
}
}
@end
+71
View File
@@ -12,6 +12,77 @@
button = [CPPopUpButton new];
}
- (void)testMenuSynchronization
{
var popUpButton = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 28.0) pullsDown:NO];
[self assert:CPNotFound equals:[popUpButton indexOfSelectedItem]];
[popUpButton addItemWithTitle:@"one"];
[self assert:0 equals:[popUpButton indexOfSelectedItem]];
[popUpButton addItemWithTitle:@"two"];
[popUpButton addItemWithTitle:@"three"];
[popUpButton addItemWithTitle:@"four"];
[popUpButton addItemWithTitle:@"five"];
[popUpButton addItemWithTitle:@"six"];
[self assert:0 equals:[popUpButton indexOfSelectedItem]];
[popUpButton insertItemWithTitle:@"negative one" atIndex:0];
[self assert:1 equals:[popUpButton indexOfSelectedItem]];
var items = [
[[CPMenuItem alloc] initWithTitle:@"negative five" action:nil keyEquivalent:@""],
[[CPMenuItem alloc] initWithTitle:@"negative four" action:nil keyEquivalent:@""],
[[CPMenuItem alloc] initWithTitle:@"negative three" action:nil keyEquivalent:@""],
[[CPMenuItem alloc] initWithTitle:@"negative two" action:nil keyEquivalent:@""]
],
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, 4)],
mutableItemsArray = [[popUpButton menu] mutableArrayValueForKey:@"items"];
[mutableItemsArray insertObjects:items atIndexes:indexes];
[self assert:5 equals:[popUpButton indexOfSelectedItem]];
[[popUpButton menu] removeItemAtIndex:5];
[self assert:4 equals:[popUpButton indexOfSelectedItem]];
[[popUpButton menu] removeItemAtIndex:0];
[self assert:3 equals:[popUpButton indexOfSelectedItem]];
[popUpButton selectItemAtIndex:1];
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(1, 3)];
[mutableItemsArray removeObjectsAtIndexes:indexes];
[self assert:0 equals:[popUpButton indexOfSelectedItem]];
var pullDownButton = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 28.0) pullsDown:YES];
[pullDownButton addItemWithTitle:@"First Item"];
[self assert:YES equals:[[pullDownButton itemAtIndex:0] isHidden]];
[pullDownButton addItemWithTitle:@"Second Item"];
[self assert:YES equals:[[pullDownButton itemAtIndex:0] isHidden]];
[self assert:NO equals:[[pullDownButton itemAtIndex:1] isHidden]];
[pullDownButton removeItemAtIndex:0];
[self assert:YES equals:[[pullDownButton itemAtIndex:0] isHidden]];
[pullDownButton insertItemWithTitle:@"A Title" atIndex:0];
[self assert:YES equals:[[pullDownButton itemAtIndex:0] isHidden]];
[self assert:NO equals:[[pullDownButton itemAtIndex:1] isHidden]];
}
- (void)testItemTitles
{
[self assert:[] equals:[button itemTitles]];
+34 -4
View File
@@ -19,8 +19,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPString.j>
@import <Foundation/CPDecimalNumber.j>
@import <Foundation/CPKeyedArchiver.j>
@import <Foundation/CPKeyedUnarchiver.j>
@import <Foundation/CPString.j>
@implementation CPDecimalNumberHandlerTest : OJTestCase
@@ -46,7 +48,7 @@
- (void)testdefaultDecimalNumberHandler
{
[self assert:_cappdefaultDcmHandler equals:[CPDecimalNumberHandler defaultDecimalNumberHandler] message:"T1 defaultDecimalNumberHandler returned different handler than the current default"];
[self assertTrue:[CPDecimalNumberHandler defaultDecimalNumberHandler] message:"T1 defaultDecimalNumberHandler returned nothing"];
}
- (void)testroundingMode
@@ -72,8 +74,8 @@
var h1 = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundDown scale:0 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
[self assertTrue:h1 message:"T1 exceptionDuringOperation: no alloc"];
var a = [CPDecimalNumber decimalNumberWithString:@"100"];
var b = [CPDecimalNumber decimalNumberWithString:@"100"];
var a = [CPDecimalNumber decimalNumberWithString:@"100"],
b = [CPDecimalNumber decimalNumberWithString:@"100"];
// no throw first
try {
@@ -146,4 +148,32 @@
}
}
- (void)testEncoding
{
var handler = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundDown scale:3 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:YES raiseOnDivideByZero:NO],
encoded = [CPKeyedArchiver archivedDataWithRootObject:handler],
decoded = [CPKeyedUnarchiver unarchiveObjectWithData:encoded];
[self assert:[handler roundingMode] equals:[decoded roundingMode]];
[self assert:[handler scale] equals:[decoded scale]];
try {
[decoded exceptionDuringOperation:nil error:CPCalculationDivideByZero leftOperand:CPDecimalMakeZero() rightOperand:CPDecimalMakeZero()];
}
catch (e)
{
[self fail:"Should not have thrown a divide by zero exception"];
}
try {
[decoded exceptionDuringOperation:nil error:CPCalculationUnderflow leftOperand:CPDecimalMakeZero() rightOperand:CPDecimalMakeZero()];
[self fail:"Should have thrown an underflow exception"];
}
catch (e)
{
if ((e.isa) && [e name] == AssertionFailedError)
throw e;
}
}
@end
+36 -59
View File
@@ -93,7 +93,7 @@
[self assert:NO equals:dcm._isNegative message:"decimalNumberWithMantissa:exponent:isNegative: - sign"];
// Def behavior
[self assert:[CPDecimalNumber defaultBehavior] equals:_cappdefaultDcmHandler message:"defaultBehavior: - returned different object"];
[self assertTrue:[CPDecimalNumber defaultBehavior] message:"defaultBehavior: - returned nothing"];
[CPDecimalNumber setDefaultBehavior:_dcmnhWithExactness];
[self assertTrue:[CPDecimalNumber defaultBehavior]._raiseOnExactness message:"setDefaultBehavior: - new behavior not set"];
@@ -108,7 +108,7 @@
dcmn = [CPDecimalNumber minimumDecimalNumber];
dcm = [dcmn decimalValue];
[self assert:CPDecimalMinExponent equals:dcm._exponent message:"minimumDecimalNumber: - exponent"];
[self assert:CPDecimalMaxExponent equals:dcm._exponent message:"minimumDecimalNumber: - exponent"];
[self assert:[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9] equals:dcm._mantissa message:"minimumDecimalNumber: - mantissa"];
[self assert:YES equals:dcm._isNegative message:"minimumDecimalNumber: - sign"];
@@ -139,63 +139,26 @@
dcm = [dcmn boolValue];
[self assert:true equals:dcm message:"boolValue: - should be true"];
// exceptions
try {
dcmn = [[CPDecimalNumber alloc] initWithString:@"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"];
[self fail:"initWithString: TEX1: overflow from string"];
} catch (e)
{
if ((e.isa) && [e name] == AssertionFailedError)
throw e;
}
try {
dcmn = [[CPDecimalNumber alloc] initWithString:@"foo"];
[self fail:"initWithString: TEX2: invalid string"];
} catch (e)
{
if ((e.isa) && [e name] == AssertionFailedError)
throw e;
}
try {
dcmn = [[CPDecimalNumber alloc] initWithString:@".123"];
[self fail:"initWithString: TEX3: invalid string"];
} catch (e)
{
if ((e.isa) && [e name] == AssertionFailedError)
throw e;
}
try {
dcmn = [[CPDecimalNumber alloc] initWithString:@"-.123"];
[self fail:"initWithString: TEX4: invalid string"];
} catch (e)
{
if ((e.isa) && [e name] == AssertionFailedError)
throw e;
}
try {
dcmn = [[CPDecimalNumber alloc] initWithString:@"0123"];
[self fail:"initWithString: TEX5: invalid string"];
} catch (e)
{
if ((e.isa) && [e name] == AssertionFailedError)
throw e;
}
try {
dcmn = [[CPDecimalNumber alloc] initWithString:@"1e200"];
[self fail:"initWithString: TEX6: exponent overflow"];
} catch (e)
{
if ((e.isa) && [e name] == AssertionFailedError)
throw e;
}
try{
dcmn = [[CPDecimalNumber alloc] initWithString:@"12312e-23421"];
[self fail:"initWithString: TEX7: exponent underflow"];
} catch (e)
{
if ((e.isa) && [e name] == AssertionFailedError)
throw e;
}
dcmn = [[CPDecimalNumber alloc] initWithString:@"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 1 overflow should return NaN"];
dcmn = [[CPDecimalNumber alloc] initWithString:@"foo"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 2 overflow should return NaN"];
dcmn = [[CPDecimalNumber alloc] initWithString:@".123"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 3 overflow should return NaN"];
dcmn = [[CPDecimalNumber alloc] initWithString:@"-.123"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 4 overflow should return NaN"];
dcmn = [[CPDecimalNumber alloc] initWithString:@"0123"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 5 overflow should return NaN"];
dcmn = [[CPDecimalNumber alloc] initWithString:@"1e200"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 6 overflow should return NaN"];
dcmn = [[CPDecimalNumber alloc] initWithString:@"12312e-23421"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 7 overflow should return NaN"];
}
- (void)testAdd
@@ -532,4 +495,18 @@
[self assert:"82346.2341144" equals:[dcmn descriptionWithLocale:nil] message:"descriptionWithLocale: - large number"];
}
- (void)testEncoding
{
var number = [CPDecimalNumber decimalNumberWithString:@"-1.233e24"],
encoded = [CPKeyedArchiver archivedDataWithRootObject:number],
decoded = [CPKeyedUnarchiver unarchiveObjectWithData:encoded];
[self assert:21 equals:decoded._data._exponent message:"exponent not unarchived correctly"];
[self assert:[1,2,3,3] equals:decoded._data._mantissa message:"mantissa not unarchived correctly"];
[self assert:YES equals:decoded._data._isNegative message:"sign not unarchived correctly"];
[self assert:NO equals:decoded._data._isNaN message:"isNaN not unarchived correctly"];
[self assert:YES equals:decoded._data._isCompact message:"isCompact not unarchived correctly"];
}
@end
+37 -20
View File
@@ -68,27 +68,42 @@
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithString() Tf4: NaN is incorrectly set"];
dcm = CPDecimalMakeWithString(@"000000000000000000");
[self assertNull:dcm message:"CPDecimalMakeWithString() Tf5: Should be invalid"];
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Tf5: Should be invalid"];
// too large return nil
[self assertNull:CPDecimalMakeWithString(@"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") message:"CPDecimalMakeWithString() To1: number overflow handling"];
[self assertNull:CPDecimalMakeWithString(@"-1e1000") message:"CPDecimalMakeWithString() To2: exponent overflow not caught"];
[self assertNull:CPDecimalMakeWithString(@"-1e-2342") message:"CPDecimalMakeWithString() To3: exponent underflow not caught"];
// too large return NaN
dcm = CPDecimalMakeWithString(@"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() To1: number overflow handling. Should return NaN"];
dcm =CPDecimalMakeWithString(@"-1e1000");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() To2: exponent overflow not caught. Should return NaN"];
dcm = CPDecimalMakeWithString(@"-1e-2342");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() To3: exponent underflow not caught. Should return NaN"];
// Tests for invalid strings
[self assertNull:CPDecimalMakeWithString(@"abc") message:"CPDecimalMakeWithString() Ti1: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"123a") message:"CPDecimalMakeWithString() Ti2: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"12.7e") message:"CPDecimalMakeWithString() Ti3: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"e") message:"CPDecimalMakeWithString() Ti4: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"12 ") message:"CPDecimalMakeWithString() Ti5: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"1 2 3") message:"CPDecimalMakeWithString() Ti6: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"e10") message:"CPDecimalMakeWithString() Ti7: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"123ee") message:"CPDecimalMakeWithString() Ti8: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"0001") message:"CPDecimalMakeWithString() Ti9: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"-0001") message:"CPDecimalMakeWithString() Ti10: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@".123") message:"CPDecimalMakeWithString() Ti11: catch of invalid number string"];
[self assertNull:CPDecimalMakeWithString(@"-.1") message:"CPDecimalMakeWithString() Ti12: catch of invalid number string"];
dcm = CPDecimalMakeWithString(@"abc");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti1: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"123a");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti2: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"12.7e");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti3: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"e");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti4: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"12 ");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti5: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"1 2 3");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti6: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"e10");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti7: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"123ee");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti8: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"0001");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti9: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"-0001");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti10: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@".123");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti11: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"-.1");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti12: catch of invalid number string. Should return NaN"];
//test make with parts
dcm = CPDecimalMakeWithParts(10127658,2);
[self assert:2 equals:dcm._exponent message:"CPDecimalMakeWithParts() Tmp1: exponent"];
@@ -101,8 +116,10 @@
[self assert:YES equals:dcm._isNegative message:"CPDecimalMakeWithParts() Tmp2: sign"];
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithParts() Tmp2: NaN is incorrectly set"];
[self assertNull:CPDecimalMakeWithParts(1,10000) message:"CPDecimalMakeWithParts() Tmp3: exponent overflow not caught"];
[self assertNull:CPDecimalMakeWithParts(-1,-1000) message:"CPDecimalMakeWithParts() Tmp4: exponent underflow not caught"];
dcm = CPDecimalMakeWithParts(1,10000);
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithParts() Tmp3: exponent overflow not caught. Should return NaN"];
dcm = CPDecimalMakeWithParts(-1,-1000);
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithParts() Tmp4: exponent underflow not caught. Should return NaN"];
}
- (void)testZeros
+8
View File
@@ -26,6 +26,14 @@
[array addObject:[arrayClass arrayWithObjects:0, 1, 2]];
[self assert:array equals:[arrayClass arrayWithObjects:0, 0, 1, [arrayClass arrayWithObjects:0, 1, 2]]];
[array addObject:[0, 1, 2]];
[self assert:array equals:[arrayClass arrayWithObjects:0, 0, 1, [arrayClass arrayWithObjects:0, 1, 2], [0, 1, 2]]];
var object = { };
[array addObject:object];
[self assert:array equals:[arrayClass arrayWithObjects:0, 0, 1, [arrayClass arrayWithObjects:0, 1, 2], [0, 1, 2], object]];
}
- (void)test_addObjectsFromArray_
+8 -6
View File
@@ -272,7 +272,7 @@
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
// Test Symbolic token
predicate = [CPPredicate predicateWithFormat:@"Record1.Children[FIRST] = 'Kid1'"];
predicate = [CPPredicate predicateWithFormat:@"Record1.Children[ FIRST ] = 'Kid1'"];
[self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"];
predicate = [CPPredicate predicateWithFormat:@"Record1.Children[1] = 'Kid2'"];
@@ -332,8 +332,8 @@
predicate = [CPPredicate predicateWithFormat: @"sum:(1,1) = 2"];
[self assertTrue:[predicate evaluateWithObject:nil] message:"Predicate " + predicate + " should evaluate to TRUE"];
// predicate = [CPPredicate predicateWithFormat: @"multiply:by:(5,3) = 15"];
// [self assertTrue:[predicate evaluateWithObject:nil] message:"Predicate " + predicate + " should evaluate to TRUE"];
predicate = [CPPredicate predicateWithFormat: @"multiply:by:(5,3) = 15"];
[self assertTrue:[predicate evaluateWithObject:nil] message:"Predicate " + predicate + " should evaluate to TRUE"];
// TEST custom functions
predicate = [CPPredicate predicateWithFormat:@"FUNCTION('a/path', 'lastPathComponent') = 'path'"];
@@ -342,14 +342,16 @@
predicate = [CPPredicate predicateWithFormat:@"FUNCTION('a/path', 'substringFromIndex:', 2) = 'path'"];
[self assertTrue:[predicate evaluateWithObject:nil] message:"Predicate " + predicate + " should evaluate to TRUE"];
predicate = [CPPredicate predicateWithFormat:@"FUNCTION('toto', 'stringByReplacingOccurrencesOfString:withString:', 'o', 'a') == 'tata'"];
[self assertTrue:[predicate evaluateWithObject:nil] message:"Predicate " + predicate + " should be TRUE"];
// TEST Subquery -- This means: search people who have 2 boys.
predicate = [CPPredicate predicateWithFormat: @"SUBQUERY(Record1.Children, $x, $x BEGINSWITH 'Kid')[SIZE] = 2"];
[self assertTrue:[predicate evaluateWithObject:dict] message:"Predicate " + predicate + " should evaluate to TRUE"];
// Test Set expressions
// Parsing is ok but the evaluation of this predicate will return NO for 2 reasons:
// 1- CPSet -isEqual: is unimplemented.
// 2- lhs will evaluate to a CPSet and rhs to a CPArray (aggregate exp). Comparing sets against arrays will always fail in CPComparisonPredicate. This is also cocoa behavior but i guess it's for historical reasons (set expressions are 10.5+) and should be changed in capp in my opinion.
// Parsing is ok but the evaluation of this predicate will return NO because:
// - lhs will evaluate to a CPSet and rhs to a CPArray (aggregate exp). Comparing sets against arrays will always fail in CPComparisonPredicate. This is also cocoa behavior but i guess it's for historical reasons (set expressions are 10.5+) and should be changed in capp in my opinion.
var object = [CPDictionary dictionaryWithObject:[CPSet setWithObjects:@"a"] forKey:"a"],
result = [CPSet setWithObjects:@"a",@"b"];
+2 -2
View File
@@ -94,9 +94,9 @@
return YES;
}
- (void)browserClicked:(id)sender
- (void)browserClicked:(id)aBrowser
{
console.log("selected column: " + [browser selectedColumn] + " row: " + [browser selectedRowInColumn:[browser selectedColumn]]);
console.log("selected column: " + [aBrowser selectedColumn] + " row: " + [aBrowser selectedRowInColumn:[aBrowser selectedColumn]]);
}
- (void)dblClicked:(id)sender
@@ -0,0 +1,79 @@
/*
* AppController.j
* CPOutlineViewCibTest
*
* Created by cacaodev on January 14, 2011.
* Copyright 2011, Your Company All rights reserved.
*/
@import <Foundation/CPObject.j>
@implementation AppController : CPObject
{
CPWindow theWindow;
CPOutlineView outlineView;
CPDictionary rootItem;
}
- (void)awakeFromCib
{
var path = [[CPBundle mainBundle] pathForResource:@"InitInfo.dict"],
request = [CPURLRequest requestWithURL:path],
connection = [CPURLConnection connectionWithRequest:request delegate:self];
rootItem = nil;
[theWindow setFullBridge:YES];
}
- (void)connection:(CPURLConnection)connection didReceiveData:(CPString)dataString
{
if (!dataString)
return;
var data = [[CPData alloc] initWithRawString:dataString],
rootItem = [CPPropertyListSerialization propertyListFromData:data format:CPPropertyListXMLFormat_v1_0];
[outlineView reloadData];
}
// ==========================
// ! CPOutlineView Delegate
// ==========================
- (int)outlineView:(CPOutlineView)theOutlineView numberOfChildrenOfItem:(id)theItem
{
if (theItem == nil)
theItem = rootItem;
if ([theItem isKindOfClass:[CPString class]])
return 0;
return [[theItem objectForKey:"Children"] count];
}
- (id)outlineView:(CPOutlineView)theOutlineView child:(int)theIndex ofItem:(id)theItem
{
if (theItem == nil)
theItem = rootItem;
return [[theItem objectForKey:"Children"] objectAtIndex:theIndex];
}
- (BOOL)outlineView:(CPOutlineView)theOutlineView isItemExpandable:(id)theItem
{
if (theItem == nil)
theItem = rootItem;
return ![theItem isKindOfClass:[CPString class]];
}
- (id)outlineView:(CPOutlineView)anOutlineView objectValueForTableColumn:(CPTableColumn)theColumn byItem:(id)theItem
{
if ([theItem isKindOfClass:[CPString class]])
return theItem;
return [theItem objectForKey:"Name"];
}
@end
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Main cib file base name</key>
<string>MainMenu.cib</string>
<key>CPBundleName</key>
<string>CPOutlineViewCibTest</string>
<key>CPPrincipalClass</key>
<string>CPApplication</string>
</dict>
</plist>
@@ -0,0 +1,94 @@
/*
* Jakefile
* CPOutlineViewCibTest
*
* Created by You on January 14, 2011.
* Copyright 2011, 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 ("CPOutlineViewCibTest", function(task)
{
task.setBuildIntermediatesPath(FILE.join("Build", "CPOutlineViewCibTest.build", configuration));
task.setBuildPath(FILE.join("Build", configuration));
task.setProductName("CPOutlineViewCibTest");
task.setIdentifier("com.yourcompany.CPOutlineViewCibTest");
task.setVersion("1.0");
task.setAuthor("Your Company");
task.setEmail("feedback @nospam@ yourcompany.com");
task.setSummary("CPOutlineViewCibTest");
task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**")));
task.setResources(new FileList("Resources/**"));
task.setIndexFilePath("index.html");
task.setInfoPlistPath("Info.plist");
task.setNib2CibFlags("-R Resources/");
if (configuration === "Debug")
task.setCompilerFlags("-DDEBUG -g");
else
task.setCompilerFlags("-O");
});
task ("default", ["CPOutlineViewCibTest"], 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", "CPOutlineViewCibTest", "index.html")]);
});
task ("run-release", ["release"], function()
{
OS.system(["open", FILE.join("Build", "Release", "CPOutlineViewCibTest", "index.html")]);
});
task ("deploy", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Deployment", "CPOutlineViewCibTest"));
OS.system(["press", "-f", FILE.join("Build", "Release", "CPOutlineViewCibTest"), FILE.join("Build", "Deployment", "CPOutlineViewCibTest")]);
printResults("Deployment")
});
task ("desktop", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Desktop", "CPOutlineViewCibTest"));
require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "CPOutlineViewCibTest"), FILE.join("Build", "Desktop", "CPOutlineViewCibTest", "CPOutlineViewCibTest.app"));
printResults("Desktop")
});
task ("run-desktop", ["desktop"], function()
{
OS.system([FILE.join("Build", "Desktop", "CPOutlineViewCibTest", "CPOutlineViewCibTest.app", "Contents", "MacOS", "NativeHost"), "-i"]);
});
function printResults(configuration)
{
print("----------------------------");
print(configuration+" app built at path: "+FILE.join("Build", configuration, "CPOutlineViewCibTest"));
print("----------------------------");
}
@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Children</key>
<array>
<dict>
<key>Children</key>
<array>
<dict>
<key>Children</key>
<array>
<dict>
<key>Children</key>
<array>
<string>Monty</string>
<string>Smithers</string>
<string>Frink</string>
<string>Carl</string>
<string>Cletus</string>
<string>Bobo</string>
<string>Duff</string>
</array>
<key>Name</key>
<string>Simpsons</string>
</dict>
<dict>
<key>Children</key>
<array>
<string>Mountain Unicycling</string>
<string>Rock Climbing</string>
<string>Bouldering</string>
<string>Snowboarding</string>
</array>
<key>Name</key>
<string>Sports</string>
</dict>
<dict>
<key>Children</key>
<array>
<string>Eating Strawberries</string>
<string>Mangoes</string>
<string>Treehouses</string>
<string>Good Weather</string>
<string>Maui</string>
<string>Trogdor</string>
</array>
<key>Name</key>
<string>Just Fun Stuff</string>
</dict>
<string>Foo with the Bar</string>
<string>Bar</string>
<string>BooFar</string>
<string>Foo Bar</string>
</array>
<key>Name</key>
<string>Shows</string>
</dict>
<dict>
<key>Children</key>
<array>
<dict>
<key>Children</key>
<array>
<string>Big Sur</string>
<string>New York</string>
<string>Naples</string>
<string>Chez Panisse</string>
<string>Lucia</string>
<string>Switzerland</string>
<string>Ireland</string>
</array>
<key>Name</key>
<string>Vacation</string>
</dict>
<dict>
<key>Children</key>
<array>
<string>Green Bay</string>
<string>Milwaukee</string>
<string>Monroe</string>
</array>
<key>Name</key>
<string>Other</string>
</dict>
</array>
<key>Name</key>
<string>Travel</string>
</dict>
<dict>
<key>Children</key>
<array>
<string>Kark</string>
<string>Valen</string>
<string>Kosh</string>
<string>Red Letter</string>
<string>Fluffy Ears</string>
<string>Hiro</string>
</array>
<key>Name</key>
<string>Science Fiction</string>
</dict>
</array>
<key>Name</key>
<string>Favorite Things Group</string>
</dict>
<dict>
<key>Children</key>
<array>
<string>Mischief</string>
<string>Mayhem</string>
<string>Soap</string>
</array>
<key>Name</key>
<string>Movies Group with a Long Title</string>
</dict>
<dict>
<key>Children</key>
<array>
<string>ObjC</string>
<string>Cocoa</string>
<string>KVC</string>
<string>NSTooblar</string>
</array>
<key>Name</key>
<string>Things That Rule</string>
</dict>
<string>Eagle</string>
<string>Boiler</string>
<string>Tarheel</string>
</array>
<key>Name</key>
<string>OVRoot</string>
</dict>
</plist>
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,103 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!--
index-debug.html
CPOutlineViewCibTest
Created by You on January 14, 2011.
Copyright 2011, Your Company All rights reserved.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7, chrome=1" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="apple-touch-icon" href="Resources/icon.png" />
<link rel="apple-touch-startup-image" href="Resources/default.png" />
<title>CPOutlineViewCibTest</title>
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks", "SomethingElse"];
</script>
<script type="text/javascript" src="Frameworks/Debug/Objective-J/Objective-J.js" charset="UTF-8"></script>
<script type="text/javascript">
objj_msgSend_reset();
// DEBUG OPTIONS:
// 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);
// Uncomment (along with both above) to print backtraces on type check errors:
//objj_typecheck_prints_backtrace = true;
// Uncomment to disable the default logger (CPLogConsole if window.console exists, CPLogPopup otherwise):
//CPLogUnregister(CPLogDefault);
// Uncomment to enable a specific logger:
//CPLogRegister(CPLogConsole);
//CPLogRegister(CPLogPopup);
</script>
<style type="text/css">
body{margin:0; padding:0;}
#container {position: absolute; top:50%; left:50%;}
#content {width:800px; text-align:center; margin-left: -400px; height:50px; margin-top:-25px; line-height: 50px;}
#content {font-family: "Helvetica", "Arial", sans-serif; font-size: 18px; color: black; text-shadow: 0px 1px 0px white; }
#loadgraphic {margin-right: 0.2em; margin-bottom:-2px;}
</style>
<!--[if lt IE 7]>
<STYLE type="text/css">
#container { position: relative; top: 50%; }
#content { position: relative;}
</STYLE>
<![endif]-->
</head>
<body style="">
<div id="cappuccino-body">
<div id="loadingcontainer" style="background-color: #eeeeee; overflow:hidden; width:100%; height:100%; position: absolute; top: 0; left: 0;">
<script type="text/javascript">
document.write("<div id='container'><p id='content'>" +
"<img id='loadgraphic' width='16' height='16' src='Resources/spinner.gif' /> " +
"Loading CPOutlineViewCibTest...</p></div>");
</script>
<noscript>
<div id="container">
<div style="width: 440px; padding: 10px 25px 20px 25px; font-family: sans-serif; background-color: #ffffff; position: relative; left: -245px; top: -120px; text-align: center; -moz-border-radius: 20px; -webkit-border-radius: 20px; color: #555555">
<p style="line-height: 1.4em;">JavaScript is required for this site to work correctly but is either disabled or not supported by your browser.</p>
<p style="font-size:120%; padding:10px;"><a href="http://cappuccino.org/noscript">Show me how to enable JavaScript</a></p>
<p style="font-size:80%;">You may want to upgrade to a newer browser while you're at it:</p>
<ul style="margin:0;padding:0; text-align: center; font-size:80%;" >
<li style="display: inline;"><a href="http://www.apple.com/safari/download/">Safari</a></li>
<li style="display: inline;"><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a></li>
<li style="display: inline;"><a href="http://www.google.com/chrome/">Chrome</a></li>
<li style="display: inline;"><a href="http://www.opera.com/download/">Opera</a></li>
<li style="display: inline;"><a href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer</a></li>
</ul>
</div>
</div>
</noscript>
</div>
</div>
</body>
</html>
@@ -0,0 +1,77 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!--
index.html
CPOutlineViewCibTest
Created by You on January 14, 2011.
Copyright 2011, Your Company All rights reserved.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7, chrome=1" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="apple-touch-icon" href="Resources/icon.png" />
<link rel="apple-touch-startup-image" href="Resources/default.png" />
<title>CPOutlineViewCibTest</title>
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
</script>
<script type="text/javascript" src="Frameworks/Objective-J/Objective-J.js" charset="UTF-8"></script>
<style type="text/css">
body{margin:0; padding:0;}
#container {position: absolute; top:50%; left:50%;}
#content {width:800px; text-align:center; margin-left: -400px; height:50px; margin-top:-25px; line-height: 50px;}
#content {font-family: "Helvetica", "Arial", sans-serif; font-size: 18px; color: black; text-shadow: 0px 1px 0px white; }
#loadgraphic {margin-right: 0.2em; margin-bottom:-2px;}
</style>
<!--[if lt IE 7]>
<STYLE type="text/css">
#container { position: relative; top: 50%; }
#content { position: relative;}
</STYLE>
<![endif]-->
</head>
<body style="">
<div id="cappuccino-body">
<div id="loadingcontainer" style="background-color: #eeeeee; overflow:hidden; width:100%; height:100%; position: absolute; top: 0; left: 0;">
<script type="text/javascript">
document.write("<div id='container'><p id='content'>" +
"<img id='loadgraphic' width='16' height='16' src='Resources/spinner.gif' /> " +
"Loading CPOutlineViewCibTest...</p></div>");
</script>
<noscript>
<div id="container">
<div style="width: 440px; padding: 10px 25px 20px 25px; font-family: sans-serif; background-color: #ffffff; position: relative; left: -245px; top: -120px; text-align: center; -moz-border-radius: 20px; -webkit-border-radius: 20px; color: #555555">
<p style="line-height: 1.4em;">JavaScript is required for this site to work correctly but is either disabled or not supported by your browser.</p>
<p style="font-size:120%; padding:10px;"><a href="http://cappuccino.org/noscript">Show me how to enable JavaScript</a></p>
<p style="font-size:80%;">You may want to upgrade to a newer browser while you're at it:</p>
<ul style="margin:0;padding:0; text-align: center; font-size:80%;" >
<li style="display: inline;"><a href="http://www.apple.com/safari/download/">Safari</a></li>
<li style="display: inline;"><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a></li>
<li style="display: inline;"><a href="http://www.google.com/chrome/">Chrome</a></li>
<li style="display: inline;"><a href="http://www.opera.com/download/">Opera</a></li>
<li style="display: inline;"><a href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer</a></li>
</ul>
</div>
</div>
</noscript>
</div>
</div>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
/*
* AppController.j
* CPOutlineViewCibTest
*
* Created by cacaodev on January 14, 2011.
* Copyright 2011, Your Company All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import "AppController.j"
function main(args, namedArgs)
{
CPApplicationMain(args, namedArgs);
}
@@ -180,13 +180,13 @@ CustomOutlineViewDragType = @"CustomOutlineViewDragType";
var column = [[CPTableColumn alloc] initWithIdentifier:@"One"];
[_outlineView addTableColumn:column];
[_outlineView setOutlineTableColumn:column];
//[_outlineView setOutlineTableColumn:column];
setTimeout(function(){
[column setWidth:200];
},0);
[_outlineView addTableColumn:[[CPTableColumn alloc] initWithIdentifier:@"Two"]];
[_outlineView addTableColumn:[[CPTableColumn alloc] initWithIdentifier:@"Three"]];
[_outlineView addTableColumn:[[CPTableColumn alloc] initWithIdentifier:@"Three"]];
[_outlineView registerForDraggedTypes:[CustomOutlineViewDragType]];
@@ -6,7 +6,5 @@
<string>MainMenu.cib</string>
<key>CPBundleName</key>
<string>__project.name__</string>
<key>CPPrincipalClass</key>
<string>CPApplication</string>
</dict>
</plist>
+4 -1
View File
@@ -36,7 +36,10 @@
else
_outlineTableColumn = [[self tableColumns] objectAtIndex:0];
_indentationPerLevel = [aCoder decodeFloatForKey:@"NSOutlineViewIndentationPerLevelKey"];
if ([aCoder containsValueForKey:"NSOutlineViewIndentationPerLevelKey"])
_indentationPerLevel = [aCoder decodeFloatForKey:@"NSOutlineViewIndentationPerLevelKey"];
else
_indentationPerLevel = 16;
_outlineViewDataSource = [aCoder decodeObjectForKey:@"NSDataSource"];
_outlineViewDelegate = [aCoder decodeObjectForKey:@"NSDelegate"];
+2 -2
View File
@@ -68,8 +68,8 @@
{
var frame = [self frame];
[self setFrameOrigin:CGPointMake(frame.origin.x - 4.0, frame.origin.y - 4.0)];
[self setFrameSize:CGSizeMake(frame.size.width + 8.0, frame.size.height + 8.0)];
[self setFrameOrigin:CGPointMake(frame.origin.x - 3.0, frame.origin.y - 3.0)];
[self setFrameSize:CGSizeMake(frame.size.width + 7.0, frame.size.height + 7.0)];
}
CPLog.debug([self stringValue] + " => isBordered=" + [self isBordered] + ", isBezeled=" + [self isBezeled] + ", bezelStyle=" + [self bezelStyle] + "("+[cell stringValue]+", " + [cell placeholderString] + ")");