mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-09 12:17:13 +00:00
Compare commits
45
Commits
0.9.0-RC1
...
v0.9.0-RC2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9796f5d5d7 | ||
|
|
8720a952b0 | ||
|
|
bf4724d401 | ||
|
|
c73e2e1a91 | ||
|
|
630cd121a6 | ||
|
|
5d88ffbe66 | ||
|
|
bd5aa1c959 | ||
|
|
c65bfd22a2 | ||
|
|
e656e0561b | ||
|
|
ddbba22533 | ||
|
|
91b5596034 | ||
|
|
e0185a0eff | ||
|
|
2fe8845842 | ||
|
|
c02128a1fd | ||
|
|
27ad98e160 | ||
|
|
fc746db70f | ||
|
|
6a6256bdb4 | ||
|
|
5a0cfc1595 | ||
|
|
32107ab650 | ||
|
|
5c2ebd546c | ||
|
|
72b8ed2faf | ||
|
|
6b8c85df7c | ||
|
|
cce4e3ded8 | ||
|
|
0240c648aa | ||
|
|
6019ff9107 | ||
|
|
c4ee83e4c1 | ||
|
|
61b0cbb1af | ||
|
|
af30e96b7b | ||
|
|
b7bdec189a | ||
|
|
2a27a87ae6 | ||
|
|
31ac84f683 | ||
|
|
c41defe864 | ||
|
|
6bc109f7fc | ||
|
|
2d603df83c | ||
|
|
dcf440396d | ||
|
|
1dc10440b7 | ||
|
|
0ef2557ec3 | ||
|
|
05e69c85c7 | ||
|
|
9c6476615d | ||
|
|
b393d0597f | ||
|
|
f69e2e8d8f | ||
|
|
5fd470acea | ||
|
|
28e660c295 | ||
|
|
9a76b4451f | ||
|
|
b50f955cfd |
+10
-6
@@ -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
@@ -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
@@ -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
@@ -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",
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
@@ -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
@@ -26,7 +26,7 @@
|
||||
CPOKButton = 1;
|
||||
CPCancelButton = 0;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPPanel
|
||||
|
||||
|
||||
+165
-152
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -604,7 +604,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
[headerView setFrame:frame];
|
||||
|
||||
if([headerView superview] != self)
|
||||
if ([headerView superview] != self)
|
||||
[self addSubview:headerView];
|
||||
}
|
||||
|
||||
|
||||
+30
-3
@@ -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
@@ -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
@@ -50,8 +50,8 @@ CPToolbarDisplayModeIconOnly = 2;
|
||||
*/
|
||||
CPToolbarDisplayModeLabelOnly = 3;
|
||||
|
||||
var CPToolbarsByIdentifier = nil;
|
||||
var CPToolbarConfigurationsByIdentifier = nil;
|
||||
var CPToolbarsByIdentifier = nil,
|
||||
CPToolbarConfigurationsByIdentifier = nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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]];
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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
|
||||
/*!
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
+690
-142
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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]];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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"];
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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"];
|
||||
|
||||
@@ -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] + ")");
|
||||
|
||||
Reference in New Issue
Block a user