diff --git a/.gitignore b/.gitignore
index 71e257752..b72055ed9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,5 +2,5 @@
Frameworks
Build
Demos
-Aristo
+./Aristo
WebSite
diff --git a/AppKit/AppKit.j b/AppKit/AppKit.j
index 3a2a3f421..ec791365d 100644
--- a/AppKit/AppKit.j
+++ b/AppKit/AppKit.j
@@ -29,8 +29,12 @@
@import "CPButtonBar.j"
@import "CPCheckBox.j"
@import "CPCib.j"
+@import "CPCibConnector.j"
+@import "CPCibControlConnector.j"
@import "CPCibLoading.j"
+@import "CPCibOutletConnector.j"
@import "CPClipView.j"
+@import "CPCollectionViewItem.j"
@import "CPCollectionView.j"
@import "CPColor.j"
@import "CPColorPanel.j"
@@ -57,6 +61,7 @@
@import "CPProgressIndicator.j"
@import "CPRadio.j"
@import "CPResponder.j"
+@import "CPSearchField.j"
@import "CPScrollView.j"
@import "CPScroller.j"
@import "CPSecureTextField.j"
@@ -71,6 +76,7 @@
@import "CPToolbar.j"
@import "CPToolbarItem.j"
@import "CPView.j"
+@import "CPViewController.j"
@import "CPWebView.j"
@import "CPWindow.j"
@import "CPWindowController.j"
diff --git a/AppKit/CPAccordionView.j b/AppKit/CPAccordionView.j
new file mode 100644
index 000000000..b3294149b
--- /dev/null
+++ b/AppKit/CPAccordionView.j
@@ -0,0 +1,361 @@
+/*
+ * CPAccordionView.j
+ * AppKit
+ *
+ * Created by Francisco Tolmasky.
+ * Copyright 2009, 280 North, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+@import
+@import
+@import
+@import
+@import
+
+@import
+
+#import "CoreGraphics/CGGeometry.h"
+
+
+@implementation CPAccordionViewItem : CPObject
+{
+ CPString _identifier @accessors(property=identifier);
+ CPView _view @accessors(property=view);
+ CPString _label @accessors(property=label);
+}
+
+- (id)init
+{
+ return [self initWithIdentifier:@""];
+}
+
+- (id)initWithIdentifier:(CPString)anIdentifier
+{
+ self = [super init];
+
+ if (self)
+ [self setIdentifier:anIdentifier];
+
+ return self;
+}
+
+@end
+
+@implementation CPAccordionView : CPView
+{
+ CPInteger _dirtyItemIndex;
+ CPView _itemHeaderPrototype;
+
+ CPMutableArray _items;
+ CPMutableArray _itemViews;
+ CPIndexSet _expandedItemIndexes;
+}
+
+- (id)initWithFrame:(CGRect)aFrame
+{
+ self = [super initWithFrame:aFrame];
+
+ if (self)
+ {
+ _items = [];
+ _itemViews = [];
+ _expandedItemIndexes = [CPIndexSet indexSet];
+
+ [self setItemHeaderPrototype:[[CPButton alloc] initWithFrame:_CGRectMake(0.0, 0.0, 100.0, 24.0)]];
+ }
+
+ return self;
+}
+
+- (void)setItemHeaderPrototype:(CPView)aView
+{
+ _itemHeaderPrototype = aView;
+}
+
+- (CPView)itemHeaderPrototype
+{
+ return _itemHeaderPrototype;
+}
+
+- (CPArray)items
+{
+ return _items;
+}
+
+- (void)addItem:(CPAccordionItem)anItem
+{
+ [self insertItem:anItem atIndex:_items.length];
+}
+
+- (void)insertItem:(CPAccordionItem)anItem atIndex:(CPInteger)anIndex
+{
+ // FIXME: SHIFT ITEMS RIGHT
+ [_expandedItemIndexes addIndex:anIndex];
+
+ var itemView = [[_CPAccordionItemView alloc] initWithAccordionView:self];
+
+ [itemView setIndex:anIndex];
+ [itemView setLabel:[anItem label]];
+ [itemView setContentView:[anItem view]];
+
+ [self addSubview:itemView];
+
+ [_items insertObject:anItem atIndex:anIndex];
+ [_itemViews insertObject:itemView atIndex:anIndex];
+
+ [self _invalidateItemsStartingAtIndex:anIndex];
+
+ [self setNeedsLayout];
+}
+
+- (void)removeItem:(CPAccordionItem)anItem
+{
+ [self removeItemAtIndex:[_items indexOfObjectIdenticalTo:anItem]];
+}
+
+- (void)removeItemAtIndex:(CPInteger)anIndex
+{
+ // SHIFT ITEMS LEFT
+ [_expandedItemIndexes removeIndex:anIndex];
+
+ [_itemViews[anIndex] removeFromSuperview];
+
+ [_items removeObjectAtIndex:anIndex];
+ [_itemViews removeObjectAtIndex:anIndex];
+
+ [self _invalidateItemsStartingAtIndex:anIndex];
+
+ [self setNeedsLayout];
+}
+
+- (void)removeAllItems
+{
+ var count = _items.length;
+
+ while (count--)
+ [self removeItemAtIndex:count];
+}
+
+- (void)expandItemAtIndex:(CPInteger)anIndex
+{
+ if (![_itemViews[anIndex] isCollapsed])
+ return;
+
+ [_expandedItemIndexes addIndex:anIndex];
+ [_itemViews[anIndex] setCollapsed:NO];
+
+ [self _invalidateItemsStartingAtIndex:anIndex];
+}
+
+- (void)collapseItemAtIndex:(CPInteger)anIndex
+{
+ if ([_itemViews[anIndex] isCollapsed])
+ return;
+
+ [_expandedItemIndexes removeIndex:anIndex];
+ [_itemViews[anIndex] setCollapsed:YES];
+
+ [self _invalidateItemsStartingAtIndex:anIndex];
+}
+
+- (void)toggleItemAtIndex:(CPInteger)anIndex
+{
+ var itemView = _itemViews[anIndex];
+
+ if ([itemView isCollapsed])
+ [self expandItemAtIndex:anIndex];
+
+ else
+ [self collapseItemAtIndex:anIndex];
+}
+
+- (CPIndexSet)expandedItemIndexes
+{
+ return _expandedItemIndexes;
+}
+
+- (CPIndexSet)collapsedItemIndexes
+{
+ var indexSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, _items.length)];
+
+ [indexSet removeIndexes:_expandedIndexes];
+
+ return indexSet;
+}
+
+- (void)_invalidateItemsStartingAtIndex:(CPInteger)anIndex
+{
+ if (_dirtyItemIndex === CPNotFound)
+ _dirtyItemIndex = anIndex;
+
+ _dirtyItemIndex = MIN(_dirtyItemIndex, anIndex);
+
+ [self setNeedsLayout];
+}
+
+- (void)setFrameSize:(CGSize)aSize
+{
+ var width = _CGRectGetWidth([self frame]);
+
+ [super setFrameSize:aSize];
+
+ if (width !== _CGRectGetWidth([self frame]))
+ [self _invalidateItemsStartingAtIndex:0];
+}
+
+- (void)layoutSubviews
+{
+ if (_items.length <= 0)
+ return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)];
+
+ if (_dirtyItemIndex === CPNotFound)
+ return;
+
+ _dirtyItemIndex = MIN(_dirtyItemIndex, _items.length - 1);
+
+ var index = _dirtyItemIndex,
+ count = _itemViews.length,
+ width = _CGRectGetWidth([self bounds]),
+ y = index > 0 ? CGRectGetMaxY([_itemViews[index - 1] frame]) : 0.0;
+
+ // Do this now (instead of after looping), so that if we are made dirty again in the middle we don't blow this value away.
+ _dirtyItemIndex = CPNotFound;
+
+ for (; index < count; ++index)
+ {
+ var itemView = _itemViews[index];
+
+ [itemView setFrameY:y width:width];
+
+ y = CGRectGetMaxY([itemView frame]);
+ }
+
+ [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), y)];
+}
+
+@end
+
+@implementation _CPAccordionItemView : CPView
+{
+ CPAccordionView _accordionView;
+
+ BOOL _isCollapsed @accessors(getter=isCollapsed, setter=setCollapsed:);
+ CPInteger _index @accessors(property=index);
+ CPView _headerView;
+ CPView _contentView;
+}
+
+- (id)initWithAccordionView:(CPAccordionView)anAccordionView
+{
+ self = [super initWithFrame:_CGRectMakeZero()];
+
+ if (self)
+ {
+ _accordionView = anAccordionView;
+ _isCollapsed = NO;
+
+ var bounds = [self bounds];
+
+ _headerView = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:[_accordionView itemHeaderPrototype]]];
+
+ if ([_headerView respondsToSelector:@selector(setTarget:)] && [_headerView respondsToSelector:@selector(setAction:)])
+ {
+ [_headerView setTarget:self];
+ [_headerView setAction:@selector(toggle:)];
+ }
+
+ [self addSubview:_headerView];
+ }
+
+ return self;
+}
+
+- (void)toggle:(id)aSender
+{
+ [_accordionView toggleItemAtIndex:[self index]];
+}
+
+- (void)setLabel:(CPString)aLabel
+{
+ if ([_headerView respondsToSelector:@selector(setTitle:)])
+ [_headerView setTitle:aLabel];
+
+ else if ([_headerView respondsToSelector:@selector(setLabel:)])
+ [_headerView setLabel:aLabel];
+
+ else if ([_headerView respondsToSelector:@selector(setStringValue:)])
+ [_headerView setStringValue:aLabel];
+}
+
+- (void)setContentView:(CPView)aView
+{
+ if (_contentView === aView)
+ return;
+
+ [_contentView removeObserver:self forKeyPath:@"frame"];
+
+ [_contentView removeFromSuperview];
+
+ _contentView = aView;
+
+ [_contentView addObserver:self forKeyPath:@"frame" options:0 context:NULL];
+
+ [self addSubview:_contentView];
+
+ [_accordionView _invalidateItemsStartingAtIndex:[self index]];
+}
+
+- (void)setFrameY:(float)aY width:(float)aWidth
+{
+ var headerHeight = _CGRectGetHeight([_headerView frame]);
+
+ // Size to fit or something?
+ [_headerView setFrameSize:_CGSizeMake(aWidth, headerHeight)];
+ [_contentView setFrameOrigin:_CGPointMake(0.0, headerHeight)];
+
+ if ([self isCollapsed])
+ [self setFrame:_CGRectMake(0.0, aY, aWidth, headerHeight)];
+
+ else
+ {
+ var contentHeight = _CGRectGetHeight([_contentView frame]);
+
+ [_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)];
+ [self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
+ }
+}
+
+- (void)resizeSubviewsWithOldSize:(CGSize)aSize
+{
+}
+
+- (void)observeValueForKeyPath:(CPString)aKeyPath
+ ofObject:(id)anObject
+ change:(CPDictionary)aChange
+ context:(id)aContext
+{
+ if (aKeyPath === "frame" && !CGRectEqualToRect([aChange objectForKey:CPKeyValueChangeOldKey], [aChange objectForKey:CPKeyValueChangeNewKey]))
+ [_accordionView _invalidateItemsStartingAtIndex:[self index]];
+/*
+ else if (aKeyPath === "itemHeaderPrototype")
+ {
+
+ }
+*/
+}
+
+@end
diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j
index f25d78b32..6e41f149b 100644
--- a/AppKit/CPAlert.j
+++ b/AppKit/CPAlert.j
@@ -62,12 +62,12 @@ var CPAlertWarningImage,
CPAlert is an alert panel that can be displayed modally to present the
user with a message and one or more options.
- It can be used to display an information message (
CPInformationalAlertStyle
),
- a warning message (
CPWarningAlertStyle
- which is the default), or a critical
- alert (
CPCriticalAlertStyle
). In each case the user can be presented with one
- or more options by adding buttons using the
addButtonWithTitle:
method.
+ It can be used to display an information message \c CPInformationalAlertStyle,
+ a warning message \c CPWarningAlertStyle (the default), or a critical
+ alert \c CPCriticalAlertStyle. In each case the user can be presented with one
+ or more options by adding buttons using the \c -addButtonWithTitle: method.
- The panel is displayed modally by calling
runModal
and once the user has
+ The panel is displayed modally by calling \c -runModal and once the user has
dismissed the panel, a message will be sent to the panel's delegate (if set), informing
it which button was clicked (see delegate methods).
@@ -112,7 +112,7 @@ var CPAlertWarningImage,
}
/*!
- Initializes a
CPAlert
panel with the default alert style (
CPWarningAlertStyle
).
+ Initializes a \c CPAlert panel with the default alert style \c CPWarningAlertStyle.
*/
- (id)init
{
@@ -244,7 +244,7 @@ var CPAlertWarningImage,
/*!
Adds a button with a given title to the receiver.
- Buttons will be added starting from the right hand side of the
CPAlert
panel.
+ Buttons will be added starting from the right hand side of the \c CPAlert panel.
The first button will have the index 0, the second button 1 and so on.
You really shouldn't need more than 3 buttons.
@@ -269,7 +269,7 @@ var CPAlertWarningImage,
}
/*!
- Displays the
CPAlert
panel as a modal dialog. The user will not be
+ Displays the \c CPAlert panel as a modal dialog. The user will not be
able to interact with any other controls until s/he has dismissed the alert
by clicking on one of the buttons.
*/
diff --git a/AppKit/CPAnimation.j b/AppKit/CPAnimation.j
index 77fdaab91..df880842c 100644
--- a/AppKit/CPAnimation.j
+++ b/AppKit/CPAnimation.j
@@ -57,10 +57,10 @@ ACTUAL_FRAME_RATE = 0;
@par Delegate Methods
@delegate -(BOOL)animationShouldStart:(CPAnimation)animation;
- Called at the beginning of startAnimation.
+ Called at the beginning of \c -startAnimation.
@param animation the animation that will start
- @return YES allows the animation to start.
- NO stops the animation.
+ @return \c YES allows the animation to start.
+ \c NO stops the animation.
@delegate -(void)animationDidEnd:(CPAnimation)animation;
Called when an animation has completed.
@@ -72,7 +72,7 @@ ACTUAL_FRAME_RATE = 0;
@delegate - (float)animation:(CPAnimation)animation valueForProgress:(float)progress;
The value from this method will be returned when CPAnimation's
- currentValue method is called.
+ \c currentValue method is called.
@param animation the animation to obtain the curve value for
@param progress the current animation progress
@return the curve value
@@ -154,7 +154,7 @@ ACTUAL_FRAME_RATE = 0;
/*!
Sets the animation's length.
@param aDuration the new animation length
- @throws CPInvalidArgumentException if aDuration is negative
+ @throws CPInvalidArgumentException if \c aDuration is negative
*/
- (void)setDuration:(CPTimeInterval)aDuration
{
@@ -175,7 +175,7 @@ ACTUAL_FRAME_RATE = 0;
/*!
Sets the animation frame rate. This is not a guaranteed frame rate. 0 means to go as fast as possible.
@param frameRate the new desired frame rate
- @throws CPInvalidArgumentException if frameRate is negative
+ @throws CPInvalidArgumentException if \c frameRate is negative
*/
- (void)setFrameRate:(float)frameRate
{
@@ -211,7 +211,7 @@ ACTUAL_FRAME_RATE = 0;
}
/*!
- Starts the animation. The method calls animationShouldStart:
+ Starts the animation. The method calls \c -animationShouldStart:
on the delegate (if it implements it) to see if the animation
should begin.
*/
@@ -270,7 +270,7 @@ ACTUAL_FRAME_RATE = 0;
}
/*!
- Returns YES if the animation
+ Returns \c YES if the animation
is running.
*/
- (BOOL)isAnimating
diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j
index 012cc2ffb..26aa821e6 100644
--- a/AppKit/CPApplication.j
+++ b/AppKit/CPApplication.j
@@ -28,6 +28,9 @@
@import "CPResponder.j"
@import "CPDocumentController.j"
@import "CPThemeBlend.j"
+@import "CPCibLoading.j"
+@import "CPPlatform.j"
+
var CPMainCibFile = @"CPMainCibFile",
CPMainCibFileHumanFriendly = @"Main cib file base name";
@@ -48,7 +51,7 @@ CPRunContinuesResponse = -1002;
CPApplication is THE way to start up the Cappucino framework for your application to use.
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of
CPApplication). Your program's main() function can create that instance by calling the
- CPApplicationMain function. A simple example looks like this:
+ \c CPApplicationMain function. A simple example looks like this:
function main(args, namedArgs)
@@ -83,6 +86,7 @@ CPRunContinuesResponse = -1002;
//
id _delegate;
+ BOOL _finishedLaunching;
CPDictionary _namedArgs;
CPArray _args;
@@ -104,7 +108,7 @@ CPRunContinuesResponse = -1002;
/*!
Initializes the Document based application with basic menu functions.
- Functions are New, Open, Undo, Redo, Save, Cut, Copy, Paste.
+ Functions are \c New, \c Open, \c Undo, \c Redo, \c Save, \c Cut, \c Copy, \c Paste.
@return the initialized application
*/
- (id)init
@@ -234,10 +238,10 @@ CPRunContinuesResponse = -1002;
}
/*!
- This method is called by run before the event loop begins.
+ This method is called by \c -run before the event loop begins.
When it successfully completes, it posts the notification
CPApplicationDidFinishLaunchingNotification. If you override
- finishLaunching, the subclass method should invoke the superclass method.
+ \c -finishLaunching, the subclass method should invoke the superclass method.
*/
- (void)finishLaunching
{
@@ -265,19 +269,37 @@ CPRunContinuesResponse = -1002;
[defaultCenter
postNotificationName:CPApplicationWillFinishLaunchingNotification
object:self];
-
- if (_documentController)
+
+ var filename = window.cpOpeningFilename && window.cpOpeningFilename(),
+ needsUntitled = !!_documentController;
+
+ if ([filename length])
+ {
+ needsUntitled = ![self _openFile:filename];
+ }
+
+ if (needsUntitled && [_delegate respondsToSelector: @selector(applicationShouldOpenUntitledFile:)])
+ needsUntitled = [_delegate applicationShouldOpenUntitledFile:self];
+
+ if (needsUntitled)
[_documentController newDocument:self];
[defaultCenter
postNotificationName:CPApplicationDidFinishLaunchingNotification
object:self];
-
+
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
+
+ _finishedLaunching = YES;
+}
+
+- (void)terminate:(id)aSender
+{
+ [CPPlatform terminateApplication];
}
/*!
- Calls finishLaunching method which results in starting
+ Calls \c -finishLaunching method which results in starting
the main event loop.
*/
- (void)run
@@ -287,7 +309,7 @@ CPRunContinuesResponse = -1002;
// Managing the Event Loop
/*!
- Starts a modal event loop for aWindow
+ Starts a modal event loop for \c aWindow
@param aWindow the window to start the event loop for
*/
- (void)runModalForWindow:(CPWindow)aWindow
@@ -296,8 +318,8 @@ CPRunContinuesResponse = -1002;
}
/*!
- Stops the event loop started by runModalForWindow: and
- sets the code that runModalForWindow: will return.
+ Stops the event loop started by \c -runModalForWindow: and
+ sets the code that \c -runModalForWindow: will return.
@param aCode the return code for the modal event
*/
- (void)stopModalWithCode:(int)aCode
@@ -338,7 +360,7 @@ CPRunContinuesResponse = -1002;
}
/*!
- Aborts the event loop started by runModalForWindow:
+ Aborts the event loop started by \c -runModalForWindow:
*/
- (void)abortModal
{
@@ -346,7 +368,7 @@ CPRunContinuesResponse = -1002;
}
/*!
- Sets up a modal session with theWindow.
+ Sets up a modal session with \c theWindow.
@param aWindow the window to set up the modal session for
*/
- (CPModalSession)beginModalSessionForWindow:(CPWindow)aWindow
@@ -375,7 +397,7 @@ CPRunContinuesResponse = -1002;
/*!
Returns the window for the current modal session. If there is no
- modal session, it returns nil.
+ modal session, it returns \c nil.
*/
- (CPWindow)modalWindow
{
@@ -390,7 +412,7 @@ CPRunContinuesResponse = -1002;
{
if ([_mainMenu performKeyEquivalent:anEvent])
return YES;
-
+
return NO;
}
@@ -400,6 +422,8 @@ CPRunContinuesResponse = -1002;
*/
- (void)sendEvent:(CPEvent)anEvent
{
+ _currentEvent = anEvent;
+
// Check if this is a candidate for key equivalent...
if ([anEvent type] == CPKeyDown &&
[anEvent modifierFlags] & (CPCommandKeyMask | CPControlKeyMask) &&
@@ -443,7 +467,7 @@ CPRunContinuesResponse = -1002;
}
/*!
- Returns the CPWindow object corresponding to aWindowNumber.
+ Returns the CPWindow object corresponding to \c aWindowNumber.
*/
- (CPWindow)windowWithWindowNumber:(int)aWindowNumber
{
@@ -473,7 +497,18 @@ CPRunContinuesResponse = -1002;
*/
- (void)setMainMenu:(CPMenu)aMenu
{
- _mainMenu = aMenu;
+ if ([aMenu _menuName] === "CPMainMenu")
+ {
+ if (_mainMenu === aMenu)
+ return;
+
+ _mainMenu = aMenu;
+
+ if ([CPPlatform supportsNativeMainMenu])
+ window.cpSetMainMenu(_mainMenu);
+ }
+ else
+ [aMenu _setMenuName:@"CPMainMenu"];
}
- (void)orderFrontColorPanel:(id)aSender
@@ -499,7 +534,7 @@ CPRunContinuesResponse = -1002;
@param anAction the action to perform.
@param anObject the argument for the action
method
- @return YES if the action was performed
+ @return \c YES if the action was performed
*/
- (BOOL)tryToPerform:(SEL)anAction with:(id)anObject
{
@@ -524,7 +559,7 @@ CPRunContinuesResponse = -1002;
@param anAction the action to send
@param aTarget the target for the action
@param aSender the action sender
- @return YES
+ @return \c YES
*/
- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)aSender
{
@@ -540,12 +575,12 @@ CPRunContinuesResponse = -1002;
/*!
Finds a target for the specified action. If the
- action is nil, returns nil.
- If the target is not nil, aTarget is
- returned. Otherwise, it calls targetForAction:
+ action is \c nil, returns \c nil.
+ If the target is not \c nil, \c aTarget is
+ returned. Otherwise, it calls \c -targetForAction:
to search for a target.
@param anAction the action to find a target for
- @param aTarget if not nil, this will be returned
+ @param aTarget if not \c nil, this will be returned
@aSender not used
@return a target for the action
*/
@@ -573,7 +608,7 @@ CPRunContinuesResponse = -1002;
@param aWindow the window to search for a target
@param anAction the action to find a responder to
- @return the object that responds to the action, or nil
+ @return the object that responds to the action, or \c nil
if no matching target was found
@ignore
*/
@@ -625,7 +660,7 @@ CPRunContinuesResponse = -1002;
the document controller
@param anAction the action to handle
- @return a target that can respond, or nil
+ @return a target that can respond, or \c nil
if no match could be found
*/
- (id)targetForAction:(SEL)anAction
@@ -667,6 +702,11 @@ CPRunContinuesResponse = -1002;
_eventListeners.push(_CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }));
}
+- (CPEvent)currentEvent
+{
+ return _currentEvent;
+}
+
// Managing Sheets
/*!
@@ -730,6 +770,14 @@ CPRunContinuesResponse = -1002;
return _namedArgs;
}
+- (BOOL)_openFile:(CPString)aFilename
+{
+ if (_delegate && [_delegate respondsToSelector:@selector(application:openFile:)])
+ return [_delegate application:self openFile:aFilename];
+ else
+ return [_documentController openDocumentWithContentsOfURL:aFilename display:YES error:NULL];
+}
+
@end
var _CPModalSessionMake = function(aWindow, aStopCode)
@@ -755,7 +803,7 @@ var _CPRunModalLoop = function(anEvent)
/*!
Starts the GUI and Cappuccino frameworks. This function should be
- called from the main() function of your program.
+ called from the \c main() function of your program.
@class CPApplication
@return void
*/
@@ -771,14 +819,18 @@ function CPApplicationMain(args, namedArgs)
[principalClass sharedApplication];
//FIXME?
- if (!args && !namedArgs)
+ if (!args)
{
- var args = [CPApp arguments],
- searchParams = window.location.search.substring(1).split("&");
- namedArgs = [CPDictionary dictionary];
+ var args = [CPApp arguments];
if([args containsObject:"debug"])
CPLogRegister(CPLogPopup);
+ }
+
+ if (!namedArgs)
+ {
+ var searchParams = window.location.search.substring(1).split("&");
+ namedArgs = [CPDictionary dictionary];
for(var i=0; iYES if the button has a 'mixed' state in addition to on and off.
+ Returns \c YES if the button has a 'mixed' state in addition to on and off.
*/
- (BOOL)allowsMixedState
{
@@ -248,9 +248,9 @@ CPButtonStateMixed = CPThemeState("mixed");
}
/*!
- Sets the button's state to aState.
+ Sets the button's state to \c aState.
@param aState Possible states are any of the CPButton globals:
- CPOffState, CPOnState, CPMixedState
+ \c CPOffState, \c CPOnState, \c CPMixedState
*/
- (void)setState:(CPInteger)aState
{
@@ -602,7 +602,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
@implementation CPButton (CPCoding)
/*!
- Initializes the button by unarchiving data from aCoder.
+ Initializes the button by unarchiving data from \c aCoder.
@param aCoder the coder containing the archived CPButton.
*/
- (id)initWithCoder:(CPCoder)aCoder
diff --git a/AppKit/CPClipView.j b/AppKit/CPClipView.j
index 6349ed58e..cae93bd44 100644
--- a/AppKit/CPClipView.j
+++ b/AppKit/CPClipView.j
@@ -38,8 +38,8 @@
}
/*!
- Sets the document view to be aView.
- @param aView the new document view. It's frame origin will be changed to (0,0) after calling this method.
+ Sets the document view to be \c aView.
+ @param aView the new document view. It's frame origin will be changed to \c (0,0) after calling this method.
*/
- (void)setDocumentView:(CPView)aView
{
@@ -95,7 +95,7 @@
}
/*!
- Returns a new point that may be adjusted from aPoint
+ Returns a new point that may be adjusted from \c aPoint
to make sure it lies within the document view.
@param aPoint
@return the adjusted point
@@ -128,7 +128,7 @@
/*!
Scrolls the clip view to the specified point. The method
- sets its bounds origin to aPoint.
+ sets its bounds origin to \c aPoint.
*/
- (void)scrollToPoint:(CGPoint)aPoint
{
diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j
index 325175309..b59710e75 100644
--- a/AppKit/CPCollectionView.j
+++ b/AppKit/CPCollectionView.j
@@ -26,7 +26,8 @@
@import
@import
-@import
+@import "CPView.j"
+@import "CPCollectionViewItem.j"
/*!
@@ -61,6 +62,7 @@
@param indices the indices to obtain drag types
@return an array of drag types (CPString)
*/
+
@implementation CPCollectionView : CPView
{
CPArray _content;
@@ -76,7 +78,9 @@
CGSize _minItemSize;
CGSize _maxItemSize;
-
+
+ CPArray _backgroundColors;
+
float _tileWidth;
BOOL _isSelectable;
@@ -93,6 +97,8 @@
unsigned _numberOfColumns;
id _delegate;
+
+ CPEvent _mouseDownEvent;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -109,7 +115,9 @@
_itemSize = CGSizeMakeZero();
_minItemSize = CGSizeMakeZero();
_maxItemSize = CGSizeMakeZero();
-
+
+ [self setBackgroundColors:nil];
+
_verticalMargin = 5.0;
_tileWidth = -1.0;
@@ -122,15 +130,16 @@
}
/*!
- Sets the item prototype to anItem
+ Sets the item prototype to \c anItem
@param anItem the new item prototype
*/
- (void)setItemPrototype:(CPCollectionViewItem)anItem
{
- _itemData = [CPKeyedArchiver archivedDataWithRootObject:anItem];
- _itemForDragging = anItem//[CPKeyedUnarchiver unarchiveObjectWithData:_itemData];
+ _cachedItems = [];
+ _itemData = nil;
+ _itemForDragging = nil;
_itemPrototype = anItem;
-
+
[self reloadContent];
}
@@ -143,17 +152,24 @@
}
/*!
- Returns a collection view item for anObject.
+ Returns a collection view item for \c anObject.
@param anObject the object to be represented.
*/
- (CPCollectionViewItem)newItemForRepresentedObject:(id)anObject
{
var item = nil;
-
+
if (_cachedItems.length)
item = _cachedItems.pop();
+
else
+ {
+ if (!_itemData)
+ if (_itemPrototype)
+ _itemData = [CPKeyedArchiver archivedDataWithRootObject:_itemPrototype];
+
item = [CPKeyedUnarchiver unarchiveObjectWithData:_itemData];
+ }
[item setRepresentedObject:anObject];
[[item view] setFrameSize:_itemSize];
@@ -163,7 +179,7 @@
// Working with the Responder Chain
/*!
- Returns YES by default.
+ Returns \c YES by default.
*/
- (BOOL)acceptsFirstResponder
{
@@ -175,13 +191,13 @@
*/
- (BOOL)isFirstResponder
{
- return [[self window] firstResponder] == self;
+ return [[self window] firstResponder] === self;
}
// Setting the Content
/*!
- Sets the content of the collection view to the content in anArray.
- This array can be of any type, and each element will be passed to the setRepresentedObject: method.
+ Sets the content of the collection view to the content in \c anArray.
+ This array can be of any type, and each element will be passed to the \c -setRepresentedObject: method.
It's the responsibility of your custom collection view item to interpret the object.
@param anArray the content array
*/
@@ -214,7 +230,7 @@
// Setting the Selection Mode
/*!
Sets whether the user is allowed to select items
- @param isSelectable YES allows the user to select items.
+ @param isSelectable \c YES allows the user to select items.
*/
- (void)setSelectable:(BOOL)isSelectable
{
@@ -233,8 +249,8 @@
}
/*!
- Returns YES if the collection view is
- selected, and NO otherwise.
+ Returns \c YES if the collection view is
+ selected, and \c NO otherwise.
*/
- (BOOL)isSelected
{
@@ -243,7 +259,7 @@
/*!
Sets whether the user may have no items selected. If YES, mouse clicks not on any item will empty the current selection. The first item will also start off as selected.
- @param shouldAllowMultipleSelection YES allows the user to select multiple items
+ @param shouldAllowMultipleSelection \c YES allows the user to select multiple items
*/
- (void)setAllowsEmptySelection:(BOOL)shouldAllowEmptySelection
{
@@ -251,7 +267,7 @@
}
/*!
- Returns YES if the user can select no items, NO otherwise.
+ Returns \c YES if the user can select no items, \c NO otherwise.
*/
- (BOOL)allowsEmptySelection
{
@@ -260,7 +276,7 @@
/*!
Sets whether the user can select multiple items.
- @param shouldAllowMultipleSelection YES allows the user to select multiple items
+ @param shouldAllowMultipleSelection \c YES allows the user to select multiple items
*/
- (void)setAllowsMultipleSelection:(BOOL)shouldAllowMultipleSelection
{
@@ -268,7 +284,7 @@
}
/*!
- Returns YES if the user can select multiple items, NO otherwise.
+ Returns \c YES if the user can select multiple items, \c NO otherwise.
*/
- (BOOL)allowsMultipleSelection
{
@@ -322,13 +338,13 @@
_items = [];
- if (!_itemData || !_content)
+ if (!_itemPrototype || !_content)
return;
-
+
var index = 0;
-
+
count = _content.length;
-
+
for (; index < count; ++index)
{
_items.push([self newItemForRepresentedObject:_content[index]]);
@@ -520,6 +536,30 @@
return _maxItemSize;
}
+- (void)setBackgroundColors:(CPArray)backgroundColors
+{
+ if (_backgroundColors === backgroundColors)
+ return;
+
+ _backgroundColors = backgroundColors;
+
+ if (!_backgroundColors)
+ _backgroundColors = [CPColor whiteColor];
+
+ if ([_backgroundColors count] === 1)
+ [self setBackgroundColor:_backgroundColors[0]];
+
+ else
+ [self setBackgroundColor:nil];
+
+ [self setNeedsDisplay:YES];
+}
+
+- (CPArray)backgroundColors
+{
+ return _backgroundColors;
+}
+
- (void)mouseUp:(CPEvent)anEvent
{
if ([_selectionIndexes count] && [anEvent clickCount] == 2 && [_delegate respondsToSelector:@selector(collectionView:didDoubleClickOnItemAtIndex:)])
@@ -528,13 +568,16 @@
- (void)mouseDown:(CPEvent)anEvent
{
+ _mouseDownEvent = anEvent;
+
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
row = FLOOR(location.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(location.x / (_itemSize.width + _horizontalMargin)),
index = row * _numberOfColumns + column;
-
+
if (index >= 0 && index < _items.length)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
+
else if (_allowsEmptySelection)
[self setSelectionIndexes:[CPIndexSet indexSet]];
}
@@ -543,30 +586,32 @@
{
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
return;
-
+
// If we don't have any selected items, we've clicked away, and thus the drag is meaningless.
if (![_selectionIndexes count])
return;
-
+
// Set up the pasteboard
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
-
+
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
-
+
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
- [_itemForDragging setRepresentedObject:_content[[_selectionIndexes firstIndex]]];
+ if (!_itemForDragging)
+ _itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
+ else
+ [_itemForDragging setRepresentedObject:_content[[_selectionIndexes firstIndex]]];
+
+ var view = [_itemForDragging view];
- var view = [_itemForDragging view],
- frame = [view frame];
-
[view setFrameSize:_itemSize];
[view setAlphaValue:0.7];
-
+
[self dragView:view
at:[[_items[[_selectionIndexes firstIndex]] view] frame].origin
- offset:CGPointMakeZero()
- event:anEvent
+ offset:CGSizeMakeZero()
+ event:_mouseDownEvent
pasteboard:nil
source:self
slideBack:YES];
@@ -627,98 +672,10 @@
@end
-/*!
- Represents an object inside a CPCollectionView.
-*/
-@implementation CPCollectionViewItem : CPObject
-{
- id _representedObject;
-
- CPView _view;
-
- BOOL _isSelected;
-}
-
-// Setting the Represented Object
-/*!
- Sets the object to be represented by this item.
- @param anObject the object to be represented
-*/
-- (void)setRepresentedObject:(id)anObject
-{
- if (_representedObject == anObject)
- return;
-
- _representedObject = anObject;
-
- // FIXME: This should be set up by bindings
- [_view setRepresentedObject:anObject];
-}
-
-/*!
- Returns the object represented by this view item
-*/
-- (id)representedObject
-{
- return _representedObject;
-}
-
-// Modifying the View
-/*!
- Sets the view that is used represent this object.
- @param aView the view used to represent this object
-*/
-- (void)setView:(CPView)aView
-{
- _view = aView;
-}
-
-/*!
- Returns the view that represents this object.
-*/
-- (CPView)view
-{
- return _view;
-}
-
-// Modifying the Selection
-/*!
- Sets whether this view item should be selected.
- @param shouldBeSelected YES makes the item selected. NO deselects it.
-*/
-- (void)setSelected:(BOOL)shouldBeSelected
-{
- if (_isSelected == shouldBeSelected)
- return;
-
- _isSelected = shouldBeSelected;
-
- // FIXME: This should be set up by bindings
- [_view setSelected:_isSelected];
-}
-
-/*!
- Returns YES if the item is currently selected. NO if the item is not selected.
-*/
-- (BOOL)isSelected
-{
- return _isSelected;
-}
-
-// Parent Collection View
-/*!
- Returns the collection view of which this item is a part.
-*/
-- (CPCollectionView)collectionView
-{
- return [_view superview];
-}
-
-@end
-
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
- CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey";
+ CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
+ CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
@implementation CPCollectionView (CPCoding)
@@ -735,13 +692,19 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
_cachedItems = [];
_itemSize = CGSizeMakeZero();
- _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey];
- _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey];
+
+ _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
+ _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
+ _verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
- _verticalMargin = [aCoder decodeSizeForKey:CPCollectionViewVerticalMarginKey];
+ [self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
+
_tileWidth = -1.0;
_selectionIndexes = [CPIndexSet indexSet];
+
+ _allowsEmptySelection = YES;
+ _isSelectable = YES;
}
return self;
@@ -751,54 +714,15 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
{
[super encodeWithCoder:aCoder];
- [aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
- [aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
+ if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
+ [aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
- [aCoder encodeSize:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
+ if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
+ [aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
+
+ [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
+
+ [aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];
}
@end
-
-var CPCollectionViewItemViewKey = @"CPCollectionViewItemViewKey";
-
-@implementation CPCollectionViewItem (CPCoding)
-
-/*
- FIXME Not yet implemented
-*/
-- (id)copy
-{
-
-}
-
-@end
-
-var CPCollectionViewItemViewKey = @"CPCollectionViewItemViewKey";
-
-@implementation CPCollectionViewItem (CPCoding)
-
-/*!
- Initializes the view item by unarchiving data from a coder.
- @param aCoder the coder from which the data will be unarchived
- @return the initialized collection view item
-*/
-- (id)initWithCoder:(CPCoder)aCoder
-{
- self = [super init];
-
- if (self)
- _view = [aCoder decodeObjectForKey:CPCollectionViewItemViewKey];
-
- return self;
-}
-
-/*!
- Archives the colletion view item to the provided coder.
- @param aCoder the coder to which the view item should be archived
-*/
-- (void)encodeWithCoder:(CPCoder)aCoder
-{
- [aCoder encodeObject:_view forKey:CPCollectionViewItemViewKey];
-}
-
-@end
\ No newline at end of file
diff --git a/AppKit/CPCollectionViewItem.j b/AppKit/CPCollectionViewItem.j
new file mode 100644
index 000000000..1711df6c0
--- /dev/null
+++ b/AppKit/CPCollectionViewItem.j
@@ -0,0 +1,85 @@
+/*
+ * CPCollectionViewItem.j
+ * AppKit
+ *
+ * Created by Francisco Tolmasky.
+ * Copyright 2009, 280 North, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+@import "CPViewController.j"
+
+/*!
+ Represents an object inside a CPCollectionView.
+*/
+@implementation CPCollectionViewItem : CPViewController
+{
+ BOOL _isSelected;
+}
+
+// Setting the Represented Object
+/*!
+ Sets the object to be represented by this item.
+ @param anObject the object to be represented
+*/
+- (void)setRepresentedObject:(id)anObject
+{
+ [super setRepresentedObject:anObject];
+
+ var view = [self view];
+
+ if ([view respondsToSelector:@selector(setRepresentedObject:)])
+ [view setRepresentedObject:[self representedObject]];
+}
+
+// Modifying the Selection
+/*!
+ Sets whether this view item should be selected.
+ @param shouldBeSelected \c YES makes the item selected. \c NO deselects it.
+*/
+- (void)setSelected:(BOOL)shouldBeSelected
+{
+ shouldBeSelected = !!shouldBeSelected;
+
+ if (_isSelected === shouldBeSelected)
+ return;
+
+ _isSelected = shouldBeSelected;
+
+ var view = [self view];
+
+ if ([view respondsToSelector:@selector(setSelected:)])
+ [view setSelected:[self isSelected]];
+}
+
+/*!
+ Returns \c YES if the item is currently selected. \c NO if the item is not selected.
+*/
+- (BOOL)isSelected
+{
+ return _isSelected;
+}
+
+// Parent Collection View
+/*!
+ Returns the collection view of which this item is a part.
+*/
+- (CPCollectionView)collectionView
+{
+ return [_view superview];
+}
+
+@end
diff --git a/AppKit/CPColor.j b/AppKit/CPColor.j
index d4188c92e..636f96a3f 100644
--- a/AppKit/CPColor.j
+++ b/AppKit/CPColor.j
@@ -46,6 +46,11 @@ var cachedBlackColor,
cachedLightGrayColor,
cachedDarkGrayColor,
cachedWhiteColor,
+ cachedBrownColor,
+ cachedCyanColor,
+ cachedMagentaColor,
+ cachedOrangeColor,
+ cachedPurpleColor,
cachedShadowColor,
cachedClearColor;
@@ -53,13 +58,13 @@ var cachedBlackColor,
@ingroup appkit
@code CPColor
- CPColor can be used to represent color
+ \c CPColor can be used to represent color
in an RGB or HSB model with an optional transparency value.
It also provides some class helper methods that
returns instances of commonly used colors.
-
The class does not have a set: method
+
The class does not have a \c -set: method
like NextStep based frameworks to change the color of
the current context. To change the color of the current
context, use CGContextSetFillColor().
@@ -112,7 +117,7 @@ var cachedBlackColor,
/*!
- Creates a new color object with white for the RGB components.
+ Creates a new color object with \c white for the RGB components.
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
@param white a float between 0.0 and 1.0
@@ -128,7 +133,7 @@ var cachedBlackColor,
/*!
@deprecated in favor of colorWithWhite:apha:
- Creates a new color object with white for the RGB components.
+ Creates a new color object with \c white for the RGB components.
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
@param white a float between 0.0 and 1.0
@@ -291,6 +296,61 @@ var cachedBlackColor,
return cachedYellowColor;
}
+/*!
+ Returns a brown color object (RGBA=[0.6, 0.4, 0.2, 1.0])
+*/
++ (CPColor)brownColor
+{
+ if (!cachedBrownColor)
+ cachedBrownColor = [[CPColor alloc] _initWithRGBA:[0.6, 0.4, 0.2, 1.0]];
+
+ return cachedBrownColor;
+}
+
+/*!
+ Returns a cyan color object (RGBA=[0.0, 1.0, 1.0, 1.0])
+*/
++ (CPColor)cyanColor
+{
+ if (!cachedCyanColor)
+ cachedCyanColor = [[CPColor alloc] _initWithRGBA:[0.0, 1.0, 1.0, 1.0]];
+
+ return cachedCyanColor;
+}
+
+/*!
+ Returns a magenta color object (RGBA=[1.0, 0.0, 1.0, 1.0])
+*/
++ (CPColor)magentaColor
+{
+ if (!cachedMagentaColor)
+ cachedMagentaColor = [[CPColor alloc] _initWithRGBA:[1.0, 0.0, 1.0, 1.0]];
+
+ return cachedMagentaColor;
+}
+
+/*!
+ Returns a orange color object (RGBA=[1.0, 0.5, 0.0, 1.0])
+*/
++ (CPColor)orangeColor
+{
+ if (!cachedOrangeColor)
+ cachedOrangeColor = [[CPColor alloc] _initWithRGBA:[1.0, 0.5, 0.0, 1.0]];
+
+ return cachedOrangeColor;
+}
+
+/*!
+ Returns a purple color object (RGBA=[0.5, 0.0, 0.5, 1.0])
+*/
++ (CPColor)purpleColor
+{
+ if (!cachedPurpleColor)
+ cachedPurpleColor = [[CPColor alloc] _initWithRGBA:[0.5, 0.0, 0.5, 1.0]];
+
+ return cachedPurpleColor;
+}
+
/*!
Returns a shadow looking color (RGBA=[0.0, 0.0, 0.0, 0.33])
*/
@@ -315,8 +375,18 @@ var cachedBlackColor,
return cachedClearColor;
}
++ (CPColor)alternateSelectedControlColor
+{
+ return [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]];
+}
+
++ (CPColor)secondarySelectedControlColor
+{
+ return [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]];
+}
+
/*!
- Creates a color using a tile pattern with anImage
+ Creates a color using a tile pattern with \c anImage
@param the image to tile
@return a tiled image color object
*/
@@ -666,7 +736,7 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
var hexCharacters = "0123456789ABCDEF";
/*!
- Used for the CPColor colorWithHexString: implementation
+ Used for the CPColor \c +colorWithHexString: implementation
@ignore
@class CPColor
@return an array of rgb components
diff --git a/AppKit/CPColorPanel.j b/AppKit/CPColorPanel.j
index 1dde0cd52..4c57cf99a 100644
--- a/AppKit/CPColorPanel.j
+++ b/AppKit/CPColorPanel.j
@@ -58,7 +58,7 @@ CPColorPickerViewHeight = 370;
CPColorPanel provides a reusable panel that can be used
displayed on screen to prompt the user for a color selection. To
- obtain the panel, call the sharedColorPanel method.
+ obtain the panel, call the \c +sharedColorPanel method.
*/
@implementation CPColorPanel : CPPanel
{
@@ -111,7 +111,7 @@ CPColorPickerViewHeight = 370;
}
/*
- To obtain the color panel, use sharedColorPanel.
+ To obtain the color panel, use \c +sharedColorPanel.
@ignore
*/
- (id)init
@@ -137,7 +137,7 @@ CPColorPickerViewHeight = 370;
}
/*!
- Sets the color of the panel, and updates the picker. Also posts a CPColorPanelDidChangeNotification.
+ Sets the color of the panel, and updates the picker. Also posts a \c CPColorPanelDidChangeNotification.
*/
- (void)setColor:(CPColor)aColor
{
@@ -491,7 +491,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
var future = new Date();
future.setYear(2019);
- [_swatchCookie setValue: CPJSObjectCreateJSON(result) expires:future domain: nil];
+ [_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
}
- (void)setColorPanel:(CPColorPanel)panel
diff --git a/AppKit/CPColorPicker.j b/AppKit/CPColorPicker.j
index eeb0e8c60..f8e89f334 100644
--- a/AppKit/CPColorPicker.j
+++ b/AppKit/CPColorPicker.j
@@ -27,7 +27,7 @@
@ingroup appkit
@class CPColorPicker
- CPColorPicker is an abstract superclass for all color picker subclasses. If you want a particular color picker, use CPColorPanel's setPickerMode: method. The simplest way to implement your own color picker is to create a subclass of CPColorPicker.
+ CPColorPicker is an abstract superclass for all color picker subclasses. If you want a particular color picker, use CPColorPanel's \c +setPickerMode: method. The simplest way to implement your own color picker is to create a subclass of CPColorPicker.
*/
@implementation CPColorPicker : CPObject
{
@@ -60,7 +60,7 @@
/*
FIXME Not implemented.
- @return nil
+ @return \c nil
@ignore
*/
- (CPImage)provideNewButtonImage
diff --git a/AppKit/CPColorWell.j b/AppKit/CPColorWell.j
index 355f7c739..2c2586821 100644
--- a/AppKit/CPColorWell.j
+++ b/AppKit/CPColorWell.j
@@ -35,7 +35,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
CPColorWell is a CPControl for selecting and displaying a single color value. An example of a CPColorWell object (or simply color well) is found in CPColorPanel, which uses a color well to display the current color selection.
-
An application can have one or more active CPColorWells. You can activate multiple CPColorWells by invoking the activate: method with NO as its argument. When a mouse-down event occurs on an CPColorWell's border, it becomes the only active color well. When a color well becomes active, it brings up the color panel also.
+
An application can have one or more active CPColorWells. You can activate multiple CPColorWells by invoking the \c -activate: method with \c NO as its argument. When a mouse-down event occurs on an CPColorWell's border, it becomes the only active color well. When a color well becomes active, it brings up the color panel also.
*/
@implementation CPColorWell : CPControl
{
@@ -127,7 +127,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
}
/*!
- Changes the color of the well to that of aSender.
+ Changes the color of the well to that of \c aSender.
@param aSender the object from which to retrieve the color
*/
- (void)takeColorFrom:(id)aSender
@@ -138,7 +138,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
// Activating and Deactivating Color Wells
/*!
Activates the color well, displays the color panel, and makes the panel's current color the same as its own.
- If exclusive is YES, deactivates any other CPColorWells. NO, keeps them active.
+ If exclusive is \c YES, deactivates any other CPColorWells. \c NO, keeps them active.
@param shouldBeExclusive whether other color wells should be deactivated.
*/
- (void)activate:(BOOL)shouldBeExclusive
@@ -179,7 +179,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
}
/*!
- Returns YES if the color well is active.
+ Returns \c YES if the color well is active.
*/
- (BOOL)isActive
{
@@ -262,7 +262,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
@implementation CPColorWell (CPCoding)
/*!
- Initializes the color well by unarchiving data from aCoder.
+ Initializes the color well by unarchiving data from \c aCoder.
@param aCoder the coder containing the archived CPColorWell.
*/
- (id)initWithCoder:(CPCoder)aCoder
diff --git a/AppKit/CPCompatibility.j b/AppKit/CPCompatibility.j
index 2ba69a747..b381cd359 100644
--- a/AppKit/CPCompatibility.j
+++ b/AppKit/CPCompatibility.j
@@ -35,17 +35,18 @@ CPCSSRGBAFeature = 1 << 5;
CPHTMLCanvasFeature = 1 << 6;
CPHTMLContentEditableFeature = 1 << 7;
+CPHTMLDragAndDropFeature = 1 << 8;
-CPJavascriptInnerTextFeature = 1 << 8;
-CPJavascriptTextContentFeature = 1 << 9;
-CPJavascriptClipboardEventsFeature = 1 << 10;
-CPJavascriptClipboardAccessFeature = 1 << 11;
-CPJavaScriptCanvasDrawFeature = 1 << 12;
-CPJavaScriptCanvasTransformFeature = 1 << 13;
+CPJavascriptInnerTextFeature = 1 << 9;
+CPJavascriptTextContentFeature = 1 << 10;
+CPJavascriptClipboardEventsFeature = 1 << 11;
+CPJavascriptClipboardAccessFeature = 1 << 12;
+CPJavaScriptCanvasDrawFeature = 1 << 13;
+CPJavaScriptCanvasTransformFeature = 1 << 14;
-CPVMLFeature = 1 << 14;
+CPVMLFeature = 1 << 15;
-CPJavascriptRemedialKeySupport = 1 << 15;
+CPJavascriptRemedialKeySupport = 1 << 16;
CPJavaScriptShadowFeature = 1 << 20;
CPJavaScriptNegativeMouseWheelValues = 1 << 22;
@@ -54,7 +55,8 @@ CPJavaScriptMouseWheelValues_8_15 = 1 << 23
CPOpacityRequiresFilterFeature = 1 << 24;
//Internet explorer does not allow dynamically changing the type of an input element
-CPInputTypeCanBeChangedFeature = 1 << 25;
+CPInputTypeCanBeChangedFeature = 1 << 25;
+
@@ -100,15 +102,19 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
// Features we can only be sure of with WebKit (no known independent tests)
PLATFORM_FEATURES |= CPCSSRGBAFeature;
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
+ PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
versionEnd = USER_AGENT.indexOf(" ", versionStart),
- version = parseFloat(USER_AGENT.substring(versionStart, versionEnd), 10);
+ versionString = USER_AGENT.substring(versionStart, versionEnd),
+ versionDivision = versionString.indexOf('.'),
+ majorVersion = parseInt(versionString.substring(0, versionDivision)),
+ minorVersion = parseInt(versionString.substr(versionDivision + 1));
- if(USER_AGENT.indexOf("Plainview") == -1 && version >= 525.14 || USER_AGENT.indexOf("Chrome") != -1)
+ if((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion >= 525 && minorVersion > 14)) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
}
diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j
index 6fe63b8a8..87d11f5f7 100644
--- a/AppKit/CPControl.j
+++ b/AppKit/CPControl.j
@@ -100,9 +100,6 @@ var CPControlBlackColor = [CPColor blackColor];
BOOL _trackingWasWithinFrame;
unsigned _trackingMouseDownFlags;
CGPoint _previousTrackingLocation;
-
- JSObject _ephemeralSubviewsForNames;
- CPSet _ephereralSubviews;
CPString _toolTip;
}
@@ -181,7 +178,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
- Causes anAction to be sent to anObject.
+ Causes \c anAction to be sent to \c anObject.
@param anAction the action to send
@param anObject the object to which the action will be sent
*/
@@ -304,6 +301,15 @@ var CPControlBlackColor = [CPColor blackColor];
[self highlight:NO];
}
+- (void)setState:(int)state
+{
+}
+
+- (int)nextState
+{
+ return 0;
+}
+
- (unsigned)mouseDownFlags
{
return _trackingMouseDownFlags;
@@ -505,10 +511,12 @@ var CPControlBlackColor = [CPColor blackColor];
}
#define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
+/*! Sets the value for ATTRIBUTENAME */\
- (void)set##UPPERCASE:(id)aValue\
{\
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
}\
+/*! Returns the current value for ATTRIBUTENAME */\
- (id)LOWERCASE\
{\
return [self valueForThemeAttribute:ATTRIBUTENAME];\
@@ -555,54 +563,6 @@ BRIDGE(ImageScaling, imageScaling, "image-scaling")
return [self hasThemeState:CPThemeStateHighlighted];
}
-- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
-{
- return nil;
-}
-
-- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
-{
- return _CGRectMakeZero();
-}
-
-- (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName
- positioned:(CPWindowOrderingMode)anOrderingMode
- relativeToEphemeralSubviewNamed:(CPString)relativeToViewName
-{
- if (!_ephemeralSubviewsForNames)
- {
- _ephemeralSubviewsForNames = {};
- _ephemeralSubviews = [CPSet set];
- }
-
- var frame = [self rectForEphemeralSubviewNamed:aViewName];
-
- if (frame && !_CGRectIsEmpty(frame))
- {
- if (!_ephemeralSubviewsForNames[aViewName])
- {
- _ephemeralSubviewsForNames[aViewName] = [self createEphemeralSubviewNamed:aViewName];
-
- [_ephemeralSubviews addObject:_ephemeralSubviewsForNames[aViewName]];
-
- if (_ephemeralSubviewsForNames[aViewName])
- [self addSubview:_ephemeralSubviewsForNames[aViewName] positioned:anOrderingMode relativeTo:_ephemeralSubviewsForNames[relativeToViewName]];
- }
-
- if (_ephemeralSubviewsForNames[aViewName])
- [_ephemeralSubviewsForNames[aViewName] setFrame:frame];
- }
- else if (_ephemeralSubviewsForNames[aViewName])
- {
- [_ephemeralSubviewsForNames[aViewName] removeFromSuperview];
-
- [_ephemeralSubviews removeObject:_ephemeralSubviewsForNames[aViewName]];
- delete _ephemeralSubviewsForNames[aViewName];
- }
-
- return _ephemeralSubviewsForNames[aViewName];
-}
-
@end
var CPControlValueKey = "CPControlValueKey",
@@ -645,24 +605,8 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
- var count = [_subviews count],
- ephemeral
- subviews = nil;
-
- if (count > 0 && [_ephemeralSubviews count] > 0)
- {
- subviews = [_subviews.slice(0) copy];
-
- while (count--)
- if ([_ephemeralSubviews containsObject:_subviews[count]])
- _subviews.splice(count, 1);
- }
-
[super encodeWithCoder:aCoder];
- if (subviews)
- _subviews = subviews;
-
if (_value !== nil)
[aCoder encodeObject:_value forKey:CPControlValueKey];
diff --git a/AppKit/CPCookie.j b/AppKit/CPCookie.j
index 2be313551..5a5694a94 100644
--- a/AppKit/CPCookie.j
+++ b/AppKit/CPCookie.j
@@ -38,7 +38,7 @@
}
/*!
- Initializes a cookie with a given name aName.
+ Initializes a cookie with a given name \c aName.
@param the name for the cookie
*/
- (id)initWithName:(CPString)aName
diff --git a/AppKit/CPDocument.j b/AppKit/CPDocument.j
index b39506c37..82159b55f 100644
--- a/AppKit/CPDocument.j
+++ b/AppKit/CPDocument.j
@@ -24,6 +24,7 @@
@import
@import "CPResponder.j"
+@import "CPViewController.j"
@import "CPWindowController.j"
@@ -90,19 +91,23 @@ var CPDocumentUntitledCount = 0;
CPDocuments should be used to represent this.
*/
@implementation CPDocument : CPResponder
-{
- CPURL _fileURL;
- CPString _fileType;
- CPArray _windowControllers;
- unsigned _untitledDocumentIndex;
+{
+ CPWindow _window; // For outlet purposes.
+ CPView _view; // For outlet purposes
+ CPDictionary _viewControllersForWindowControllers;
- BOOL _hasUndoManager;
- CPUndoManager _undoManager;
-
- int _changeCount;
-
- CPURLConnection _readConnection;
- CPURLRequest _writeRequest;
+ CPURL _fileURL;
+ CPString _fileType;
+ CPArray _windowControllers;
+ unsigned _untitledDocumentIndex;
+
+ BOOL _hasUndoManager;
+ CPUndoManager _undoManager;
+
+ int _changeCount;
+
+ CPURLConnection _readConnection;
+ CPURLRequest _writeRequest;
}
/*!
@@ -116,10 +121,11 @@ var CPDocumentUntitledCount = 0;
if (self)
{
_windowControllers = [];
-
+ _viewControllersForWindowControllers = [CPDictionary dictionary];
+
_hasUndoManager = YES;
_changeCount = 0;
-
+
[self setNextResponder:CPApp];
}
@@ -159,10 +165,10 @@ var CPDocumentUntitledCount = 0;
if (self)
{
- [self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
-
[self setFileURL:anAbsoluteURL];
[self setFileType:aType];
+
+ [self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
}
return self;
@@ -174,8 +180,8 @@ var CPDocumentUntitledCount = 0;
@param absoluteContentsURL the location of the document's contents
@param aType the type of the contents
@param aDelegate this object will receive a callback after the document's contents are loaded
- @param aDidReadSelector the message selector that will be sent to aDelegate
- @param aContextInfo passed as the argument to the message sent to the aDelegate
+ @param aDidReadSelector the message selector that will be sent to \c aDelegate
+ @param aContextInfo passed as the argument to the message sent to the \c aDelegate
@return the initialized document
*/
- (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
@@ -184,10 +190,10 @@ var CPDocumentUntitledCount = 0;
if (self)
{
- [self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
-
[self setFileURL:anAbsoluteURL];
[self setFileType:aType];
+
+ [self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
}
return self;
@@ -222,15 +228,68 @@ var CPDocumentUntitledCount = 0;
reason:"readFromData:ofType: must be overridden by the document subclass."];
}
+- (void)viewControllerWillLoadCib:(CPViewController)aViewController
+{
+}
+
+- (void)viewControllerDidLoadCib:(CPViewController)aViewController
+{
+}
+
+- (CPWindowController)firstEligibleExistingWindowController
+{
+ return nil;
+}
+
// Creating and managing window controllers
/*!
Creates the window controller for this document.
*/
- (void)makeWindowControllers
{
- var controller = [[CPWindowController alloc] initWithWindowCibName:nil];
-
- [self addWindowController:controller];
+ [self makeViewAndWindowControllers];
+}
+
+- (void)makeViewAndWindowControllers
+{
+ var viewCibName = [self viewCibName],
+ viewController = nil,
+ windowController = nil;
+
+ // Create our view controller if we have a cib for it.
+ if ([viewCibName length])
+ viewController = [[CPViewController alloc] initWithCibName:viewCibName bundle:nil owner:self];
+
+ // If we have a view controller, check if we have a free window for it.
+ if (viewController)
+ windowController = [self firstEligibleExistingWindowController];
+
+ // If not, create one.
+ if (!windowController)
+ {
+ var windowCibName = [self windowCibName];
+
+ // From a cib if we have one.
+ if ([windowCibName length])
+ windowController = [[CPWindowController alloc] initWithWindowCibName:windowCibName owner:self];
+
+ // If not you get a standard window capable of displaying multiple documents and view
+ else if (viewController)
+ {
+ var view = [viewController view],
+ theWindow = [[CPWindow alloc] initWithContentRect:[view frame] styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
+
+ [theWindow setSupportsMultipleDocuments:YES];
+
+ windowController = [[CPWindowController alloc] initWithWindow:theWindow];
+ }
+ }
+
+ if (windowController)
+ [self addWindowController:windowController];
+
+ if (viewController)
+ [self addViewController:viewController forWindowController:windowController];
}
/*!
@@ -249,20 +308,50 @@ var CPDocumentUntitledCount = 0;
- (void)addWindowController:(CPWindowController)aWindowController
{
[_windowControllers addObject:aWindowController];
-
- if ([aWindowController document] != self)
+
+ if ([aWindowController document] !== self)
{
[aWindowController setNextResponder:self];
[aWindowController setDocument:self];
}
}
+- (CPView)view
+{
+ return _view;
+}
+
+- (CPArray)viewControllers
+{
+ return [_viewControllersForWindowControllers allValues];
+}
+
+- (void)addViewController:(CPViewController)aViewController forWindowController:(CPWindowController)aWindowController
+{
+ // FIXME: exception if we don't own the window controller?
+ [_viewControllersForWindowControllers setObject:aViewController forKey:[aWindowController UID]];
+
+ if ([aWindowController document] === self)
+ [aWindowController setViewController:aViewController];
+}
+
+- (void)removeViewController:(CPViewController)aViewController
+{
+ [_viewControllersForWindowControllers removeObject:aViewController];
+}
+
+- (CPViewController)viewControllerForWindowController:(CPWindowController)aWindowController
+{
+ return [_viewControllersForWindowControllers objectForKey:[aWindowController UID]];
+}
+
// Managing Document Windows
/*!
Shows all the document's windows.
*/
- (void)showWindows
{
+ [_windowControllers makeObjectsPerformSelector:@selector(setDocument:) withObject:self];
[_windowControllers makeObjectsPerformSelector:@selector(showWindow:) withObject:self];
}
@@ -283,6 +372,11 @@ var CPDocumentUntitledCount = 0;
return @"Untitled " + _untitledDocumentIndex;
}
+- (CPString)viewCibName
+{
+ return nil;
+}
+
/*!
Returns the document's Cib name
*/
@@ -292,18 +386,18 @@ var CPDocumentUntitledCount = 0;
}
/*!
- Called after aWindowController loads the document's Nib file.
+ Called after \c aWindowController loads the document's Nib file.
@param aWindowController the controller that loaded the Nib file
*/
-- (void)windowControllerDidLoadNib:(CPWindowController)aWindowController
+- (void)windowControllerDidLoadCib:(CPWindowController)aWindowController
{
}
/*!
- Called before aWindowController will load the document's Nib file.
+ Called before \c aWindowController will load the document's Nib file.
@param aWindowController the controller that will load the Nib file
*/
-- (void)windowControllerWillLoadNib:(CPWindowController)aWindowController
+- (void)windowControllerWillLoadCib:(CPWindowController)aWindowController
{
}
@@ -340,7 +434,7 @@ var CPDocumentUntitledCount = 0;
*/
- (void)setFileURL:(CPURL)aFileURL
{
- if (_fileURL == aFileURL)
+ if (_fileURL === aFileURL)
return;
_fileURL = aFileURL;
@@ -502,7 +596,7 @@ var CPDocumentUntitledCount = 0;
// Managing Document Status
/*!
- Returns YES if there are any unsaved changes.
+ Returns \c YES if there are any unsaved changes.
*/
- (BOOL)isDocumentEdited
{
@@ -548,7 +642,7 @@ var CPDocumentUntitledCount = 0;
// Working with Undo Manager
/*!
- Returns YES if the document has a
+ Returns \c YES if the document has a
CPUndoManager.
*/
- (BOOL)hasUndoManager
@@ -558,7 +652,7 @@ var CPDocumentUntitledCount = 0;
/*!
Sets whether the document should have a CPUndoManager.
- @param aFlag YES makes the document have an undo manager
+ @param aFlag \c YES makes the document have an undo manager
*/
- (void)setHasUndoManager:(BOOL)aFlag
{
@@ -642,7 +736,7 @@ var CPDocumentUntitledCount = 0;
/*!
Returns the document's undo manager. If the document
- should have one, but the manager is nil, it
+ should have one, but the manager is \c nil, it
will be created and then returned.
@return the document's undo manager
*/
@@ -666,8 +760,8 @@ var CPDocumentUntitledCount = 0;
// Handling User Actions
/*!
Saves the document. If the document does not
- have a file path to save to (fileURL)
- then saveDocumentAs: will be called.
+ have a file path to save to (\c fileURL)
+ then \c -saveDocumentAs: will be called.
@param aSender the object requesting the save
*/
- (void)saveDocument:(id)aSender
diff --git a/AppKit/CPDocumentController.j b/AppKit/CPDocumentController.j
index 0dff57fad..4a8f83724 100644
--- a/AppKit/CPDocumentController.j
+++ b/AppKit/CPDocumentController.j
@@ -78,7 +78,7 @@ var CPSharedDocumentController = nil;
method searches documents already open. It does not
open the document at the URL if it is not already open.
@param aURL the url of the document
- @return the document, or nil if such a document is not open
+ @return the document, or \c nil if such a document is not open
*/
- (CPDocument)documentForURL:(CPURL)aURL
{
@@ -157,7 +157,7 @@ var CPSharedDocumentController = nil;
@param anAbsoluteURL the document URL
@param absoluteContentsURL the location of the document's contents
@param anError not used
- @return the loaded document or nil if there was an error
+ @return the loaded document or \c nil if there was an error
*/
- (CPDocument)reopenDocumentForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL error:(CPError)anError
{
@@ -187,7 +187,7 @@ var CPSharedDocumentController = nil;
@param aDelegate receives a callback after the load has completed
@param aSelector the selector to invoke for the callback
@param aContextInfo an object passed as an argument for the callback
- @return a new document or nil if there was an error
+ @return a new document or \c nil if there was an error
*/
- (CPDocument)makeDocumentForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aSelector contextInfo:(id)aContextInfo
{
@@ -231,7 +231,7 @@ var CPSharedDocumentController = nil;
}
/*!
- Adds aDocument under the control of the receiver.
+ Adds \c aDocument under the control of the receiver.
@param aDocument the document to add
*/
- (void)addDocument:(CPDocument)aDocument
@@ -240,7 +240,7 @@ var CPSharedDocumentController = nil;
}
/*!
- Removes aDocument from the control of the receiver.
+ Removes \c aDocument from the control of the receiver.
@param aDocument the document to remove
*/
- (void)removeDocument:(CPDocument)aDocument
@@ -296,9 +296,9 @@ var CPSharedDocumentController = nil;
}
/*!
- Returns the CPDocument subclass associated with aType.
+ Returns the CPDocument subclass associated with \c aType.
@param aType the type of document
- @return a Cappuccino Class object, or nil if no match was found
+ @return a Cappuccino Class object, or \c nil if no match was found
*/
- (Class)documentClassForType:(CPString)aType
{
diff --git a/AppKit/CPDragServer.j b/AppKit/CPDragServer.j
index f39524a61..9d64de97d 100644
--- a/AppKit/CPDragServer.j
+++ b/AppKit/CPDragServer.j
@@ -26,73 +26,28 @@
@import
#import "CoreGraphics/CGGeometry.h"
+#import "Platform/Platform.h"
+CPDragOperationNone = 0,
+CPDragOperationCopy = 1 << 1,
+CPDragOperationLink = 1 << 1,
+CPDragOperationGeneric = 1 << 2,
+CPDragOperationPrivate = 1 << 3,
+CPDragOperationMove = 1 << 4,
+CPDragOperationDelete = 1 << 5,
+CPDragOperationEvery = -1;
+
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
-var CPSharedDragServer = nil;
-
-var CPDragServerView = nil,
- CPDragServerSource = nil,
- CPDragServerWindow = nil,
- CPDragServerOffset = nil,
- CPDragServerLocation = nil,
- CPDragServerPasteboard = nil,
- CPDragServerDestination = nil,
- CPDragServerDraggingInfo = nil,
- CPDragServerPreviousEvent = nil,
- CPDragServerAutoscrollInterval = nil;
-
-var CPDragServerIsDraggingImage = NO,
-
- CPDragServerShouldSendDraggedViewMovedTo = NO,
- CPDragServerShouldSendDraggedImageMovedTo = NO,
-
- CPDragServerShouldSendDraggedViewEndedAtOperation = NO,
- CPDragServerShouldSendDraggedImageEndedAtOperation = NO;
-
+var CPDragServerPreviousEvent = nil,
+CPDragServerAutoscrollInterval = nil;
+/*
var CPDragServerAutoscroll = function()
{
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
}
-var CPDragServerStartDragging = function(anEvent)
-{
- CPDragServerUpdateDragging(anEvent);
-}
-
-var CPDragServerUpdateDragging = function(anEvent)
-{
- // If this is a mouse up, then complete the drag.
- if([anEvent type] == CPLeftMouseUp)
- {
- if (CPDragServerAutoscrollInterval !== nil)
- clearInterval(CPDragServerAutoscrollInterval);
-
- CPDragServerAutoscrollInterval = nil;
-
- CPDragServerLocation = [DRAGGING_WINDOW(CPDragServerDestination) convertBridgeToBase:[[anEvent window] convertBaseToBridge:[anEvent locationInWindow]]];
-
- [CPDragServerView removeFromSuperview];
- [CPSharedDragServer._dragWindow orderOut:nil];
-
- if (CPDragServerDestination &&
- (![CPDragServerDestination respondsToSelector:@selector(prepareForDragOperation:)] || [CPDragServerDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
- (![CPDragServerDestination respondsToSelector:@selector(performDragOperation:)] || [CPDragServerDestination performDragOperation:CPDragServerDraggingInfo]) &&
- [CPDragServerDestination respondsToSelector:@selector(concludeDragOperation:)])
- [CPDragServerDestination concludeDragOperation:CPDragServerDraggingInfo];
-
- if (CPDragServerShouldSendDraggedImageEndedAtOperation)
- [CPDragServerSource draggedImage:[CPDragServerView image] endedAt:CPDragServerLocation operation:NO];
- else if (CPDragServerShouldSendDraggedViewEndedAtOperation)
- [CPDragServerSource draggedView:CPDragServerView endedAt:CPDragServerLocation operation:NO];
-
- CPDragServerIsDraggingImage = NO;
- CPDragServerDestination = nil;
-
- return;
- }
-
if (CPDragServerAutoscrollInterval === nil)
{
if ([CPDragServerSource respondsToSelector:@selector(autoscroll:)])
@@ -101,43 +56,16 @@ var CPDragServerUpdateDragging = function(anEvent)
CPDragServerPreviousEvent = anEvent;
- // If we're not a mouse up, then we're going to want to grab the next event.
- [CPApp setCallback:CPDragServerUpdateDragging
- forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
- untilDate:nil inMode:0 dequeue:NO];
+ if (CPDragServerAutoscrollInterval !== nil)
+ clearInterval(CPDragServerAutoscrollInterval);
- var location = [anEvent locationInWindow],
- operation =
- bridgeLocation = [[anEvent window] convertBaseToBridge:location];
+ CPDragServerAutoscrollInterval = nil;
+*/
- // We have to convert base to bridge since the drag event comes from the source window, not the drag window.
- var draggingDestination = [[CPDOMWindowBridge sharedDOMWindowBridge] _dragHitTest:bridgeLocation pasteboard:CPDragServerPasteboard];
-
- CPDragServerLocation = [DRAGGING_WINDOW(draggingDestination) convertBridgeToBase:bridgeLocation];
-
- if(draggingDestination != CPDragServerDestination)
- {
- if (CPDragServerDestination && [CPDragServerDestination respondsToSelector:@selector(draggingExited:)])
- [CPDragServerDestination draggingExited:CPDragServerDraggingInfo];
-
- CPDragServerDestination = draggingDestination;
-
- if (CPDragServerDestination && [CPDragServerDestination respondsToSelector:@selector(draggingEntered:)])
- [CPDragServerDestination draggingEntered:CPDragServerDraggingInfo];
- }
- else if (CPDragServerDestination && [CPDragServerDestination respondsToSelector:@selector(draggingUpdated:)])
- [CPDragServerDestination draggingUpdated:CPDragServerDraggingInfo];
-
- location.x -= CPDragServerOffset.x;
- location.y -= CPDragServerOffset.y;
-
- [CPDragServerView setFrameOrigin:location];
-
- if (CPDragServerShouldSendDraggedImageMovedTo)
- [CPDragServerSource draggedImage:[CPDragServerView image] movedTo:location];
- else if (CPDragServerShouldSendDraggedViewMovedTo)
- [CPDragServerSource draggedView:CPDragServerView movedTo:location];
-}
+var CPSharedDragServer = nil;
+
+var CPDragServerSource = nil;
+var CPDragServerDraggingInfo = nil;
/*
CPDraggingInfo is a container of information about a specific dragging session.
@@ -147,24 +75,36 @@ var CPDragServerUpdateDragging = function(anEvent)
{
}
+- (CPPasteboard)draggingPasteboard
+{
+ if ([CPPlatform supportsDragAndDrop])
+ return [_CPDOMDataTransferPasteboard DOMDataTransferPasteboard];
+
+ return [[CPDragServer sharedDragServer] draggingPasteboard];
+}
+
- (id)draggingSource
{
- return CPDragServerSource;
+ return [[CPDragServer sharedDragServer] draggingSource];
}
+/*
+- (unsigned)draggingSourceOperationMask
+*/
+
- (CPPoint)draggingLocation
{
- return CPDragServerLocation;
+ return [[CPDragServer sharedDragServer] draggingLocation];
}
-- (CPPasteboard)draggingPasteboard
+- (CPWindow)draggingDestinationWindow
{
- return CPDragServerPasteboard;
+ return DRAGGING_WINDOW([[CPDragServer sharedDragServer] draggingDestination]);
}
- (CPImage)draggedImage
{
- return [CPDragServerView image];
+ return [[self draggedView] image];
}
- (CGPoint)draggedImageLocation
@@ -172,22 +112,44 @@ var CPDragServerUpdateDragging = function(anEvent)
return [self draggedViewLocation];
}
-- (CGPoint)draggedViewLocation
-{
- return [DRAGGING_WINDOW(CPDragServerDestination) convertBridgeToBase:[CPDragServerView frame].origin];
-}
-
- (CPView)draggedView
{
- return CPDragServerView;
+ return [[CPDragServer sharedDragServer] draggedView];
+}
+
+- (CGPoint)draggedViewLocation
+{
+ var dragServer = [CPDragServer sharedDragServer];
+
+ return [DRAGGING_WINDOW([dragServer draggingDestination]) convertPlatformWindowToBase:[[dragServer draggedView] frame].origin];
}
@end
+var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
+ CPDraggingSource_draggedImage_endAt_operation_ = 1 << 1,
+ CPDraggingSource_draggedView_movedTo_ = 1 << 2,
+ CPDraggingSource_draggedView_endedAt_operation_ = 1 << 3;
+
@implementation CPDragServer : CPObject
{
- CPWindow _dragWindow;
- CPImageView _imageView;
+ BOOL _isDragging @accessors(readonly, getter=isDragging);
+
+ CPWindow _draggedWindow @accessors(readonly, getter=draggedWindow);
+ CPView _draggedView @accessors(readonly, getter=draggedView);
+ CPImageView _imageView;
+
+ BOOL _isDraggingImage;
+
+ CGSize _draggingOffset @accessors(readonly, getter=draggingOffset);
+
+ CPPasteboard _draggingPasteboard @accessors(readonly, getter=draggingPasteboard);
+
+ id _draggingSource @accessors(readonly, getter=draggingSource);
+ unsigned _implementedDraggingSourceMethods;
+
+ CGPoint _draggingLocation;
+ id _draggingDestination;
}
/*
@@ -196,9 +158,9 @@ var CPDragServerUpdateDragging = function(anEvent)
*/
+ (void)initialize
{
- if (self != [CPDragServer class])
+ if (self !== [CPDragServer class])
return;
-
+
CPDragServerDraggingInfo = [[CPDraggingInfo alloc] init];
}
@@ -206,7 +168,7 @@ var CPDragServerUpdateDragging = function(anEvent)
{
if (!CPSharedDragServer)
CPSharedDragServer = [[CPDragServer alloc] init];
-
+
return CPSharedDragServer;
}
@@ -216,16 +178,104 @@ var CPDragServerUpdateDragging = function(anEvent)
- (id)init
{
self = [super init];
-
+
if (self)
{
- _dragWindow = [[CPWindow alloc] initWithContentRect:CPRectMakeZero() styleMask:CPBorderlessWindowMask];
- [_dragWindow setLevel:CPDraggingWindowLevel];
+ _draggedWindow = [[CPWindow alloc] initWithContentRect:_CGRectMakeZero() styleMask:CPBorderlessWindowMask];
+
+ [_draggedWindow setLevel:CPDraggingWindowLevel];
}
-
+
return self;
}
+- (CGPoint)draggingLocation
+{
+ return _draggingLocation
+}
+
+- (void)draggingStartedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation
+{
+ if (_isDraggingImage)
+ {
+ if ([_draggingSource respondsToSelector:@selector(draggedImage:beganAt:)])
+ [_draggingSource draggedImage:[_draggedView image] beganAt:aLocation];
+ }
+ else
+ {
+ if ([_draggingSource respondsToSelector:@selector(draggedView:beganAt:)])
+ [_draggingSource draggedView:_draggedView beganAt:aLocation];
+ }
+
+ if (![CPPlatform supportsDragAndDrop])
+ [_draggedWindow orderFront:self];
+}
+
+- (void)draggingSourceUpdatedWithGlobalLocation:(CGPoint)aGlobalLocation
+{
+ if (![CPPlatform supportsDragAndDrop])
+ [_draggedWindow setFrameOrigin:_CGPointMake(aGlobalLocation.x - _draggingOffset.width, aGlobalLocation.y - _draggingOffset.height)];
+
+ if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_movedTo_)
+ [_draggingSource draggedImage:[_draggedView image] movedTo:aGlobalLocation];
+
+ else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_movedTo_)
+ [_draggingSource draggedView:_draggedView movedTo:aGlobalLocation];
+}
+
+- (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
+{
+ var dragOperation = CPDragOperationCopy;
+ // We have to convert base to bridge since the drag event comes from the source window, not the drag window.
+ var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
+
+ if (draggingDestination)
+ _draggingLocation = [DRAGGING_WINDOW(draggingDestination) convertPlatformWindowToBase:aLocation];
+
+ if(draggingDestination !== _draggingDestination)
+ {
+ if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingExited:)])
+ [_draggingDestination draggingExited:CPDragServerDraggingInfo];
+
+ _draggingDestination = draggingDestination;
+
+ if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingEntered:)])
+ dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
+ }
+ else if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
+ dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
+
+ if (!_draggingDestination)
+ dragOperation = CPDragOperationNone;
+
+ return dragOperation;
+}
+
+- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation
+{
+ [_draggedView removeFromSuperview];
+
+ if (![CPPlatform supportsDragAndDrop])
+ [_draggedWindow orderOut:self];
+
+ if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endAt_operation_)
+ [_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:NO];
+
+ else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_endedAt_operation_)
+ [_draggingSource draggedView:_draggedView endedAt:aLocation operation:NO];
+
+ _isDragging = NO;
+}
+
+- (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow
+{
+ if (_draggingDestination &&
+ (![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
+ (![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) &&
+ [_draggingDestination respondsToSelector:@selector(concludeDragOperation:)])
+ [_draggingDestination concludeDragOperation:CPDragServerDraggingInfo];
+}
+
/*!
Initiates a drag session.
@param aView the view being dragged
@@ -235,50 +285,70 @@ var CPDragServerUpdateDragging = function(anEvent)
@param anEvent
@param aPasteboard the pasteboard that contains the drag data
@param aSourceObject the object where the drag started
- @param slideBack if YES, aView slides back to
+ @param slideBack if \c YES, \c aView slides back to
its origin on a failed drop
*/
-- (void)dragView:(CPView)aView fromWindow:(CPWindow)aWindow at:(CGPoint)viewLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
+- (void)dragView:(CPView)aView fromWindow:(CPWindow)aWindow at:(CGPoint)viewLocation offset:(CGSize)mouseOffset event:(CPEvent)mouseDownEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
{
- var eventLocation = [anEvent locationInWindow];
-
- CPDragServerView = aView;
- CPDragServerSource = aSourceObject;
- CPDragServerWindow = aWindow;
- CPDragServerOffset = CPPointMake(eventLocation.x - viewLocation.x, eventLocation.y - viewLocation.y);
- CPDragServerPasteboard = [CPPasteboard pasteboardWithName:CPDragPboard];//aPasteboard;
+ _isDragging = YES;
- [_dragWindow setFrameSize:CGSizeMakeCopy([[CPDOMWindowBridge sharedDOMWindowBridge] frame].size)];
- [_dragWindow orderFront:self];
+ _draggedView = aView;
+ _draggingPasteboard = aPasteboard || [CPPasteboard pasteboardWithName:CPDragPboard];
+ _draggingSource = aSourceObject;
+ _draggingDestination = nil;
- [aView setFrameOrigin:viewLocation];
- [[_dragWindow contentView] addSubview:aView];
+ // The offset is based on the distance from where we want the view to be initially from where the mouse is initially
+ // Hence the use of mouseDownEvent's location and view's location in global coordinates.
+ var mouseDownWindow = [mouseDownEvent window],
+ mouseDownEventLocation = [mouseDownEvent locationInWindow];
- if (CPDragServerIsDraggingImage)
+ if (mouseDownEventLocation)
{
- if ([CPDragServerSource respondsToSelector:@selector(draggedImage:beganAt:)])
- [CPDragServerSource draggedImage:[aView image] beganAt:viewLocation];
-
- CPDragServerShouldSendDraggedImageMovedTo = [CPDragServerSource respondsToSelector:@selector(draggedImage:movedTo:)];
- CPDragServerShouldSendDraggedImageEndedAtOperation = [CPDragServerSource respondsToSelector:@selector(draggedImage:endAt:operation:)];
-
- CPDragServerShouldSendDraggedViewMovedTo = NO;
- CPDragServerShouldSendDraggedViewEndedAtOperation = NO;
+ if (mouseDownWindow)
+ mouseDownEventLocation = [mouseDownWindow convertBaseToGlobal:mouseDownEventLocation];
+
+ _draggingOffset = _CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
+ }
+ else
+ _draggingOffset = _CGSizeMakerZero();
+
+ if ([CPPlatform isBrowser])
+ [_draggedWindow setPlatformWindow:[aWindow platformWindow]];
+
+ [aView setFrameOrigin:_CGPointMakeZero()];
+
+ var mouseLocation = [CPEvent mouseLocation];
+
+ // Place it where the mouse pointer is.
+ [_draggedWindow setFrameOrigin:_CGPointMake(mouseLocation.x - _draggingOffset.width, mouseLocation.y - _draggingOffset.height)];
+ [_draggedWindow setFrameSize:[aView frame].size];
+
+ [[_draggedWindow contentView] addSubview:aView];
+
+ _implementedDraggingSourceMethods = 0;
+
+ if (_draggedView === _imageView)
+ {
+ if ([_draggingSource respondsToSelector:@selector(draggedImage:movedTo:)])
+ _implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_movedTo_;
+
+ if ([_draggingSource respondsToSelector:@selector(draggedImage:endAt:operation:)])
+ _implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endAt_operation_;
}
else
{
- if ([CPDragServerSource respondsToSelector:@selector(draggedView:beganAt:)])
- [CPDragServerSource draggedView:aView beganAt:viewLocation];
-
- CPDragServerShouldSendDraggedViewMovedTo = [CPDragServerSource respondsToSelector:@selector(draggedView:movedTo:)];
- CPDragServerShouldSendDraggedViewEndedAtOperation = [CPDragServerSource respondsToSelector:@selector(draggedView:endedAt:operation:)];
-
+ if ([_draggingSource respondsToSelector:@selector(draggedView:movedTo:)])
+ _implementedDraggingSourceMethods |= CPDraggingSource_draggedView_movedTo_;
- CPDragServerShouldSendDraggedImageMovedTo = NO;
- CPDragServerShouldSendDraggedImageEndedAtOperation = NO;
+ if ([_draggingSource respondsToSelector:@selector(draggedView:endedAt:operation:)])
+ _implementedDraggingSourceMethods |= CPDraggingSource_draggedView_endedAt_operation_;
}
- CPDragServerStartDragging(anEvent);
+ if (![CPPlatform supportsDragAndDrop])
+ {
+ [self draggingStartedInPlatformWindow:[aWindow platformWindow] globalLocation:mouseLocation];
+ [self trackDragging:mouseDownEvent];
+ }
}
/*!
@@ -290,22 +360,47 @@ var CPDragServerUpdateDragging = function(anEvent)
@param anEvent
@param aPasteboard the pasteboard where the drag data is located
@param aSourceObject the object where the drag started
- @param slideBack if YES, aView slides back to
+ @param slideBack if \c YES, \c aView slides back to
its origin on a failed drop
*/
- (void)dragImage:(CPImage)anImage fromWindow:(CPWindow)aWindow at:(CGPoint)imageLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
{
- CPDragServerIsDraggingImage = YES;
-
+ _isDraggingImage = YES;
+
+ var imageSize = [anImage size];
+
if (!_imageView)
- _imageView = [[CPImageView alloc] initWithFrame:CPRectMakeZero()];
-
+ _imageView = [[CPImageView alloc] initWithFrame:_CGRectMake(0.0, 0.0, imageSize.width, imageSize.height)];
+
[_imageView setImage:anImage];
- [_imageView setFrameSize:CGSizeMakeCopy([anImage size])];
-
+
[self dragView:_imageView fromWindow:aWindow at:imageLocation offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
}
+- (void)trackDragging:(CPEvent)anEvent
+{
+ var type = [anEvent type],
+ platformWindow = [_draggedWindow platformWindow],
+ platformWindowLocation = [[anEvent window] convertBaseToPlatformWindow:[anEvent locationInWindow]];
+
+ if (type === CPLeftMouseUp)
+ {
+ [self performDragOperationInPlatformWindow:platformWindow];
+ [self draggingEndedInPlatformWindow:platformWindow globalLocation:platformWindowLocation];
+
+ // Stop tracking events.
+ return;
+ }
+
+ [self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
+ [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
+
+ // If we're not a mouse up, then we're going to want to grab the next event.
+ [CPApp setTarget:self selector:@selector(trackDragging:)
+ forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
+ untilDate:nil inMode:0 dequeue:NO];
+}
+
@end
@implementation CPWindow (CPDraggingAdditions)
@@ -318,23 +413,23 @@ var CPDragServerUpdateDragging = function(anEvent)
return nil;
// We don't need to do this because the only place this gets called
-// -_dragHitTest: in CPDOMWindowBridge does this already. Perhaps to
+// -_dragHitTest: in CPPlatformWindow does this already. Perhaps to
// be safe?
// if (![self containsPoint:aPoint])
// return nil;
- var adjustedPoint = _CGPointMake(aPoint.x - _CGRectGetMinX(_frame), aPoint.y - _CGRectGetMinY(_frame)),
+ var adjustedPoint = [self convertPlatformWindowToBase:aPoint],
hitView = [_windowView hitTest:adjustedPoint];
while (hitView && ![aPasteboard availableTypeFromArray:[hitView registeredDraggedTypes]])
hitView = [hitView superview];
-
+
if (hitView)
return hitView;
-
+
if ([aPasteboard availableTypeFromArray:[self registeredDraggedTypes]])
return self;
-
+
return nil;
}
diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j
index 5a5cf2a75..eb942a79f 100644
--- a/AppKit/CPEvent.j
+++ b/AppKit/CPEvent.j
@@ -221,16 +221,16 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Creates a new keyboard event.
@param anEventType the event type. Must be one of CPKeyDown, CPKeyUp or CPFlagsChanged
- @param aPoint the location of the cursor in the window specified by aWindowNumber
+ @param aPoint the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@param aTimestamp the time the event occurred
@param aWindowNumber the number of the CPWindow where the event occurred
@param aGraphicsContext the graphics context where the event occurred
@param characters the characters associated with the event
@param unmodCharacters the string of keys pressed without the presence of any modifiers other than Shift
- @param repeatKey YES if this is caused by the system repeat as opposed to the user pressing the key again
+ @param repeatKey \c YES if this is caused by the system repeat as opposed to the user pressing the key again
@param code a number associated with the keyboard key of this event
- @throws CPInternalInconsistencyException if anEventType is not a CPKeyDown,
+ @throws CPInternalInconsistencyException if \c anEventType is not a CPKeyDown,
CPKeyUp or CPFlagsChanged
@return the keyboard event
*/
@@ -246,7 +246,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Creates a new mouse event
@param anEventType the event type
- @param aPoint the location of the cursor in the window specified by aWindowNumber
+ @param aPoint the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@param aTimestamp the time the event occurred
@param aWindowNumber the number of the CPWindow where the event occurred
@@ -268,7 +268,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Creates a new custom event
@param anEventType the event type. Must be one of CPAppKitDefined, CPSystemDefined, CPApplicationDefined or CPPeriodic
- @param aLocation the location of the cursor in the window specified by aWindowNumber
+ @param aLocation the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@param aTimestamp the time the event occurred
@param aWindowNumber the number of the CPWindow where the event occurred
@@ -358,15 +358,15 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns the location of the mouse (for mouse events).
- If this is not a mouse event, it returns nil.
- If window returns nil, then
+ If this is not a mouse event, it returns \c nil.
+ If \c window returns \c nil, then
the mouse coordinates will be based on the screen coordinates.
Otherwise, the coordinates are relative to the window's coordinates.
- @return the location of the mouse, or nil for non-mouse events.
+ @return the location of the mouse, or \c nil for non-mouse events.
*/
- (CGPoint)locationInWindow
{
- return _location;
+ return _CGPointMakeCopy(_location);
}
/*!
@@ -448,7 +448,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
- Returns YES if the keyboard event was caused by the key being held down.
+ Returns \c YES if the keyboard event was caused by the key being held down.
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (BOOL)isARepeat
@@ -465,6 +465,18 @@ var _CPEventPeriodicEventPeriod = 0,
return _keyCode;
}
++ (CGPoint)mouseLocation
+{
+ // FIXME: this is incorrect, we shouldn't depend on the current event.
+ var event = [CPApp currentEvent],
+ eventWindow = [event window];
+
+ if (eventWindow)
+ return [eventWindow convertBaseToGlobal:[event locationInWindow]];
+
+ return [event locationInWindow];
+}
+
- (float)pressure
{
return _pressure;
@@ -504,7 +516,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
- Generates periodic events every aPeriod seconds.
+ Generates periodic events every \c aPeriod seconds.
@param aDelay the number of seconds before the first event
@param aPeriod the length of time in seconds between successive events
*/
diff --git a/AppKit/CPFlashMovie.j b/AppKit/CPFlashMovie.j
index ef6298fc6..b666c2391 100644
--- a/AppKit/CPFlashMovie.j
+++ b/AppKit/CPFlashMovie.j
@@ -34,7 +34,7 @@
}
/*!
- Creates a new Flash movie with the swf at aFileName.
+ Creates a new Flash movie with the swf at \c aFileName.
@param aFilename the swf to load
@return the initialized CPFlashMovie
*/
diff --git a/AppKit/CPFlashView.j b/AppKit/CPFlashView.j
index 874614b7a..5d3f983a4 100644
--- a/AppKit/CPFlashView.j
+++ b/AppKit/CPFlashView.j
@@ -20,10 +20,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-@import "CPDOMWindowBridge.j"
@import "CPFlashMovie.j"
@import "CPView.j"
+
/*!
@ingroup appkit
*/
@@ -96,17 +96,17 @@
- (void)mouseDragged:(CPEvent)anEvent
{
- [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES];
+ [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (void)mouseDown:(CPEvent)anEvent
{
- [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES];
+ [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (void)mouseUp:(CPEvent)anEvent
{
- [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES];
+ [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
}
@end
diff --git a/AppKit/CPGeometry.j b/AppKit/CPGeometry.j
index c49ec1e4d..c7d190afb 100644
--- a/AppKit/CPGeometry.j
+++ b/AppKit/CPGeometry.j
@@ -62,11 +62,11 @@ function CPPointMake(x, y)
}
/*!
- Makes a CGRect with an origin and size equal to aRect less the dX/dY insets specified.
+ Makes a CGRect with an origin and size equal to \c aRect less the \c dX/dY insets specified.
@param dX the size of the inset in the x-axis
@param dY the size of the inset in the y-axis
@group CGRect
- @return CGRect a rectangle like aRect with an inset
+ @return CGRect a rectangle like \c aRect with an inset
*/
function CPRectInset(aRect, dX, dY)
{
@@ -132,7 +132,7 @@ function CPRectMake(x, y, width, height)
}
/*!
- Creates a new rectangle with its origin offset by dX and dY.
+ Creates a new rectangle with its origin offset by \c dX and \c dY.
@group CGRect
@param aRect the rectangle to copy the origin and size from
@param dX the amount added to the x-size of the new rectangle
@@ -171,7 +171,7 @@ function CPRectStandardize(aRect)
}
/*!
- Returns the smallest rectangle that can contain the two argument CGRects.
+ Returns the smallest rectangle that can contain the two argument \c CGRects.
@group CGRect
@param lhsRect the first CGRect to use for the union calculation
@param rhsRect the second CGRect to use for the union calculation
@@ -211,12 +211,12 @@ function CPSizeMake(width, height)
}
/*!
- Returns YES if the CGRect, aRect, contains
- the CGPoint, aPoint.
+ Returns \c YES if the CGRect, \c aRect, contains
+ the CGPoint, \c aPoint.
@param aRect the rectangle to test with
@param aPoint the point to test with
@group CGRect
- @return BOOL YES if the rectangle contains the point, NO otherwise.
+ @return BOOL \c YES if the rectangle contains the point, \c NO otherwise.
*/
function CPRectContainsPoint(aRect, aPoint)
{
@@ -227,12 +227,12 @@ function CPRectContainsPoint(aRect, aPoint)
}
/*!
- Returns a BOOL indicating whether CGRect possibleOuter
- contains CGRect possibleInner.
+ Returns a \c BOOL indicating whether CGRect \c possibleOuter
+ contains CGRect \c possibleInner.
@group CGRect
- @param possibleOuter the CGRect to test if possibleInner is inside of
- @param possibleInner the CGRect to test if it fits inside possibleOuter.
- @return BOOL YES if possibleInner fits inside possibleOuter.
+ @param possibleOuter the CGRect to test if \c possibleInner is inside of
+ @param possibleInner the CGRect to test if it fits inside \c possibleOuter.
+ @return BOOL \c YES if \c possibleInner fits inside \c possibleOuter.
*/
function CPRectContainsRect(lhsRect, rhsRect)
{
@@ -241,11 +241,11 @@ function CPRectContainsRect(lhsRect, rhsRect)
/*!
Tests whether the two CGPoints are equal to each other by comparing their
- x and y members.
+ \c x and \c y members.
@group @CGPoint
@param lhsPoint the first CGPoint to check
@param rhsPoint the second CGPoint to check
- @return BOOL YES if the two points have the same x's, and the same y's.
+ @return BOOL \c YES if the two points have the same x's, and the same y's.
*/
function CPPointEqualToPoint(lhsPoint, rhsPoint)
{
@@ -257,7 +257,7 @@ function CPPointEqualToPoint(lhsPoint, rhsPoint)
@group CGRect
@param lhsRect the first CGRect to compare
@param rhsRect the second CGRect to compare
- @return BOOL YES if the two rectangles have the same origin and size. NO, otherwise.
+ @return BOOL \c YES if the two rectangles have the same origin and size. \c NO, otherwise.
*/
function CPRectEqualToRect(lhsRect, rhsRect)
{
@@ -346,11 +346,11 @@ function CPRectGetWidth(aRect)
}
/*!
- Returns YES if the two rectangles intersect
+ Returns \c YES if the two rectangles intersect
@group CGRect
@param lhsRect the first CGRect
@param rhsRect the second CGRect
- @return BOOL YES if the two rectangles have any common spaces, and NO, otherwise.
+ @return BOOL \c YES if the two rectangles have any common spaces, and \c NO, otherwise.
*/
function CPRectIntersectsRect(lhsRect, rhsRect)
{
@@ -358,11 +358,11 @@ function CPRectIntersectsRect(lhsRect, rhsRect)
}
/*!
- Returns YES if the CGRect has no area.
+ Returns \c YES if the CGRect has no area.
The test is performed by checking if the width and height are both zero.
@group CGRect
@param aRect the CGRect to test
- @return BOOL YES if the CGRect has no area, and NO, otherwise.
+ @return BOOL \c YES if the CGRect has no area, and \c NO, otherwise.
*/
function CPRectIsEmpty(aRect)
{
@@ -370,10 +370,10 @@ function CPRectIsEmpty(aRect)
}
/*!
- Returns YES if the CGRect has no area.
+ Returns \c YES if the CGRect has no area.
The test is performed by checking if the width and height are both zero.
@group CGRect
- @return BOOL YES if the CGRect has no area, and NO, otherwise.
+ @return BOOL \c YES if the CGRect has no area, and \c NO, otherwise.
*/
function CPRectIsNull(aRect)
{
@@ -381,11 +381,11 @@ function CPRectIsNull(aRect)
}
/*!
- Returns YES if the two CGSizes are identical.
+ Returns \c YES if the two CGSizes are identical.
@group CGSize
@param lhsSize the first CGSize to compare
@param rhsSize the second CGSize to compare
- @return BOOL YES if the two sizes are identical. NO, otherwise.
+ @return BOOL \c YES if the two sizes are identical. \c NO, otherwise.
*/
function CPSizeEqualToSize(lhsSize, rhsSize)
{
@@ -454,7 +454,7 @@ function CPSizeFromString(aString)
/*!
Returns a CGRect created from a string.
@group CGRect
- @param aString a string in the form generated by CPStringFromRect
+ @param aString a string in the form generated by \c CPStringFromRect
@return CGRect the rectangle created from the string
*/
function CPRectFromString(aString)
@@ -477,7 +477,7 @@ function CPPointFromEvent(anEvent)
/*!
Returns a zero sized CGSize.
@group CGSize
- @return CGSize a size object with zeros for width and height
+ @return CGSize a size object with zeros for \c width and \c height
*/
function CPSizeMakeZero()
{
@@ -485,7 +485,7 @@ function CPSizeMakeZero()
}
/*!
- Returns a rectangle at origin (0,0) and size of (0,0).
+ Returns a rectangle at origin \c (0,0) and size of \c (0,0).
@group CGRect
@return CGRect a zeroed out CGRect
*/
@@ -495,9 +495,9 @@ function CPRectMakeZero()
}
/*!
- Returns a point located at (0, 0).
+ Returns a point located at \c (0, 0).
@group CGPoint
- @return CGPoint a point located at (0, 0)
+ @return CGPoint a point located at \c (0, 0)
*/
function CPPointMakeZero()
{
diff --git a/AppKit/CPImage.j b/AppKit/CPImage.j
index 4962912bf..e42bf35b1 100644
--- a/AppKit/CPImage.j
+++ b/AppKit/CPImage.j
@@ -92,7 +92,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
/*!
Initializes the image, by associating it with a filename. The image
- denoted in aFilename is not actually loaded. It will
+ denoted in \c aFilename is not actually loaded. It will
be loaded once needed.
@param aFilename the file containing the image
@param aSize the image's size
@@ -187,9 +187,9 @@ function CPImageInBundle(aFilename, aSize, aBundle)
}
/*!
- Returns YES if the image data has already been loaded.
+ Returns the load status, which will be CPImageLoadStatusCompleted if the image data has already been loaded.
*/
-- (BOOL)loadStatus
+- (unsigned)loadStatus
{
return _loadStatus;
}
diff --git a/AppKit/CPImageView.j b/AppKit/CPImageView.j
index ceec7c59d..ed6eeea42 100644
--- a/AppKit/CPImageView.j
+++ b/AppKit/CPImageView.j
@@ -70,7 +70,9 @@ var LEFT_SHADOW_INSET = 3.0,
BOOL _hasShadow;
CPView _shadowView;
-
+
+ BOOL _isEditable;
+
CGRect _imageRect;
}
@@ -85,7 +87,13 @@ var LEFT_SHADOW_INSET = 3.0,
_DOMImageElement.style.position = "absolute";
_DOMImageElement.style.left = "0px";
_DOMImageElement.style.top = "0px";
-
+
+ if ([CPPlatform supportsDragAndDrop])
+ {
+ _DOMImageElement.setAttribute("draggable", "true");
+ _DOMImageElement.style["-khtml-user-drag"] = "element";
+ }
+
CPDOMDisplayServerAppendChild(_DOMElement, _DOMImageElement);
_DOMImageElement.style.visibility = "hidden";
@@ -159,8 +167,8 @@ var LEFT_SHADOW_INSET = 3.0,
}
/*!
- Returns YES if the image view draws with
- a drop shadow. The default is NO.
+ Returns \c YES if the image view draws with
+ a drop shadow. The default is \c NO.
*/
- (BOOL)hasShadow
{
@@ -339,11 +347,47 @@ var LEFT_SHADOW_INSET = 3.0,
[[self nextResponder] mouseDown:anEvent];
}
+- (void)setEditable:(BOOL)shouldBeEditable
+{
+ if (_isEditable === shouldBeEditable)
+ return;
+
+ _isEditable = shouldBeEditable;
+
+ if (_isEditable)
+ [self registerForDraggedTypes:[CPImagesPboardType]];
+
+ else
+ {
+ var draggedTypes = [self registeredDraggedTypes];
+
+ [self unregisterDraggedTypes];
+
+ [draggedTypes removeObjectIdenticalTo:CPImagesPboardType];
+
+ [self registerForDraggedTypes:draggedTypes];
+ }
+}
+
+- (BOOL)isEditable
+{
+ return _isEditable;
+}
+
+- (void)performDragOperation:(CPDraggingInfo)aSender
+{
+ var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
+
+ if ([images count])
+ [self setImage:images[0]];
+}
+
@end
var CPImageViewImageKey = @"CPImageViewImageKey",
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
- CPImageViewHasShadowKey = @"CPImageViewHasShadowKey";
+ CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
+ CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
@implementation CPImageView (CPCoding)
@@ -360,6 +404,11 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
_DOMImageElement.style.left = "0px";
_DOMImageElement.style.top = "0px";
_DOMImageElement.style.visibility = "hidden";
+ if ([CPPlatform supportsDragAndDrop])
+ {
+ _DOMImageElement.setAttribute("draggable", "true");
+ _DOMImageElement.style["-khtml-user-drag"] = "element";
+ }
#endif
self = [super initWithCoder:aCoder];
@@ -372,6 +421,9 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
+ if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
+ [self setEditable:YES];
+
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -402,6 +454,9 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
_subviews = actualSubviews;
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
+
+ if (_isEditable)
+ [aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
}
@end
diff --git a/AppKit/CPMenu.j b/AppKit/CPMenu.j
index 10bb0b4dc..2434040a7 100644
--- a/AppKit/CPMenu.j
+++ b/AppKit/CPMenu.j
@@ -60,6 +60,7 @@ var _CPMenuBarVisible = NO,
CPMenu _supermenu;
CPString _title;
+ CPString _name;
CPMutableArray _items;
CPMenu _attachedMenu;
@@ -91,7 +92,10 @@ var _CPMenuBarVisible = NO,
return;
_CPMenuBarVisible = menuBarShouldBeVisible;
-
+
+ if ([CPPlatform supportsNativeMainMenu])
+ return;
+
if (menuBarShouldBeVisible)
{
if (!_CPMenuBarSharedWindow)
@@ -119,7 +123,7 @@ var _CPMenuBarVisible = NO,
// FIXME: There must be a better way to do this.
#if PLATFORM(DOM)
- [[CPDOMWindowBridge sharedDOMWindowBridge] _bridgeResizeEvent:nil];
+ [[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil];
#endif
}
@@ -267,13 +271,13 @@ var _CPMenuBarVisible = NO,
- (void)insertItem:(CPMenuItem)aMenuItem atIndex:(unsigned)anIndex
{
var menu = [aMenuItem menu];
-
+
if (menu)
- if (menu != self)
+ 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];
@@ -369,9 +373,9 @@ var _CPMenuBarVisible = NO,
/*!
Returns the menu item with the specified tag
@param the tag of the desired menu item
- @return the menu item or nil if a match was not found
+ @return the menu item or \c nil if a match was not found
*/
-- (CPMenuItem)menuWithTag:(int)aTag
+- (CPMenuItem)itemWithTag:(int)aTag
{
var index = [self indexOfItemWithTag:aTag];
@@ -384,9 +388,9 @@ var _CPMenuBarVisible = NO,
/*!
Returns the menu item with the specified title.
@param aTitle the title of the menu item
- @return the menu item or nil if a match was not found
+ @return the menu item or \c nil if a match was not found
*/
-- (CPMenuItem)menuWithTitle:(CPString)aTitle
+- (CPMenuItem)itemWithTitle:(CPString)aTitle
{
var index = [self indexOfItemWithTitle:aTitle];
@@ -551,7 +555,7 @@ var _CPMenuBarVisible = NO,
}
/*!
- Returns the attaced menu, or nil if there isn't one.
+ Returns the attaced menu, or \c nil if there isn't one.
*/
- (CPMenu)attachedMenu
{
@@ -559,7 +563,7 @@ var _CPMenuBarVisible = NO,
}
/*!
- Returns YES if the menu is attached to another menu.
+ Returns \c YES if the menu is attached to another menu.
*/
- (BOOL)isAttached
{
@@ -575,7 +579,7 @@ var _CPMenuBarVisible = NO,
}
/*!
- Returns the super menu or nil if there is none.
+ Returns the super menu or \c nil if there is none.
*/
- (CPMenu)supermenu
{
@@ -592,8 +596,8 @@ var _CPMenuBarVisible = NO,
}
/*!
- If there are two instances of this menu visible, return NO.
- Otherwise, return YES if we are a detached menu and visible.
+ If there are two instances of this menu visible, return \c NO.
+ Otherwise, return \c YES if we are a detached menu and visible.
*/
- (BOOL)isTornOff
{
@@ -603,7 +607,7 @@ var _CPMenuBarVisible = NO,
// Enabling and Disabling Menu Items
/*!
Sets whether the menu automatically enables menu items.
- @param aFlag YES sets the menu to automatically enable items.
+ @param aFlag \c YES sets the menu to automatically enable items.
*/
- (void)setAutoenablesItems:(BOOL)aFlag
{
@@ -611,7 +615,7 @@ var _CPMenuBarVisible = NO,
}
/*!
- Returns YES if the menu auto enables items.
+ Returns \c YES if the menu auto enables items.
*/
- (BOOL)autoenablesItems
{
@@ -672,7 +676,7 @@ var _CPMenuBarVisible = NO,
[menuWindow setDelegate:self];
[menuWindow setBackgroundStyle:isForMenuBar ? _CPMenuWindowMenuBarBackgroundStyle : _CPMenuWindowPopUpBackgroundStyle];
- [menuWindow setFrameOrigin:[[anEvent window] convertBaseToBridge:[anEvent locationInWindow]]];
+ [menuWindow setFrameOrigin:[[anEvent window] convertBaseToGlobal:[anEvent locationInWindow]]];
[menuWindow orderFront:self];
[menuWindow beginTrackingWithEvent:anEvent sessionDelegate:self didEndSelector:@selector(_menuWindowDidFinishTracking:highlightedItem:)];
@@ -686,17 +690,12 @@ var _CPMenuBarVisible = NO,
if([aMenuItem isEnabled])
[CPApp sendAction:[aMenuItem action] to:[aMenuItem target] from:aMenuItem];
-
- var delegate = [menu delegate];
-
- if ([delegate respondsToSelector:@selector(menuDidClose:)])
- [delegate menuDidClose:menu];
}
// Managing Display of State Column
/*!
Sets whether to show the state column
- @param shouldShowStateColumn YES shows the state column
+ @param shouldShowStateColumn \c YES shows the state column
*/
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
{
@@ -704,7 +703,7 @@ var _CPMenuBarVisible = NO,
}
/*!
- Returns YES if the menu shows the state column
+ Returns \c YES if the menu shows the state column
*/
- (BOOL)showsStateColumn
{
@@ -714,7 +713,7 @@ var _CPMenuBarVisible = NO,
// Handling Highlighting
/*!
Returns the currently highlighted menu item.
- @return the highlighted menu item or nil if no item is currently highlighted
+ @return the highlighted menu item or \c nil if no item is currently highlighted
*/
- (CPMenuItem)highlightedItem
{
@@ -750,9 +749,9 @@ var _CPMenuBarVisible = NO,
/*!
Initiates the action of the menu item that
- has a keyboard shortcut equivalent to anEvent
+ has a keyboard shortcut equivalent to \c anEvent
@param anEvent the keyboard event
- @return YES if it was handled.
+ @return \c YES if it was handled.
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
@@ -826,10 +825,36 @@ var _CPMenuBarVisible = NO,
[[_items[_highlightedIndex] _menuItemView] highlight:YES];
}
+- (void)_setMenuName:(CPString)aName
+{
+ if (_name === aName)
+ return;
+
+ _name = aName;
+
+ if (_name === @"CPMainMenu")
+ [CPApp setMainMenu:self];
+}
+
+- (CPString)_menuName
+{
+ return _name;
+}
+
+- (void)awakeFromCib
+{
+ if (_name === @"_CPMainMenu")
+ {
+ [self _setMenuName:@"CPMainMenu"];
+ [CPMenu setMenuBarVisible:YES];
+ }
+}
+
@end
var CPMenuTitleKey = @"CPMenuTitleKey",
+ CPMenuNameKey = @"CPMenuNameKey",
CPMenuItemsKey = @"CPMenuItemsKey",
CPMenuShowsStateColumnKey = @"CPMenuShowsStateColumnKey";
@@ -849,6 +874,8 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
_title = [aCoder decodeObjectForKey:CPMenuTitleKey];
_items = [aCoder decodeObjectForKey:CPMenuItemsKey];
+ [self _setMenuName:[aCoder decodeObjectForKey:CPMenuNameKey]];
+
_showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
}
@@ -862,6 +889,10 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_title forKey:CPMenuTitleKey];
+
+ if (_name)
+ [aCoder encodeObject:_name forKey:CPMenuNameKey];
+
[aCoder encodeObject:_items forKey:CPMenuItemsKey];
if (!_showsStateColumn)
@@ -909,7 +940,7 @@ var STICKY_TIME_INTERVAL = 500,
CPTimeInterval _startTime;
int _scrollingState;
- CGPoint _lastScreenLocation;
+ CGPoint _lastGlobalLocation;
BOOL _isShowingTopScrollIndicator;
BOOL _isShowingBottomScrollIndicator;
@@ -926,10 +957,10 @@ var STICKY_TIME_INTERVAL = 500,
menuWindow = _CPMenuWindowPool.pop();
else
menuWindow = [[_CPMenuWindow alloc] init];
-
+
[menuWindow setFont:aFont];
[menuWindow setMenu:aMenu];
-
+
return menuWindow;
}
@@ -1081,35 +1112,42 @@ var STICKY_TIME_INTERVAL = 500,
- (void)constrainToScreen
{
+ // FIXME: There are integral window issues with platform windows.
+ // FIXME: This gets called far too often.
_unconstrainedFrame = CGRectMakeCopy([self frame]);
- var screenBounds = CGRectInset([[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds], 5.0, 5.0),
- constrainedFrame = CGRectIntersection(_unconstrainedFrame, screenBounds),
- menuViewOrigin = [self convertBaseToBridge:CGPointMake(LEFT_MARGIN, TOP_MARGIN)];
-
+ var isBrowser = [CPPlatform isBrowser],
+ visibleFrame = CGRectInset(isBrowser ? [[self platformWindow] contentBounds] : [[self screen] visibleFrame], 5.0, 5.0),
+ constrainedFrame = CGRectIntersection(_unconstrainedFrame, visibleFrame);
+
+ // We don't want to simply intersect the visible frame and the unconstrained frame.
+ // We should be allowing as much of the width to fit as possible (pushing back and forward).
constrainedFrame.origin.x = CGRectGetMinX(_unconstrainedFrame);
constrainedFrame.size.width = CGRectGetWidth(_unconstrainedFrame);
-
- if (CGRectGetWidth(constrainedFrame) > CGRectGetWidth(screenBounds))
- constrainedFrame.size.width = CGRectGetWidth(screenBounds);
-
- if (CGRectGetMaxX(constrainedFrame) > CGRectGetMaxX(screenBounds))
- constrainedFrame.origin.x -= CGRectGetMaxX(constrainedFrame) - CGRectGetMaxX(screenBounds);
-
- if (CGRectGetMinX(constrainedFrame) < CGRectGetMinX(screenBounds))
- constrainedFrame.origin.x = CGRectGetMinX(screenBounds);
-
+
+ if (CGRectGetWidth(constrainedFrame) > CGRectGetWidth(visibleFrame))
+ constrainedFrame.size.width = CGRectGetWidth(visibleFrame);
+
+ if (CGRectGetMaxX(constrainedFrame) > CGRectGetMaxX(visibleFrame))
+ constrainedFrame.origin.x -= CGRectGetMaxX(constrainedFrame) - CGRectGetMaxX(visibleFrame);
+
+ if (CGRectGetMinX(constrainedFrame) < CGRectGetMinX(visibleFrame))
+ constrainedFrame.origin.x = CGRectGetMinX(visibleFrame);
+
+ // This needs to happen before changing the frame.
+ var menuViewOrigin = [self convertBaseToGlobal:CGPointMake(LEFT_MARGIN, TOP_MARGIN)];
+
[super setFrame:constrainedFrame];
-
- var topMargin = TOP_MARGIN,
+
+ var moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + TOP_MARGIN,
+ moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - BOTTOM_MARGIN,
+
+ topMargin = TOP_MARGIN,
bottomMargin = BOTTOM_MARGIN,
contentView = [self contentView],
bounds = [contentView bounds];
-
- var moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + TOP_MARGIN,
- moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - BOTTOM_MARGIN;
-
+
if (moreAbove)
{
topMargin += SCROLL_INDICATOR_HEIGHT;
@@ -1118,9 +1156,9 @@ var STICKY_TIME_INTERVAL = 500,
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
}
-
+
[_moreAboveView setHidden:!moreAbove];
-
+
if (moreBelow)
{
bottomMargin += SCROLL_INDICATOR_HEIGHT;
@@ -1129,13 +1167,13 @@ var STICKY_TIME_INTERVAL = 500,
}
[_moreBelowView setHidden:!moreBelow];
-
+
var clipFrame = CGRectMake(LEFT_MARGIN, topMargin, CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN, CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin)
-
+
[_menuClipView setFrame:clipFrame];
[_menuView setFrameSize:CGSizeMake(CGRectGetWidth(clipFrame), CGRectGetHeight([_menuView frame]))];
-
- [_menuView scrollPoint:CGPointMake(0.0, [self convertBaseToBridge:clipFrame.origin].y - menuViewOrigin.y)];
+
+ [_menuView scrollPoint:CGPointMake(0.0, [self convertBaseToGlobal:clipFrame.origin].y - menuViewOrigin.y)];
}
- (void)cancelTracking
@@ -1159,11 +1197,11 @@ var STICKY_TIME_INTERVAL = 500,
{
var type = [anEvent type],
theWindow = [anEvent window],
- screenLocation = theWindow ? [theWindow convertBaseToBridge:[anEvent locationInWindow]] : [anEvent locationInWindow];
-
- if (type == CPPeriodic)
+ globalLocation = theWindow ? [theWindow convertBaseToGlobal:[anEvent locationInWindow]] : [anEvent locationInWindow];
+
+ if (type === CPPeriodic)
{
- var constrainedBounds = CGRectInset([[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds], 5.0, 5.0);
+ var constrainedBounds = CGRectInset([CPPlatform isBrowser] ? [[self platformWindow] contentBounds] : [[self screen] visibleFrame], 5.0, 5.0);
if (_scrollingState == _CPMenuWindowScrollingStateUp)
{
@@ -1177,13 +1215,13 @@ var STICKY_TIME_INTERVAL = 500,
[self setFrame:_unconstrainedFrame];
[self constrainToScreen];
- screenLocation = _lastScreenLocation;
+ globalLocation = _lastGlobalLocation;
}
- _lastScreenLocation = screenLocation;
+ _lastGlobalLocation = globalLocation;
var menu = [_menuView menu],
- menuLocation = [self convertBridgeToBase:screenLocation],
+ menuLocation = [self convertGlobalToBase:globalLocation],
activeItemIndex = [_menuView itemIndexAtPoint:[_menuView convertPoint:menuLocation fromView:nil]],
mouseOverMenuView = [[menu itemAtIndex:activeItemIndex] view];
@@ -1214,7 +1252,7 @@ var STICKY_TIME_INTERVAL = 500,
_lastMouseOverMenuView = nil;
}
- [menu _highlightItemAtIndex:[_menuView itemIndexAtPoint:[_menuView convertPoint:[self convertBridgeToBase:screenLocation] fromView:nil]]];
+ [menu _highlightItemAtIndex:[_menuView itemIndexAtPoint:[_menuView convertPoint:[self convertGlobalToBase:globalLocation] fromView:nil]]];
if (type == CPMouseMoved || type == CPLeftMouseDragged || type == CPLeftMouseDown)
{
@@ -1224,11 +1262,11 @@ var STICKY_TIME_INTERVAL = 500,
_scrollingState = _CPMenuWindowScrollingStateNone;
// If we're at or above of the top scroll indicator...
- if (screenLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT)
+ if (globalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT)
_scrollingState = _CPMenuWindowScrollingStateUp;
// If we're at or below the bottom scroll indicator...
- else if (screenLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT)
+ else if (globalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT)
_scrollingState = _CPMenuWindowScrollingStateDown;
if (_scrollingState != oldScrollingState)
@@ -1259,23 +1297,23 @@ var STICKY_TIME_INTERVAL = 500,
[menu _highlightItemAtIndex:CPNotFound];
- // Clear these now so its faster next time around.
- [_menuView setMenu:nil];
-
[self orderOut:self];
-
- if (_sessionDelegate && _didEndSelector)
- objj_msgSend(_sessionDelegate, _didEndSelector, self, highlightedItem);
-
- [[CPNotificationCenter defaultCenter]
- postNotificationName:CPMenuDidEndTrackingNotification
- object:menu];
-
+
var delegate = [menu delegate];
if ([delegate respondsToSelector:@selector(menuDidClose:)])
[delegate menuDidClose:menu];
-
+
+ if (_sessionDelegate && _didEndSelector)
+ objj_msgSend(_sessionDelegate, _didEndSelector, self, highlightedItem);
+
+ [[CPNotificationCenter defaultCenter]
+ postNotificationName:CPMenuDidEndTrackingNotification
+ object:menu];
+
+ // Clear these now so its faster next time around.
+ [_menuView setMenu:nil];
+
return;
}
@@ -1452,10 +1490,12 @@ var _CPMenuBarWindowBackgroundColor = nil,
- (id)init
{
- var bridgeWidth = CGRectGetWidth([[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds]);
-
- self = [super initWithContentRect:CGRectMake(0.0, 0.0, bridgeWidth, MENUBAR_HEIGHT) styleMask:CPBorderlessWindowMask];
-
+ var contentRect = [CPPlatform isBrowser] ? [[CPPlatformWindow primaryPlatformWindow] contentBounds] : [[self screen] visibleFrame];
+
+ contentRect.size.height = MENUBAR_HEIGHT;
+
+ self = [super initWithContentRect:contentRect styleMask:CPBorderlessWindowMask];
+
if (self)
{
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/39-dont-allow-windows-to-go-above-menubar
@@ -1735,7 +1775,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
return frame;
}
-- (CPView)menuItemAtPoint:(CGPoint)aPoint
+- (CPMenuItem)menuItemAtPoint:(CGPoint)aPoint
{
var items = [_menu itemArray],
count = items.length;
diff --git a/AppKit/CPMenuItem.j b/AppKit/CPMenuItem.j
index b890c8593..b738729ed 100644
--- a/AppKit/CPMenuItem.j
+++ b/AppKit/CPMenuItem.j
@@ -113,7 +113,7 @@
// Enabling a Menu Item
/*!
Sets whether the menu item is enabled or not
- @param isEnabled YES enables the item. NO disables it.
+ @param isEnabled \c YES enables the item. \c NO disables it.
*/
- (void)setEnabled:(BOOL)isEnabled
{
@@ -128,7 +128,7 @@
}
/*!
- Returns YES if the item is enabled.
+ Returns \c YES if the item is enabled.
*/
- (BOOL)isEnabled
{
@@ -138,7 +138,7 @@
// Managing Hidden Status
/*!
Sets whether the item should be hidden. A hidden item can not be triggered by keyboard shortcuts.
- @param isHidden YES hides the item. NO reveals it.
+ @param isHidden \c YES hides the item. \c NO reveals it.
*/
- (void)setHidden:(BOOL)isHidden
{
@@ -151,7 +151,7 @@
}
/*!
- Returns YES if the item is hidden.
+ Returns \c YES if the item is hidden.
*/
- (BOOL)isHidden
{
@@ -159,7 +159,7 @@
}
/*!
- Returns YES if the item is hidden or if one of it's supermenus is hidden.
+ Returns \c YES if the item is hidden or if one of it's supermenus is hidden.
*/
- (BOOL)isHiddenOrHasHiddenAncestor
{
@@ -461,7 +461,7 @@ CPOffState
}
/*!
- Returns the submenu of the item. nil if there is no submenu.
+ Returns the submenu of the item. \c nil if there is no submenu.
*/
- (CPMenu)submenu
{
@@ -469,7 +469,7 @@ CPOffState
}
/*!
- Returns YES if the menu item has a submenu.
+ Returns \c YES if the menu item has a submenu.
*/
- (BOOL)hasSubmenu
{
@@ -491,7 +491,7 @@ CPOffState
}
/*!
- Returns YES if the menu item is a separator.
+ Returns \c YES if the menu item is a separator.
*/
- (BOOL)isSeparatorItem
{
@@ -613,7 +613,7 @@ CPControlKeyMask
/*!
Sets whether this item is an alternate for the previous menu item.
- @param isAlternate YES denotes that this menu item is an alternate
+ @param isAlternate \c YES denotes that this menu item is an alternate
*/
- (void)setAlternate:(BOOL)isAlternate
{
@@ -621,7 +621,7 @@ CPControlKeyMask
}
/*!
- Returns YES if the menu item is an alternate for the previous item.
+ Returns \c YES if the menu item is an alternate for the previous item.
*/
- (BOOL)isAlternate
{
@@ -717,7 +717,7 @@ CPControlKeyMask
// Getting Highlighted Status
/*!
- Returns YES if the menu item is highlighted.
+ Returns \c YES if the menu item is highlighted.
*/
- (BOOL)isHighlighted
{
@@ -1188,7 +1188,7 @@ var _CPMenuItemSelectionColor = nil,
- (CPColor)textColor
{
- return [_menuItem isEnabled] ? (_textColor ? _textColor : [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0]) : [CPColor darkGrayColor];
+ return [_menuItem isEnabled] ? (_textColor ? _textColor : [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0]) : [CPColor lightGrayColor];
}
- (void)setTextShadowColor:(CPColor)aColor
diff --git a/AppKit/CPOutlineView.j b/AppKit/CPOutlineView.j
index d82d737c9..fdf2b28a4 100644
--- a/AppKit/CPOutlineView.j
+++ b/AppKit/CPOutlineView.j
@@ -3,7 +3,7 @@
* AppKit
*
* Created by Francisco Tolmasky.
- * Copyright 2008, 280 North, Inc.
+ * Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,93 +20,834 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+@import "CPTableColumn.j"
@import "CPTableView.j"
-/*!
- @ignore
- This class is a subclass of CPTableView which provides the user with a way to display
- tree structured data in an outline format. It is particularly useful for displaying hierarchical data
- such as a class inheritance tree or any other set of relationships.
-*/
+#include "CoreGraphics/CGGeometry.h"
+
+
+CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification";
+CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification";
+CPOutlineViewItemDidCollapseNotification = @"CPOutlineViewItemDidCollapseNotification";
+CPOutlineViewItemDidExpandNotification = @"CPOutlineViewItemDidExpandNotification";
+CPOutlineViewItemWillCollapseNotification = @"CPOutlineViewItemWillCollapseNotification";
+CPOutlineViewItemWillExpandNotification = @"CPOutlineViewItemWillExpandNotification";
+CPOutlineViewSelectionDidChangeNotification = @"CPOutlineViewSelectionDidChangeNotification";
+CPOutlineViewSelectionIsChangingNotification = @"CPOutlineViewSelectionIsChangingNotification";
+
+var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_ = 1 << 1,
+ CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_ = 1 << 2,
+
+ CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_ = 1 << 3,
+ CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_ = 1 << 4,
+ CPOutlineViewDataSource_outlineView_validateDrop_proposedRow_proposedDropOperation_ = 1 << 5,
+ CPOutlineViewDataSource_outlineView_namesOfPromisedFilesDroppedAtDestination_forDraggedItems_ = 1 << 6,
+
+ CPOutlineViewDataSource_outlineView_itemForPersistentObject_ = 1 << 7,
+ CPOutlineViewDataSource_outlineView_persistentObjectForItem_ = 1 << 8,
+
+ CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_ = 1 << 9,
+
+ CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
@implementation CPOutlineView : CPTableView
{
- id _outlineDataSource;
- CPArray _itemsByRow;
+ id _outlineViewDataSource;
+ id _outlineViewDelegate;
+ CPTableColumn _outlineTableColumn;
+
+ float _indentationPerLevel;
+ BOOL _indentationMarkerFollowsDataView;
+
+ CPInteger _implementedOutlineViewDataSourceMethods;
+
+ Object _rootItemInfo;
+ CPMutableArray _itemsForRows;
+ Object _itemInfosForItems;
+
+ CPControl _disclosureControlPrototype;
+ CPArray _disclosureControlsForRows;
+ CPData _disclosureControlData;
+ CPArray _disclosureControlQueue;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
-
+
if (self)
{
- [super setDataSource:self];
- _itemsByRow = [[CPArray alloc] init];
+ // The root item has weight "0", thus represents the weight solely of its descendants.
+ _rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
+
+ _itemsForRows = [];
+ _itemInfosForItems = { };
+ _disclosureControlsForRows = [];
+
+ [self setIndentationPerLevel:16.0];
+ [self setIndentationMarkerFollowsDataView:YES];
+
+ [super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
+
+ [self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
}
-
+
return self;
}
-/*!
- @ignore
- Sets the outline's data source. The data source must implement the following methods:
-
- @param aDataSource the outline's data source
- @throws CPInternalInconsistencyException if the data source does not implement all the required methods
-*/
- (void)setDataSource:(id)aDataSource
{
- if (![aDataSource respondsToSelector:@selector(outlineView:child:ofItem)])
- [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:child:ofItem'"];
- if (![aDataSource respondsToSelector:@selector(outlineView:isItemExpandable)])
- [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:isItemExpandable'"];
- if (![aDataSource respondsToSelector:@selector(outlineView:numberOfChildrenOfItem)])
- [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:numberOfChildrenOfItem'"];
- if (![aDataSource respondsToSelector:@selector(outlineView:objectValueForTableColumn:byItem)])
- [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:objectValueForTableColumn:byItem'"];
+ if (_outlineViewDataSource === aDataSource)
+ return;
- _outlineDataSource = aDataSource;
+ if (![aDataSource respondsToSelector:@selector(outlineView:child:ofItem:)])
+ [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:child:ofItem:'"];
+
+ if (![aDataSource respondsToSelector:@selector(outlineView:isItemExpandable:)])
+ [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:isItemExpandable:'"];
+
+ if (![aDataSource respondsToSelector:@selector(outlineView:numberOfChildrenOfItem:)])
+ [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:numberOfChildrenOfItem:'"];
+
+ if (![aDataSource respondsToSelector:@selector(outlineView:objectValueForTableColumn:byItem:)])
+ [CPException raise:CPInternalInconsistencyException reason:"Data source must implement 'outlineView:objectValueForTableColumn:byItem:'"];
+
+ _outlineViewDataSource = aDataSource;
+ _implementedOutlineViewDataSourceMethods = 0;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:setObjectValue:forTableColumn:byItem:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:shouldDeferDisplayingChildrenOfItem:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:acceptDrop:item:childIndex:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:validateDrop:proposedItem:proposedChildIndex:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:validateDrop:proposedRow:proposedDropOperation:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_validateDrop_proposedRow_proposedDropOperation_;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:namesOfPromisedFilesDroppedAtDestination:forDraggedItems:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_namesOfPromisedFilesDroppedAtDestination_forDraggedItems_;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:itemForPersistentObject:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_itemForPersistentObject_;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:persistentObjectForItem:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_persistentObjectForItem_;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:writeItems:toPasteboard:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_;
+
+ if ([_outlineViewDataSource respondsToSelector:@selector(outlineView:sortDescriptorsDidChange:)])
+ _implementedOutlineViewDataSourceMethods |= CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_;
[self reloadData];
}
-/* @ignore */
+
+- (id)dataSource
+{
+ return _outlineViewDataSource;
+}
+
+- (BOOL)isExpandable:(id)anItem
+{
+ if (!anItem)
+ return YES;
+
+ var itemInfo = _itemInfosForItems[[anItem UID]];
+
+ if (!itemInfo)
+ return NO;
+
+ return itemInfo.isExpandable;
+}
+
+- (void)isItemExpanded:(id)anItem
+{
+ if (!anItem)
+ return YES;
+
+ var itemInfo = _itemInfosForItems[[anItem UID]];
+
+ if (!itemInfo)
+ return NO;
+
+ return itemInfo.isExpanded;
+}
+
+- (void)expandItem:(id)anItem
+{
+ if (!anItem)
+ return;
+
+ var itemInfo = _itemInfosForItems[[anItem UID]];
+
+ if (!itemInfo)
+ return;
+
+ if (itemInfo.isExpanded)
+ return;
+
+ itemInfo.isExpanded = YES;
+
+ [self reloadItem:anItem reloadChildren:YES];
+}
+
+- (void)collapseItem:(id)anItem
+{
+ if (!anItem)
+ return;
+
+ var itemInfo = _itemInfosForItems[[anItem UID]];
+
+ if (!itemInfo)
+ return;
+
+ if (!itemInfo.isExpanded)
+ return;
+
+ itemInfo.isExpanded = NO;
+
+ [self reloadItem:anItem reloadChildren:YES];
+}
+
+- (void)reloadItem:(id)anItem
+{
+ [self reloadItem:anItem reloadChildren:NO];
+}
+
+- (void)reloadItem:(id)anItem reloadChildren:(BOOL)shouldReloadChildren
+{
+ if (!!shouldReloadChildren || !anItem)
+ _loadItemInfoForItem(self, anItem);
+ else
+ _reloadItem(self, anItem);
+
+ [super reloadData];
+}
+
+- (id)itemAtRow:(CPInteger)aRow
+{
+ return _itemsForRows[aRow] || nil;
+}
+
+- (CPInteger)rowForItem:(id)aItem
+{
+ if (!anItem)
+ return _rootItemInfo.row;
+
+ var itemInfo = _itemInfosForItems[[anItem UID]];
+
+ if (!itemInfo)
+ return CPNotFound;
+
+ return itemInfo.row;
+}
+
+- (void)setOutlineTableColumn:(CPTableColumn)aTableColumn
+{
+ if (_outlineTableColumn === aTableColumn)
+ return;
+
+ _outlineTableColumn = aTableColumn;
+
+ // FIXME: efficiency.
+ [self reloadData];
+}
+
+- (CPTableColumn)outlineTableColumn
+{
+ return _outlineTableColumn;
+}
+
+- (CPInteger)levelForItem:(id)anItem
+{
+ if (!anItem)
+ return _rootItemInfo.level;
+
+ var itemInfo = _itemInfosForItems[[anItem UID]];
+
+ if (!itemInfo)
+ return CPNotFound;
+
+ return itemInfo.level;
+}
+
+- (CPInteger)levelForRow:(CPInteger)aRow
+{
+ return [self levelForItem:[self itemAtRow:aRow]];
+}
+
+- (void)setIndentationPerLevel:(float)anIndentationWidth
+{
+ if (_indentationPerLevel === anIndentationWidth)
+ return;
+
+ _indentationPerLevel = anIndentationWidth;
+
+ // FIXME: efficiency!!!!
+ [self reloadData];
+}
+
+- (float)indentationPerLevel
+{
+ return _indentationPerLevel;
+}
+
+- (void)setIndentationMarkerFollowsDataView:(BOOL)indentationMarkerShouldFollowDataView
+{
+ if (_indentationMarkerFollowsDataView === indentationMarkerShouldFollowDataView)
+ return;
+
+ _indentationMarkerFollowsDataView = indentationMarkerShouldFollowDataView;
+
+ // !!!!
+ [self reloadData];
+}
+
+- (BOOL)indentationMarkerFollowsDataView
+{
+ return _indentationMarkerFollowsDataView;
+}
+
+- (id)parentForItem:(id)anItem
+{
+ if (!anItem)
+ return nil;
+
+ var itemInfo = _itemInfosForItems[[anItem UID]];
+
+ if (!itemInfo)
+ return nil;
+
+ return itemInfo.parent;
+}
+
+- (CGRect)frameOfOutlineDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
+{
+ var frame = [super frameOfDataViewAtColumn:aColumn row:aRow],
+ indentationWidth = ([self levelForRow:aRow] + 1) * [self indentationPerLevel];
+
+ frame.origin.x += indentationWidth;
+ frame.size.width -= indentationWidth;
+
+ return frame;
+}
+
+- (void)setDelegate:(id)aDelegate
+{
+ if (_outlineViewDelegate === aDelegate)
+ return;
+
+ var defaultCenter = [CPNotificationCenter defaultCenter];
+
+ if (_outlineViewDelegate)
+ {
+ if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
+ [defaultCenter
+ removeObserver:_outlineViewDelegate
+ name:CPOutlineViewColumnDidMoveNotification
+ object:self];
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidResize:)])
+ [defaultCenter
+ removeObserver:_outlineViewDelegate
+ name:CPOutlineViewColumnDidResizeNotification
+ object:self];
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewSelectionDidChange:)])
+ [defaultCenter
+ removeObserver:_outlineViewDelegate
+ name:CPOutlineViewSelectionDidChangeNotification
+ object:self];
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewSelectionIsChanging:)])
+ [defaultCenter
+ removeObserver:_outlineViewDelegate
+ name:CPOutlineViewSelectionIsChangingNotification
+ object:self];
+ }
+
+ _outlineViewDelegate = aDelegate;/*
+ _implementedDelegateMethods = 0;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(selectionShouldChangeInTableView:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_selectionShouldChangeInTableView_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:dataViewForTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_dataViewForTableColumn_row_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:didClickTableColumn:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_didClickTableColumn_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:didDragTableColumn:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_didDragTableColumn_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:heightOfRow:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_heightOfRow_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:isGroupRow:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_isGroupRow_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:mouseDownInHeaderOfTableColumn:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_mouseDownInHeaderOfTableColumn_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:nextTypeSelectMatchFromRow:toRow:forString:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_nextTypeSelectMatchFromRow_toRow_forString_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:selectionIndexesForProposedSelection:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_selectionIndexesForProposedSelection_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldEditTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldEditTableColumn_row_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldSelectRow:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectRow_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldSelectTableColumn:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectTableColumn_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldShowViewExpansionForTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldShowViewExpansionForTableColumn_row_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldTrackView:forTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTrackView_forTableColumn_row_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldTypeSelectForEvent:withCurrentSearchString:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTypeSelectForEvent_withCurrentSearchString_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:toolTipForView:rect:tableColumn:row:mouseLocation:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_toolTipForView_rect_tableColumn_row_mouseLocation_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:typeSelectStringForTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_typeSelectStringForTableColumn_row_;
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(tableView:willDisplayView:forTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_willDisplayView_forTableColumn_row_;
+*/
+ if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
+ [defaultCenter
+ addObserver:_outlineViewDelegate
+ selector:@selector(outlineViewColumnDidMove:)
+ name:CPOutlineViewColumnDidMoveNotification
+ object:self];
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidResize:)])
+ [defaultCenter
+ addObserver:_outlineViewDelegate
+ selector:@selector(outlineViewColumnDidMove:)
+ name:CPOutlineViewColumnDidResizeNotification
+ object:self];
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewSelectionDidChange:)])
+ [defaultCenter
+ addObserver:_outlineViewDelegate
+ selector:@selector(outlineViewSelectionDidChange:)
+ name:CPOutlineViewSelectionDidChangeNotification
+ object:self];
+
+ if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewSelectionIsChanging:)])
+ [defaultCenter
+ addObserver:_outlineViewDelegate
+ selector:@selector(outlineViewSelectionIsChanging:)
+ name:CPOutlineViewSelectionIsChangingNotification
+ object:self];
+}
+
+- (id)delegate
+{
+ return _outlineViewDelegate;
+}
+
+- (void)setDisclosureControlPrototype:(CPControl)aControl
+{
+ _disclosureControlPrototype = aControl;
+ _disclosureControlData = nil;
+ _disclosureControlQueue = [];
+
+ // fIXME: reall?
+ [self reloadData];
+}
+
- (void)reloadData
{
- _numberOfVisibleItems = [_outlineDataSource outlineView:self numberOfChildrenOfItem:nil];
- _numberOfRows = _numberOfVisibleItems;
-
- var i = 0;
-
- for (; i < _numberOfVisibleItems; ++i)
- _itemsByRow[i] = [_outlineDataSource outlineView:self child:i ofItem:nil];
-
- [self loadTableCellsInRect:[self bounds]];
+ [self reloadItem:nil reloadChildren:YES];
+}
+
+- (CGRect)frameOfDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
+{
+ var tableColumn = [self tableColumns][aColumn];
+
+ if (tableColumn === _outlineTableColumn)
+ return [self frameOfOutlineDataViewAtColumn:aColumn row:aRow];
+
+ return [super frameOfDataViewAtColumn:aColumn row:aRow];
+}
+
+- (void)_loadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
+{
+ [super _loadDataViewsInRows:rows columns:columns];
+
+ var outlineColumn = [[self tableColumns] indexOfObjectIdenticalTo:[self outlineTableColumn]];
+
+ if (![columns containsIndex:outlineColumn])
+ return;
+
+ var rowArray = [];
+
+ [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
+
+ var rowIndex = 0,
+ rowsCount = rowArray.length;
+
+ for (; rowIndex < rowsCount; ++rowIndex)
+ {
+ var row = rowArray[rowIndex],
+ item = _itemsForRows[row],
+ isExpandable = [self isExpandable:item];
+
+ if (!isExpandable)
+ continue;
+
+ var control = [self _dequeueDisclosureControl],
+ frame = [control frame],
+ dataViewFrame = [self frameOfDataViewAtColumn:outlineColumn row:row];
+
+ frame.origin.x = _indentationMarkerFollowsDataView ? _CGRectGetMinX(dataViewFrame) - _CGRectGetWidth(frame) : 0.0;
+ frame.origin.y = _CGRectGetMinY(dataViewFrame);
+ frame.size.height = _CGRectGetHeight(dataViewFrame);
+ // FIXME: center instead?
+ //frame.origin.y = _CGRectGetMidY(dataViewFrame) - _CGRectGetHeight(frame) / 2.0;
+
+ _disclosureControlsForRows[row] = control;
+
+ [control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
+ [control setFrame:frame];
+
+ [self addSubview:control];
+ }
+}
+
+- (void)_unloadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
+{
+ [super _unloadDataViewsInRows:rows columns:columns];
+
+ var outlineColumn = [[self tableColumns] indexOfObjectIdenticalTo:[self outlineTableColumn]];
+
+ if (![columns containsIndex:outlineColumn])
+ return;
+
+ var rowArray = [];
+
+ [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
+
+ var rowIndex = 0,
+ rowsCount = rowArray.length;
+
+ for (; rowIndex < rowsCount; ++rowIndex)
+ {
+ var row = rowArray[rowIndex],
+ control = _disclosureControlsForRows[row];
+
+ if (!control)
+ continue;
+
+ [control removeFromSuperview];
+
+ [self _enqueueDisclosureControl:control];
+
+ _disclosureControlsForRows[row] = nil;
+ }
+}
+
+- (void)_toggleFromDisclosureControl:(CPControl)aControl
+{
+ var controlFrame = [aControl frame],
+ item = [self itemAtRow:[self rowAtPoint:_CGPointMake(_CGRectGetMinX(controlFrame), _CGRectGetMidY(controlFrame))]];
+
+ if ([self isItemExpanded:item])
+ [self collapseItem:item];
+
+ else
+ [self expandItem:item];
+}
+
+- (void)_enqueueDisclosureControl:(CPControl)aControl
+{
+ _disclosureControlQueue.push(aControl);
+}
+
+- (CPControl)_dequeueDisclosureControl
+{
+ if (_disclosureControlQueue.length)
+ return _disclosureControlQueue.pop();
+
+ if (!_disclosureControlData)
+ if (!_disclosureControlPrototype)
+ return nil;
+ else
+ _disclosureControlData = [CPKeyedArchiver archivedDataWithRootObject:_disclosureControlPrototype];
+
+ var disclosureControl = [CPKeyedUnarchiver unarchiveObjectWithData:_disclosureControlData];
+
+ [disclosureControl setTarget:self];
+ [disclosureControl setAction:@selector(_toggleFromDisclosureControl:)];
+
+ return disclosureControl;
+}
+
+- (void)_noteSelectionIsChanging
+{
+ [[CPNotificationCenter defaultCenter]
+ postNotificationName:CPOutlineViewSelectionIsChangingNotification
+ object:self
+ userInfo:nil];
+}
+
+- (void)_noteSelectionDidChange
+{
+ [[CPNotificationCenter defaultCenter]
+ postNotificationName:CPOutlineViewSelectionDidChangeNotification
+ object:self
+ userInfo:nil];
}
@end
-/* @ignore */
-@implementation CPOutlineView (CPTableDataSource)
-
-/*
- FIXME
-*/
-/* @ignore */
-- (void)numberOfRowsInTableView:(CPTableView)aTableView
+var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
{
- return _numberOfVisibleItems;
+ if (!anItem)
+ return;
+
+ // Get the existing info if it exists.
+ var itemInfosForItems = anOutlineView._itemInfosForItems,
+ dataSource = anOutlineView._outlineViewDataSource,
+ itemUID = [anItem UID],
+ itemInfo = itemInfosForItems[itemUID];
+
+ // If we're not in the tree, then just bail.
+ if (!itemInfo)
+ return [];
+
+ // See if the item itself can be swapped out.
+ var parent = itemInfo.parent,
+ parentItemInfo = parent ? itemInfosForItems[[parent UID]] : anOutlineView._rootItemInfo,
+ parentChildren = parentItemInfo.children,
+ index = [parentChildren indexOfObjectIdenticalTo:anItem],
+ newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
+
+ if (anItem !== newItem)
+ {
+ itemInfosForItems[[anItem UID]] = nil;
+ itemInfosForItems[[newItem UID]] = itemInfo;
+
+ parentChildren[index] = newItem;
+ anOutlineView._itemsForRows[itemInfo.row] = newItem;
+ }
+
+ itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
+ itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
}
-/* @ignore */
-- (void)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)aTableColumn row:(int)aRowIndex
+var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
{
- return [_outlineDataSource outlineView:self objectValueForTableColumn:aTableColumn byItem:_itemsByRow[aRowIndex]];
+ var itemInfosForItems = anOutlineView._itemInfosForItems,
+ dataSource = anOutlineView._outlineViewDataSource;
+
+ if (!anItem)
+ var itemInfo = anOutlineView._rootItemInfo;
+
+ else
+ {
+ // Get the existing info if it exists.
+ var itemUID = [anItem UID],
+ itemInfo = itemInfosForItems[itemUID];
+
+ // If we're not in the tree, then just bail.
+ if (!itemInfo)
+ return [];
+
+ itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
+
+ // If we were previously expanded, but now no longer expandable, "de-expand".
+ // NOTE: we are *not* collapsing, thus no notification is posted.
+ if (!itemInfo.isExpandable && itemInfo.isExpanded)
+ {
+ itemInfo.isExpanded = NO;
+ itemInfo.children = [];
+ }
+ }
+
+ // The root item does not count as a descendant.
+ var weight = itemInfo.weight,
+ descendants = anItem ? [anItem] : [];
+
+ if (itemInfo.isExpanded && (!(anOutlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
+ ![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
+ {
+ var index = 0,
+ count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
+ level = itemInfo.level + 1;
+
+ itemInfo.children = [];
+
+ for (; index < count; ++index)
+ {
+ var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
+ childItemInfo = itemInfosForItems[[childItem UID]];
+
+ if (!childItemInfo)
+ {
+ childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
+ itemInfosForItems[[childItem UID]] = childItemInfo;
+ }
+
+ itemInfo.children[index] = childItem;
+
+ var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
+
+ childItemInfo.parent = anItem;
+ childItemInfo.level = level;
+ descendants = descendants.concat(childDescendants);
+ }
+ }
+
+ itemInfo.weight = descendants.length;
+
+ if (!isIntermediate)
+ {
+ // row = -1 is the root item, so just go to row 0 since it is ignored.
+ var index = MAX(itemInfo.row, 0),
+ itemsForRows = anOutlineView._itemsForRows;
+
+ descendants.unshift(index, weight);
+
+ itemsForRows.splice.apply(itemsForRows, descendants);
+
+ var count = itemsForRows.length;
+
+ for (; index < count; ++index)
+ itemInfosForItems[[itemsForRows[index] UID]].row = index;
+
+ var deltaWeight = itemInfo.weight - weight;
+
+ if (deltaWeight !== 0)
+ {
+ var parent = itemInfo.parent;
+
+ while (parent)
+ {
+ var parentItemInfo = itemInfosForItems[[parent UID]];
+
+ parentItemInfo.weight += deltaWeight;
+ parent = parentItemInfo.parent;
+ }
+
+ if (anItem)
+ anOutlineView._rootItemInfo.weight += deltaWeight;
+ }
+ }
+
+ return descendants;
}
-@end
\ No newline at end of file
+@implementation _CPOutlineViewTableViewDataSource : CPObject
+{
+ CPObject _outlineView;
+}
+
+- (id)initWithOutlineView:(CPOutlineView)anOutlineView
+{
+ self = [super init];
+
+ if (self)
+ _outlineView = anOutlineView;
+
+ return self;
+}
+
+- (CPInteger)numberOfRowsInTableView:(CPTableView)anOutlineView
+{
+ return _outlineView._itemsForRows.length;
+}
+
+- (id)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRow
+{
+ return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]];
+}
+
+@end
+
+@implementation _CPOutlineViewTableViewDelegate : CPObject
+{
+ CPOutlineView _outlineView;
+}
+
+- (id)initWithOutlineView:(CPOutlineView)anOutlineView
+{
+ self = [super init];
+
+ if (self)
+ _outlineView = anOutlineView;
+
+ return self;
+}
+
+@end
+
+@implementation CPDisclosureButton : CPButton
+{
+ float _angle;
+}
+
+- (id)initWithFrame:(CGRect)aFrame
+{
+ self = [super initWithFrame:aFrame];
+
+ if (self)
+ [self setBordered:NO];
+
+ return self;
+}
+
+- (void)setState:(CPState)aState
+{
+ [super setState:aState];
+
+ if ([self state] === CPOnState)
+ _angle = 0.0;
+
+ else
+ _angle = -PI_2;
+}
+
+- (void)drawRect:(CGRect)aRect
+{
+ var bounds = [self bounds],
+ context = [[CPGraphicsContext currentContext] graphicsPort];
+
+ CGContextBeginPath(context);
+
+ CGContextTranslateCTM(context, _CGRectGetWidth(bounds) / 2.0, _CGRectGetHeight(bounds) / 2.0);
+ CGContextRotateCTM(context, _angle);
+ CGContextTranslateCTM(context, -_CGRectGetWidth(bounds) / 2.0, -_CGRectGetHeight(bounds) / 2.0);
+
+ // Center, but crisp.
+ CGContextTranslateCTM(context, FLOOR((_CGRectGetWidth(bounds) - 9.0) / 2.0), FLOOR((_CGRectGetHeight(bounds) - 8.0) / 2.0));
+
+ CGContextMoveToPoint(context, 0.0, 0.0);
+ CGContextAddLineToPoint(context, 9.0, 0.0);
+ CGContextAddLineToPoint(context, 4.5, 8.0);
+ CGContextAddLineToPoint(context, 0.0, 0.0);
+
+ CGContextClosePath(context);
+
+ CGContextSetFillColor(context, ([self themeState] & CPThemeState("highlighted")) ? [CPColor blackColor] : [CPColor grayColor]);
+ CGContextFillPath(context);
+}
+
+@end
diff --git a/AppKit/CPPanel.j b/AppKit/CPPanel.j
index bcff72814..65dc9b177 100644
--- a/AppKit/CPPanel.j
+++ b/AppKit/CPPanel.j
@@ -53,7 +53,7 @@ CPCancelButton = 0;
}
/*!
- Returns YES if the receiver is a floating panel (like a palette).
+ Returns \c YES if the receiver is a floating panel (like a palette).
*/
- (BOOL)isFloatingPanel
{
@@ -61,8 +61,8 @@ CPCancelButton = 0;
}
/*!
- Sets the receiver to be a floating panel. YES
- makes the window a floating panel. NO makes it a normal window.
+ Sets the receiver to be a floating panel. \c YES
+ makes the window a floating panel. \c NO makes it a normal window.
@param isFloatingPanel specifies whether to make it floating
*/
- (void)setFloatingPanel:(BOOL)isFloatingPanel
@@ -71,8 +71,8 @@ CPCancelButton = 0;
}
/*!
- Returns YES if the window only becomes key
- if needed. NO means it behaves just like other windows.
+ Returns \c YES if the window only becomes key
+ if needed. \c NO means it behaves just like other windows.
*/
- (BOOL)becomesKeyOnlyIfNeeded
{
@@ -81,7 +81,7 @@ CPCancelButton = 0;
/*!
Sets whether the the window becomes key only if needed.
- @param shouldBecomeKeyOnlyIfNeeded YES makes the window become key only if needed
+ @param shouldBecomeKeyOnlyIfNeeded \c YES makes the window become key only if needed
*/
- (void)setBecomesKeyOnlyIfNeeded:(BOOL)shouldBecomeKeyOnlyIfNeeded
{
diff --git a/AppKit/CPPasteboard.j b/AppKit/CPPasteboard.j
index dd7c5816f..4da0d92ec 100644
--- a/AppKit/CPPasteboard.j
+++ b/AppKit/CPPasteboard.j
@@ -25,6 +25,8 @@
@import
@import
+#include "Platform/Platform.h"
+
CPGeneralPboard = @"CPGeneralPboard";
CPFontPboard = @"CPFontPboard";
@@ -38,8 +40,12 @@ CPFontPboardType = @"CPFontPboardType";
CPHTMLPboardType = @"CPHTMLPboardType";
CPStringPboardType = @"CPStringPboardType";
CPURLPboardType = @"CPURLPboardType";
+CPImagesPboardType = @"CPImagesPboardType";
+CPVideosPboardType = @"CPVideosPboardType";
+
+// Deprecated
CPImagePboardType = @"CPImagePboardType";
-CPVideoPboardType = @"CPVideoPboardType";
+
var CPPasteboards = nil;
@@ -169,7 +175,7 @@ var CPPasteboards = nil;
Sets the pasteboard data for the specified type
@param aData the data
@param aType the data type being set
- @return YES if the data was successfully written to the pasteboard
+ @return \c YES if the data was successfully written to the pasteboard
*/
- (BOOL)setData:(CPData)aData forType:(CPString)aType
{
@@ -182,7 +188,7 @@ var CPPasteboards = nil;
Writes the specified property list as data for the specified type
@param aPropertyList the property list to write
@param aType the data type
- @return YES if the property list was successfully written to the pasteboard
+ @return \c YES if the property list was successfully written to the pasteboard
*/
- (BOOL)setPropertyList:(id)aPropertyList forType:(CPString)aType
{
@@ -193,7 +199,7 @@ var CPPasteboards = nil;
Sets the specified string as data for the specified type
@param aString the string to write
@param aType the data type
- @return YES if the string was successfully written to the pasteboard
+ @return \c YES if the string was successfully written to the pasteboard
*/
- (void)setString:(CPString)aString forType:(CPString)aType
{
@@ -205,11 +211,11 @@ var CPPasteboards = nil;
Checks the pasteboard's types for a match with the types listen in the specified array. The array should
be ordered by the requestor's most preferred data type first.
@param anArray an array of requested types ordered by preference
- @return the highest match with the pasteboard's supported types or nil if no match was found
+ @return the highest match with the pasteboard's supported types or \c nil if no match was found
*/
- (CPString)availableTypeFromArray:(CPArray)anArray
{
- return [_types firstObjectCommonWithArray:anArray];
+ return [[self types] firstObjectCommonWithArray:anArray];
}
/*!
@@ -232,7 +238,7 @@ var CPPasteboards = nil;
/*!
Returns the pasteboard data for the specified data type
@param aType the requested data type
- @return the requested data or nil if the data doesn't exist
+ @return the requested data or \c nil if the data doesn't exist
*/
- (CPData)dataForType:(CPString)aType
{
@@ -258,7 +264,7 @@ var CPPasteboards = nil;
/*!
Returns the property list for the specified data type
@param aType the requested data type
- @return the property list or nil if the list was not found
+ @return the property list or \c nil if the list was not found
*/
- (id)propertyListForType:(CPString)aType
{
@@ -273,7 +279,7 @@ var CPPasteboards = nil;
/*!
Returns the string for the specified data type
@param aType the requested data type
- @return the string or nil if the string was not found
+ @return the string or \c nil if the string was not found
*/
- (CPString)stringForType:(CPString)aType
{
@@ -300,3 +306,70 @@ var CPPasteboards = nil;
}
@end
+
+#if PLATFORM(DOM)
+
+var DOMDataTransferPasteboard = nil;
+
+@implementation _CPDOMDataTransferPasteboard : CPPasteboard
+{
+ DataTransfer _dataTransfer;
+}
+
++ (_CPDOMDataTransferPasteboard)DOMDataTransferPasteboard
+{
+ if (!DOMDataTransferPasteboard)
+ DOMDataTransferPasteboard = [[_CPDOMDataTransferPasteboard alloc] init];
+
+ return DOMDataTransferPasteboard;
+}
+
+- (void)_setDataTransfer:(DataTransfer)aDataTransfer
+{
+ _dataTransfer = aDataTransfer;
+}
+
+- (void)_setPasteboard:(CPPasteboard)aPasteboard
+{
+ _dataTransfer.clearData();
+
+ var types = [aPasteboard types],
+ count = types.length;
+
+ while (count--)
+ {
+ var type = types[count];
+
+ if (type === CPStringPboardType)
+ _dataTransfer.setData(type, [aPasteboard stringForType:type]);
+ else
+ _dataTransfer.setData(type, [[aPasteboard dataForType:type] string]);
+ }
+}
+
+- (CPArray)types
+{
+ return Array.prototype.slice.apply(_dataTransfer.types);
+}
+
+- (CPData)dataForType:(CPString)aType
+{
+ var dataString = _dataTransfer.getData(aType);
+
+ if (aType === CPStringPboardType)
+ return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0 errorDescription:0];
+
+ return [CPData dataWithString:dataString];
+}
+
+- (id)propertyListForType:(CPString)aType
+{
+ if (aType === CPStringPboardType)
+ return _dataTransfer.getData(aType);
+
+ return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat errorDescription:nil];
+}
+
+@end
+
+#endif
diff --git a/AppKit/CPPopUpButton.j b/AppKit/CPPopUpButton.j
index acaecb870..17700fb28 100644
--- a/AppKit/CPPopUpButton.j
+++ b/AppKit/CPPopUpButton.j
@@ -54,7 +54,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
Initializes the pop-up button to the specified size.
@param aFrame the size for the button
- @param shouldPullDown YES makes this a pull-down menu, NO makes it a pop-up menu.
+ @param shouldPullDown \c YES makes this a pull-down menu, \c NO makes it a pop-up menu.
@return the initialized pop-up button
*/
- (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
@@ -87,8 +87,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
Specifies whether the object is a pull-down or a pop-up menu.
- @param shouldPullDown YES makes the pop-up button
- a pull-down menu. NO makes it a pop-up menu.
+ @param shouldPullDown \c YES makes the pop-up button
+ a pull-down menu. \c NO makes it a pop-up menu.
*/
- (void)setPullsDown:(BOOL)shouldPullDown
{
@@ -111,7 +111,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
}
/*!
- Returns YES if the button is a pull-down menu. NO if the button is a pop-up menu.
+ Returns \c YES if the button is a pull-down menu. \c NO if the button is a pop-up menu.
*/
- (BOOL)pullsDown
{
@@ -200,18 +200,18 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
// Getting the User's Selection
/*!
- Returns the selected item or nil if no item is selected.
+ Returns the selected item or \c nil if no item is selected.
*/
- (CPMenuItem)selectedItem
{
- if (_selectedIndex < 0)
+ if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1)
return nil;
return [_menu itemAtIndex:_selectedIndex];
}
/*!
- Returns the title of the selected item or nil if no item is selected.
+ Returns the title of the selected item or \c nil if no item is selected.
*/
- (CPString)titleOfSelectedItem
{
@@ -372,7 +372,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
}
/*!
- Returns the item at the specified index or nil if the item does not exist.
+ Returns the item at the specified index or \c nil if the item does not exist.
@param anIndex the index of the item to obtain
*/
- (CPMenuItem)itemAtIndex:(unsigned)anIndex
@@ -381,7 +381,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
}
/*!
- Returns the title of the item at the specified index or nil if no item exists.
+ Returns the title of the item at the specified index or \c nil if no item exists.
@param anIndex the index of the item
*/
- (CPString)itemTitleAtIndex:(unsigned)anIndex
@@ -628,13 +628,15 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
var numberOfItems = [self numberOfItems];
- if (numberOfItems <= _selectedIndex)
+ if (numberOfItems <= _selectedIndex && numberOfItems > 0)
[self selectItemAtIndex:numberOfItems - 1];
+ else
+ [self synchronizeTitleAndSelectedItem];
}
- (void)mouseDown:(CPEvent)anEvent
{
- if (![self isEnabled])
+ if (![self isEnabled] || ![self numberOfItems])
return;
[self highlight:YES];
@@ -648,7 +650,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
// Pull Down Menus show up directly below their buttons.
if ([self pullsDown])
- var menuOrigin = [theWindow convertBaseToBridge:[self convertPoint:CGPointMake(0.0, CGRectGetMaxY([self bounds])) toView:nil]];
+ var menuOrigin = [theWindow convertBaseToGlobal:[self convertPoint:CGPointMake(0.0, CGRectGetMaxY([self bounds])) toView:nil]];
// Pop Up Menus attempt to show up "on top" of the selected item.
else
@@ -659,21 +661,21 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
// 2. Move LEFT by whatever indentation we have (offsetWidths, aka, window margin, item margin, etc).
// 3. MOVE UP by the difference in sizes of the content and menu item, this will only work if the content is vertically centered.
var contentRect = [self convertRect:[self contentRectForBounds:[self bounds]] toView:nil],
- menuOrigin = [theWindow convertBaseToBridge:contentRect.origin],
+ menuOrigin = [theWindow convertBaseToGlobal:contentRect.origin],
menuItemRect = [menuWindow rectForItemAtIndex:_selectedIndex];
menuOrigin.x -= CGRectGetMinX(menuItemRect) + [menuWindow overlapOffsetWidth] + [[[menu itemAtIndex:_selectedIndex] _menuItemView] overlapOffsetWidth];
menuOrigin.y -= CGRectGetMinY(menuItemRect) + (CGRectGetHeight(menuItemRect) - CGRectGetHeight(contentRect)) / 2.0;
}
-
+
[menuWindow setFrameOrigin:menuOrigin];
-
+
var menuMaxX = CGRectGetMaxX([menuWindow frame]),
- buttonMaxX = [theWindow convertBaseToBridge:CGPointMake(CGRectGetMaxX([self convertRect:[self bounds] toView:nil]), 0.0)].x;
-
+ buttonMaxX = [theWindow convertBaseToGlobal:CGPointMake(CGRectGetMaxX([self convertRect:[self bounds] toView:nil]), 0.0)].x;
+
if (menuMaxX < buttonMaxX)
[menuWindow setMinWidth:CGRectGetWidth([menuWindow frame]) + buttonMaxX - menuMaxX - ([self pullsDown] ? 0.0 : VISIBLE_MARGIN)];
-
+
[menuWindow orderFront:self];
[menuWindow beginTrackingWithEvent:anEvent sessionDelegate:self didEndSelector:@selector(menuWindowDidFinishTracking:highlightedItem:)];
}
diff --git a/AppKit/CPProgressIndicator.j b/AppKit/CPProgressIndicator.j
index a5e1756ee..663da8450 100644
--- a/AppKit/CPProgressIndicator.j
+++ b/AppKit/CPProgressIndicator.j
@@ -205,7 +205,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
/*!
- Always returns NO. Cappuccino does not have multiple threads.
+ Always returns \c NO. Cappuccino does not have multiple threads.
*/
- (BOOL)usesThreadedAnimation
{
@@ -329,7 +329,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
/*!
Specifies whether this progress indicator should be indeterminate or display progress based on it's max and min.
- @param isDeterminate YES makes the indicator indeterminate
+ @param isDeterminate \c YES makes the indicator indeterminate
*/
- (void)setIndeterminate:(BOOL)isIndeterminate
{
@@ -342,7 +342,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
/*!
- Returns YES if the progress bar is indeterminate.
+ Returns \c YES if the progress bar is indeterminate.
*/
- (BOOL)isIndeterminate
{
@@ -377,9 +377,9 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
/*!
- Sets whether the indicator should be displayed when it isn't animating. By default this is YES if the style
- is CPProgressIndicatorBarStyle, and NO if it's CPProgressIndicatorSpinningStyle.
- @param isDisplayedWhenStopped YES means the indicator will be displayed when it's not animating.
+ Sets whether the indicator should be displayed when it isn't animating. By default this is \c YES if the style
+ is CPProgressIndicatorBarStyle, and \c NO if it's CPProgressIndicatorSpinningStyle.
+ @param isDisplayedWhenStopped \c YES means the indicator will be displayed when it's not animating.
*/
- (void)setDisplayedWhenStopped:(BOOL)isDisplayedWhenStopped
{
@@ -394,7 +394,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
/*!
- Returns YES if the progress bar is displayed when not animating.
+ Returns \c YES if the progress bar is displayed when not animating.
*/
- (BOOL)isDisplayedWhenStopped
{
diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j
index 5d07e987b..cdb541abd 100644
--- a/AppKit/CPResponder.j
+++ b/AppKit/CPResponder.j
@@ -46,7 +46,7 @@ CPDownArrowKeyCode = 40;
// Changing the first responder
/*!
- Returns YES if the receiver is able to become the first responder. NO otherwise.
+ Returns \c YES if the receiver is able to become the first responder. \c NO otherwise.
*/
- (BOOL)acceptsFirstResponder
{
@@ -55,8 +55,8 @@ CPDownArrowKeyCode = 40;
/*!
Notifies the receiver that it will become the first responder. The receiver can reject first
- responder if it returns NO. The default implementation always returns YES.
- @return YES if the receiver accepts first responder status.
+ responder if it returns \c NO. The default implementation always returns \c YES.
+ @return \c YES if the receiver accepts first responder status.
*/
- (BOOL)becomeFirstResponder
{
@@ -65,7 +65,7 @@ CPDownArrowKeyCode = 40;
/*!
Notifies the receiver that it has been asked to give up first responder status.
- @return YES if the receiver is willing to give up first responder status.
+ @return \c YES if the receiver is willing to give up first responder status.
*/
- (BOOL)resignFirstResponder
{
@@ -96,36 +96,38 @@ CPDownArrowKeyCode = 40;
*/
- (void)interpretKeyEvents:(CPArray)events
{
- var event,
- index = 0;
-
- while(event = events[index++])
+ var index = 0,
+ count = [events count];
+
+ for (; index < count; ++index)
{
+ var event = events[index];
+
switch([event keyCode])
{
- case CPLeftArrowKeyCode: [self moveBackward:self];
+ case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)];
break;
- case CPRightArrowKeyCode: [self moveForward:self];
+ case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)];
break;
- case CPUpArrowKeyCode: [self moveUp:self];
+ case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)];
break;
- case CPDownArrowKeyCode: [self moveDown:self];
+ case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)];
break;
- case CPDeleteKeyCode: [self deleteBackward:self];
+ case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)];
break;
case CPReturnKeyCode:
- case 3: [self insertLineBreak:self];
+ case 3: [self doCommandBySelector:@selector(insertLineBreak:)];
break;
- case CPEscapeKeyCode: [self cancel:self];
+ case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)];
break;
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
if (!shift)
- [self insertTab:self];
+ [self doCommandBySelector:@selector(insertTab:)];
else
- [self insertBackTab:self];
+ [self doCommandBySelector:@selector(insertBackTab:)];
break;
@@ -214,9 +216,9 @@ CPDownArrowKeyCode = 40;
/*
FIXME This description is bad.
- Based on anEvent, the receiver should simulate the event.
+ Based on \c anEvent, the receiver should simulate the event.
@param anEvent the event to simulate
- @return YES if the event receiver simulated the event
+ @return \c YES if the event receiver simulated the event
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
@@ -224,14 +226,6 @@ CPDownArrowKeyCode = 40;
}
// Action Methods
-/*!
- Deletes one character backward, or the selection if anything is selected.
- @param aSender the object requesting this
-*/
-- (void)deleteBackward:(id)aSender
-{
-}
-
/*!
Insert a line break at the caret position or selection.
@param aSender the object requesting this
@@ -273,12 +267,12 @@ CPDownArrowKeyCode = 40;
// Dispatch methods
/*!
The receiver will attempt to perform the command,
- if it responds to it. If not, the nextResponder will be called to do it.
+ if it responds to it. If not, the \c -nextResponder will be called to do it.
@param aSelector the command to attempt
*/
- (void)doCommandBySelector:(SEL)aSelector
{
- if([self respondsToSelector:aSelector])
+ if ([self respondsToSelector:aSelector])
[self performSelector:aSelector];
else
[_nextResponder doCommandBySelector:aSelector];
@@ -288,7 +282,7 @@ CPDownArrowKeyCode = 40;
The receiver will attempt to perform the command, or pass it on to the next responder if it doesn't respond to it.
@param aSelector the command to perform
@param anObject the argument to the method
- @return YES if the receiver was able to perform the command, or a responder down the chain was
+ @return \c YES if the receiver was able to perform the command, or a responder down the chain was
able to perform the command.
*/
- (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject
diff --git a/AppKit/CPScreen.j b/AppKit/CPScreen.j
new file mode 100644
index 000000000..4d0b7b3c8
--- /dev/null
+++ b/AppKit/CPScreen.j
@@ -0,0 +1,16 @@
+
+@import
+
+
+#import "CoreGraphics/CGGeometry.h"
+
+@implementation CPScreen : CPObject
+{
+}
+
+- (CGRect)visibleFrame
+{
+ return _CGRectMake(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
+}
+
+@end
\ No newline at end of file
diff --git a/AppKit/CPScrollView.j b/AppKit/CPScrollView.j
index 9b92c6032..4c223422d 100644
--- a/AppKit/CPScrollView.j
+++ b/AppKit/CPScrollView.j
@@ -38,7 +38,9 @@
@implementation CPScrollView : CPView
{
CPClipView _contentView;
-
+ CPClipView _headerClipView;
+ CPView _cornerView;
+
BOOL _hasVerticalScroller;
BOOL _hasHorizontalScroller;
BOOL _autohidesScrollers;
@@ -57,23 +59,27 @@
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
-
+
if (self)
{
_verticalLineScroll = 10.0;
_verticalPageScroll = 10.0;
-
+
_horizontalLineScroll = 10.0;
_horizontalPageScroll = 10.0;
_contentView = [[CPClipView alloc] initWithFrame:[self bounds]];
-
+
[self addSubview:_contentView];
-
+
+ _headerClipView = [[CPClipView alloc] init];
+
+ [self addSubview:_headerClipView];
+
[self setHasVerticalScroller:YES];
[self setHasHorizontalScroller:YES];
}
-
+
return self;
}
@@ -100,24 +106,24 @@
*/
- (void)setContentView:(CPClipView)aContentView
{
- if (!aContentView)
+ if (_contentView !== aContentView || !aContentView)
return;
-
+
var documentView = [aContentView documentView];
-
+
if (documentView)
[documentView removeFromSuperview];
-
+
[_contentView removeFromSuperview];
-
- var size = [self contentSize];
-
+
_contentView = aContentView;
-
- [_contentView setFrame:CGRectMake(0.0, 0.0, size.width, size.height)];
+
[_contentView setDocumentView:documentView];
[self addSubview:_contentView];
+
+ // This will size the content view appropriately, so no need to size it in this method.
+ [self reflectScrolledClipView:_contentView];
}
/*!
@@ -134,8 +140,11 @@
*/
- (void)setDocumentView:(CPView)aView
{
- [_contentView setDocumentView:aView];
- [self reflectScrolledClipView:_contentView];
+ [_contentView setDocumentView:aView];
+
+ // FIXME: This should be observed.
+ [self _updateCornerAndHeaderView];
+ [self reflectScrolledClipView:_contentView];
}
/*!
@@ -166,72 +175,98 @@
// [_verticalScroller setEnabled:NO];
// [_horizontalScroller setEnabled:NO];
}
-
+
[_contentView setFrame:[self bounds]];
-
+ [_headerClipView setFrame:_CGRectMakeZero()];
+
--_recursionCount;
-
+
return;
}
- var documentFrame = [documentView frame],
- contentViewFrame = [self bounds],
- scrollPoint = [_contentView bounds].origin,
- difference = _CGSizeMake(CPRectGetWidth(documentFrame) - CPRectGetWidth(contentViewFrame), CPRectGetHeight(documentFrame) - CPRectGetHeight(contentViewFrame)),
- shouldShowVerticalScroller = (!_autohidesScrollers || difference.height > 0.0) && _hasVerticalScroller,
- shouldShowHorizontalScroller = (!_autohidesScrollers || difference.width > 0.0) && _hasHorizontalScroller,
- wasShowingVerticalScroller = ![_verticalScroller isHidden],
- wasShowingHorizontalScroller = ![_horizontalScroller isHidden],
- verticalScrollerWidth = _CGRectGetWidth([_verticalScroller frame]);
- horizontalScrollerHeight = _CGRectGetHeight([_horizontalScroller frame]);
+ var documentFrame = [documentView frame], // the size of the whole document
+ contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers)
+ headerClipViewFrame = [self _headerClipViewFrame],
+ headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
- if (_autohidesScrollers)
- {
- // Check to see if either affected the other!
- if (shouldShowVerticalScroller)
- shouldShowHorizontalScroller = (!_autohidesScrollers || difference.width > -verticalScrollerWidth) && _hasHorizontalScroller;
+ contentFrame.origin.y += headerClipViewHeight;
+ contentFrame.size.height -= headerClipViewHeight;
- if (shouldShowHorizontalScroller)
- shouldShowVerticalScroller = (!_autohidesScrollers || difference.height > -horizontalScrollerHeight) && _hasVerticalScroller;
- }
-
- [_verticalScroller setHidden:!shouldShowVerticalScroller];
- [_verticalScroller setEnabled:difference.height > 0.0];
-
- [_horizontalScroller setHidden:!shouldShowHorizontalScroller];
- [_horizontalScroller setEnabled:difference.width > 0.0];
+ var difference = _CGSizeMake(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentFrame), _CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentFrame)),
+ verticalScrollerWidth = _CGRectGetWidth([_verticalScroller frame]),
+ horizontalScrollerHeight = _CGRectGetHeight([_horizontalScroller frame]),
+ hasVerticalScroll = difference.height > 0.0,
+ hasHorizontalScroll = difference.width > 0.0,
+ shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll),
+ shouldShowHorizontalScroller = _hasHorizontalScroller && (!_autohidesScrollers || hasHorizontalScroll);
+ // Now we have to account for the shown scrollers affecting the deltas.
if (shouldShowVerticalScroller)
{
- var verticalScrollerHeight = CPRectGetHeight(contentViewFrame);
-
- if (shouldShowHorizontalScroller)
- verticalScrollerHeight -= horizontalScrollerHeight;
-
difference.width += verticalScrollerWidth;
- contentViewFrame.size.width -= verticalScrollerWidth;
-
- [_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height
- knobProportion:CPRectGetHeight(contentViewFrame) / CPRectGetHeight(documentFrame)];
- [_verticalScroller setFrame:CPRectMake(CPRectGetMaxX(contentViewFrame), 0.0, verticalScrollerWidth, verticalScrollerHeight)];
+ hasHorizontalScroll = difference.width > 0.0;
+ shouldShowHorizontalScroller = _hasHorizontalScroller && (!_autohidesScrollers || hasHorizontalScroll);
}
- else if (wasShowingVerticalScroller)
- [_verticalScroller setFloatValue:0.0 knobProportion:1.0];
-
+
if (shouldShowHorizontalScroller)
{
difference.height += horizontalScrollerHeight;
- contentViewFrame.size.height -= horizontalScrollerHeight;
-
- [_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width
- knobProportion:CPRectGetWidth(contentViewFrame) / CPRectGetWidth(documentFrame)];
- [_horizontalScroller setFrame:CPRectMake(0.0, CPRectGetMaxY(contentViewFrame), CPRectGetWidth(contentViewFrame), horizontalScrollerHeight)];
+ hasVerticalScroll = difference.height > 0.0;
+ shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll);
+ }
+
+ // We now definitively know which scrollers are shown or not, as well as whether they are showing scroll values.
+ [_verticalScroller setHidden:!shouldShowVerticalScroller];
+ [_verticalScroller setEnabled:hasVerticalScroll];
+
+ [_horizontalScroller setHidden:!shouldShowHorizontalScroller];
+ [_horizontalScroller setEnabled:hasHorizontalScroll];
+
+ // We can thus appropriately account for them changing the content size.
+ if (shouldShowVerticalScroller)
+ contentFrame.size.width -= verticalScrollerWidth;
+
+ if (shouldShowHorizontalScroller)
+ contentFrame.size.height -= horizontalScrollerHeight;
+
+ var scrollPoint = [_contentView bounds].origin,
+ wasShowingVerticalScroller = ![_verticalScroller isHidden],
+ wasShowingHorizontalScroller = ![_horizontalScroller isHidden];
+
+ if (shouldShowVerticalScroller)
+ {
+ var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight),
+ verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY;
+
+ if (shouldShowHorizontalScroller)
+ verticalScrollerHeight -= horizontalScrollerHeight;
+
+ [_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
+ [_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
+ [_verticalScroller setFrame:_CGRectMake(_CGRectGetMaxX(contentFrame), verticalScrollerY, verticalScrollerWidth, verticalScrollerHeight)];
+ }
+ else if (wasShowingVerticalScroller)
+ {
+ [_verticalScroller setFloatValue:0.0];
+ [_verticalScroller setKnobProportion:1.0];
+ }
+
+ if (shouldShowHorizontalScroller)
+ {
+ [_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
+ [_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
+ [_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
}
else if (wasShowingHorizontalScroller)
- [_horizontalScroller setFloatValue:0.0 knobProportion:1.0];
-
- [_contentView setFrame:contentViewFrame];
-
+ {
+ [_horizontalScroller setFloatValue:0.0];
+ [_horizontalScroller setKnobProportion:1.0];
+ }
+
+ [_contentView setFrame:contentFrame];
+ [_headerClipView setFrame:headerClipViewFrame];
+ [_cornerView setFrame:[self _cornerViewFrame]];
+
--_recursionCount;
}
@@ -269,7 +304,7 @@
/*!
Specifies whether the scroll view can have a horizontal scroller.
- @param hasHorizontalScroller YES lets the scroll view
+ @param hasHorizontalScroller \c YES lets the scroll view
allocate a horizontal scroller if necessary.
*/
- (void)setHasHorizontalScroller:(BOOL)shouldHaveHorizontalScroller
@@ -280,7 +315,7 @@
_hasHorizontalScroller = shouldHaveHorizontalScroller;
if (_hasHorizontalScroller && !_horizontalScroller)
- [self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, CPRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
+ [self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, _CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
else if (!_hasHorizontalScroller && _horizontalScroller)
{
@@ -291,7 +326,7 @@
}
/*!
- Returns YES if the scroll view can have a horizontal scroller.
+ Returns \c YES if the scroll view can have a horizontal scroller.
*/
- (BOOL)hasHorizontalScroller
{
@@ -332,7 +367,7 @@
/*!
Specifies whether the scroll view has can have
a vertical scroller. It allocates it if necessary.
- @param hasVerticalScroller YES allows
+ @param hasVerticalScroller \c YES allows
the scroll view to display a vertical scroller
*/
- (void)setHasVerticalScroller:(BOOL)shouldHaveVerticalScroller
@@ -343,7 +378,7 @@
_hasVerticalScroller = shouldHaveVerticalScroller;
if (_hasVerticalScroller && !_verticalScroller)
- [self setVerticalScroller:[[CPScroller alloc] initWithFrame:CPRectMake(0.0, 0.0, [CPScroller scrollerWidth], CPRectGetHeight([self bounds]))]];
+ [self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))]];
else if (!_hasVerticalScroller && _verticalScroller)
{
@@ -354,7 +389,7 @@
}
/*!
- Returns YES if the scroll view can have a vertical scroller.
+ Returns \c YES if the scroll view can have a vertical scroller.
*/
- (BOOL)hasVerticalScroller
{
@@ -363,7 +398,7 @@
/*!
Sets whether the scroll view hides its scoll bars when not needed.
- @param autohidesScrollers YES causes the scroll bars
+ @param autohidesScrollers \c YES causes the scroll bars
to be hidden when not needed.
*/
- (void)setAutohidesScrollers:(BOOL)autohidesScrollers
@@ -377,20 +412,76 @@
}
/*!
- Returns YES if the scroll view hides its scroll
+ Returns \c YES if the scroll view hides its scroll
bars when not necessary.
*/
- (BOOL)autohidesScrollers
{
return _autohidesScrollers;
}
-/*
-- (void)setFrameSize:(CPRect)aSize
+
+- (void)_updateCornerAndHeaderView
{
- [super setFrameSize:aSize];
-
+ var documentView = [self documentView],
+ currentHeaderView = [self _headerView],
+ documentHeaderView = [documentView respondsToSelector:@selector(headerView)] ? [documentView headerView] : nil;
+
+ if (currentHeaderView !== documentHeaderView)
+ {
+ [currentHeaderView removeFromSuperview];
+ [_headerClipView setDocumentView:documentHeaderView];
+ }
+
+ var documentCornerView = [documentView respondsToSelector:@selector(cornerView)] ? [documentView cornerView] : nil;
+
+ if (_cornerView !== documentCornerView)
+ {
+ [_cornerView removeFromSuperview];
+
+ _cornerView = documentCornerView;
+
+ if (_cornerView)
+ [self addSubview:_cornerView];
+ }
+
[self reflectScrolledClipView:_contentView];
-}*/
+}
+
+- (CPView)_headerView
+{
+ var headerClipViewSubviews = [_headerClipView subviews];
+
+ return [headerClipViewSubviews count] ? headerClipViewSubviews[0] : nil;
+}
+
+- (CGRect)_cornerViewFrame
+{
+ if (!_cornerView)
+ return _CGRectMakeZero();
+
+ var bounds = [self bounds],
+ frame = [_cornerView frame];
+
+ frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
+ frame.origin.y = 0;
+
+ return frame;
+}
+
+- (CGRect)_headerClipViewFrame
+{
+ var headerView = [self _headerView];
+
+ if (!headerView)
+ return _CGRectMakeZero();
+
+ var frame = [self bounds];
+
+ frame.size.height = _CGRectGetHeight([headerView frame]);
+ frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
+
+ return frame;
+}
/* @ignore */
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
@@ -448,6 +539,7 @@
}
[_contentView scrollToPoint:contentBounds.origin];
+ [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
}
/*!
@@ -580,20 +672,19 @@
*/
- (void)scrollWheel:(CPEvent)anEvent
{
- var value = [_verticalScroller floatValue],
- documentFrame = [[self documentView] frame],
+ var documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds];
contentBounds.origin.x += [anEvent deltaX] * _horizontalLineScroll;
contentBounds.origin.y += [anEvent deltaY] * _verticalLineScroll;
[_contentView scrollToPoint:contentBounds.origin];
+ [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
}
- (void)keyDown:(CPEvent)anEvent
{
var keyCode = [anEvent keyCode],
- value = [_verticalScroller floatValue],
documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds];
@@ -627,6 +718,7 @@
}
[_contentView scrollToPoint:contentBounds.origin];
+ [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin, 0)];
}
@end
diff --git a/AppKit/CPScroller.j b/AppKit/CPScroller.j
index d922603d7..69bd0208c 100644
--- a/AppKit/CPScroller.j
+++ b/AppKit/CPScroller.j
@@ -64,9 +64,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
BOOL _isVertical @accessors(readonly, getter=isVertical);
float _knobProportion;
-
+
CPScrollerPart _hitPart;
-
+
CPScrollerPart _trackingPart;
float _trackingFloatValue;
CGPoint _trackingStartPoint;
@@ -104,11 +104,12 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_controlSize = CPRegularControlSize;
_partRects = [];
- [self setFloatValue:0.0 knobProportion:1.0];
+ [self setFloatValue:0.0];
+ [self setKnobProportion:1.0];
_hitPart = CPScrollerNoPart;
- [self _recalculateIsVertical];
+ [self _calculateIsVertical];
}
return self;
@@ -120,7 +121,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
+ (float)scrollerWidth
{
- return 17.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
+ return 15.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
}
/*!
@@ -129,7 +130,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
{
- return 17.0;//_CPScrollerWidths[aControlSize];
+ return 15.0;//_CPScrollerWidths[aControlSize];
}
/*!
@@ -155,28 +156,17 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
return _controlSize;
}
-// Setting the Knob Position
-/*!
- Sets the scroller's knob position (ranges from 0.0 to 1.0).
- @param aValue the knob position (ranges from 0.0 to 1.0)
-*/
-- (void)setFloatValue:(float)aValue
+- (void)setObjectValue:(id)aValue
{
- [super setFloatValue:MIN(1.0, MAX(0.0, aValue))];
-
- [self setNeedsLayout];
+ [super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
}
-/*!
- Sets the position and proportion of the knob.
- @param aValue the knob position (ranges from 0.0 to 1.0)
- @param aProportion the knob's proportion (ranges from 0.0 to 1.0)
-*/
-- (void)setFloatValue:(float)aValue knobProportion:(float)aProportion
+- (void)setKnobProportion:(float)aProportion
{
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
- [self setFloatValue:aValue];
+ [self setNeedsDisplay:YES];
+ [self setNeedsLayout];
}
/*!
@@ -208,7 +198,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
}
/*!
- Returns the part of the scroller that would be hit by aPoint.
+ Returns the part of the scroller that would be hit by \c aPoint.
@param aPoint the simulated point hit
@return the part of the scroller that intersects the point
*/
@@ -533,15 +523,15 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
}
-- (void)_recalculateIsVertical
+- (void)_calculateIsVertical
{
// Recalculate isVertical.
var bounds = [self bounds],
width = _CGRectGetWidth(bounds),
height = _CGRectGetHeight(bounds);
-
+
_isVertical = width < height ? 1 : (width > height ? 0 : -1);
-
+
if (_isVertical === 1)
[self setThemeState:CPThemeStateVertical];
else if (_isVertical === 0)
@@ -552,8 +542,6 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{
[super setFrameSize:aSize];
- [self _recalculateIsVertical];
-
[self checkSpaceForParts];
[self setNeedsLayout];
}
@@ -590,18 +578,16 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
_controlSize = CPRegularControlSize;
if ([aCoder containsValueForKey:CPScrollerControlSizeKey])
_controlSize = [aCoder decodeIntForKey:CPScrollerControlSizeKey];
-
+
_knobProportion = 1.0;
if ([aCoder containsValueForKey:CPScrollerKnobProportionKey])
_knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
-
+
_partRects = [];
_hitPart = CPScrollerNoPart;
- [self _recalculateIsVertical];
-// [self checkSpaceForParts];
-// [self setNeedsLayout];
+ [self _calculateIsVertical];
}
return self;
@@ -616,3 +602,18 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
}
@end
+
+@implementation CPScroller (Deprecated)
+
+/*!
+ Sets the position and proportion of the knob.
+ @param aValue the knob position (ranges from 0.0 to 1.0)
+ @param aProportion the knob's proportion (ranges from 0.0 to 1.0)
+*/
+- (void)setFloatValue:(float)aValue knobProportion:(float)aProportion
+{
+ [self setFloatValue:aValue];
+ [self setKnobProportion:aProportion];
+}
+
+@end
diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j
new file mode 100644
index 000000000..63f61b6ce
--- /dev/null
+++ b/AppKit/CPSearchField.j
@@ -0,0 +1,704 @@
+/*
+ * CPSearchField.j
+ * AppKit
+ *
+ * Created by cacaodev.
+ * Copyright 2009.
+ *
+ * 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 "CPTextField.j"
+
+#include "Platform/Platform.h"
+
+/*!
+ @global
+ @group Menu tags
+*/
+CPSearchFieldRecentsTitleMenuItemTag = 1000;
+/*!
+ @global
+ @group Menu tags
+*/
+CPSearchFieldRecentsMenuItemTag = 1001;
+/*!
+ @global
+ @group Menu tags
+*/
+CPSearchFieldClearRecentsMenuItemTag = 1002;
+/*!
+ @global
+ @group Menu tags
+*/
+CPSearchFieldNoRecentsMenuItemTag = 1003;
+
+var CPSearchFieldSearchImage = nil,
+ CPSearchFieldFindImage = nil,
+ CPSearchFieldCancelImage = nil,
+ CPSearchFieldCancelPressedImage = nil;
+
+/*!
+ @ingroup appkit
+ @class CPSearchField
+ The CPSearchField class defines the programmatic interface for text fields that are optimized for text-based searches. A CPSearchField object directly inherits from the CPTextField class. The search field implemented by these classes presents a standard user interface for searches, including a search button, a cancel button, and a pop-up icon menu for listing recent search strings and custom search categories.
+
+ When the user types and then pauses, the text field's action message is sent to its target. You can query the text field's string value for the current text to search for. Do not rely on the sender of the action to be an CPMenu object because the menu may change. If you need to change the menu, modify the search menu template and call the setSearchMenuTemplate: method to update.
+*/
+@implementation CPSearchField : CPTextField
+{
+ CPButton _searchButton;
+ CPButton _cancelButton;
+ CPMenu _searchMenuTemplate;
+ CPMenu _searchMenu;
+
+ CPString _recentsAutosaveName;
+ CPArray _recentSearches;
+
+ int _maximumRecents;
+ BOOL _sendsWholeSearchString;
+ BOOL _sendsSearchStringImmediately;
+ CPTimer _partialStringTimer;
+}
+
++ (void)initialize
+{
+ if (self != [CPSearchField class])
+ return;
+
+ var bundle = [CPBundle bundleForClass:self];
+ CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"]];
+ CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"]];
+ CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"]];
+ CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"]];
+}
+
+- (id)initWithFrame:(CPRect)frame
+{
+ self = [super initWithFrame:frame];
+ if (self != nil)
+ {
+ _recentSearches = [CPArray array];
+ _maximumRecents = 10;
+ _sendsWholeSearchString = NO;
+ _sendsSearchStringImmediately = NO;
+
+ [self setBezeled:YES];
+ [self setBezelStyle:CPTextFieldRoundedBezel];
+ [self setBordered:YES];
+ [self setEditable:YES];
+ [self setDelegate:self];
+
+ _cancelButton = [[CPButton alloc] initWithFrame:CPMakeRect(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
+ [self resetCancelButton];
+
+
+ [_cancelButton setHidden:YES];
+ [self addSubview:_cancelButton];
+
+ _searchButton = [[CPButton alloc] initWithFrame:CPMakeRect(5,(frame.size.height-25)/2,25,25)];
+ [_searchButton setBezelStyle:CPRegularSquareBezelStyle];
+ [_searchButton setBordered:NO];
+ [_searchButton setImageScaling:CPScaleToFit];
+
+#if PLATFORM(DOM)
+ _cancelButton._DOMElement.style.cursor = "default";
+ _searchButton._DOMElement.style.cursor = "default";
+#endif
+
+ [self setSearchMenuTemplate:[self _searchMenuTemplate]];
+ [self addSubview:_searchButton];
+ }
+
+ return self;
+}
+
+- (id)copy
+{
+ var copy = [super copy];
+
+ [copy setCancelButton:[_cancelButton copy]];
+ [copy setSearchButton:[_searchButton copy]];
+ [copy setrecentsAutosaveName:[_recentsAutosaveName copy]];
+ [copy setSendsWholeSearchString:[_sendsWholeSearchString copy]];
+ [copy setSendsSearchStringImmediately:[_sendsSearchStringImmediately copy]];
+ [copy setMaximumRecents:_maximumRecents];
+ [copy setSearchMenutemplate:[_searchMenuTemplate copy]];
+
+ return copy;
+}
+
+// Managing Buttons
+/*!
+ Sets the button used to display the search-button image
+ @param button The search button.
+*/
+- (void)setSearchButton:(CPButton)button
+{
+ _searchButton = button;
+}
+
+/*!
+ Returns the button used to display the search-button image.
+ @return The search button.
+*/
+- (CPButton)searchButton
+{
+ return _searchButton;
+}
+
+/*!
+ Resets the search button to its default attributes.
+ This method resets the target, action, regular image, and pressed image. By default, when users click the search button or press the Return key, the action defined for the receiver is sent to its designated target. This method gives you a way to customize the search button for specific situations and then reset the button defaults without having to undo changes individually.
+*/
+- (void)resetSearchButton
+{
+ var searchButtonImage,
+ action,
+ target,
+ button = [self searchButton];
+
+ if (_searchMenuTemplate == nil)
+ {
+ searchButtonImage = CPSearchFieldSearchImage;
+ action = [self action];
+ target = [self target];
+ }
+ else
+ {
+ searchButtonImage = CPSearchFieldFindImage;
+ action = @selector(_showMenu:);
+ target = self;
+ }
+
+ [button setImage:searchButtonImage];
+ [button setTarget:target];
+ [button setAction:action];
+}
+
+/*!
+ Sets the button object used to display the cancel-button image.
+ @param button The cancel button.
+*/
+- (void)setCancelButton:(CPButton)button
+{
+ _cancelButton = button;
+}
+
+/*!
+ Returns the button object used to display the cancel-button image.
+ @return The cancel button.
+*/
+- (CPButton)cancelButton
+{
+ return _cancelButton;
+}
+
+/*!
+ Resets the cancel button to its default attributes.
+ This method resets the target, action, regular image, and pressed image. By default, when users click the cancel button, the delete: action message is sent up the responder chain. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
+*/
+- (void)resetCancelButton
+{
+ var button = [self cancelButton];
+ [button setBezelStyle:CPRegularSquareBezelStyle];
+ [button setBordered:NO];
+ [button setImageScaling:CPScaleToFit];
+ [button setImage:CPSearchFieldCancelImage];
+ [button setAlternateImage:CPSearchFieldCancelPressedImage];
+ [button setTarget:self];
+ [button setAction:@selector(_searchFieldCancel:)];
+}
+
+// Custom Layout
+/*!
+ Modifies the bounding rectangle for the search-text field.
+ @param rect The current bounding rectangle for the search text field.
+ @return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter.
+ Subclasses can override this method to return a new bounding rectangle for the text-field object. You might use this method to provide a custom layout for the search field control.
+*/
+- (CPRect)searchTextRectForBounds:(CPRect)rect
+{
+ var leftOffset = 0, width = rect.size.width;
+
+ if (_searchButton)
+ {
+ var searchRect = [_searchButton frame];
+ leftOffset = searchRect.origin.x + searchRect.size.width;
+ }
+
+ if (_cancelButton)
+ {
+ var cancelRect = [_cancelButton frame];
+ width = cancelRect.origin.x - leftOffset;
+ }
+
+ return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height);
+}
+
+/*!
+ Modifies the bounding rectangle for the search button.
+ @param rect The current bounding rectangle for the search button.
+ Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control.
+*/
+- (CPRect)searchButtonRectForBounds:(CPRect)rect // fix
+{
+ return [_searchButton frame];
+}
+
+/*!
+ Modifies the bounding rectangle for the cancel button.
+ @param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter.
+ Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control.
+*/
+- (CPRect)cancelButtonRectForBounds:(CPRect)rect
+{
+ return [_cancelButton frame];
+}
+
+// Managing Menu Templates
+/*!
+ Returns the menu template object used to dynamically construct the search pop-up icon menu.
+ @return The current menu template.
+*/
+- (CPMenu)searchMenuTemplate
+{
+ return _searchMenuTemplate;
+}
+
+/*!
+ Sets the menu template object used to dynamically construct the receiver's pop-up icon menu.
+ @param menu The menu template to use.
+ The receiver looks for the tag constants described in ÒMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ÒConfiguring a Search MenuÓ for a sample of how you might set up the search menu template.
+*/
+- (void)setSearchMenuTemplate:(CPMenu)menu
+{
+ _searchMenuTemplate = menu;
+
+ [self resetSearchButton];
+ [self _updateSearchMenu];
+}
+
+// Managing Search Modes
+/*!
+ Returns a Boolean value indicating whether the receiver sends the search action message when the user clicks the search button (or presses return) or after each keystroke.
+ @return \c YES if the action message is sent all at once when the user clicks the search button or presses return; otherwise, NO if the search string is sent after each keystroke. The default value is NO.
+*/
+- (BOOL)sendsWholeSearchString
+{
+ return _sendsWholeSearchString;
+}
+
+/*!
+ Sets whether the receiver sends the search action message when the user clicks the search button (or presses return) or after each keystroke.
+ @param flag \c YES to send the action message all at once when the user clicks the search button or presses return; otherwise, NO to send the search string after each keystroke.
+*/
+- (void)setSendsWholeSearchString:(BOOL)flag
+{
+ _sendsWholeSearchString = flag;
+}
+
+/*!
+ Returns a Boolean value indicating whether the receiver sends its action immediately upon being notified of changes to the search field text or after a brief pause.
+ @return \c YES if the text field sends its action immediately upon notification of any changes to the search field; otherwise, NO.
+*/
+- (BOOL)sendsSearchStringImmediately
+{
+ return _sendsSearchStringImmediately;
+}
+
+/*!
+ Sets whether the text field sends its action message to the target immediately upon notification of any changes to the search field text or after a brief pause.
+ @param flag \c YES to send the text field's action immediately upon notification of any changes to the search field; otherwise, NO if you want the text field to pause briefly before sending its action message. Pausing gives the user the opportunity to type more text into the search field before initiating the search.
+*/
+- (void)setSendsSearchStringImmediately:(BOOL)flag
+{
+ _sendsSearchStringImmediately = flag;
+}
+
+// Managing Recent Search Strings
+/*!
+ Returns the maximum number of recent search strings to display in the custom search menu.
+ @return The maximum number of search strings that can appear in the menu. This value is between 0 and 254.
+*/
+- (int)maximumRecents
+{
+ return _maximumRecents;
+}
+
+/*!
+ Sets the maximum number of search strings that can appear in the search menu.
+ @param maxRecents The maximum number of search strings that can appear in the menu. This value can be between 0 and 254. Specifying a value less than 0 sets the value to the default, which is 10. Specifying a value greater than 254 sets the maximum to 254.
+*/
+- (void)setMaximumRecents:(int)max
+{
+ if (max > 254)
+ max = 254;
+ else if (max < 0)
+ max = 10;
+
+ _maximumRecents = max;
+}
+
+/*!
+ Returns the list of recent search strings for the control.
+ @return An array of \c CPString objects, each of which contains a search string either displayed in the search menu or from a recent autosave archive. If there have been no recent searches and no prior searches saved under an autosave name, this array may be empty.
+ */
+- (CPArray)recentSearches
+{
+ return _recentSearches;
+}
+
+/*!
+ Sets the list of recent search strings to list in the pop-up icon menu of the receiver.
+ @param searches An array of CPString objects containing the search strings.
+ You might use this method to set the recent list of searches from an archived copy.
+*/
+- (void)setRecentSearches:(CPArray)searches
+{
+ var max = MIN([self maximumRecents],[searches count]);
+ var searches = [searches subarrayWithRange:CPMakeRange(0,max)];
+ _recentSearches = searches;
+
+ [self _autosaveRecentSearchList];
+}
+
+/*!
+ Returns the key under which the prior list of recent search strings has been archived.
+ @return The autosave name, which is used as a key in the standard user defaults to save the recent searches. The default value is nil, which causes searches not to be autosaved.
+*/
+- (CPString)recentsAutosaveName
+{
+ return _recentsAutosaveName;
+}
+
+/*!
+ Sets the autosave name under which the receiver automatically archives the list of recent search strings.
+ @param name The autosave name, which is used as a key in the standard user defaults to save the recent searches. If you specify nil or an empty string for this parameter, no autosave name is set and searches are not autosaved.
+*/
+- (void)setRecentsAutosaveName:(CPString)name
+{
+ _recentsAutosaveName = name;
+
+ if(name != nil)
+ [self _registerForAutosaveNotification];
+ else
+ [self _deregisterForAutosaveNotification];
+}
+
+// Private methods and subclassing
+
+- (CPRect)contentRectForBounds:(CPRect)bounds
+{
+ var superbounds = [super contentRectForBounds:bounds];
+ return [self searchTextRectForBounds:superbounds];
+}
+
++ (double)_keyboardDelayForPartialSearchString:(CPString)string
+{
+ return (6 - MIN([string length],4))/10;
+}
+
+- (CPMenu)menu
+{
+ return _searchMenu;
+}
+
+- (BOOL)isOpaque
+{
+ return [super isOpaque] && [_cancelButton isOpaque] && [_searchButton isOpaque];
+}
+
+- (void)_updateCancelButtonVisibility
+{
+ [_cancelButton setHidden:([[self stringValue] length] == 0)];
+}
+
+- (void)controlTextDidChange:(CPNotification)aNotification
+{
+ if(!_sendsWholeSearchString)
+ {
+ if(_sendsSearchStringImmediately)
+ [self _sendPartialString];
+ else
+ {
+ [_partialStringTimer invalidate];
+ var timeInterval = [CPSearchField _keyboardDelayForPartialSearchString:[self stringValue]];
+
+ _partialStringTimer = [CPTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(_sendPartialString) userInfo:nil repeats:NO];
+ }
+ }
+ [self _updateCancelButtonVisibility];
+}
+
+- (void)sendAction:(SEL)anAction to:(id)anObject
+{
+ [super sendAction:anAction to:anObject];
+
+ [_partialStringTimer invalidate];
+
+ var current_value = [self objectValue];
+ if(current_value != nil && current_value != "" && ![_recentSearches containsObject:current_value])
+ {
+ [self _addStringToRecentSearches:current_value];
+ [self _updateSearchMenu];
+ }
+
+ [self _updateCancelButtonVisibility];
+}
+
+- (void)_addStringToRecentSearches:(CPString)string
+{
+ var newSearches = [CPMutableArray arrayWithArray:_recentSearches];
+ [newSearches addObject:string];
+ [self setRecentSearches:newSearches];
+}
+
+- (BOOL)trackMouse:(CPEvent)event
+{
+ var rect;
+ var point;
+ var location = [event locationInWindow];
+
+ point = [self convertPoint:location fromView:nil];
+
+ rect = [self searchButtonRectForBounds:[self frame]];
+
+ if (CPRectContainsPoint(rect,point))
+ {
+ return [[self searchButton] trackMouse:event];
+ }
+
+ rect = [self cancelButtonRectForBounds:[self frame]];
+ if (CPRectContainsPoint(rect,point))
+ {
+ return [[self cancelButton] trackMouse:event];
+ }
+
+ return [super trackMouse:event];
+}
+
+- (CPMenu)_searchMenuTemplate
+{
+ var template, item;
+
+ template = [[CPMenu alloc] init];
+
+ item = [[CPMenuItem alloc] initWithTitle:@"Recent searches" action:NULL keyEquivalent:@""];
+ [item setTag:CPSearchFieldRecentsTitleMenuItemTag];
+ [item setEnabled:NO];
+ [template addItem:item];
+
+ item = [[CPMenuItem alloc] initWithTitle:@"Recent search item" action:@selector(_searchFieldSearch:) keyEquivalent:@""];
+ [item setTag:CPSearchFieldRecentsMenuItemTag];
+ [item setTarget:self];
+ [template addItem:item];
+
+ item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches" action:@selector(_searchFieldClearRecents:) keyEquivalent:@""];
+ [item setTag:CPSearchFieldClearRecentsMenuItemTag];
+ [item setTarget:self];
+ [template addItem:item];
+
+ item = [[CPMenuItem alloc] initWithTitle:@"No recent searches" action:NULL keyEquivalent:@""];
+ [item setTag:CPSearchFieldNoRecentsMenuItemTag];
+ [item setEnabled:NO];
+ [template addItem:item];
+
+ return template;
+}
+
+- (void)_updateSearchMenu
+{
+ if(_searchMenuTemplate == nil)
+ return;
+
+ var i, menu = [[CPMenu alloc] init];
+ var countOfRecents = [_recentSearches count];
+
+ for (i = 0; i < [_searchMenuTemplate numberOfItems]; i++)
+ {
+ var item = [_searchMenuTemplate itemAtIndex:i];
+ var tag = [item tag];
+
+ if(tag == CPSearchFieldClearRecentsMenuItemTag && countOfRecents != 0)
+ {
+ var separator = [CPMenuItem separatorItem];
+ [menu addItem:separator];
+ }
+
+ if (!(tag == CPSearchFieldRecentsTitleMenuItemTag && countOfRecents == 0) &&
+ !(tag == CPSearchFieldClearRecentsMenuItemTag && countOfRecents == 0) &&
+ !(tag == CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
+ !(tag == CPSearchFieldRecentsMenuItemTag))
+ {
+ var templateItem = [[CPMenuItem alloc] initWithTitle:[item title] action:[item action] keyEquivalent:[item keyEquivalent]];
+ [templateItem setTarget:[item target]];
+ [templateItem setEnabled:[item isEnabled]];
+ [templateItem setTag:[item tag]];
+ [menu addItem:templateItem];
+ }
+ else if (tag == CPSearchFieldRecentsMenuItemTag)
+ {
+ var j;
+ for (j = 0; j < countOfRecents; j++)
+ {
+ var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j] action:[item action] keyEquivalent:[item keyEquivalent]];
+ [rencentItem setTarget:[item target]];
+ [menu addItem:rencentItem];
+ }
+ }
+ }
+ _searchMenu = menu;
+}
+
+
+- (void)_showMenu:(id)sender
+{
+ if(_searchMenu == nil || ![self isEnabled])
+ return;
+
+ [super selectText:nil];
+
+ var origin = CPMakePoint([self frame].origin.x, [self frame].origin.y + [self frame].size.height);
+ var anEvent = [CPEvent keyEventWithType:CPRightMouseDown location:origin modifierFlags:0 timestamp:[CPDate date] windowNumber:1 context:[[CPGraphicsContext currentContext] graphicsPort] characters:"" charactersIgnoringModifiers:"" isARepeat:NO keyCode:0];
+
+ [CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
+}
+
+- (void)_sendPartialString
+{
+ [[self target] performSelector:[self action] withObject:self];
+}
+
+- (void)_searchFieldCancel:(id)sender
+{
+ [self setObjectValue:nil];
+ [self _sendPartialString];
+ [self _updateCancelButtonVisibility];
+ [sender setHidden:YES];
+}
+
+- (void)_searchFieldSearch:(id)sender
+{
+ [self setObjectValue:[sender title]];
+ [self _sendPartialString];
+ [self _updateCancelButtonVisibility];
+}
+
+- (void)_searchFieldClearRecents:(id)sender
+{
+ [self setRecentSearches:[CPArray array]];
+ [self _updateSearchMenu];
+ }
+
+- (void)_registerForAutosaveNotification
+{
+ [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_updateAutosavedRecents:) name:@"CPAutosavedRecentsChangedNotification" object:nil];
+}
+
+- (void)_deregisterForAutosaveNotification
+{
+ [[CPNotificationCenter defaultCenter] removeObserver:self name:@"CPAutosavedRecentsChangedNotification" object:nil];
+}
+
+- (void)_updateAutosavedRecents:(id)notification
+{
+ var name = [notification object];
+ var list = [self recentSearches];
+
+ [[CPUserDefaults standardUserDefaults] setObject:list forKey:name];
+
+}
+
+- (void)_autosaveRecentSearchList
+{
+ if(_recentsAutosaveName != nil)
+ [[CPNotificationCenter defaultCenter] postNotificationName:@"CPAutosavedRecentsChangedNotification" object:_recentsAutosaveName];
+}
+
+- (void)_loadRecentSearchList
+{
+ var list,
+ name = [self recentsAutosaveName];
+
+ list = [[CPUserDefaults standardUserDefaults] objectForKey:name];
+ _recentSearches = list;
+}
+
+/*
+- (BOOL)trackMouse:(CPEvent)theEvent inRect:(CPRect)cellFrame ofView:(CPView)aTextView untilMouseUp:(BOOL)flag
+{
+}
+
+- (BOOL)_trimRecentSearchList
+{
+}
+
+- (void)_trackButton:(CPButton)button forEvent:(CPEvent)event inRect:(CPRect)rect ofView:(id)view
+{
+}
+
+- (id)_selectOrEdit:(CPRect)rect inView:(id)view target:(id)target editor:(id)editor event:(id)event start:(int)start end:(int)end
+{
+}
+
+- (void)resetCursorRect:(CPRect)rect inView:(id)view
+{
+}
+*/
+
+@end
+
+var CPSearchButtonKey = @"CPSearchButtonKey",
+ CPCancelButtonKey = @"CPCancelButtonKey",
+ CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
+ CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
+ CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
+ CPMaximumRecentsKey = @"CPMaximumRecentsKey",
+ CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
+
+@implementation CPSearchField (CPCoding)
+
+- (void)encodeWithCoder:(CPCoder)coder
+{
+ [super encodeWithCoder:coder];
+
+ [coder encodeObject:_searchButton forKey:CPSearchButtonKey];
+ [coder encodeObject:_cancelButton forKey:CPCancelButtonKey];
+ [coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
+ [coder encodeBool:_sendsWholeSearchString forKey:CPSendsWholeSearchStringKey];
+ [coder encodeBool:_sendsSearchStringImmediately forKey:CPSendsSearchStringImmediatelyKey];
+ [coder encodeInt:_maximumRecents forKey:CPMaximumRecentsKey];
+ [coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
+}
+
+- (id)initWithCoder:(CPCoder)coder
+{
+ self = [super initWithCoder:coder];
+
+ _searchButton = [coder decodeObjectForKey:CPSearchButtonKey];
+ _cancelButton = [coder decodeObjectForKey:CPCancelButtonKey];
+ _recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
+ _sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
+ _sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
+ _maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
+ [self setSearchMenuTemplate:[coder decodeObjectForKey:CPSearchMenuTemplateKey]];
+ [self resetCancelButton];
+ [self setDelegate:self];
+
+ return self;
+}
+
+@end
\ No newline at end of file
diff --git a/AppKit/CPSegmentedControl.j b/AppKit/CPSegmentedControl.j
index 611dc584c..60769e041 100644
--- a/AppKit/CPSegmentedControl.j
+++ b/AppKit/CPSegmentedControl.j
@@ -119,13 +119,13 @@ CPSegmentSwitchTrackingMomentary = 2;
}
else if (aCount < _segments.length)
{
- for (var index = aCount; index < _segments.length; ++index)
- _segments[index] = nil;
+ _segments.length = aCount;
+ _themeStates.length = aCount;
}
-
- if (_selectedSegment < _segments.length)
+
+ if (_selectedSegment >= _segments.length)
_selectedSegment = -1;
-
+
[self tileWithChangedSegment:0];
}
@@ -141,7 +141,7 @@ CPSegmentSwitchTrackingMomentary = 2;
/*!
Selects a segment.
@param aSegment the segment to select
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setSelectedSegment:(unsigned)aSegment
{
@@ -225,7 +225,7 @@ CPSegmentSwitchTrackingMomentary = 2;
Sets the width of the specified segment.
@param aWidth the new width for the segment
@param aSegment the segment to set the width for
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
{
@@ -237,7 +237,7 @@ CPSegmentSwitchTrackingMomentary = 2;
/*!
Returns the width for the specified segment.
@param aSegment the segment to get the width for
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (float)widthForSegment:(unsigned)aSegment
{
@@ -248,7 +248,7 @@ CPSegmentSwitchTrackingMomentary = 2;
Sets the image for the specified segment.
@param anImage the image for the segment
@param aSegment the segment to set the image on
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
{
@@ -262,7 +262,7 @@ CPSegmentSwitchTrackingMomentary = 2;
/*!
Returns the image for the specified segment
@param aSegment the segment to obtain the image for
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (CPImage)imageForSegment:(unsigned)aSegment
{
@@ -273,7 +273,7 @@ CPSegmentSwitchTrackingMomentary = 2;
Sets the label for the specified segment
@param aLabel the label for the segment
@param aSegment the segment to label
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
{
@@ -287,7 +287,7 @@ CPSegmentSwitchTrackingMomentary = 2;
/*!
Returns the label for the specified segment
@param the segment to obtain the label for
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (CPString)labelForSegment:(unsigned)aSegment
{
@@ -298,7 +298,7 @@ CPSegmentSwitchTrackingMomentary = 2;
Sets the menu for the specified segment
@param aMenu the menu to set
@param aSegment the segment to set the menu on
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
{
@@ -308,7 +308,7 @@ CPSegmentSwitchTrackingMomentary = 2;
/*!
Returns the menu for the specified segment.
@param aSegment the segment to obtain the menu for
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (CPMenu)menuForSegment:(unsigned)aSegment
{
@@ -318,9 +318,9 @@ CPSegmentSwitchTrackingMomentary = 2;
/*!
Sets the selection for the specified segment. If only one segment
can be selected at a time, any other segment will be deselected.
- @param isSelected YES selects the segment. NO deselects it.
+ @param isSelected \c YES selects the segment. \c NO deselects it.
@param aSegment the segment to set the selection for
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
{
@@ -358,9 +358,9 @@ CPSegmentSwitchTrackingMomentary = 2;
}
/*!
- Returns YES if the specified segment is selected.
+ Returns \c YES if the specified segment is selected.
@param aSegment the segment to check for selection
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (BOOL)isSelectedForSegment:(unsigned)aSegment
{
@@ -369,9 +369,9 @@ CPSegmentSwitchTrackingMomentary = 2;
/*!
Enables/diables the specified segment.
- @param isEnabled YES enables the segment
+ @param isEnabled \c YES enables the segment
@param aSegment the segment to enable/disble
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
{
@@ -382,9 +382,9 @@ CPSegmentSwitchTrackingMomentary = 2;
}
/*!
- Returns YES if the specified segment is enabled.
+ Returns \c YES if the specified segment is enabled.
@param aSegment the segment to check
- @throws CPRangeException if aSegment is out of bounds
+ @throws CPRangeException if \c aSegment is out of bounds
*/
- (BOOL)isEnabledForSegment:(unsigned)aSegment
{
@@ -414,7 +414,7 @@ CPSegmentSwitchTrackingMomentary = 2;
/*!
Draws the specified segment bezel
@param aSegment the segment to draw the bezel for
- @param shouldHighlight YES highlights the bezel
+ @param shouldHighlight \c YES highlights the bezel
*/
- (void)drawSegmentBezel:(int)aSegment highlight:(BOOL)shouldHighlight
{
@@ -439,6 +439,16 @@ CPSegmentSwitchTrackingMomentary = 2;
return [self _leftOffsetForSegment:segment - 1] + [self widthForSegment:segment - 1] + thickness;
}
+- (unsigned)_indexOfLastSegment
+{
+ var lastSegmentIndex = [_segments count] - 1;
+
+ if (lastSegmentIndex < 0)
+ lastSegmentIndex = 0;
+
+ return lastSegmentIndex;
+}
+
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
{
var height = [self currentValueForThemeAttribute:@"default-height"],
@@ -452,7 +462,12 @@ CPSegmentSwitchTrackingMomentary = 2;
}
else if (aName === "right-segment-bezel")
{
- return CGRectMake(CGRectGetMaxX(bounds) - contentInset.right - bezelInset.right, bezelInset.top, contentInset.right, height);
+ var lastSegmentLeftOffset = [self _leftOffsetForSegment:[self _indexOfLastSegment]];
+
+ return CPRectMake(lastSegmentLeftOffset + [self widthForSegment:[self _indexOfLastSegment]] - contentInset.right,
+ bezelInset.top,
+ contentInset.right,
+ height);
}
else if (aName.substring(0, "segment-bezel".length) == "segment-bezel")
{
@@ -499,6 +514,9 @@ CPSegmentSwitchTrackingMomentary = 2;
- (void)layoutSubviews
{
+ if (_segments.length <= 0)
+ return;
+
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
inState:_themeStates[0]];
@@ -582,7 +600,7 @@ CPSegmentSwitchTrackingMomentary = 2;
/*!
Draws the specified segment
@param aSegment the segment to draw
- @param shouldHighlight YES highlights the bezel
+ @param shouldHighlight \c YES highlights the bezel
*/
- (void)drawSegment:(int)aSegment highlight:(BOOL)shouldHighlight
{
diff --git a/AppKit/CPSlider.j b/AppKit/CPSlider.j
index b4564a705..6f5e764fd 100644
--- a/AppKit/CPSlider.j
+++ b/AppKit/CPSlider.j
@@ -83,6 +83,10 @@ CPCircularSlider = 1;
if (doubleValue < _minValue)
[self setDoubleValue:_minValue];
+
+ // The relative position may have (did) change.
+ [self setNeedsLayout];
+ [self setNeedsDisplay:YES];
}
- (float)minValue
@@ -101,6 +105,10 @@ CPCircularSlider = 1;
if (doubleValue > _maxValue)
[self setDoubleValue:_maxValue];
+
+ // The relative position may have (did) change.
+ [self setNeedsLayout];
+ [self setNeedsDisplay:YES];
}
- (float)maxValue
diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j
index 533e74198..0540bd560 100644
--- a/AppKit/CPSplitView.j
+++ b/AppKit/CPSplitView.j
@@ -210,7 +210,7 @@ var CPSplitViewHorizontalImage = nil,
_DOMDividerElements[_drawingDivider].style.cursor = "move";
_DOMDividerElements[_drawingDivider].style.position = "absolute";
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
-
+
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
if (_isPaneSplitter)
@@ -224,7 +224,7 @@ var CPSplitViewHorizontalImage = nil,
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
}
}
-
+
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
#endif
@@ -303,7 +303,7 @@ var CPSplitViewHorizontalImage = nil,
- (void)trackDivider:(CPEvent)anEvent
{
var type = [anEvent type];
-
+
if (type == CPLeftMouseUp)
{
if (_currentDivider != CPNotFound)
@@ -359,6 +359,9 @@ var CPSplitViewHorizontalImage = nil,
}
}
}
+
+ if (_currentDivider === CPNotFound)
+ return;
}
else if (type == CPLeftMouseDragged && _currentDivider != CPNotFound)
@@ -423,7 +426,7 @@ var CPSplitViewHorizontalImage = nil,
frameA = [viewA frame],
viewB = _subviews[dividerIndex + 1],
frameB = [viewB frame];
-
+
var realPosition = MAX(MIN(position, actualMax), actualMin);
if (position < proposedMin + (actualMin - proposedMin) / 2)
@@ -488,8 +491,9 @@ var CPSplitViewHorizontalImage = nil,
totalSizableSpace = 0;
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
- ratio = (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace),
- remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent];
+ remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent],
+ oldDimension = (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace),
+ ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / oldDimension;
for (index = 0; index < count; ++index)
{
@@ -510,7 +514,7 @@ var CPSplitViewHorizontalImage = nil,
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
else
alert("SHOULD NEVER GET HERE");
-
+
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
[view setFrame:viewFrame];
@@ -559,7 +563,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
@implementation CPSplitView (CPCoding)
/*
- Initializes the split view by unarchiving data from aCoder.
+ Initializes the split view by unarchiving data from \c aCoder.
@param aCoder the coder containing the archived CPSplitView.
*/
- (id)initWithCoder:(CPCoder)aCoder
diff --git a/AppKit/CPStringDrawing.j b/AppKit/CPStringDrawing.j
index 61b4fda70..dec7bde1c 100644
--- a/AppKit/CPStringDrawing.j
+++ b/AppKit/CPStringDrawing.j
@@ -22,13 +22,9 @@
@import
-#include "CoreGraphics/CGGeometry.h"
-#include "Platform/Platform.h"
+@import "CPPlatformString.j"
-var CPStringReferenceElement = nil,
- CPStringDefaultFont = nil;
-
@implementation CPString (CPStringDrawing)
/*!
@@ -46,75 +42,7 @@ var CPStringReferenceElement = nil,
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
{
-#if PLATFORM(DOM)
- if (!CPStringReferenceElement)
- {
- CPStringReferenceElement = document.createElement("span");
-
- var style = CPStringReferenceElement.style;
-
- style.position = "absolute";
- style.whiteSpace = "pre";
- style.visibility = "visible";
- style.padding = "0px";
- style.margin = "0px";
-
- style.left = "-100000px";
- style.top = "-100000px";
- style.zIndex = "10000";
- style.background = "red";
-
- document.getElementsByTagName("body")[0].appendChild(CPStringReferenceElement);
- }
-
- if (!aFont)
- {
- if (!CPStringDefaultFont)
- CPStringDefaultFont = [CPFont systemFontOfSize:12.0];
-
- aFont = CPStringDefaultFont;
- }
-
- var style = CPStringReferenceElement.style;
-
- if (aWidth === NULL)
- {
- style.width = "";
- style.whiteSpace = "pre";
- }
-
- else
- {
- style.width = ROUND(aWidth) + "px";
-
- if (document.attachEvent)
- style.wordWrap = "break-word";
-
- else
- {
- style.whiteSpace = "-o-pre-wrap";
- style.whiteSpace = "-pre-wrap";
- style.whiteSpace = "-moz-pre-wrap";
- style.whiteSpace = "pre-wrap";
- }
- }
-
- style.font = [aFont cssString];
-
- if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
- CPStringReferenceElement.innerText = self;
-
- else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
- CPStringReferenceElement.textContent = self;
-
- return _CGSizeMake(CPStringReferenceElement.clientWidth, CPStringReferenceElement.clientHeight);
-#endif
- return _CGSizeMakeZero();
-}
-
-+ (void)_resetSize
-{
- CPStringReferenceElement = nil;
+ return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
}
@end
diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j
index 4484e266d..aaf50090b 100644
--- a/AppKit/CPTableColumn.j
+++ b/AppKit/CPTableColumn.j
@@ -3,7 +3,7 @@
* AppKit
*
* Created by Francisco Tolmasky.
- * Copyright 2008, 280 North, Inc.
+ * Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,12 +20,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-@import
+@import
+@import
+@import
+@import
+@import "CPTableHeaderView.j"
-/*
-@ignore
-*/
/*
@global
@@ -43,389 +44,300 @@ CPTableColumnAutoresizingMask = 1;
*/
CPTableColumnUserResizingMask = 2;
-#define PurgableInfoMake(aView, aRow) { view:(aView), row:(aRow) }
-#define PurgableInfoView(anInfo) ((anInfo).view)
-#define PurgableInfoRow(anInfo) ((anInfo).row)
-
-/*!
- @ingroup appkit
- @class CPTableColumn
-
- An CPTableColumn object mainly keeps information about the width of the column, its minimum and maximum width; whether the column can be edited or resized; and the cells used to draw the column header and the data in the column. You can change all these attributes of the column by calling the appropriate methods. Please note that the table column does not hold nor has access to the data to be displayed in the column; this data is maintained in the table view's data source.
-
-
Each CPTableColumn object is identified by a CPString, called the column identifier. The reason is that, after a column has been added to a table view, the user might move the columns around, so there is a need to identify the columns regardless of its position in the table.
-
- @ignore
-*/
@implementation CPTableColumn : CPObject
{
- CPString _identifier;
- CPView _headerView;
-
- CPTableView _tableView;
-
- float _width;
- float _minWidth;
- float _maxWidth;
-
- unsigned _resizingMask;
+ CPTableView _tableView;
+ CPView _headerView;
+ CPView _dataView;
+ Object _dataViewData;
- CPView _dataView; // default data view for this column
+ float _width;
+ float _minWidth;
+ float _maxWidth;
- Object _dataViewData; // cache of data view archives (key=data view hash, value=data view archive)
- Object _dataViewForView; // mapping from view instances back to their data view prototype (key=view instance hash, value=data view)
- Object _purgableInfosForDataView; // (key=data view hash, value=)
+ id _identifier;
+ BOOL _isEditable;
+ CPSortDescriptor _sortDescriptorPrototype;
+ BOOL _isHidden;
+ CPString _headerToolTip;
}
-/*!
- Initializes the table column with the specified identifier.
- @param anIdentifier the identifier
- @return the initialized table column
-*/
-- (id)initWithIdentifier:(CPString)anIdentifier
+- (id)initWithIdentifier:(id)anIdentifier
{
self = [super init];
-
+
if (self)
{
- [self _init];
-
- _identifier = anIdentifier;
-
- _width = 40.0;
- _minWidth = 8.0;
- _maxWidth = 1000.0;
-
- var dataView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
- [dataView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateHighlighted];
-
- [self setDataView:dataView];
-
- _headerView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
- [_headerView setBackgroundColor:[CPColor greenColor]];
+ _dataViewData = { };
+
+ _width = 100.0;
+ _minWidth = 10.0;
+ _maxWidth = 1000000.0;
+
+ [self setIdentifier:anIdentifier];
+ [self setHeaderView:[CPTextField new]];
+ [self setDataView:[CPTextField new]];
}
-
+
return self;
}
-- (void)_init
-{
- _dataViewData = {};
- _dataViewForView = {};
- _purgableInfosForDataView = {};
-}
-
-/*!
- Sets the table column's identifier
- @param anIdentifier the new identifier
-*/
-- (void)setIdentifier:(CPString)anIdentifier
-{
- _identifier = anIdentifier;
-}
-
-/*!
- Returns the table column's identifier
-*/
-- (CPString)identifier
-{
- return _identifier;
-}
-
-// Setting the CPTableView
-/*!
- Sets the table's view. This is called automatically by Cappuccino.
- @param aTableView the new table view
-*/
- (void)setTableView:(CPTableView)aTableView
{
_tableView = aTableView;
}
-/*!
- Returns the column's table view.
-*/
- (CPTableView)tableView
{
return _tableView;
}
-// Controlling size
-/*!
- Sets the column's width.
- @param aWidth the new column width
-*/
- (void)setWidth:(float)aWidth
{
- _width = aWidth;
+ aWidth = +aWidth;
+
+ if (_width === aWidth)
+ return;
+
+ var newWidth = MIN(MAX(aWidth, [self minWidth]), [self maxWidth]);
+
+ if (_width === newWidth)
+ return;
+
+ var oldWidth = _width;
+
+ _width = newWidth;
+
+ var tableView = [self tableView];
+
+ if (tableView)
+ {
+ var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self];
+
+ // FIXME: THIS IS HORRIBLE. Don't just reload everything when a table column changes, just relayout the changed widths.
+ tableView._reloadAllRows = YES;
+ tableView._dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex < 0 ? index : MIN(index, tableView._dirtyTableColumnRangeIndex);
+
+ [tableView tile];
+
+ [[CPNotificationCenter defaultCenter]
+ postNotificationName:CPTableViewColumnDidResizeNotification
+ object:tableView
+ userInfo:[CPDictionary dictionaryWithObjects:[self, oldWidth] forKeys:[@"CPTableColumn", "CPOldWidth"]]];
+ }
}
-/*!
- Returns the column's width
-*/
- (float)width
{
return _width;
}
-/*!
- Sets column's minimum width.
- @param aWidth the new minimum column width
-*/
-- (void)setMinWidth:(float)aWidth
+- (void)setMinWidth:(float)aMinWidth
{
- if (_width < (_minWidth = aWidth))
- [self setWidth:_minWidth];
+ aMinWidth = +aMinWidth;
+
+ if (_minWidth === aMinWidth)
+ return;
+
+ _minWidth = aMinWidth;
+
+ var width = [self width],
+ newWidth = MAX(width, [self minWidth]);
+
+ if (width !== newWidth)
+ [self setWidth:newWidth];
}
-/*!
- The column's minimum width
-*/
- (float)minWidth
{
return _minWidth;
}
-/*!
- Sets the column's maximum width.
- @param aWidth the new maximum width
-*/
-- (void)setMaxWidth:(float)aWidth
+- (void)setMaxWidth:(float)aMaxWidth
{
- if (_width > (_maxmimumWidth = aWidth))
- [self setWidth:_maxWidth];
+ aMaxWidth = +aMaxWidth;
+
+ if (_maxWidth === aMaxWidth)
+ return;
+
+ _maxWidth = aMaxWidth;
+
+ var width = [self width],
+ newWidth = MAX(width, [self maxWidth]);
+
+ if (width !== newWidth)
+ [self setWidth:newWidth];
}
-/*!
- Sets the resizing mask. The mask is one of:
-
- @param aDataSource the object with the table data
- @throws CPInternalInconsistencyException if aDataSource doesn't implement all the required methods
-*/
- (void)setDataSource:(id)aDataSource
{
- if (![aDataSource respondsToSelector:@selector(numberOfRowsInTableView:)])
- [CPException raise:CPInternalInconsistencyException reason:"Data source doesn't support 'numberOfRowsInTableView:'"];
- if (![aDataSource respondsToSelector:@selector(tableView:objectValueForTableColumn:row:)])
- [CPException raise:CPInternalInconsistencyException reason:"Data source doesn't support 'tableView:objectValueForTableColumn:row:'"];
+ if (_dataSource === aDataSource)
+ return;
_dataSource = aDataSource;
-
+ _implementedDataSourceMethods = 0;
+
+ if (!_dataSource)
+ return;
+
+ if (![_dataSource respondsToSelector:@selector(numberOfRowsInTableView:)])
+ [CPException raise:CPInternalInconsistencyException
+ reason:[aDataSource description] + " does not implement numberOfRowsInTableView:."];
+
+ if (![_dataSource respondsToSelector:@selector(tableView:objectValueForTableColumn:row:)])
+ [CPException raise:CPInternalInconsistencyException
+ reason:[aDataSource description] + " does not implement tableView:objectValueForTableColumn:row:"];
+
+ if ([_dataSource respondsToSelector:@selector(tableView:setObjectValue:forTableColumn:row:)])
+ _implementedDataSourceMethods |= CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_;
+
+ if ([_dataSource respondsToSelector:@selector(tableView:setObjectValue:forTableColumn:row:)])
+ _implementedDataSourceMethods |= CPTableViewDataSource_tableView_acceptDrop_row_dropOperation_;
+
+ if ([_dataSource respondsToSelector:@selector(tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes:)])
+ _implementedDataSourceMethods |= CPTableViewDataSource_tableView_namesOfPromisedFilesDroppedAtDestination_forDraggedRowsWithIndexes_;
+
+ if ([_dataSource respondsToSelector:@selector(tableView:validateDrop:proposedRow:proposedDropOperation:)])
+ _implementedDataSourceMethods |= CPTableViewDataSource_tableView_validateDrop_proposedRow_proposedDropOperation_;
+
+ if ([_dataSource respondsToSelector:@selector(tableView:writeRowsWithIndexes:toPasteboard:)])
+ _implementedDataSourceMethods |= CPTableViewDataSource_tableView_writeRowsWithIndexes_toPasteboard_;
+
[self reloadData];
}
-/*
- Returns the object that has access to the table data
-*/
- (id)dataSource
{
return _dataSource;
}
+//Loading Data
+
+- (void)reloadDataForRowIndexes:(CPIndexSet)rowIndexes columnIndexes:(CPIndexSet)columnIndexes
+{
+ [self reloadData];
+// [_previouslyExposedRows removeIndexes:rowIndexes];
+// [_previouslyExposedColumns removeIndexes:columnIndexes];
+}
+
+
+- (void)reloadData
+{
+ if (!_dataSource)
+ return;
+
+ _reloadAllRows = YES;
+ _objectValues = { };
+
+ // This updates the size too.
+ [self noteNumberOfRowsChanged];
+
+ [self setNeedsLayout];
+ [self setNeedsDisplay:YES];
+}
+
+//Target-action Behavior
+
+- (void)setDoubleAction:(SEL)anAction
+{
+ _doubleAction = anAction;
+}
+
+- (SEL)doubleAction
+{
+ return _doubleAction;
+}
+
+/*
+ * - clickedColumn
+ * - clickedRow
+*/
+//Configuring Behavior
+
+- (void)setAllowsColumnReordering:(BOOL)shouldAllowColumnReordering
+{
+ _allowsColumnReordering = !!shouldAllowColumnReordering;
+}
+
+- (BOOL)allowsColumnReordering
+{
+ return _allowsColumnReordering;
+}
+
+- (void)setAllowsColumnResizing:(BOOL)shouldAllowColumnResizing
+{
+ _allowsColumnResizing = !!shouldAllowColumnResizing;
+}
+
+- (BOOL)allowsColumnResizing
+{
+ return _allowsColumnResizing;
+}
+
+- (void)setAllowsMultipleSelection:(BOOL)shouldAllowMultipleSelection
+{
+ _allowsMultipleSelection = !!shouldAllowMultipleSelection;
+}
+
+- (BOOL)allowsMultipleSelection
+{
+ return _allowsMultipleSelection;
+}
+
+- (void)setAllowsEmptySelection:(BOOL)shouldAllowEmptySelection
+{
+ _allowsEmptySelection = !!shouldAllowEmptySelection;
+}
+
+- (BOOL)allowsEmptySelection
+{
+ return _allowsEmptySelection;
+}
+
+- (void)setAllowsColumnSelection:(BOOL)shouldAllowColumnSelection
+{
+ _allowsColumnSelection = !!shouldAllowColumnSelection;
+}
+
+- (BOOL)allowsColumnSelection
+{
+ return _allowsColumnSelection;
+}
+
+//Setting Display Attributes
+
+- (void)setIntercellSpacing:(CGSize)aSize
+{
+ if (_CGSizeEqualToSize(_intercellSpacing, aSize))
+ return;
+
+ _intercellSpacing = _CGSizeMakeCopy(aSize);
+
+ [self setNeedsLayout];
+}
+
+- (void)setThemeState:(int)astae
+{
+}
+
+- (CGSize)intercellSpacing
+{
+ return _CGSizeMakeCopy(_intercellSpacing);
+}
+
+- (void)setRowHeight:(unsigned)aRowHeight
+{
+ aRowHeight = +aRowHeight;
+
+ if (_rowHeight === aRowHeight)
+ return;
+
+ _rowHeight = MAX(0.0, aRowHeight);
+
+ [self setNeedsLayout];
+}
+
+- (unsigned)rowHeight
+{
+ return _rowHeight;
+}
+
+- (void)setUsesAlternatingRowBackgroundColors:(BOOL)shouldUseAlternatingRowBackgroundColors
+{
+ // TODO:need to look at how one actually sets the alternating row, a tip at:
+ // http://forums.macnn.com/79/developer-center/228347/nstableview-alternating-row-colors/
+ // otherwise this may not be feasible or may introduce an additional change req'd in CP
+ // we'd probably need to iterate through rowId % 2 == 0 and setBackgroundColor with
+ // whatever the alternating row color is.
+ _usesAlternatingRowBackgroundColors = shouldUseAlternatingRowBackgroundColors;
+}
+
+- (BOOL)usesAlternatingRowBackgroundColors
+{
+ return _usesAlternatingRowBackgroundColors;
+}
+
+- (void)setAlternatingRowBackgroundColors:(CPArray)alternatingRowBackgroundColors
+{
+ if ([_alternatingRowBackgroundColors isEqual:alternatingRowBackgroundColors])
+ return;
+
+ _alternatingRowBackgroundColors = alternatingRowBackgroundColors;
+
+ [self setNeedsDisplay:YES];
+}
+
+- (CPArray)alternatingRowBackgroundColors
+{
+ return _alternatingRowBackgroundColors;
+}
+
+- (unsigned)selectionHighlightStyle
+{
+ return _selectionHighlightMask;
+}
+
+- (void)setSelectionHighlightStyle:(unsigned)aSelectionHighlightStyle
+{
+ _selectionHighlightMask = aSelectionHighlightStyle;
+}
+
+/*
+ * - indicatorImageInTableColumn:
+ * - setIndicatorImage:inTableColumn:
+*/
+
+- (void)setGridColor:(CPColor)aColor
+{
+ if (_gridColor === aColor)
+ return;
+
+ _gridColor = aColor;
+
+ [self setNeedsDisplay:YES];
+}
+
+- (CPColor)gridColor
+{
+ return _gridColor;
+}
+
+- (void)setGridStyleMask:(unsigned)aGrideStyleMask
+{
+ if (_gridStyleMask === aGrideStyleMask)
+ return;
+
+ _gridStyleMask = aGrideStyleMask
+
+ [self setNeedsDisplay:YES];
+}
+
+- (unsigned)gridStyleMask
+{
+ return _gridStyleMask;
+}
+
+//Column Management
+
+- (void)addTableColumn:(CPTableColumn)aTableColumn
+{
+ [_tableColumns addObject:aTableColumn];
+ [aTableColumn setTableView:self];
+
+ if (_dirtyTableColumnRangeIndex < 0)
+ _dirtyTableColumnRangeIndex = NUMBER_OF_COLUMNS() - 1;
+ else
+ _dirtyTableColumnRangeIndex = MIN(NUMBER_OF_COLUMNS() - 1, _dirtyTableColumnRangeIndex);
+
+ [self setNeedsLayout];
+}
+
+- (void)removeTableColumn:(CPTableColumn)aTableColumn
+{
+ if ([aTableColumn tableView] !== self)
+ return;
+
+ var index = [_tableColumns indexOfObjectIdenticalTo:aTableColumn];
+
+ if (index === CPNotFound)
+ return;
+
+ [aTableColumn setTableView:nil];
+ [_tableColumns removeObjectAtIndex:index];
+
+ var tableColumnUID = [aTableColumn UID];
+
+ if (_objectValues[tableColumnUID])
+ _objectValues[tableColumnUID] = nil;
+
+ if (_dirtyTableColumnRangeIndex < 0)
+ _dirtyTableColumnRangeIndex = index;
+ else
+ _dirtyTableColumnRangeIndex = MIN(index, _dirtyTableColumnRangeIndex);
+
+ [self setNeedsLayout];
+}
+
+- (void)moveColumn:(unsigned)fromIndex toColumn:(unsigned)toIndex
+{
+ fromIndex = +fromIndex;
+ toIndex = +toIndex;
+
+ if (fromIndex === toIndex)
+ return;
+
+ if (_dirtyTableColumnRangeIndex < 0)
+ _dirtyTableColumnRangeIndex = MIN(fromIndex, toIndex);
+ else
+ _dirtyTableColumnRangeIndex = MIN(fromIndex, toIndex, _dirtyTableColumnRangeIndex);
+
+ if (toIndex > fromIndex)
+ --toIndex;
+
+ var tableColumn = _tableColumns[fromIndex];
+
+ [_tableColumns removeObjectAtIndex:fromIndex];
+ [_tableColumns insertObject:tableColumn atIndex:toIndex];
+
+ [self setNeedsLayout];
+}
+
+- (CPArray)tableColumns
+{
+ return _tableColumns;
+}
+
+- (CPInteger)columnWithIdentifier:(CPString)anIdentifier
+{
+ var index = 0,
+ count = NUMBER_OF_COLUMNS();
+
+ for (; index < count; ++index)
+ if ([_tableColumns identifier] === anIdentifier)
+ return index;
+
+ return CPNotFound;
+}
+
+- (CPTableColumn)tableColumnWithIdentifier:(CPString)anIdentifier
+{
+ var index = [self columnWithIdentifier:anIdentifier];
+
+ if (index === CPNotFound)
+ return nil;
+
+ return _tableColumns[index];
+}
+
+//Selecting Columns and Rows
+- (void)selectColumnIndexes:(CPIndexSet)columns byExtendingSelection:(BOOL)shouldExtendSelection
+{
+ // We deselect all columns when selecting rows.
+ _selectedRowIndexes = [CPIndexSet indexSet];
+
+ if (shouldExtendSelection)
+ [_selectedColumnIndexes addIndexes:columns];
+ else
+ _selectedColumnIndexes = [columns copy];
+
+ [self setNeedsLayout];
+}
+
+- (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection
+{
+ // We deselect all rows when selecting columns.
+ _selectedColumnIndexes = [CPIndexSet indexSet];
+
+ if (shouldExtendSelection)
+ [_selectedRowIndexes addIndexes:rows];
+ else
+ _selectedRowIndexes = [rows copy];
+
+ [self setNeedsLayout];
+}
+
+- (CPIndexSet)selectedColumnIndexes
+{
+ return _selectedColumnIndexes;
+}
+
+- (void)selectedRowIndexes
+{
+ return _selectedRowIndexes;
+}
+
+- (void)deselectColumn:(CPInteger)aColumn
+{
+ [_selectedColumnIndexes removeIndex:aColumn];
+}
+
+- (void)deselectRow:(CPInteger)aRow
+{
+ [_selectedRowIndexes removeIndex:aRow];
+}
+
+- (CPInteger)numberOfSelectedColumns
+{
+ return [_selectedColumnIndexes count];
+}
+
+- (CPInteger)numberOfSelectedRows
+{
+ return [_selectedRowIndexes count];
+}
+
+/*
+- (CPInteger)selectedColumn
+ * - selectedRow
+*/
+
+- (BOOL)isColumnSelected:(CPInteger)aColumn
+{
+ return [_selectedColumnIndexes containsIndex:aColumn];
+}
+
+- (BOOL)isRowSelected:(CPInteger)aRow
+{
+ return [_selectedRowIndexes containsIndex:aRow];
+}
+/*
+- (void)selectAll:
+ * - deselectAll:
+ * - allowsTypeSelect
+ * - setAllowsTypeSelect:
+*/
+//Table Dimensions
+
+- (int)numberOfColumns
+{
+ return NUMBER_OF_COLUMNS();
+}
+
+/*
+ Returns the number of rows in the receiver.
+*/
+- (int)numberOfRows
+{
+ if (!_dataSource)
+ return 0;
+
+ return [_dataSource numberOfRowsInTableView:self];
+}
+
+//Displaying Cell
+/*
+ * - preparedCellAtColumn:row:
+*/
+//Editing Cells
+/*
+ * - editColumn:row:withEvent:select:
+ * - editedColumn
+ * - editedRow
+*/
+//Setting Auxiliary Views
+/*
+ * - setHeaderView:
+ * - headerView
+ * - setCornerView:
+ * - cornerView
+*/
+
+- (CPView)cornerView
+{
+ return _cornerView;
+}
+
+- (void)setCornerView:(CPView)aView
+{
+ if (_cornerView === aView)
+ return;
+
+ _cornerView = aView;
+
+ var scrollView = [[self superview] superview];
+
+ if ([scrollView isKindOfClass:[CPScrollView class]] && [scrollView documentView] === self)
+ [scrollView _updateCornerAndHeaderView];
+}
+
+- (CPView)headerView
+{
+ return _headerView;
+}
+
+- (void)setHeaderView:(CPView)aHeaderView
+{
+ if (_headerView === aHeaderView)
+ return;
+
+ [_headerView setTableView:nil];
+
+ _headerView = aHeaderView;
+
+ if (_headerView)
+ {
+ [_headerView setTableView:self];
+ [_headerView setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), _CGRectGetHeight([_headerView frame]))];
+ }
+
+ var scrollView = [[self superview] superview];
+
+ if ([scrollView isKindOfClass:[CPScrollView class]] && [scrollView documentView] === self)
+ [scrollView _updateCornerAndHeaderView];
+}
+
+//Layout Support
+
+// Complexity:
+// O(Columns)
+- (void)_recalculateTableColumnRanges
+{
+ if (_dirtyTableColumnRangeIndex < 0)
+ return;
+
+ var index = _dirtyTableColumnRangeIndex,
+ count = NUMBER_OF_COLUMNS(),
+ x = index === 0 ? 0.0 : CPMaxRange(_tableColumnRanges[index - 1]);
+
+ for (; index < count; ++index)
+ {
+ var tableColumn = _tableColumns[index];
+
+ if ([tableColumn isHidden])
+ _tableColumnRanges[index] = CPMakeRange(x, 0.0);
+
+ else
+ {
+ var width = [_tableColumns[index] width];
+
+ _tableColumnRanges[index] = CPMakeRange(x, width);
+
+ x += width;
+ }
+ }
+
+ _tableColumnRanges.length = count;
+ _dirtyTableColumnRangeIndex = CPNotFound;
+}
+
+// Complexity:
+// O(1)
+- (CGRect)rectOfColumn:(CPInteger)aColumnIndex
+{
+ aColumnIndex = +aColumnIndex;
+
+ if (aColumnIndex < 0 || aColumnIndex >= NUMBER_OF_COLUMNS())
+ return _CGRectMakeZero();
+
+ UPDATE_COLUMN_RANGES_IF_NECESSARY();
+
+ var range = _tableColumnRanges[aColumnIndex];
+
+ return _CGRectMake(range.location, 0.0, range.length, CGRectGetHeight([self bounds]));
+}
+
+- (CGRect)rectOfRow:(CPInteger)aRowIndex
+{
+ if (NO)
+ return NULL;
+
+ // FIXME: WRONG: ASK TABLE COLUMN RANGE
+ return _CGRectMake(0.0, (aRowIndex * (_rowHeight + _intercellSpacing.height)), _CGRectGetWidth([self bounds]), _rowHeight);
+}
+
+// Complexity:
+// O(1)
+- (CPRange)rowsInRect:(CGRect)aRect
+{
+ // If we have no rows, then we won't intersect anything.
+ if (_numberOfRows <= 0)
+ return CPMakeRange(0, 0);
+
+ var bounds = [self bounds];
+
+ // No rows if the rect doesn't even intersect us.
+ if (!CGRectIntersectsRect(aRect, bounds))
+ return CPMakeRange(0, 0);
+
+ var firstRow = [self rowAtPoint:aRect.origin];
+
+ // first row has to be undershot, because if not we wouldn't be intersecting.
+ if (firstRow < 0)
+ firstRow = 0;
+
+ var lastRow = [self rowAtPoint:_CGPointMake(0.0, _CGRectGetMaxY(aRect))];
+
+ // last row has to be overshot, because if not we wouldn't be intersecting.
+ if (lastRow < 0)
+ lastRow = _numberOfRows - 1;
+
+ return CPMakeRange(firstRow, lastRow - firstRow + 1);
+}
+
+// Complexity:
+// O(lg Columns) if table view contains no hidden columns
+// O(Columns) if table view contains hidden columns
+- (CPIndexSet)columnIndexesInRect:(CGRect)aRect
+{
+ var column = MAX(0, [self columnAtPoint:_CGPointMake(aRect.origin.x, 0.0)]),
+ lastColumn = [self columnAtPoint:_CGPointMake(_CGRectGetMaxX(aRect), 0.0)];
+
+ if (lastColumn === CPNotFound)
+ lastColumn = NUMBER_OF_COLUMNS() - 1;
+
+ // Don't bother doing the expensive removal of hidden indexes if we have no hidden columns.
+ if (_numberOfHiddenColumns <= 0)
+ return [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(column, lastColumn - column + 1)];
+
+ //
+ var indexSet = [CPIndexSet indexSet];
+
+ for (; column <= lastColumn; ++column)
+ {
+ var tableColumn = _tableColumns[column];
+
+ if (![tableColumn isHidden])
+ [indexSet addIndex:column];
+ }
+
+ return indexSet;
+}
+
+// Complexity:
+// O(lg Columns) if table view contains now hidden columns
+// O(Columns) if table view contains hidden columns
+- (CPInteger)columnAtPoint:(CGPoint)aPoint
+{
+ var bounds = [self bounds];
+
+ if (!_CGRectContainsPoint(bounds, aPoint))
+ return CPNotFound;
+
+ UPDATE_COLUMN_RANGES_IF_NECESSARY();
+
+ var x = aPoint.x,
+ low = 0,
+ high = _tableColumnRanges.length - 1;
+
+ while (low <= high)
+ {
+ var middle = FLOOR(low + (high - low) / 2),
+ range = _tableColumnRanges[middle];
+
+ if (x < range.location)
+ high = middle - 1;
+
+ else if (x >= CPMaxRange(range))
+ low = middle + 1;
+
+ else
+ {
+ var numberOfColumns = _tableColumnRanges.length;
+
+ while (middle < numberOfColumns && [_tableColumns[middle] isHidden])
+ ++middle;
+
+ if (middle < numberOfColumns)
+ return middle;
+
+ return CPNotFound;
+ }
+ }
+
+ return CPNotFound;
+}
+
+- (CPInteger)rowAtPoint:(CGPoint)aPoint
+{
+ var y = aPoint.y;
+
+ if (NO)
+ {
+ }
+
+ var row = FLOOR(y / (_rowHeight + _intercellSpacing.height));
+
+ if (row >= _numberOfRows)
+ return -1;
+
+ return row;
+}
+
+- (CGRect)frameOfDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
+{
+ UPDATE_COLUMN_RANGES_IF_NECESSARY();
+
+ var tableColumnRange = _tableColumnRanges[aColumn],
+ rectOfRow = [self rectOfRow:aRow];
+
+ return _CGRectMake(tableColumnRange.location, _CGRectGetMinY(rectOfRow), tableColumnRange.length, _CGRectGetHeight(rectOfRow));
+}
+/*
+ * - columnAutoresizingStyle
+ * - setColumnAutoresizingStyle:
+*/
+- (void)sizeLastColumnToFit
+{
+ var superview = [self superview];
+
+ if (!superview)
+ return;
+
+ var superviewSize = [superview bounds].size;
+
+ UPDATE_COLUMN_RANGES_IF_NECESSARY();
+
+ var count = NUMBER_OF_COLUMNS();
+
+ while (count-- && [_tableColumns[count] isHidden]) ;
+
+ if (count >= 0)
+ [_tableColumns[count] setWidth:MAX(0.0, superviewSize.width - _CGRectGetMinX([self rectOfColumn:count]))];
+
+ [self setNeedsLayout];
+}
+
+- (void)noteNumberOfRowsChanged
+{
+ _numberOfRows = [_dataSource numberOfRowsInTableView:self];
+
+ [self tile];
+}
+
+- (void)tile
+{
+ UPDATE_COLUMN_RANGES_IF_NECESSARY();
+
+ // FIXME: variable row heights.
+ var width = _tableColumnRanges.length > 0 ? CPMaxRange([_tableColumnRanges lastObject]) : 0.0,
+ height = (_rowHeight + _intercellSpacing.height) * _numberOfRows,
+ superview = [self superview];
+
+ if ([superview isKindOfClass:[CPClipView class]])
+ {
+ var superviewSize = [superview bounds].size;
+
+ width = MAX(superviewSize.width, width);
+ height = MAX(superviewSize.height, height);
+ }
+
+ [self setFrameSize:_CGSizeMake(width, height)];
+
+ [self setNeedsLayout];
+ [self setNeedsDisplay:YES];
+}
+
+/*
+ * - tile
+ * - sizeToFit
+ * - noteHeightOfRowsWithIndexesChanged:
+*/
+//Scrolling
+/*
+ * - scrollRowToVisible:
+ * - scrollColumnToVisible:
+*/
+//Persistence
+/*
+ * - autosaveName
+ * - autosaveTableColumns
+ * - setAutosaveName:
+ * - setAutosaveTableColumns:
+*/
+
+//Setting the Delegate:(id)aDelegate
+
+- (void)setDelegate:(id)aDelegate
+{
+ if (_delegate === aDelegate)
+ return;
+
+ var defaultCenter = [CPNotificationCenter defaultCenter];
+
+ if (_delegate)
+ {
+ if ([_delegate respondsToSelector:@selector(tableViewColumnDidMove:)])
+ [defaultCenter
+ removeObserver:_delegate
+ name:CPTableViewColumnDidMoveNotification
+ object:self];
+
+ if ([_delegate respondsToSelector:@selector(tableViewColumnDidResize:)])
+ [defaultCenter
+ removeObserver:_delegate
+ name:CPTableViewColumnDidResizeNotification
+ object:self];
+
+ if ([_delegate respondsToSelector:@selector(tableViewSelectionDidChange:)])
+ [defaultCenter
+ removeObserver:_delegate
+ name:CPTableViewSelectionDidChangeNotification
+ object:self];
+
+ if ([_delegate respondsToSelector:@selector(tableViewSelectionIsChanging:)])
+ [defaultCenter
+ removeObserver:_delegate
+ name:CPTableViewSelectionIsChangingNotification
+ object:self];
+ }
+
+ _delegate = aDelegate;
+ _implementedDelegateMethods = 0;
+
+ if ([_delegate respondsToSelector:@selector(selectionShouldChangeInTableView:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_selectionShouldChangeInTableView_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:dataViewForTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_dataViewForTableColumn_row_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:didClickTableColumn:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_didClickTableColumn_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:didDragTableColumn:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_didDragTableColumn_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:heightOfRow:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_heightOfRow_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:isGroupRow:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_isGroupRow_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:mouseDownInHeaderOfTableColumn:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_mouseDownInHeaderOfTableColumn_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:nextTypeSelectMatchFromRow:toRow:forString:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_nextTypeSelectMatchFromRow_toRow_forString_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:selectionIndexesForProposedSelection:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_selectionIndexesForProposedSelection_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:shouldEditTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldEditTableColumn_row_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:shouldSelectRow:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectRow_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:shouldSelectTableColumn:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectTableColumn_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:shouldShowViewExpansionForTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldShowViewExpansionForTableColumn_row_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:shouldTrackView:forTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTrackView_forTableColumn_row_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:shouldTypeSelectForEvent:withCurrentSearchString:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTypeSelectForEvent_withCurrentSearchString_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:toolTipForView:rect:tableColumn:row:mouseLocation:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_toolTipForView_rect_tableColumn_row_mouseLocation_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:typeSelectStringForTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_typeSelectStringForTableColumn_row_;
+
+ if ([_delegate respondsToSelector:@selector(tableView:willDisplayView:forTableColumn:row:)])
+ _implementedDelegateMethods |= CPTableViewDelegate_tableView_willDisplayView_forTableColumn_row_;
+
+ if ([_delegate respondsToSelector:@selector(tableViewColumnDidMove:)])
+ [defaultCenter
+ addObserver:_delegate
+ selector:@selector(tableViewColumnDidMove:)
+ name:CPTableViewColumnDidMoveNotification
+ object:self];
+
+ if ([_delegate respondsToSelector:@selector(tableViewColumnDidResize:)])
+ [defaultCenter
+ addObserver:_delegate
+ selector:@selector(tableViewColumnDidMove:)
+ name:CPTableViewColumnDidResizeNotification
+ object:self];
+
+ if ([_delegate respondsToSelector:@selector(tableViewSelectionDidChange:)])
+ [defaultCenter
+ addObserver:_delegate
+ selector:@selector(tableViewSelectionDidChange:)
+ name:CPTableViewSelectionDidChangeNotification
+ object:self];
+
+ if ([_delegate respondsToSelector:@selector(tableViewSelectionIsChanging:)])
+ [defaultCenter
+ addObserver:_delegate
+ selector:@selector(tableViewSelectionIsChanging:)
+ name:CPTableViewSelectionIsChangingNotification
+ object:self];
+}
- (id)delegate
{
return _delegate;
}
-
-/*!
- Sets the delegate for the tableview.
-*/
-- (void)setDelegate:(id)aDelegate
+//Highlightable Column Headers
+/*
+- (CPTableColumn)highlightedTableColumn
{
- if (_delegate === aDelegate)
- return;
-
- var notificationCenter = [CPNotificationCenter defaultCenter];
-
- if ([_delegate respondsToSelector:@selector(tableViewColumnDidMove:)])
- [notificationCenter removeObserver:_delegate name:CPTableViewColumnDidMoveNotification object:self];
- if ([_delegate respondsToSelector:@selector(tableViewColumnDidResize:)])
- [notificationCenter removeObserver:_delegate name:CPTableViewColumnDidResizeNotification object:self];
- if ([_delegate respondsToSelector:@selector(tableViewSelectionDidChange:)])
- [notificationCenter removeObserver:_delegate name:CPTableViewSelectionDidChangeNotification object:self];
- if ([_delegate respondsToSelector:@selector(tableViewSelectionIsChanging:)])
- [notificationCenter removeObserver:_delegate name:CPTableViewSelectionIsChangingNotification object:self];
-
- _delegate = aDelegate;
-
- if ([_delegate respondsToSelector:@selector(tableViewColumnDidMove:)])
- [notificationCenter addObserver:_delegate selector:@selector(tableViewColumnDidMove:) name:CPTableViewColumnDidMoveNotification object:self];
- if ([_delegate respondsToSelector:@selector(tableViewColumnDidResize:)])
- [notificationCenter addObserver:_delegate selector:@selector(tableViewColumnDidResize:) name:CPTableViewColumnDidResizeNotification object:self];
- if ([_delegate respondsToSelector:@selector(tableViewSelectionDidChange:)])
- [notificationCenter addObserver:_delegate selector:@selector(tableViewSelectionDidChange:) name:CPTableViewSelectionDidChangeNotification object:self];
- if ([_delegate respondsToSelector:@selector(tableViewSelectionIsChanging:)])
- [notificationCenter addObserver:_delegate selector:@selector(tableViewSelectionIsChanging:) name:CPTableViewSelectionIsChangingNotification object:self];
- _delegateSelectorsCache = 0;
+}
- if ([_delegate respondsToSelector:@selector(tableView:willDisplayCell:forTableColumn:row:)])
- _delegateSelectorsCache |= _CPTableViewWillDisplayCellSelector;
- if ([_delegate respondsToSelector:@selector(tableView:shouldSelectRow:)])
- _delegateSelectorsCache |= _CPTableViewShouldSelectRowSelector;
- if ([_delegate respondsToSelector:@selector(tableView:shouldSelectTableColumn:)])
- _delegateSelectorsCache |= _CPTableViewShouldSelectTableColumnSelector;
- if ([_delegate respondsToSelector:@selector(selectionShouldChangeInTableView:)])
- _delegateSelectorsCache |= _CPTableViewSelectionShouldChangeSelector;
- if ([_delegate respondsToSelector:@selector(tableView:shouldEditTableColumn:row:)])
- _delegateSelectorsCache |= _CPTableViewShouldEditTableColumnSelector;
- if ([_delegate respondsToSelector:@selector(tableView:selectionIndexesForProposedSelection:)])
- _delegateSelectorsCache |= _CPTableViewSelectionIndexesForProposedSelectionSelector;
- if ([_delegate respondsToSelector:@selector(tableView:heightOfRow:)])
+ * - setHighlightedTableColumn:
+*/
+//Dragging
+/*
+ * - dragImageForRowsWithIndexes:tableColumns:event:offset:
+ * - canDragRowsWithIndexes:atPoint:
+ * - setDraggingSourceOperationMask:forLocal:
+ * - setDropRow:dropOperation:
+ * - setVerticalMotionCanBeginDrag:
+ * - verticalMotionCanBeginDrag
+*/
+//Sorting
+/*
+ * - setSortDescriptors:
+ * - sortDescriptors
+*/
+
+//Text Delegate Methods
+/*
+ * - textShouldBeginEditing:
+ * - textDidBeginEditing:
+ * - textDidChange:
+ * - textShouldEndEditing:
+ * - textDidEndEditing:
+*/
+
+- (id)_objectValueForTableColumn:(CPTableColumn)aTableColumn row:(CPInteger)aRowIndex
+{
+ var tableColumnUID = [aTableColumn UID],
+ tableColumnObjectValues = _objectValues[tableColumnUID];
+
+ if (!tableColumnObjectValues)
{
- _delegateSelectorsCache |= _CPTableViewHeightOfRowSelector;
- _hasVariableHeightRows = YES;
+ tableColumnObjectValues = [];
+ _objectValues[tableColumnUID] = tableColumnObjectValues;
}
- else
- _hasVariableHeightRows = NO;
-}
+ var objectValue = tableColumnObjectValues[aRowIndex];
-/*
- Tells the table view that the number of rows in the table
- has changed.
-*/
-- (void)noteNumberOfRowsChanged
-{
- var numberOfRows = [_dataSource numberOfRowsInTableView:self];
-
- if (_numberOfRows != numberOfRows)
+ if (objectValue === undefined)
{
- _numberOfRows = numberOfRows;
-
- [self _recalculateColumnHeight];
+ objectValue = [_dataSource tableView:self objectValueForTableColumn:aTableColumn row:aRowIndex];
+ tableColumnObjectValues[aRowIndex] = objectValue;
}
+
+ return objectValue;
}
-- (void)noteHeightOfRowsWithIndexesChanged:(CPIndexSet)indexSet
-{
- // FIXME: more efficient version is possible since we know which indexes changes
- [self _recalculateColumnHeight];
-}
-
-/*
- Returns the rectangle bounding the specified row.
- @param aRowIndex the row to obtain a rectangle for
- @return the bounding rectangle
-*/
-- (CGRect)rectOfRow:(int)aRowIndex
-{
- return CPRectMake(0.0, ROW_MIN_Y(aRowIndex), CPRectGetWidth([self bounds]), ROW_HEIGHT(aRowIndex));
-}
-
-/*
- Returns the rectangle bounding the specified column
- @param aColumnIndex the column to obtain a rectangle for
- @return the bounding column
-*/
-- (CGRect)rectOfColumn:(int)aColumnIndex
-{
- return [_tableColumnViews[aColumnIndex] frame];
-}
-
-/*
- Adjusts column widths to make them all visible at once. Same as tile.
-*/
-- (void)sizeToFit
-{
-// [self tile];
-}
-
-- (void)_recalculateColumnHeight
-{
- var oldColumnHeight = _columnHeight;
-
- if (_hasVariableHeightRows)
- {
- _rowMinYs[0] = 0;
- for (var row = 0; row < _numberOfRows; row++)
- {
- _rowHeights[row] = [_delegate tableView:self heightOfRow:row];
- _rowMinYs[row+1] = _rowMinYs[row] + _rowHeights[row] + _intercellSpacing.height;
- }
- _columnHeight = _rowMinYs[_numberOfRows]; // last index is one more than last row, and is the total column height
- }
- else
- _columnHeight = _numberOfRows * (_rowHeight + _intercellSpacing.height);
-
- var count = _tableColumnViews.length;
-
- while (count--)
- [_tableColumnViews[count] setFrameSize:CGSizeMake([_tableColumns[count] width], _columnHeight)];
-
- [self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), _columnHeight)];
-}
-
-- (CGRect)visibleRectInParent
+- (CGRect)_exposedRect
{
var superview = [self superview];
-
- if (!superview)
+
+ if (![superview isKindOfClass:[CPClipView class]])
return [self bounds];
-
+
return [self convertRect:CGRectIntersection([superview bounds], [self frame]) fromView:superview];
}
-/*
- Reloads the data from the dataSource. This is an
- expensive method, so use it lightly.
-*/
-- (void)reloadData
+- (void)load
{
- var oldNumberOfRows = _numberOfRows;
-
- _numberOfRows = [_dataSource numberOfRowsInTableView:self];
+// if (!window.blah)
+// return window.setTimeout(function() { window.blah = true; [self load]; window.blah = false}, 0.0);
- if (oldNumberOfRows != _numberOfRows)
+ // if (window.console && window.console.profile)
+ // console.profile("cell-load");
+
+ if (_reloadAllRows)
{
- [self _recalculateColumnHeight];
- [self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), [self _columnHeight])];
+ [self _unloadDataViewsInRows:_exposedRows columns:_exposedColumns];
+
+ _exposedRows = [CPIndexSet indexSet];
+ _exposedColumns = [CPIndexSet indexSet];
+
+ _reloadAllRows = NO;
}
-
- _objectValueCache = [];
-
- [self clearCells];
-
- [self setNeedsLayout];
+
+ var exposedRect = [self _exposedRect],
+ exposedRows = [CPIndexSet indexSetWithIndexesInRange:[self rowsInRect:exposedRect]],
+ exposedColumns = [self columnIndexesInRect:exposedRect],
+ obscuredRows = [_exposedRows copy],
+ obscuredColumns = [_exposedColumns copy];
+
+ [obscuredRows removeIndexes:exposedRows];
+ [obscuredColumns removeIndexes:exposedColumns];
+
+ var newlyExposedRows = [exposedRows copy],
+ newlyExposedColumns = [exposedColumns copy];
+
+ [newlyExposedRows removeIndexes:_exposedRows];
+ [newlyExposedColumns removeIndexes:_exposedColumns];
+
+ var previouslyExposedRows = [exposedRows copy],
+ previouslyExposedColumns = [exposedColumns copy];
+
+ [previouslyExposedRows removeIndexes:newlyExposedRows];
+ [previouslyExposedColumns removeIndexes:newlyExposedColumns];
+
+// console.log("will remove:" + '\n\n' +
+// previouslyExposedRows + "\n" + obscuredColumns + "\n\n" +
+// obscuredRows + "\n" + previouslyExposedColumns + "\n\n" +
+// obscuredRows + "\n" + obscuredColumns);
+ [self _unloadDataViewsInRows:previouslyExposedRows columns:obscuredColumns];
+ [self _unloadDataViewsInRows:obscuredRows columns:previouslyExposedColumns];
+ [self _unloadDataViewsInRows:obscuredRows columns:obscuredColumns];
+
+ [self _loadDataViewsInRows:previouslyExposedRows columns:newlyExposedColumns];
+ [self _loadDataViewsInRows:newlyExposedRows columns:previouslyExposedColumns];
+ [self _loadDataViewsInRows:newlyExposedRows columns:newlyExposedColumns];
+
+// console.log("newly exposed rows: " + newlyExposedRows + "\nnewly exposed columns: " + newlyExposedColumns);
+ _exposedRows = exposedRows;
+ _exposedColumns = exposedColumns;
+
+ [_tableDrawView setFrame:exposedRect];
+
+// [_tableDrawView setBounds:exposedRect];
+ [_tableDrawView display];
+
+ // Now clear all the leftovers
+ // FIXME: this could be faster!
+ for (identifier in _cachedDataViews)
+ {
+ var dataViews = _cachedDataViews[identifier],
+ count = dataViews.length;
+
+ while (count--)
+ [dataViews[count] removeFromSuperview];
+ }
+
+ // if (window.console && window.console.profile)
+// console.profileEnd("cell-load");
+}
+
+- (void)_unloadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
+{
+ if (![rows count] || ![columns count])
+ return;
+
+ var rowArray = [],
+ columnArray = [];
+
+ [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
+ [columns getIndexes:columnArray maxCount:-1 inIndexRange:nil];
+
+ var columnIndex = 0,
+ columnsCount = columnArray.length;
+
+ for (; columnIndex < columnsCount; ++columnIndex)
+ {
+ var column = columnArray[columnIndex],
+ tableColumn = _tableColumns[column],
+ tableColumnUID = [tableColumn UID];
+
+ var rowIndex = 0,
+ rowsCount = rowArray.length;
+
+ for (; rowIndex < rowsCount; ++rowIndex)
+ {
+ var row = rowArray[rowIndex],
+ dataView = _dataViewsForTableColumns[tableColumnUID][row];
+
+ _dataViewsForTableColumns[tableColumnUID][row] = nil;
+
+ [self _enqueueReusableDataView:dataView];
+ }
+ }
+}
+
+- (void)_loadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
+{
+ if (![rows count] || ![columns count])
+ return;
+
+ var rowArray = [],
+ rowRects = [],
+ columnArray = [];
+
+ [rows getIndexes:rowArray maxCount:-1 inIndexRange:nil];
+ [columns getIndexes:columnArray maxCount:-1 inIndexRange:nil];
+
+ UPDATE_COLUMN_RANGES_IF_NECESSARY();
+
+ var columnIndex = 0,
+ columnsCount = columnArray.length;
+
+ for (; columnIndex < columnsCount; ++columnIndex)
+ {
+ var column = columnArray[columnIndex],
+ tableColumn = _tableColumns[column],
+ tableColumnUID = [tableColumn UID];
+
+ if (!_dataViewsForTableColumns[tableColumnUID])
+ _dataViewsForTableColumns[tableColumnUID] = [];
+
+ var rowIndex = 0,
+ rowsCount = rowArray.length;
+
+ for (; rowIndex < rowsCount; ++rowIndex)
+ {
+ var row = rowArray[rowIndex],
+ dataView = [self _newDataViewForRow:row tableColumn:tableColumn];
+
+ [dataView setFrame:[self frameOfDataViewAtColumn:column row:row]];
+ [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
+
+ if ([dataView superview] !== self)
+ [self addSubview:dataView];
+
+ _dataViewsForTableColumns[tableColumnUID][row] = dataView;
+ }
+ }
+}
+
+- (CPView)_newDataViewForRow:(CPInteger)aRow tableColumn:(CPTableColumn)aTableColumn
+{
+ return [aTableColumn _newDataViewForRow:aRow];
+}
+
+- (void)_enqueueReusableDataView:(CPView)aDataView
+{
+ // FIXME: yuck!
+ var identifier = aDataView.identifier;
+
+ if (!_cachedDataViews[identifier])
+ _cachedDataViews[identifier] = [aDataView];
+ else
+ _cachedDataViews[identifier].push(aDataView);
+}
+
+- (void)setFrameSize:(CGSize)aSize
+{
+ [super setFrameSize:aSize];
+
+ if (_headerView)
+ [_headerView setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), _CGRectGetHeight([_headerView frame]))];
+}
+
+- (CGRect)exposedClipRect
+{
+ var superview = [self superview];
+
+ if (![superview isKindOfClass:[CPClipView class]])
+ return [self bounds];
+
+ return [self convertRect:CGRectIntersection([superview bounds], [self frame]) fromView:superview];
+}
+
+- (void)_drawRect:(CGRect)aRect
+{
+ var exposedRect = [self _exposedRect];
+
+ [self drawBackgroundInClipRect:exposedRect];
+ [self highlightSelectionInClipRect:exposedRect];
+ [self drawGridInClipRect:exposedRect];
+}
+
+- (void)drawBackgroundInClipRect:(CGRect)aRect
+{
+ if (![self usesAlternatingRowBackgroundColors])
+ return;
+
+ var rowColors = [self alternatingRowBackgroundColors],
+ colorCount = [rowColors count];
+
+ if (colorCount === 0)
+ return;
+
+ var context = [[CPGraphicsContext currentContext] graphicsPort];
+
+ if (colorCount === 1)
+ {
+ CGContextSetFillColor(context, rowColors[0]);
+ CGContextFillRect(context, aRect);
+
+ return;
+ }
+ // CGContextFillRect(context, CGRectIntersection(aRect, fillRect));
+ // console.profile("row-paint");
+ var exposedRows = [self rowsInRect:aRect],
+ firstRow = exposedRows.location,
+ lastRow = CPMaxRange(exposedRows) - 1,
+ colorIndex = MIN(exposedRows.length, colorCount),
+ heightFilled = 0.0;
+
+ while (colorIndex--)
+ {
+ var row = firstRow % colorCount + firstRow + colorIndex,
+ fillRect = nil;
+
+ CGContextBeginPath(context);
+
+ for (; row <= lastRow; row += colorCount)
+ CGContextAddRect(context, CGRectIntersection(aRect, fillRect = [self rectOfRow:row]));
+
+ if (row - colorCount === lastRow)
+ heightFilled = _CGRectGetMaxY(fillRect);
+
+ CGContextClosePath(context);
+
+ CGContextSetFillColor(context, rowColors[colorIndex]);
+ CGContextFillPath(context);
+ }
+ // console.profileEnd("row-paint");
+
+ var totalHeight = _CGRectGetMaxY(aRect);
+
+ if (heightFilled >= totalHeight || _rowHeight <= 0.0)
+ return;
+
+ var rowHeight = _rowHeight + _intercellSpacing.height,
+ fillRect = _CGRectMake(_CGRectGetMinX(aRect), _CGRectGetMinY(aRect) + heightFilled, _CGRectGetWidth(aRect), rowHeight);
+
+ for (row = lastRow + 1; heightFilled < totalHeight; ++row)
+ {
+ CGContextSetFillColor(context, rowColors[row % colorCount]);
+ CGContextFillRect(context, fillRect);
+
+ heightFilled += rowHeight;
+ fillRect.origin.y += rowHeight;
+ }
+}
+
+- (void)drawGridInClipRect:(CGRect)aRect
+{
+ var context = [[CPGraphicsContext currentContext] graphicsPort],
+ gridStyleMask = [self gridStyleMask];
+
+ if (!(gridStyleMask & (CPTableViewSolidHorizontalGridLineMask | CPTableViewSolidVerticalGridLineMask)))
+ return;
+
+ CGContextBeginPath(context);
+
+ if (gridStyleMask & CPTableViewSolidHorizontalGridLineMask)
+ {
+ var exposedRows = [self rowsInRect:aRect];
+ row = exposedRows.location,
+ lastRow = CPMaxRange(exposedRows) - 1,
+ rowY = 0.0,
+ minX = _CGRectGetMinX(aRect),
+ maxX = _CGRectGetMaxX(aRect);
+
+ for (; row <= lastRow; ++row)
+ {
+ // grab each row rect and add the top and bottom lines
+ var rowRect = [self rectOfRow:row],
+ rowY = _CGRectGetMaxY(rowRect) - 0.5;
+
+ CGContextMoveToPoint(context, minX, rowY);
+ CGContextAddLineToPoint(context, maxX, rowY);
+ }
+
+ if (_rowHeight > 0.0)
+ {
+ var rowHeight = _rowHeight + _intercellSpacing.height,
+ totalHeight = _CGRectGetMaxY(aRect);
+
+ while (rowY < totalHeight)
+ {
+ rowY += rowHeight;
+
+ CGContextMoveToPoint(context, minX, rowY);
+ CGContextAddLineToPoint(context, maxX, rowY);
+ }
+ }
+ }
+
+ if (gridStyleMask & CPTableViewSolidVerticalGridLineMask)
+ {
+ var exposedColumnIndexes = [self columnIndexesInRect:aRect],
+ columnsArray = [];
+
+ [exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:nil];
+
+ var columnArrayIndex = 0,
+ columnArrayCount = columnsArray.length,
+ minY = _CGRectGetMinY(aRect),
+ maxY = _CGRectGetMaxY(aRect);
+
+ for (; columnArrayIndex < columnArrayCount; ++columnArrayIndex)
+ {
+ var columnRect = [self rectOfColumn:columnArrayIndex],
+ columnX = _CGRectGetMaxX(columnRect) - 0.5;
+
+ CGContextMoveToPoint(context, columnX, minY);
+ CGContextAddLineToPoint(context, columnX, maxY);
+ }
+ }
+
+ CGContextClosePath(context);
+ CGContextSetStrokeColor(context, _gridColor);
+ CGContextStrokePath(context);
+}
+
+
+- (void)highlightSelectionInClipRect:(CGRect)aRect
+{
+ // FIXME: This color thingy is terrible probably.
+ if ([self selectionHighlightStyle] === CPTableViewSelectionHighlightStyleSourceList)
+ [[CPColor selectionColorSourceView] setFill];
+ else
+ [[CPColor selectionColor] setFill];
+
+ var context = [[CPGraphicsContext currentContext] graphicsPort],
+ indexes = [],
+ rectSelector = @selector(rectOfRow:);
+
+ if ([_selectedRowIndexes count] >= 1)
+ {
+ var exposedRows = [CPIndexSet indexSetWithIndexesInRange:[self rowsInRect:aRect]],
+ firstRow = [exposedRows firstIndex],
+ exposedRange = CPMakeRange(firstRow, [exposedRows lastIndex] - firstRow + 1);
+
+ [_selectedRowIndexes getIndexes:indexes maxCount:-1 inIndexRange:exposedRange];
+ }
+
+ else if ([_selectedColumnIndexes count] >= 1)
+ {
+ rectSelector = @selector(rectOfColumn:);
+
+ var exposedColumns = [self columnIndexesInRect:aRect],
+ firstColumn = [exposedColumns firstIndex],
+ exposedRange = CPMakeRange(firstColumn, [exposedColumns lastIndex] - firstColumn + 1);
+
+ [_selectedColumnIndexes getIndexes:indexes maxCount:-1 inIndexRange:exposedRange];
+ }
+
+ var count = [indexes count];
+
+ if (!count)
+ return;
+
+ CGContextBeginPath(context);
+
+ while (count--)
+ CGContextAddRect(context, CGRectIntersection(objj_msgSend(self, rectSelector, indexes[count]), aRect));
+
+ CGContextClosePath(context);
+ CGContextFillPath(context);
}
- (void)layoutSubviews
{
- [self loadTableCellsInRect:[self visibleRectInParent]];
+ [self load];
}
-- (void)displaySoon
+- (void)viewWillMoveToSuperview:(CPView)aView
{
- [_scrollTimer invalidate];
- _scrollTimer = [CPTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(displayNow) userInfo:nil repeats:NO];
+ var superview = [self superview],
+ defaultCenter = [CPNotificationCenter defaultCenter];
+
+ if (superview)
+ {
+ [defaultCenter
+ removeObserver:self
+ name:CPViewFrameDidChangeNotification
+ object:superview];
+
+ [defaultCenter
+ removeObserver:self
+ name:CPViewBoundsDidChangeNotification
+ object:superview];
+ }
+
+ if (aView)
+ {
+ [aView setPostsFrameChangedNotifications:YES];
+ [aView setPostsBoundsChangedNotifications:YES];
+
+ [defaultCenter
+ addObserver:self
+ selector:@selector(superviewFrameChanged:)
+ name:CPViewFrameDidChangeNotification
+ object:aView];
+
+ [defaultCenter
+ addObserver:self
+ selector:@selector(superviewBoundsChanged:)
+ name:CPViewBoundsDidChangeNotification
+ object:aView];
+ }
}
-- (void)displayNow
+- (void)superviewBoundsChanged:(CPNotification)aNotification
{
+ [self setNeedsDisplay:YES];
[self setNeedsLayout];
}
-- (void)viewDidMoveToSuperview
+- (void)superviewFrameChanged:(CPNotification)aNotification
{
- [[[self enclosingScrollView] contentView] setPostsBoundsChangedNotifications:YES];
-
- [[CPNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(viewBoundsChanged:)
- name:CPViewBoundsDidChangeNotification
- object:[[self enclosingScrollView] contentView]];
+ [self tile];
}
-- (void)viewBoundsChanged:(CPNotification)aNotification
-{
- //CPLog.info(_cmd + CPStringFromRect([[[self enclosingScrollView] contentView] bounds]));
- //objj_debug_print_backtrace();
- //[self setNeedsLayout];
- [self displayNow];
-}
+//
/*
-- (void)setAllowsColumnReordering:(BOOL)allowsColumnReordering
-{
- if (_allowsColumnReordering === _allowsColumnReordering)
- return;
-
- _allowsColumnReordering = allowsColumnReordering;
-}
-- (void)allowsColumnReordering
-{
- return _allowsColumnReordering;
-}
-
-- (void)setAllowsColumnResizing:(BOOL)allowsColumnResizing
-{
- if (_allowsColumnResizing === allowsColumnResizing)
- return;
-
- _allowsColumnResizing = allowsColumnResizing;
-}
-- (void)allowsColumnResizing
-{
- return _allowsColumnResizing;
-}
-
-- (void)setAllowsColumnSelection:(BOOL)allowsColumnSelection
-{
- if (_allowsColumnSelection === allowsColumnSelection)
- return;
-
- _allowsColumnSelection = allowsColumnSelection;
-}
-- (void)allowsColumnSelection
-{
- return _allowsColumnSelection;
-}
-*/
-
-- (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection
-{
- if (_allowsMultipleSelection === allowsMultipleSelection)
- return;
-
- _allowsMultipleSelection = allowsMultipleSelection;
-
- // TODO: more stuff?
-}
-- (void)allowsMultipleSelection
-{
- return _allowsMultipleSelection;
-}
-
-- (void)setAllowsEmptySelection:(BOOL)allowsEmptySelection
-{
- if (_allowsEmptySelection === allowsEmptySelection)
- return;
-
- _allowsEmptySelection = allowsEmptySelection;
-}
-- (void)allowsEmptySelection
-{
- return _allowsEmptySelection;
-}
-
-
-/*
- Returns the index of the row at the given point, or CPNotFound (-1) if it is out of range.
- @param aPoint the point
- @return the index of the row at aPoint
-*/
-- (int)rowAtPoint:(CGPoint)aPoint
-{
- var index = [self _rowAtY:aPoint.y]
-
- if (index >= 0 && index < _numberOfRows)
- return index;
- else
- return CPNotFound;
-}
-
-- (int)columnAtPoint:(CGPoint)aPoint
-{
- var index = [self _columnAtX:aPoint.x]
-
- if (index >= 0 && index < _tableColumns.length)
- return index;
- else
- return CPNotFound;
-}
-
-/*
- @ignore
-
- Internal version takes a Y value, returns an index, or -1 if its beyond the min, or numberOfRows if it's beyond the max
-*/
-- (int)_rowAtY:(float)y
-{
- if (_hasVariableHeightRows)
- {
- var a = 0,
- b = _numberOfRows;
-
- if (y < _rowMinYs[0])
- return -1;
- if (y >= _rowMinYs[_rowMinYs.length-1])
- return _numberOfRows;
-
- // binary search
- while (true)
- {
- var half = a + Math.floor((b - a) / 2);
-
- if (y < _rowMinYs[half])
- b = half;
- else if (half < _numberOfRows-1 && y >= _rowMinYs[half+1])
- a = half;
- else
- return half;
- }
- }
- else
- return FLOOR(y / (_rowHeight + _intercellSpacing.height));
-}
-
-/*
- @ignore
-
- Internal version takes a X value, returns an index, or -1 if its beyond the min, or numberOfColumns if it's beyond the max
-*/
-- (int)_columnAtX:(float)x
-{
- var a = 0,
- b = _tableColumns.length;
-
- var last = [_tableColumnViews[_tableColumns.length-1] frame];
- if (x < [_tableColumnViews[0] frame].origin.x)
- return -1;
- if (x >= last.origin.x + last.size.width)
- return _tableColumns.length;
-
- // binary search
- while (true)
- {
- var half = a + Math.floor((b - a) / 2);
-
- if (x < [_tableColumnViews[half] frame].origin.x)
- b = half;
- else if (half < _tableColumns.length-1 && x >= [_tableColumnViews[half+1] frame].origin.x)
- a = half;
- else
- return half;
- }
-}
-
-/*
- Selects the specified row indexes, optionally adding to existing selection
- @param indexes the indexes to select
- @param extend whether or not to add to the existing selection
-*/
-- (void)selectRowIndexes:(CPIndexSet)indexes byExtendingSelection:(BOOL)extend
-{
- // FIXME: should this be subject to the delegate filters, etc?
-
- if (extend)
- _selectedRowIndexes = [[_selectedRowIndexes copy] addIndexes:indexes];
- else if ([indexes count] > 0 || _allowsEmptySelection)
- _selectedRowIndexes = [indexes copy];
-
- [self _drawSelection];
-}
-
-/*
- Returns a CPIndexSet of the selected rows
- @return indexes of the selected rows
-*/
-- (CPIndexSet)selectedRowIndexes
-{
- return _selectedRowIndexes;
-}
-
-/*
- Returns the number of selected rows
- @return number of selected rows
-*/
-- (int)numberOfSelectedRows
-{
- return [_selectedRowIndexes count];
-}
-
-
-/*
- Deselects all rows if allowsEmptySelection is true. If delegate responds to "selectionShouldChangeInTableView:", asks if it should chnage.
- Sends the CPTableViewSelectionDidChangeNotification on deselection.
- @param the sender in a target/action
-*/
-- (void)deselectAll:(id)sender
-{
- if (!_allowsEmptySelection || [_selectedRowIndexes count] === 0 ||
- ((_delegateSelectorsCache & _CPTableViewSelectionShouldChangeSelector) && ![_delegate selectionShouldChangeInTableView:self]))
- return;
-
- [self selectRowIndexes:[CPIndexSet indexSet] byExtendingSelection:NO];
- [[CPNotificationCenter defaultCenter] postNotificationName:CPTableViewSelectionDidChangeNotification object:self userInfo:nil];
-}
-
-- (void)editColumn:(int)columnIndex row:(int)rowIndex withEvent:(CPEvent)theEvent select:(BOOL)flag
-{
-
-}
-
-/*
- @ignore
-*/
-- (void)_updateSelectionWithMouseAtRow:(int)aRow
-{
- // Make a preliminary new selection
- var newSelection;
- if (_allowsMultipleSelection)
- newSelection = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(MIN(aRow, _selectionStartRow), ABS(aRow-_selectionStartRow)+1)];
- else if (aRow >= 0 && aRow < _numberOfRows)
- newSelection = [CPIndexSet indexSetWithIndex:aRow];
- else
- newSelection = [CPIndexSet indexSet];
-
- // If cmd/ctrl was held down XOR the old selection with the proposed selection
- if (_allowsMultipleSelection && _selectionModifier & (CPCommandKeyMask | CPControlKeyMask | CPAlternateKeyMask))
- {
- // A = newSelection, B = _previousSelectedRowIndexes
- // (A intersection B) = (A - (A - B))
- var intersection = [newSelection copy],
- difference = [newSelection copy];
- [difference removeIndexes:_previousSelectedRowIndexes];
- [intersection removeIndexes:difference]
-
- // (A xor B) = (A + B) - (A intersection B)
- [newSelection addIndexes:_previousSelectedRowIndexes];
- [newSelection removeIndexes:intersection];
-
- // FIXME: if multiple selection is off, and we cmd/ctrl click the previously selected row, then deselect it.
- }
-
- // if the new selection is different than the old selection
- if (![newSelection isEqualToIndexSet:_selectedRowIndexes])
- {
- // ask the delegate if we should change the selection
- if ((_delegateSelectorsCache & _CPTableViewSelectionShouldChangeSelector) && ![_delegate selectionShouldChangeInTableView:self])
- return;
-
- // ask the delegate which indexes can be selected. selectionIndexesForProposedSelection is faster than shouldSelectRow
- if (_delegateSelectorsCache & _CPTableViewSelectionIndexesForProposedSelectionSelector)
- newSelection = [_delegate tableView:self selectionIndexesForProposedSelection:newSelection];
- else if (_delegateSelectorsCache & _CPTableViewShouldSelectRowSelector)
- {
- var indexes = [];
- [newSelection getIndexes:indexes maxCount:Number.MAX_VALUE inIndexRange:nil];
- for (var i = 0; i < indexes.length; i++)
- if (![_delegate tableView:self shouldSelectRow:indexes[i]])
- [newSelection removeIndex:indexes[i]];
- }
- }
-
- // if empty selection is not allowed and the new selection has nothing selected, abort
- if (!_allowsEmptySelection && [newSelection count] === 0)
- return;
-
- // if the new selection is *still* different, and update the selection and send a notification
- if (![newSelection isEqualToIndexSet:_selectedRowIndexes])
- {
- [self selectRowIndexes:newSelection byExtendingSelection:NO];
- [[CPNotificationCenter defaultCenter] postNotificationName:CPTableViewSelectionIsChangingNotification object:self userInfo:nil];
- }
-}
-
-/*
- @ignore
-*/
-- (void)mouseDown:(CPEvent)anEvent
-{
- [self trackSelection:anEvent];
-}
-
-/*
- Sets the message to be sent to the target when a cell is double clicked
- @param aSelector the selector to be performed
-*/
-- (void)setDoubleAction:(SEL)aSelector
-{
- _doubleAction = aSelector;
-}
-- (SEL)doubleAction
-{
- return _doubleAction;
-}
-
-- (int)clickedColumn
-{
- return _clickedColumn;
-}
-- (int)clickedRow
-{
- return _clickedRow;
-}
-
-/*
- @ignore
-*/
-- (void)trackSelection:(CPEvent)anEvent
-{
var type = [anEvent type],
point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
currentRow = MAX(0, MIN(_numberOfRows-1, [self _rowAtY:point.y]));
-
- if (type == CPLeftMouseUp)
- {
- _clickedRow = [self rowAtPoint:point];
- _clickedColumn = [self columnAtPoint:point];
-
- if ([anEvent clickCount] === 2)
- {
- CPLog.warn("edit?!");
-
- [self sendAction:_doubleAction to:_target];
- }
- else
- {
- if (![_previousSelectedRowIndexes isEqualToIndexSet:_selectedRowIndexes])
- {
- [[CPNotificationCenter defaultCenter] postNotificationName:CPTableViewSelectionDidChangeNotification object:self userInfo:nil];
- }
-
- [self sendAction:_action to:_target];
- }
-
- return;
- }
-
- if (type == CPLeftMouseDown)
- {
- _previousSelectedRowIndexes = _selectedRowIndexes;
- _selectionModifier = [anEvent modifierFlags];
-
- if (_selectionModifier & CPShiftKeyMask)
- _selectionStartRow = (ABS([_previousSelectedRowIndexes firstIndex] - currentRow) < ABS([_previousSelectedRowIndexes lastIndex] - currentRow)) ?
- [_previousSelectedRowIndexes firstIndex] : [_previousSelectedRowIndexes lastIndex];
- else
- _selectionStartRow = currentRow;
-
- [self _updateSelectionWithMouseAtRow:currentRow];
- }
- else if (type == CPLeftMouseDragged)
- {
- [self _updateSelectionWithMouseAtRow:currentRow];
- }
-
- [CPApp setTarget:self selector:@selector(trackSelection:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
+
+*/
+
+- (BOOL)tracksMouseOutsideOfFrame
+{
+ return YES;
}
-/*
- @ignore
-*/
-- (void)_drawSelection
+- (BOOL)startTrackingAt:(CGPoint)aPoint
{
- if (!_currentlySelected) {
- _currentlySelected = [CPIndexSet indexSet];
- _selectionViews = [];
- _selectionViewsPool = [];
- }
+ var row = [self rowAtPoint:aPoint];
- // TODO: we could also remove selections that aren't visible, but then we'll need to run this on every scroll/resize?
-
- // get array of indexes we can remove
- var removeSet = [_currentlySelected copy],
- indexesToRemove = [];
- [removeSet removeIndexes:_selectedRowIndexes];
- [removeSet getIndexes:indexesToRemove maxCount:Number.MAX_VALUE inIndexRange:nil];
-
- // get array of indexes we need to add
- var addSet = [_selectedRowIndexes copy],
- indexesToAdd = [];
- [addSet removeIndexes:_currentlySelected];
- [addSet getIndexes:indexesToAdd maxCount:Number.MAX_VALUE inIndexRange:nil];
-
- for (var i = 0; i < indexesToRemove.length; i++)
- {
- var row = indexesToRemove[i];
- for (var column = 0; column < _tableColumns.length; column++)
- if ([_tableCells[column][row] respondsToSelector:@selector(highlight:)])
- [_tableCells[column][row] highlight:NO];
- }
- for (var i = 0; i < indexesToAdd.length; i++)
- {
- var row = indexesToAdd[i];
- for (var column = 0; column < _tableColumns.length; column++)
- if ([_tableCells[column][row] respondsToSelector:@selector(highlight:)])
- [_tableCells[column][row] highlight:YES];
- }
+ if ([self mouseDownFlags] & CPShiftKeyMask)
+ _selectionAnchorRow = (ABS([_selectedRowIndexes firstIndex] - row) < ABS([_selectedRowIndexes lastIndex] - row)) ?
+ [_selectedRowIndexes firstIndex] : [_selectedRowIndexes lastIndex];
+ else
+ _selectionAnchorRow = row;
- // add each one we need to add, taking the selection views from removed seelctions, the pool, or new
- for (var i = 0; i < indexesToAdd.length; i++)
+ _previouslySelectedRowIndexes = nil;
+
+ [self _updateSelectionWithMouseAtRow:row];
+
+ return YES;
+}
+
+- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
+{
+ [self _updateSelectionWithMouseAtRow:[self rowAtPoint:aPoint]];
+
+ return YES;
+}
+
+- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
+{
+ if (![_previouslySelectedRowIndexes isEqualToIndexSet:_selectedRowIndexes])
+ [self _noteSelectionDidChange];
+}
+
+- (void)_updateSelectionWithMouseAtRow:(CPInteger)aRow
+{
+ // If cmd/ctrl was held down XOR the old selection with the proposed selection
+ if ([self mouseDownFlags] & (CPCommandKeyMask | CPControlKeyMask | CPAlternateKeyMask))
{
- var index = indexesToAdd[i],
- view;
-
- if (indexesToRemove.length > 0)
+ if ([_selectedRowIndexes containsIndex:aRow])
{
- view = _selectionViews[indexesToRemove.pop()];
+ newSelection = [_selectedRowIndexes copy];
+
+ [newSelection removeIndex:aRow];
}
- else if (_selectionViewsPool.length > 0)
+
+ else if (_allowsMultipleSelection)
{
- view = _selectionViewsPool.pop();
- [self addSubview:view positioned:CPWindowBelow relativeTo:nil];
+ newSelection = [_selectedRowIndexes copy];
+
+ [newSelection addIndex:aRow];
}
+
else
- {
- view = [[CPView alloc] init];
- [view setBackgroundColor:[CPColor alternateSelectedControlColor]];
-
- [self addSubview:view positioned:CPWindowBelow relativeTo:nil];
- }
-
- _selectionViews[index] = view;
-
- var frame = [self rectOfRow:index];
- frame.size.height += _intercellSpacing.height - 1;
- //frame.size.width += 500;
-
- [view setFrame:frame];
+ newSelection = [CPIndexSet indexSetWithIndex:aRow];
}
-
- // remove any selections that weren't already reused
- for (var i = 0; i < indexesToRemove.length; i++)
+
+ else if (_allowsMultipleSelection)
+ newSelection = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(MIN(aRow, _selectionAnchorRow), ABS(aRow - _selectionAnchorRow) + 1)];
+
+ else if (aRow >= 0 && aRow < _numberOfRows)
+ newSelection = [CPIndexSet indexSetWithIndex:aRow];
+
+ else
+ newSelection = [CPIndexSet indexSet];
+
+ if ([newSelection isEqualToIndexSet:_selectedRowIndexes])
+ return;
+
+ if (_implementedDelegateMethods & CPTableViewDelegate_selectionShouldChangeInTableView_ &&
+ ![_delegate selectionShouldChangeInTableView:self])
+ return;
+
+ if (_implementedDelegateMethods & CPTableViewDelegate_tableView_selectionIndexesForProposedSelection_)
+ newSelection = [_delegate tableView:self selectionIndexesForProposedSelection:newSelection];
+
+ if (_implementedDelegateMethods & CPTableViewDelegate_tableView_shouldSelectRow_)
{
- var row = indexesToRemove[i],
- view = _selectionViews[row];
-
- [view removeFromSuperview];
- _selectionViewsPool.push(view);
+ var indexArray = [];
+
+ [newSelection getIndexes:indexArray maxCount:-1 inIndexRange:nil];
+
+ var indexCount = indexArray.length;
+
+ while (indexCount--)
+ {
+ var index = indexArray[indexCount];
+
+ if (![_delegate tableView:self shouldSelectRow:index])
+ [newSelection removeIndex:index];
+ }
}
-
- // update the currently selected index set
- _currentlySelected = [_selectedRowIndexes copy];
+
+ // if empty selection is not allowed and the new selection has nothing selected, abort
+ if (!_allowsEmptySelection && [newSelection count] === 0)
+ return;
+
+ if ([newSelection isEqualToIndexSet:_selectedRowIndexes])
+ return;
+
+ if (!_previouslySelectedRowIndexes)
+ _previouslySelectedRowIndexes = [_selectedRowIndexes copy];
+
+ [self selectRowIndexes:newSelection byExtendingSelection:NO];
+
+ [self _noteSelectionIsChanging];
+}
+
+- (void)_noteSelectionIsChanging
+{
+ [[CPNotificationCenter defaultCenter]
+ postNotificationName:CPTableViewSelectionIsChangingNotification
+ object:self
+ userInfo:nil];
+}
+
+- (void)_noteSelectionDidChange
+{
+ [[CPNotificationCenter defaultCenter]
+ postNotificationName:CPTableViewSelectionDidChangeNotification
+ object:self
+ userInfo:nil];
}
@end
-
var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
CPTableViewDelegateKey = @"CPTableViewDelegateKey",
CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey",
@@ -1245,22 +1746,62 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
- (id)initWithCoder:(CPCoder)aCoder
{
- if (self = [super initWithCoder:aCoder])
+ self = [super initWithCoder:aCoder];
+
+ if (self)
{
- [self _init];
-
- _dataSource = [aCoder decodeObjectForKey:CPTableViewDataSourceKey];
- _delegate = [aCoder decodeObjectForKey:CPTableViewDelegateKey];
-
- _rowHeight = [aCoder decodeFloatForKey:CPTableViewRowHeightKey];
- _intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey];
-
+ //Configuring Behavior
+ _allowsColumnReordering = YES;
+ _allowsColumnResizing = YES;
_allowsMultipleSelection = [aCoder decodeBoolForKey:CPTableViewMultipleSelectionKey];
_allowsEmptySelection = [aCoder decodeBoolForKey:CPTableViewEmptySelectionKey];
-
- var tableColumns = [aCoder decodeObjectForKey:CPTableViewTableColumnsKey];
- for (var i = 0; i < tableColumns.length; i++)
- [self addTableColumn:tableColumns[i]];
+ _allowsColumnSelection = NO;
+
+ _tableViewFlags = 0;
+
+ //Setting Display Attributes
+ _selectionHighlightMask = CPTableViewSelectionHighlightStyleRegular;
+
+ [self setUsesAlternatingRowBackgroundColors:NO];
+ [self setAlternatingRowBackgroundColors:[[CPColor whiteColor], [CPColor colorWithHexString:@"e4e7ff"]]];
+
+ _tableColumns = [aCoder decodeObjectForKey:CPTableViewTableColumnsKey];
+ [_tableColumns makeObjectsPerformSelector:@selector(setTableView:) withObject:self];
+
+ _tableColumnRanges = [];
+ _dirtyTableColumnRangeIndex = 0;
+ _numberOfHiddenColumns = 0;
+
+ _objectValues = { };
+ _dataViewsForTableColumns = { };
+ _dataViews= [];
+ _numberOfRows = 0;
+ _exposedRows = [CPIndexSet indexSet];
+ _exposedColumns = [CPIndexSet indexSet];
+ _cachedDataViews = { };
+ _rowHeight = [aCoder decodeFloatForKey:CPTableViewRowHeightKey];
+ _intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey];
+
+ [self setGridColor:[CPColor grayColor]];
+ [self setGridStyleMask:CPTableViewGridNone];
+
+ _headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)];
+
+ [_headerView setTableView:self];
+
+ _cornerView = [[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))];
+
+ _selectedColumnIndexes = [CPIndexSet indexSet];
+ _selectedRowIndexes = [CPIndexSet indexSet];
+
+ [self setDataSource:[aCoder decodeObjectForKey:CPTableViewDataSourceKey]];
+ [self setDelegate:[aCoder decodeObjectForKey:CPTableViewDelegateKey]];
+
+ _tableDrawView = [[_CPTableDrawView alloc] initWithTableView:self];
+ [_tableDrawView setBackgroundColor:[CPColor clearColor]];
+ [self addSubview:_tableDrawView];
+
+ [self viewWillMoveToSuperview:[self superview]];
}
return self;
@@ -1273,29 +1814,28 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
[aCoder encodeObject:_dataSource forKey:CPTableViewDataSourceKey];
[aCoder encodeObject:_delegate forKey:CPTableViewDelegateKey];
- [aCoder encodeObject:_tableColumns forKey:CPTableViewTableColumnsKey];
-
[aCoder encodeFloat:_rowHeight forKey:CPTableViewRowHeightKey];
[aCoder encodeSize:_intercellSpacing forKey:CPTableViewIntercellSpacingKey];
[aCoder encodeBool:_allowsMultipleSelection forKey:CPTableViewMultipleSelectionKey];
[aCoder encodeBool:_allowsEmptySelection forKey:CPTableViewEmptySelectionKey];
+
+ [aCoder encodeObject:_tableColumns forKey:CPTableViewTableColumnsKey];
}
@end
+@implementation CPColor (tableview)
-
-@implementation CPColor (TableView)
-
-+ (CPColor)alternateSelectedControlColor
++ (CPColor)selectionColor
{
- return [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]];
+ return [CPColor colorWithHexString:@"5f83b9"];
}
-+ (CPColor)secondarySelectedControlColor
++ (CPColor)selectionColorSourceView
{
- return [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]];
+ return [CPColor colorWithPatternImage:[[CPImage alloc] initByReferencingFile:@"Resources/tableviewselection.png" size:CGSizeMake(6,22)]];
}
-@end
+
+@end
\ No newline at end of file
diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j
index 9c44c1f69..b4dc02792 100644
--- a/AppKit/CPTextField.j
+++ b/AppKit/CPTextField.j
@@ -100,7 +100,7 @@ var CPSecureTextFieldCharacter = "\u2022";
@implementation CPString (CPTextFieldAdditions)
/*!
- Returns the string (self).
+ Returns the string (\c self).
*/
- (CPString)string
{
@@ -389,7 +389,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
/*!
- Returns YES if the textfield is currently editable by the user.
+ Returns \c YES if the textfield is currently editable by the user.
*/
- (BOOL)isEditable
{
@@ -398,7 +398,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
/*!
Sets whether the field's text is selectable by the user.
- @param aFlag YES makes the text selectable
+ @param aFlag \c YES makes the text selectable
*/
- (void)setSelectable:(BOOL)aFlag
{
@@ -406,7 +406,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
/*!
- Returns YES if the field's text is selectable by the user.
+ Returns \c YES if the field's text is selectable by the user.
*/
- (BOOL)isSelectable
{
@@ -415,7 +415,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
/*!
Sets whether the field's text is secure.
- @param aFlag YES makes the text secure
+ @param aFlag \c YES makes the text secure
*/
- (void)setSecure:(BOOL)aFlag
{
@@ -423,7 +423,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
/*!
- Returns YES if the field's text is secure (password entry).
+ Returns \c YES if the field's text is secure (password entry).
*/
- (BOOL)isSecure
{
@@ -433,7 +433,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
// Setting the Bezel Style
/*!
Sets whether the textfield will have a bezeled border.
- @param shouldBeBezeled YES means the textfield will draw a bezeled border
+ @param shouldBeBezeled \c YES means the textfield will draw a bezeled border
*/
- (void)setBezeled:(BOOL)shouldBeBezeled
{
@@ -444,7 +444,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
/*!
- Returns YES if the textfield draws a bezeled border.
+ Returns \c YES if the textfield draws a bezeled border.
*/
- (BOOL)isBezeled
{
@@ -478,7 +478,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
/*!
Sets whether the textfield will have a border drawn.
- @param shouldBeBordered YES makes the textfield draw a border
+ @param shouldBeBordered \c YES makes the textfield draw a border
*/
- (void)setBordered:(BOOL)shouldBeBordered
{
@@ -489,7 +489,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
/*!
- Returns YES if the textfield has a border.
+ Returns \c YES if the textfield has a border.
*/
- (BOOL)isBordered
{
@@ -498,7 +498,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
/*!
Sets whether the textfield will have a background drawn.
- @param shouldDrawBackground YES makes the textfield draw a background
+ @param shouldDrawBackground \c YES makes the textfield draw a background
*/
- (void)setDrawsBackground:(BOOL)shouldDrawBackground
{
@@ -512,7 +512,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
/*!
- Returns YES if the textfield draws a background.
+ Returns \c YES if the textfield draws a background.
*/
- (BOOL)drawsBackground
{
@@ -570,6 +570,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
element.style.font = [[self currentValueForThemeAttribute:@"font"] cssString];
element.style.zIndex = 1000;
+ switch ([self alignment])
+ {
+ case CPCenterTextAlignment: element.style.textAlign = "center";
+ break;
+ case CPRightTextAlignment: element.style.textAlign = "right";
+ break;
+ default: element.style.textAlign = "left";
+ }
+
var contentRect = [self contentRectForBounds:[self bounds]];
element.style.top = _CGRectGetMinY(contentRect) + "px";
@@ -588,7 +597,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
//post CPControlTextDidBeginEditingNotification
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
- [[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES];
+ [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
CPTextFieldInputIsActive = YES;
@@ -647,7 +656,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
#endif
//post CPControlTextDidEndEditingNotification
- [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
+ [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
return YES;
}
@@ -683,7 +692,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
var string = [self stringValue];
- if ((!string || [string length] === 0) && ![self hasThemeState:CPThemeStateEditing])
+ if ((!string || string.length === 0) && ![self hasThemeState:CPThemeStateEditing])
[self setThemeState:CPTextFieldStatePlaceholder];
else
[self unsetThemeState:CPTextFieldStatePlaceholder];
@@ -763,8 +772,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
#if PLATFORM(DOM)
var element = [self _inputElement];
- if (element.parentNode == _DOMElement && ([self isEditable] || [self isSelectable]))
- element.select();
+ if (element.parentNode === _DOMElement && ([self isEditable] || [self isSelectable]))
+ window.setTimeout(function() { element.select(); }, 0);
#endif
}
diff --git a/AppKit/CPTheme.j b/AppKit/CPTheme.j
index 2a32a9573..499aaa8f7 100644
--- a/AppKit/CPTheme.j
+++ b/AppKit/CPTheme.j
@@ -531,7 +531,7 @@ function CPThemeAttributeEncode(aCoder, aThemeAttribute)
function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme, aClass)
{
- var key = "$a" + anAttributeName;
+ var key = "$a" + anAttributeName;
if (![aCoder containsValueForKey:key])
var attribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
@@ -555,3 +555,34 @@ function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme,
return attribute;
}
+
+/* TO AUTO CREATE THESE:
+function bit_count(bits)
+ {
+ var count = 0;
+
+ while (bits)
+ {
+ ++count;
+ bits &= (bits - 1);
+ }
+
+ return count ;
+ }
+
+zeros = "000000000";
+
+function pad(string, digits)
+{
+ return zeros.substr(0, digits - string.length) + string;
+}
+
+var str = ""
+str += '[';
+for (i = 0;i < Math.pow(2,6);++i)
+{
+ str += bit_count(i) + " /*" + pad(i.toString(2),6) + "*" + "/, ";
+}
+print(str+']');
+
+*/
\ No newline at end of file
diff --git a/AppKit/CPToolbar.j b/AppKit/CPToolbar.j
index 7d976b513..6bcff4a60 100644
--- a/AppKit/CPToolbar.j
+++ b/AppKit/CPToolbar.j
@@ -76,9 +76,9 @@ var CPToolbarConfigurationsByIdentifier = nil;
Called to obtain a toolbar item. Required.
@param toolbar the toolbar the item belongs to
@param itemIdentifier the identifier of the toolbar item
- @param flag YES means the item will be placed in the toolbar. NO means the item will be displayed for
+ @param flag \c YES means the item will be placed in the toolbar. \c NO means the item will be displayed for
some other purpose (non-functional)
- @return the toolbar item or nil if no such item belongs in the toolbar
+ @return the toolbar item or \c nil if no such item belongs in the toolbar
*/
@implementation CPToolbar : CPObject
{
@@ -176,7 +176,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
}
/*!
- Returns YES if the toolbar is currently visible
+ Returns \c YES if the toolbar is currently visible
*/
- (BOOL)isVisible
{
@@ -185,7 +185,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
/*!
Sets whether the toolbar should be visible.
- @param aFlag YES makes the toolbar visible
+ @param aFlag \c YES makes the toolbar visible
*/
- (void)setVisible:(BOOL)aFlag
{
@@ -304,7 +304,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
}
/*!
- Returns the toolbar items sorted by their visibilityPriority(ies).
+ Returns the toolbar items sorted by their \c visibilityPriority(ies).
*/
- (CPArray)itemsSortedByVisibilityPriority
{
@@ -369,7 +369,7 @@ var CPToolbarIdentifierKey = "CPToolbarIdentifierKey",
@implementation CPToolbar (CPCoding)
/*
- Initializes the toolbar by unarchiving data from aCoder.
+ Initializes the toolbar by unarchiving data from \c aCoder.
@param aCoder the coder containing the archived CPToolbar.
*/
- (id)initWithCoder:(CPCoder)aCoder
@@ -725,7 +725,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
- (CPView)viewForItem:(CPToolbarItem)anItem
{
- var info = [_itemInfos objectForKey:[anItem hash]];
+ var info = [_itemInfos objectForKey:[anItem UID]];
if (!info)
return nil;
@@ -735,7 +735,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
- (CPTextField)labelForItem:(CPToolbarItem)anItem
{
- var info = [_itemInfos objectForKey:[anItem hash]];
+ var info = [_itemInfos objectForKey:[anItem UID]];
if (!info)
return nil;
@@ -745,7 +745,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
- (float)minWidthForItem:(CPToolbarItem)anItem
{
- var info = [_itemInfos objectForKey:[anItem hash]];
+ var info = [_itemInfos objectForKey:[anItem UID]];
if (!info)
return 0;
@@ -814,7 +814,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
var minSize = [item minSize],
minWidth = MAX(minSize.width, CGRectGetWidth([label frame]));
- [_itemInfos setObject:_CPToolbarItemInfoMake(index, view, label, minWidth) forKey:[item hash]];
+ [_itemInfos setObject:_CPToolbarItemInfoMake(index, view, label, minWidth) forKey:[item UID]];
_minWidth += minWidth + TOOLBAR_ITEM_MARGIN;
diff --git a/AppKit/CPToolbarItem.j b/AppKit/CPToolbarItem.j
index b0d9f9c47..64c4aea7c 100644
--- a/AppKit/CPToolbarItem.j
+++ b/AppKit/CPToolbarItem.j
@@ -223,7 +223,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
}
/*!
- Sets the target of the action that is triggered when the user clicks this item. nil will cause
+ Sets the target of the action that is triggered when the user clicks this item. \c nil will cause
the action to be passed on to the first responder.
@param aTarget the new target
*/
@@ -261,7 +261,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
}
/*!
- Returns YES if the item is enabled.
+ Returns \c YES if the item is enabled.
*/
- (BOOL)isEnabled
{
@@ -273,7 +273,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
/*!
Sets whether the item is enabled.
- @param aFlag YES enables the item
+ @param aFlag \c YES enables the item
*/
- (void)setEnabled:(BOOL)shouldBeEnabled
{
@@ -458,15 +458,16 @@ CPToolbarItemVisibilityPriorityUser
[copy setLabel:_label];
[copy setPaletteLabel:_paletteLabel];
[copy setToolTip:[self toolTip]];
-
+
[copy setTag:[self tag]];
[copy setTarget:[self target]];
[copy setAction:[self action]];
[copy setEnabled:[self isEnabled]];
- [copy setImage:_image];
- [copy setAlternateImage:_alternateImage];
-
+
+ [copy setImage:[self image]];
+ [copy setAlternateImage:[self alternateImage]];
+
[copy setMinSize:_minSize];
[copy setMaxSize:_maxSize];
diff --git a/AppKit/CPTreeNode.j b/AppKit/CPTreeNode.j
new file mode 100644
index 000000000..4e8cb1600
--- /dev/null
+++ b/AppKit/CPTreeNode.j
@@ -0,0 +1,82 @@
+
+@import
+
+
+@implementation CPTreeNode : CPObject
+{
+ id _representedObject @accessors(readonly, property=representedObject);
+
+ CPTreeNode _parentNode @accessors(readonly, property=parentNode);
+ CPMutableArray _childNodes @accessors(readonly, property=childNodes);
+}
+
++ (id)treeNodeWithRepresentedObject:(id)anObject
+{
+ return [[self alloc] initWithRepresentedObject:anObject];
+}
+
+- (id)initWithRepresentedObject:(id)anObject
+{
+ self = [super init];
+
+ if (self)
+ {
+ _representedObject = anObject;
+ _childNodes = [];
+ }
+
+ return self;
+}
+
+- (BOOL)isLeaf
+{
+ return [_childNodes count] <= 0;
+}
+
+- (CPMutableArray)mutableChildNodes
+{
+ return [self mutableArrayValueForKey:@"childNodes"];
+}
+
+- (void)insertObject:(id)anObject inChildNodesAtIndex:(CPInteger)anIndex
+{
+ anObject._parentNode = self;
+
+ [_childNodes addObject:anObject];
+}
+
+- (void)removeObjectFromChildNodesAtIndex:(CPInteger)anIndex
+{
+ anObject._parentNode = nil;
+
+ [_childNodes removeObjectAtIndex:anIndex];
+}
+
+- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)anObject
+{
+ var oldObject = [_childNodes objectAtIndex:anIndex];
+
+ oldObject._parentNode = nil;
+
+ [_childNodes replaceObjectAtIndex:anIndex withObject:anObject];
+}
+
+- (id)objectInChildNodesAtIndex:(CPInteger)anIndex
+{
+ return _childNodes[anIndex];
+}
+
+- (void)sortWithSortDescriptors:(CPArray)sortDescriptors recursively:(BOOL)shouldSortRecursively
+{
+ [_childNodes sortUsingDescriptors:sortDescriptors];
+
+ if (!shouldSortRecursively)
+ return;
+
+ var count = [_childNodes count];
+
+ while (count--)
+ [_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
+}
+
+@end
diff --git a/AppKit/CPView.j b/AppKit/CPView.j
index 61cba8ec6..c0e7a5157 100644
--- a/AppKit/CPView.j
+++ b/AppKit/CPView.j
@@ -27,11 +27,11 @@
@import "CGGeometry.j"
@import "CPColor.j"
-@import "CPDOMDisplayServer.j"
@import "CPGeometry.j"
@import "CPGraphicsContext.j"
@import "CPResponder.j"
@import "CPTheme.j"
+@import "_CPDisplayServer.j"
#include "Platform/Platform.h"
@@ -94,12 +94,13 @@ var DOMElementPrototype = nil,
BackgroundTrivialColor = 0,
BackgroundVerticalThreePartImage = 1,
BackgroundHorizontalThreePartImage = 2,
- BackgroundNinePartImage = 3,
-
- CustomDrawRectViews = {},
- CustomLayoutSubviewsViews = {};
+ BackgroundNinePartImage = 3;
#endif
+var CPViewFlags = { },
+ CPViewHasCustomDrawRect = 1 << 0,
+ CPViewHasCustomLayoutSubviews = 1 << 1;
+
/*!
@ingroup appkit
@class CPView
@@ -113,7 +114,7 @@ var DOMElementPrototype = nil,
headed by the window's content view. Every other view in a window is a descendant
of this view.
-
Subclasses can override -drawRect: in order to implement their
+
Subclasses can override \c -drawRect: in order to implement their
appearance. Other methods of CPView and CPResponder can
also be overridden to handle user generated events.
*/
@@ -143,8 +144,6 @@ var DOMElementPrototype = nil,
BOOL _postsBoundsChangedNotifications;
BOOL _inhibitFrameAndBoundsChangedNotifications;
- CPString _displayHash;
-
#if PLATFORM(DOM)
DOMElement _DOMElement;
DOMElement _DOMContentsElement;
@@ -180,9 +179,14 @@ var DOMElementPrototype = nil,
JSObject _themeAttributes;
unsigned _themeState;
+ JSObject _ephemeralSubviewsForNames;
+ CPSet _ephereralSubviews;
+
// Key View Support
CPView _nextKeyView;
CPView _previousKeyView;
+
+ unsigned _viewClassFlags;
}
/*
@@ -208,6 +212,32 @@ var DOMElementPrototype = nil,
CachedNotificationCenter = [CPNotificationCenter defaultCenter];
}
+- (void)setupViewFlags
+{
+ var theClass = [self class],
+ classUID = [theClass UID];
+
+ if (CPViewFlags[classUID] === undefined)
+ {
+ var flags = 0;
+
+ if ([theClass instanceMethodForSelector:@selector(drawRect:)] !== [CPView instanceMethodForSelector:@selector(drawRect:)])
+ flags |= CPViewHasCustomDrawRect;
+
+ if ([theClass instanceMethodForSelector:@selector(layoutSubviews)] !== [CPView instanceMethodForSelector:@selector(layoutSubviews)])
+ flags |= CPViewHasCustomLayoutSubviews;
+
+ CPViewFlags[classUID] = flags;
+ }
+
+ _viewClassFlags = CPViewFlags[classUID];
+}
+
++ (CPSet)keyPathsForValuesAffectingFrame
+{
+ return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
+}
+
- (id)init
{
return [self initWithFrame:CGRectMakeZero()];
@@ -242,11 +272,9 @@ var DOMElementPrototype = nil,
_isHidden = NO;
_hitTests = YES;
- _displayHash = [self hash];
-
#if PLATFORM(DOM)
_DOMElement = DOMElementPrototype.cloneNode(false);
-
+
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(aFrame), _CGRectGetMinY(aFrame));
CPDOMDisplayServerSetStyleSize(_DOMElement, width, height);
@@ -257,6 +285,8 @@ var DOMElementPrototype = nil,
_theme = [CPTheme defaultTheme];
_themeState = CPThemeStateNormal;
+ [self setupViewFlags];
+
[self _loadThemeAttributes];
}
@@ -299,10 +329,10 @@ var DOMElementPrototype = nil,
}
/*!
- Makes aSubview a subview of the receiver. It is positioned relative to anotherView
+ Makes \c aSubview a subview of the receiver. It is positioned relative to \c anotherView
@param aSubview the view to add as a subview
- @param anOrderingMode specifies aSubview's ordering relative to anotherView
- @param anotherView aSubview will be positioned relative to this argument
+ @param anOrderingMode specifies \c aSubview's ordering relative to \c anotherView
+ @param anotherView \c aSubview will be positioned relative to this argument
*/
- (void)addSubview:(CPView)aSubview positioned:(CPWindowOrderingMode)anOrderingMode relativeTo:(CPView)anotherView
{
@@ -390,7 +420,7 @@ var DOMElementPrototype = nil,
}
/*!
- Called when the receiver has added aSubview to it's child views.
+ Called when the receiver has added \c aSubview to it's child views.
@param aSubview the view that was added
*/
- (void)didAddSubview:(CPView)aSubview
@@ -474,7 +504,7 @@ var DOMElementPrototype = nil,
}
/*!
- Returns YES if the receiver is, or is a descendant of, aView.
+ Returns \c YES if the receiver is, or is a descendant of, \c aView.
@param aView the view to test for ancestry
*/
- (BOOL)isDescendantOf:(CPView)aView
@@ -532,7 +562,7 @@ var DOMElementPrototype = nil,
/*!
Returns the menu item containing the receiver or one of its ancestor views.
- @return a menu item, or nil if the view or one of its ancestors wasn't found
+ @return a menu item, or \c nil if the view or one of its ancestors wasn't found
*/
- (CPMenuItem)enclosingMenuItem
{
@@ -585,7 +615,7 @@ var DOMElementPrototype = nil,
/*!
Returns whether the view is flipped.
- @return YES if the view is flipped. NO, otherwise.
+ @return \c YES if the view is flipped. \c NO, otherwise.
*/
- (BOOL)isFlipped
{
@@ -624,6 +654,16 @@ var DOMElementPrototype = nil,
return _CGRectMakeCopy(_frame);
}
+- (CGPoint)frameOrigin
+{
+ return _CGPointMakeCopy(_frame.origin);
+}
+
+- (CGSize)frameSize
+{
+ return _CGSizeMakeCopy(_frame.size);
+}
+
/*!
Moves the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system.
The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver
@@ -666,12 +706,14 @@ var DOMElementPrototype = nil,
[CachedNotificationCenter postNotificationName:CPViewFrameDidChangeNotification object:self];
#if PLATFORM(DOM)
- CPDOMDisplayServerSetStyleLeftTop(_DOMElement, _superview ? _superview._boundsTransform : NULL, origin.x, origin.y);
+ var transform = _superview ? _superview._boundsTransform : NULL;
+
+ CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y);
#endif
}
/*!
- Sets the receiver's frame size. If aSize is the same as the frame's current dimensions, this
+ Sets the receiver's frame size. If \c aSize is the same as the frame's current dimensions, this
method simply returns. The method posts a CPViewFrameDidChangeNotification to the
default notification center if the receiver is configured to do so.
@param aSize the new size for the frame
@@ -888,7 +930,7 @@ var DOMElementPrototype = nil,
}
/*!
- Initiates superviewSizeChanged: messages to subviews.
+ Initiates \c -superviewSizeChanged: messages to subviews.
@param aSize the size for the subviews
*/
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
@@ -901,9 +943,9 @@ var DOMElementPrototype = nil,
/*!
Specifies whether the receiver view should automatically resize its
- subviews when its setFrameSize: method receives a change.
- @param aFlag If YES, then subviews will automatically be resized
- when this view is resized. NO means the views will not
+ subviews when its \c -setFrameSize: method receives a change.
+ @param aFlag If \c YES, then subviews will automatically be resized
+ when this view is resized. \c NO means the views will not
be resized automatically.
*/
- (void)setAutoresizesSubviews:(BOOL)aFlag
@@ -913,7 +955,7 @@ var DOMElementPrototype = nil,
/*!
Reports whether the receiver automatically resizes its subviews when its frame size changes.
- @return YES means it resizes its subviews on a frame size change.
+ @return \c YES means it resizes its subviews on a frame size change.
*/
- (BOOL)autoresizesSubviews
{
@@ -956,7 +998,7 @@ var DOMElementPrototype = nil,
{
_fullScreenModeState = _CPViewFullScreenModeStateMake(self);
- var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds] styleMask:CPBorderlessWindowMask];
+ var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPPlatformWindow primaryPlatformWindow] contentBounds] styleMask:CPBorderlessWindowMask];
[fullScreenWindow setLevel:CPScreenSaverWindowLevel];
[fullScreenWindow setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
@@ -1005,7 +1047,7 @@ var DOMElementPrototype = nil,
}
/*!
- Returns YES if the receiver is currently in full screen mode.
+ Returns \c YES if the receiver is currently in full screen mode.
*/
- (BOOL)isInFullScreenMode
{
@@ -1014,7 +1056,7 @@ var DOMElementPrototype = nil,
/*!
Sets whether the receiver should be hidden.
- @param aFlag YES makes the receiver hidden.
+ @param aFlag \c YES makes the receiver hidden.
*/
- (void)setHidden:(BOOL)aFlag
{
@@ -1050,7 +1092,7 @@ var DOMElementPrototype = nil,
}
/*!
- Returns YES if the receiver is hidden.
+ Returns \c YES if the receiver is hidden.
*/
- (BOOL)isHidden
{
@@ -1094,8 +1136,8 @@ var DOMElementPrototype = nil,
}
/*!
- Returns YES if the receiver is hidden, or one
- of it's ancestor views is hidden. NO, otherwise.
+ Returns \c YES if the receiver is hidden, or one
+ of it's ancestor views is hidden. \c NO, otherwise.
*/
- (BOOL)isHiddenOrHasHiddenAncestor
{
@@ -1108,9 +1150,9 @@ var DOMElementPrototype = nil,
}
/*!
- Returns whether the receiver should be sent a mouseDown: message for anEvent.
- Returns YES by default.
- @return YES, if the view object accepts first mouse-down event. NO, otherwise.
+ Returns whether the receiver should be sent a \c -mouseDown: message for \c anEvent.
+ Returns \c YES by default.
+ @return \c YES, if the view object accepts first mouse-down event. \c NO, otherwise.
*/
//FIXME: should be NO by default?
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
@@ -1120,7 +1162,7 @@ var DOMElementPrototype = nil,
/*!
Returns whether or not the view responds to hit tests.
- @return YES if this view listens to hitTest messages, NO otherwise.
+ @return \c YES if this view listens to \c -hitTest messages, \c NO otherwise.
*/
- (BOOL)hitTests
{
@@ -1129,7 +1171,7 @@ var DOMElementPrototype = nil,
/*!
Set whether or not the view should respond to hit tests.
- @param shouldHitTest should be YES if this view should respond to hit tests, NO otherwise.
+ @param shouldHitTest should be \c YES if this view should respond to hit tests, \c NO otherwise.
*/
- (void)setHitTests:(BOOL)shouldHitTest
{
@@ -1161,8 +1203,8 @@ var DOMElementPrototype = nil,
}
/*!
- Returns YES if mouse events aren't needed by the receiver and can be sent to the superview. The
- default implementation returns NO if the view is opaque.
+ Returns \c YES if mouse events aren't needed by the receiver and can be sent to the superview. The
+ default implementation returns \c NO if the view is opaque.
*/
- (BOOL)mouseDownCanMoveWindow
{
@@ -1208,7 +1250,7 @@ var DOMElementPrototype = nil,
amount = 0 - _DOMImageParts.length;
}
-
+
if (amount > 0)
while (amount--)
{
@@ -1236,16 +1278,16 @@ var DOMElementPrototype = nil,
else
{
var slices = [patternImage imageSlices],
- count = slices.length,
+ count = MIN(_DOMImageParts.length, slices.length),
frameSize = _frame.size;
-
+
while (count--)
{
var image = slices[count],
size = _DOMImageSizes[count] = image ? [image size] : _CGSizeMakeZero();
CPDOMDisplayServerSetStyleSize(_DOMImageParts[count], size.width, size.height);
-
+
_DOMImageParts[count].style.background = image ? "url(\"" + [image filename] + "\")" : "";
}
@@ -1300,7 +1342,7 @@ var DOMElementPrototype = nil,
// Converting Coordinates
/*!
- Converts aPoint from the coordinate space of aView to the coordinate space of the receiver.
+ Converts \c aPoint from the coordinate space of \c aView to the coordinate space of the receiver.
@param aPoint the point to convert
@param aView the view space to convert from
@return the converted point
@@ -1311,7 +1353,7 @@ var DOMElementPrototype = nil,
}
/*!
- Converts aPoint from the receiver's coordinate space to the coordinate space of aView.
+ Converts \c aPoint from the receiver's coordinate space to the coordinate space of \c aView.
@param aPoint the point to convert
@param aView the coordinate space to which the point will be converted
@return the converted point
@@ -1322,7 +1364,7 @@ var DOMElementPrototype = nil,
}
/*!
- Convert's aSize from aView's coordinate space to the receiver's coordinate space.
+ Convert's \c aSize from \c aView's coordinate space to the receiver's coordinate space.
@param aSize the size to convert
@param aView the coordinate space to convert from
@return the converted size
@@ -1333,7 +1375,7 @@ var DOMElementPrototype = nil,
}
/*!
- Convert's aSize from the receiver's coordinate space to aView's coordinate space.
+ Convert's \c aSize from the receiver's coordinate space to \c aView's coordinate space.
@param aSize the size to convert
@param the coordinate space to which the size will be converted
@return the converted size
@@ -1344,7 +1386,7 @@ var DOMElementPrototype = nil,
}
/*!
- Converts aRect from aView's coordinate space to the receiver's space.
+ Converts \c aRect from \c aView's coordinate space to the receiver's space.
@param aRect the rectangle to convert
@param aView the coordinate space from which to convert
@return the converted rectangle
@@ -1355,7 +1397,7 @@ var DOMElementPrototype = nil,
}
/*!
- Converts aRect from the receiver's coordinate space to aView's coordinate space.
+ Converts \c aRect from the receiver's coordinate space to \c aView's coordinate space.
@param aRect the rectangle to convert
@param aView the coordinate space to which the rectangle will be converted
@return the converted rectangle
@@ -1367,14 +1409,14 @@ var DOMElementPrototype = nil,
/*!
Sets whether the receiver posts a CPViewFrameDidChangeNotification notification
- to the default notification center when its frame is changed. The default is NO.
+ to the default notification center when its frame is changed. The default is \c NO.
Methods that could cause a frame change notification are:
setFrame:
setFrameSize:
setFrameOrigin:
- @param shouldPostFrameChangedNotifications YES makes the receiver post
+ @param shouldPostFrameChangedNotifications \c YES makes the receiver post
notifications on frame changes (size or origin)
*/
- (void)setPostsFrameChangedNotifications:(BOOL)shouldPostFrameChangedNotifications
@@ -1391,7 +1433,7 @@ setFrameOrigin:
}
/*!
- Returns YES if the receiver posts a CPViewFrameDidChangeNotification if its frame is changed.
+ Returns \c YES if the receiver posts a CPViewFrameDidChangeNotification if its frame is changed.
*/
- (BOOL)postsFrameChangedNotifications
{
@@ -1400,14 +1442,14 @@ setFrameOrigin:
/*!
Sets whether the receiver posts a CPViewBoundsDidChangeNotification notification
- to the default notification center when its bounds is changed. The default is NO.
+ to the default notification center when its bounds is changed. The default is \c NO.
Methods that could cause a bounds change notification are:
setBounds:
setBoundsSize:
setBoundsOrigin:
- @param shouldPostBoundsChangedNotifications YES makes the receiver post
+ @param shouldPostBoundsChangedNotifications \c YES makes the receiver post
notifications on bounds changes
*/
- (void)setPostsBoundsChangedNotifications:(BOOL)shouldPostBoundsChangedNotifications
@@ -1424,7 +1466,7 @@ setBoundsOrigin:
}
/*!
- Returns YES if the receiver posts a
+ Returns \c YES if the receiver posts a
CPViewBoundsDidChangeNotification when its
bounds is changed.
*/
@@ -1436,9 +1478,9 @@ setBoundsOrigin:
/*!
Initiates a drag operation from the receiver to another view that accepts dragged data.
@param anImage the image to be dragged
- @param aLocation the lower-left corner coordinate of anImage
- @param mouseOffset the distance from the mouseDown: location and the current location
- @param anEvent the mouseDown: that triggered the drag
+ @param aLocation the lower-left corner coordinate of \c anImage
+ @param mouseOffset the distance from the \c -mouseDown: location and the current location
+ @param anEvent the \c -mouseDown: that triggered the drag
@param aPastebaord the pasteboard that holds the drag data
@param aSourceObject the drag operation controller
@param slideBack Whether the image should 'slide back' if the drag is rejected
@@ -1451,9 +1493,9 @@ setBoundsOrigin:
/*!
Initiates a drag operation from the receiver to another view that accepts dragged data.
@param aView the view to be dragged
- @param aLocation the top-left corner coordinate of aView
- @param mouseOffset the distance from the mouseDown: location and the current location
- @param anEvent the mouseDown: that triggered the drag
+ @param aLocation the top-left corner coordinate of \c aView
+ @param mouseOffset the distance from the \c -mouseDown: location and the current location
+ @param anEvent the \c -mouseDown: that triggered the drag
@param aPastebaord the pasteboard that holds the drag data
@param aSourceObject the drag operation controller
@param slideBack Whether the view should 'slide back' if the drag is rejected
@@ -1469,7 +1511,7 @@ setBoundsOrigin:
*/
- (void)registerForDraggedTypes:(CPArray)pasteboardTypes
{
- if (!pasteboardTypes)
+ if (!pasteboardTypes || ![pasteboardTypes count])
return;
var theWindow = [self window];
@@ -1505,7 +1547,7 @@ setBoundsOrigin:
}
/*!
- Draws the receiver into aRect. This method should be overridden by subclasses.
+ Draws the receiver into \c aRect. This method should be overridden by subclasses.
@param aRect the area that should be drawn into
*/
- (void)drawRect:(CPRect)aRect
@@ -1522,43 +1564,26 @@ setBoundsOrigin:
{
if (aFlag)
[self setNeedsDisplayInRect:[self bounds]];
-#if PLATFORM(DOM)
- else
- CPDOMDisplayServerRemoveView(self);
-#endif
}
/*!
- Marks the area denoted by aRect as dirty, and initiates a redraw on it.
+ Marks the area denoted by \c aRect as dirty, and initiates a redraw on it.
@param aRect the area that needs to be redrawn
*/
- (void)setNeedsDisplayInRect:(CPRect)aRect
{
-#if PLATFORM(DOM)
- var hash = [[self class] hash],
- hasCustomDrawRect = CustomDrawRectViews[hash];
-
- if (!hasCustomDrawRect && typeof hasCustomDrawRect === "undefined")
- {
- hasCustomDrawRect = [self methodForSelector:@selector(drawRect:)] != [CPView instanceMethodForSelector:@selector(drawRect:)];
- CustomDrawRectViews[hash] = hasCustomDrawRect;
- }
-
- if (!hasCustomDrawRect)
+ if (!(_viewClassFlags & CPViewHasCustomDrawRect))
return;
-#endif
-
+
if (_CGRectIsEmpty(aRect))
return;
-
+
if (_dirtyRect && !_CGRectIsEmpty(_dirtyRect))
_dirtyRect = CGRectUnion(aRect, _dirtyRect);
else
_dirtyRect = _CGRectMakeCopy(aRect);
-#if PLATFORM(DOM)
- CPDOMDisplayServerAddView(self);
-#endif
+ _CPDisplayServerAddDisplayObject(self);
}
- (BOOL)needsDisplay
@@ -1576,7 +1601,7 @@ setBoundsOrigin:
}
/*!
- Draws the entire area of the receiver as defined by its bounds.
+ Draws the entire area of the receiver as defined by its \c -bounds.
*/
- (void)display
{
@@ -1590,7 +1615,7 @@ setBoundsOrigin:
}
/*!
- Draws the receiver into the area defined by aRect.
+ Draws the receiver into the area defined by \c aRect.
@param aRect the area to be drawn
*/
- (void)displayRect:(CPRect)aRect
@@ -1663,26 +1688,12 @@ setBoundsOrigin:
- (void)setNeedsLayout
{
- _needsLayout = YES;
-
-#if PLATFORM(DOM)
- var hash = [[self class] hash],
- hasCustomLayoutSubviews = CustomLayoutSubviewsViews[hash];
-
- if (hasCustomLayoutSubviews === undefined)
- {
- hasCustomLayoutSubviews = [self methodForSelector:@selector(layoutSubviews)] != [CPView instanceMethodForSelector:@selector(layoutSubviews)];
- CustomLayoutSubviewsViews[hash] = hasCustomLayoutSubviews;
- }
-
- if (!hasCustomLayoutSubviews)
+ if (!(_viewClassFlags & CPViewHasCustomLayoutSubviews))
return;
- if (_needsLayout)
- {
- CPDOMDisplayServerAddView(self);
- }
-#endif
+ _needsLayout = YES;
+
+ _CPDisplayServerAddLayoutObject(self);
}
- (void)layoutIfNeeded
@@ -1700,7 +1711,7 @@ setBoundsOrigin:
}
/*!
- Returns whether the receiver is completely opaque. By default, returns NO.
+ Returns whether the receiver is completely opaque. By default, returns \c NO.
*/
- (BOOL)isOpaque
{
@@ -1732,7 +1743,7 @@ setBoundsOrigin:
}
/*!
- Changes the receiver's frame origin to a 'constrained' aPoint.
+ Changes the receiver's frame origin to a 'constrained' \c aPoint.
@param aPoint the proposed frame origin
*/
- (void)scrollPoint:(CGPoint)aPoint
@@ -1746,9 +1757,9 @@ setBoundsOrigin:
}
/*!
- Scrolls the nearest ancestor CPClipView a minimum amount so aRect can become visible.
+ Scrolls the nearest ancestor CPClipView a minimum amount so \c aRect can become visible.
@param aRect the area to become visible
- @return if any scrolling occurred, NO otherwise.
+ @return YES means the receiver wants a layer.
+ @param \c YES means the receiver wants a layer.
*/
- (void)setWantsLayer:(BOOL)aFlag
{
@@ -1950,8 +1961,8 @@ setBoundsOrigin:
}
/*!
- Returns YES if the receiver uses a CALayer
- @returns YES if the receiver uses a CALayer
+ Returns \c YES if the receiver uses a CALayer
+ @returns \c YES if the receiver uses a CALayer
*/
- (BOOL)wantsLayer
{
@@ -2184,6 +2195,54 @@ setBoundsOrigin:
return [_themeAttributes[aName] valueForState:_themeState];
}
+- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
+{
+ return nil;
+}
+
+- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
+{
+ return _CGRectMakeZero();
+}
+
+- (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName
+ positioned:(CPWindowOrderingMode)anOrderingMode
+ relativeToEphemeralSubviewNamed:(CPString)relativeToViewName
+{
+ if (!_ephemeralSubviewsForNames)
+ {
+ _ephemeralSubviewsForNames = {};
+ _ephemeralSubviews = [CPSet set];
+ }
+
+ var frame = [self rectForEphemeralSubviewNamed:aViewName];
+
+ if (frame && !_CGRectIsEmpty(frame))
+ {
+ if (!_ephemeralSubviewsForNames[aViewName])
+ {
+ _ephemeralSubviewsForNames[aViewName] = [self createEphemeralSubviewNamed:aViewName];
+
+ [_ephemeralSubviews addObject:_ephemeralSubviewsForNames[aViewName]];
+
+ if (_ephemeralSubviewsForNames[aViewName])
+ [self addSubview:_ephemeralSubviewsForNames[aViewName] positioned:anOrderingMode relativeTo:_ephemeralSubviewsForNames[relativeToViewName]];
+ }
+
+ if (_ephemeralSubviewsForNames[aViewName])
+ [_ephemeralSubviewsForNames[aViewName] setFrame:frame];
+ }
+ else if (_ephemeralSubviewsForNames[aViewName])
+ {
+ [_ephemeralSubviewsForNames[aViewName] removeFromSuperview];
+
+ [_ephemeralSubviews removeObject:_ephemeralSubviewsForNames[aViewName]];
+ delete _ephemeralSubviewsForNames[aViewName];
+ }
+
+ return _ephemeralSubviewsForNames[aViewName];
+}
+
@end
var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
@@ -2234,6 +2293,10 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
_subviews = [aCoder decodeObjectForKey:CPViewSubviewsKey] || [];
_superview = [aCoder decodeObjectForKey:CPViewSuperviewKey];
+ // FIXME: Should we encode/decode this?
+ _registeredDraggedTypes = [CPSet set];
+ _registeredDraggedTypesArray = [];
+
_autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable;
_autoresizesSubviews = ![aCoder containsValueForKey:CPViewAutoresizesSubviewsKey] || [aCoder decodeBoolForKey:CPViewAutoresizesSubviewsKey];
@@ -2256,7 +2319,6 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
//_subviews[index]._superview = self;
}
#endif
- _displayHash = [self hash];
if ([aCoder containsValueForKey:CPViewIsHiddenKey])
[self setHidden:[aCoder decodeBoolForKey:CPViewIsHiddenKey]];
@@ -2270,6 +2332,8 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
[self setBackgroundColor:[aCoder decodeObjectForKey:CPViewBackgroundColorKey]];
+ [self setupViewFlags];
+
_theme = [CPTheme defaultTheme];
_themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
_themeAttributes = {};
@@ -2287,6 +2351,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
}
[self setNeedsDisplay:YES];
+ [self setNeedsLayout];
}
return self;
@@ -2310,8 +2375,20 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
if (_window !== nil)
[aCoder encodeConditionalObject:_window forKey:CPViewWindowKey];
- if (_subviews.length > 0)
- [aCoder encodeObject:_subviews forKey:CPViewSubviewsKey];
+ var count = [_subviews count],
+ encodedSubviews = _subviews;
+
+ if (count > 0 && [_ephemeralSubviews count] > 0)
+ {
+ encodedSubviews = [encodedSubviews copy];
+
+ while (count--)
+ if ([_ephemeralSubviews containsObject:encodedSubviews[count]])
+ encodedSubviews.splice(count, 1);
+ }
+
+ if (encodedSubviews.length > 0)
+ [aCoder encodeObject:encodedSubviews forKey:CPViewSubviewsKey];
// This will come out nil on the other side with decodeObjectForKey:
if (_superview !== nil)
@@ -2372,6 +2449,7 @@ var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView)
{
var view = fromView;
+ // FIXME: This doesn't handle the case when the outside views are equal.
// If we have a fromView, "climb up" the view tree until
// we hit the root node or we hit the toLayer.
while (view && view != toView)
diff --git a/AppKit/CPViewController.j b/AppKit/CPViewController.j
new file mode 100644
index 000000000..3529d29a3
--- /dev/null
+++ b/AppKit/CPViewController.j
@@ -0,0 +1,203 @@
+/*
+ * CPViewController.j
+ * AppKit
+ *
+ * Created by Nicholas Small and Francisco Tolmasky.
+ * Copyright 2009, 280 North, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+@import
+
+
+/*! @class CPViewController
+ The CPViewController class provides the fundamental view-management controller for Cappuccino applications.
+ The basic view controller class supports the presentation of an associated view in addition to basic support
+ for managing modal views and, in the future, animations. Subclasses such as CPNavigationController and
+ CPTabBarController provide additional behavior for managing complex hierarchies of view controllers and views.
+
+ You use each instance of CPViewController to manage a single view (and hierarchy). For a simple view controller,
+ this entails managing the view hierarchy responsible for presenting your application content.
+ A typical view hierarchy consists of a root viewÑa reference to which is available in the view property of this classÑ
+ and one or more subviews presenting the actual content. In the case of navigation and tab bar controllers, the view
+ controller manages not only the high-level view hierarchy (which provides the navigation controls) but also one
+ or more additional view controllers that handle the presentation of the application content.
+
+ Unlike UIViewController in Cocoa Touch, a CPViewController does not represent an entire screen of content. You
+ will add your root view to an existing view or window's content view. You can manage many view controllers
+ on screen at once. CPViewController is also the preferred way of working with Cibs.
+
+ Subclasses can override -loadView to create their custom view hierarchy, or specify a cib name to be loaded automatically.
+ It has methods that are called when a view appears or disappears.
+ This class is also a good place for delegate & datasource methods, and other controller stuff.
+*/
+@implementation CPViewController : CPResponder
+{
+ CPView _view;
+
+ id _representedObject @accessors(property=representedObject);
+ CPString _title @accessors(property=title);
+
+ CPString _cibName @accessors(property=cibName, readonly);
+ CPBundle _cibBundle @accessors(property=cibBundle, readonly);
+ CPDictionary _cibExternalNameTable @accessors(property=cibExternalNameTable, readonly);
+}
+
+/*!
+ Convenience initializer calls -initWithCibName:bundle: with nil for both parameters.
+*/
+- (id)init
+{
+ return [self initWithCibName:nil bundle:nil];
+}
+
+- (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil
+{
+ return [self initWithCibName:aCibNameOrNil bundle:aCibBundleOrNil externalNameTable:nil];
+}
+
+- (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil owner:(id)anOwner
+{
+ return [self initWithCibName:aCibNameOrNil bundle:aCibBundleOrNil externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
+}
+
+/*!
+ The designated initializer. If you subclass CPViewController, you must call the super implementation of this method, even if you aren't using a Cib.
+ In the specified Cib, the File's Owner proxy should have its class set to your view controller subclass, with the view outlet connected to the main view.
+ If you pass in a nil Cib name, then you must either call -setView: before -view is invoked, or override -loadView to set up your views.
+
+ @param cibNameOrNil The path to the cib to load for the root view or nil to programmatically create views.
+ @param cibBundleOrNil The bundle that the cib is located in or nil for the main bundle.
+*/
+- (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil externalNameTable:(CPDictionary)anExternalNameTable
+{
+ self = [super init];
+
+ if (self)
+ {
+ // Don't load the cib until someone actually requests the view. The user may just be intending to use setView:.
+ _cibName = aCibNameOrNil;
+ _cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
+ _cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
+ }
+
+ return self;
+}
+
+/*!
+ Programmatically creates the view that the controller manages.
+ You should never call this method directly. The view controller calls this method when the view property is requested but is nil.
+
+ If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
+ The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
+
+ If you use Interface Builder to create your views and initialize the view controllerÑthat is, you initialize the view using the
+ initWithCibName:bundle: methodÑthen you must not override this method. The consequences risk shattering the space-time continuum.
+
+ Note: The cib loading system is currently asynchronous.
+*/
+- (void)loadView
+{
+ if (_view)
+ return;
+
+// if (_cibName)
+// [CPException raise: reason:];
+
+ var cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]];
+
+ [cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
+}
+
+/*!
+ Returns the view that the controller manages.
+ If this property is nil, the controller sends loadView to itself to create the view that it manages.
+ Subclasses should override the loadView method to create any custom views. The default value is nil.
+
+ Note: An error will not be thrown if after -loadView, the view property is still nil. -view will simply return nil, but will continue to call -loadView on subsequent calls.
+*/
+- (CPView)view
+{
+ if (!_view)
+ {
+ var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
+
+ if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
+ [cibOwner viewControllerWillLoadCib:self];
+
+ [self loadView];
+
+ if (_view === nil && [cibOwner isKindOfClass:[CPDocument class]])
+ [self setView:[cibOwner valueForKey:@"view"]];
+
+ if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
+ [cibOwner viewControllerDidLoadCib:self];
+ }
+
+ return _view;
+}
+
+
+/*!
+ Manually sets the view that the controller manages.
+ Setting to nil will cause -loadView to be called on all subsequent calls of -view.
+
+ @param aView The view this controller should represent.
+*/
+- (void)setView:(CPView)aView
+{
+ _view = aView;
+}
+
+@end
+
+
+var CPViewControllerViewKey = @"CPViewControllerViewKey",
+ CPViewControllerTitleKey = @"CPViewControllerTitleKey";
+
+@implementation CPViewController (CPCoding)
+
+/*!
+ Initializes the view item by unarchiving data from a coder.
+ @param aCoder the coder from which the data will be unarchived
+ @return the initialized collection view item
+*/
+- (id)initWithCoder:(CPCoder)aCoder
+{
+ self = [super initWithCoder:aCoder];
+
+ if (self)
+ {
+ _view = [aCoder decodeObjectForKey:CPViewControllerViewKey];
+ _title = [aCoder decodeObjectForKey:CPViewControllerTitleKey];
+ }
+
+ return self;
+}
+
+/*!
+ Archives the colletion view item to the provided coder.
+ @param aCoder the coder to which the view item should be archived
+*/
+- (void)encodeWithCoder:(CPCoder)aCoder
+{
+ [super encodeWithCoder:aCoder];
+
+ [aCoder encodeObject:_view forKey:CPViewControllerViewKey];
+ [aCoder encodeObject:_title forKey:CPViewControllerTitleKey];
+}
+
+@end
diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j
index a2dd7d717..21202eb85 100644
--- a/AppKit/CPWindow/CPWindow.j
+++ b/AppKit/CPWindow/CPWindow.j
@@ -27,6 +27,8 @@
@import "CGGeometry.j"
@import "CPAnimation.j"
@import "CPResponder.j"
+@import "CPScreen.j"
+@import "CPPlatformWindow.j"
#include "../Platform/Platform.h"
#include "../Platform/DOM/CPDOMDisplayServer.h"
@@ -95,61 +97,61 @@ CPBackgroundWindowLevel = -1;
@group CPWindowLevel
@global
*/
-CPNormalWindowLevel = 4;
+CPNormalWindowLevel = 0;
/*
Floating palette type window
@group CPWindowLevel
@global
*/
-CPFloatingWindowLevel = 5;
+CPFloatingWindowLevel = 3;
/*
Submenu type window
@group CPWindowLevel
@global
*/
-CPSubmenuWindowLevel = 6;
+CPSubmenuWindowLevel = 3;
/*
For a torn-off menu
@group CPWindowLevel
@global
*/
-CPTornOffMenuWindowLevel = 6;
+CPTornOffMenuWindowLevel = 3;
/*
For the application's main menu
@group CPWindowLevel
@global
*/
-CPMainMenuWindowLevel = 8;
+CPMainMenuWindowLevel = 24;
/*
Status window level
@group CPWindowLevel
@global
*/
-CPStatusWindowLevel = 9;
+CPStatusWindowLevel = 25;
/*
Level for a modal panel
@group CPWindowLevel
@global
*/
-CPModalPanelWindowLevel = 10;
+CPModalPanelWindowLevel = 8;
/*
Level for a pop up menu
@group CPWindowLevel
@global
*/
-CPPopUpMenuWindowLevel = 11;
+CPPopUpMenuWindowLevel = 101;
/*
Level for a window being dragged
@group CPWindowLevel
@global
*/
-CPDraggingWindowLevel = 12;
+CPDraggingWindowLevel = 500;
/*
Level for the screens saver
@group CPWindowLevel
@global
*/
-CPScreenSaverWindowLevel = 13;
+CPScreenSaverWindowLevel = 1000;
/*
The receiver is removed from the screen list and hidden.
@@ -230,72 +232,77 @@ var CPWindowSaveImage = nil,
@delegate -(BOOL)windowShouldClose:(id)window;
Called when the user tries to close the window.
@param window the window to close
- @return YES allows the window to close. NO
+ @return \c YES allows the window to close. \c NO
vetoes the close operation and leaves the window open.
*/
@implementation CPWindow : CPResponder
{
- int _windowNumber;
- unsigned _styleMask;
- CGRect _frame;
- int _level;
- BOOL _isVisible;
- BOOL _isAnimating;
- BOOL _hasShadow;
- BOOL _isMovableByWindowBackground;
+ CPPlatformWindow _platformWindow;
- BOOL _isDocumentEdited;
- BOOL _isDocumentSaving;
+ int _windowNumber;
+ unsigned _styleMask;
+ CGRect _frame;
+ int _level;
+ BOOL _isVisible;
+ BOOL _isAnimating;
+ BOOL _hasShadow;
+ BOOL _isMovableByWindowBackground;
- CPImageView _shadowView;
+ BOOL _supportsMultipleDocuments;
+ BOOL _isDocumentEdited;
+ BOOL _isDocumentSaving;
- CPView _windowView;
- CPView _contentView;
- CPView _toolbarView;
+ CPImageView _shadowView;
- CPView _mouseOverView;
- CPView _leftMouseDownView;
- CPView _rightMouseDownView;
+ CPView _windowView;
+ CPView _contentView;
+ CPView _toolbarView;
- CPToolbar _toolbar;
- CPResponder _firstResponder;
- CPResponder _initialFirstResponder;
- id _delegate;
+ CPArray _mouseEnteredStack;
+ CPView _leftMouseDownView;
+ CPView _rightMouseDownView;
- CPString _title;
+ CPToolbar _toolbar;
+ CPResponder _firstResponder;
+ CPResponder _initialFirstResponder;
+ id _delegate;
- BOOL _acceptsMouseMovedEvents;
- BOOL _ignoresMouseEvents;
+ CPString _title;
- CPWindowController _windowController;
+ BOOL _acceptsMouseMovedEvents;
+ BOOL _ignoresMouseEvents;
- CGSize _minSize;
- CGSize _maxSize;
+ CPWindowController _windowController;
- CPUndoManager _undoManager;
- CPURL _representedURL;
+ CGSize _minSize;
+ CGSize _maxSize;
- CPSet _registeredDraggedTypes;
- CPArray _registeredDraggedTypesArray;
- CPCountedSet _inclusiveRegisteredDraggedTypes;
+ CPUndoManager _undoManager;
+ CPURL _representedURL;
- CPButton _defaultButton;
- BOOL _defaultButtonEnabled;
+ CPSet _registeredDraggedTypes;
+ CPArray _registeredDraggedTypesArray;
+ CPCountedSet _inclusiveRegisteredDraggedTypes;
- BOOL _autorecalculatesKeyViewLoop;
- BOOL _keyViewLoopIsDirty;
+ CPButton _defaultButton;
+ BOOL _defaultButtonEnabled;
+
+ BOOL _autorecalculatesKeyViewLoop;
+ BOOL _keyViewLoopIsDirty;
+
+ BOOL _sharesChromeWithPlatformWindow;
// Bridge Support
#if PLATFORM(DOM)
- DOMElement _DOMElement;
+ DOMElement _DOMElement;
#endif
- CPDOMWindowBridge _bridge;
- unsigned _autoresizingMask;
-
- BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector;
- BOOL _isFullBridge;
- _CPWindowFullBridgeSession _fullBridgeSession;
+ unsigned _autoresizingMask;
+
+ BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector;
+
+ BOOL _isFullPlatformWindow;
+ _CPWindowFullPlatformWindowSession _fullPlatformWindowSession;
}
/*
@@ -328,38 +335,26 @@ CPTexturedBackgroundWindowMask
@return the initialized window
*/
- (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask
-{
-#if PLATFORM(DOM)
- return [self initWithContentRect:aContentRect styleMask:aStyleMask bridge:[CPDOMWindowBridge sharedDOMWindowBridge]];
-#else
- return [self initWithContentRect:aContentRect styleMask:aStyleMask bridge:nil];
-#endif
-}
-
-/*!
- Initializes the window. The method also takes a style bit mask made up
- of any of the following values:
-
+ @param aDataSource the object with the table data
+ @throws CPInternalInconsistencyException if aDataSource doesn't implement all the required methods
+*/
+- (void)setDataSource:(id)aDataSource
+{
+ if (![aDataSource respondsToSelector:@selector(numberOfRowsInTableView:)])
+ [CPException raise:CPInternalInconsistencyException reason:"Data source doesn't support 'numberOfRowsInTableView:'"];
+ if (![aDataSource respondsToSelector:@selector(tableView:objectValueForTableColumn:row:)])
+ [CPException raise:CPInternalInconsistencyException reason:"Data source doesn't support 'tableView:objectValueForTableColumn:row:'"];
+
+ _dataSource = aDataSource;
+
+ [self reloadData];
+}
+
+/*
+ Returns the object that has access to the table data
+*/
+- (id)dataSource
+{
+ return _dataSource;
+}
+
+
+- (id)delegate
+{
+ return _delegate;
+}
+
+
+/*!
+ Sets the delegate for the tableview.
+*/
+- (void)setDelegate:(id)aDelegate
+{
+ if (_delegate === aDelegate)
+ return;
+
+ var notificationCenter = [CPNotificationCenter defaultCenter];
+
+ if ([_delegate respondsToSelector:@selector(tableViewColumnDidMove:)])
+ [notificationCenter removeObserver:_delegate name:CPTableViewColumnDidMoveNotification object:self];
+ if ([_delegate respondsToSelector:@selector(tableViewColumnDidResize:)])
+ [notificationCenter removeObserver:_delegate name:CPTableViewColumnDidResizeNotification object:self];
+ if ([_delegate respondsToSelector:@selector(tableViewSelectionDidChange:)])
+ [notificationCenter removeObserver:_delegate name:CPTableViewSelectionDidChangeNotification object:self];
+ if ([_delegate respondsToSelector:@selector(tableViewSelectionIsChanging:)])
+ [notificationCenter removeObserver:_delegate name:CPTableViewSelectionIsChangingNotification object:self];
+
+ _delegate = aDelegate;
+
+ if ([_delegate respondsToSelector:@selector(tableViewColumnDidMove:)])
+ [notificationCenter addObserver:_delegate selector:@selector(tableViewColumnDidMove:) name:CPTableViewColumnDidMoveNotification object:self];
+ if ([_delegate respondsToSelector:@selector(tableViewColumnDidResize:)])
+ [notificationCenter addObserver:_delegate selector:@selector(tableViewColumnDidResize:) name:CPTableViewColumnDidResizeNotification object:self];
+ if ([_delegate respondsToSelector:@selector(tableViewSelectionDidChange:)])
+ [notificationCenter addObserver:_delegate selector:@selector(tableViewSelectionDidChange:) name:CPTableViewSelectionDidChangeNotification object:self];
+ if ([_delegate respondsToSelector:@selector(tableViewSelectionIsChanging:)])
+ [notificationCenter addObserver:_delegate selector:@selector(tableViewSelectionIsChanging:) name:CPTableViewSelectionIsChangingNotification object:self];
+
+ _delegateSelectorsCache = 0;
+
+ if ([_delegate respondsToSelector:@selector(tableView:willDisplayCell:forTableColumn:row:)])
+ _delegateSelectorsCache |= _CPTableViewWillDisplayCellSelector;
+ if ([_delegate respondsToSelector:@selector(tableView:shouldSelectRow:)])
+ _delegateSelectorsCache |= _CPTableViewShouldSelectRowSelector;
+ if ([_delegate respondsToSelector:@selector(tableView:shouldSelectTableColumn:)])
+ _delegateSelectorsCache |= _CPTableViewShouldSelectTableColumnSelector;
+ if ([_delegate respondsToSelector:@selector(selectionShouldChangeInTableView:)])
+ _delegateSelectorsCache |= _CPTableViewSelectionShouldChangeSelector;
+ if ([_delegate respondsToSelector:@selector(tableView:shouldEditTableColumn:row:)])
+ _delegateSelectorsCache |= _CPTableViewShouldEditTableColumnSelector;
+ if ([_delegate respondsToSelector:@selector(tableView:selectionIndexesForProposedSelection:)])
+ _delegateSelectorsCache |= _CPTableViewSelectionIndexesForProposedSelectionSelector;
+ if ([_delegate respondsToSelector:@selector(tableView:heightOfRow:)])
+ {
+ _delegateSelectorsCache |= _CPTableViewHeightOfRowSelector;
+ _hasVariableHeightRows = YES;
+ }
+ else
+ _hasVariableHeightRows = NO;
+}
+
+
+/*
+ Tells the table view that the number of rows in the table
+ has changed.
+*/
+- (void)noteNumberOfRowsChanged
+{
+ var numberOfRows = [_dataSource numberOfRowsInTableView:self];
+
+ if (_numberOfRows != numberOfRows)
+ {
+ _numberOfRows = numberOfRows;
+
+ [self _recalculateColumnHeight];
+ }
+}
+
+- (void)noteHeightOfRowsWithIndexesChanged:(CPIndexSet)indexSet
+{
+ // FIXME: more efficient version is possible since we know which indexes changes
+ [self _recalculateColumnHeight];
+}
+
+/*
+ Returns the rectangle bounding the specified row.
+ @param aRowIndex the row to obtain a rectangle for
+ @return the bounding rectangle
+*/
+- (CGRect)rectOfRow:(int)aRowIndex
+{
+ return CPRectMake(0.0, ROW_MIN_Y(aRowIndex), CPRectGetWidth([self bounds]), ROW_HEIGHT(aRowIndex));
+}
+
+/*
+ Returns the rectangle bounding the specified column
+ @param aColumnIndex the column to obtain a rectangle for
+ @return the bounding column
+*/
+- (CGRect)rectOfColumn:(int)aColumnIndex
+{
+ return [_tableColumnViews[aColumnIndex] frame];
+}
+
+/*
+ Adjusts column widths to make them all visible at once. Same as tile.
+*/
+- (void)sizeToFit
+{
+// [self tile];
+}
+
+- (void)_recalculateColumnHeight
+{
+ var oldColumnHeight = _columnHeight;
+
+ if (_hasVariableHeightRows)
+ {
+ _rowMinYs[0] = 0;
+ for (var row = 0; row < _numberOfRows; row++)
+ {
+ _rowHeights[row] = [_delegate tableView:self heightOfRow:row];
+ _rowMinYs[row+1] = _rowMinYs[row] + _rowHeights[row] + _intercellSpacing.height;
+ }
+ _columnHeight = _rowMinYs[_numberOfRows]; // last index is one more than last row, and is the total column height
+ }
+ else
+ _columnHeight = _numberOfRows * (_rowHeight + _intercellSpacing.height);
+
+ var count = _tableColumnViews.length;
+
+ while (count--)
+ [_tableColumnViews[count] setFrameSize:CGSizeMake([_tableColumns[count] width], _columnHeight)];
+
+ [self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), _columnHeight)];
+}
+
+- (CGRect)visibleRectInParent
+{
+ var superview = [self superview];
+
+ if (!superview)
+ return [self bounds];
+
+ return [self convertRect:CGRectIntersection([superview bounds], [self frame]) fromView:superview];
+}
+
+/*
+ Reloads the data from the dataSource. This is an
+ expensive method, so use it lightly.
+*/
+- (void)reloadData
+{
+ var oldNumberOfRows = _numberOfRows;
+
+ _numberOfRows = [_dataSource numberOfRowsInTableView:self];
+
+ if (oldNumberOfRows != _numberOfRows)
+ {
+ [self _recalculateColumnHeight];
+ [self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), [self _columnHeight])];
+ }
+
+ _objectValueCache = [];
+
+ [self clearCells];
+
+ [self setNeedsLayout];
+}
+
+- (void)layoutSubviews
+{
+ [self loadTableCellsInRect:[self visibleRectInParent]];
+}
+
+- (void)displaySoon
+{
+ [_scrollTimer invalidate];
+ _scrollTimer = [CPTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(displayNow) userInfo:nil repeats:NO];
+}
+
+- (void)displayNow
+{
+ [self setNeedsLayout];
+}
+
+- (void)viewDidMoveToSuperview
+{
+ [[[self enclosingScrollView] contentView] setPostsBoundsChangedNotifications:YES];
+
+ [[CPNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(viewBoundsChanged:)
+ name:CPViewBoundsDidChangeNotification
+ object:[[self enclosingScrollView] contentView]];
+}
+
+- (void)viewBoundsChanged:(CPNotification)aNotification
+{
+ //CPLog.info(_cmd + CPStringFromRect([[[self enclosingScrollView] contentView] bounds]));
+ //objj_debug_print_backtrace();
+ //[self setNeedsLayout];
+ [self displayNow];
+}
+
+/*
+- (void)setAllowsColumnReordering:(BOOL)allowsColumnReordering
+{
+ if (_allowsColumnReordering === _allowsColumnReordering)
+ return;
+
+ _allowsColumnReordering = allowsColumnReordering;
+}
+- (void)allowsColumnReordering
+{
+ return _allowsColumnReordering;
+}
+
+- (void)setAllowsColumnResizing:(BOOL)allowsColumnResizing
+{
+ if (_allowsColumnResizing === allowsColumnResizing)
+ return;
+
+ _allowsColumnResizing = allowsColumnResizing;
+}
+- (void)allowsColumnResizing
+{
+ return _allowsColumnResizing;
+}
+
+- (void)setAllowsColumnSelection:(BOOL)allowsColumnSelection
+{
+ if (_allowsColumnSelection === allowsColumnSelection)
+ return;
+
+ _allowsColumnSelection = allowsColumnSelection;
+}
+- (void)allowsColumnSelection
+{
+ return _allowsColumnSelection;
+}
+*/
+
+- (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection
+{
+ if (_allowsMultipleSelection === allowsMultipleSelection)
+ return;
+
+ _allowsMultipleSelection = allowsMultipleSelection;
+
+ // TODO: more stuff?
+}
+- (void)allowsMultipleSelection
+{
+ return _allowsMultipleSelection;
+}
+
+- (void)setAllowsEmptySelection:(BOOL)allowsEmptySelection
+{
+ if (_allowsEmptySelection === allowsEmptySelection)
+ return;
+
+ _allowsEmptySelection = allowsEmptySelection;
+}
+- (void)allowsEmptySelection
+{
+ return _allowsEmptySelection;
+}
+
+
+/*
+ Returns the index of the row at the given point, or CPNotFound (-1) if it is out of range.
+ @param aPoint the point
+ @return the index of the row at aPoint
+*/
+- (int)rowAtPoint:(CGPoint)aPoint
+{
+ var index = [self _rowAtY:aPoint.y]
+
+ if (index >= 0 && index < _numberOfRows)
+ return index;
+ else
+ return CPNotFound;
+}
+
+- (int)columnAtPoint:(CGPoint)aPoint
+{
+ var index = [self _columnAtX:aPoint.x]
+
+ if (index >= 0 && index < _tableColumns.length)
+ return index;
+ else
+ return CPNotFound;
+}
+
+/*
+ @ignore
+
+ Internal version takes a Y value, returns an index, or -1 if its beyond the min, or numberOfRows if it's beyond the max
+*/
+- (int)_rowAtY:(float)y
+{
+ if (_hasVariableHeightRows)
+ {
+ var a = 0,
+ b = _numberOfRows;
+
+ if (y < _rowMinYs[0])
+ return -1;
+ if (y >= _rowMinYs[_rowMinYs.length-1])
+ return _numberOfRows;
+
+ // binary search
+ while (true)
+ {
+ var half = a + Math.floor((b - a) / 2);
+
+ if (y < _rowMinYs[half])
+ b = half;
+ else if (half < _numberOfRows-1 && y >= _rowMinYs[half+1])
+ a = half;
+ else
+ return half;
+ }
+ }
+ else
+ return FLOOR(y / (_rowHeight + _intercellSpacing.height));
+}
+
+/*
+ @ignore
+
+ Internal version takes a X value, returns an index, or -1 if its beyond the min, or numberOfColumns if it's beyond the max
+*/
+- (int)_columnAtX:(float)x
+{
+ var a = 0,
+ b = _tableColumns.length;
+
+ var last = [_tableColumnViews[_tableColumns.length-1] frame];
+ if (x < [_tableColumnViews[0] frame].origin.x)
+ return -1;
+ if (x >= last.origin.x + last.size.width)
+ return _tableColumns.length;
+
+ // binary search
+ while (true)
+ {
+ var half = a + Math.floor((b - a) / 2);
+
+ if (x < [_tableColumnViews[half] frame].origin.x)
+ b = half;
+ else if (half < _tableColumns.length-1 && x >= [_tableColumnViews[half+1] frame].origin.x)
+ a = half;
+ else
+ return half;
+ }
+}
+
+/*
+ Selects the specified row indexes, optionally adding to existing selection
+ @param indexes the indexes to select
+ @param extend whether or not to add to the existing selection
+*/
+- (void)selectRowIndexes:(CPIndexSet)indexes byExtendingSelection:(BOOL)extend
+{
+ // FIXME: should this be subject to the delegate filters, etc?
+
+ if (extend)
+ _selectedRowIndexes = [[_selectedRowIndexes copy] addIndexes:indexes];
+ else if ([indexes count] > 0 || _allowsEmptySelection)
+ _selectedRowIndexes = [indexes copy];
+
+ [self _drawSelection];
+}
+
+/*
+ Returns a CPIndexSet of the selected rows
+ @return indexes of the selected rows
+*/
+- (CPIndexSet)selectedRowIndexes
+{
+ return _selectedRowIndexes;
+}
+
+/*
+ Returns the number of selected rows
+ @return number of selected rows
+*/
+- (int)numberOfSelectedRows
+{
+ return [_selectedRowIndexes count];
+}
+
+
+/*
+ Deselects all rows if allowsEmptySelection is true. If delegate responds to "selectionShouldChangeInTableView:", asks if it should chnage.
+ Sends the CPTableViewSelectionDidChangeNotification on deselection.
+ @param the sender in a target/action
+*/
+- (void)deselectAll:(id)sender
+{
+ if (!_allowsEmptySelection || [_selectedRowIndexes count] === 0 ||
+ ((_delegateSelectorsCache & _CPTableViewSelectionShouldChangeSelector) && ![_delegate selectionShouldChangeInTableView:self]))
+ return;
+
+ [self selectRowIndexes:[CPIndexSet indexSet] byExtendingSelection:NO];
+ [[CPNotificationCenter defaultCenter] postNotificationName:CPTableViewSelectionDidChangeNotification object:self userInfo:nil];
+}
+
+- (void)editColumn:(int)columnIndex row:(int)rowIndex withEvent:(CPEvent)theEvent select:(BOOL)flag
+{
+
+}
+
+/*
+ @ignore
+*/
+- (void)_updateSelectionWithMouseAtRow:(int)aRow
+{
+ // Make a preliminary new selection
+ var newSelection;
+ if (_allowsMultipleSelection)
+ newSelection = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(MIN(aRow, _selectionStartRow), ABS(aRow-_selectionStartRow)+1)];
+ else if (aRow >= 0 && aRow < _numberOfRows)
+ newSelection = [CPIndexSet indexSetWithIndex:aRow];
+ else
+ newSelection = [CPIndexSet indexSet];
+
+ // If cmd/ctrl was held down XOR the old selection with the proposed selection
+ if (_allowsMultipleSelection && _selectionModifier & (CPCommandKeyMask | CPControlKeyMask | CPAlternateKeyMask))
+ {
+ // A = newSelection, B = _previousSelectedRowIndexes
+ // (A intersection B) = (A - (A - B))
+ var intersection = [newSelection copy],
+ difference = [newSelection copy];
+ [difference removeIndexes:_previousSelectedRowIndexes];
+ [intersection removeIndexes:difference]
+
+ // (A xor B) = (A + B) - (A intersection B)
+ [newSelection addIndexes:_previousSelectedRowIndexes];
+ [newSelection removeIndexes:intersection];
+
+ // FIXME: if multiple selection is off, and we cmd/ctrl click the previously selected row, then deselect it.
+ }
+
+ // if the new selection is different than the old selection
+ if (![newSelection isEqualToIndexSet:_selectedRowIndexes])
+ {
+ // ask the delegate if we should change the selection
+ if ((_delegateSelectorsCache & _CPTableViewSelectionShouldChangeSelector) && ![_delegate selectionShouldChangeInTableView:self])
+ return;
+
+ // ask the delegate which indexes can be selected. selectionIndexesForProposedSelection is faster than shouldSelectRow
+ if (_delegateSelectorsCache & _CPTableViewSelectionIndexesForProposedSelectionSelector)
+ newSelection = [_delegate tableView:self selectionIndexesForProposedSelection:newSelection];
+ else if (_delegateSelectorsCache & _CPTableViewShouldSelectRowSelector)
+ {
+ var indexes = [];
+ [newSelection getIndexes:indexes maxCount:Number.MAX_VALUE inIndexRange:nil];
+ for (var i = 0; i < indexes.length; i++)
+ if (![_delegate tableView:self shouldSelectRow:indexes[i]])
+ [newSelection removeIndex:indexes[i]];
+ }
+ }
+
+ // if empty selection is not allowed and the new selection has nothing selected, abort
+ if (!_allowsEmptySelection && [newSelection count] === 0)
+ return;
+
+ // if the new selection is *still* different, and update the selection and send a notification
+ if (![newSelection isEqualToIndexSet:_selectedRowIndexes])
+ {
+ [self selectRowIndexes:newSelection byExtendingSelection:NO];
+ [[CPNotificationCenter defaultCenter] postNotificationName:CPTableViewSelectionIsChangingNotification object:self userInfo:nil];
+ }
+}
+
+/*
+ @ignore
+*/
+- (void)mouseDown:(CPEvent)anEvent
+{
+ [self trackSelection:anEvent];
+}
+
+/*
+ Sets the message to be sent to the target when a cell is double clicked
+ @param aSelector the selector to be performed
+*/
+- (void)setDoubleAction:(SEL)aSelector
+{
+ _doubleAction = aSelector;
+}
+- (SEL)doubleAction
+{
+ return _doubleAction;
+}
+
+- (int)clickedColumn
+{
+ return _clickedColumn;
+}
+- (int)clickedRow
+{
+ return _clickedRow;
+}
+
+/*
+ @ignore
+*/
+- (void)trackSelection:(CPEvent)anEvent
+{
+ var type = [anEvent type],
+ point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
+ currentRow = MAX(0, MIN(_numberOfRows-1, [self _rowAtY:point.y]));
+
+ if (type == CPLeftMouseUp)
+ {
+ _clickedRow = [self rowAtPoint:point];
+ _clickedColumn = [self columnAtPoint:point];
+
+ if ([anEvent clickCount] === 2)
+ {
+ CPLog.warn("edit?!");
+
+ [self sendAction:_doubleAction to:_target];
+ }
+ else
+ {
+ if (![_previousSelectedRowIndexes isEqualToIndexSet:_selectedRowIndexes])
+ {
+ [[CPNotificationCenter defaultCenter] postNotificationName:CPTableViewSelectionDidChangeNotification object:self userInfo:nil];
+ }
+
+ [self sendAction:_action to:_target];
+ }
+
+ return;
+ }
+
+ if (type == CPLeftMouseDown)
+ {
+ _previousSelectedRowIndexes = _selectedRowIndexes;
+ _selectionModifier = [anEvent modifierFlags];
+
+ if (_selectionModifier & CPShiftKeyMask)
+ _selectionStartRow = (ABS([_previousSelectedRowIndexes firstIndex] - currentRow) < ABS([_previousSelectedRowIndexes lastIndex] - currentRow)) ?
+ [_previousSelectedRowIndexes firstIndex] : [_previousSelectedRowIndexes lastIndex];
+ else
+ _selectionStartRow = currentRow;
+
+ [self _updateSelectionWithMouseAtRow:currentRow];
+ }
+ else if (type == CPLeftMouseDragged)
+ {
+ [self _updateSelectionWithMouseAtRow:currentRow];
+ }
+
+ [CPApp setTarget:self selector:@selector(trackSelection:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
+}
+
+/*
+ @ignore
+*/
+- (void)_drawSelection
+{
+ if (!_currentlySelected) {
+ _currentlySelected = [CPIndexSet indexSet];
+ _selectionViews = [];
+ _selectionViewsPool = [];
+ }
+
+ // TODO: we could also remove selections that aren't visible, but then we'll need to run this on every scroll/resize?
+
+ // get array of indexes we can remove
+ var removeSet = [_currentlySelected copy],
+ indexesToRemove = [];
+ [removeSet removeIndexes:_selectedRowIndexes];
+ [removeSet getIndexes:indexesToRemove maxCount:Number.MAX_VALUE inIndexRange:nil];
+
+ // get array of indexes we need to add
+ var addSet = [_selectedRowIndexes copy],
+ indexesToAdd = [];
+ [addSet removeIndexes:_currentlySelected];
+ [addSet getIndexes:indexesToAdd maxCount:Number.MAX_VALUE inIndexRange:nil];
+
+ for (var i = 0; i < indexesToRemove.length; i++)
+ {
+ var row = indexesToRemove[i];
+ for (var column = 0; column < _tableColumns.length; column++)
+ if ([_tableCells[column][row] respondsToSelector:@selector(highlight:)])
+ [_tableCells[column][row] highlight:NO];
+ }
+ for (var i = 0; i < indexesToAdd.length; i++)
+ {
+ var row = indexesToAdd[i];
+ for (var column = 0; column < _tableColumns.length; column++)
+ if ([_tableCells[column][row] respondsToSelector:@selector(highlight:)])
+ [_tableCells[column][row] highlight:YES];
+ }
+
+ // add each one we need to add, taking the selection views from removed seelctions, the pool, or new
+ for (var i = 0; i < indexesToAdd.length; i++)
+ {
+ var index = indexesToAdd[i],
+ view;
+
+ if (indexesToRemove.length > 0)
+ {
+ view = _selectionViews[indexesToRemove.pop()];
+ }
+ else if (_selectionViewsPool.length > 0)
+ {
+ view = _selectionViewsPool.pop();
+ [self addSubview:view positioned:CPWindowBelow relativeTo:nil];
+ }
+ else
+ {
+ view = [[CPView alloc] init];
+ [view setBackgroundColor:[CPColor alternateSelectedControlColor]];
+
+ [self addSubview:view positioned:CPWindowBelow relativeTo:nil];
+ }
+
+ _selectionViews[index] = view;
+
+ var frame = [self rectOfRow:index];
+ frame.size.height += _intercellSpacing.height - 1;
+ //frame.size.width += 500;
+
+ [view setFrame:frame];
+ }
+
+ // remove any selections that weren't already reused
+ for (var i = 0; i < indexesToRemove.length; i++)
+ {
+ var row = indexesToRemove[i],
+ view = _selectionViews[row];
+
+ [view removeFromSuperview];
+ _selectionViewsPool.push(view);
+ }
+
+ // update the currently selected index set
+ _currentlySelected = [_selectedRowIndexes copy];
+}
+
+@end
+
+
+var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
+ CPTableViewDelegateKey = @"CPTableViewDelegateKey",
+ CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey",
+ CPTableViewTableColumnsKey = @"CPTableViewTableColumnsKey",
+ CPTableViewRowHeightKey = @"CPTableViewRowHeightKey",
+ CPTableViewIntercellSpacingKey = @"CPTableViewIntercellSpacingKey",
+ CPTableViewMultipleSelectionKey = @"CPTableViewMultipleSelectionKey",
+ CPTableViewEmptySelectionKey = @"CPTableViewEmptySelectionKey";
+
+@implementation CPTableView (CPCoding)
+
+- (id)initWithCoder:(CPCoder)aCoder
+{
+ if (self = [super initWithCoder:aCoder])
+ {
+ [self _init];
+
+ _dataSource = [aCoder decodeObjectForKey:CPTableViewDataSourceKey];
+ _delegate = [aCoder decodeObjectForKey:CPTableViewDelegateKey];
+
+ _rowHeight = [aCoder decodeFloatForKey:CPTableViewRowHeightKey];
+ _intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey];
+
+ _allowsMultipleSelection = [aCoder decodeBoolForKey:CPTableViewMultipleSelectionKey];
+ _allowsEmptySelection = [aCoder decodeBoolForKey:CPTableViewEmptySelectionKey];
+
+ var tableColumns = [aCoder decodeObjectForKey:CPTableViewTableColumnsKey];
+ for (var i = 0; i < tableColumns.length; i++)
+ [self addTableColumn:tableColumns[i]];
+ }
+
+ return self;
+}
+
+- (void)encodeWithCoder:(CPCoder)aCoder
+{
+ [super encodeWithCoder:aCoder];
+
+ [aCoder encodeObject:_dataSource forKey:CPTableViewDataSourceKey];
+ [aCoder encodeObject:_delegate forKey:CPTableViewDelegateKey];
+
+ [aCoder encodeObject:_tableColumns forKey:CPTableViewTableColumnsKey];
+
+ [aCoder encodeFloat:_rowHeight forKey:CPTableViewRowHeightKey];
+ [aCoder encodeSize:_intercellSpacing forKey:CPTableViewIntercellSpacingKey];
+
+ [aCoder encodeBool:_allowsMultipleSelection forKey:CPTableViewMultipleSelectionKey];
+ [aCoder encodeBool:_allowsEmptySelection forKey:CPTableViewEmptySelectionKey];
+}
+
+@end
+
+
+
+@implementation CPColor (TableView)
+
++ (CPColor)alternateSelectedControlColor
+{
+ return [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]];
+}
+
++ (CPColor)secondarySelectedControlColor
+{
+ return [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]];
+}
+
+@end
diff --git a/AppKit/Platform/CPPlatform.j b/AppKit/Platform/CPPlatform.j
new file mode 100644
index 000000000..851e538bc
--- /dev/null
+++ b/AppKit/Platform/CPPlatform.j
@@ -0,0 +1,48 @@
+
+@import
+
+#include "Platform.h"
+
+
+@implementation CPPlatform : CPObject
+{
+}
+
++ (void)bootstrap
+{
+#if PLATFORM(DOM)
+ var body = document.getElementsByTagName("body")[0];
+
+ body.innerHTML = ""; // Get rid of anything that might be lingering in the body element.
+ body.style.overflow = "hidden";
+
+ if (document.documentElement)
+ document.documentElement.style.overflow = "hidden";
+#endif
+
+ [CPPlatformString bootstrap];
+ [CPPlatformWindow setPrimaryPlatformWindow:[[CPPlatformWindow alloc] _init]];
+}
+
++ (BOOL)isBrowser
+{
+ return typeof window.cpIsDesktop === "undefined";
+}
+
++ (BOOL)supportsDragAndDrop
+{
+ return CPFeatureIsCompatible(CPHTMLDragAndDropFeature);
+}
+
++ (BOOL)supportsNativeMainMenu
+{
+ return (typeof window["cpSetMainMenu"] === "function");
+}
+
++ (void)terminateApplication
+{
+ if (typeof window["cpTerminate"] === "function")
+ window.cpTerminate();
+}
+
+@end
diff --git a/AppKit/Platform/CPPlatformString.j b/AppKit/Platform/CPPlatformString.j
new file mode 100644
index 000000000..24e91d152
--- /dev/null
+++ b/AppKit/Platform/CPPlatformString.j
@@ -0,0 +1,104 @@
+
+
+@import
+
+#include "../CoreGraphics/CGGeometry.h"
+#include "Platform.h"
+
+
+#if PLATFORM(DOM)
+var DOMIFrameElement = nil,
+ DOMSpanElement = nil,
+ DefaultFont = nil;
+#endif
+
+@implementation CPPlatformString : CPObject
+{
+}
+
++ (void)bootstrap
+{
+#if PLATFORM(DOM)
+ DOMIFrameElement = document.createElement("iframe");
+
+ DOMIFrameElement.name = name = "iframe_" + FLOOR(RAND() * 10000);
+ DOMIFrameElement.style.position = "absolute";
+ DOMIFrameElement.style.left = "-100px";
+ DOMIFrameElement.style.top = "-100px";
+ DOMIFrameElement.style.width = "1px";
+ DOMIFrameElement.style.height = "1px";
+ DOMIFrameElement.style.borderWidth = "0px";
+ DOMIFrameElement.style.background = "blue";
+ DOMIFrameElement.style.overflow = "hidden";
+ DOMIFrameElement.style.zIndex = 100000000000;
+
+ document.getElementsByTagName("body")[0].appendChild(DOMIFrameElement);
+
+ var DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
+
+ DOMIFrameDocument.write("");
+ DOMIFrameDocument.close();
+
+ DOMSpanElement = DOMIFrameDocument.createElement("span");
+
+ DOMSpanElement.style.position = "absolute";
+ DOMSpanElement.style.whiteSpace = "pre";
+ DOMSpanElement.style.visibility = "visible";
+ DOMSpanElement.style.padding = "0px";
+ DOMSpanElement.style.margin = "0px";
+ DOMSpanElement.style.background = "red";
+
+ DOMIFrameDocument.getElementsByTagName("body")[0].appendChild(DOMSpanElement);
+#endif
+}
+
++ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
+{
+#if PLATFORM(DOM)
+ if (!aFont)
+ {
+ if (!DefaultFont)
+ DefaultFont = [CPFont systemFontOfSize:12.0];
+
+ aFont = DefaultFont;
+ }
+
+ var style = DOMSpanElement.style;
+
+ if (aWidth === NULL)
+ {
+ style.width = "";
+ style.whiteSpace = "pre";
+ }
+
+ else
+ {
+ style.width = ROUND(aWidth) + "px";
+
+ if (document.attachEvent)
+ style.wordWrap = "break-word";
+
+ else
+ {
+ style.whiteSpace = "-o-pre-wrap";
+ style.whiteSpace = "-pre-wrap";
+ style.whiteSpace = "-moz-pre-wrap";
+ style.whiteSpace = "pre-wrap";
+ }
+ }
+
+ style.font = [aFont cssString];
+
+ if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
+ DOMSpanElement.innerText = aString;
+
+ else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
+ DOMSpanElement.textContent = aString;
+
+ return _CGSizeMake(DOMSpanElement.clientWidth, DOMSpanElement.clientHeight);
+#else
+ return _CGSizeMakeZero();
+#endif
+}
+
+@end
diff --git a/AppKit/Platform/CPPlatformWindow.j b/AppKit/Platform/CPPlatformWindow.j
new file mode 100644
index 000000000..e11f598cc
--- /dev/null
+++ b/AppKit/Platform/CPPlatformWindow.j
@@ -0,0 +1,181 @@
+
+@import
+
+#import "Platform.h"
+#import "../CoreGraphics/CGGeometry.h"
+
+
+var PrimaryPlatformWindow = NULL;
+
+@implementation CPPlatformWindow : CPObject
+{
+ CGRect _contentRect;
+
+ CPInteger _level;
+ BOOL _hasShadow;
+
+#if PLATFORM(DOM)
+ DOMWindow _DOMWindow;
+
+ DOMElement _DOMBodyElement;
+ DOMElement _DOMFocusElement;
+
+ CPArray _windowLevels;
+ CPDictionary _windowLayers;
+
+ BOOL _mouseIsDown;
+ CPWindow _mouseDownWindow;
+ CPTimeInterval _lastMouseUp;
+ CPTimeInterval _lastMouseDown;
+
+ Object _charCodes;
+ unsigned _keyCode;
+
+ BOOL _DOMEventMode;
+
+ // Native Pasteboard Support
+ DOMElement _DOMPasteboardElement;
+ CPEvent _pasteboardKeyDownEvent;
+
+ CPString _overriddenEventType;
+#endif
+}
+
++ (CPPlatformWindow)primaryPlatformWindow
+{
+ return PrimaryPlatformWindow;
+}
+
++ (void)setPrimaryPlatformWindow:(CPPlatformWindow)aPlatformWindow
+{
+ PrimaryPlatformWindow = aPlatformWindow;
+}
+
+- (id)initWithContentRect:(CGRect)aRect
+{
+ self = [super init];
+
+ if (self)
+ {
+ _contentRect = _CGRectMakeCopy(aRect);
+
+#if PLATFORM(DOM)
+ _windowLevels = [];
+ _windowLayers = [CPDictionary dictionary];
+
+ _charCodes = {};
+#endif
+ }
+
+ return self;
+}
+
+- (id)init
+{
+ return [self initWithContentRect:_CGRectMake(0.0, 0.0, 400.0, 500.0)];
+}
+
+- (CGRect)contentRect
+{
+ return _CGRectMakeCopy(_contentRect);
+}
+
+- (CGRect)contentBounds
+{
+ var contentBounds = [self contentRect];
+
+ contentBounds.origin = _CGPointMakeZero();
+
+ return contentBounds;
+}
+
+- (CGRect)visibleFrame
+{
+ var frame = [self contentBounds];
+
+ frame.origin = CGPointMakeZero();
+
+ if ([CPMenu menuBarVisible])
+ {
+ var menuBarHeight = [[CPApp mainMenu] menuBarHeight];
+
+ frame.origin.y += menuBarHeight;
+ frame.size.height -= menuBarHeight;
+ }
+
+ return frame;
+}
+
+- (void)usableContentFrame
+{
+ return [self visibleFrame];
+}
+
+- (void)setContentRect:(CGRect)aRect
+{
+ if (!aRect || _CGRectEqualToRect(_contentRect, aRect))
+ return;
+
+ _contentRect = _CGRectMakeCopy(aRect);
+
+ [self updateNativeContentRect];
+}
+
+- (void)updateFromNativeContentRect
+{
+ [self setContentRect:[self nativeContentRect]];
+}
+
+- (CGPoint)convertBaseToScreen:(CGPoint)aPoint
+{
+ var contentRect = [self contentRect];
+
+ return _CGPointMake(aPoint.x + _CGRectGetMinX(contentRect), aPoint.y + _CGRectGetMinY(contentRect));
+}
+
+- (CGPoint)convertScreenToBase:(CGPoint)aPoint
+{
+ var contentRect = [self contentRect];
+
+ return _CGPointMake(aPoint.x - _CGRectGetMinX(contentRect), aPoint.y - _CGRectGetMinY(contentRect));
+}
+
+- (BOOL)isVisible
+{
+#if PLATFORM(DOM)
+ return _DOMWindow !== NULL;
+#else
+ return NO;
+#endif
+}
+
+- (void)setLevel:(CPInteger)aLevel
+{
+ _level = aLevel;
+
+#if PLATFORM(DOM)
+ if (_DOMWindow && _DOMWindow.cpSetLevel)
+ _DOMWindow.cpSetLevel(aLevel);
+#endif
+}
+
+- (void)setHasShadow:(BOOL)shouldHaveShadow
+{
+ _hasShadow = shouldHaveShadow;
+
+#if PLATFORM(DOM)
+ if (_DOMWindow && _DOMWindow.cpSetHasShadow)
+ _DOMWindow.cpSetHasShadow(shouldHaveShadow);
+#endif
+}
+
+- (BOOL)supportsFullPlatformWindows
+{
+ return [CPPlatform isBrowser];
+}
+
+@end
+
+#if PLATFORM(BROWSER)
+@import "CPPlatformWindow+DOM.j"
+#endif
diff --git a/AppKit/Platform/DOM/CPDOMDisplayServer.h b/AppKit/Platform/DOM/CPDOMDisplayServer.h
index 9216ab901..34e3ba838 100644
--- a/AppKit/Platform/DOM/CPDOMDisplayServer.h
+++ b/AppKit/Platform/DOM/CPDOMDisplayServer.h
@@ -20,6 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#define DOM_OPTIMIZATION 0
+
#define SetStyleOrigin 0
#define SetStyleLeftTop 0
#define SetStyleRightTop 1
@@ -45,7 +47,49 @@
CPDOMDisplayServerInstructions[__index + 2] = aTransform;\
CPDOMDisplayServerInstructions[__index + 3] = x;\
CPDOMDisplayServerInstructions[__index + 4] = y;
-
+#if !DOM_OPTIMIZATION
+#define CPDOMDisplayServerSetStyleLeftTop(aDOMElement, aTransform, aLeft, aTop) \
+if (aTransform) var ____p = _CGPointApplyAffineTransform(CGPointMake(aLeft, aTop), aTransform); \
+else var ____p = _CGPointMake(aLeft, aTop); \
+aDOMElement.style.left = ROUND(____p.x) + "px";\
+aDOMElement.style.top = ROUND(____p.y) + "px";
+
+#define CPDOMDisplayServerSetStyleRightTop(aDOMElement, aTransform, aRight, aTop) \
+if (aTransform) var ____p = _CGPointApplyAffineTransform(CGPointMake(aRight, aTop), aTransform); \
+else var ____p = _CGPointMake(aRight, aTop); \
+aDOMElement.style.right = ROUND(____p.x) + "px";\
+aDOMElement.style.top = ROUND(____p.y) + "px";
+
+#define CPDOMDisplayServerSetStyleLeftBottom(aDOMElement, aTransform, aLeft, aBottom) \
+if (aTransform) var ____p = _CGPointApplyAffineTransform(CGPointMake(aLeft, aBottom), aTransform); \
+else var ____p = _CGPointMake(aLeft, aBottom); \
+aDOMElement.style.left = ROUND(____p.x) + "px";\
+aDOMElement.style.bottom = ROUND(____p.y) + "px";
+
+#define CPDOMDisplayServerSetStyleRightBottom(aDOMElement, aTransform, aRight, aBottom) \
+if (aTransform) var ____p = _CGPointApplyAffineTransform(CGPointMake(aRight, aBottom), aTransform); \
+else var ____p = _CGPointMake(aRight, aBottom); \
+aDOMElement.style.right = ROUND(____p.x) + "px";\
+aDOMElement.style.bottom = ROUND(____p.y) + "px";
+
+#define CPDOMDisplayServerSetStyleSize(aDOMElement, aWidth, aHeight) \
+ aDOMElement.style.width = MAX(0.0, ROUND(aWidth)) + "px";\
+ aDOMElement.style.height = MAX(0.0, ROUND(aHeight)) + "px";
+
+#define CPDOMDisplayServerSetSize(aDOMElement, aWidth, aHeight) \
+ aDOMElement.width = MAX(0.0, ROUND(aWidth));\
+ aDOMElement.height = MAX(0.0, ROUND(aHeight));
+
+#define CPDOMDisplayServerAppendChild(aParentElement, aChildElement) aParentElement.appendChild(aChildElement)
+
+#define CPDOMDisplayServerInsertBefore(aParentElement, aChildElement, aBeforeElement) aParentElement.insertBefore(aChildElement, aBeforeElement)
+
+#define CPDOMDisplayServerRemoveChild(aParentElement, aChildElement) aParentElement.removeChild(aChildElement)
+
+#define PREPARE_DOM_OPTIMIZATION()
+#define EXECUTE_DOM_INSTRUCTIONS()
+
+#else
#define CPDOMDisplayServerSetStyleLeftTop(aDOMElement, aTransform, aLeft, aTop) CPDOMDisplayServerSetStyleOrigin(SetStyleLeftTop, aDOMElement, aTransform, aLeft, aTop)
#define CPDOMDisplayServerSetStyleRightTop(aDOMElement, aTransform, aRight, aTop) CPDOMDisplayServerSetStyleOrigin(SetStyleRightTop, aDOMElement, aTransform, aRight, aTop)
@@ -99,27 +143,70 @@
CPDOMDisplayServerInstructions[CPDOMDisplayServerInstructionCount++] = RemoveChild;\
CPDOMDisplayServerInstructions[CPDOMDisplayServerInstructionCount++] = aParentElement;\
CPDOMDisplayServerInstructions[CPDOMDisplayServerInstructionCount++] = aChildElement;
-
-//#dfeine CPDOMDisplayServerCustomAction()
-#define CPDOMDisplayServerAddView(aView)\
+#define PREPARE_DOM_OPTIMIZATION()\
+CPDOMDisplayServerInstructions = [];\
+CPDOMDisplayServerInstructionCount = 0;
+#define EXECUTE_DOM_INSTRUCTIONS()\
+ var index = 0;\
+ while (index < CPDOMDisplayServerInstructionCount)\
{\
- var ___hash = [aView hash];\
- if (typeof (CPDOMDisplayServerViewsContext[___hash]) == "undefined")\
- {\
- CPDOMDisplayServerViews[CPDOMDisplayServerViewsCount++] = aView;\
- CPDOMDisplayServerViewsContext[___hash] = aView;\
+ var instruction = CPDOMDisplayServerInstructions[index++];\
+ try{\
+ switch (instruction)\
+ {\
+ case SetStyleLeftTop:\
+ case SetStyleRightTop:\
+ case SetStyleLeftBottom:\
+ case SetStyleRightBottom: var element = CPDOMDisplayServerInstructions[index],\
+ style = element.style,\
+ x = (instruction == SetStyleLeftTop || instruction == SetStyleLeftBottom) ? "left" : "right",\
+ y = (instruction == SetStyleLeftTop || instruction == SetStyleRightTop) ? "top" : "bottom";\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ var transform = CPDOMDisplayServerInstructions[index++];\
+ if (transform)\
+ {\
+ var point = _CGPointMake(CPDOMDisplayServerInstructions[index++], CPDOMDisplayServerInstructions[index++]),\
+ transformed = _CGPointApplyAffineTransform(point, transform);\
+ style[x] = ROUND(transformed.x) + "px";\
+ style[y] = ROUND(transformed.y) + "px";\
+ }\
+ else\
+ {\
+ style[x] = ROUND(CPDOMDisplayServerInstructions[index++]) + "px";\
+ style[y] = ROUND(CPDOMDisplayServerInstructions[index++]) + "px";\
+ }\
+ element.CPDOMDisplayContext[SetStyleOrigin] = -1;\
+ break;\
+ case SetStyleSize: var element = CPDOMDisplayServerInstructions[index],\
+ style = element.style;\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ element.CPDOMDisplayContext[SetStyleSize] = -1;\
+ style.width = MAX(0.0, ROUND(CPDOMDisplayServerInstructions[index++])) + "px";\
+ style.height = MAX(0.0, ROUND(CPDOMDisplayServerInstructions[index++])) + "px";\
+ break;\
+ case SetSize: var element = CPDOMDisplayServerInstructions[index];\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ element.CPDOMDisplayContext[SetSize] = -1;\
+ element.width = MAX(0.0, ROUND(CPDOMDisplayServerInstructions[index++]));\
+ element.height = MAX(0.0, ROUND(CPDOMDisplayServerInstructions[index++]));\
+ break;\
+ case AppendChild: CPDOMDisplayServerInstructions[index].appendChild(CPDOMDisplayServerInstructions[index + 1]);\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ break;\
+ case InsertBefore: CPDOMDisplayServerInstructions[index].insertBefore(CPDOMDisplayServerInstructions[index + 1], CPDOMDisplayServerInstructions[index + 2]);\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ break;\
+ case RemoveChild: CPDOMDisplayServerInstructions[index].removeChild(CPDOMDisplayServerInstructions[index + 1]);\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ CPDOMDisplayServerInstructions[index++] = nil;\
+ break;\
+ }\
+ }\
+ catch(e) { CPLog("e " + e + " " + instruction); }\
}\
- }\
-
-#define CPDOMDisplayServerRemoveView(aView)\
- {\
- var index = CPDOMDisplayServerViewsContext[[aView hash]];\
- if (typeof index != "undefined") \
- {\
- CPDOMDisplayServerViewsContext[[aView hash]];\
- CPDOMDisplayServerViews[index] = NULL;\
- }\
- }\
-
-
\ No newline at end of file
+ CPDOMDisplayServerInstructionCount = 0;
+#endif
diff --git a/AppKit/Platform/DOM/CPDOMDisplayServer.j b/AppKit/Platform/DOM/CPDOMDisplayServer.j
deleted file mode 100644
index 2c77e40e3..000000000
--- a/AppKit/Platform/DOM/CPDOMDisplayServer.j
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * CPDOMDisplayServer.j
- * AppKit
- *
- * Created by Francisco Tolmasky.
- * Copyright 2008, 280 North, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-@import
-
-#include "../../CoreGraphics/CGAffineTransform.h"
-#include "CPDOMDisplayServer.h"
-
-
-var CPDOMDisplayRunLoop = nil;
-
-CPDOMDisplayServerInstructions = [];
-CPDOMDisplayServerInstructionCount = 0;
-
-CPDOMDisplayServerViews = [];
-CPDOMDisplayServerViewsCount = 0;
-CPDOMDisplayServerViewsContext = {};
-
-@implementation CPDOMDisplayServer : CPObject
-{
-}
-
-+ (void)start
-{
- CPDOMDisplayRunLoop = [CPRunLoop currentRunLoop];
-
- [CPDOMDisplayRunLoop performSelector:@selector(run) target:CPDOMDisplayServer argument:nil order:0 modes:[CPDefaultRunLoopMode]];
-}
-
-+ (void)run
-{
- while (CPDOMDisplayServerInstructionCount || CPDOMDisplayServerViewsCount)
- {
- var index = 0;
-
- while (index < CPDOMDisplayServerInstructionCount)
- {
- var instruction = CPDOMDisplayServerInstructions[index++];
- try{
- switch (instruction)
- {
- case SetStyleLeftTop:
- case SetStyleRightTop:
- case SetStyleLeftBottom:
- case SetStyleRightBottom: var element = CPDOMDisplayServerInstructions[index],
- style = element.style,
- x = (instruction == SetStyleLeftTop || instruction == SetStyleLeftBottom) ? "left" : "right",
- y = (instruction == SetStyleLeftTop || instruction == SetStyleRightTop) ? "top" : "bottom";
-
- CPDOMDisplayServerInstructions[index++] = nil;
-
- var transform = CPDOMDisplayServerInstructions[index++];
-
- if (transform)
- {
- var point = _CGPointMake(CPDOMDisplayServerInstructions[index++], CPDOMDisplayServerInstructions[index++]),
- transformed = _CGPointApplyAffineTransform(point, transform);
-
- style[x] = ROUND(transformed.x) + "px";
- style[y] = ROUND(transformed.y) + "px";
-
- }
- else
- {
- style[x] = ROUND(CPDOMDisplayServerInstructions[index++]) + "px";
- style[y] = ROUND(CPDOMDisplayServerInstructions[index++]) + "px";
- }
-
- element.CPDOMDisplayContext[SetStyleOrigin] = -1;
-
- break;
-
- case SetStyleSize: var element = CPDOMDisplayServerInstructions[index],
- style = element.style;
-
- CPDOMDisplayServerInstructions[index++] = nil;
-
- element.CPDOMDisplayContext[SetStyleSize] = -1;
-
- style.width = MAX(0.0, ROUND(CPDOMDisplayServerInstructions[index++])) + "px";
- style.height = MAX(0.0, ROUND(CPDOMDisplayServerInstructions[index++])) + "px";
-
- break;
-
- case SetSize: var element = CPDOMDisplayServerInstructions[index];
-
- CPDOMDisplayServerInstructions[index++] = nil;
-
- element.CPDOMDisplayContext[SetSize] = -1;
-
- element.width = MAX(0.0, ROUND(CPDOMDisplayServerInstructions[index++]));
- element.height = MAX(0.0, ROUND(CPDOMDisplayServerInstructions[index++]));
-
- break;
-
- case AppendChild: CPDOMDisplayServerInstructions[index].appendChild(CPDOMDisplayServerInstructions[index + 1]);
-
- CPDOMDisplayServerInstructions[index++] = nil;
- CPDOMDisplayServerInstructions[index++] = nil;
-
- break;
-
- case InsertBefore: CPDOMDisplayServerInstructions[index].insertBefore(CPDOMDisplayServerInstructions[index + 1], CPDOMDisplayServerInstructions[index + 2]);
-
- CPDOMDisplayServerInstructions[index++] = nil;
- CPDOMDisplayServerInstructions[index++] = nil;
- CPDOMDisplayServerInstructions[index++] = nil;
-
- break;
-
- case RemoveChild: CPDOMDisplayServerInstructions[index].removeChild(CPDOMDisplayServerInstructions[index + 1]);
-
- CPDOMDisplayServerInstructions[index++] = nil;
- CPDOMDisplayServerInstructions[index++] = nil;
-
- break;
- }}catch(e) { CPLog("here?" + instruction) }
- }
-
- CPDOMDisplayServerInstructionCount = 0;
-
- var views = CPDOMDisplayServerViews,
- index = 0,
- count = CPDOMDisplayServerViewsCount;
-
- // We don't reset CPDOMDisplayServerViewsContext because it can serve for displays that are coming...
- CPDOMDisplayServerViews = [];
- CPDOMDisplayServerViewsCount = 0;
-
- for (; index < count; ++index)
- {
- var view = views[index];
-
- delete CPDOMDisplayServerViewsContext[[view hash]];
-
- [view layoutIfNeeded];
- [view displayIfNeeded];
- }
- }
-
- [CPDOMDisplayRunLoop performSelector:@selector(run) target:CPDOMDisplayServer argument:nil order:0 modes:[CPDefaultRunLoopMode]];
-}
-
-@end
-
-[CPDOMDisplayServer start];
diff --git a/AppKit/Platform/DOM/CPDOMWindowBridge.j b/AppKit/Platform/DOM/CPDOMWindowBridge.j
deleted file mode 100644
index e86944001..000000000
--- a/AppKit/Platform/DOM/CPDOMWindowBridge.j
+++ /dev/null
@@ -1,998 +0,0 @@
-/*
- * CPDOMWindowBridge.j
- * AppKit
- *
- * Created by Francisco Tolmasky.
- * Copyright 2008, 280 North, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-@import
-@import
-
-@import "CPEvent.j"
-@import "CPCompatibility.j"
-
-@import "CPDOMWindowLayer.j"
-
-#import "../../CoreGraphics/CGGeometry.h"
-
-
-CPSharedDOMWindowBridge = nil;
-
-var ExcludedDOMElements = [];
-
-// Define up here so compressor knows about em.
-var CPDOMWindowGetFrame,
- CPDOMEventGetClickCount,
- CPDOMEventStop;
-
-@implementation CPDOMWindowBridge : CPObject
-{
- CPArray _orderedWindows;
- CPWindow _mouseDownWindow;
-
- DOMWindow _DOMWindow;
- DOMElement _DOMBodyElement;
- DOMElement _DOMFocusElement;
-
- CPArray _windowLevels;
- CPDictionary _windowLayers;
-
- CPRect _frame;
- CPRect _contentBounds;
-
- BOOL _mouseIsDown;
- CPTimeInterval _lastMouseUp;
- CPTimeInterval _lastMouseDown;
-
- JSObject _charCodes;
- unsigned _keyCode;
-
- BOOL _DOMEventMode;
-
- // Native Pasteboard Support
- DOMElement _DOMPasteboardElement;
- CPEvent _pasteboardKeyDownEvent;
-
- CPString _overriddenEventType;
-}
-
-/*!
- Returns the shared DOMWindowBridge.
-*/
-+ (id)sharedDOMWindowBridge
-{
- if (!CPSharedDOMWindowBridge)
- CPSharedDOMWindowBridge = [[CPDOMWindowBridge alloc] _initWithDOMWindow:window];
-
- return CPSharedDOMWindowBridge;
-}
-
-- (id)initWithFrame:(CPRect)aFrame
-{
- alert("unimplemented");
-}
-
-/* @ignore */
-- (id)_initWithDOMWindow:(DOMWindow)aDOMWindow
-{
- self = [super init];
-
- if (self)
- {
- _DOMWindow = aDOMWindow;
-
- _windowLevels = [];
- _windowLayers = [CPDictionary dictionary];
-
- // Do this before getting the frame of the window, because if not it will be wrong in IE.
- _DOMBodyElement = document.getElementsByTagName("body")[0];
- _DOMBodyElement.innerHTML = ""; // Get rid of anything that might be lingering in the body element.
- _DOMBodyElement.style.overflow = "hidden";
- _DOMBodyElement.style.webkitTouchCallout = "none";
-
- [CPString _resetSize];
-
- if (document.documentElement)
- document.documentElement.style.overflow = "hidden";
-
- _frame = CPDOMWindowGetFrame(_DOMWindow);
- _contentBounds = CGRectMake(0.0, 0.0, CPRectGetWidth(_frame), CPRectGetHeight(_frame));
-
- _DOMFocusElement = document.createElement("input");
- _DOMFocusElement.style.position = "absolute";
- _DOMFocusElement.style.zIndex = "-1000";
- _DOMFocusElement.style.opacity = "0";
- _DOMFocusElement.style.filter = "alpha(opacity=0)";
- _DOMBodyElement.appendChild(_DOMFocusElement);
-
- // Create Native Pasteboard handler.
- _DOMPasteboardElement = document.createElement("input");
- _DOMPasteboardElement.style.position = "absolute";
- _DOMPasteboardElement.style.top = "-10000px";
- _DOMPasteboardElement.style.zIndex = "99";
-
- _DOMBodyElement.appendChild(_DOMPasteboardElement);
-
- // Make sure the pastboard element is blurred.
- _DOMPasteboardElement.blur();
-
- _charCodes = {};
-
- //
- var theClass = [self class],
-
- keyEventSelector = @selector(_bridgeKeyEvent:),
- keyEventImplementation = class_getMethodImplementation(theClass, keyEventSelector),
- keyEventCallback = function (anEvent) { keyEventImplementation(self, nil, anEvent); },
-
- mouseEventSelector = @selector(_bridgeMouseEvent:),
- mouseEventImplementation = class_getMethodImplementation(theClass, mouseEventSelector),
- mouseEventCallback = function (anEvent) { mouseEventImplementation(self, nil, anEvent); },
-
- scrollEventSelector = @selector(_bridgeScrollEvent:),
- scrollEventImplementation = class_getMethodImplementation(theClass, scrollEventSelector),
- scrollEventCallback = function (anEvent) { scrollEventImplementation(self, nil, anEvent); },
-
- resizeEventSelector = @selector(_bridgeResizeEvent:),
- resizeEventImplementation = class_getMethodImplementation(theClass, resizeEventSelector),
- resizeEventCallback = function (anEvent) { resizeEventImplementation(self, nil, anEvent); },
-
- touchEventSelector = @selector(_bridgeTouchEvent:),
- touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector),
- touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); },
-
- theDocument = _DOMWindow.document;
-
- if (document.addEventListener)
- {
- _DOMWindow.addEventListener("resize", resizeEventCallback, NO);
-
- theDocument.addEventListener(CPDOMEventMouseUp, mouseEventCallback, NO);
- theDocument.addEventListener(CPDOMEventMouseDown, mouseEventCallback, NO);
- theDocument.addEventListener(CPDOMEventMouseMoved, mouseEventCallback, NO);
-
- theDocument.addEventListener(CPDOMEventKeyUp, keyEventCallback, NO);
- theDocument.addEventListener(CPDOMEventKeyDown, keyEventCallback, NO);
- theDocument.addEventListener(CPDOMEventKeyPress, keyEventCallback, NO);
-
-
- theDocument.addEventListener(CPDOMEventTouchStart, touchEventCallback, NO);
- theDocument.addEventListener(CPDOMEventTouchEnd, touchEventCallback, NO);
- theDocument.addEventListener(CPDOMEventTouchMove, touchEventCallback, NO);
- theDocument.addEventListener(CPDOMEventTouchCancel, touchEventCallback, NO);
-
- //FIXME: does firefox really need a different value?
- _DOMWindow.addEventListener("DOMMouseScroll", scrollEventCallback, NO);
- _DOMWindow.addEventListener(CPDOMEventScrollWheel, scrollEventCallback, NO);
- }
- else if(document.attachEvent)
- {
- _DOMWindow.attachEvent("onresize", resizeEventCallback);
-
- theDocument.attachEvent("on" + CPDOMEventMouseUp, mouseEventCallback);
- theDocument.attachEvent("on" + CPDOMEventMouseDown, mouseEventCallback);
- theDocument.attachEvent("on" + CPDOMEventMouseMoved, mouseEventCallback);
- theDocument.attachEvent("on" + CPDOMEventDoubleClick, mouseEventCallback);
-
- theDocument.attachEvent("on" + CPDOMEventKeyUp, keyEventCallback);
- theDocument.attachEvent("on" + CPDOMEventKeyDown, keyEventCallback);
- theDocument.attachEvent("on" + CPDOMEventKeyPress, keyEventCallback);
-
- _DOMWindow.onmousewheel = scrollEventCallback;
- theDocument.onmousewheel = scrollEventCallback;
-
- theDocument.body.ondrag = function () { return NO; };
- theDocument.body.onselectstart = function () { return window.event.srcElement == _DOMPasteboardElement; };
- }
-
- ExcludedDOMElements["INPUT"] = YES;
- ExcludedDOMElements["SELECT"] = YES;
- ExcludedDOMElements["TEXTAREA"] = YES;
- ExcludedDOMElements["OPTION"] = YES;
- }
-
- return self;
-}
-
-- (CPRect)frame
-{
- return CGRectMakeCopy(_frame);
-}
-
-- (CGRect)visibleFrame
-{
- var frame = [self frame];
-
- frame.origin = CGPointMakeZero();
-
- if ([CPMenu menuBarVisible])
- {
- var menuBarHeight = [[CPApp mainMenu] menuBarHeight];
-
- frame.origin.y += menuBarHeight;
- frame.size.height -= menuBarHeight;
- }
-
- return frame;
-}
-
-- (CPRect)contentBounds
-{
- return CPRectCreateCopy(_contentBounds);
-}
-
-- (CPArray)orderedWindowsAtLevel:(int)aLevel
-{
- var layer = [self layerAtLevel:aLevel create:NO];
-
- if (!layer)
- return [];
-
- return [layer orderedWindows];
-}
-
-- (CPDOMWindowLayer)layerAtLevel:(int)aLevel create:(BOOL)aFlag
-{
- var layer = [_windowLayers objectForKey:aLevel];
-
- // If the layer doesn't currently exist, and the create flag is true,
- // create the layer.
- if (!layer && aFlag)
- {
- layer = [[CPDOMWindowLayer alloc] initWithLevel:aLevel];
-
- [_windowLayers setObject:layer forKey:aLevel];
-
- // Find the nearest layer. This is similar to a binary search,
- // only we know we won't find the value.
- var low = 0,
- high = _windowLevels.length - 1,
- middle;
-
- while (low <= high)
- {
- middle = FLOOR((low + high) / 2);
-
- if (_windowLevels[middle] > aLevel)
- high = middle - 1;
- else
- low = middle + 1;
- }
-
- [_windowLevels insertObject:aLevel atIndex:_windowLevels[middle] > aLevel ? middle : middle + 1];
- layer._DOMElement.style.zIndex = aLevel;
- _DOMBodyElement.appendChild(layer._DOMElement);
- }
-
- return layer;
-}
-
-- (void)order:(CPWindowOrderingMode)aPlace window:(CPWindow)aWindow relativeTo:(CPWindow)otherWindow
-{
- // Grab the appropriate level for the layer, and create it if
- // necessary (if we are not simply removing the window).
- var layer = [self layerAtLevel:[aWindow level] create:aPlace != CPWindowOut];
-
- // Ignore otherWindow, simply remove this window from it's level.
- // If layer is nil, this will be a no-op.
- if (aPlace == CPWindowOut)
- return [layer removeWindow:aWindow];
-
- // Place the window at the appropriate index.
- [layer insertWindow:aWindow atIndex:(otherWindow ? (aPlace == CPWindowAbove ? otherWindow._index + 1 : otherWindow._index) : CPNotFound)];
-}
-
-/* @ignore */
-- (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard
-{
- var levels = _windowLevels,
- layers = _windowLayers,
- levelCount = levels.length;
-
- while (levelCount--)
- {
- // Skip any windows above or at the dragging level.
- if (levels[levelCount] >= CPDraggingWindowLevel)
- continue;
-
- var windows = [layers objectForKey:levels[levelCount]]._windows,
- windowCount = windows.length;
-
- while (windowCount--)
- {
- var theWindow = windows[windowCount];
-
- if ([theWindow containsPoint:aPoint])
- return [theWindow _dragHitTest:aPoint pasteboard:aPasteboard];
- }
- }
-
- return nil;
-}
-
-/* @ignore */
-- (void)_propagateCurrentDOMEvent:(BOOL)aFlag
-{
- StopDOMEventPropagation = !aFlag;
-}
-
-- (CPWindow)hitTest:(CPPoint)location
-{
- var levels = _windowLevels,
- layers = _windowLayers,
- levelCount = levels.length,
- theWindow = nil;
-
- while (levelCount-- && !theWindow)
- {
- var windows = [layers objectForKey:levels[levelCount]]._windows,
- windowCount = windows.length;
-
- while (windowCount-- && !theWindow)
- {
- var candidateWindow = windows[windowCount];
-
- if (!candidateWindow._ignoresMouseEvents && [candidateWindow containsPoint:location])
- theWindow = candidateWindow;
- }
- }
-
- return theWindow;
-}
-
-@end
-
-var CPDOMWindowGetFrame = function(_DOMWindow)
-{
- var frame = nil;//CGRectMakeZero();
-
- // We will rarely be able to get all this information, but we do the best we can:
- if (_DOMWindow.outerWidth)
- frame = CGRectMake(0, 0, _DOMWindow.outerWidth, _DOMWindow.outerHeight);
-
- else /*if(self.outerWidth)*/
- frame = CGRectMake(0, 0, -1, -1);
-
- if (window.screenTop)
- frame.origin = CGPointMake(_DOMWindow.screenLeft, _DOMWindow.screenTop, 0);
-
- else if (window.screenX)
- frame.origin = CGPointMake(_DOMWindow.screenX, _DOMWindow.screenY, 0);
-
- // Safari, Mozilla, Firefox, and Opera
- if (_DOMWindow.innerWidth)
- frame.size = CGSizeMake(_DOMWindow.innerWidth, _DOMWindow.innerHeight);
-
- // Internet Explorer 6 in Strict Mode
- else if (document.documentElement && document.documentElement.clientWidth)
- frame.size = CGSizeMake(_DOMWindow.document.documentElement.clientWidth, _DOMWindow.document.documentElement.clientHeight);
-
- // Internet Explorer X
- else
- frame.size = CGSizeMake(_DOMWindow.document.body.clientWidth, _DOMWindow.document.body.clientHeight);
-
- return frame;
-}
-
-//right now we hard code q, w, r and t as keys to propogate
-//these aren't normal keycodes, they are with modifier key codes
-//might be mac only, we should investigate futher later.
-var KeyCodesToPrevent = {},
- CharacterKeysToPrevent = {},
- KeyCodesWithoutKeyPressEvents = { '8':1, '9':1, '37':1, '38':1, '39':1, '40':1, '46':1, '33':1, '34':1 };
-
-var CTRL_KEY_CODE = 17;
-
-@implementation CPDOMWindowBridge (Events)
-
-/*!
- When using command (mac) or control (windows), keys are propagated to the browser by default.
- To prevent a character key from propagating (to prevent its default action, and instead use it
- in your own application), use these methods. These methods are additive -- the list builds until you clear it.
-
- @param characters a list of characters to stop propagating keypresses to the browser.
-*/
-- (void)preventCharacterKeysFromPropagating:(CPArray)characters
-{
- for(var i=characters.length; i>0; i--)
- CharacterKeysToPrevent[""+characters[i-1].toLowerCase()] = YES;
-}
-
-/*!
- @param character a character to stop propagating keypresses to the browser.
-*/
-- (void)preventCharacterKeyFromPropagating:(CPString)character
-{
- CharacterKeysToPrevent[character.toLowerCase()] = YES;
-}
-
-/*!
- Clear the list of characters for which we are not sending keypresses to the browser.
-*/
-- (void)clearCharacterKeysToPreventFromPropagating
-{
- CharacterKeysToPrevent = {};
-}
-
-/*!
- Prevent these keyCodes from sending their keypresses to the browser.
- @param keyCodes an array of keycodes to prevent propagation.
-*/
-- (void)preventKeyCodesFromPropagating:(CPArray)keyCodes
-{
- for(var i=keyCodes.length; i>0; i--)
- KeyCodesToPrevent[keyCodes[i-1]] = YES;
-}
-
-/*!
- Prevent this keyCode from sending its key events to the browser.
- @param keyCode a keycode to prevent propagation.
-*/
-- (void)preventKeyCodeFromPropagating:(CPString)keyCode
-{
- KeyCodesToPrevent[keyCode] = YES;
-}
-
-/*!
- Clear the list of keyCodes for which we are not sending keypresses to the browser.
-*/
-- (void)clearKeyCodesToPreventFromPropagating
-{
- KeyCodesToPrevent = {};
-}
-
-/* @ignore */
-- (void)_bridgeMouseEvent:(DOMEvent)aDOMEvent
-{
- var theType = _overriddenEventType || aDOMEvent.type;
-
- // IE's event order is down, up, up, dblclick, so we have create these events artificially.
- if (theType === CPDOMEventDoubleClick)
- {
- _overriddenEventType = CPDOMEventMouseDown;
- [self _bridgeMouseEvent:aDOMEvent];
-
- _overriddenEventType = CPDOMEventMouseUp;
- [self _bridgeMouseEvent:aDOMEvent];
-
- _overriddenEventType = nil;
-
- return;
- }
-
- try
- {
- var event,
- location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY),
- timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
- sourceElement = (aDOMEvent.target || aDOMEvent.srcElement),
- windowNumber = 0,
- modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
- (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
- (aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
- (aDOMEvent.metaKey ? CPCommandKeyMask : 0);
-
- StopDOMEventPropagation = YES;
-
- if (_mouseDownWindow)
- windowNumber = [_mouseDownWindow windowNumber];
- else
- {
- var theWindow = [self hitTest:location];
-
- if ((aDOMEvent.type === CPDOMEventMouseDown) && theWindow)
- _mouseDownWindow = theWindow;
-
- windowNumber = [theWindow windowNumber];
- }
-
- if (windowNumber)
- {
- var windowFrame = CPApp._windows[windowNumber]._frame;
-
- location.x -= _CGRectGetMinX(windowFrame);
- location.y -= _CGRectGetMinY(windowFrame);
- }
-
- switch (theType)
- {
- case CPDOMEventMouseUp: if(_mouseIsDown)
- {
- event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0);
-
- _mouseIsDown = NO;
- _lastMouseUp = event;
- _mouseDownWindow = nil;
- }
-
- if(_DOMEventMode)
- {
- _DOMEventMode = NO;
- return;
- }
-
- break;
-
- case CPDOMEventMouseDown: if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement)
- {
- _DOMEventMode = YES;
- _mouseIsDown = YES;
-
- //fake a down and up event so that event tracking mode will work correctly
- [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:location modifierFlags:modifierFlags
- timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
- clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
-
- [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseUp location:location modifierFlags:modifierFlags
- timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
- clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
-
- return;
- }
-
- event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0);
-
- _mouseIsDown = YES;
- _lastMouseDown = event;
-
- break;
-
- case CPDOMEventMouseMoved: if (_DOMEventMode)
- return;
-
- event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? CPLeftMouseDragged : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0);
-
- break;
- }
-
- if (event)
- {
- event._DOMEvent = aDOMEvent;
-
- [CPApp sendEvent:event];
- }
-
- if (StopDOMEventPropagation)
- CPDOMEventStop(aDOMEvent);
-
- [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
- }
- catch (anException)
- {
- objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
- }
-}
-
-/* @ignore */
-- (void)_bridgeKeyEvent:(DOMEvent)aDOMEvent
-{
- try
- {
- var event,
- timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
- sourceElement = (aDOMEvent.target || aDOMEvent.srcElement),
- windowNumber = [[CPApp keyWindow] windowNumber],
- modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
- (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
- (aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
- (aDOMEvent.metaKey ? CPCommandKeyMask : 0);
-
- if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement && sourceElement != _DOMPasteboardElement)
- return;
-
- //We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist
- StopDOMEventPropagation = !(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
- CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] ||
- KeyCodesToPrevent[aDOMEvent.keyCode];
-
- var isNativePasteEvent = NO,
- isNativeCopyOrCutEvent = NO;
-
- switch (aDOMEvent.type)
- {
- case CPDOMEventKeyDown: // Grab and store the keycode now since it is correct and consistent at this point.
- _keyCode = aDOMEvent.keyCode;
-
- var characters = String.fromCharCode(_keyCode).toLowerCase();
-
- // If this could be a native PASTE event, then we need to further examine it before
- // sending a CPEvent. Select our element to see if anything gets pasted in it.
- if (characters == "v" && (modifierFlags & CPPlatformActionKeyMask))
- {
- _DOMPasteboardElement.select();
- _DOMPasteboardElement.value = "";
-
- isNativePasteEvent = YES;
- }
-
- // Normally we return now because we let keypress send the actual CPEvent keyDown event, since we don't have
- // a complete set of information yet.
-
- // However, of this could be a native COPY event, we need to let the normal event-process take place so it
- // can capture our internal Cappuccino pasteboard.
- else if ((characters == "c" || characters == "x") && (modifierFlags & CPPlatformActionKeyMask))
- isNativeCopyOrCutEvent = YES;
-
- // Also, certain browsers (IE and Safari), have broken keyboard supportwhere they don't send keypresses for certain events.
- // So, allow the keypress event to handle the event if we are not a browser with broken (remedial) key support...
- else if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport))
- return;
-
- // Or, if this is not one of those special keycodes, and also not a ctrl+event
- else if (!KeyCodesWithoutKeyPressEvents[_keyCode] && (_keyCode == CTRL_KEY_CODE || !(modifierFlags & CPControlKeyMask)))
- return;
-
- // If this is in fact our broke state, continue to keypress and send the keydown.
- case CPDOMEventKeyPress:
- // If the source of this event is our pasteboard element, then simply let it continue
- // as normal, so that the paste event can successfully complete.
- if ((aDOMEvent.target || aDOMEvent.srcElement) == _DOMPasteboardElement)
- return;
-
- var keyCode = _keyCode,
- charCode = aDOMEvent.keyCode || aDOMEvent.charCode,
- isARepeat = (_charCodes[keyCode] != nil);
-
- _charCodes[keyCode] = charCode;
-
- var characters = String.fromCharCode(charCode),
- charactersIgnoringModifiers = characters.toLowerCase();
-
- event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
- timestamp:timestamp windowNumber:windowNumber context:nil
- characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:keyCode];
-
- if (isNativePasteEvent)
- {
- _pasteboardKeyDownEvent = event;
-
- window.setNativeTimeout(function () { [self _checkPasteboardElement] }, 0);
-
- return;
- }
-
- break;
-
- case CPDOMEventKeyUp: var keyCode = aDOMEvent.keyCode,
- charCode = _charCodes[keyCode];
-
- _charCodes[keyCode] = nil;
-
- var characters = String.fromCharCode(charCode),
- charactersIgnoringModifiers = characters.toLowerCase();
-
- if (!(modifierFlags & CPShiftKeyMask))
- characters = charactersIgnoringModifiers;
-
- event = [CPEvent keyEventWithType:CPKeyUp location:location modifierFlags:modifierFlags
- timestamp: timestamp windowNumber:windowNumber context:nil
- characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:keyCode];
- break;
- }
-
- if (event)
- {
- event._DOMEvent = aDOMEvent;
-
- [CPApp sendEvent:event];
-
- if (isNativeCopyOrCutEvent)
- {
- var pasteboard = [CPPasteboard generalPasteboard],
- types = [pasteboard types];
-
- // If this is a native copy event, then check if the pasteboard has anything in it.
- if (types.length)
- {
- if ([types indexOfObjectIdenticalTo:CPStringPboardType] != CPNotFound)
- _DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType];
- else
- _DOMPasteboardElement.value = [pasteboard _generateStateUID];
-
- _DOMPasteboardElement.select();
-
- window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0);
- }
-
- return;
- }
- }
-
- if (StopDOMEventPropagation)
- CPDOMEventStop(aDOMEvent);
-
- [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
- }
- catch (anException)
- {
- objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
- }
-}
-
-/* @ignore */
-- (void)_bridgeScrollEvent:(DOMEvent)aDOMEvent
-{
- if(!aDOMEvent)
- aDOMEvent = window.event;
-
- try
- {
- if (CPFeatureIsCompatible(CPJavaScriptMouseWheelValues_8_15))
- {
- var x = 0.0,
- y = 0.0,
- element = aDOMEvent.target;
-
- while (element.nodeType !== 1)
- element = element.parentNode;
-
- if (element.offsetParent)
- {
- do
- {
- x += element.offsetLeft;
- y += element.offsetTop;
-
- } while (element = element.offsetParent);
- }
-
- var location = _CGPointMake((x + ((aDOMEvent.clientX - 8) / 15)), (y + ((aDOMEvent.clientY - 8) / 15)));}
- else
- var location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY);
-
- var deltaX = 0.0,
- deltaY = 0.0,
- windowNumber = 0,
- timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
- modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
- (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
- (aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
- (aDOMEvent.metaKey ? CPCommandKeyMask : 0);
-
- StopDOMEventPropagation = YES;
-
- windowNumber = [[self hitTest:location] windowNumber];
-
- if (!windowNumber)
- return;
-
- var windowFrame = CPApp._windows[windowNumber]._frame;
-
- location.x -= CGRectGetMinX(windowFrame);
- location.y -= CGRectGetMinY(windowFrame);
-
- if(typeof aDOMEvent.wheelDeltaX != "undefined")
- {
- deltaX = aDOMEvent.wheelDeltaX / 120.0;
- deltaY = aDOMEvent.wheelDeltaY / 120.0;
- }
-
- else if (aDOMEvent.wheelDelta)
- deltaY = aDOMEvent.wheelDelta / 120.0;
-
- else if (aDOMEvent.detail)
- deltaY = -aDOMEvent.detail / 3.0;
-
- else
- return;
-
- if(!CPFeatureIsCompatible(CPJavaScriptNegativeMouseWheelValues))
- {
- deltaX = -deltaX;
- deltaY = -deltaY;
- }
-
- var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags
- timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0 ];
-
- event._DOMEvent = aDOMEvent;
- event._deltaX = ROUND(deltaX * 1.5);
- event._deltaY = ROUND(deltaY * 1.5);
-
- [CPApp sendEvent:event];
-
- if (StopDOMEventPropagation)
- CPDOMEventStop(aDOMEvent);
-
- [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
- }
- catch (anException)
- {
- objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
- }
-
-}
-
-/* @ignore */
-- (void)_bridgeResizeEvent:(DOMEvent)aDOMEvent
-{
- try
- {
- // FIXME: This is not the right way to do this.
- // We should pay attention to mouse down and mouse up in conjunction with this.
- //window.liveResize = YES;
-
- var oldSize = _frame.size;
-
- // window.liveResize = YES?
- _frame = CPDOMWindowGetFrame(_DOMWindow);
- _contentBounds.size = CGSizeCreateCopy(_frame.size);
-
- var levels = _windowLevels,
- layers = _windowLayers,
- levelCount = levels.length;
-
- while (levelCount--)
- {
- var windows = [layers objectForKey:levels[levelCount]]._windows,
- windowCount = windows.length;
-
- while (windowCount--)
- [windows[windowCount] resizeWithOldBridgeSize:oldSize];
- }
-
- //window.liveResize = NO;
-
- [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
- }
- catch (anException)
- {
- objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
- }
-}
-
-// DOM event properties used in mouse bridge code
-
-// type
-// clientX
-// clientY
-// timestamp
-// target/srcElement
-// shiftKey,ctrlKey,altKey,metaKey
-
-/* @ignore */
-- (void)_bridgeTouchEvent:(DOMEvent)aDOMEvent
-{
- try
- {
- if (aDOMEvent.touches && (aDOMEvent.touches.length == 1 || (aDOMEvent.touches.length == 0 && aDOMEvent.changedTouches.length == 1)))
- {
- var newEvent = {};
-
- switch(aDOMEvent.type)
- {
- case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown;
- break;
- case CPDOMEventTouchEnd: newEvent.type = CPDOMEventMouseUp;
- break;
- case CPDOMEventTouchMove: newEvent.type = CPDOMEventMouseMoved;
- break;
- case CPDOMEventTouchCancel: newEvent.type = CPDOMEventMouseUp;
- break;
- }
-
- var touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0];
-
- newEvent.clientX = touch.clientX;
- newEvent.clientY = touch.clientY;
-
- newEvent.timestamp = aDOMEvent.timestamp;
- newEvent.target = aDOMEvent.target;
-
- newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false;
-
- newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()};
- newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()};
-
- [self _bridgeMouseEvent:newEvent];
-
- return;
- }
- else
- {
- if (aDOMEvent.preventDefault)
- aDOMEvent.preventDefault();
-
- if (aDOMEvent.stopPropagation)
- aDOMEvent.stopPropagation();
- }
- }
- catch(e)
- {
- objj_exception_report(e, {path:@"CPDOMWindowBridge.j"});
- }
-
- // handle touch cases specifically
-}
-
-/* @ignore */
-- (void)_checkPasteboardElement
-{
- try
- {
- var value = _DOMPasteboardElement.value;
-
- if ([value length])
- {
- var pasteboard = [CPPasteboard generalPasteboard];
-
- if ([pasteboard _stateUID] != value)
- {
- [pasteboard declareTypes:[CPStringPboardType] owner:self];
-
- [pasteboard setString:value forType:CPStringPboardType];
- }
- }
-
- [self _clearPasteboardElement];
-
- [CPApp sendEvent:_pasteboardKeyDownEvent];
-
- _pasteboardKeyDownEvent = nil;
-
- [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
- }
- catch (anException)
- {
- objj_exception_report(anException, {path:@"CPDOMWindowBridge.j"});
- }
-}
-
-/* @ignore */
-- (void)_clearPasteboardElement
-{
- _DOMPasteboardElement.value = "";
- _DOMPasteboardElement.blur();
-}
-
-@end
-
-var CLICK_SPACE_DELTA = 5.0,
- CLICK_TIME_DELTA = (typeof document != "undefined" && document.addEventListener) ? 350.0 : 1000.0;
-
-var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation)
-{
- if (!aComparisonEvent)
- return 1;
-
- var comparisonLocation = [aComparisonEvent locationInWindow];
-
- return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA &&
- ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA &&
- ABS(comparisonLocation.y - aLocation.y) < CLICK_SPACE_DELTA) ? [aComparisonEvent clickCount] + 1 : 1;
-}
-
-var CPDOMEventStop = function(aDOMEvent)
-{
- // IE Model
- aDOMEvent.cancelBubble = true;
- aDOMEvent.returnValue = false;
-
- // W3C Model
- if (aDOMEvent.preventDefault)
- aDOMEvent.preventDefault();
-
- if (aDOMEvent.stopPropagation)
- aDOMEvent.stopPropagation();
-
- if (aDOMEvent.type === CPDOMEventMouseDown)
- {
- CPSharedDOMWindowBridge._DOMFocusElement.focus();
- CPSharedDOMWindowBridge._DOMFocusElement.blur();
- }
-}
diff --git a/AppKit/Platform/DOM/CPDOMWindowLayer.j b/AppKit/Platform/DOM/CPDOMWindowLayer.j
index bb5c5c882..3d6f3dede 100644
--- a/AppKit/Platform/DOM/CPDOMWindowLayer.j
+++ b/AppKit/Platform/DOM/CPDOMWindowLayer.j
@@ -115,7 +115,7 @@
aWindow._isVisible = YES;
if ([aWindow isFullBridge])
- [aWindow setFrame:[aWindow._bridge visibleFrame]];
+ [aWindow setFrame:[aWindow._platformWindow usableContentFrame]];
}
}
diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j
new file mode 100644
index 000000000..299e14a82
--- /dev/null
+++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j
@@ -0,0 +1,1147 @@
+/*
+ * _CPDOMWindow.j
+ * AppKit
+ *
+ * Created by Francisco Tolmasky.
+ * Copyright 2008, 280 North, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+@import
+@import
+
+@import "CPEvent.j"
+@import "CPCompatibility.j"
+
+@import "CPDOMWindowLayer.j"
+
+@import "CPPlatform.j"
+@import "CPPlatformWindow.j"
+
+#import "../../CoreGraphics/CGGeometry.h"
+
+
+var DoubleClick = "dblclick",
+ MouseDown = "mousedown",
+ MouseUp = "mouseup",
+ MouseMove = "mousemove",
+ MouseDrag = "mousedrag",
+ KeyUp = "keyup",
+ KeyDown = "keydown",
+ KeyPress = "keypress",
+ Copy = "copy",
+ Paste = "paste",
+ Resize = "resize",
+ ScrollWheel = "mousewheel",
+ TouchStart = "touchstart",
+ TouchMove = "touchmove",
+ TouchEnd = "touchend",
+ TouchCancel = "touchcancel";
+
+var ExcludedDOMElements = [];
+
+ExcludedDOMElements["INPUT"] = YES;
+ExcludedDOMElements["SELECT"] = YES;
+ExcludedDOMElements["TEXTAREA"] = YES;
+ExcludedDOMElements["OPTION"] = YES;
+
+// Define up here so compressor knows about em.
+var CPDOMEventGetClickCount,
+ CPDOMEventStop;
+
+//right now we hard code q, w, r and t as keys to propogate
+//these aren't normal keycodes, they are with modifier key codes
+//might be mac only, we should investigate futher later.
+var KeyCodesToPrevent = {},
+ CharacterKeysToPrevent = {},
+ KeyCodesWithoutKeyPressEvents = { '8':1, '9':1, '16':1, '37':1, '38':1, '39':1, '40':1, '46':1, '33':1, '34':1 };
+
+var CTRL_KEY_CODE = 17;
+
+var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
+
+@implementation CPPlatformWindow (DOM)
+
+- (id)_init
+{
+ self = [super init];
+
+ if (self)
+ {
+ _DOMWindow = window;
+ _contentRect = _CGRectMakeZero();
+
+ _windowLevels = [];
+ _windowLayers = [CPDictionary dictionary];
+
+ [self registerDOMWindow];
+ [self updateFromNativeContentRect];
+
+ _charCodes = {};
+ }
+
+ return self;
+}
+
+- (CGRect)nativeContentRect
+{
+ if (!_DOMWindow)
+ return [self contentRect];
+
+ if (_DOMWindow.cpFrame)
+ return _DOMWindow.cpFrame();
+
+ var contentRect = _CGRectMakeZero();
+
+ if (window.screenTop)
+ contentRect.origin = _CGPointMake(_DOMWindow.screenLeft, _DOMWindow.screenTop);
+
+ else if (window.screenX)
+ contentRect.origin = _CGPointMake(_DOMWindow.screenX, _DOMWindow.screenY);
+
+ // Safari, Mozilla, Firefox, and Opera
+ if (_DOMWindow.innerWidth)
+ contentRect.size = _CGSizeMake(_DOMWindow.innerWidth, _DOMWindow.innerHeight);
+
+ // Internet Explorer 6 in Strict Mode
+ else if (document.documentElement && document.documentElement.clientWidth)
+ contentRect.size = _CGSizeMake(_DOMWindow.document.documentElement.clientWidth, _DOMWindow.document.documentElement.clientHeight);
+
+ // Internet Explorer X
+ else
+ contentRect.size = _CGSizeMake(_DOMWindow.document.body.clientWidth, _DOMWindow.document.body.clientHeight);
+
+ return contentRect;
+}
+
+- (void)updateNativeContentRect
+{
+ if (!_DOMWindow)
+ return;
+
+ if (typeof _DOMWindow["cpSetFrame"] === "function")
+ return _DOMWindow.cpSetFrame([self contentRect]);
+
+ var origin = [self contentRect].origin,
+ nativeOrigin = [self nativeContentRect].origin;
+
+ if (origin.x !== nativeOrigin.x || origin.y !== nativeOrigin.y)
+ {
+ _DOMWindow.moveBy(origin.x - nativeOrigin.x, origin.y - nativeOrigin.y);
+ }
+
+ var size = [self contentRect].size,
+ nativeSize = [self nativeContentRect].size;
+
+ if (size.width !== nativeSize.width || size.height !== nativeSize.height)
+ {
+ _DOMWindow.resizeBy(size.width - nativeSize.width, size.height - nativeSize.height);
+ }
+}
+
+- (void)orderBack:(id)aSender
+{
+ if (_DOMWindow)
+ _DOMWindow.blur();
+}
+
+- (void)registerDOMWindow
+{
+ var theDocument = _DOMWindow.document;
+
+ _DOMBodyElement = theDocument.getElementsByTagName("body")[0];
+
+ // FIXME: Always do this?
+ if ([CPPlatform supportsDragAndDrop])
+ _DOMBodyElement.style["-khtml-user-select"] = "none";
+
+ _DOMBodyElement.webkitTouchCallout = "none";
+
+ _DOMFocusElement = theDocument.createElement("input");
+
+ _DOMFocusElement.style.position = "absolute";
+ _DOMFocusElement.style.zIndex = "-1000";
+ _DOMFocusElement.style.opacity = "0";
+ _DOMFocusElement.style.filter = "alpha(opacity=0)";
+
+ _DOMBodyElement.appendChild(_DOMFocusElement);
+
+ // Create Native Pasteboard handler.
+ _DOMPasteboardElement = theDocument.createElement("input");
+
+ _DOMPasteboardElement.style.position = "absolute";
+ _DOMPasteboardElement.style.top = "-10000px";
+ _DOMPasteboardElement.style.zIndex = "99";
+
+ _DOMBodyElement.appendChild(_DOMPasteboardElement);
+
+ // Make sure the pastboard element is blurred.
+ _DOMPasteboardElement.blur();
+
+ var theClass = [self class],
+
+ dragEventImplementation = class_getMethodImplementation(theClass, @selector(dragEvent:)),
+ dragEventCallback = function (anEvent) { dragEventImplementation(self, nil, anEvent); },
+
+ resizeEventSelector = @selector(resizeEvent:),
+ resizeEventImplementation = class_getMethodImplementation(theClass, resizeEventSelector),
+ resizeEventCallback = function (anEvent) { resizeEventImplementation(self, nil, anEvent); },
+
+ keyEventSelector = @selector(keyEvent:),
+ keyEventImplementation = class_getMethodImplementation(theClass, keyEventSelector),
+ keyEventCallback = function (anEvent) { keyEventImplementation(self, nil, anEvent); },
+
+ mouseEventSelector = @selector(mouseEvent:),
+ mouseEventImplementation = class_getMethodImplementation(theClass, mouseEventSelector),
+ mouseEventCallback = function (anEvent) { mouseEventImplementation(self, nil, anEvent); },
+
+ scrollEventSelector = @selector(scrollEvent:),
+ scrollEventImplementation = class_getMethodImplementation(theClass, scrollEventSelector),
+ scrollEventCallback = function (anEvent) { scrollEventImplementation(self, nil, anEvent); },
+
+ touchEventSelector = @selector(touchEvent:),
+ touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector),
+ touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); };
+
+ if (theDocument.addEventListener)
+ {
+ if ([CPPlatform supportsDragAndDrop])
+ {
+ theDocument.addEventListener("dragstart", dragEventCallback, NO);
+ theDocument.addEventListener("drag", dragEventCallback, NO);
+ theDocument.addEventListener("dragend", dragEventCallback, NO);
+ theDocument.addEventListener("dragover", dragEventCallback, NO);
+ theDocument.addEventListener("dragleave", dragEventCallback, NO);
+ theDocument.addEventListener("drop", dragEventCallback, NO);
+ }
+
+ theDocument.addEventListener("mouseup", mouseEventCallback, NO);
+ theDocument.addEventListener("mousedown", mouseEventCallback, NO);
+ theDocument.addEventListener("mousemove", mouseEventCallback, NO);
+
+ theDocument.addEventListener("keyup", keyEventCallback, NO);
+ theDocument.addEventListener("keydown", keyEventCallback, NO);
+ theDocument.addEventListener("keypress", keyEventCallback, NO);
+
+ theDocument.addEventListener("touchstart", touchEventCallback, NO);
+ theDocument.addEventListener("touchend", touchEventCallback, NO);
+ theDocument.addEventListener("touchmove", touchEventCallback, NO);
+ theDocument.addEventListener("touchcancel", touchEventCallback, NO);
+
+ _DOMWindow.addEventListener("DOMMouseScroll", scrollEventCallback, NO);
+ _DOMWindow.addEventListener("mousewheel", scrollEventCallback, NO);
+
+ _DOMWindow.addEventListener("resize", resizeEventCallback, NO);
+
+ _DOMWindow.addEventListener("unload", function()
+ {
+ [self updateFromNativeContentRect];
+
+ theDocument.removeEventListener("mouseup", mouseEventCallback, NO);
+ theDocument.removeEventListener("mousedown", mouseEventCallback, NO);
+ theDocument.removeEventListener("mousemove", mouseEventCallback, NO);
+
+ theDocument.removeEventListener("keyup", keyEventCallback, NO);
+ theDocument.removeEventListener("keydown", keyEventCallback, NO);
+ theDocument.removeEventListener("keypress", keyEventCallback, NO);
+
+ theDocument.removeEventListener("touchstart", touchEventCallback, NO);
+ theDocument.removeEventListener("touchend", touchEventCallback, NO);
+ theDocument.removeEventListener("touchmove", touchEventCallback, NO);
+
+ _DOMWindow.removeEventListener("resize", resizeEventCallback, NO);
+
+ //FIXME: does firefox really need a different value?
+ _DOMWindow.removeEventListener("DOMMouseScroll", scrollEventCallback, NO);
+ _DOMWindow.removeEventListener("mousewheel", scrollEventCallback, NO);
+
+ //_DOMWindow.removeEventListener("beforeunload", this, NO);
+
+ self._DOMWindow = nil;
+ }, NO);
+ }
+ else
+ {
+ theDocument.attachEvent("onmouseup", mouseEventCallback);
+ theDocument.attachEvent("onmousedown", mouseEventCallback);
+ theDocument.attachEvent("onmousemove", mouseEventCallback);
+ theDocument.attachEvent("ondblclick", mouseEventCallback);
+
+ theDocument.attachEvent("onkeyup", keyEventCallback);
+ theDocument.attachEvent("onkeydown", keyEventCallback);
+ theDocument.attachEvent("onkeypress", keyEventCallback);
+
+ _DOMWindow.attachEvent("onresize", resizeEventCallback);
+
+ _DOMWindow.onmousewheel = scrollEventCallback;
+ theDocument.onmousewheel = scrollEventCallback;
+
+ theDocument.body.ondrag = function () { return NO; };
+ theDocument.body.onselectstart = function () { return _DOMWindow.event.srcElement === _DOMPasteboardElement; };
+
+ _DOMWindow.attachEvent("onbeforeunload", function()
+ {
+ [self updateFromNativeContentRect];
+
+ theDocument.removeEvent("onmouseup", mouseEventCallback);
+ theDocument.removeEvent("onmousedown", mouseEventCallback);
+ theDocument.removeEvent("onmousemove", mouseEventCallback);
+ theDocument.removeEvent("ondblclick", mouseEventCallback);
+
+ theDocument.removeEvent("onkeyup", keyEventCallback);
+ theDocument.removeEvent("onkeydown", keyEventCallback);
+ theDocument.removeEvent("onkeypress", keyEventCallback);
+
+ _DOMWindow.removeEvent("onresize", resizeEventCallback);
+
+ _DOMWindow.onmousewheel = NULL;
+ theDocument.onmousewheel = NULL;
+
+ theDocument.body.ondrag = NULL;
+ theDocument.body.onselectstart = NULL;
+
+ //_DOMWindow.removeEvent("beforeunload", this);
+
+ self._DOMWindow = nil;
+ }, NO);
+ }
+}
+
+- (void)orderFront:(id)aSender
+{
+ if (_DOMWindow)
+ return _DOMWindow.focus();
+
+ _DOMWindow = window.open("", "_blank", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no,left=" + _CGRectGetMinX(_contentRect) + ",top=" + _CGRectGetMinY(_contentRect) + ",width=" + _CGRectGetWidth(_contentRect) + ",height=" + _CGRectGetHeight(_contentRect));
+
+ // FIXME: cpSetFrame?
+ _DOMWindow.document.write("");
+ _DOMWindow.document.close();
+
+ if (![CPPlatform isBrowser])
+ {
+ _DOMWindow.cpSetLevel(_level);
+ _DOMWindow.cpSetHasShadow(_hasShadow);
+ }
+
+ [self registerDOMWindow];
+}
+
+- (void)orderOut:(id)aSender
+{
+ if (!_DOMWindow)
+ return;
+
+ _DOMWindow.close();
+}
+
+- (void)dragEvent:(DOMEvent)aDOMEvent
+{
+ var type = aDOMEvent.type,
+ dragServer = [CPDragServer sharedDragServer],
+ location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY),
+ pasteboard = [_CPDOMDataTransferPasteboard DOMDataTransferPasteboard];
+
+ [pasteboard _setDataTransfer:aDOMEvent.dataTransfer];
+
+ if (aDOMEvent.type === "dragstart")
+ {
+ [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
+
+ [pasteboard _setPasteboard:[dragServer draggingPasteboard]];
+
+ var draggedWindow = [dragServer draggedWindow],
+ draggedWindowFrame = [draggedWindow frame],
+ DOMDragElement = draggedWindow._DOMElement;
+
+ DOMDragElement.style.left = -_CGRectGetWidth(draggedWindowFrame) + "px";
+ DOMDragElement.style.top = -_CGRectGetHeight(draggedWindowFrame) + "px";
+
+ document.getElementsByTagName("body")[0].appendChild(DOMDragElement);
+
+ var draggingOffset = [dragServer draggingOffset];
+
+ aDOMEvent.dataTransfer.setDragImage(DOMDragElement, draggingOffset.width, draggingOffset.height);
+
+ [dragServer draggingStartedInPlatformWindow:self globalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY)];
+ }
+
+ else if (type === "drag")
+ [dragServer draggingSourceUpdatedWithGlobalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY)];
+
+ else if (type === "dragover" || type === "dragleave")
+ {
+ if (aDOMEvent.preventDefault)
+ aDOMEvent.preventDefault();
+
+ var dropEffect = "none",
+ dragOperation = [dragServer draggingUpdatedInPlatformWindow:self location:location];
+
+ if (dragOperation === CPDragOperationMove || dragOperation === CPDragOperationGeneric || dragOperation === CPDragOperationPrivate)
+ dropEffect = "move";
+
+ else if (dragOperation === CPDragOperationCopy)
+ dropEffect = "copy";
+
+ else if (dragOperation === CPDragOperationLink)
+ dropEffect = "link";
+
+ aDOMEvent.dataTransfer.dropEffect = dropEffect;
+ }
+
+ else if (type === "dragend")
+ [dragServer draggingEndedInPlatformWindow:self globalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY)];
+
+ else //if (type === "drop")
+ {
+ [dragServer performDragOperationInPlatformWindow:self];
+
+ // W3C Model
+ if (aDOMEvent.preventDefault)
+ aDOMEvent.preventDefault();
+
+ if (aDOMEvent.stopPropagation)
+ aDOMEvent.stopPropagation();
+ }
+
+ [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
+}
+
+- (void)keyEvent:(DOMEvent)aDOMEvent
+{
+ var event,
+ timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
+ sourceElement = (aDOMEvent.target || aDOMEvent.srcElement),
+ windowNumber = [[CPApp keyWindow] windowNumber],
+ modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
+ (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
+ (aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
+ (aDOMEvent.metaKey ? CPCommandKeyMask : 0);
+
+ if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement && sourceElement != _DOMPasteboardElement)
+ return;
+
+ //We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist
+ StopDOMEventPropagation = !(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
+ CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] ||
+ KeyCodesToPrevent[aDOMEvent.keyCode];
+
+ var isNativePasteEvent = NO,
+ isNativeCopyOrCutEvent = NO;
+
+ switch (aDOMEvent.type)
+ {
+ case "keydown": // Grab and store the keycode now since it is correct and consistent at this point.
+ _keyCode = aDOMEvent.keyCode;
+
+ var characters = String.fromCharCode(_keyCode).toLowerCase();
+
+ // If this could be a native PASTE event, then we need to further examine it before
+ // sending a CPEvent. Select our element to see if anything gets pasted in it.
+ if (characters == "v" && (modifierFlags & CPPlatformActionKeyMask))
+ {
+ _DOMPasteboardElement.select();
+ _DOMPasteboardElement.value = "";
+
+ isNativePasteEvent = YES;
+ }
+
+ // Normally we return now because we let keypress send the actual CPEvent keyDown event, since we don't have
+ // a complete set of information yet.
+
+ // However, of this could be a native COPY event, we need to let the normal event-process take place so it
+ // can capture our internal Cappuccino pasteboard.
+ else if ((characters == "c" || characters == "x") && (modifierFlags & CPPlatformActionKeyMask))
+ isNativeCopyOrCutEvent = YES;
+
+ // Also, certain browsers (IE and Safari), have broken keyboard supportwhere they don't send keypresses for certain events.
+ // So, allow the keypress event to handle the event if we are not a browser with broken (remedial) key support...
+ else if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport))
+ return;
+
+ // Or, if this is not one of those special keycodes, and also not a ctrl+event
+ else if (!KeyCodesWithoutKeyPressEvents[_keyCode] && (_keyCode == CTRL_KEY_CODE || !(modifierFlags & CPControlKeyMask)))
+ return;
+
+ // If this is in fact our broke state, continue to keypress and send the keydown.
+ case "keypress": // If the source of this event is our pasteboard element, then simply let it continue
+ // as normal, so that the paste event can successfully complete.
+ if ((aDOMEvent.target || aDOMEvent.srcElement) == _DOMPasteboardElement)
+ return;
+
+ var keyCode = _keyCode,
+ charCode = aDOMEvent.keyCode || aDOMEvent.charCode,
+ isARepeat = (_charCodes[keyCode] != nil);
+
+ _charCodes[keyCode] = charCode;
+
+ var characters = String.fromCharCode(charCode),
+ charactersIgnoringModifiers = characters.toLowerCase();
+
+ event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
+ timestamp:timestamp windowNumber:windowNumber context:nil
+ characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:keyCode];
+
+ if (isNativePasteEvent)
+ {
+ _pasteboardKeyDownEvent = event;
+
+ window.setNativeTimeout(function () { [self _checkPasteboardElement] }, 0);
+
+ return;
+ }
+
+ break;
+
+ case "keyup": var keyCode = aDOMEvent.keyCode,
+ charCode = _charCodes[keyCode];
+
+ _charCodes[keyCode] = nil;
+
+ var characters = String.fromCharCode(charCode),
+ charactersIgnoringModifiers = characters.toLowerCase();
+
+ if (!(modifierFlags & CPShiftKeyMask))
+ characters = charactersIgnoringModifiers;
+
+ event = [CPEvent keyEventWithType:CPKeyUp location:location modifierFlags:modifierFlags
+ timestamp: timestamp windowNumber:windowNumber context:nil
+ characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:keyCode];
+ break;
+ }
+
+ if (event)
+ {
+ event._DOMEvent = aDOMEvent;
+
+ [CPApp sendEvent:event];
+
+ if (isNativeCopyOrCutEvent)
+ {
+ var pasteboard = [CPPasteboard generalPasteboard],
+ types = [pasteboard types];
+
+ // If this is a native copy event, then check if the pasteboard has anything in it.
+ if (types.length)
+ {
+ if ([types indexOfObjectIdenticalTo:CPStringPboardType] != CPNotFound)
+ _DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType];
+ else
+ _DOMPasteboardElement.value = [pasteboard _generateStateUID];
+
+ _DOMPasteboardElement.select();
+
+ window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0);
+ }
+
+ return;
+ }
+ }
+
+ if (StopDOMEventPropagation)
+ CPDOMEventStop(aDOMEvent, self);
+
+ [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
+
+}
+
+- (void)scrollEvent:(DOMEvent)aDOMEvent
+{
+ if(!aDOMEvent)
+ aDOMEvent = window.event;
+
+ if (CPFeatureIsCompatible(CPJavaScriptMouseWheelValues_8_15))
+ {
+ var x = 0.0,
+ y = 0.0,
+ element = aDOMEvent.target;
+
+ while (element.nodeType !== 1)
+ element = element.parentNode;
+
+ if (element.offsetParent)
+ {
+ do
+ {
+ x += element.offsetLeft;
+ y += element.offsetTop;
+
+ } while (element = element.offsetParent);
+ }
+
+ var location = _CGPointMake((x + ((aDOMEvent.clientX - 8) / 15)), (y + ((aDOMEvent.clientY - 8) / 15)));
+ }
+ else
+ var location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY);
+
+ var deltaX = 0.0,
+ deltaY = 0.0,
+ windowNumber = 0,
+ timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
+ modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
+ (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
+ (aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
+ (aDOMEvent.metaKey ? CPCommandKeyMask : 0);
+
+ StopDOMEventPropagation = YES;
+
+ var theWindow = [self hitTest:location];
+
+ if (!theWindow)
+ return;
+
+ var windowNumber = [theWindow windowNumber];
+
+ location = [theWindow convertBridgeToBase:location];
+
+ if(typeof aDOMEvent.wheelDeltaX != "undefined")
+ {
+ deltaX = aDOMEvent.wheelDeltaX / 120.0;
+ deltaY = aDOMEvent.wheelDeltaY / 120.0;
+ }
+
+ else if (aDOMEvent.wheelDelta)
+ deltaY = aDOMEvent.wheelDelta / 120.0;
+
+ else if (aDOMEvent.detail)
+ deltaY = -aDOMEvent.detail / 3.0;
+
+ else
+ return;
+
+ if(!CPFeatureIsCompatible(CPJavaScriptNegativeMouseWheelValues))
+ {
+ deltaX = -deltaX;
+ deltaY = -deltaY;
+ }
+
+ var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags
+ timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0 ];
+
+ event._DOMEvent = aDOMEvent;
+ event._deltaX = deltaX;
+ event._deltaY = deltaY;
+
+ [CPApp sendEvent:event];
+
+ if (StopDOMEventPropagation)
+ CPDOMEventStop(aDOMEvent, self);
+
+ [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
+}
+
+- (void)resizeEvent:(DOMEvent)aDOMEvent
+{
+ // FIXME: This is not the right way to do this.
+ // We should pay attention to mouse down and mouse up in conjunction with this.
+ //window.liveResize = YES;
+
+ var oldSize = [self contentRect].size;
+
+ [self updateFromNativeContentRect];
+
+ var levels = _windowLevels,
+ layers = _windowLayers,
+ levelCount = levels.length;
+
+ while (levelCount--)
+ {
+ var windows = [layers objectForKey:levels[levelCount]]._windows,
+ windowCount = windows.length;
+
+ while (windowCount--)
+ [windows[windowCount] resizeWithOldPlatformWindowSize:oldSize];
+ }
+
+ //window.liveResize = NO;
+
+ [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
+}
+
+- (void)touchEvent:(DOMEvent)aDOMEvent
+{
+ if (aDOMEvent.touches && (aDOMEvent.touches.length == 1 || (aDOMEvent.touches.length == 0 && aDOMEvent.changedTouches.length == 1)))
+ {
+ var newEvent = {};
+
+ switch(aDOMEvent.type)
+ {
+ case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown;
+ break;
+ case CPDOMEventTouchEnd: newEvent.type = CPDOMEventMouseUp;
+ break;
+ case CPDOMEventTouchMove: newEvent.type = CPDOMEventMouseMoved;
+ break;
+ case CPDOMEventTouchCancel: newEvent.type = CPDOMEventMouseUp;
+ break;
+ }
+
+ var touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0];
+
+ newEvent.clientX = touch.clientX;
+ newEvent.clientY = touch.clientY;
+
+ newEvent.timestamp = aDOMEvent.timestamp;
+ newEvent.target = aDOMEvent.target;
+
+ newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false;
+
+ newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()};
+ newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()};
+
+ [self _bridgeMouseEvent:newEvent];
+
+ return;
+ }
+ else
+ {
+ if (aDOMEvent.preventDefault)
+ aDOMEvent.preventDefault();
+
+ if (aDOMEvent.stopPropagation)
+ aDOMEvent.stopPropagation();
+ }
+ // handle touch cases specifically
+}
+
+- (void)mouseEvent:(DOMEvent)aDOMEvent
+{
+ var type = _overriddenEventType || aDOMEvent.type;
+
+ // IE's event order is down, up, up, dblclick, so we have create these events artificially.
+ if (type === @"dblclick")
+ {
+ _overriddenEventType = CPDOMEventMouseDown;
+ [self _bridgeMouseEvent:aDOMEvent];
+
+ _overriddenEventType = CPDOMEventMouseUp;
+ [self _bridgeMouseEvent:aDOMEvent];
+
+ _overriddenEventType = nil;
+
+ return;
+ }
+
+ var event,
+ location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY),
+ timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
+ sourceElement = (aDOMEvent.target || aDOMEvent.srcElement),
+ windowNumber = 0,
+ modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
+ (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
+ (aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
+ (aDOMEvent.metaKey ? CPCommandKeyMask : 0);
+
+ StopDOMEventPropagation = YES;
+
+ if (_mouseDownWindow)
+ windowNumber = [_mouseDownWindow windowNumber];
+
+ else
+ {
+ var theWindow = [self hitTest:location];
+
+ if ((aDOMEvent.type === CPDOMEventMouseDown) && theWindow)
+ _mouseDownWindow = theWindow;
+
+ windowNumber = [theWindow windowNumber];
+ }
+
+ if (windowNumber)
+ location = [CPApp._windows[windowNumber] convertPlatformWindowToBase:location];
+
+ if (type === "mouseup")
+ {
+ if(_mouseIsDown)
+ {
+ event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0);
+
+ _mouseIsDown = NO;
+ _lastMouseUp = event;
+ _mouseDownWindow = nil;
+ }
+
+ if(_DOMEventMode)
+ {
+ _DOMEventMode = NO;
+ return;
+ }
+ }
+
+ else if (type === "mousedown")
+ {
+ if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement)
+ {
+ if ([CPPlatform supportsDragAndDrop])
+ {
+ _DOMBodyElement.setAttribute("draggable", "false");
+ _DOMBodyElement.style["-khtml-user-drag"] = "none";
+ }
+
+ _DOMEventMode = YES;
+ _mouseIsDown = YES;
+
+ //fake a down and up event so that event tracking mode will work correctly
+ [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:location modifierFlags:modifierFlags
+ timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
+ clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
+
+ [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseUp location:location modifierFlags:modifierFlags
+ timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
+ clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
+
+ return;
+ }
+ else if ([CPPlatform supportsDragAndDrop])
+ {
+ _DOMBodyElement.setAttribute("draggable", "true");
+ _DOMBodyElement.style["-khtml-user-drag"] = "element";
+ }
+
+ event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0);
+
+ _mouseIsDown = YES;
+ _lastMouseDown = event;
+ }
+
+ else // if (type === "mousemove" || type === "drag")
+ {
+ if (_DOMEventMode)
+ return;
+
+ event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? CPLeftMouseDragged : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0);
+ }
+
+ var isDragging = [[CPDragServer sharedDragServer] isDragging];
+
+ if (event && (!isDragging || !supportsNativeDragAndDrop))
+ {
+ event._DOMEvent = aDOMEvent;
+
+ [CPApp sendEvent:event];
+ }
+
+ if (StopDOMEventPropagation && (!supportsNativeDragAndDrop || type !== "mousedown" && !isDragging))
+ CPDOMEventStop(aDOMEvent, self);
+
+ [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
+}
+
+ (CPArray)orderedWindowsAtLevel:(int)aLevel
+{
+ var layer = [self layerAtLevel:aLevel create:NO];
+
+ if (!layer)
+ return [];
+
+ return [layer orderedWindows];
+}
+
+- (CPDOMWindowLayer)layerAtLevel:(int)aLevel create:(BOOL)aFlag
+{
+ var layer = [_windowLayers objectForKey:aLevel];
+
+ // If the layer doesn't currently exist, and the create flag is true,
+ // create the layer.
+ if (!layer && aFlag)
+ {
+ layer = [[CPDOMWindowLayer alloc] initWithLevel:aLevel];
+
+ [_windowLayers setObject:layer forKey:aLevel];
+
+ // Find the nearest layer. This is similar to a binary search,
+ // only we know we won't find the value.
+ var low = 0,
+ high = _windowLevels.length - 1,
+ middle;
+
+ while (low <= high)
+ {
+ middle = FLOOR((low + high) / 2);
+
+ if (_windowLevels[middle] > aLevel)
+ high = middle - 1;
+ else
+ low = middle + 1;
+ }
+
+ [_windowLevels insertObject:aLevel atIndex:_windowLevels[middle] > aLevel ? middle : middle + 1];
+ layer._DOMElement.style.zIndex = aLevel;
+ _DOMBodyElement.appendChild(layer._DOMElement);
+ }
+
+ return layer;
+}
+
+- (void)order:(CPWindowOrderingMode)aPlace window:(CPWindow)aWindow relativeTo:(CPWindow)otherWindow
+{
+ // Grab the appropriate level for the layer, and create it if
+ // necessary (if we are not simply removing the window).
+ var layer = [self layerAtLevel:[aWindow level] create:aPlace != CPWindowOut];
+
+ // Ignore otherWindow, simply remove this window from it's level.
+ // If layer is nil, this will be a no-op.
+ if (aPlace == CPWindowOut)
+ return [layer removeWindow:aWindow];
+
+ // Place the window at the appropriate index.
+ [layer insertWindow:aWindow atIndex:(otherWindow ? (aPlace == CPWindowAbove ? otherWindow._index + 1 : otherWindow._index) : CPNotFound)];
+}
+
+/* @ignore */
+- (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard
+{
+ var levels = _windowLevels,
+ layers = _windowLayers,
+ levelCount = levels.length;
+
+ while (levelCount--)
+ {
+ // Skip any windows above or at the dragging level.
+ if (levels[levelCount] >= CPDraggingWindowLevel)
+ continue;
+
+ var windows = [layers objectForKey:levels[levelCount]]._windows,
+ windowCount = windows.length;
+
+ while (windowCount--)
+ {
+ var theWindow = windows[windowCount];
+
+ if ([theWindow _sharesChromeWithPlatformWindow])
+ return [theWindow _dragHitTest:aPoint pasteboard:aPasteboard];
+
+ if ([theWindow containsPoint:aPoint])
+ return [theWindow _dragHitTest:aPoint pasteboard:aPasteboard];
+ }
+ }
+
+ return nil;
+}
+
+/* @ignore */
+- (void)_propagateCurrentDOMEvent:(BOOL)aFlag
+{
+ StopDOMEventPropagation = !aFlag;
+}
+
+- (CPWindow)hitTest:(CPPoint)location
+{if (self._only) return self._only;
+ var levels = _windowLevels,
+ layers = _windowLayers,
+ levelCount = levels.length,
+ theWindow = nil;
+
+ while (levelCount-- && !theWindow)
+ {
+ var windows = [layers objectForKey:levels[levelCount]]._windows,
+ windowCount = windows.length;
+
+ while (windowCount-- && !theWindow)
+ {
+ var candidateWindow = windows[windowCount];
+
+ if (!candidateWindow._ignoresMouseEvents && [candidateWindow containsPoint:location])
+ theWindow = candidateWindow;
+ }
+ }
+
+ return theWindow;
+}
+
+- (void)_checkPasteboardElement
+{
+ var value = _DOMPasteboardElement.value;
+
+ if ([value length])
+ {
+ var pasteboard = [CPPasteboard generalPasteboard];
+
+ if ([pasteboard _stateUID] != value)
+ {
+ [pasteboard declareTypes:[CPStringPboardType] owner:self];
+
+ [pasteboard setString:value forType:CPStringPboardType];
+ }
+ }
+
+ [self _clearPasteboardElement];
+
+ [CPApp sendEvent:_pasteboardKeyDownEvent];
+
+ _pasteboardKeyDownEvent = nil;
+
+ [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
+}
+
+- (void)_clearPasteboardElement
+{
+ _DOMPasteboardElement.value = "";
+ _DOMPasteboardElement.blur();
+}
+
+/*!
+ When using command (mac) or control (windows), keys are propagated to the browser by default.
+ To prevent a character key from propagating (to prevent its default action, and instead use it
+ in your own application), use these methods. These methods are additive -- the list builds until you clear it.
+
+ @param characters a list of characters to stop propagating keypresses to the browser.
+*/
++ (void)preventCharacterKeysFromPropagating:(CPArray)characters
+{
+ for(var i=characters.length; i>0; i--)
+ CharacterKeysToPrevent[""+characters[i-1].toLowerCase()] = YES;
+}
+
+/*!
+ @param character a character to stop propagating keypresses to the browser.
+*/
++ (void)preventCharacterKeyFromPropagating:(CPString)character
+{
+ CharacterKeysToPrevent[character.toLowerCase()] = YES;
+}
+
+/*!
+ Clear the list of characters for which we are not sending keypresses to the browser.
+*/
++ (void)clearCharacterKeysToPreventFromPropagating
+{
+ CharacterKeysToPrevent = {};
+}
+
+/*!
+ Prevent these keyCodes from sending their keypresses to the browser.
+ @param keyCodes an array of keycodes to prevent propagation.
+*/
++ (void)preventKeyCodesFromPropagating:(CPArray)keyCodes
+{
+ for(var i=keyCodes.length; i>0; i--)
+ KeyCodesToPrevent[keyCodes[i-1]] = YES;
+}
+
+/*!
+ Prevent this keyCode from sending its key events to the browser.
+ @param keyCode a keycode to prevent propagation.
+*/
++ (void)preventKeyCodeFromPropagating:(CPString)keyCode
+{
+ KeyCodesToPrevent[keyCode] = YES;
+}
+
+/*!
+ Clear the list of keyCodes for which we are not sending keypresses to the browser.
+*/
++ (void)clearKeyCodesToPreventFromPropagating
+{
+ KeyCodesToPrevent = {};
+}
+
+@end
+
+var CPEventClass = [CPEvent class];
+
+var _CPEventFromNativeMouseEvent = function(aNativeEvent, anEventType, aPoint, modifierFlags, aTimestamp, aWindowNumber, aGraphicsContext, anEventNumber, aClickCount, aPressure)
+{
+ aNativeEvent.isa = CPEventClass;
+
+ aNativeEvent._type = anEventType;
+ aNativeEvent._location = aPoint;
+ aNativeEvent._modifierFlags = modifierFlags;
+ aNativeEvent._timestamp = aTimestamp;
+ aNativeEvent._windowNumber = aWindowNumber;
+ aNativeEvent._window = nil;
+ aNativeEvent._context = aGraphicsContext;
+ aNativeEvent._eventNumber = anEventNumber;
+ aNativeEvent._clickCount = aClickCount;
+ aNativeEvent._pressure = aPressure;
+
+ return aNativeEvent;
+}
+
+var CLICK_SPACE_DELTA = 5.0,
+ CLICK_TIME_DELTA = (typeof document != "undefined" && document.addEventListener) ? 350.0 : 1000.0;
+
+var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation)
+{
+ if (!aComparisonEvent)
+ return 1;
+
+ var comparisonLocation = [aComparisonEvent locationInWindow];
+
+ return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA &&
+ ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA &&
+ ABS(comparisonLocation.y - aLocation.y) < CLICK_SPACE_DELTA) ? [aComparisonEvent clickCount] + 1 : 1;
+}
+
+var CPDOMEventStop = function(aDOMEvent, aPlatformWindow)
+{
+ // IE Model
+ aDOMEvent.cancelBubble = true;
+ aDOMEvent.returnValue = false;
+
+ // W3C Model
+ if (aDOMEvent.preventDefault)
+ aDOMEvent.preventDefault();
+
+ if (aDOMEvent.stopPropagation)
+ aDOMEvent.stopPropagation();
+
+ if (aDOMEvent.type === CPDOMEventMouseDown)
+ {
+ aPlatformWindow._DOMFocusElement.focus();
+ aPlatformWindow._DOMFocusElement.blur();
+ }
+}
+
+function CPWindowObjectList()
+{
+ var platformWindow = [CPPlatformWindow primaryPlatformWindow],
+ levels = platformWindow._windowLevels,
+ layers = platformWindow._windowLayers,
+ levelCount = levels.length,
+ windowObjects = [];
+
+ while (levelCount--)
+ {
+ var windows = [layers objectForKey:levels[levelCount]]._windows,
+ windowCount = windows.length;
+
+ while (windowCount--)
+ windowObjects.push(windows[windowCount]);
+ }
+
+ return windowObjects;
+}
+
+function CPWindowList()
+{
+ var platformWindow = [CPPlatformWindow primaryPlatformWindow],
+ levels = platformWindow._windowLevels,
+ layers = platformWindow._windowLayers,
+ levelCount = levels.length,
+ windowNumbers = [];
+
+ while (levelCount--)
+ {
+ var windows = [layers objectForKey:levels[levelCount]]._windows,
+ windowCount = windows.length;
+
+ while (windowCount--)
+ windowNumbers.push([windows[windowCount] windowNumber]);
+ }
+
+ return windowNumbers;
+}
diff --git a/AppKit/Rakefile b/AppKit/Rakefile
index 90a77b47c..a93beb55c 100644
--- a/AppKit/Rakefile
+++ b/AppKit/Rakefile
@@ -17,7 +17,7 @@ AppKitFiles = FileList['**/*.j'].exclude('CoreGraphics/CGContextCanvas.j', 'Core
ObjectiveJ::BundleTask.new(:AppKit) do |t|
t.name = 'AppKit'
t.identifier = 'com.280n.AppKit'
- t.version = '0.7.0'
+ t.version = '0.7.1'
t.author = '280 North, Inc.'
t.email = 'feedback @nospam@ 280north.com'
t.summary = 'AppKit classes for Cappuccino'
@@ -53,6 +53,7 @@ file_d $THEME_PRODUCT => ThemeFiles << $ENVIRONMENT_PRODUCT do
puts str
end
end
+ rake abort if ($? != 0)
end
task :build => [:build_subprojects, :AppKit, $ENVIRONMENT_PRODUCT, $THEME_PRODUCT, $ENVIRONMENT_THEME_PRODUCT]
diff --git a/AppKit/Resources/CPSearchField/CPSearchFieldCancel.png b/AppKit/Resources/CPSearchField/CPSearchFieldCancel.png
new file mode 100644
index 000000000..fc32eabb3
Binary files /dev/null and b/AppKit/Resources/CPSearchField/CPSearchFieldCancel.png differ
diff --git a/AppKit/Resources/CPSearchField/CPSearchFieldCancelPressed.png b/AppKit/Resources/CPSearchField/CPSearchFieldCancelPressed.png
new file mode 100644
index 000000000..e4fc62e23
Binary files /dev/null and b/AppKit/Resources/CPSearchField/CPSearchFieldCancelPressed.png differ
diff --git a/AppKit/Resources/CPSearchField/CPSearchFieldFind.png b/AppKit/Resources/CPSearchField/CPSearchFieldFind.png
new file mode 100644
index 000000000..0dcd0cd53
Binary files /dev/null and b/AppKit/Resources/CPSearchField/CPSearchFieldFind.png differ
diff --git a/AppKit/Resources/CPSearchField/CPSearchFieldSearch.png b/AppKit/Resources/CPSearchField/CPSearchFieldSearch.png
new file mode 100644
index 000000000..77434b8a2
Binary files /dev/null and b/AppKit/Resources/CPSearchField/CPSearchFieldSearch.png differ
diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-disabled-center.png b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-center.png
new file mode 100644
index 000000000..2f25f5252
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-center.png differ
diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-disabled-left.png b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-left.png
new file mode 100644
index 000000000..8ae5e8eb3
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-left.png differ
diff --git a/AppKit/Themes/Aristo/Resources/button-bezel-disabled-right.png b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-right.png
new file mode 100644
index 000000000..92127238a
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/button-bezel-disabled-right.png differ
diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel-disabled.png b/AppKit/Themes/Aristo/Resources/check-box-bezel-disabled.png
new file mode 100644
index 000000000..c1246094f
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/check-box-bezel-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel-highlighted.png b/AppKit/Themes/Aristo/Resources/check-box-bezel-highlighted.png
new file mode 100644
index 000000000..51e26047e
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/check-box-bezel-highlighted.png differ
diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-disabled.png b/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-disabled.png
new file mode 100644
index 000000000..fea5c786c
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-highlighted.png b/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-highlighted.png
new file mode 100644
index 000000000..dc2a5f089
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/check-box-bezel-selected-highlighted.png differ
diff --git a/AppKit/Themes/Aristo/Resources/radio-bezel-disabled.png b/AppKit/Themes/Aristo/Resources/radio-bezel-disabled.png
new file mode 100644
index 000000000..76d3c79d7
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/radio-bezel-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/radio-bezel-highlighted.png b/AppKit/Themes/Aristo/Resources/radio-bezel-highlighted.png
new file mode 100644
index 000000000..6f16d4803
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/radio-bezel-highlighted.png differ
diff --git a/AppKit/Themes/Aristo/Resources/radio-bezel-selected-disabled.png b/AppKit/Themes/Aristo/Resources/radio-bezel-selected-disabled.png
new file mode 100644
index 000000000..7d5d963df
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/radio-bezel-selected-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/radio-bezel-selected-highlighted.png b/AppKit/Themes/Aristo/Resources/radio-bezel-selected-highlighted.png
new file mode 100644
index 000000000..aa4fbc1d6
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/radio-bezel-selected-highlighted.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-down-arrow-disabled.png b/AppKit/Themes/Aristo/Resources/scroller-down-arrow-disabled.png
index f6f302091..20d0883f3 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-down-arrow-disabled.png and b/AppKit/Themes/Aristo/Resources/scroller-down-arrow-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-down-arrow-highlighted.png b/AppKit/Themes/Aristo/Resources/scroller-down-arrow-highlighted.png
index 00f3466ca..ce6759743 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-down-arrow-highlighted.png and b/AppKit/Themes/Aristo/Resources/scroller-down-arrow-highlighted.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-down-arrow.png b/AppKit/Themes/Aristo/Resources/scroller-down-arrow.png
index e5a516aa6..d16693f25 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-down-arrow.png and b/AppKit/Themes/Aristo/Resources/scroller-down-arrow.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-center.png b/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-center.png
index 514e235f7..abd26ef61 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-center.png and b/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-center.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-left.png b/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-left.png
index 897505467..b4cf2610a 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-left.png and b/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-left.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-right.png b/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-right.png
index 2e34e2ceb..af81149bd 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-right.png and b/AppKit/Themes/Aristo/Resources/scroller-horizontal-knob-right.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-horizontal-track-disabled.png b/AppKit/Themes/Aristo/Resources/scroller-horizontal-track-disabled.png
index cd9002943..7e0745278 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-horizontal-track-disabled.png and b/AppKit/Themes/Aristo/Resources/scroller-horizontal-track-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-horizontal-track.png b/AppKit/Themes/Aristo/Resources/scroller-horizontal-track.png
index 3043f2628..782f5f069 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-horizontal-track.png and b/AppKit/Themes/Aristo/Resources/scroller-horizontal-track.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-left-arrow-disabled.png b/AppKit/Themes/Aristo/Resources/scroller-left-arrow-disabled.png
index 34e8f9b77..3371f342f 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-left-arrow-disabled.png and b/AppKit/Themes/Aristo/Resources/scroller-left-arrow-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-left-arrow-highlighted.png b/AppKit/Themes/Aristo/Resources/scroller-left-arrow-highlighted.png
index 3c88f8e38..5079dda5a 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-left-arrow-highlighted.png and b/AppKit/Themes/Aristo/Resources/scroller-left-arrow-highlighted.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-left-arrow.png b/AppKit/Themes/Aristo/Resources/scroller-left-arrow.png
index ff8c1459a..3d2fdcf62 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-left-arrow.png and b/AppKit/Themes/Aristo/Resources/scroller-left-arrow.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-right-arrow-disabled.png b/AppKit/Themes/Aristo/Resources/scroller-right-arrow-disabled.png
index 2d154f203..dc63d7018 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-right-arrow-disabled.png and b/AppKit/Themes/Aristo/Resources/scroller-right-arrow-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-right-arrow-highlighted.png b/AppKit/Themes/Aristo/Resources/scroller-right-arrow-highlighted.png
index b924bb18a..4606638c1 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-right-arrow-highlighted.png and b/AppKit/Themes/Aristo/Resources/scroller-right-arrow-highlighted.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-right-arrow.png b/AppKit/Themes/Aristo/Resources/scroller-right-arrow.png
index 1ad602ea1..96b6ba49d 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-right-arrow.png and b/AppKit/Themes/Aristo/Resources/scroller-right-arrow.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-up-arrow-disabled.png b/AppKit/Themes/Aristo/Resources/scroller-up-arrow-disabled.png
index 7da7d03e7..0142d9ca0 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-up-arrow-disabled.png and b/AppKit/Themes/Aristo/Resources/scroller-up-arrow-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-up-arrow-highlighted.png b/AppKit/Themes/Aristo/Resources/scroller-up-arrow-highlighted.png
index 52c58d793..c5e96d1d7 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-up-arrow-highlighted.png and b/AppKit/Themes/Aristo/Resources/scroller-up-arrow-highlighted.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-up-arrow.png b/AppKit/Themes/Aristo/Resources/scroller-up-arrow.png
index ce98d9f08..6be0e2dfa 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-up-arrow.png and b/AppKit/Themes/Aristo/Resources/scroller-up-arrow.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-bottom.png b/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-bottom.png
index 93be3702c..a1140fd69 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-bottom.png and b/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-bottom.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-center.png b/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-center.png
index 0e71759ec..fbdb8822e 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-center.png and b/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-center.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-top.png b/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-top.png
index 297b28ac0..f7d6c3875 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-top.png and b/AppKit/Themes/Aristo/Resources/scroller-vertical-knob-top.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-vertical-track-disabled.png b/AppKit/Themes/Aristo/Resources/scroller-vertical-track-disabled.png
index a3b3544ef..7954ac948 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-vertical-track-disabled.png and b/AppKit/Themes/Aristo/Resources/scroller-vertical-track-disabled.png differ
diff --git a/AppKit/Themes/Aristo/Resources/scroller-vertical-track.png b/AppKit/Themes/Aristo/Resources/scroller-vertical-track.png
index 9a2c7d9cb..7954ac948 100644
Binary files a/AppKit/Themes/Aristo/Resources/scroller-vertical-track.png and b/AppKit/Themes/Aristo/Resources/scroller-vertical-track.png differ
diff --git a/AppKit/Themes/Aristo/Resources/CircularSliderBezel.png b/AppKit/Themes/Aristo/Resources/slider-circular-bezel.png
similarity index 100%
rename from AppKit/Themes/Aristo/Resources/CircularSliderBezel.png
rename to AppKit/Themes/Aristo/Resources/slider-circular-bezel.png
diff --git a/AppKit/Themes/Aristo/Resources/CircularSliderKnob.png b/AppKit/Themes/Aristo/Resources/slider-circular-knob.png
similarity index 100%
rename from AppKit/Themes/Aristo/Resources/CircularSliderKnob.png
rename to AppKit/Themes/Aristo/Resources/slider-circular-knob.png
diff --git a/AppKit/Themes/Aristo/Resources/spinner.gif b/AppKit/Themes/Aristo/Resources/spinner.gif
new file mode 100644
index 000000000..06dbc2bc2
Binary files /dev/null and b/AppKit/Themes/Aristo/Resources/spinner.gif differ
diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j
index f5ecf0d27..8e8c96a6a 100644
--- a/AppKit/Themes/Aristo/ThemeDescriptors.j
+++ b/AppKit/Themes/Aristo/ThemeDescriptors.j
@@ -53,6 +53,14 @@
[_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-center.png" size:CGSizeMake(1.0, 24.0)],
[_CPCibCustomResource imageResourceWithName:"default-button-bezel-highlighted-right.png" size:CGSizeMake(4.0, 24.0)]
]
+ isVertical:NO]],
+
+ disabledBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
+ [
+ [_CPCibCustomResource imageResourceWithName:"button-bezel-disabled-left.png" size:CGSizeMake(4.0, 24.0)],
+ [_CPCibCustomResource imageResourceWithName:"button-bezel-disabled-center.png" size:CGSizeMake(1.0, 24.0)],
+ [_CPCibCustomResource imageResourceWithName:"button-bezel-disabled-right.png" size:CGSizeMake(4.0, 24.0)]
+ ]
isVertical:NO]];
[button setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateBordered];
@@ -65,6 +73,10 @@
[button setValue:highlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted];
[button setValue:CGInsetMake(0.0, 5.0, 0.0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered];
+ [button setValue:[CPColor colorWithCalibratedWhite:0.6 alpha:1.0] forThemeAttribute:@"text-color" inState:CPThemeStateDisabled];
+ [button setValue:disabledBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled];
+ [button setValue:disabledBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDefault|CPThemeStateDisabled];
+
[button setValue:defaultBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateDefault];
[button setValue:defaultHighlightedBezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered|CPThemeStateHighlighted|CPThemeStateDefault];
[button setValue:[CPColor colorWithCalibratedRed:13.0/255.0 green:51.0/255.0 blue:70.0/255.0 alpha:1.0] forThemeAttribute:@"text-color" inState:CPThemeStateDefault];
@@ -152,92 +164,94 @@
+ (CPScroller)themedVerticalScroller
{
- var scroller = [[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, 17.0, 170.0)],
- trackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-vertical-track.png" size:CGSizeMake(17.0, 1.0)]),
- disabledTrackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-vertical-track-disabled.png" size:CGSizeMake(17.0, 1.0)]);
+ var scroller = [[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, 15.0, 170.0)],
+ trackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-vertical-track.png" size:CGSizeMake(15.0, 1.0)]),
+ disabledTrackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-vertical-track-disabled.png" size:CGSizeMake(15.0, 1.0)]);
- [scroller setValue:19.0 forThemeAttribute:@"minimum-knob-length" inState:CPThemeStateVertical];
- [scroller setValue:CGInsetMake(0.0, 1.0, 0.0, 1.0) forThemeAttribute:@"knob-inset" inState:CPThemeStateVertical];
- [scroller setValue:CGInsetMake(-9.0, 0.0, -9.0, 0.0) forThemeAttribute:@"track-inset" inState:CPThemeStateVertical];
+ [scroller setValue:17.0 forThemeAttribute:@"minimum-knob-length" inState:CPThemeStateVertical];
+ [scroller setValue:CGInsetMake(0.0, 0.0, 0.0, 1.0) forThemeAttribute:@"knob-inset" inState:CPThemeStateVertical];
+ [scroller setValue:CGInsetMake(-10.0, 0.0, -10.0, 0.0) forThemeAttribute:@"track-inset" inState:CPThemeStateVertical];
[scroller setValue:trackColor forThemeAttribute:@"knob-slot-color" inState:CPThemeStateVertical];
[scroller setValue:disabledTrackColor forThemeAttribute:@"knob-slot-color" inState:CPThemeStateVertical | CPThemeStateDisabled];
- var arrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow.png" size:CGSizeMake(17.0, 30.0)]),
- highlightedArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow-highlighted.png" size:CGSizeMake(17.0, 30.0)]),
- disabledArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow-disabled.png" size:CGSizeMake(17.0, 30.0)]);
+ var arrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow.png" size:CGSizeMake(15.0, 25.0)]),
+ highlightedArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow-highlighted.png" size:CGSizeMake(15.0, 25.0)]),
+ disabledArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-up-arrow-disabled.png" size:CGSizeMake(15.0, 25.0)]);
- [scroller setValue:CGSizeMake(17.0, 30.0) forThemeAttribute:@"decrement-line-size" inState:CPThemeStateVertical];
+ [scroller setValue:CGSizeMake(15.0, 25.0) forThemeAttribute:@"decrement-line-size" inState:CPThemeStateVertical];
[scroller setValue:arrowColor forThemeAttribute:@"decrement-line-color" inState:CPThemeStateVertical];
[scroller setValue:highlightedArrowColor forThemeAttribute:@"decrement-line-color" inState:CPThemeStateVertical | CPThemeStateHighlighted],
[scroller setValue:disabledArrowColor forThemeAttribute:@"decrement-line-color" inState:CPThemeStateVertical | CPThemeStateDisabled];
- var arrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow.png" size:CGSizeMake(17.0, 30.0)]),
- highlightedArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow-highlighted.png" size:CGSizeMake(17.0, 30.0)]),
- disabledArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow-disabled.png" size:CGSizeMake(17.0, 30.0)]);
+ var arrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow.png" size:CGSizeMake(15.0, 25.0)]),
+ highlightedArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow-highlighted.png" size:CGSizeMake(15.0, 25.0)]),
+ disabledArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-down-arrow-disabled.png" size:CGSizeMake(15.0, 25.0)]);
- [scroller setValue:CGSizeMake(17.0, 30.0) forThemeAttribute:@"increment-line-size" inState:CPThemeStateVertical];
+ [scroller setValue:CGSizeMake(15.0, 25.0) forThemeAttribute:@"increment-line-size" inState:CPThemeStateVertical];
[scroller setValue:arrowColor forThemeAttribute:@"increment-line-color" inState:CPThemeStateVertical];
[scroller setValue:highlightedArrowColor forThemeAttribute:@"increment-line-color" inState:CPThemeStateVertical | CPThemeStateHighlighted];
[scroller setValue:disabledArrowColor forThemeAttribute:@"increment-line-color" inState:CPThemeStateVertical | CPThemeStateDisabled];
var knobColor = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
[
- [_CPCibCustomResource imageResourceWithName:"scroller-vertical-knob-top.png" size:CGSizeMake(15.0, 8.0)],
- [_CPCibCustomResource imageResourceWithName:"scroller-vertical-knob-center.png" size:CGSizeMake(15.0, 1.0)],
- [_CPCibCustomResource imageResourceWithName:"scroller-vertical-knob-bottom.png" size:CGSizeMake(15.0, 10.0)]
+ [_CPCibCustomResource imageResourceWithName:"scroller-vertical-knob-top.png" size:CGSizeMake(14.0, 8.0)],
+ [_CPCibCustomResource imageResourceWithName:"scroller-vertical-knob-center.png" size:CGSizeMake(14.0, 1.0)],
+ [_CPCibCustomResource imageResourceWithName:"scroller-vertical-knob-bottom.png" size:CGSizeMake(14.0, 8.0)]
]
isVertical:YES]);
[scroller setValue:knobColor forThemeAttribute:@"knob-color" inState:CPThemeStateVertical];
- [scroller setFloatValue:0.1 knobProportion:0.5];
+ [scroller setFloatValue:0.1];
+ [scroller setKnobProportion:0.5];
return scroller;
}
+ (CPScroller)themedHorizontalScroller
{
- var scroller = [[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, 170.0, 17.0)],
- trackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-horizontal-track.png" size:CGSizeMake(1.0, 17.0)]),
- disabledTrackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-horizontal-track-disabled.png" size:CGSizeMake(17.0, 1.0)]);
+ var scroller = [[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, 170.0, 15.0)],
+ trackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-horizontal-track.png" size:CGSizeMake(1.0, 15.0)]),
+ disabledTrackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-horizontal-track-disabled.png" size:CGSizeMake(1.0, 15.0)]);
- [scroller setValue:19.0 forThemeAttribute:@"minimum-knob-length"];
- [scroller setValue:CGInsetMake(2.0, 0.0, 0.0, 0.0) forThemeAttribute:@"knob-inset"];
+ [scroller setValue:17.0 forThemeAttribute:@"minimum-knob-length"];
+ [scroller setValue:CGInsetMake(1.0, 0.0, 0.0, 0.0) forThemeAttribute:@"knob-inset"];
[scroller setValue:CGInsetMake(0.0, -10.0, 0.0, -11.0) forThemeAttribute:@"track-inset"];
[scroller setValue:trackColor forThemeAttribute:@"knob-slot-color"];
[scroller setValue:disabledTrackColor forThemeAttribute:@"knob-slot-color" inState:CPThemeStateDisabled];
- var arrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-left-arrow.png" size:CGSizeMake(32.0, 17.0)]),
- highlightedArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-left-arrow-highlighted.png" size:CGSizeMake(32.0, 17.0)]),
- disabledArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-left-arrow-disabled.png" size:CGSizeMake(32.0, 17.0)]);
+ var arrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-left-arrow.png" size:CGSizeMake(25.0, 15.0)]),
+ highlightedArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-left-arrow-highlighted.png" size:CGSizeMake(25.0, 15.0)]),
+ disabledArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-left-arrow-disabled.png" size:CGSizeMake(25.0, 15.0)]);
- [scroller setValue:CGSizeMake(32.0, 17.0) forThemeAttribute:@"decrement-line-size"];
+ [scroller setValue:CGSizeMake(25.0, 15.0) forThemeAttribute:@"decrement-line-size"];
[scroller setValue:arrowColor forThemeAttribute:@"decrement-line-color"];
[scroller setValue:highlightedArrowColor forThemeAttribute:@"decrement-line-color" inState:CPThemeStateHighlighted],
[scroller setValue:disabledArrowColor forThemeAttribute:@"decrement-line-color" inState:CPThemeStateDisabled];
- var arrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-right-arrow.png" size:CGSizeMake(31.0, 17.0)]),
- highlightedArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-right-arrow-highlighted.png" size:CGSizeMake(31.0, 17.0)]),
- disabledArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-right-arrow-disabled.png" size:CGSizeMake(31.0, 17.0)]);
+ var arrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-right-arrow.png" size:CGSizeMake(25.0, 15.0)]),
+ highlightedArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-right-arrow-highlighted.png" size:CGSizeMake(25.0, 15.0)]),
+ disabledArrowColor = PatternColor([_CPCibCustomResource imageResourceWithName:"scroller-right-arrow-disabled.png" size:CGSizeMake(25.0, 15.0)]);
- [scroller setValue:CGSizeMake(31.0, 17.0) forThemeAttribute:@"increment-line-size"];
+ [scroller setValue:CGSizeMake(25.0, 15.0) forThemeAttribute:@"increment-line-size"];
[scroller setValue:arrowColor forThemeAttribute:@"increment-line-color"];
[scroller setValue:highlightedArrowColor forThemeAttribute:@"increment-line-color" inState:CPThemeStateHighlighted];
[scroller setValue:disabledArrowColor forThemeAttribute:@"increment-line-color" inState:CPThemeStateDisabled];
var knobColor = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
[
- [_CPCibCustomResource imageResourceWithName:"scroller-horizontal-knob-left.png" size:CGSizeMake(11.0, 15.0)],
- [_CPCibCustomResource imageResourceWithName:"scroller-horizontal-knob-center.png" size:CGSizeMake(1.0, 15.0)],
- [_CPCibCustomResource imageResourceWithName:"scroller-horizontal-knob-right.png" size:CGSizeMake(9.0, 15.0)]
+ [_CPCibCustomResource imageResourceWithName:"scroller-horizontal-knob-left.png" size:CGSizeMake(8.0, 14.0)],
+ [_CPCibCustomResource imageResourceWithName:"scroller-horizontal-knob-center.png" size:CGSizeMake(1.0, 14.0)],
+ [_CPCibCustomResource imageResourceWithName:"scroller-horizontal-knob-right.png" size:CGSizeMake(8.0, 14.0)]
]
isVertical:NO]);
-
+
[scroller setValue:knobColor forThemeAttribute:@"knob-color"];
-
- [scroller setFloatValue:0.1 knobProportion:0.5];
+
+ [scroller setFloatValue:0.1];
+ [scroller setKnobProportion:0.5];
return scroller;
}
@@ -346,6 +360,26 @@
[
[_CPCibCustomResource imageResourceWithName:"radio-bezel-selected.png" size:CGSizeMake(17.0, 17.0)], nil, nil
]
+ isVertical:NO]),
+ bezelColorSelectedHighlighted = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
+ [
+ [_CPCibCustomResource imageResourceWithName:"radio-bezel-selected-highlighted.png" size:CGSizeMake(17.0, 17.0)], nil, nil
+ ]
+ isVertical:NO]),
+ bezelColorSelectedDisabled = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
+ [
+ [_CPCibCustomResource imageResourceWithName:"radio-bezel-selected-disabled.png" size:CGSizeMake(17.0, 17.0)], nil, nil
+ ]
+ isVertical:NO]),
+ bezelColorDisabled = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
+ [
+ [_CPCibCustomResource imageResourceWithName:"radio-bezel-disabled.png" size:CGSizeMake(17.0, 17.0)], nil, nil
+ ]
+ isVertical:NO]),
+ bezelColorHighlighted = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
+ [
+ [_CPCibCustomResource imageResourceWithName:"radio-bezel-highlighted.png" size:CGSizeMake(17.0, 17.0)], nil, nil
+ ]
isVertical:NO]);
[button setValue:CPLeftTextAlignment forThemeAttribute:@"alignment" inState:CPThemeStateBordered];
@@ -353,6 +387,10 @@
[button setValue:CGInsetMake(0.0, 0.0, 0.0, 20.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered];
[button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
[button setValue:bezelColorSelected forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected];
+ [button setValue:bezelColorSelectedHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected | CPThemeStateHighlighted];
+ [button setValue:bezelColorHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
+ [button setValue:bezelColorDisabled forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
+ [button setValue:bezelColorSelectedDisabled forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled | CPThemeStateSelected];
[button setValue:CGSizeMake(0.0, 17.0) forThemeAttribute:@"min-size"];
@@ -374,6 +412,26 @@
[
[_CPCibCustomResource imageResourceWithName:"check-box-bezel-selected.png" size:CGSizeMake(15.0, 16.0)], nil, nil
]
+ isVertical:NO]),
+ bezelColorSelectedHighlighted = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
+ [
+ [_CPCibCustomResource imageResourceWithName:"check-box-bezel-selected-highlighted.png" size:CGSizeMake(15.0, 16.0)], nil, nil
+ ]
+ isVertical:NO]),
+ bezelColorSelectedDisabled = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
+ [
+ [_CPCibCustomResource imageResourceWithName:"check-box-bezel-selected-disabled.png" size:CGSizeMake(15.0, 16.0)], nil, nil
+ ]
+ isVertical:NO]),
+ bezelColorDisabled = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
+ [
+ [_CPCibCustomResource imageResourceWithName:"check-box-bezel-disabled.png" size:CGSizeMake(15.0, 16.0)], nil, nil
+ ]
+ isVertical:NO]),
+ bezelColorHighlighted = PatternColor([[CPThreePartImage alloc] initWithImageSlices:
+ [
+ [_CPCibCustomResource imageResourceWithName:"check-box-bezel-highlighted.png" size:CGSizeMake(15.0, 16.0)], nil, nil
+ ]
isVertical:NO]);
[button setValue:CPLeftTextAlignment forThemeAttribute:@"alignment" inState:CPThemeStateBordered];
@@ -381,6 +439,10 @@
[button setValue:CGInsetMake(0.0, 0.0, 0.0, 20.0) forThemeAttribute:@"content-inset" inState:CPThemeStateBordered];
[button setValue:bezelColor forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
[button setValue:bezelColorSelected forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected];
+ [button setValue:bezelColorSelectedHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateSelected | CPThemeStateHighlighted];
+ [button setValue:bezelColorHighlighted forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
+ [button setValue:bezelColorDisabled forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
+ [button setValue:bezelColorSelectedDisabled forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled | CPThemeStateSelected];
[button setValue:CGSizeMake(0.0, 17.0) forThemeAttribute:@"min-size"];
@@ -516,12 +578,12 @@
+ (CPSlider)themedCircularSlider
{
var slider = [[CPSlider alloc] initWithFrame:CGRectMake(0.0, 0.0, 34.0, 34.0)],
- trackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"circularSliderBezel.png" size:CGSizeMake(34.0, 34.0)]);
+ trackColor = PatternColor([_CPCibCustomResource imageResourceWithName:"slider-circular-bezel.png" size:CGSizeMake(34.0, 34.0)]);
[slider setSliderType:CPCircularSlider];
[slider setValue:trackColor forThemeAttribute:@"track-color" inState:CPThemeStateCircular];
- var knobColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"circularSliderKnob.png" size:CGSizeMake(5.0, 5.0)]],
+ var knobColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"slider-circular-knob.png" size:CGSizeMake(5.0, 5.0)]],
knobHighlightedColor = knobColor;
[slider setValue:CGSizeMake(5.0, 5.0) forThemeAttribute:@"knob-size" inState:CPThemeStateCircular];
diff --git a/AppKit/Tools/BlendKit/Rakefile b/AppKit/Tools/BlendKit/Rakefile
index 47edc0a5f..0de00f5c5 100644
--- a/AppKit/Tools/BlendKit/Rakefile
+++ b/AppKit/Tools/BlendKit/Rakefile
@@ -12,7 +12,7 @@ $BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'BlendKit')
ObjectiveJ::BundleTask.new(:BlendKit) do |t|
t.name = 'BlendKit'
t.identifier = 'com.280n.BlendKit'
- t.version = '0.7.0'
+ t.version = '0.7.1'
t.author = '280 North, Inc.'
t.email = 'feedback @nospam@ 280north.com'
t.summary = 'BlendKit classes for Cappuccino'
diff --git a/AppKit/Tools/blend/Rakefile b/AppKit/Tools/blend/Rakefile
index 010e38fe8..ab4ccf908 100644
--- a/AppKit/Tools/blend/Rakefile
+++ b/AppKit/Tools/blend/Rakefile
@@ -15,7 +15,7 @@ $ENVIRONMENT_LIB_PRODUCT = File.join($ENVIRONMENT_LIB_DIR, 'blend')
ObjectiveJ::BundleTask.new(:blend) do |t|
t.name = 'blend'
t.identifier = 'com.280n.blend'
- t.version = '0.7.0'
+ t.version = '0.7.1'
t.author = '280 North, Inc.'
t.email = 'feedback @nospam@ 280north.com'
t.summary = 'blend classes for Cappuccino'
diff --git a/AppKit/_CPCornerView.j b/AppKit/_CPCornerView.j
new file mode 100644
index 000000000..5a30dfc90
--- /dev/null
+++ b/AppKit/_CPCornerView.j
@@ -0,0 +1,18 @@
+
+@import "CPView.j"
+
+@implementation _CPCornerView : CPView
+{
+}
+
+- (id)initWithFrame:(CGRect)aFrame
+{
+ if (self = [super initWithFrame:aFrame])
+ {
+ [self setBackgroundColor:[CPColor purpleColor]];
+ }
+
+ return self;
+}
+
+@end
diff --git a/AppKit/_CPDisplayServer.j b/AppKit/_CPDisplayServer.j
new file mode 100644
index 000000000..c2dfb3e1e
--- /dev/null
+++ b/AppKit/_CPDisplayServer.j
@@ -0,0 +1,111 @@
+/*
+ * _CPDisplayServer.j
+ * AppKit
+ *
+ * Created by Francisco Tolmasky.
+ * Copyright 2009, 280 North, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "CoreGraphics/CGGeometry.h"
+#include "CoreGraphics/CGAffineTransform.h"
+#include "Platform/DOM/CPDOMDisplayServer.h"
+
+PREPARE_DOM_OPTIMIZATION();
+
+var displayObjects = [],
+ displayObjectsByUID = { },
+
+ layoutObjects = [],
+ layoutObjectsByUID = { },
+
+ runLoop = [CPRunLoop mainRunLoop];
+
+function _CPDisplayServerAddDisplayObject(anObject)
+{
+ var UID = [anObject UID];
+
+ if (typeof displayObjectsByUID[UID] !== "undefined")
+ return;
+
+ var index = displayObjects.length;
+
+ displayObjectsByUID[UID] = index;
+ displayObjects[index] = anObject;
+}
+
+function _CPDisplayServerAddLayoutObject(anObject)
+{
+ var UID = [anObject UID];
+
+ if (typeof layoutObjectsByUID[UID] !== "undefined")
+ return;
+
+ var index = layoutObjects.length;
+
+ layoutObjectsByUID[UID] = index;
+ layoutObjects[index] = anObject;
+}
+
+@implementation _CPDisplayServer : CPObject
+{
+}
+
++ (void)run
+{
+ while (layoutObjects.length || displayObjects.length)
+ {
+ var index = 0;
+
+ for (; index < layoutObjects.length; ++index)
+ {
+ var object = layoutObjects[index];
+
+ delete layoutObjectsByUID[[object UID]];
+ [object layoutIfNeeded];
+ }
+
+ layoutObjects = [];
+ layoutObjectsByUID = { };
+
+ index = 0;
+
+ for (; index < displayObjects.length; ++index)
+ {
+ if (layoutObjects.length)
+ break;
+
+ var object = displayObjects[index];
+
+ delete displayObjectsByUID[[object UID]];
+ [object displayIfNeeded];
+ }
+
+ if (index === displayObjects.length)
+ {
+ displayObjects = [];
+ displayObjectsByUID = { };
+ }
+ else
+ displayObjects = displayObjects.splice(0, index);
+ }
+
+ [runLoop performSelector:@selector(run) target:self argument:nil order:0 modes:[CPDefaultRunLoopMode]];
+}
+
+@end
+
+[_CPDisplayServer run];
diff --git a/AppKit/_CPImageAndTextView.j b/AppKit/_CPImageAndTextView.j
index 8710d269f..c80fed2e7 100644
--- a/AppKit/_CPImageAndTextView.j
+++ b/AppKit/_CPImageAndTextView.j
@@ -511,7 +511,13 @@ var HORIZONTAL_MARGIN = 3.0,
else
{
_DOMImageElement = document.createElement("img");
-
+
+ if ([CPPlatform supportsDragAndDrop])
+ {
+ _DOMImageElement.setAttribute("draggable", "true");
+ _DOMImageElement.style["-khtml-user-drag"] = "element";
+ }
+
var imageStyle = _DOMImageElement.style;
imageStyle.top = "0px";
diff --git a/External/Rakefile b/External/Rakefile
index 0272cabf9..4a50f5de4 100644
--- a/External/Rakefile
+++ b/External/Rakefile
@@ -7,34 +7,48 @@ require 'rake/clean'
require 'fileutils'
-$ENVIRONMENT_NARWHAL_PRODUCT = File.join($ENVIRONMENT_DIR, 'narwhal')
-$ENVIRONMENT_BROWSERJS_PRODUCT = File.join($ENVIRONMENT_NARWHAL_PRODUCT, 'packages', 'browserjs')
-$ENVIRONMENT_JACK_PRODUCT = File.join($ENVIRONMENT_NARWHAL_PRODUCT, 'packages', 'jack')
+$ENVIRONMENT_NARWHAL_PRODUCT = $ENVIRONMENT_DIR
+$ENVIRONMENT_PACKAGES_PRODUCT = File.join($ENVIRONMENT_NARWHAL_PRODUCT, 'packages')
-$ENVIRONMENT_NARWHAL_EXECUTABLE = File.join($ENVIRONMENT_BIN_DIR, 'narwhal')
+$EXTERNALS = ['browserjs', 'jack', 'narwhal', 'ojunit']
+$PACKAGES = ['browserjs', 'jack']
+
+def git_export(source, dest)
+ dest = File.join(File.expand_path(dest), '');
+ system %{cd "#{source}" && git checkout-index -a -f "--prefix=#{dest}"}
+end
file_d $ENVIRONMENT_DIR do
mkdir_p $ENVIRONMENT_DIR
end
-file_d $ENVIRONMENT_NARWHAL_EXECUTABLE do
- FileUtils.ln_sf('../narwhal/bin/narwhal', $ENVIRONMENT_NARWHAL_EXECUTABLE)
-end
-
task :update_submodules do
- if executable_exists? "git"
- system %{cd .. && git submodule init && git submodule update}
- else
- puts "Git not installed"
- rake abort
+ if !ENV['NOSUBUP'] then
+ if executable_exists? "git"
+ system %{cd .. && git submodule init && git submodule update}
+ else
+ puts "Git not installed"
+ rake abort
+ end
end
end
-task :build => [:update_submodules, $ENVIRONMENT_DIR, $ENVIRONMENT_NARWHAL_EXECUTABLE] do
+task :build => [:update_submodules, $ENVIRONMENT_DIR] do
rm_rf($ENVIRONMENT_NARWHAL_PRODUCT)
- cp_r('narwhal', $ENVIRONMENT_NARWHAL_PRODUCT)
- cp_r('browserjs', $ENVIRONMENT_BROWSERJS_PRODUCT)
- cp_r('jack', $ENVIRONMENT_JACK_PRODUCT)
+
+ git_export('narwhal', $ENVIRONMENT_NARWHAL_PRODUCT)
+
+ $PACKAGES.each do |package|
+ git_export(package, File.join($ENVIRONMENT_PACKAGES_PRODUCT, package))
+ end
+
+ symlink_executable(File.join($ENVIRONMENT_PACKAGES_PRODUCT, 'jack', 'bin', 'jackup'))
end
-CLOBBER.include($ENVIRONMENT_NARWHAL_PRODUCT, $ENVIRONMENT_NARWHAL_EXECUTABLE)
+CLOBBER.include($ENVIRONMENT_NARWHAL_PRODUCT)
+
+task :pull do
+ $EXTERNALS.each do |external|
+ system "cd #{external} && git pull origin master"
+ end
+end
\ No newline at end of file
diff --git a/External/browserjs b/External/browserjs
index bd20c3745..b01b92b12 160000
--- a/External/browserjs
+++ b/External/browserjs
@@ -1 +1 @@
-Subproject commit bd20c3745e242f1428a9565e19d9d4825cf3c1b4
+Subproject commit b01b92b128c1ba8258344806bc7df79ce5ffee3c
diff --git a/External/jack b/External/jack
index ffc5ea4a6..68f55a806 160000
--- a/External/jack
+++ b/External/jack
@@ -1 +1 @@
-Subproject commit ffc5ea4a6e84f9eb2979fac4364ebda371a6f8d0
+Subproject commit 68f55a8064d107f8bcd09671f962417d01aef46b
diff --git a/External/narwhal b/External/narwhal
index b91ecad8a..d147c160f 160000
--- a/External/narwhal
+++ b/External/narwhal
@@ -1 +1 @@
-Subproject commit b91ecad8a498467be409bef1ea02119c33b15493
+Subproject commit d147c160f11fdfb7f3c0763acf352b2b0e2713f7
diff --git a/External/ojunit b/External/ojunit
index ca10912c3..352b7e8c6 160000
--- a/External/ojunit
+++ b/External/ojunit
@@ -1 +1 @@
-Subproject commit ca10912c3ff8823d19067d327828812698239c56
+Subproject commit 352b7e8c618729a48d130098368ae0a774ce5f0d
diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j
index 80039d8fd..566eb57bb 100755
--- a/Foundation/CPArray.j
+++ b/Foundation/CPArray.j
@@ -26,6 +26,7 @@
@import "CPSortDescriptor.j"
@import "CPException.j"
+
/* @ignore */
@implementation _CPArrayEnumerator : CPEnumerator
{
@@ -116,7 +117,7 @@
}
/*!
- Creates a new array containing the objects in anArray.
+ Creates a new array containing the objects in \c anArray.
@param anArray Objects in this array will be added to the new array
@return a new CPArray of the provided objects
*/
@@ -126,7 +127,7 @@
}
/*!
- Creates a new array with anObject in it.
+ Creates a new array with \c anObject in it.
@param anObject the object to be added to the array
@return a new CPArray containing a single object
*/
@@ -174,9 +175,9 @@
// Creating an Array
/*!
- Creates a new CPArray from anArray.
+ Creates a new CPArray from \c anArray.
@param anArray objects in this array will be added to the new array
- @return a new CPArray containing the objects of anArray
+ @return a new CPArray containing the objects of \c anArray
*/
- (id)initWithArray:(CPArray)anArray
{
@@ -189,10 +190,10 @@
}
/*!
- Initializes a the array with the contents of anArray
- and optionally performs a deep copy of the objects based on copyItems.
+ Initializes a the array with the contents of \c anArray
+ and optionally performs a deep copy of the objects based on \c copyItems.
@param anArray the array to copy the data from
- @param copyItems if YES, each object will be copied by having a copy message sent to it, and the
+ @param copyItems if \c YES, each object will be copied by having a \c -copy message sent to it, and the
returned object will be added to the receiver. Otherwise, no copying will be performed.
@return the initialized array of objects
*/
@@ -239,7 +240,7 @@
/*!
Initializes the array with a JavaScript array of objects.
@param objects the array of objects to add to the receiver
- @param aCount the number of objects in objects
+ @param aCount the number of objects in \c objects
@return the initialized CPArray
*/
- (id)initWithObjects:(id)objects count:(unsigned)aCount
@@ -259,7 +260,7 @@
// Querying an array
/*!
- Returns YES if the array contains anObject. Otherwise, it returns NO.
+ Returns \c YES if the array contains \c anObject. Otherwise, it returns \c NO.
@param anObject the method checks if this object is already in the array
*/
- (BOOL)containsObject:(id)anObject
@@ -276,10 +277,10 @@
}
/*!
- Returns the index of anObject in this array.
- If the object is nil or not in the array,
- returns CPNotFound. It first attempts to find
- a match using isEqual:, then ==.
+ Returns the index of \c anObject in this array.
+ If the object is \c nil or not in the array,
+ returns \c CPNotFound. It first attempts to find
+ a match using \c -isEqual:, then \c ==.
@param anObject the object to search for
*/
- (int)indexOfObject:(id)anObject
@@ -290,7 +291,7 @@
var i = 0,
count = length;
- // Only use isEqual: if our object is a CPObject.
+ // Only use -isEqual: if our object is a CPObject.
if (anObject.isa)
{
for(; i < count; ++i)
@@ -311,12 +312,12 @@
}
/*!
- Returns the index of anObject in the array
- within aRange. It first attempts to find
- a match using isEqual:, then ==.
+ Returns the index of \c anObject in the array
+ within \c aRange. It first attempts to find
+ a match using \c -isEqual:, then \c ==.
@param anObject the object to search for
@param aRange the range to search within
- @return the index of the object, or CPNotFound if it was not found.
+ @return the index of the object, or \c CPNotFound if it was not found.
*/
- (int)indexOfObject:(id)anObject inRange:(CPRange)aRange
{
@@ -343,9 +344,9 @@
}
/*!
- Returns the index of anObject in the array. The test for equality is done using only ==.
+ Returns the index of \c anObject in the array. The test for equality is done using only \c ==.
@param anObject the object to search for
- @return the index of the object in the array. CPNotFound if the object is not in the array.
+ @return the index of the object in the array. \c CPNotFound if the object is not in the array.
*/
- (int)indexOfObjectIdenticalTo:(id)anObject
{
@@ -372,12 +373,12 @@
}
/*!
- Returns the index of anObject in the array
- within aRange. The test for equality is
- done using only ==.
+ Returns the index of \c anObject in the array
+ within \c aRange. The test for equality is
+ done using only \c ==.
@param anObject the object to search for
@param aRange the range to search within
- @return the index of the object, or CPNotFound if it was not found.
+ @return the index of the object, or \c CPNotFound if it was not found.
*/
- (int)indexOfObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
{
@@ -409,12 +410,12 @@
}
/*!
- Returns the index of anObject in the array, which must be sorted in the same order as
+ Returns the index of \c anObject in the array, which must be sorted in the same order as
calling sortUsingSelector: with the selector passed to this method would result in.
@param anObject the object to search for
@param aSelector the comparison selector to call on each item in the list, the same
selector should have been used to sort the array (or to maintain its sorted order).
- @return the index of the object, or CPNotFound if it was not found.
+ @return the index of the object, or \c CPNotFound if it was not found.
*/
- (unsigned)indexOfObject:(id)anObject sortedBySelector:(SEL)aSelector
{
@@ -422,7 +423,7 @@
}
/*!
- Returns the index of anObject in the array, which must be sorted in the same order as
+ Returns the index of \c anObject in the array, which must be sorted in the same order as
calling sortUsingFunction: with the selector passed to this method would result in.
The function will be called like so:
@@ -431,7 +432,7 @@
@param anObject the object to search for
@param aFunction the comparison function to call on each item in the array that we search. the same
selector should have been used to sort the array (or to maintain its sorted order).
- @return the index of the object, or CPNotFound if it was not found.
+ @return the index of the object, or \c CPNotFound if it was not found.
*/
- (unsigned)indexOfObject:(id)anObject sortedByFunction:(Function)aFunction
{
@@ -439,7 +440,7 @@
}
/*!
- Returns the index of anObject in the array, which must be sorted in the same order as
+ Returns the index of \c anObject in the array, which must be sorted in the same order as
calling sortUsingFunction: with the selector passed to this method would result in.
The function will be called like so:
@@ -449,7 +450,7 @@
@param aFunction the comparison function to call on each item in the array that we search. the same
function should have been used to sort the array (or to maintain its sorted order).
@param aContext a context object that will be passed to the sort function
- @return the index of the object, or CPNotFound if it was not found.
+ @return the index of the object, or \c CPNotFound if it was not found.
*/
- (unsigned)indexOfObject:(id)anObject sortedByFunction:(Function)aFunction context:(id)aContext
{
@@ -479,16 +480,16 @@
}
/*!
- Returns the index of anObject in the array, which must be sorted in the same order as
+ Returns the index of \c anObject in the array, which must be sorted in the same order as
calling sortUsingDescriptors: with the descriptors passed to this method would result in.
@param anObject the object to search for
@param descriptors the array of descriptors to use to compare each item in the array that we search. the same
descriptors should have been used to sort the array (or to maintain its sorted order).
- @return the index of the object, or CPNotFound if it was not found.
+ @return the index of the object, or \c CPNotFound if it was not found.
*/
- (unsigned)indexOfObject:(id)anObject sortedByDescriptors:(CPArray)descriptors
{
- [self indexOfObject:anObject sortedByFunction:function(lhs, rhs)
+ return [self indexOfObject:anObject sortedByFunction:function(lhs, rhs)
{
var i = 0,
count = [descriptors count],
@@ -503,7 +504,7 @@
}
/*!
- Returns the last object in the array. If the array is empty, returns nil/
+ Returns the last object in the array. If the array is empty, returns \c nil/
*/
- (id)lastObject
{
@@ -515,16 +516,19 @@
}
/*!
- Returns the object at index anIndex.
- @throws CPRangeException if anIndex is out of bounds
+ Returns the object at index \c anIndex.
+ @throws CPRangeException if \c anIndex is out of bounds
*/
- (id)objectAtIndex:(int)anIndex
{
+ if (anIndex >= length)
+ [CPException raise:CPRangeException reason:@"index (" + anIndex + @") beyond bounds (" + length + @")"];
+
return self[anIndex];
}
/*!
- Returns the objects at indexes in a new CPArray.
+ Returns the objects at \c indexes in a new CPArray.
@param indexes the set of indices
@throws CPRangeException if any of the indices is greater than or equal to the length of the array
*/
@@ -566,7 +570,7 @@
/*!
Sends each element in the array a message.
@param aSelector the selector of the message to send
- @throws CPInvalidArgumentException if aSelector is nil
+ @throws CPInvalidArgumentException if \c aSelector is \c nil
*/
- (void)makeObjectsPerformSelector:(SEL)aSelector
{
@@ -584,7 +588,7 @@
Sends each element in the array a message with an argument.
@param aSelector the selector of the message to send
@param anObject the first argument of the message
- @throws CPInvalidArgumentException if aSelector is nil
+ @throws CPInvalidArgumentException if \c aSelector is \c nil
*/
- (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject
{
@@ -601,8 +605,8 @@
// Comparing arrays
/*!
Returns the first object found in the receiver (starting at index 0) which is present in the
- otherArray as determined by using the -containsObject: method.
- @return the first object found, or nil if no common object was found.
+ \c otherArray as determined by using the \c -containsObject: method.
+ @return the first object found, or \c nil if no common object was found.
*/
- (id)firstObjectCommonWithArray:(CPArray)anArray
{
@@ -659,9 +663,9 @@
// Deriving new arrays
/*!
- Returns a copy of this array plus anObject inside the copy.
+ Returns a copy of this array plus \c anObject inside the copy.
@param anObject the object to be added to the array copy
- @throws CPInvalidArgumentException if anObject is nil
+ @throws CPInvalidArgumentException if \c anObject is \c nil
@return a new array that should be n+1 in size compared to the receiver.
*/
- (CPArray)arrayByAddingObject:(id)anObject
@@ -678,7 +682,7 @@
}
/*!
- Returns a new array which is the concatenation of self and otherArray (in this precise order).
+ Returns a new array which is the concatenation of \c self and otherArray (in this precise order).
@param anArray the array that will be concatenated to the receiver's copy
*/
- (CPArray)arrayByAddingObjectsFromArray:(CPArray)anArray
@@ -702,7 +706,7 @@
*/
/*!
- Returns a subarray of the receiver containing the objects found in the specified range aRange.
+ Returns a subarray of the receiver containing the objects found in the specified range \c aRange.
@param aRange the range of objects to be copied into the subarray
@throws CPRangeException if the specified range exceeds the bounds of the array
*/
@@ -737,8 +741,8 @@
/*!
Returns an array in which the objects are ordered according
- to a sort with aFunction. This invokes
- -sortUsingFunction:context.
+ to a sort with \c aFunction. This invokes
+ \c -sortUsingFunction:context.
@param aFunction a JavaScript 'Function' type that compares objects
@param aContext context information
@return a new sorted array
@@ -753,7 +757,7 @@
}
/*!
- Returns a new array in which the objects are ordered according to a sort with aSelector.
+ Returns a new array in which the objects are ordered according to a sort with \c aSelector.
@param aSelector the selector that will perform object comparisons
*/
- (CPArray)sortedArrayUsingSelector:(SEL)aSelector
@@ -770,7 +774,7 @@
/*!
Returns a string formed by concatenating the objects in the
receiver, with the specified separator string inserted between each part.
- If the element is a Objective-J object, then the description
+ If the element is a Objective-J object, then the \c -description
of that object will be used, otherwise the default JavaScript representation will be used.
@param aString the separator that will separate each object string
@return the string representation of the array
@@ -789,25 +793,30 @@
*/
- (CPString)description
{
- var i = 0,
+ var index = 0,
count = [self count],
description = '(';
-
- for(; i < count; ++i)
+
+ for(; index < count; ++index)
{
- if (self[i].isa) description += [self[i] description];
- else description += self[i];
-
- if (i != count - 1) description += ", ";
+ var object = self[index];
+
+ if (object && object.isa)
+ description += [object description];
+ else
+ description += object;
+
+ if (index !== count - 1)
+ description += ", ";
}
-
+
return description + ')';
}
// Collecting paths
/*!
Returns a new array subset formed by selecting the elements that have
- filename extensions from filterTypes. Only elements
+ filename extensions from \c filterTypes. Only elements
that are of type CPString are candidates for inclusion in the returned array.
@param filterTypes an array of CPString objects that contain file extensions (without the '.')
@return a new array with matching paths
@@ -841,7 +850,7 @@
}
/*!
- Returns the value for aKey from each element in the array.
+ Returns the value for \c aKey from each element in the array.
@param aKey the key to return the value for
@return an array of containing a value for each element in the array
*/
@@ -874,7 +883,7 @@
// Creating arrays
/*!
- Creates an array able to store at least aCapacity
+ Creates an array able to store at least \c aCapacity
items. Because CPArray is backed by JavaScript arrays,
this method ends up simply returning a regular array.
*/
@@ -884,7 +893,7 @@
}
/*!
- Initializes an array able to store at least aCapacity items. Because CPArray
+ Initializes an array able to store at least \c aCapacity items. Because CPArray
is backed by JavaScript arrays, this method ends up simply returning a regular array.
*/
- (id)initWithCapacity:(unsigned)aCapacity
@@ -894,7 +903,7 @@
// Adding and replacing objects
/*!
- Adds anObject to the end of the array.
+ Adds \c anObject to the end of the array.
@param anObject the object to add to the array
*/
- (void)addObject:(id)anObject
@@ -903,7 +912,7 @@
}
/*!
- Adds the objects in anArray to the receiver array.
+ Adds the objects in \c anArray to the receiver array.
@param anArray the array of objects to add to the end of the receiver
*/
- (void)addObjectsFromArray:(CPArray)anArray
@@ -914,7 +923,7 @@
/*!
Inserts an object into the receiver at the specified location.
@param anObject the object to insert into the array
- @param anIndex the location to insert anObject at
+ @param anIndex the location to insert \c anObject at
*/
- (void)insertObject:(id)anObject atIndex:(int)anIndex
{
@@ -947,9 +956,9 @@
}
/*!
- Replaces the element at anIndex with anObject.
- The current element at position anIndex will be removed from the array.
- @param anIndex the position in the array to place anObject
+ Replaces the element at \c anIndex with \c anObject.
+ The current element at position \c anIndex will be removed from the array.
+ @param anIndex the position in the array to place \c anObject
*/
- (void)replaceObjectAtIndex:(int)anIndex withObject:(id)anObject
{
@@ -957,8 +966,8 @@
}
/*!
- Replace the elements at the indices specified by anIndexSet with
- the objects in objects.
+ Replace the elements at the indices specified by \c anIndexSet with
+ the objects in \c objects.
@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
*/
@@ -975,12 +984,12 @@
}
/*!
- Replaces some of the receiver's objects with objects from anArray. Specifically, the elements of the
- receiver in the range specified by aRange,
- with the elements of anArray in the range specified by otherRange.
+ Replaces some of the receiver's objects with objects from \c anArray. Specifically, the elements of the
+ receiver in the range specified by \c aRange,
+ with the elements of \c anArray in the range specified by \c otherRange.
@param aRange the range of elements to be replaced in the receiver
@param anArray the array to retrieve objects for placement into the receiver
- @param otherRange the range of objects in anArray to pull from for placement into the receiver
+ @param otherRange the range of objects in \c anArray to pull from for placement into the receiver
*/
- (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray range:(CPRange)otherRange
{
@@ -992,8 +1001,8 @@
/*!
Replaces some of the receiver's objects with the objects from
- anArray. Specifically, the elements of the
- receiver in the range specified by aRange.
+ \c anArray. Specifically, the elements of the
+ receiver in the range specified by \c aRange.
@param aRange the range of elements to be replaced in the receiver
@param anArray the array to retrieve objects for placement into the receiver
*/
@@ -1003,7 +1012,7 @@
}
/*!
- Sets the contents of the receiver to be identical to the contents of anArray.
+ Sets the contents of the receiver to be identical to the contents of \c anArray.
@param anArray the array of objects used to replace the receiver's objects
*/
- (void)setArray:(CPArray)anArray
@@ -1031,7 +1040,7 @@
}
/*!
- Removes all entries of anObject from the array.
+ Removes all entries of \c anObject from the array.
@param anObject the object whose entries are to be removed
*/
- (void)removeObject:(id)anObject
@@ -1040,7 +1049,7 @@
}
/*!
- Removes all entries of anObject from the array, in the range specified by aRange.
+ Removes all entries of \c anObject from the array, in the range specified by \c aRange.
@param anObject the object to remove
@param aRange the range to search in the receiver for the object
*/
@@ -1056,7 +1065,7 @@
}
/*!
- Removes the object at anIndex.
+ Removes the object at \c anIndex.
@param anIndex the location of the element to be removed
*/
- (void)removeObjectAtIndex:(int)anIndex
@@ -1065,7 +1074,7 @@
}
/*!
- Removes the objects at the indices specified by CPIndexSet.
+ Removes the objects at the indices specified by \c CPIndexSet.
@param anIndexSet the indices of the elements to be removed from the array
*/
- (void)removeObjectsAtIndexes:(CPIndexSet)anIndexSet
@@ -1080,8 +1089,8 @@
}
/*!
- Remove the first instance of anObject from the array.
- The search for the object is done using ==.
+ Remove the first instance of \c anObject from the array.
+ The search for the object is done using \c ==.
@param anObject the object to remove
*/
- (void)removeObjectIdenticalTo:(id)anObject
@@ -1090,9 +1099,9 @@
}
/*!
- Remove the first instance of anObject from the array,
- within the range specified by aRange.
- The search for the object is done using ==.
+ Remove the first instance of \c anObject from the array,
+ within the range specified by \c aRange.
+ The search for the object is done using \c ==.
@param anObject the object to remove
@param aRange the range in the array to search for the object
*/
@@ -1108,7 +1117,7 @@
}
/*!
- Remove the objects in anArray from the receiver array.
+ Remove the objects in \c anArray from the receiver array.
@param anArray the array of objects to remove from the receiver
*/
- (void)removeObjectsInArray:(CPArray)anArray
@@ -1161,7 +1170,7 @@
/*!
Sorts the receiver array using a JavaScript function as a comparator, and a specified context.
@param aFunction a JavaScript function that will be called to compare objects
- @param aContext an object that will be passed to aFunction with comparison
+ @param aContext an object that will be passed to \c aFunction with comparison
*/
- (void)sortUsingFunction:(Function)aFunction context:(id)aContext
{
diff --git a/Foundation/CPAttributedString.j b/Foundation/CPAttributedString.j
index 580ffde7d..b6bcb23cb 100644
--- a/Foundation/CPAttributedString.j
+++ b/Foundation/CPAttributedString.j
@@ -51,7 +51,7 @@
/*!
Creates a new attributed string from a character string.
@param aString is the string to initialise from.
- @return a new CPAttributedString containing the string aString.
+ @return a new CPAttributedString containing the string \c aString.
*/
- (id)initWithString:(CPString)aString
{
@@ -61,7 +61,7 @@
/*!
Creates a new attributed string from an existing attributed string.
@param aString is the attributed string to initialise from.
- @return a new CPAttributedString containing the string aString.
+ @return a new CPAttributedString containing the string \c aString.
*/
- (id)initWithAttributedString:(CPAttributedString)aString
{
@@ -77,8 +77,8 @@
dictionary of attributes.
@param aString is the attributed string to initialise from.
@param attributes is a dictionary of string attributes.
- @return a new CPAttributedString containing the string aString
- with associated attributes, attributes.
+ @return a new CPAttributedString containing the string \c aString
+ with associated attributes, \c attributes.
*/
- (id)initWithString:(CPString)aString attributes:(CPDictionary)attributes
{
@@ -152,16 +152,16 @@
same, can be returned if desired.
@note there is no guarantee that the range returned is in fact the complete
range of the particular attributes. To ensure this use
- attributesAtIndex:longestEffectiveRange:inRange: instead. Note
+ \c attributesAtIndex:longestEffectiveRange:inRange: instead. Note
however that it may take significantly longer to execute.
@param anIndex is an unsigned integer index. It must lie within the bounds
of the string.
@param aRange is a reference to a CPRange object
that is set (upon return) to the range over which the attributes are the
- same as those at index, anIndex. If not required pass
- nil.
+ same as those at index, \c anIndex. If not required pass
+ \c nil.
@return a CPDictionary containing the attributes associated with the
- character at index anIndex. Returns nil if index
+ character at index \c anIndex. Returns \c nil if index
is out of bounds.
*/
- (CPDictionary)attributesAtIndex:(unsigned)anIndex effectiveRange:(CPRangePointer)aRange
@@ -187,10 +187,10 @@
and, by reference, the range over which the attributes apply. This is the
maximum range both forwards and backwards in the string over which the
attributes apply, bounded in both directions by the range limit parameter,
- rangeLimit.
+ \c rangeLimit.
@note this method performs a search to find this range which may be
- computationally intensive. Use the rangeLimit to limit the
- search space or use attributesAtIndex:effectiveRange: but
+ computationally intensive. Use the \c rangeLimit to limit the
+ search space or use \c -attributesAtIndex:effectiveRange: but
note that it is not guaranteed to return the full range of the current
character's attributes.
@param anIndex is the unsigned integer index. It must lie within the bounds
@@ -200,7 +200,7 @@
@param rangeLimit a range limiting the search for the attributes' applicable
range.
@return a CPDictionary containing the attributes associated with the
- character at index anIndex. Returns nil if index
+ character at index \c anIndex. Returns \c nil if index
is out of bounds.
*/
- (CPDictionary)attributesAtIndex:(unsigned)anIndex longestEffectiveRange:(CPRangePointer)aRange inRange:(CPRange)rangeLimit
@@ -268,15 +268,15 @@
required, the range over which the attribute applies.
@note there is no guarantee that the range returned is in fact the complete
range of a particular attribute. To ensure this use
- attribute:atIndex:longestEffectiveRange:inRange: instead but
+ \c -attribute:atIndex:longestEffectiveRange:inRange: instead but
note that it may take significantly longer to execute.
@param attribute the name of the desired attribute.
@param anIndex is an unsigned integer character index from which to retrieve
the attribute. It must lie within the bounds of the string.
@param aRange is a reference to a CPRange object, that is set upon return
to the range over which the named attribute applies. If not required pass
- nil.
- @return the named attribute or nil is the attribute does not
+ \c nil.
+ @return the named attribute or \c nil is the attribute does not
exist.
*/
- (id)attribute:(CPString)attribute atIndex:(unsigned)index effectiveRange:(CPRangePointer)aRange
@@ -300,10 +300,10 @@
range over which the attribute applies. This is the maximum range both
forwards and backwards in the string over which the attribute applies,
bounded in both directions by the range limit parameter,
- rangeLimit.
+ \c rangeLimit.
@note this method performs a search to find this range which may be
- computationally intensive. Use the rangeLimit to limit the
- search space or use attribute:atIndex:effectiveRange: but
+ computationally intensive. Use the \c rangeLimit to limit the
+ search space or use \c -attribute:atIndex:effectiveRange: but
note that it is not guaranteed to return the full range of the current
character's named attribute.
@param attribute the name of the desired attribute.
@@ -313,7 +313,7 @@
to the range over which the named attribute applies.
@param rangeLimit a range limiting the search for the attribute's applicable
range.
- @return the named attribute or nil is the attribute does not
+ @return the named attribute or \c nil is the attribute does not
exist.
*/
- (id)attribute:(CPString)attribute atIndex:(unsigned)anIndex longestEffectiveRange:(CPRangePointer)aRange inRange:(CPRange)rangeLimit
@@ -380,7 +380,7 @@
//Comparing Attributed Strings
/*!
Compares the receiver's characters and attributes to the specified
- attributed string, aString, and tests for equality.
+ attributed string, \c aString, and tests for equality.
@param aString the CPAttributedString to compare.
@return a boolean indicating equality.
*/
@@ -432,7 +432,7 @@
//Extracting a Substring
/*!
Extracts a substring from the receiver, both characters and attributes,
- within the range given by aRange.
+ within the range given by \c aRange.
@param aRange the range of the substring to extract.
@return a CPAttributedString containing the desired substring.
@exception CPRangeException if the range lies outside the receiver's bounds.
@@ -487,13 +487,13 @@
//Changing Characters
/*!
Replaces the characters in the receiver with those of the specified string
- over the range, aRange. If the range has a length of 0 then
+ over the range, \c aRange. If the range has a length of 0 then
the specified string is inserted at the range location. The new characters
inherit the attributes of the first character in the range that they
replace or in the case if a 0 range length, the first character before of
after the insert (after if the insert is at location 0).
@note the replacement string need not be the same length as the range
- being replaced. The full aString is inserted and thus the
+ being replaced. The full \c aString is inserted and thus the
receiver's length changes to match this
@param aRange the range of characters to replace.
@param aString the string to replace the specified characters in the
@@ -549,11 +549,11 @@
@note This process removes the attributes already associated with the
character range. If you wish to retain the current attributes use
- addAttributes:range:.
+ \c -addAttributes:range:.
@param aDictionary a CPDictionary of attributes (names and values) to set
to.
@param aRange a CPRange indicating the range of characters to set their
- associated attributes to aDictionary.
+ associated attributes to \c aDictionary.
*/
- (void)setAttributes:(CPDictionary)aDictionary range:(CPRange)aRange
{
@@ -580,7 +580,7 @@
@note Attributes currently associated with the characters in the range are
untouched. To remove all previous attributes when adding use
- setAttributes:range:.
+ \c -setAttributes:range:.
@param aDictionary a CPDictionary of attributes (names and values) to add.
@param aRange a CPRange indicating the range of characters to add the
attributes to.
@@ -619,7 +619,7 @@
@note Attributes currently associated with the characters in the range are
untouched. To remove all previous attributes when adding use
- setAttributes:range:.
+ \c -setAttributes:range:.
@param anAttribute a CPString of the attribute name.
@param aValue a value to assign to the attribute. Can be of any type.
@param aRange a CPRange indicating the range of characters to add the
@@ -654,7 +654,7 @@
/*!
Inserts an attributed string (characters and attributes) at index,
- anIndex, into the receiver. The portion of the
+ \c anIndex, into the receiver. The portion of the
receiver's attributed string from the specified index to the end is shifted
until after the inserted string.
@param aString a CPAttributedString to insert.
@@ -699,8 +699,8 @@
}
/*!
- Replaces characters and attributes in the range aRange with
- those of the given attributed string, aString.
+ Replaces characters and attributes in the range \c aRange with
+ those of the given attributed string, \c aString.
@param aRange a CPRange object specifying the range of characters and
attributes in the object to replace.
@param aString a CPAttributedString containing the data to be used for
@@ -717,7 +717,7 @@
}
/*!
- Sets the objects characters and attributes to those of aString.
+ Sets the objects characters and attributes to those of \c aString.
@param aString is a CPAttributedString from which the contents will be
copied.
*/
diff --git a/Foundation/CPCoder.j b/Foundation/CPCoder.j
index e9a376fa0..a9cd1bf97 100644
--- a/Foundation/CPCoder.j
+++ b/Foundation/CPCoder.j
@@ -39,7 +39,7 @@
/*!
Returns a flag indicating whether the receiver supports keyed coding. The default implementation returns
- NO. Subclasses supporting keyed coding must override this to return YES.
+ \c NO. Subclasses supporting keyed coding must override this to return \c YES.
*/
-(BOOL)allowsKeyedCoding
{
@@ -148,7 +148,7 @@
/*!
Called after an object is unarchived in case a different object should be used in place of it.
- The defaut method returns self. Interested subclasses should override this.
+ The defaut method returns \c self. Interested subclasses should override this.
@param aDecoder
@return the original object or it's substitute.
*/
diff --git a/Foundation/CPCountedSet.j b/Foundation/CPCountedSet.j
index ccad1365f..a99b94a98 100644
--- a/Foundation/CPCountedSet.j
+++ b/Foundation/CPCountedSet.j
@@ -40,12 +40,12 @@
[super addObject:anObject];
- var hash = [anObject hash];
+ var UID = [anObject UID];
- if (_counts[hash] === undefined)
- _counts[hash] = 1;
+ if (_counts[UID] === undefined)
+ _counts[UID] = 1;
else
- ++_counts[hash];
+ ++_counts[UID];
}
- (void)removeObject:(id)anObject
@@ -53,18 +53,18 @@
if (!_counts)
return;
- var hash = [anObject hash];
+ var UID = [anObject UID];
- if (_counts[hash] === undefined)
+ if (_counts[UID] === undefined)
return;
else
{
- --_counts[hash];
+ --_counts[UID];
- if (_counts[hash] === 0)
+ if (_counts[UID] === 0)
{
- delete _counts[hash];
+ delete _counts[UID];
[super removeObject:anObject];
}
}
@@ -85,12 +85,12 @@
if (!_counts)
_counts = {};
- var hash = [anObject hash];
+ var UID = [anObject UID];
- if (_counts[hash] === undefined)
+ if (_counts[UID] === undefined)
return 0;
- return _counts[hash];
+ return _counts[UID];
}
diff --git a/Foundation/CPDictionary.j b/Foundation/CPDictionary.j
index 0233f439a..50243f1df 100755
--- a/Foundation/CPDictionary.j
+++ b/Foundation/CPDictionary.j
@@ -70,7 +70,7 @@
If you are familiar with dictionaries in Cocoa, you'll notice that
there is no CPMutableDictionary class. The regular CPDictionary
- has setObject: and removeObjectForKey: methods.
+ has \c -setObject:forKey: and \c -removeObjectForKey: methods.
In Cappuccino there is no distinction between immutable and mutable classes.
They are all mutable.
*/
@@ -95,7 +95,7 @@
}
/*!
- Returns a new dictionary, initialized with the contents of aDictionary.
+ Returns a new dictionary, initialized with the contents of \c aDictionary.
@param aDictionary the dictionary to copy key-value pairs from
@return the new CPDictionary
*/
@@ -402,7 +402,7 @@
}
*/
/*!
- Returns the object for the entry with key aKey.
+ Returns the object for the entry with key \c aKey.
@param aKey the key for the object's entry
@return the object for the entry
*/
diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j
index 50f7421a7..03b427d34 100644
--- a/Foundation/CPIndexSet.j
+++ b/Foundation/CPIndexSet.j
@@ -23,6 +23,9 @@
@import "CPRange.j"
@import "CPObject.j"
+#define _CPMaxRange(aRange) ((aRange).location + (aRange).length)
+#define _CPMakeRange(aLocation, aLength) { location:(aLocation), length:aLength }
+#define _CPMakeRangeCopy(aRange) { location:(aRange).location, length:(aRange).length }
/*!
@class CPIndexSet
@@ -35,7 +38,6 @@
@implementation CPIndexSet : CPObject
{
unsigned _count;
- unsigned _cachedRangeIndex;
CPArray _ranges;
}
@@ -45,7 +47,7 @@
*/
+ (id)indexSet
{
- return [[self alloc] init];
+ return [[self alloc] init];
}
/*!
@@ -53,7 +55,7 @@
*/
+ (id)indexSetWithIndex:(int)anIndex
{
- return [[self alloc] initWithIndex:anIndex];
+ return [[self alloc] initWithIndex:anIndex];
}
/*!
@@ -62,41 +64,23 @@
*/
+ (id)indexSetWithIndexesInRange:(CPRange)aRange
{
- return [[self alloc] initWithIndexesInRange:aRange];
+ return [[self alloc] initWithIndexesInRange:aRange];
}
// Initializing and Index Set
- (id)init
{
- self = [super init];
-
- if (self)
- {
- _count = 0;
- _ranges = [];
- _cachedRangeIndex = 0;
- }
-
- return self;
+ return [self initWithIndexesInRange:_CPMakeRange(0, 0)];
}
/*!
Initializes the index set with a single index.
@return the initialized index set
*/
-- (id)initWithIndex:(int)anIndex
+- (id)initWithIndex:(CPInteger)anIndex
{
- self = [super init];
-
- if (self)
- {
- _count = 1;
- _ranges = [CPArray arrayWithObject:CPMakeRange(anIndex, 1)];
- _cachedRangeIndex = 0;
- }
-
- return self;
+ return [self initWithIndexesInRange:_CPMakeRange(anIndex, 1)];
}
/*!
@@ -107,14 +91,17 @@
- (id)initWithIndexesInRange:(CPRange)aRange
{
self = [super init];
-
+
if (self)
{
- _count = aRange.length;
- _ranges = [CPArray arrayWithObject:aRange];
- _cachedRangeIndex = 0;
+ _count = MAX(0, aRange.length);
+
+ if (_count > 0)
+ _ranges = [aRange];
+ else
+ _ranges = [];
}
-
+
return self;
}
@@ -126,20 +113,19 @@
- (id)initWithIndexSet:(CPIndexSet)anIndexSet
{
self = [super init];
-
+
if (self)
{
_count = [anIndexSet count];
_ranges = [];
- _cachedRangeIndex = 0;
-
- var index = 0,
- count = anIndexSet._ranges.length;
-
- for (; index < count; ++index)
- _ranges.push(CPCopyRange(anIndexSet._ranges[index]));
+
+ var otherRanges = anIndexSet._ranges,
+ otherRangesCount = otherRanges.length;
+
+ while (otherRangesCount--)
+ _ranges[otherRangesCount] = _CPMakeRangeCopy(otherRanges[otherRangesCount]);
}
-
+
return self;
}
@@ -147,118 +133,114 @@
/*!
Compares the receiver with the provided index set.
@param anIndexSet the index set to compare to
- @return YES if the receiver and the index set are functionally equivalent
+ @return \c YES if the receiver and the index set are functionally equivalent
*/
- (BOOL)isEqualToIndexSet:(CPIndexSet)anIndexSet
{
+ if (!anIndexSet)
+ return NO;
+
// Comparisons to ourself are always return YES.
- if (self == anIndexSet)
- return YES;
-
- var i = 0,
- count = _ranges.length;
+ if (self === anIndexSet)
+ return YES;
+
+ var rangesCount = _ranges.length,
otherRanges = anIndexSet._ranges;
-
- // If we have a discrepency in the number of ranges or the number of indexes,
- // simply return NO.
- if (count != otherRanges.length || _count != [anIndexSet count])
- return NO;
-
- for (; i < count; ++i)
- if (!CPEqualRanges(_ranges[i], otherRanges[i]))
- return NO;
-
- return YES;
-}
-/*!
- Returns YES if the index set contains the specified index.
- @param anIndex the index to check for in the set
- @return YES if anIndex is in the receiver index set
-*/
-- (BOOL)containsIndex:(unsigned)anIndex
-{
- return [self containsIndexesInRange:CPMakeRange(anIndex, 1)];
-}
-
-/*!
- Returns YES if the index set contains all the numbers in the specified range.
- @param aRange the range of numbers to check for in the index set
-*/
-- (BOOL)containsIndexesInRange:(CPRange)aRange
-{
- if(!_count)
+ // If we have a discrepency in the number of ranges or the number of indexes,
+ // simply return NO.
+ if (rangesCount !== otherRanges.length || _count !== anIndexSet._count)
return NO;
- var i = SOERangeIndex(self, aRange.location),
- lower = aRange.location,
- upper = CPMaxRange(aRange),
- count = _ranges.length;
-
- // Stop if the location is ever bigger than or equal to our
- // non-inclusive upper bound
- for(;i < count && _ranges[i].location < upper; ++i)
- // The range must be a subset of one our ranges.
- if (_ranges[i].location <= lower && CPMaxRange(_ranges[i]) >= upper)
- {
- _cachedRangeIndex = i;
- return YES;
- }
-
- // The value isn't here, but values greater than anIndex should
- // start from here regardless.
- _cachedRangeIndex = i;
-
- return NO;
-}
-
-/*!
- Returns YES if the receving index set contains all the indices in the argument.
- @param anIndexSet the set of indices to check for in the receiving index set
-*/
-- (BOOL)containsIndexes:(CPIndexSet)anIndexSet
-{
- // Return YES if anIndexSet has no indexes
- if(![anIndexSet count])
- return YES;
-
- // Return NO if we have no indexes.
- if(!_count)
- return NO;
-
- var i = 0,
- count = _ranges.length;
-
- // This is fast thanks to the _cachedIndexRange.
- for(; i < count; ++i)
- if (![anIndexSet containsIndexesInRange:_ranges[i]])
+ while (rangesCount--)
+ if (!CPEqualRanges(_ranges[rangesCount], otherRanges[rangesCount]))
return NO;
-
+
return YES;
}
/*!
- Checks if the receiver contains at least one number in aRange.
+ Returns \c YES if the index set contains the specified index.
+ @param anIndex the index to check for in the set
+ @return \c YES if \c anIndex is in the receiver index set
+*/
+- (BOOL)containsIndex:(CPInteger)anIndex
+{
+ return positionOfIndex(_ranges, anIndex) !== CPNotFound;
+}
+
+/*!
+ Returns \c YES if the index set contains all the numbers in the specified range.
+ @param aRange the range of numbers to check for in the index set
+*/
+- (BOOL)containsIndexesInRange:(CPRange)aRange
+{
+ if (aRange.length <= 0)
+ return NO;
+
+ // If we have less total indexes than aRange, we can't possibly contain aRange.
+ if(_count < aRange.length)
+ return NO;
+
+ // Search for first location
+ var rangeIndex = positionOfIndex(_ranges, aRange.location);
+
+ // If we don't have the first location, then we don't contain aRange.
+ if (rangeIndex === CPNotFound)
+ return NO;
+
+ var range = _ranges[rangeIndex];
+
+ // The intersection must contain all the indexes from the original range.
+ return CPIntersectionRange(range, aRange).length === aRange.length;
+}
+
+/*!
+ Returns \c YES if the receving index set contains all the indices in the argument.
+ @param anIndexSet the set of indices to check for in the receiving index set
+*/
+- (BOOL)containsIndexes:(CPIndexSet)anIndexSet
+{
+ var otherCount = anIndexSet._count;
+
+ if(otherCount <= 0)
+ return YES;
+
+ // If we have less total indexes than anIndexSet, we can't possibly contain aRange.
+ if (_count < otherCount)
+ return NO;
+
+ var otherRanges = anIndexSet._ranges,
+ otherRangesCount = otherRanges.length;
+
+ while (otherRangesCount--)
+ if (![self containsIndexesInRange:otherRanges[otherRangesCount]])
+ return NO;
+
+ return YES;
+}
+
+/*!
+ Checks if the receiver contains at least one number in \c aRange.
@param aRange the range of numbers to check.
- @return YES if the receiving index set contains at least one number in the provided range
+ @return \c YES if the receiving index set contains at least one number in the provided range
*/
- (BOOL)intersectsIndexesInRange:(CPRange)aRange
{
- // This is fast thanks to the _cachedIndexRange.
- if(!_count)
+ if (_count <= 0)
return NO;
-
- var i = SOERangeIndex(self, aRange.location),
- count = _ranges.length,
- upper = CPMaxRange(aRange);
-
- // Stop if the location is ever bigger than or equal to our
- // non-inclusive upper bound
- for (; i < count && _ranges[i].location < upper; ++i)
- if(CPIntersectionRange(aRange, _ranges[i]).length)
- return YES;
-
- return NO;
+
+ var lhsRangeIndex = assumedPositionOfIndex(_ranges, aRange.location);
+
+ if (FLOOR(lhsRangeIndex) === lhsRangeIndex)
+ return YES;
+
+ var rhsRangeIndex = assumedPositionOfIndex(_ranges, _CPMaxRange(aRange) - 1);
+
+ if (FLOOR(rhsRangeIndex) === rhsRangeIndex)
+ return YES;
+
+ return lhsRangeIndex !== rhsRangeIndex;
}
/*!
@@ -273,163 +255,213 @@
/*!
Return the first index in the set
*/
-- (int)firstIndex
+- (CPInteger)firstIndex
{
- return _count ? _ranges[0].location : CPNotFound;
-}
-
-/*!
- Returns the last index in the set
-*/
-- (int)lastIndex
-{
- return _count ? CPMaxRange(_ranges[_ranges.length - 1]) - 1 : CPNotFound;
-}
-
-/*!
- Returns the first index value in the receiver which is greater than anIndex.
- @return the closest index or CPNotFound if no match was found
-*/
-- (unsigned)indexGreaterThanIndex:(unsigned)anIndex
-{
- if(!_count)
- return CPNotFound;
-
- var i = SOERangeIndex(self, anIndex++),
- count = _ranges.length;
-
- for(; i < count && anIndex >= CPMaxRange(_ranges[i]); ++i) ;
-
- if (i == count)
- return CPNotFound;
-
- _cachedRangeIndex = i;
-
- if (anIndex < _ranges[i].location)
- return _ranges[i].location;
-
- return anIndex;
-}
-
-/*!
- Returns the first index value in the receiver which is less than anIndex.
- @return the closest index or CPNotFound if no match was found
-*/
-- (unsigned)indexLessThanIndex:(unsigned)anIndex
-{
- if (!_count)
- return CPNotFound;
-
- var i = GOERangeIndex(self, anIndex--);
-
- for (; i >= 0 && anIndex < _ranges[i].location; --i) ;
-
- if(i < 0)
- return CPNotFound;
-
- _cachedRangeIndex = i;
-
- if (CPLocationInRange(anIndex, _ranges[i]))
- return anIndex;
-
- if (CPMaxRange(_ranges[i]) - 1 < anIndex)
- return CPMaxRange(_ranges[i]) - 1;
+ if (_count > 0)
+ return _ranges[0].location;
return CPNotFound;
}
/*!
- Returns the first index value in the receiver which is greater than or equal to anIndex.
- @return the matching index or CPNotFound if no match was found
+ Returns the last index in the set
*/
-- (unsigned int)indexGreaterThanOrEqualToIndex:(unsigned)anIndex
+- (CPInteger)lastIndex
{
- return [self indexGreaterThanIndex:anIndex - 1];
+ if (_count > 0)
+ return _CPMaxRange(_ranges[_ranges.length - 1]) - 1;
+
+ return CPNotFound;
}
/*!
- Returns the first index value in the receiver which is less than or equal to anIndex.
+ Returns the first index value in the receiver which is greater than \c anIndex.
+ @return the closest index or CPNotFound if no match was found
+*/
+- (CPInteger)indexGreaterThanIndex:(CPInteger)anIndex
+{
+ // The first possible index that would satisfy this requirement.
+ ++anIndex;
+
+ // Attempt to find it or something bigger.
+ var rangeIndex = assumedPositionOfIndex(_ranges, anIndex);
+
+ // Nothing at all found?
+ if (rangeIndex === CPNotFound)
+ return CPNotFound;
+
+ rangeIndex = CEIL(rangeIndex);
+
+ if (rangeIndex >= _ranges.length)
+ return CPNotFound;
+
+ var range = _ranges[rangeIndex];
+
+ // Check if it's actually in this range.
+ if (CPLocationInRange(anIndex, range))
+ return anIndex;
+
+ // If not, it must be the first element of this range.
+ return range.location;
+}
+
+/*!
+ Returns the first index value in the receiver which is less than \c anIndex.
+ @return the closest index or CPNotFound if no match was found
+*/
+- (CPInteger)indexLessThanIndex:(CPInteger)anIndex
+{
+ // The first possible index that would satisfy this requirement.
+ --anIndex;
+
+ // Attempt to find it or something smaller.
+ var rangeIndex = assumedPositionOfIndex(_ranges, anIndex);
+
+ // Nothing at all found?
+ if (rangeIndex === CPNotFound)
+ return CPNotFound;
+
+ rangeIndex = FLOOR(rangeIndex);
+
+ if (rangeIndex < 0)
+ return CPNotFound;
+
+ var range = _ranges[rangeIndex];
+
+ // Check if it's actually in this range.
+ if (CPLocationInRange(anIndex, range))
+ return anIndex;
+
+ // If not, it must be the first element of this range.
+ return _CPMaxRange(range) - 1;
+}
+
+/*!
+ Returns the first index value in the receiver which is greater than or equal to \c anIndex.
@return the matching index or CPNotFound if no match was found
*/
-- (unsigned int)indexLessThanOrEqualToIndex:(unsigned)anIndex
+- (CPInteger)indexGreaterThanOrEqualToIndex:(CPInteger)anIndex
{
- return [self indexLessThanIndex:anIndex + 1];
+ return [self indexGreaterThanIndex:anIndex - 1];
+}
+
+/*!
+ Returns the first index value in the receiver which is less than or equal to \c anIndex.
+ @return the matching index or CPNotFound if no match was found
+*/
+- (CPInteger)indexLessThanOrEqualToIndex:(CPInteger)anIndex
+{
+ return [self indexLessThanIndex:anIndex + 1];
}
/*!
Fills up the specified array with numbers from the index set within
the specified range. The method stops filling up the array until the
- aMaxCount number have been added or the range maximum is reached.
+ \c aMaxCount number have been added or the range maximum is reached.
@param anArray the array to fill up
@param aMaxCount the maximum number of numbers to adds
@param aRangePointer the range of indices to add
@return the number of elements added to the array
*/
-- (unsigned)getIndexes:(CPArray)anArray maxCount:(unsigned)aMaxCount inIndexRange:(CPRange)aRangePointer
+- (CPInteger)getIndexes:(CPArray)anArray maxCount:(CPInteger)aMaxCount inIndexRange:(CPRange)aRange
{
- if (!_count || aMaxCount <= 0 || aRangePointer && !aRangePointer.length)
- return 0;
-
- var i = SOERangeIndex(self, aRangePointer? aRangePointer.location : 0),
- total = 0,
- count = _ranges.length;
-
- for (; i < count; ++i)
+ if (!_count || aMaxCount === 0 || aRange && !aRange.length)
{
- // If aRangePointer is nil, all indexes are acceptable.
- var intersection = aRangePointer ? CPIntersectionRange(_ranges[i], aRangePointer) : _ranges[i],
- index = intersection.location,
- maximum = CPMaxRange(intersection);
-
- for (; index < maximum; ++index)
+ if (aRange)
+ aRange.length = 0;
+
+ return 0;
+ }
+
+ var total = 0;
+
+ if (aRange)
+ {
+ var firstIndex = aRange.location,
+ lastIndex = _CPMaxRange(aRange) - 1,
+ rangeIndex = CEIL(assumedPositionOfIndex(_ranges, firstIndex)),
+ lastRangeIndex = FLOOR(assumedPositionOfIndex(_ranges, lastIndex));
+ }
+ else
+ {
+ var firstIndex = [self firstIndex],
+ lastIndex = [self lastIndex],
+ rangeIndex = 0,
+ lastRangeIndex = _ranges.length - 1;
+ }
+
+ while (rangeIndex <= lastRangeIndex)
+ {
+ var range = _ranges[rangeIndex],
+ index = MAX(firstIndex, range.location),
+ maxRange = MIN(lastIndex + 1, _CPMaxRange(range));
+
+ for (; index < maxRange; ++index)
{
anArray[total++] = index;
-
- if (total == aMaxCount)
+
+ if (total === aMaxCount)
{
- // Update aRangePointer if it exists...
- if (aRangePointer)
+ // Update aRange if it exists...
+ if (aRange)
{
- var upper = CPMaxRange(aRangePointer);
-
- // Don't use CPMakeRange since the values need to persist.
- aRangePointer.location = index + 1;
- aRangePointer.length = upper - index - 1;
+ aRange.location = index + 1;
+ aRange.length = lastIndex + 1 - index - 1;
}
-
+
return aMaxCount;
}
}
+
+ ++rangeIndex;
}
-
- // Update aRangePointer if it exists...
- if (aRangePointer)
+
+ // Update aRange if it exists...
+ if (aRange)
{
- aRangePointer.location = CPNotFound;
- aRangePointer.length = 0;
+ aRange.location = CPNotFound;
+ aRange.length = 0;
}
-
+
return total;
}
- (CPString)description
{
- var desc = [super description] + " ";
-
- if (_count)
- {
- desc += "[number of indexes: " + _count + " (in " + _ranges.length + " ranges), indexes: (";
- for (i = 0; i < _ranges.length; i++)
- {
- desc += _ranges[i].location;
- if (_ranges[i].length > 1) desc += "-" + (CPMaxRange(_ranges[i])-1) + ":"+_ranges[i].length+":";
- if (i+1 < _ranges.length) desc += " ";
- }
- desc += ")]";
- }
- else
- desc += "(no indexes)";
- return desc;
+ var description = [super description];
+
+ if (_count)
+ {
+ var index = 0,
+ count = _ranges.length;
+
+ description += "[number of indexes: " + _count + " (in " + count;
+
+ if (count === 1)
+ description += " range), indexes: (";
+ else
+ description += " ranges), indexes: (";
+
+ for (; index < count; ++index)
+ {
+ var range = _ranges[index];
+
+ description += range.location;
+
+ if (range.length > 1)
+ description += "-" + (CPMaxRange(range) - 1);
+
+ if (index + 1 < count)
+ description += " ";
+ }
+
+ description += ")]";
+ }
+
+ else
+ description += "(no indexes)";
+
+ return description;
}
@end
@@ -441,9 +473,9 @@
Adds an index to the set.
@param anIndex the index to add
*/
-- (void)addIndex:(unsigned)anIndex
+- (void)addIndex:(CPInteger)anIndex
{
- [self addIndexesInRange:CPMakeRange(anIndex, 1)];
+ [self addIndexesInRange:_CPMakeRange(anIndex, 1)];
}
/*!
@@ -452,13 +484,12 @@
*/
- (void)addIndexes:(CPIndexSet)anIndexSet
{
- var i = 0,
- ranges = anIndexSet._ranges,
- count = ranges.length;
-
+ var otherRanges = anIndexSet._ranges,
+ otherRangesCount = otherRanges.length;
+
// Simply add each range within anIndexSet.
- for(; i < count; ++i)
- [self addIndexesInRange:ranges[i]];
+ while (otherRangesCount--)
+ [self addIndexesInRange:otherRanges[otherRangesCount]];
}
/*!
@@ -467,91 +498,66 @@
*/
- (void)addIndexesInRange:(CPRange)aRange
{
- if (_ranges.length == 0)
+ // If empty range, bail.
+ if (aRange.length <= 0)
+ return;
+
+ // If we currently don't have any indexes, this represents our entire set.
+ if (_count <= 0)
{
_count = aRange.length;
-
- return [_ranges addObject:CPCopyRange(aRange)];
- }
-
- // FIXME: Should we really use SOERangeIndex here? There is no real
- // reason the cached index would be a better guess than 0, and it
- // would avoid a function call.
- var i = SOERangeIndex(self, aRange.location),
- count = _ranges.length,
- padded = CPMakeRange(aRange.location - 1, aRange.length + 2),
- maximum = CPMaxRange(aRange);
+ _ranges = [aRange];
+
+ return;
+ }
+
+ var rangeCount = _ranges.length,
+ lhsRangeIndex = assumedPositionOfIndex(_ranges, aRange.location - 1),
+ lhsRangeIndexCEIL = CEIL(lhsRangeIndex);
+
+ if (lhsRangeIndexCEIL === lhsRangeIndex && lhsRangeIndexCEIL < rangeCount)
+ aRange = CPUnionRange(aRange, _ranges[lhsRangeIndexCEIL]);
+
+ var rhsRangeIndex = assumedPositionOfIndex(_ranges, CPMaxRange(aRange)),
+ rhsRangeIndexFLOOR = FLOOR(rhsRangeIndex);
+
+ if (rhsRangeIndexFLOOR === rhsRangeIndex && rhsRangeIndexFLOOR >= 0)
+ aRange = CPUnionRange(aRange, _ranges[rhsRangeIndexFLOOR]);
+
+ var removalCount = rhsRangeIndexFLOOR - lhsRangeIndexCEIL + 1;
+
+ if (removalCount === _ranges.length)
+ {
+ _ranges = [aRange];
+ _count = aRange.length;
+ }
+
+ else if (removalCount === 1)
+ {
+ if (lhsRangeIndexCEIL < _ranges.length)
+ _count -= _ranges[lhsRangeIndexCEIL].length;
+
+ _count += aRange.length;
+ _ranges[lhsRangeIndexCEIL] = aRange;
+ }
- // If our range won't intersect with the last range, just append it to the end.
- if (count && CPMaxRange(_ranges[count - 1]) < aRange.location)
- [_ranges addObject:CPCopyRange(aRange)];
else
- for (; i < count; ++i)
+ {
+ if (removalCount > 0)
{
- // This range is completely independent of existing ranges,
- // simply add it to the array.
- if (maximum < _ranges[i].location)
- {
- _count += aRange.length;
-
- // Keep _cachedRangeIndex relevant.
- if (i < _cachedRangeIndex) ++_cachedRangeIndex;
-
- return [_ranges insertObject:CPCopyRange(aRange) atIndex:i];
- }
-
- if (CPIntersectionRange(_ranges[i], padded).length)
- {
- var union = CPUnionRange(_ranges[i], aRange);
-
- // We already contain all the indexes in this range.
- if (union.length == _ranges[i].length)
- return;
-
- // Pad the length to collapse with later ranges.
- ++union.length;
-
- // We only need to check if we now intersect with any following
- // ranges since if we now intersected with the previous range,
- // it would have already been handled. We start at i and not i + 1
- // to make sure we subtract i's length.
- var j = i;
-
- for(; j < count; ++j)
- // Bail as soon as we don't find an intersection.
- if(CPIntersectionRange(union, _ranges[j]).length)
- _count -= _ranges[j].length;
- else
- break;
-
- // Remove the padding now that we are done.
- // NOTE: We could have set _ranges[i] = CPCopyRange(union),
- // and then not had to bother decerementing here, but this avoids
- // a lookup above during unioning, and a function call (CPCopyRange).
- --union.length;
- _ranges[i] = union;
-
- // Now remove indexes [i + 1, j - 1]
- if (j - i - 1 > 0)
- {
- var remove = CPMakeRange(i + 1, j - i - 1);
-
- _ranges[i] = CPUnionRange(_ranges[i], _ranges[j - 1]);
- [_ranges removeObjectsInRange:remove];
-
- // Keep _cachedRangeIndex relevant.
- if (_cachedRangeIndex >= CPMaxRange(remove)) _cachedRangedIndex -= remove.length;
- else if (CPLocationInRange(_cachedRangeIndex, remove)) _cachedRangeIndex = i;
- }
-
- // Update count.
- _count += _ranges[i].length;
-
- return;
- }
+ var removal = lhsRangeIndexCEIL,
+ lastRemoval = lhsRangeIndexCEIL + removalCount - 1;
+
+ for (; removal <= lastRemoval; ++removal)
+ _count -= _ranges[removal].length;
+
+ [_ranges removeObjectsInRange:_CPMakeRange(lhsRangeIndexCEIL, removalCount)];
}
-
- _count += aRange.length;
+
+ [_ranges insertObject:aRange atIndex:lhsRangeIndexCEIL];
+
+ _count += aRange.length;
+ }
}
// Removing Indexes
@@ -559,9 +565,9 @@
Removes an index from the set
@param anIndex the index to remove
*/
-- (void)removeIndex:(unsigned int)anIndex
+- (void)removeIndex:(CPInteger)anIndex
{
- [self removeIndexesInRange:CPMakeRange(anIndex, 1)];
+ [self removeIndexesInRange:_CPMakeRange(anIndex, 1)];
}
/*!
@@ -571,13 +577,12 @@
*/
- (void)removeIndexes:(CPIndexSet)anIndexSet
{
- var i = 0,
- ranges = anIndexSet._ranges,
- count = ranges.length;
-
+ var otherRanges = anIndexSet._ranges,
+ otherRangesCount = otherRanges.length;
+
// Simply remove each index from anIndexSet
- for(; i < count; ++i)
- [self removeIndexesInRange:ranges[i]];
+ while (otherRangesCount--)
+ [self removeIndexesInRange:otherRanges[otherRangesCount]];
}
/*!
@@ -586,8 +591,7 @@
- (void)removeAllIndexes
{
_ranges = [];
- _count = 0;
- _cachedRangeIndex = 0;
+ _count = 0;
}
/*!
@@ -597,63 +601,78 @@
*/
- (void)removeIndexesInRange:(CPRange)aRange
{
- // FIXME: Should we really use SOERangeIndex here? There is no real
- // reason the cached index would be a better guess than 0, and it
- // would avoid a function call.
- var i = SOERangeIndex(self, aRange.location),
- count = _ranges.length,
- maximum = CPMaxRange(aRange),
- removal = CPMakeRange(CPNotFound, 0);
-
- for (; i < count; ++i)
- {
- var range = _ranges[i];
-
- // Our range will not intersect with any coming ranges.
- if (maximum < range.location)
- break;
+ // If empty range, bail.
+ if (aRange.length <= 0)
+ return;
- var intersection = CPIntersectionRange(range, aRange);
-
- // If we don't have an intersection, then just continue iterating.
- if (!intersection.length)
- continue;
-
- // If the intersection consists of the entirety of this range,
- // then remove it completely.
- else if (intersection.length == range.length)
+ // If we currently don't have any indexes, there's nothing to remove.
+ if (_count <= 0)
+ return;
+
+ var rangeCount = _ranges.length,
+ lhsRangeIndex = assumedPositionOfIndex(_ranges, aRange.location),
+ lhsRangeIndexCEIL = CEIL(lhsRangeIndex);
+
+ // Do we fall on an actual existing range?
+ if (lhsRangeIndex === lhsRangeIndexCEIL && lhsRangeIndexCEIL < rangeCount)
+ {
+ var existingRange = _ranges[lhsRangeIndexCEIL];
+
+ // If these ranges don't start in the same place, we have to cull it.
+ if (aRange.location !== existingRange.location)
{
- if (removal.location == CPNotFound)
- removal = CPMakeRange(i, 1);
+ var maxRange = CPMaxRange(aRange),
+ existingMaxRange = CPMaxRange(existingRange);
+
+ existingRange.length = aRange.location - existingRange.location;
+
+ // If this range is internal to the existing range, we have a unique splitting case.
+ if (maxRange < existingMaxRange)
+ {
+ _count -= aRange.length;
+ [_ranges insertObject:_CPMakeRange(maxRange, existingMaxRange - maxRange) atIndex:lhsRangeIndexCEIL + 1];
+
+ return;
+ }
else
- ++removal.length;
+ {
+ _count -= existingMaxRange - aRange.location;
+ lhsRangeIndexCEIL += 1;
+ }
}
- // If the intersection is contained entirely within this range,
- // then split it into two and return.
- else if (intersection.location > range.location && CPMaxRange(intersection) < CPMaxRange(range))
- {
- var insert = CPMakeRange(CPMaxRange(intersection), CPMaxRange(range) - CPMaxRange(intersection));
-
- range.length = intersection.location - range.location;
-
- _count -= intersection.length;
-
- return [_ranges insertObject:insert atIndex:i + 1];
- }
- // Else if we at least have an intersection, then trim the existing range.
- else
- {
- range.length -= intersection.length;
-
- if (intersection.location <= range.location)
- range.location += intersection.length;
- }
-
- _count -= intersection.length;
}
-
- if (removal.length)
- [_ranges removeObjectsInRange:removal];
+
+ var rhsRangeIndex = assumedPositionOfIndex(_ranges, CPMaxRange(aRange) - 1),
+ rhsRangeIndexFLOOR = FLOOR(rhsRangeIndex);
+
+ if (rhsRangeIndex === rhsRangeIndexFLOOR && rhsRangeIndexFLOOR >= 0)
+ {
+ var maxRange = CPMaxRange(aRange),
+ existingRange = _ranges[rhsRangeIndexFLOOR],
+ existingMaxRange = CPMaxRange(existingRange);
+
+ if (maxRange !== existingMaxRange)
+ {
+ _count -= maxRange - existingRange.location;
+ rhsRangeIndexFLOOR -= 1; // This is accounted for, and thus as if we got the previous spot.
+
+ existingRange.location = maxRange;
+ existingRange.length = existingMaxRange - maxRange;
+ }
+ }
+
+ var removalCount = rhsRangeIndexFLOOR - lhsRangeIndexCEIL + 1;
+
+ if (removalCount > 0)
+ {
+ var removal = lhsRangeIndexCEIL,
+ lastRemoval = lhsRangeIndexCEIL + removalCount - 1;
+
+ for (; removal <= lastRemoval; ++removal)
+ _count -= _ranges[removal].length;
+
+ [_ranges removeObjectsInRange:_CPMakeRange(lhsRangeIndexCEIL, removalCount)];
+ }
}
// Shifting Index Groups
@@ -663,11 +682,11 @@
@param aDelta the amount and direction to shift. A positive value shifts to
the right. A negative value shifts to the left.
*/
-- (void)shiftIndexesStartingAtIndex:(unsigned)anIndex by:(int)aDelta
-{
- if (!_count || aDelta == 0)
- return;
-
+- (void)shiftIndexesStartingAtIndex:(CPInteger)anIndex by:(int)aDelta
+{
+ if (!_count || aDelta == 0)
+ return;
+
// Later indexes have a higher probability of being shifted
// than lower ones, so start at the end and work backwards.
var i = _ranges.length - 1,
@@ -677,7 +696,7 @@
{
var range = _ranges[i],
maximum = CPMaxRange(range);
-
+
if (anIndex > maximum)
break;
@@ -699,11 +718,11 @@
shifted.length = CPMaxRange(shifted);
shifted.location = 0;
}
-
+
// We don't need to continue.
break;
}
-
+
// Shift the range, and normalize it if the result is negative.
if ((range.location += aDelta) < 0)
{
@@ -711,21 +730,21 @@
range.location = 0;
}
}
-
+
// We need to add the shifted ranges if the delta is negative.
if (aDelta < 0)
{
var j = i + 1,
count = _ranges.length,
shifts = [];
-
+
for (; j < count; ++j)
[shifts addObject:_ranges[j]];
-
+
if ((j = i + 1) < count)
{
[_ranges removeObjectsInRange:CPMakeRange(j, count - j)];
-
+
for (j = 0, count = shifts.length; j < count; ++j)
[self addIndexesInRange:shifts[j]];
}
@@ -738,7 +757,6 @@
@end
var CPIndexSetCountKey = @"CPIndexSetCountKey",
- CPIndexSetCachedRangeIndexKey = @"CPIndexSetCachedRangeIndexKey",
CPIndexSetRangeStringsKey = @"CPIndexSetRangeStringsKey";
@implementation CPIndexSet (CPCoding)
@@ -752,21 +770,20 @@ var CPIndexSetCountKey = @"CPIndexSetCountKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
-
+
if (self)
{
_count = [aCoder decodeIntForKey:CPIndexSetCountKey];
- _cachedRangeIndex = [aCoder decodeIntForKey:CPIndexSetCachedRangeIndexKey];
_ranges = [];
-
+
var rangeStrings = [aCoder decodeObjectForKey:CPIndexSetRangeStringsKey],
index = 0,
count = rangeStrings.length;
-
+
for (; index < count; ++index)
_ranges.push(CPRangeFromString(rangeStrings[index]));
}
-
+
return self;
}
@@ -778,12 +795,11 @@ var CPIndexSetCountKey = @"CPIndexSetCountKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeInt:_count forKey:CPIndexSetCountKey];
- [aCoder encodeInt:_cachedRangeIndex forKey:CPIndexSetCachedRangeIndexKey];
-
+
var index = 0,
count = _ranges.length,
rangeStrings = [];
-
+
for (; index < count; ++index)
rangeStrings[index] = CPStringFromRange(_ranges[index]);
@@ -830,56 +846,102 @@ var CPIndexSetCountKey = @"CPIndexSetCountKey",
@end
-var SOERangeIndex = function(anIndexSet, anIndex)
+var positionOfIndex = function(ranges, anIndex)
{
- var ranges = anIndexSet._ranges,
- cachedRangeIndex = 0;//anIndexSet._cachedRangeIndex;
-
- if(cachedRangeIndex < ranges.length && anIndex >= ranges[cachedRangeIndex].location)
- return cachedRangeIndex;
+ var low = 0,
+ high = ranges.length - 1;
- return 0;
+ while (low <= high)
+ {
+ var middle = FLOOR(low + (high - low) / 2),
+ range = ranges[middle];
+
+ if (anIndex < range.location)
+ high = middle - 1;
+
+ else if (anIndex >= CPMaxRange(range))
+ low = middle + 1;
+
+ else
+ return middle;
+ }
+
+ return CPNotFound;
}
-var GOERangeIndex = function(anIndexSet, anIndex)
+var assumedPositionOfIndex = function(ranges, anIndex)
{
- var ranges = anIndexSet._ranges,
- cachedRangeIndex = anIndexSet._ranges.length;//anIndexSet._cachedRangeIndex;
-
- if(cachedRangeIndex < ranges.length && anIndex <= ranges[cachedRangeIndex].location)
- return cachedRangeIndex;
-
- return ranges.length - 1;
+ var count = ranges.length;
+
+ if (count <= 0)
+ return CPNotFound;
+
+ var low = 0,
+ high = count * 2;
+
+ while (low <= high)
+ {
+ var middle = FLOOR(low + (high - low) / 2),
+ position = middle / 2,
+ positionFLOOR = FLOOR(position);
+
+ if (position === positionFLOOR)
+ {
+ if (positionFLOOR - 1 >= 0 && anIndex < CPMaxRange(ranges[positionFLOOR - 1]))
+ high = middle - 1;
+
+ else if (positionFLOOR < count && anIndex >= ranges[positionFLOOR].location)
+ low = middle + 1;
+
+ else
+ return positionFLOOR - 0.5;
+ }
+ else
+ {
+ var range = ranges[positionFLOOR];
+
+ if (anIndex < range.location)
+ high = middle - 1;
+
+ else if (anIndex >= CPMaxRange(range))
+ low = middle + 1;
+
+ else
+ return positionFLOOR;
+ }
+ }
+
+ return CPNotFound;
}
/*
new old method
-X + (id)indexSet;
-X + (id)indexSetWithIndex:(unsigned int)value;
-X + (id)indexSetWithIndexesInRange:(NSRange)range;
-X X - (id)init;
-X X - (id)initWithIndex:(unsigned int)value;
-X X - (id)initWithIndexesInRange:(NSRange)range; // designated initializer
-X X - (id)initWithIndexSet:(NSIndexSet *)indexSet; // designated initializer
-X - (BOOL)isEqualToIndexSet:(NSIndexSet *)indexSet;
-X X - (unsigned int)count;
-X X - (unsigned int)firstIndex;
-X X - (unsigned int)lastIndex;
-X X - (unsigned int)indexGreaterThanIndex:(unsigned int)value;
-X X - (unsigned int)indexLessThanIndex:(unsigned int)value;
-X X - (unsigned int)indexGreaterThanOrEqualToIndex:(unsigned int)value;
-X X - (unsigned int)indexLessThanOrEqualToIndex:(unsigned int)value;
-X - (unsigned int)getIndexes:(unsigned int *)indexBuffer maxCount:(unsigned int)bufferSize inIndexRange:(NSRangePointer)range;
-X X - (BOOL)containsIndex:(unsigned int)value;
-X X - (BOOL)containsIndexesInRange:(NSRange)range;
-X X - (BOOL)containsIndexes:(NSIndexSet *)indexSet;
-X X - (BOOL)intersectsIndexesInRange:(NSRange)range;
-X X - (void)addIndexes:(NSIndexSet *)indexSet;
-X - (void)removeIndexes:(NSIndexSet *)indexSet;
-X X - (void)removeAllIndexes;
-X - (void)addIndex:(unsigned int)value;
-X - (void)removeIndex:(unsigned int)value;
-X - (void)addIndexesInRange:(NSRange)range;
-X - (void)removeIndexesInRange:(NSRange)range;
- - (void)shiftIndexesStartingAtIndex:(unsigned int)index by:(int)delta;
+X + (id)indexSet;
+X + (id)indexSetWithIndex:(unsigned int)value;
+X + (id)indexSetWithIndexesInRange:(NSRange)range;
+X X - (id)init;
+X X - (id)initWithIndex:(unsigned int)value;
+X X - (id)initWithIndexesInRange:(NSRange)range; // designated initializer
+X X - (id)initWithIndexSet:(NSIndexSet *)indexSet; // designated initializer
+X - (BOOL)isEqualToIndexSet:(NSIndexSet *)indexSet;
+X X - (unsigned int)count;
+X X - (unsigned int)firstIndex;
+X X - (unsigned int)lastIndex;
+X X - (unsigned int)indexGreaterThanIndex:(unsigned int)value;
+X X - (unsigned int)indexLessThanIndex:(unsigned int)value;
+X X - (unsigned int)indexGreaterThanOrEqualToIndex:(unsigned int)value;
+X X - (unsigned int)indexLessThanOrEqualToIndex:(unsigned int)value;
+X - (unsigned int)getIndexes:(unsigned int *)indexBuffer maxCount:(unsigned int)bufferSize inIndexRange:(NSRangePointer)range;
+X X - (BOOL)containsIndex:(unsigned int)value;
+X X - (BOOL)containsIndexesInRange:(NSRange)range;
+X X - (BOOL)containsIndexes:(NSIndexSet *)indexSet;
+X X - (BOOL)intersectsIndexesInRange:(NSRange)range;
+X X - (void)addIndexes:(NSIndexSet *)indexSet;
+X - (void)removeIndexes:(NSIndexSet *)indexSet;
+X X - (void)removeAllIndexes;
+X - (void)addIndex:(unsigned int)value;
+X - (void)removeIndex:(unsigned int)value;
+X - (void)addIndexesInRange:(NSRange)range;
+X - (void)removeIndexesInRange:(NSRange)range;
+ - (void)shiftIndexesStartingAtIndex:(unsigned int)index by:(int)delta;
*/
diff --git a/Foundation/CPInvocation.j b/Foundation/CPInvocation.j
index 9aca90a23..19e8c2cb1 100644
--- a/Foundation/CPInvocation.j
+++ b/Foundation/CPInvocation.j
@@ -103,7 +103,7 @@
}
/*!
- Sets a method argument for the invocation. Arguments 0 and 1 are self and _cmd.
+ Sets a method argument for the invocation. Arguments 0 and 1 are \c self and \c _cmd.
@param anArgument the argument to add
@param anIndex the index of the argument in the method
*/
@@ -114,7 +114,7 @@
/*!
Returns the argument at the specified index. Arguments 0 and 1 are
- self and _cmd respectively. Thus, method arguments start at 2.
+ \c self and \c _cmd respectively. Thus, method arguments start at 2.
@param anIndex the index of the argument to return
@throws CPInvalidArgumentException if anIndex is greater than or equal to the invocation's number of arguments.
*/
diff --git a/Foundation/CPJSONPConnection.j b/Foundation/CPJSONPConnection.j
index 7076697f3..8ec76e0e7 100644
--- a/Foundation/CPJSONPConnection.j
+++ b/Foundation/CPJSONPConnection.j
@@ -73,7 +73,7 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}";
_callbackParameter = aString;
- if (!_callbackParameter && [_request URL].indexOf(CPJSONPCallbackReplacementString) < 0)
+ if (!_callbackParameter && [[_request URL] absoluteString].indexOf(CPJSONPCallbackReplacementString) < 0)
[CPException raise:CPInvalidArgumentException reason:@"JSONP source specified without callback parameter or CPJSONPCallbackReplacementString in URL."];
if(shouldStartImmediately)
@@ -86,7 +86,7 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}";
{
try
{
- CPJSONPConnectionCallbacks["callback"+[self hash]] = function(data)
+ CPJSONPConnectionCallbacks["callback"+[self UID]] = function(data)
{
[_delegate connection:self didReceiveData:data];
[self removeScriptTag];
@@ -95,16 +95,16 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}";
};
var head = document.getElementsByTagName("head").item(0),
- source = [_request URL];
+ source = [[_request URL] absoluteString];
if (_callbackParameter)
{
source += (source.indexOf('?') < 0) ? "?" : "&";
- source += _callbackParameter+"=CPJSONPConnectionCallbacks.callback"+[self hash];
+ source += _callbackParameter+"=CPJSONPConnectionCallbacks.callback"+[self UID];
}
else if (source.indexOf(CPJSONPCallbackReplacementString) >= 0)
{
- source = [source stringByReplacingOccurrencesOfString:CPJSONPCallbackReplacementString withString:"CPJSONPConnectionCallbacks.callback"+[self hash]];
+ source = [source stringByReplacingOccurrencesOfString:CPJSONPCallbackReplacementString withString:"CPJSONPConnectionCallbacks.callback"+[self UID]];
}
else
return;
@@ -130,8 +130,8 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}";
if(_scriptTag && _scriptTag.parentNode == head)
head.removeChild(_scriptTag);
- CPJSONPConnectionCallbacks["callback"+[self hash]] = nil;
- delete CPJSONPConnectionCallbacks["callback"+[self hash]];
+ CPJSONPConnectionCallbacks["callback"+[self UID]] = nil;
+ delete CPJSONPConnectionCallbacks["callback"+[self UID]];
}
- (void)cancel
diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j
index cc661e80e..59720316a 100644
--- a/Foundation/CPKeyValueCoding.j
+++ b/Foundation/CPKeyValueCoding.j
@@ -45,9 +45,9 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey";
if (!CPObjectAccessorsForClass)
CPObjectAccessorsForClass = [CPDictionary dictionary];
- var hash = [isa hash],
+ var UID = [isa UID],
selector = nil,
- accessors = [CPObjectAccessorsForClass objectForKey:hash];
+ accessors = [CPObjectAccessorsForClass objectForKey:UID];
if (accessors)
{
@@ -60,7 +60,7 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey";
{
accessors = [CPDictionary dictionary];
- [CPObjectAccessorsForClass setObject:accessors forKey:hash];
+ [CPObjectAccessorsForClass setObject:accessors forKey:UID];
}
var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1);
@@ -88,9 +88,9 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey";
if (!CPObjectModifiersForClass)
CPObjectModifiersForClass = [CPDictionary dictionary];
- var hash = [isa hash],
+ var UID = [isa UID],
selector = nil,
- modifiers = [CPObjectModifiersForClass objectForKey:hash];
+ modifiers = [CPObjectModifiersForClass objectForKey:UID];
if (modifiers)
{
@@ -103,7 +103,7 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey";
{
modifiers = [CPDictionary dictionary];
- [CPObjectModifiersForClass setObject:modifiers forKey:hash];
+ [CPObjectModifiersForClass setObject:modifiers forKey:UID];
}
if (selector)
diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j
index 107b80810..a2c3fc2d5 100644
--- a/Foundation/CPKeyValueObserving.j
+++ b/Foundation/CPKeyValueObserving.j
@@ -58,7 +58,7 @@
if (!anObserver || !aPath)
return;
- [[KVOProxyMap objectForKey:[self hash]] _removeObserver:anObserver forKeyPath:aPath];
+ [self[KVOProxyKey] _removeObserver:anObserver forKeyPath:aPath];
}
+ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
@@ -68,8 +68,8 @@
+ (CPSet)keyPathsForValuesAffectingValueForKey:(CPString)aKey
{
- var capitalizedKey = aKey.charAt(0).toUpperCase()+aKey.substring(1);
- selector = "keyPathsForValuesAffectingValueFor"+capitalizedKey;
+ var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substring(1);
+ selector = "keyPathsForValuesAffecting" + capitalizedKey;
if ([[self class] respondsToSelector:selector])
return objj_msgSend([self class], selector);
@@ -98,12 +98,9 @@ CPKeyValueChangeInsertion = 2;
CPKeyValueChangeRemoval = 3;
CPKeyValueChangeReplacement = 4;
-//convenience
-var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld;
-
-// Map of real objects to their KVO proxy
-var KVOProxyMap = [CPDictionary dictionary],
- DependentKeysMap = [CPDictionary dictionary];
+var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
+ DependentKeysKey = "$KVODEPENDENT",
+ KVOProxyKey = "$KVOPROXY";
//rule of thumb: _ methods are called on the real proxy object, others are called on the "fake" proxy object (aka the real object)
@@ -113,13 +110,14 @@ var KVOProxyMap = [CPDictionary dictionary],
id _targetObject;
Class _nativeClass;
CPDictionary _changesForKey;
- CPDictionary _observersForKey;
+ Object _observersForKey;
+ int _observersForKeyLength;
CPSet _replacedKeys;
}
+ (id)proxyForObject:(CPObject)anObject
{
- var proxy = [KVOProxyMap objectForKey:[anObject hash]];
+ var proxy = anObject[KVOProxyKey];
if (proxy)
return proxy;
@@ -128,7 +126,7 @@ var KVOProxyMap = [CPDictionary dictionary],
[proxy _replaceClass];
- [KVOProxyMap setObject:proxy forKey:[anObject hash]];
+ anObject[KVOProxyKey] = proxy;
return proxy;
}
@@ -139,9 +137,10 @@ var KVOProxyMap = [CPDictionary dictionary],
_targetObject = aTarget;
_nativeClass = [aTarget class];
- _observersForKey = [CPDictionary dictionary];
- _changesForKey = [CPDictionary dictionary];
_replacedKeys = [CPSet set];
+ _observersForKey = {};
+ _changesForKey = {};
+ _observersForKeyLength = 0;
return self;
}
@@ -202,40 +201,36 @@ var KVOProxyMap = [CPDictionary dictionary],
var theMethod = class_getInstanceMethod(_nativeClass, theSelector);
class_addMethod(_targetObject.isa, theSelector, theReplacementMethod(aKey, theMethod), "");
-
- found = true;
}
}
- if (found)
+ var affectingKeys = [[_nativeClass keyPathsForValuesAffectingValueForKey:aKey] allObjects],
+ affectingKeysCount = affectingKeys ? affectingKeys.length : 0;
+
+ if (!affectingKeysCount)
return;
- var composedOfKeys = [[_nativeClass keyPathsForValuesAffectingValueForKey:aKey] allObjects];
-
- if (!composedOfKeys)
- return;
-
- var dependentKeysForClass = [DependentKeysMap objectForKey:[_nativeClass hash]];
+ var dependentKeysForClass = _nativeClass[DependentKeysKey];
if (!dependentKeysForClass)
{
- dependentKeysForClass = [CPDictionary new];
- [DependentKeysMap setObject:dependentKeysForClass forKey:[_nativeClass hash]];
+ dependentKeysForClass = {};
+ _nativeClass[DependentKeysKey] = dependentKeysForClass;
}
- for (var i=0, count=composedOfKeys.length; iCPKeyedUnarchiver.
+ \c CPKeyedUnarchiver.
@par Delegate Methods
@@ -87,7 +87,7 @@ var _CPKeyedArchiverStringClass = Nil,
@delegate -(id)archiver:(CPKeyedArchiver)archiver willEncodeObject:(id)object;
Called when an object is about to be encoded. Allows the delegate to replace
- the object that gets encoded with a substitute or nil.
+ the object that gets encoded with a substitute or \c nil.
@param archiver the archiver encoding the object
@param object the candidate object for encoding
@return the object to encode
@@ -158,7 +158,7 @@ var _CPKeyedArchiverStringClass = Nil,
// Initializing an NSKeyedArchiver object
/*!
- Initializes the keyed archiver with the specified CPMutableData for writing.
+ Initializes the keyed archiver with the specified \c CPMutableData for writing.
@param data the object to archive to
@return the initialized keyed archiver
*/
@@ -208,7 +208,7 @@ var _CPKeyedArchiverStringClass = Nil,
// Do whatever with the class, yo.
// We call willEncodeObject previously.
- _plistObject = _plistObjects[[_UIDs objectForKey:[object hash]]];
+ _plistObject = _plistObjects[[_UIDs objectForKey:[object UID]]];
[object encodeWithCoder:self];
if (_delegate && _delegateSelectors & _CPKeyedArchiverDidEncodeObjectSelector)
@@ -246,9 +246,9 @@ var _CPKeyedArchiverStringClass = Nil,
}
/*!
- Encodes a BOOL value
- @param aBool the BOOL value
- @param aKey the key to associate with the BOOL
+ Encodes a \c BOOL value
+ @param aBool the \c BOOL value
+ @param aKey the key to associate with the \c BOOL
*/
- (void)encodeBool:(BOOL)aBOOL forKey:(CPString)aKey
{
@@ -256,9 +256,9 @@ var _CPKeyedArchiverStringClass = Nil,
}
/*!
- Encodes a double value
- @param aDouble the double value
- @param aKey the key to associate with the double
+ Encodes a \c double value
+ @param aDouble the \c double value
+ @param aKey the key to associate with the \c double
*/
- (void)encodeDouble:(double)aDouble forKey:(CPString)aKey
{
@@ -266,9 +266,9 @@ var _CPKeyedArchiverStringClass = Nil,
}
/*!
- Encodes a float value
- @param aFloat the float value
- @param aKey the key to associate with the float
+ Encodes a \c float value
+ @param aFloat the \c float value
+ @param aKey the key to associate with the \c float
*/
- (void)encodeFloat:(float)aFloat forKey:(CPString)aKey
{
@@ -276,9 +276,9 @@ var _CPKeyedArchiverStringClass = Nil,
}
/*!
- Encodes a int value
- @param anInt the int value
- @param aKey the key to associate with the int
+ Encodes a \c int value
+ @param anInt the \c int value
+ @param aKey the key to associate with the \c int
*/
- (void)encodeInt:(float)anInt forKey:(CPString)aKey
{
@@ -409,8 +409,8 @@ var _CPKeyedArchiverStringClass = Nil,
// Managing classes and class names
/*!
Allows substitution of class types for encoding. Specifically classes
- of type aClass encountered by all keyed archivers will
- instead be archived as a class of type aClassName.
+ of type \c aClass encountered by all keyed archivers will
+ instead be archived as a class of type \c aClassName.
@param aClassName the substitute class name
@param aClass the class to substitute
*/
@@ -424,9 +424,9 @@ var _CPKeyedArchiverStringClass = Nil,
/*!
Returns the name of the substitute class used for encoding
- aClass by all keyed archivers.
+ \c aClass by all keyed archivers.
@param aClass the class to substitute
- @return the name of the substitute class, or nil if there
+ @return the name of the substitute class, or \c nil if there
is no substitute class
*/
+ (CPString)classNameForClass:(Class)aClass
@@ -441,8 +441,8 @@ var _CPKeyedArchiverStringClass = Nil,
/*!
Allows substitution of class types for encoding. Specifically classes
- of type aClass encountered by this keyed archiver will
- instead be archived as a class of type aClassName.
+ of type \c aClass encountered by this keyed archiver will
+ instead be archived as a class of type \c aClassName.
@param aClassName the substitute class name
@param aClass the class to substitute
*/
@@ -455,9 +455,9 @@ var _CPKeyedArchiverStringClass = Nil,
}
/*!
- Returns the name of the substitute class used for encoding aClass by this keyed archiver.
+ Returns the name of the substitute class used for encoding \c aClass by this keyed archiver.
@param aClass the class to substitute
- @return the name of the substitute class, or nil if there is no substitute class
+ @return the name of the substitute class, or \c nil if there is no substitute class
*/
- (CPString)classNameForClass:(Class)aClass
{
@@ -480,8 +480,8 @@ var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
anObject = [_CPKeyedArchiverValue valueWithJSObject:anObject];
// Get the proper replacement object
- var hash = [anObject hash],
- object = [self._replacementObjects objectForKey:hash];
+ var GUID = [anObject UID],
+ object = [self._replacementObjects objectForKey:GUID];
// If a replacement object doesn't exist, then actually ask for one.
// Explicitly compare to nil because object could be === 0.
@@ -506,7 +506,7 @@ var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
}
}
- [self._replacementObjects setObject:object forKey:hash];
+ [self._replacementObjects setObject:object forKey:GUID];
}
// If we still don't have an object by this point, then return a
@@ -516,7 +516,7 @@ var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
return _CPKeyedArchiverNullReference;
// If not, then grab the object's UID
- var UID = [self._UIDs objectForKey:hash = [object hash]];
+ var UID = [self._UIDs objectForKey:GUID = [object UID]];
// If this object doesn't have a unique index in the object table yet,
// then it also hasn't been properly encoded. We explicitly compare
@@ -527,10 +527,10 @@ var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
if (isConditional)
{
// If we haven't already noted this conditional object...
- if ((UID = [self._conditionalUIDs objectForKey:hash]) === nil)
+ if ((UID = [self._conditionalUIDs objectForKey:GUID]) === nil)
{
// Use the null object as a placeholder.
- [self._conditionalUIDs setObject:UID = [self._plistObjects count] forKey:hash];
+ [self._conditionalUIDs setObject:UID = [self._plistObjects count] forKey:GUID];
[self._plistObjects addObject:_CPKeyedArchiverNullString];
}
}
@@ -582,17 +582,17 @@ var _CPKeyedArchiverEncodeObject = function(self, anObject, isConditional)
[plistObject setObject:[CPDictionary dictionaryWithObject:classUID forKey:_CPKeyedArchiverUIDKey] forKey:_CPKeyedArchiverClassKey];
}
- UID = [self._conditionalUIDs objectForKey:hash];
+ UID = [self._conditionalUIDs objectForKey:GUID];
// If this object WAS previously encoded conditionally...
if (UID !== nil)
{
- [self._UIDs setObject:UID forKey:hash];
+ [self._UIDs setObject:UID forKey:GUID];
[self._plistObjects replaceObjectAtIndex:UID withObject:plistObject];
}
else
{
- [self._UIDs setObject:UID = [self._plistObjects count] forKey:hash];
+ [self._UIDs setObject:UID = [self._plistObjects count] forKey:GUID];
[self._plistObjects addObject:plistObject];
}
}
diff --git a/Foundation/CPKeyedUnarchiver.j b/Foundation/CPKeyedUnarchiver.j
index 3a4f2a87b..f9be40a40 100644
--- a/Foundation/CPKeyedUnarchiver.j
+++ b/Foundation/CPKeyedUnarchiver.j
@@ -24,11 +24,14 @@
@import "CPCoder.j"
-var _CPKeyedUnarchiverCannotDecodeObjectOfClassNameOriginalClassesSelector = 1,
- _CPKeyedUnarchiverDidDecodeObjectSelector = 1 << 1,
- _CPKeyedUnarchiverWillReplaceObjectWithObjectSelector = 1 << 2,
- _CPKeyedUnarchiverWillFinishSelector = 1 << 3,
- _CPKeyedUnarchiverDidFinishSelector = 1 << 4;
+CPInvalidUnarchiveOperationException = @"CPInvalidUnarchiveOperationException";
+
+var _CPKeyedUnarchiverCannotDecodeObjectOfClassNameOriginalClassesSelector = 1 << 0,
+ _CPKeyedUnarchiverDidDecodeObjectSelector = 1 << 1,
+ _CPKeyedUnarchiverWillReplaceObjectWithObjectSelector = 1 << 2,
+ _CPKeyedUnarchiverWillFinishSelector = 1 << 3,
+ _CPKeyedUnarchiverDidFinishSelector = 1 << 4,
+ CPKeyedUnarchiverDelegate_unarchiver_cannotDecodeObjectOfClassName_originalClasses_ = 1 << 5;
var _CPKeyedArchiverNullString = "$null"
@@ -72,7 +75,7 @@ var _CPKeyedUnarchiverArrayClass = Ni
@param an array of class names describing the encoded object's
class hierarchy. The first index is the encoded class name, and
each superclass is after that.
- @return the Class to use instead or nil
+ @return the Class to use instead or \c nil
to abort the unarchiving operation
@delegate -(id)unarchiver:(CPKeyedUnarchiver)unarchiver didDecodeObject:(id)object;
@@ -80,10 +83,10 @@ var _CPKeyedUnarchiverArrayClass = Ni
@param unarchiver the unarchiver doing the decoding
@param object the decoded objec
@return a substitute to use for the decoded object. This can be the same object argument provide,
- another object or nil.
+ another object or \c nil.
@delegate -(void)unarchiver:(CPKeyedUnarchiver)unarchiver willReplaceObject:(id)object withObject:(id)newObject;
- Called when a decoded object has been substituted with another. (for example, from unarchiver:didDecodeObject:.
+ Called when a decoded object has been substituted with another. (for example, from \c -unarchiver:didDecodeObject:.
@param unarchiver the unarchiver that decoded the object
@param object the original decoded object
@param newObject the replacement object
@@ -105,7 +108,7 @@ var _CPKeyedUnarchiverArrayClass = Ni
CPDictionary _replacementClasses;
- CPDictionary _objects;
+ CPArray _objects;
CPDictionary _archive;
CPDictionary _plistObject;
@@ -181,7 +184,7 @@ var _CPKeyedUnarchiverArrayClass = Ni
}
/*
- Returns YES if an object exists for aKey.
+ Returns \c YES if an object exists for \c aKey.
@param aKey the object's associated key
*/
- (BOOL)containsValueForKey:(CPString)aKey
@@ -210,9 +213,9 @@ var _CPKeyedUnarchiverArrayClass = Ni
}
/*
- Decodes a BOOL from the archive
- @param aKey the BOOL's associated key
- @return the decoded BOOL
+ Decodes a \c BOOL from the archive
+ @param aKey the \c BOOL's associated key
+ @return the decoded \c BOOL
*/
- (BOOL)decodeBoolForKey:(CPString)aKey
{
@@ -220,9 +223,9 @@ var _CPKeyedUnarchiverArrayClass = Ni
}
/*
- Decodes a float from the archive
- @param aKey the float's associated key
- @return the decoded float
+ Decodes a \c float from the archive
+ @param aKey the \c float's associated key
+ @return the decoded \c float
*/
- (float)decodeFloatForKey:(CPString)aKey
{
@@ -230,9 +233,9 @@ var _CPKeyedUnarchiverArrayClass = Ni
}
/*
- Decodes a double from the archive.
- @param aKey the double's associated key
- @return the decoded double
+ Decodes a \c double from the archive.
+ @param aKey the \c double's associated key
+ @return the decoded \c double
*/
- (double)decodeDoubleForKey:(CPString)aKey
{
@@ -240,9 +243,9 @@ var _CPKeyedUnarchiverArrayClass = Ni
}
/*
- Decodes an int from the archive.
- @param aKey the int's associated key
- @return the decoded int
+ Decodes an \c int from the archive.
+ @param aKey the \c int's associated key
+ @return the decoded \c int
*/
- (int)decodeIntForKey:(CPString)aKey
{
@@ -306,7 +309,7 @@ var _CPKeyedUnarchiverArrayClass = Ni
if ([object isKindOfClass:_CPKeyedUnarchiverDictionaryClass])
return _CPKeyedUnarchiverDecodeObjectAtIndex(self, [object objectForKey:_CPKeyedArchiverUIDKey]);
- else if ([object isKindOfClass:_CPKeyedUnarchiverNumberClass] || [object isKindOfClass:_CPKeyedUnarchiverDataClass])
+ else if ([object isKindOfClass:_CPKeyedUnarchiverNumberClass] || [object isKindOfClass:_CPKeyedUnarchiverDataClass] || [object isKindOfClass:_CPKeyedUnarchiverStringClass])
return object;
else if ([object isKindOfClass:_CPKeyedUnarchiverArrayClass])
@@ -384,6 +387,9 @@ var _CPKeyedUnarchiverArrayClass = Ni
if ([_delegate respondsToSelector:@selector(unarchiverDidFinish:)])
_delegateSelectors |= _CPKeyedUnarchiverDidFinishSelector;
+
+ if ([_delegate respondsToSelector:@selector(unarchiver:cannotDecodeObjectOfClassName:originalClasses:)])
+ _delegateSelectors |= CPKeyedUnarchiverDelegate_unarchiver_cannotDecodeObjectOfClassName_originalClasses_;
}
- (void)setClass:(Class)aClass forClassName:(CPString)aClassName
@@ -426,15 +432,22 @@ var _CPKeyedUnarchiverDecodeObjectAtIndex = function(self, anIndex)
if (!theClass)
theClass = CPClassFromString(className);
- object = [theClass alloc];
+ if (!theClass && (self._delegateSelectors & CPKeyedUnarchiverDelegate_unarchiver_cannotDecodeObjectOfClassName_originalClasses_))
+ theClass = [_delegate unarchiver:self cannotDecodeObjectOfClassName:className originalClasses:classes];
+
+ if (!theClass)
+ [CPException raise:CPInvalidUnarchiveOperationException reason:@"-[CPKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (" + className + @")"];
- // It is important to do this before calling initWithCoder so that decoding can be self referential (something = self).
- self._objects[anIndex] = object;
-
var savedPlistObject = self._plistObject;
self._plistObject = plistObject;
- var string = className;
+
+ // Should we only call this on _CPCibClassSwapper? (currently the only class that makes use of this).
+ object = [theClass allocWithCoder:self];
+
+ // It is important to do this before calling initWithCoder so that decoding can be self referential (something = self).
+ self._objects[anIndex] = object;
+
var processedObject = [object initWithCoder:self];
self._plistObject = savedPlistObject;
diff --git a/Foundation/CPLog.j b/Foundation/CPLog.j
index dbc020971..a876034c8 100644
--- a/Foundation/CPLog.j
+++ b/Foundation/CPLog.j
@@ -25,7 +25,7 @@ window.CPLogDisable = false;
var CPLogDefaultTitle = "Cappuccino";
var CPLogLevels = ["fatal", "error", "warn", "info", "debug", "trace"];
-var CPLogDefaultLevel = CPLogLevels[0];
+var CPLogDefaultLevel = CPLogLevels[3];
var _CPLogLevelsInverted = {};
for (var i = 0; i < CPLogLevels.length; i++)
diff --git a/Foundation/CPNotificationCenter.j b/Foundation/CPNotificationCenter.j
index 76d793271..9956229e6 100644
--- a/Foundation/CPNotificationCenter.j
+++ b/Foundation/CPNotificationCenter.j
@@ -72,7 +72,7 @@ var CPNotificationDefaultCenter = nil;
/*!
Adds an object as an observer. The observer will receive notifications with the specified name
- and/or containing the specified object (depending on if they are nil.
+ and/or containing the specified object (depending on if they are \c nil.
@param anObserver the observing object
@param aSelector the message sent to the observer when a notification occurrs
@param aNotificationName the name of the notification the observer wants to watch
@@ -181,16 +181,20 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
@implementation _CPNotificationRegistry : CPObject
{
CPDictionary _objectObservers;
- BOOL _observerRemoval;
- CPArray _postingObservers;
+ BOOL _observerRemovalCount;
}
- (id)init
{
- if (self)
- _objectObservers = [CPDictionary dictionary];
+ self = [super init];
- return self;
+ if (self)
+ {
+ _observerRemovalCount = 0;
+ _objectObservers = [CPDictionary dictionary];
+ }
+
+ return self;
}
-(void)addObserver:(_CPNotificationObserver)anObserver object:(id)anObject
@@ -201,16 +205,13 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
anObject = [CPNull null];
// Grab all the listeners for this notification/object pair
- var observers = [_objectObservers objectForKey:[anObject hash]];
+ var observers = [_objectObservers objectForKey:[anObject UID]];
if (!observers)
{
observers = [];
- [_objectObservers setObject:observers forKey:[anObject hash]];
+ [_objectObservers setObject:observers forKey:[anObject UID]];
}
-
- if (observers == _postingObservers)
- _postingObservers = [observers copy];
// Add this observer.
observers.push(anObserver);
@@ -235,10 +236,7 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
while (count--)
if ([observers[count] observer] == anObserver)
{
- _observerRemoval = YES;
- if (observers == _postingObservers)
- _postingObservers = [observers copy];
-
+ ++_observerRemovalCount;
observers.splice(count, 1);
}
@@ -248,17 +246,14 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
}
else
{
- var key = [anObject hash],
+ var key = [anObject UID],
observers = [_objectObservers objectForKey:key];
count = observers ? observers.length : 0;
while (count--)
if ([observers[count] observer] == anObserver)
{
- _observerRemoval = YES;
- if (observers == _postingObservers)
- _postingObservers = [observers copy];
-
+ ++_observerRemovalCount;
observers.splice(count, 1)
}
@@ -282,47 +277,45 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
// However, this is a very expensive operation (O(N) => O(N^2)), so to avoid it,
// we keep track of whether observers are added or removed, and only do our
// rigorous testing in those cases.
- var object = [aNotification object];
-
- if (object != nil && (_postingObservers = [_objectObservers objectForKey:[object hash]]))
+ var observerRemovalCount = _observerRemovalCount,
+ object = [aNotification object],
+ observers = nil;
+
+ if (object != nil && (observers = [[_objectObservers objectForKey:[object UID]] copy]))
{
- var observers = _postingObservers,
+ var currentObservers = observers,
count = observers.length;
- _observerRemoval = NO;
while (count--)
{
- var observer = _postingObservers[count];
+ var observer = observers[count];
// if there wasn't removal of an observer during this posting, or there
// was but we are still in the observer list...
- if (!_observerRemoval || [observers indexOfObjectIdenticalTo:observer] != CPNotFound)
+ if ((observerRemovalCount === _observerRemovalCount) || [currentObservers indexOfObjectIdenticalTo:observer] !== CPNotFound)
[observer postNotification:aNotification];
-
}
}
// Now do the same for the nil object observers...
- _postingObservers = [_objectObservers objectForKey:[[CPNull null] hash]];
-
- if (!_postingObservers)
+ observers = [[_objectObservers objectForKey:[[CPNull null] UID]] copy];
+
+ if (!observers)
return;
-
- var observers = _postingObservers,
- count = observers.length;
-
- _observerRemoval = NO;
+
+ var observerRemovalCount = _observerRemovalCount,
+ count = observers.length,
+ currentObservers = observers;
+
while (count--)
{
- var observer = _postingObservers[count];
-
+ var observer = observers[count];
+
// if there wasn't removal of an observer during this posting, or there
// was but we are still in the observer list...
- if (!_observerRemoval || [observers indexOfObjectIdenticalTo:observer] != CPNotFound)
+ if ((observerRemovalCount === _observerRemovalCount) || [currentObservers indexOfObjectIdenticalTo:observer] !== CPNotFound)
[observer postNotification:aNotification];
}
-
- _postingObservers = nil;
}
- (unsigned)count
diff --git a/Foundation/CPNull.j b/Foundation/CPNull.j
index a0aca8598..43ba1cbc9 100644
--- a/Foundation/CPNull.j
+++ b/Foundation/CPNull.j
@@ -28,10 +28,10 @@ var CPNullSharedNull = nil;
/*!
@class CPNull
@ingroup foundation
- @brief An object representation of nil.
+ @brief An object representation of \c nil.
- This class is used as an object representation of nil. This is handy when a collection
- only accepts objects as values, but you would like a nil representation in there.
+ This class is used as an object representation of \c nil. This is handy when a collection
+ only accepts objects as values, but you would like a \c nil representation in there.
*/
@implementation CPNull : CPObject
{
@@ -46,7 +46,7 @@ var CPNullSharedNull = nil;
}*/
/*!
Returns the singleton instance of the CPNull
- object. While CPNull and nil should
+ object. While CPNull and \c nil should
be interpreted as the same, they are not equal ('==').
*/
+ (CPNull)null
diff --git a/Foundation/CPNumber.j b/Foundation/CPNumber.j
index e1dccbeff..ffb89c537 100644
--- a/Foundation/CPNumber.j
+++ b/Foundation/CPNumber.j
@@ -33,7 +33,7 @@ var __placeholder = new Number(),
@brief A bridged object to native Javascript numbers.
This class primarily exists for source compatability. The JavaScript
- Number type can be changed on the fly based on context,
+ \c Number type can be changed on the fly based on context,
so there is no need to call any of these methods.
In other words, native JavaScript numbers are bridged to CPNumber,
diff --git a/Foundation/CPObject.j b/Foundation/CPObject.j
index 06e744efb..e9173f372 100644
--- a/Foundation/CPObject.j
+++ b/Foundation/CPObject.j
@@ -55,9 +55,9 @@
To get description value you can use %@ specifier everywhere where format
specifiers are allowed:
var inst = [[SomeClass alloc] initWithSomeValue:10];
-CPLog(@"Got some class: %@", inst);
+CPLog(@"Got some class: %@", inst);
would output:
-
}
/*!
- Allocates a new instance of the receiver, and sends it an init
+ Allocates a new instance of the receiver, and sends it an \c -init
@return the new object
*/
+ (id)new
@@ -93,6 +93,11 @@ CPLog(@"Got some class: %@", inst);
return class_createInstance(self);
}
++ (id)allocWithCoder:(CPCoder)aCoder
+{
+ return [self alloc];
+}
+
/*!
Initializes the receiver
@return the initialized receiver
@@ -153,7 +158,7 @@ CPLog(@"Got some class: %@", inst);
}
/*!
- Returns YES if the receiving class is a subclass of aClass.
+ Returns \c YES if the receiving class is a subclass of \c aClass.
@param aClass the class to test inheritance from
*/
+ (BOOL)isSubclassOfClass:(Class)aClass
@@ -168,7 +173,7 @@ CPLog(@"Got some class: %@", inst);
}
/*!
- Returns YES if the receiver is a aClass type, or a subtype of it.
+ Returns \c YES if the receiver is a \c aClass type, or a subtype of it.
@param aClass the class to test as the receiver's class or super class.
*/
- (BOOL)isKindOfClass:(Class)aClass
@@ -182,7 +187,7 @@ CPLog(@"Got some class: %@", inst);
}
/*!
- Returns YES if the receiver is of the aClass class type.
+ Returns \c YES if the receiver is of the \c aClass class type.
@param aClass the class to test the receiper
*/
- (BOOL)isMemberOfClass:(Class)aClass
@@ -197,7 +202,7 @@ CPLog(@"Got some class: %@", inst);
/*!
Determines whether the receiver's root object is a proxy.
- @return YES if the root object is a proxy
+ @return \c YES if the root object is a proxy
*/
- (BOOL)isProxy
{
@@ -208,7 +213,7 @@ CPLog(@"Got some class: %@", inst);
/*!
Test whether instances of this class respond to the provided selector.
@param aSelector the selector for which to test the class
- @return YES if instances of the class respond to the selector
+ @return \c YES if instances of the class respond to the selector
*/
+ (BOOL)instancesRespondToSelector:(SEL)aSelector
{
@@ -218,7 +223,7 @@ CPLog(@"Got some class: %@", inst);
/*!
Tests whether the receiver responds to the provided selector.
@param aSelector the selector for which to test the receiver
- @return YES if the receiver responds to the selector
+ @return \c YES if the receiver responds to the selector
*/
- (BOOL)respondsToSelector:(SEL)aSelector
{
@@ -264,7 +269,7 @@ CPLog(@"Got some class: %@", inst);
*/
- (CPString)description
{
- return "<" + isa.name + " 0x" + [CPString stringWithHash:[self hash]] + ">";
+ return "<" + isa.name + " 0x" + [CPString stringWithHash:[self UID]] + ">";
}
// Sending Messages
@@ -305,7 +310,7 @@ CPLog(@"Got some class: %@", inst);
/*!
Subclasses can override this method to forward message to
other objects. Overwriting this method in conjunction with
- methodSignatureForSelector: allows the receiver to
+ \c -methodSignatureForSelector: allows the receiver to
forward messages for which it does not respond, to another object that does.
*/
- (void)forwardInvocation:(CPInvocation)anInvocation
@@ -352,7 +357,7 @@ CPLog(@"Got some class: %@", inst);
{
[CPException raise:CPInvalidArgumentException reason:
(class_isMetaClass(isa) ? "+" : "-") + " [" + [self className] + " " + aSelector + "] unrecognized selector sent to " +
- (class_isMetaClass(isa) ? "class" : "instance") + " 0x" + [CPString stringWithHash:[self hash]]];
+ (class_isMetaClass(isa) ? "class" : "instance") + " 0x" + [CPString stringWithHash:[self UID]]];
}
// Archiving
@@ -371,7 +376,7 @@ CPLog(@"Got some class: %@", inst);
/*!
Can be overridden by subclasses to substitute a different class to represent the receiver for keyed archiving.
- @return the class to use. A nil means to ignore the method result.
+ @return the class to use. A \c nil means to ignore the method result.
*/
- (Class)classForKeyedArchiver
{
@@ -472,12 +477,12 @@ CPLog(@"Got some class: %@", inst);
}
/*!
- Determines if anObject is functionally equivalent to the receiver.
- @return YES if anObject is functionally equivalent to the receiver.
+ Determines if \c anObject is functionally equivalent to the receiver.
+ @return \c YES if \c anObject is functionally equivalent to the receiver.
*/
- (BOOL)isEqual:(id)anObject
{
- return self === anObject || [self hash] === [anObject hash];
+ return self === anObject || [self UID] === [anObject UID];
}
/*!
diff --git a/Foundation/CPPropertyListSerialization.j b/Foundation/CPPropertyListSerialization.j
index 19c71fa5c..342a55257 100644
--- a/Foundation/CPPropertyListSerialization.j
+++ b/Foundation/CPPropertyListSerialization.j
@@ -23,6 +23,7 @@
@import "CPObject.j"
+CPPropertyListUnknownFormat = 0;
CPPropertyListOpenStepFormat = kCFPropertyListOpenStepFormat;
CPPropertyListXMLFormat_v1_0 = kCFPropertyListXMLFormat_v1_0;
CPPropertyListBinaryFormat_v1_0 = kCFPropertyListBinaryFormat_v1_0;
diff --git a/Foundation/CPRange.j b/Foundation/CPRange.j
index aa446f77f..3e0bafa7b 100755
--- a/Foundation/CPRange.j
+++ b/Foundation/CPRange.j
@@ -60,7 +60,7 @@ function CPMakeRangeCopy(aRange)
}
/*!
- Sets a range's length to 0.
+ Sets a range's \c length to 0.
@param aRange the range to empty
@group CPRange
@return CPRange the empty range (same as the argument)
@@ -71,7 +71,7 @@ function CPEmptyRange(aRange)
}
/*!
- Finds the range maximum. (location + length)
+ Finds the range maximum. (\c location + length)
@param aRange the range to calculate a maximum from
@group CPRange
@return int the range maximum
@@ -85,7 +85,7 @@ function CPMaxRange(aRange)
Determines if two CPRanges are equal.
@param lhsRange the first CPRange
@param rhsRange the second CPRange
- @return BOOL YES if the two CPRanges are equal.
+ @return BOOL \c YES if the two CPRanges are equal.
*/
function CPEqualRanges(lhsRange, rhsRange)
{
@@ -97,7 +97,7 @@ function CPEqualRanges(lhsRange, rhsRange)
@param aLocation the number to check
@param aRange the CPRange to check within
@group CPRange
- @return BOOL YES if aLocation/code> is within the range
+ @return BOOL \c YES if \c aLocation is within the range
*/
function CPLocationInRange(aLocation, aRange)
{
@@ -105,8 +105,8 @@ function CPLocationInRange(aLocation, aRange)
}
/*!
- Creates a new range with the minimum location and a length
- that extends to the maximum length.
+ Creates a new range with the minimum \c location and a \c length
+ that extends to the maximum \c length.
@param lhsRange the first CPRange
@param rhsRange the second CPRange
@group CPRange
diff --git a/Foundation/CPSet.j b/Foundation/CPSet.j
index 824b925dc..a44fbe2ac 100644
--- a/Foundation/CPSet.j
+++ b/Foundation/CPSet.j
@@ -232,7 +232,7 @@
*/
- (BOOL)containsObject:(id)anObject
{
- if (_contents[[anObject hash]] && [_contents[[anObject hash]] isEqual:anObject])
+ if (_contents[[anObject UID]] && [_contents[[anObject UID]] isEqual:anObject])
return YES;
return NO;
@@ -372,7 +372,10 @@
*/
- (void)addObject:(id)anObject
{
- _contents[[anObject hash]] = anObject;
+ if ([self containsObject:anObject])
+ return;
+
+ _contents[[anObject UID]] = anObject;
_count++;
}
@@ -380,12 +383,12 @@
Adds to the receiver each object contained in a given array that is not already a member.
@param array An array of objects to add to the receiver.
*/
-- (void)addObjectsFromArray:(CPArray)array
+- (void)addObjectsFromArray:(CPArray)objects
{
- for (var i = 0, count = array.length; i < count; i++)
- {
- [self addObject:array[i]];
- }
+ var count = [objects count];
+
+ while (count--)
+ [self addObject:objects[count]];
}
/*
@@ -396,11 +399,19 @@
{
if ([self containsObject:anObject])
{
- delete _contents[[anObject hash]];
+ delete _contents[[anObject UID]];
_count--;
}
}
+- (void)removeObjectsInArray:(CPArray)objects
+{
+ var count = [objects count];
+
+ while (count--)
+ [self removeObject:objects[count]];
+}
+
/*
Empties the receiver of all of its members.
*/
diff --git a/Foundation/CPSortDescriptor.j b/Foundation/CPSortDescriptor.j
index 27dca8d9c..415e0b01a 100755
--- a/Foundation/CPSortDescriptor.j
+++ b/Foundation/CPSortDescriptor.j
@@ -59,6 +59,11 @@ CPOrderedDescending = 1;
BOOL _ascending;
}
++ (id)sortDescriptorWithKey:(CPString)aKey ascending:(BOOL)isAscending
+{
+ return [[self alloc] initWithKey:aKey ascending:isAscending];
+}
+
// Initializing a sort descriptor
/*!
Initializes the sort descriptor.
@@ -71,6 +76,11 @@ CPOrderedDescending = 1;
return [self initWithKey:aKey ascending:isAscending selector:@selector(compare:)];
}
++ (id)sortDescriptorWithKey:(CPString)aKey ascending:(BOOL)isAscending selector:(SEL)aSelector
+{
+ return [[self alloc] initWithKey:aKey ascending:isAscending selector:aSelector];
+}
+
/*!
Initializes the sort descriptor
@param aKey the property key path to sort
@@ -94,7 +104,7 @@ CPOrderedDescending = 1;
// Getting information about a sort descriptor
/*!
- Returns YES if the sort descriptor's order is ascending.
+ Returns \c YES if the sort descriptor's order is ascending.
*/
- (BOOL)ascending
{
diff --git a/Foundation/CPString.j b/Foundation/CPString.j
index e4eff6bbb..0639bb8b1 100644
--- a/Foundation/CPString.j
+++ b/Foundation/CPString.j
@@ -62,7 +62,8 @@ var CPStringRegexSpecialCharacters = [
'/', '.', '*', '+', '?', '|', '$', '^',
'(', ')', '[', ']', '{', '}', '\\'
],
- CPStringRegexEscapeExpression = new RegExp("(\\" + CPStringRegexSpecialCharacters.join("|\\") + ")", 'g');
+ CPStringRegexEscapeExpression = new RegExp("(\\" + CPStringRegexSpecialCharacters.join("|\\") + ")", 'g'),
+ CPStringRegexTrimWhitespace = new RegExp("(^\\s+|\\s+$)", 'g');
/*!
@class CPString
@@ -70,7 +71,7 @@ var CPStringRegexSpecialCharacters = [
@brief An immutable string (collection of characters).
CPString is an object that allows management of strings. Because CPString is
- based on the JavaScript String object, CPStrings are immutable, although the
+ based on the JavaScript \c String object, CPStrings are immutable, although the
class does have methods that create new CPStrings generated from modifications to the
receiving instance.
@@ -107,8 +108,8 @@ var CPStringRegexSpecialCharacters = [
/*!
Returns a copy of the specified string.
- @param aString a non-nil string to copy
- @throws CPInvalidArgumentException if aString is nil
+ @param aString a non-\c nil string to copy
+ @throws CPInvalidArgumentException if \c aString is \c nil
@return the new CPString
*/
+ (id)stringWithString:(CPString)aString
@@ -248,11 +249,11 @@ var CPStringRegexSpecialCharacters = [
/*!
Tokenizes the receiver string using the specified
delimiter. For example, if the receiver is:
-
"arash.francisco.ross.tom"
+ \c "arash.francisco.ross.tom"
and the delimiter is:
-
"."
+ \c "."
the returned array would contain:
-
["arash", "francisco", "ross", "tom"]
+
["arash", "francisco", "ross", "tom"]
@param the delimiter
@return the array of tokens
*/
@@ -272,7 +273,7 @@ var CPStringRegexSpecialCharacters = [
}
/*!
- Returns a substring starting from the specified range location to the range length.
+ Returns a substring starting from the specified range \c location to the range \c length.
@param the range of the substring
@return the substring
*/
@@ -295,7 +296,7 @@ var CPStringRegexSpecialCharacters = [
/*!
Finds the range of characters in the receiver where the specified string exists. If the string
- does not exist in the receiver, the range length will be 0.
+ does not exist in the receiver, the range \c length will be 0.
@param aString the string to search for in the receiver
@return the range of charactrs in the receiver
*/
@@ -319,7 +320,7 @@ var CPStringRegexSpecialCharacters = [
@param aString the string to search for
@param aMask the options to use in the search
@return the range of characters in the receiver. If the string was not found,
- the length of the range will be 0.
+ the \c length of the range will be 0.
*/
- (CPRange)rangeOfString:(CPString)aString options:(int)aMask
{
@@ -342,7 +343,7 @@ var CPStringRegexSpecialCharacters = [
@param aMask the options to use in the search
@param aRange the range of the receiver in which to search for
@return the range of characters in the receiver. If the string was not found,
- the length of the range will be 0.
+ the \c length of the range will be 0.
*/
- (CPRange)rangeOfString:(CPString)aString options:(int)aMask range:(CPrange)aRange
{
@@ -376,7 +377,7 @@ var CPStringRegexSpecialCharacters = [
Returns a new string in which all occurrences of a target string in the reciever are replaced by
another given string.
@param target The string to replace.
- @param replacement the string with which to replace the
target
+ @param replacement the string with which to replace the \c target
*/
- (CPString)stringByReplacingOccurrencesOfString:(CPString)target withString:(CPString)replacement
@@ -388,9 +389,9 @@ var CPStringRegexSpecialCharacters = [
Returns a new string in which all occurrences of a target string in a specified range of the receiver
are replaced by another given string.
@param target The string to replace
- @param replacement the string with which to replace the
target
- @param options A mask of options to use when comparing
target
with the receiver. Pass 0 to specify no options
- @param searchRange The range in the receiver in which to search for
target
.
+ @param replacement the string with which to replace the \c target.
+ @param options A mask of options to use when comparing \c target with the receiver. Pass 0 to specify no options
+ @param searchRange The range in the receiver in which to search for \c target.
*/
- (CPString)stringByReplacingOccurrencesOfString:(CPString)target withString:(CPString)replacement options:(int)options range:(CPRange)searchRange
@@ -413,7 +414,7 @@ var CPStringRegexSpecialCharacters = [
Returns a new string in which the characters in a specified range of the receiver
are replaced by a given string.
@param range A range of characters in the receiver.
- @param replacement The string with which to replace the characters in
range
.
+ @param replacement The string with which to replace the characters in \c range.
*/
- (CPString)stringByReplacingCharactersInRange:(CPRange)range withString:(CPString)replacement
@@ -421,6 +422,13 @@ var CPStringRegexSpecialCharacters = [
return '' + substring(0, range.location) + replacement + substring(range.location + range.length, self.length);
}
+/*!
+ Returns a new string with leading and trailing whitespace trimmed
+*/
+- (CPString)stringByTrimmingWhitespace
+{
+ return self.replace(CPStringRegexTrimWhitespace, "");
+}
// Identifying and comparing strings
@@ -486,9 +494,9 @@ var CPStringRegexSpecialCharacters = [
}
/*!
- Returns YES if the receiver starts
- with the specified string. If aString
- is empty, the method will return NO.
+ Returns \c YES if the receiver starts
+ with the specified string. If \c aString
+ is empty, the method will return \c NO.
*/
- (BOOL)hasPrefix:(CPString)aString
{
@@ -496,9 +504,9 @@ var CPStringRegexSpecialCharacters = [
}
/*!
- Returns NO if the receiver ends
- with the specified string. If aString
- is empty, the method will return NO.
+ Returns \c NO if the receiver ends
+ with the specified string. If \c aString
+ is empty, the method will return \c NO.
*/
- (BOOL)hasSuffix:(CPString)aString
{
@@ -506,7 +514,7 @@ var CPStringRegexSpecialCharacters = [
}
/*!
- Returns YES if the specified string contains the same characters as the receiver.
+ Returns \c YES if the specified string contains the same characters as the receiver.
*/
- (BOOL)isEqualToString:(CPString)aString
{
@@ -569,8 +577,8 @@ var CPStringRegexSpecialCharacters = [
return parseFloat(self, 10);
}
/*!
- Returns YES on encountering one of "Y", "y", "T", "t", or
- a digit 1-9. Returns NO otherwise. This method skips the initial
+ Returns \c YES on encountering one of "Y", "y", "T", "t", or
+ a digit 1-9. Returns \c NO otherwise. This method skips the initial
whitespace characters, +,- followed by Zeroes.
*/
@@ -673,7 +681,7 @@ var CPStringRegexSpecialCharacters = [
*/
+ (CPString)JSONFromObject:(JSObject)anObject
{
- return CPJSObjectCreateJSON(anObject);
+ return JSON.stringify(anObject);
}
/*!
@@ -681,7 +689,7 @@ var CPStringRegexSpecialCharacters = [
*/
- (JSObject)objectFromJSON
{
- return CPJSObjectCreateWithJSON(self);
+ return JSON.parse(self);
}
@end
diff --git a/Foundation/CPTimer.j b/Foundation/CPTimer.j
index 62d1dad7e..e1ec83ce5 100644
--- a/Foundation/CPTimer.j
+++ b/Foundation/CPTimer.j
@@ -87,7 +87,7 @@
*/
+ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
{
- return [[self alloc] initWithFireDate:nil interval:seconds invocation:anInvocation repeats:shouldRepeat];
+ return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:anInvocation repeats:shouldRepeat];
}
/*!
@@ -95,7 +95,7 @@
*/
+ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
{
- return [[self alloc] initWithFireDate:nil interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat];
+ return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat];
}
/*!
@@ -103,7 +103,7 @@
*/
+ (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
{
- return [[self alloc] initWithFireDate:nil interval:seconds callback:aFunction repeats:shouldRepeat];
+ return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds callback:aFunction repeats:shouldRepeat];
}
/*!
diff --git a/Foundation/CPURL.j b/Foundation/CPURL.j
new file mode 100644
index 000000000..14c1d0c5c
--- /dev/null
+++ b/Foundation/CPURL.j
@@ -0,0 +1,598 @@
+
+@import
+
+CPURLNameKey = @"CPURLNameKey";
+CPURLLocalizedNameKey = @"CPURLLocalizedNameKey";
+CPURLIsRegularFileKey = @"CPURLIsRegularFileKey";
+CPURLIsDirectoryKey = @"CPURLIsDirectoryKey";
+CPURLIsSymbolicLinkKey = @"CPURLIsSymbolicLinkKey";
+CPURLIsVolumeKey = @"CPURLIsVolumeKey";
+CPURLIsPackageKey = @"CPURLIsPackageKey";
+CPURLIsSystemImmutableKey = @"CPURLIsSystemImmutableKey";
+CPURLIsUserImmutableKey = @"CPURLIsUserImmutableKey";
+CPURLIsHiddenKey = @"CPURLIsHiddenKey";
+CPURLHasHiddenExtensionKey = @"CPURLHasHiddenExtensionKey";
+CPURLCreationDateKey = @"CPURLCreationDateKey";
+CPURLContentAccessDateKey = @"CPURLContentAccessDateKey";
+CPURLContentModificationDateKey = @"CPURLContentModificationDateKey";
+CPURLAttributeModificationDateKey = @"CPURLAttributeModificationDateKey";
+CPURLLinkCountKey = @"CPURLLinkCountKey";
+CPURLParentDirectoryURLKey = @"CPURLParentDirectoryURLKey";
+CPURLVolumeURLKey = @"CPURLTypeIdentifierKey";
+CPURLTypeIdentifierKey = @"CPURLTypeIdentifierKey";
+CPURLLocalizedTypeDescriptionKey = @"CPURLLocalizedTypeDescriptionKey";
+CPURLLabelNumberKey = @"CPURLLabelNumberKey";
+CPURLLabelColorKey = @"CPURLLabelColorKey";
+CPURLLocalizedLabelKey = @"CPURLLocalizedLabelKey";
+CPURLEffectiveIconKey = @"CPURLEffectiveIconKey";
+CPURLCustomIconKey = @"CPURLCustomIconKey";
+
+@implementation CPURL : CPObject
+{
+ CPURL _base @accessors(readonly, property=baseURL);
+ CPString _relative @accessors(readonly, property=relativeString);
+
+ CPDictionary _resourceValues;
+}
+
+- (id)initWithScheme:(CPString)scheme host:(CPString)host path:(CPString)path
+{
+ var uri = new URI();
+ uri.scheme = scheme;
+ uri.authority = host;
+ uri.path = path;
+ [self initWithString:uri.toString()];
+}
+
+- (id)initWithString:(CPString)URLString
+{
+ return [self initWithString:URLString relativeToURL:nil];
+}
+
++ (id)URLWithString:(CPString)URLString
+{
+ return [[self alloc] initWithString:URLString];
+}
+
+- (id)initWithString:(CPString)URLString relativeToURL:(CPURL)baseURL
+{
+ if (!URI_RE.test(URLString))
+ return nil;
+
+ if (self)
+ {
+ _base = baseURL;
+ _relative = URLString;
+ _resourceValues = [CPDictionary dictionary];
+ }
+
+ return self;
+}
+
++ (id)URLWithString:(CPString)URLString relativeToURL:(CPURL)baseURL
+{
+ return [[self alloc] initWithString:URLString relativeToURL:baseURL];
+}
+
+- (CPURL)absoluteURL
+{
+ var absStr = [self absoluteString];
+
+ if (absStr !== _relative)
+ return [[CPURL alloc] initWithString:absStr];
+
+ return self;
+}
+
+- (CPString)absoluteString
+{
+ return resolve([_base absoluteString] || "", _relative);
+}
+
+// if absolute, returns same as absoluteString
+- (CPString)relativeString
+{
+ return _relative;
+}
+
+- (CPString)path
+{
+ var str = [self absoluteString];
+ return URI_RE.test(str) ? (parse(str).path || nil) : nil;
+}
+
+// if absolute, returns the same as path
+- (CPString)relativePath
+{
+ return URI_RE.test(_relative) ? (parse(_relative).path || nil) : nil;
+}
+
+
+- (CPString)scheme
+{
+ var str = [self absoluteString];
+ return URI_RE.test(str) ? (parse(str).protocol || nil) : nil;
+}
+
+- (CPString)user
+{
+ var str = [self absoluteString];
+ return URI_RE.test(str) ? (parse(str).user || nil) : nil;
+}
+
+- (CPString)password
+{
+ var str = [self absoluteString];
+ return URI_RE.test(str) ? (parse(str).password || nil) : nil;
+}
+
+- (CPString)host
+{
+ var str = [self absoluteString];
+ return URI_RE.test(str) ? (parse(str).domain || nil) : nil;
+}
+
+- (CPString)port
+{
+ var str = [self absoluteString];
+ if (URI_RE.test(str)) {
+ var port = parse(str).port;
+ if (port)
+ return parseInt(port, 10);
+ }
+ return nil;
+}
+
+- (CPString)parameterString
+{
+ var str = [self absoluteString];
+ return URI_RE.test(str) ? (parse(str).query || nil) : nil;
+}
+
+- (CPString)fragment
+{
+ var str = [self absoluteString];
+ return URI_RE.test(str) ? (parse(str).anchor || nil) : nil;
+}
+
+- (BOOL)isEqual:(id)anObject
+{
+ // Is checking if baseURL isEqual correct? Does "identical" mean same object or equivalent values?
+ return [self relativeString] === [anObject relativeString] &&
+ ([self baseURL] === [anObject baseURL] || [[self baseURL] isEqual:[anObject baseURL]]);
+}
+
+- (CPString)lastPathComponent
+{
+ var path = [self path];
+ return path ? path.split("/").pop() : nil;
+}
+
+- (CPString)pathExtension
+{
+ var path = [self path],
+ ext = path.match(/\.(\w+)$/);
+ return ext ? ext[1] : "";
+}
+
+- (CPURL)standardizedURL
+{
+ return [CPURL URLWithString:format(parse(_relative)) relativeToURL:_base];
+}
+
+- (BOOL)isFileURL
+{
+ return [self scheme] === "file";
+}
+
+- (CPString)description
+{
+ return [self absoluteString];
+}
+
+- (id)resourceValueForKey:(CPString)aKey
+{
+ return [_resourceValues objectForKey:aKey];
+}
+
+- (id)setResourceValue:(id)anObject forKey:(CPString)aKey
+{
+ [_resourceValues setObject:anObject forKey:aKey];
+}
+
+@end
+
+@implementation CPURL (CPCoding)
+
+- (id)initWithCoder:(CPCoder)aCoder
+{
+ _base = [aCoder decodeObjectForKey:"CPURLBaseKey"];
+ _relative = [aCoder decodeObjectForKey:"CPURLRelativeKey"];
+ return self;
+}
+
+- (void)encodeWithCoder:(CPCoder)aCoder
+{
+ [aCoder encodeObject:_base forKey:"CPURLBaseKey"];
+ [aCoder encodeObject:_relative forKey:"CPURLRelativeKey"];
+}
+
+@end
+
+// original code: http://code.google.com/p/js-uri/
+
+// Based on the regex in RFC2396 Appendix B.
+var URI_RE = /^(?:([^:\/?\#]+):)?(?:\/\/([^\/?\#]*))?([^?\#]*)(?:\?([^\#]*))?(?:\#(.*))?/;
+
+/**
+ * Uniform Resource Identifier (URI) - RFC3986
+ */
+var URI = function(str) {
+ if (!str) str = "";
+ var result = str.match(URI_RE);
+ this.scheme = result[1] || null;
+ this.authority = result[2] || null;
+ this.path = result[3] || null;
+ this.query = result[4] || null;
+ this.fragment = result[5] || null;
+}
+
+/**
+ * Convert the URI to a String.
+ */
+URI.prototype.toString = function () {
+ var str = "";
+
+ if (this.scheme)
+ str += this.scheme + ":";
+
+ if (this.authority)
+ str += "//" + this.authority;
+
+ if (this.path)
+ str += this.path;
+
+ if (this.query)
+ str += "?" + this.query;
+
+ if (this.fragment)
+ str += "#" + this.fragment;
+
+ return str;
+}
+
+var parse = function(uri) {
+ return new URI(uri);
+}
+
+var unescape = function(str, plus) {
+ return decodeURI(str).replace(/\+/g, " ");
+}
+
+var unescapeComponent = function(str, plus) {
+ return decodeURIComponent(str).replace(/\+/g, " ");
+}
+
+// from Chiron's HTTP module:
+
+/**** keys
+ members of a parsed URI object.
+*/
+var keys = [
+ "url",
+ "protocol",
+ "authorityRoot",
+ "authority",
+ "userInfo",
+ "user",
+ "password",
+ "domain",
+ "domains",
+ "port",
+ "path",
+ "root",
+ "directory",
+ "directories",
+ "file",
+ "query",
+ "anchor"
+];
+
+/**** expressionKeys
+ members of a parsed URI object that you get
+ from evaluting the strict regular expression.
+*/
+var expressionKeys = [
+ "url",
+ "protocol",
+ "authorityRoot",
+ "authority",
+ "userInfo",
+ "user",
+ "password",
+ "domain",
+ "port",
+ "path",
+ "root",
+ "directory",
+ "file",
+ "query",
+ "anchor"
+];
+
+/**** strictExpression
+*/
+var strictExpression = new RegExp( /* url */
+ "^" +
+ "(?:" +
+ "([^:/?#]+):" + /* protocol */
+ ")?" +
+ "(?:" +
+ "(//)" + /* authorityRoot */
+ "(" + /* authority */
+ "(?:" +
+ "(" + /* userInfo */
+ "([^:@]*)" + /* user */
+ ":?" +
+ "([^:@]*)" + /* password */
+ ")?" +
+ "@" +
+ ")?" +
+ "([^:/?#]*)" + /* domain */
+ "(?::(\\d*))?" + /* port */
+ ")" +
+ ")?" +
+ "(" + /* path */
+ "(/?)" + /* root */
+ "((?:[^?#/]*/)*)" +
+ "([^?#]*)" + /* file */
+ ")" +
+ "(?:\\?([^#]*))?" + /* query */
+ "(?:#(.*))?" /*anchor */
+);
+
+/**** Parser
+ returns a URI parser function given
+ a regular expression that renders
+ `expressionKeys` and returns an `Object`
+ mapping all `keys` to values.
+*/
+var Parser = function (expression) {
+ return function (url) {
+ if (typeof url == "undefined")
+ throw new Error("HttpError: URL is undefined");
+ if (typeof url != "string") return new Object(url);
+
+ var items = {};
+ var parts = expression.exec(url);
+
+ for (var i = 0; i < parts.length; i++) {
+ items[expressionKeys[i]] = parts[i] ? parts[i] : "";
+ }
+
+ items.root = (items.root || items.authorityRoot) ? '/' : '';
+
+ items.directories = items.directory.split("/");
+ if (items.directories[items.directories.length - 1] == "") {
+ items.directories.pop();
+ }
+
+ /* normalize */
+ var directories = [];
+ for (var i = 0; i < items.directories.length; i++) {
+ var directory = items.directories[i];
+ if (directory == '.') {
+ } else if (directory == '..') {
+ if (directories.length && directories[directories.length - 1] != '..')
+ directories.pop();
+ else
+ directories.push('..');
+ } else {
+ directories.push(directory);
+ }
+ }
+ items.directories = directories;
+
+ items.domains = items.domain.split(".");
+
+ return items;
+ };
+};
+
+/**** parse
+ a strict URI parser.
+*/
+var parse = Parser(strictExpression);
+
+/**** format
+ accepts a parsed URI object and returns
+ the corresponding string.
+*/
+var format = function (object) {
+ if (typeof(object) == 'undefined')
+ throw new Error("UrlError: URL undefined for urls#format");
+ if (object instanceof String || typeof(object) == 'string')
+ return object;
+ var domain =
+ object.domains ?
+ object.domains.join(".") :
+ object.domain;
+ var userInfo = (
+ object.user ||
+ object.password
+ ) ?
+ (
+ (object.user || "") +
+ (object.password ? ":" + object.password : "")
+ ) :
+ object.userInfo;
+ var authority = (
+ userInfo ||
+ domain ||
+ object.port
+ ) ? (
+ (userInfo ? userInfo + "@" : "") +
+ (domain || "") +
+ (object.port ? ":" + object.port : "")
+ ) :
+ object.authority;
+ var directory =
+ object.directories ?
+ object.directories.join("/") :
+ object.directory;
+ var path =
+ directory || object.file ?
+ (
+ (directory ? directory + "/" : "") +
+ (object.file || "")
+ ) :
+ object.path;
+ return (
+ (object.protocol ? object.protocol + ":" : "") +
+ (authority ? "//" + authority : "") +
+ (object.root || (authority && path) ? "/" : "") +
+ (path ? path : "") +
+ (object.query ? "?" + object.query : "") +
+ (object.anchor ? "#" + object.anchor : "")
+ ) || object.url || "";
+};
+
+/**** resolveObject
+ returns an object representing a URL resolved from
+ a relative location and a source location.
+*/
+var resolveObject = function (source, relative) {
+ if (!source)
+ return relative;
+
+ source = parse(source);
+ relative = parse(relative);
+
+ if (relative.url == "")
+ return source;
+
+ delete source.url;
+ delete source.authority;
+ delete source.domain;
+ delete source.userInfo;
+ delete source.path;
+ delete source.directory;
+
+ if (
+ relative.protocol && relative.protocol != source.protocol ||
+ relative.authority && relative.authority != source.authority
+ ) {
+ source = relative;
+ } else {
+ if (relative.root) {
+ source.directories = relative.directories;
+ } else {
+
+ var directories = relative.directories;
+ for (var i = 0; i < directories.length; i++) {
+ var directory = directories[i];
+ if (directory == ".") {
+ } else if (directory == "..") {
+ if (source.directories.length) {
+ source.directories.pop();
+ } else {
+ source.directories.push('..');
+ }
+ } else {
+ source.directories.push(directory);
+ }
+ }
+
+ if (relative.file == ".") {
+ relative.file = "";
+ } else if (relative.file == "..") {
+ source.directories.pop();
+ relative.file = "";
+ }
+ }
+ }
+
+ if (relative.root)
+ source.root = relative.root;
+ if (relative.protcol)
+ source.protocol = relative.protocol;
+ if (!(!relative.path && relative.anchor))
+ source.file = relative.file;
+ source.query = relative.query;
+ source.anchor = relative.anchor;
+
+ return source;
+};
+
+/**** relativeObject
+ returns an object representing a relative URL to
+ a given target URL from a source URL.
+*/
+var relativeObject = function (source, target) {
+ target = parse(target);
+ source = parse(source);
+
+ delete target.url;
+
+ if (
+ target.protocol == source.protocol &&
+ target.authority == source.authority
+ ) {
+ delete target.protocol;
+ delete target.authority;
+ delete target.userInfo;
+ delete target.user;
+ delete target.password;
+ delete target.domain;
+ delete target.domains;
+ delete target.port;
+ if (
+ !!target.root == !!source.root && !(
+ target.root &&
+ target.directories[0] != source.directories[0]
+ )
+ ) {
+ delete target.path;
+ delete target.root;
+ delete target.directory;
+ while (
+ source.directories.length &&
+ target.directories.length &&
+ target.directories[0] == source.directories[0]
+ ) {
+ target.directories.shift();
+ source.directories.shift();
+ }
+ while (source.directories.length) {
+ source.directories.shift();
+ target.directories.unshift('..');
+ }
+
+ if (!target.root && !target.directories.length && !target.file && source.file)
+ target.directories.push('.');
+
+ if (source.file == target.file)
+ delete target.file;
+ if (source.query == target.query)
+ delete target.query;
+ if (source.anchor == target.anchor)
+ delete target.anchor;
+ }
+ }
+
+ return target;
+};
+
+/**** resolve
+ returns a URL resovled to a relative URL from a source URL.
+*/
+var resolve = function (source, relative) {
+ return format(resolveObject(source, relative));
+};
+
+/**** relative
+ returns a relative URL to a target from a source.
+*/
+var relative = function (source, target) {
+ return format(relativeObject(source, target));
+};
diff --git a/Foundation/CPURLConnection.j b/Foundation/CPURLConnection.j
index 675a57cd5..dfe8cedbf 100644
--- a/Foundation/CPURLConnection.j
+++ b/Foundation/CPURLConnection.j
@@ -98,7 +98,7 @@ var CPURLConnectionDelegate = nil;
@param aRequest contains the URL to request the data from
@param aURLResponse not used
@param anError not used
- @return the data at the URL or nil if there was an error
+ @return the data at the URL or \c nil if there was an error
*/
+ (CPData)sendSynchronousRequest:(CPURLRequest)aRequest returningResponse:({CPURLResponse})aURLResponse error:({CPError})anError
{
@@ -106,17 +106,17 @@ var CPURLConnectionDelegate = nil;
{
var request = objj_request_xmlhttp();
- request.open([aRequest HTTPMethod], [aRequest URL], NO);
-
+ request.open([aRequest HTTPMethod], [[aRequest URL] absoluteString], NO);
+
var fields = [aRequest allHTTPHeaderFields],
key = nil,
keys = [fields keyEnumerator];
-
+
while (key = [keys nextObject])
request.setRequestHeader(key, [fields objectForKey:key]);
-
+
request.send([aRequest HTTPBody]);
-
+
return [CPData dataWithString:request.responseText];
}
catch (anException)
@@ -130,7 +130,7 @@ var CPURLConnectionDelegate = nil;
Creates a url connection with a delegate to monitor the request progress.
@param aRequest contains the URL to obtain data from
@param aDelegate will be sent messages related to the request progress
- @return a connection that can be started to initiate the request
+ @return a connection that can be \c started to initiate the request
*/
+ (CPURLConnection)connectionWithRequest:(CPURLRequest)aRequest delegate:(id)aDelegate
{
@@ -141,7 +141,7 @@ var CPURLConnectionDelegate = nil;
Default class initializer. Use one of the class methods instead.
@param aRequest contains the URL to contact
@param aDelegate will receive progress messages
- @param shouldStartImmediately whether the start method should be called from here
+ @param shouldStartImmediately whether the \c -start method should be called from here
@return the initialized url connection
*/
- (id)initWithRequest:(CPURLRequest)aRequest delegate:(id)aDelegate startImmediately:(BOOL)shouldStartImmediately
@@ -154,20 +154,21 @@ var CPURLConnectionDelegate = nil;
_delegate = aDelegate;
_isCanceled = NO;
- var path = [_request URL];
-
+ var URL = [_request URL],
+ scheme = [URL scheme];
+
// Browsers use "file:", Titanium uses "app:"
- _isLocalFileConnection = path.indexOf("file:") === 0 ||
- ((path.indexOf("http:") !== 0 || path.indexOf("https:") !== 0) &&
+ _isLocalFileConnection = scheme === "file" ||
+ ((scheme !== "http" || scheme !== "https:") &&
window.location &&
(window.location.protocol === "file:" || window.location.protocol === "app:"));
-
+
_XMLHTTPRequest = objj_request_xmlhttp();
-
+
if (shouldStartImmediately)
[self start];
}
-
+
return self;
}
@@ -193,7 +194,7 @@ var CPURLConnectionDelegate = nil;
try
{
- _XMLHTTPRequest.open([_request HTTPMethod], [_request URL], YES);
+ _XMLHTTPRequest.open([_request HTTPMethod], [[_request URL] absoluteString], YES);
_XMLHTTPRequest.onreadystatechange = function() { [self _readyStateDidChange]; }
diff --git a/Foundation/CPURLRequest.j b/Foundation/CPURLRequest.j
index 290d4b26a..a4d7eb136 100644
--- a/Foundation/CPURLRequest.j
+++ b/Foundation/CPURLRequest.j
@@ -62,7 +62,11 @@
if (self)
{
- _URL = aURL;
+ if ([aURL isKindOfClass:[CPString class]])
+ _URL = [CPURL URLWithString:aURL];
+ else
+ _URL = aURL;
+
_HTTPBody = @"";
_HTTPMethod = @"GET";
_HTTPHeaderFields = [CPDictionary dictionary];
diff --git a/Foundation/CPUndoManager.j b/Foundation/CPUndoManager.j
index 0bab9cfc7..1223b1e29 100644
--- a/Foundation/CPUndoManager.j
+++ b/Foundation/CPUndoManager.j
@@ -163,8 +163,8 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
execution of undo or redo actions, and tuning behavior parameters such as
the size of the undo stack. Each application entity with its own editing
history (e.g., a document) should have its own undo manager instance.
- Obtain an instance through a simple [[CPUndoManager alloc] init]
- message.
+ Obtain an instance through a simple \c [[CPUndoManager \c alloc] \c init]
+ message.
*/
@implementation CPUndoManager : CPObject
{
@@ -208,7 +208,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
// Registering Undo Operations
/*!
- Registers an undo operation. You invoke this method with the target of the undo action providing the selector which can perform the undo with the provided object. The object is often a dictionary of the identifying the attribute and their values before the change. The invocation will be added to the current grouping. If the registrations have been disabled through -disableUndoRegistration, this method does nothing.
+ Registers an undo operation. You invoke this method with the target of the undo action providing the selector which can perform the undo with the provided object. The object is often a dictionary of the identifying the attribute and their values before the change. The invocation will be added to the current grouping. If the registrations have been disabled through \c -disableUndoRegistration, this method does nothing.
@param aTarget the target for the undo invocation
@param aSelector the selector for the action message
@param anObject the argument for the action message
@@ -287,7 +287,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
// Checking Undo Ability
/*!
- Returns YES if the user can perform a redo operation.
+ Returns \c YES if the user can perform a redo operation.
*/
- (BOOL)canRedo
{
@@ -295,7 +295,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
}
/*!
- Returns YES if the user can perform an undo operation.
+ Returns \c YES if the user can perform an undo operation.
*/
- (BOOL)canUndo
{
@@ -447,7 +447,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
}
/*!
- Returns YES if the manager groups undo operations at every iteration of the run loop.
+ Returns \c YES if the manager groups undo operations at every iteration of the run loop.
*/
- (BOOL)groupsByEvent
{
@@ -456,7 +456,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
/*!
Sets whether the manager should group undo operations at every iteration of the run loop.
- @param aFlag YES groups undo operations
+ @param aFlag \c YES groups undo operations
*/
- (void)setGroupsByEvent:(BOOL)aFlag
{
@@ -502,7 +502,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
}
/*!
- Returns YES if undo registration is enabled.
+ Returns \c YES if undo registration is enabled.
*/
- (BOOL)isUndoRegistrationEnabled
{
@@ -511,7 +511,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
// Checking Whether Undo or Redo Is Being Performed
/*!
- Returns YES if the manager is currently performing an undo.
+ Returns \c YES if the manager is currently performing an undo.
*/
- (BOOL)isUndoing
{
@@ -519,7 +519,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
}
/*!
- Returns YES if the manager is currently performing a redo.
+ Returns \c YES if the manager is currently performing a redo.
*/
- (BOOL)isRedoing
{
@@ -584,8 +584,8 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
/*!
If the receiver can perform a redo, this method returns the action
name previously associated with the top grouping with
- -setActionName:. This name should identify the action to be redone.
- @return the redo action's name, or nil if no there's no redo on the stack.
+ \c -setActionName:. This name should identify the action to be redone.
+ @return the redo action's name, or \c nil if no there's no redo on the stack.
*/
- (CPString)redoActionName
{
@@ -595,8 +595,8 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
/*!
If the receiver can perform an undo, this method returns the action
name previously associated with the top grouping with
- -setActionName:. This name should identify the action to be undone.
- @return the undo action name or nil if no if there's no undo on the stack.
+ \c -setActionName:. This name should identify the action to be undone.
+ @return the undo action name or \c nil if no if there's no undo on the stack.
*/
- (CPString)undoActionName
{
@@ -606,7 +606,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
// Working With Run Loops
/*!
Returns the CPRunLoopModes in which the receiver registers
- the -endUndoGrouping processing when it -groupsByEvent.
+ the \c -endUndoGrouping processing when it \c -groupsByEvent.
*/
- (CPArray)runLoopModes
{
@@ -615,8 +615,8 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
/*!
Sets the modes in which the receiver registers the calls
- with the current run loop to invoke -endUndoGrouping
- when it -groupsByEvent. This method first
+ with the current run loop to invoke \c -endUndoGrouping
+ when it \c -groupsByEvent. This method first
cancels any pending registrations in the old modes and
registers the invocation in the new modes.
@param modes the modes in which calls are registered
diff --git a/Foundation/CPValue.j b/Foundation/CPValue.j
index e51f529a4..1c6de7a92 100644
--- a/Foundation/CPValue.j
+++ b/Foundation/CPValue.j
@@ -85,7 +85,7 @@ var CPValueValueKey = @"CPValueValueKey";
self = [super init];
if (self)
- _JSObject = CPJSObjectCreateWithJSON([aCoder decodeObjectForKey:CPValueValueKey]);
+ _JSObject = JSON.parse([aCoder decodeObjectForKey:CPValueValueKey]);
return self;
}
@@ -96,131 +96,19 @@ var CPValueValueKey = @"CPValueValueKey";
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
- [aCoder encodeObject:CPJSObjectCreateJSON(_JSObject) forKey:CPValueValueKey];
+ [aCoder encodeObject:JSON.stringify(_JSObject) forKey:CPValueValueKey];
}
@end
-var _JSONCharacterEncodings = {};
-
-_JSONCharacterEncodings['\b'] = "\\b";
-_JSONCharacterEncodings['\t'] = "\\t";
-_JSONCharacterEncodings['\n'] = "\\n";
-_JSONCharacterEncodings['\f'] = "\\f";
-_JSONCharacterEncodings['\r'] = "\\r";
-_JSONCharacterEncodings['"'] = "\\\"";
-_JSONCharacterEncodings['\\'] = "\\\\";
-
-// FIXME: Workaround for https://trac.280north.com/ticket/16
-var _JSONEncodedCharacters = new RegExp("[\\\"\\\\\\x00-\\x1f\\x7f-\\x9f]", 'g');
-
function CPJSObjectCreateJSON(aJSObject)
{
- // typeof new Number() and new String() gives you "object",
- // so valueof in those cases.
- var type = typeof aJSObject,
- valueOf = aJSObject ? aJSObject.valueOf() : null,
- typeValueOf = typeof valueOf;
-
- if (type != typeValueOf)
- {
- type = typeValueOf;
- aJSObject = valueOf;
- }
-
- switch (type)
- {
- case "string": // If the string contains no control characters, no quote characters, and no
- // backslash characters, then we can safely slap some quotes around it.
- // Otherwise we must also replace the offending characters with safe sequences.
-
- if (!_JSONEncodedCharacters.test(aJSObject))
- return '"' + aJSObject + '"';
-
- return '"' + aJSObject.replace(_JSONEncodedCharacters, _CPJSObjectEncodeCharacter) + '"';
-
-
- case "number": // JSON numbers must be finite. Encode non-finite numbers as null.
- return isFinite(aJSObject) ? String(aJSObject) : "null";
-
- case "boolean":
- case "null": return String(aJSObject);
-
- case "object": // Due to a specification blunder in ECMAScript,
- // typeof null is 'object', so watch out for that case.
-
- if (!aJSObject)
- return "null";
-
- // If the object has a toJSON method, call it, and stringify the result.
-
- if (typeof aJSObject.toJSON === "function")
- return CPJSObjectCreateJSON(aJSObject.toJSON());
-
- var array = [];
-
- // If the object is an array. Stringify every element. Use null as a placeholder
- // for non-JSON values.
- if (aJSObject.slice)
- {
- var index = 0,
- count = aJSObject.length;
-
- for (; index < count; ++index)
- array.push(CPJSObjectCreateJSON(aJSObject[index]) || "null");
-
- // Join all of the elements together and wrap them in brackets.
- return '[' + array.join(',') + ']';
- }
-
-
- // Otherwise, iterate through all of the keys in the object.
- var key = NULL;
-
- for (key in aJSObject)
- {
- if (!(typeof key === "string"))
- continue;
-
- var value = CPJSObjectCreateJSON(aJSObject[key]);
-
- if (value)
- array.push(CPJSObjectCreateJSON(key) + ':' + value);
- }
-
- // Join all of the member texts together and wrap them in braces.
- return '{' + array.join(',') + '}';
- }
+ CPLog.warn("CPJSObjectCreateJSON deprecated, use JSON.stringify() or CPString's objectFromJSON");
+ return JSON.stringify(aJSObject);
}
-var _CPJSObjectEncodeCharacter = function(aCharacter)
-{
- var encoding = _JSONCharacterEncodings[aCharacter];
-
- if (encoding)
- return encoding;
-
- encoding = aCharacter.charCodeAt(0);
-
- return '\\u00' + FLOOR(encoding / 16).toString(16) + (encoding % 16).toString(16);
-}
-
-var _JSONBackslashCharacters = new RegExp("\\\\.", 'g'),
- _JSONSimpleValueTokens = new RegExp("\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?", 'g'),
- _JSONValidOpenBrackets = new RegExp("(?:^|:|,)(?:\\s*\\[)+", 'g'),
- _JSONValidExpression = new RegExp("^[\\],:{}\\s]*$");
-
function CPJSObjectCreateWithJSON(aString)
{
- if (_JSONValidExpression.test(aString.replace(_JSONBackslashCharacters, '@').replace(_JSONSimpleValueTokens, ']').replace(_JSONValidOpenBrackets, '')))
- return eval('(' + aString + ')');
-
- return nil;
+ CPLog.warn("CPJSObjectCreateWithJSON deprecated, use JSON.parse() or CPString's JSONFromObject");
+ return JSON.parse(aString);
}
-
-/*
-var _JSONBackslashCharacters = /\\./g,
- _JSONSimpleValueTokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
- _JSONValidOpenBrackets = /(?:^|:|,)(?:\s*\[)+/g,
- _JSONValidExpression = /^[\],:{}\s]*$/;
-*/
diff --git a/Foundation/CPWebDAVManager.j b/Foundation/CPWebDAVManager.j
new file mode 100644
index 000000000..3e0d16b66
--- /dev/null
+++ b/Foundation/CPWebDAVManager.j
@@ -0,0 +1,214 @@
+
+var setURLResourceValuesForKeysFromProperties = function(aURL, keys, properties)
+{
+ var resourceType = [properties objectForKey:@"resourcetype"];
+
+ if (resourceType === CPWebDAVManagerCollectionResourceType)
+ {
+ [aURL setResourceValue:YES forKey:CPURLIsDirectoryKey];
+ [aURL setResourceValue:NO forKey:CPURLIsRegularFileKey];
+ }
+ else if (resourceType === CPWebDAVManagerNonCollectionResourceType)
+ {
+ [aURL setResourceValue:NO forKey:CPURLIsDirectoryKey];
+ [aURL setResourceValue:YES forKey:CPURLIsRegularFileKey];
+ }
+
+ var displayName = [properties objectForKey:@"displayname"];
+
+ if (displayName !== nil)
+ {
+ [aURL setResourceValue:displayName forKey:CPURLNameKey];
+ [aURL setResourceValue:displayName forKey:CPURLLocalizedNameKey];
+ }
+}
+
+CPWebDAVManagerCollectionResourceType = 1;
+CPWebDAVManagerNonCollectionResourceType = 0;
+
+@implementation CPWebDAVManager : CPObject
+{
+ CPDictionary _blocksForConnections;
+}
+
+- (id)init
+{
+ self = [super init];
+
+ if (self)
+ _blocksForConnections = [CPDictionary dictionary];
+
+ return self;
+}
+
+- (CPArray)contentsOfDirectoryAtURL:(CPURL)aURL includingPropertiesForKeys:(CPArray)keys options:(CPDirectoryEnumerationOptions)aMask block:(Function)aBlock
+{
+ var properties = [],
+ count = [keys count];
+
+ while (count--)
+ properties.push(WebDAVPropertiesForURLKeys[keys[count]]);
+
+ var makeContents = function(aURL, response)
+ {
+ var contents = [],
+ URLString = nil,
+ URLStrings = [response keyEnumerator];
+
+ while (URLString = [URLStrings nextObject])
+ {
+ var URL = [CPURL URLWithString:URLString],
+ properties = [response objectForKey:URLString];
+
+ // FIXME: We need better way of comparing URLs.
+ if (![[URL absoluteString] isEqual:[aURL absoluteString]])
+ {
+ contents.push(URL);
+
+ setURLResourceValuesForKeysFromProperties(URL, keys, properties);
+ }
+ }
+
+ return contents;
+ }
+
+ if (!aBlock)
+ return makeContents(aURL, response);
+
+ [self PROPFIND:aURL properties:properties depth:1 block:function(aURL, response)
+ {
+ aBlock(aURL, makeContents(aURL, response));
+ }];
+}
+
+- (CPDictionary)PROPFIND:(CPURL)aURL properties:(CPDictionary)properties depth:(CPString)aDepth block:(Function)aBlock
+{
+ var request = [CPURLRequest requestWithURL:aURL];
+
+ [request setHTTPMethod:@"PROPFIND"];
+ [request setValue:aDepth forHTTPHeaderField:@"Depth"];
+
+ var HTTPBody = [""],
+ index = 0,
+ count = properties.length;
+
+ for (; index < count; ++index)
+ HTTPBody.push("");
+
+ HTTPBody.push("");
+
+ [request setHTTPBody:HTTPBody.join("")];
+
+ if (!aBlock)
+ return parsePROPFINDResponse([[CPURLConnection sendSynchronousRequest:request returningResponse:nil error:nil] string]);
+
+ else
+ {
+ var connection = [CPURLConnection connectionWithRequest:request delegate:self];
+
+ [_blocksForConnections setObject:aBlock forKey:[connection UID]];
+ }
+}
+
+- (void)connection:(CPURLConnection)aURLConnection didReceiveData:(CPString)aString
+{
+ var block = [_blocksForConnections objectForKey:[aURLConnection UID]];
+
+ // FIXME: get the request...
+ block([aURLConnection._request URL], parsePROPFINDResponse(aString));
+}
+
+@end
+
+var WebDAVPropertiesForURLKeys = { };
+
+WebDAVPropertiesForURLKeys[CPURLNameKey] = @"displayname";
+WebDAVPropertiesForURLKeys[CPURLLocalizedNameKey] = @"displayname";
+WebDAVPropertiesForURLKeys[CPURLIsRegularFileKey] = @"resourcetype";
+WebDAVPropertiesForURLKeys[CPURLIsDirectoryKey] = @"resourcetype";
+//CPURLIsSymbolicLinkKey = @"CPURLIsSymbolicLinkKey";
+//CPURLIsVolumeKey = @"CPURLIsVolumeKey";
+//CPURLIsPackageKey = @"CPURLIsPackageKey";
+//CPURLIsSystemImmutableKey = @"CPURLIsSystemImmutableKey";
+//CPURLIsUserImmutableKey = @"CPURLIsUserImmutableKey";
+//CPURLIsHiddenKey = @"CPURLIsHiddenKey";
+//CPURLHasHiddenExtensionKey = @"CPURLHasHiddenExtensionKey";
+//CPURLCreationDateKey = @"CPURLCreationDateKey";
+//CPURLContentAccessDateKey = @"CPURLContentAccessDateKey";
+//CPURLContentModificationDateKey = @"CPURLContentModificationDateKey";
+//CPURLAttributeModificationDateKey = @"CPURLAttributeModificationDateKey";
+//CPURLLinkCountKey = @"CPURLLinkCountKey";
+//CPURLParentDirectoryURLKey = @"CPURLParentDirectoryURLKey";
+//CPURLVolumeURLKey = @"CPURLVolumeURLKey";
+//CPURLTypeIdentifierKey = @"CPURLTypeIdentifierKey";
+//CPURLLocalizedTypeDescriptionKey = @"CPURLLocalizedTypeDescriptionKey";
+//CPURLLabelNumberKey = @"CPURLLabelNumberKey";
+//CPURLLabelColorKey = @"CPURLLabelColorKey";
+//CPURLLocalizedLabelKey = @"CPURLLocalizedLabelKey";
+//CPURLEffectiveIconKey = @"CPURLEffectiveIconKey";
+//CPURLCustomIconKey = @"CPURLCustomIconKey";
+
+var XMLDocumentFromString = function(anXMLString)
+{//console.log(anXMLString);
+ if (typeof window["ActiveXObject"] !== "undefined")
+ {
+ var XMLDocument = new ActiveXObject("Microsoft.XMLDOM");
+
+ XMLDocument.async = false;
+ XMLDocument.loadXML(anXMLString);
+
+ return XMLDocument;
+ }
+
+ return new DOMParser().parseFromString(anXMLString,"text/xml");
+}
+
+var parsePROPFINDResponse = function(anXMLString)
+{
+ var XMLDocument = XMLDocumentFromString(anXMLString),
+ responses = XMLDocument.getElementsByTagNameNS("*", "response"),
+ responseIndex = 0,
+ responseCount = responses.length;
+
+ var propertiesForURLs = [CPDictionary dictionary];
+
+ for (; responseIndex < responseCount; ++responseIndex)
+ {
+ var response = responses[responseIndex],
+ elements = response.getElementsByTagNameNS("*", "prop").item(0).childNodes,
+ index = 0,
+ count = elements.length,
+ properties = [CPDictionary dictionary];
+
+ for (; index < count; ++index)
+ {
+ var element = elements[index];
+
+ if (element.nodeType === 8 || element.nodeType === 3)
+ continue;
+
+ var nodeName = element.nodeName,
+ colonIndex = nodeName.lastIndexOf(':');
+
+ if (colonIndex > -1)
+ nodeName = nodeName.substr(colonIndex + 1);
+
+ if (nodeName === @"resourcetype")
+ [properties setObject:element.firstChild ? CPWebDAVManagerCollectionResourceType : CPWebDAVManagerNonCollectionResourceType forKey:nodeName];
+
+ else
+ [properties setObject:element.firstChild.nodeValue forKey:nodeName];
+ }
+
+ var href = response.getElementsByTagNameNS("*", "href").item(0);
+
+ [propertiesForURLs setObject:properties forKey:href.firstChild.nodeValue];
+ }
+
+ return propertiesForURLs;
+}
+
+var mapURLsAndProperties = function(/*CPDictionary*/ properties, /*CPURL*/ ignoredURL)
+{
+
+}
diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j
index a96bc8353..4bf1460e4 100755
--- a/Foundation/Foundation.j
+++ b/Foundation/Foundation.j
@@ -50,6 +50,7 @@
@import "CPString.j"
@import "CPTimer.j"
@import "CPUndoManager.j"
+@import "CPURL.j"
@import "CPURLConnection.j"
@import "CPURLRequest.j"
@import "CPURLResponse.j"
diff --git a/Foundation/Rakefile b/Foundation/Rakefile
index 4a4b4d2ed..fe768cbc4 100644
--- a/Foundation/Rakefile
+++ b/Foundation/Rakefile
@@ -14,7 +14,7 @@ task :build => [:Foundation, $ENVIRONMENT_PRODUCT]
ObjectiveJ::BundleTask.new(:Foundation) do |t|
t.name = 'Foundation'
t.identifier = 'com.280n.Foundation'
- t.version = '0.7.0'
+ t.version = '0.7.1'
t.author = '280 North, Inc.'
t.email = 'feedback @nospam@ 280north.com'
t.summary = 'Foundation classes for Cappuccino'
diff --git a/Objective-J/Rakefile b/Objective-J/Rakefile
index c8ee921dd..f9e600684 100644
--- a/Objective-J/Rakefile
+++ b/Objective-J/Rakefile
@@ -17,17 +17,11 @@ $RHINO_FILE = File.join($PRODUCT, 'rhino.platform', 'Objective-J.js'
task :Products => [$BROWSER_FILE, $RHINO_FILE, $LICENSE_PRODUCT]
-Files = [ 'constants.js',
- 'utilities.js',
- 'runtime.js',
- 'dictionary.js',
- 'plist.js',
- 'file.js',
- 'exception.js',
- 'preprocess.js',
- 'evaluate.js',
- 'debug.js',
- 'bootstrap.js'];
+Files = FileList['constants.js', 'utilities.js', 'json2.js', 'runtime.js', 'dictionary.js', 'plist.js', 'file.js', 'exception.js', 'preprocess.js', 'evaluate.js', 'bootstrap.js']
+
+if $CONFIGURATION == 'Debug'
+ Files.add('debug.js')
+end
file_d $BROWSER_FILE => Files do |t|
build_product(t.name, platform_flags(ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::ObjJ))
@@ -42,7 +36,8 @@ end
#Framework in environment directory
file_d $ENVIRONMENT_PRODUCT => [:Products] do
- cp_r(File.join($PRODUCT, '.'), $ENVIRONMENT_PRODUCT)
+ rm_rf $ENVIRONMENT_PRODUCT
+ cp_r($PRODUCT, $ENVIRONMENT_PRODUCT)
end
file_d $LICENSE_PRODUCT => [$LICENSE_FILE] do
@@ -54,9 +49,7 @@ def platform_flags(*platforms)
end
def build_product(path, flags)
-
IO.popen("gcc #{flags} -E -x c -P -", "w+") do |preprocessor|
-
Files.select { |name| name.match(/\.js$/) }.each do |fileName|
preprocessor.puts IO.read(fileName)
end
@@ -66,11 +59,11 @@ def build_product(path, flags)
File.open(path, "w") do |file|
file.write(IO.read("header.txt") + preprocessor.read)
end
-
end
+ rake abort if ($? != 0)
end
-task :build => [:Products, $ENVIRONMENT_PRODUCT, :build_subprojects]
+task :build => [:Products, :build_subprojects, $ENVIRONMENT_PRODUCT]
task :clean => :clean_suprojects
diff --git a/Objective-J/Tools/Rakefile b/Objective-J/Tools/Rakefile
index d46729d01..99271dfc4 100644
--- a/Objective-J/Tools/Rakefile
+++ b/Objective-J/Tools/Rakefile
@@ -5,35 +5,18 @@ require 'objective-j'
require 'rake'
require 'rake/clean'
-$ENVIRONMENT_NARWHAL_PRODUCT = File.join($ENVIRONMENT_DIR, 'narwhal')
+$ENVIRONMENT_NARWHAL_PRODUCT = $ENVIRONMENT_DIR
$ENVIRONMENT_OBJJ_PRODUCT = File.join($ENVIRONMENT_NARWHAL_PRODUCT, 'packages', 'objj')
-$OBJJC_JS_COMPILER = File.join($ENVIRONMENT_LIB_DIR, 'shrinksafe.jar')
-$OBJJC_JS_COMPILER_RHINO = File.join($ENVIRONMENT_LIB_DIR, 'js.jar')
-
$EXECUTABLES = ['objj', 'objjc', 'cplutil']
-$EXECUTABLES_PRODUCTS = $EXECUTABLES.map {|e| File.join($ENVIRONMENT_BIN_DIR, e) }
-$EXECUTABLES.each do |executable|
- source = File.join('objj', 'bin', executable)
- dest = File.join($ENVIRONMENT_BIN_DIR, executable)
- file_d dest => source do
- #cp(source, dest)
- FileUtils.ln_sf("../narwhal/packages/objj/bin/#{executable}", dest)
+task :build do
+ rm_rf($ENVIRONMENT_OBJJ_PRODUCT)
+ cp_r('objj', $ENVIRONMENT_OBJJ_PRODUCT)
+
+ $EXECUTABLES.each do |executable|
+ symlink_executable File.join($ENVIRONMENT_BIN_DIR, executable)
end
end
-file_d $OBJJC_JS_COMPILER => 'shrinksafe.jar' do
- cp('shrinksafe.jar', $OBJJC_JS_COMPILER)
-end
-
-file_d $OBJJC_JS_COMPILER_RHINO => 'js.jar' do
- cp('js.jar', $OBJJC_JS_COMPILER_RHINO)
-end
-
-task :build => [$OBJJC_JS_COMPILER, $OBJJC_JS_COMPILER_RHINO].concat($EXECUTABLES_PRODUCTS) do
- rm_rf($ENVIRONMENT_OBJJ_PRODUCT)
- cp_r('objj', $ENVIRONMENT_OBJJ_PRODUCT)
-end
-
-CLOBBER.include($ENVIRONMENT_OBJJ_PRODUCT, $EXECUTABLES_PRODUCTS, $OBJJC_JS_COMPILER, $OBJJC_JS_COMPILER_RHINO)
+CLOBBER.include($ENVIRONMENT_OBJJ_PRODUCT)
diff --git a/Objective-J/Tools/objj/bin/cplutil b/Objective-J/Tools/objj/bin/cplutil
index 6168fd7b5..7428b1214 100755
--- a/Objective-J/Tools/objj/bin/cplutil
+++ b/Objective-J/Tools/objj/bin/cplutil
@@ -13,6 +13,9 @@ function printUsage()
function main()
{
+ // FIXME: ARGS
+ system.args.shift();
+
if (system.args.length < 1)
return printUsage();
diff --git a/Objective-J/Tools/objj/bin/objj b/Objective-J/Tools/objj/bin/objj
index 208bcce8b..3c52d2a54 100755
--- a/Objective-J/Tools/objj/bin/objj
+++ b/Objective-J/Tools/objj/bin/objj
@@ -1,3 +1,3 @@
#!/usr/bin/env narwhal
-require("objj/objj");
+require("objj/objj").run(system.args);
diff --git a/Objective-J/Tools/objj/bin/objjc b/Objective-J/Tools/objj/bin/objjc
index ad60ee887..595203812 100755
--- a/Objective-J/Tools/objj/bin/objjc
+++ b/Objective-J/Tools/objj/bin/objjc
@@ -1,216 +1,3 @@
#!/usr/bin/env narwhal
-var objjc = require("objj/objjc"),
- File = require("file");
-
-with (objjc)
-{
-
-importPackage(java.lang);
-
-importClass(java.io.BufferedReader);
-
-
-OBJJ_PREPROCESSOR_PREPROCESS = 1 << 10;
-OBJJ_PREPROCESSOR_COMPRESS = 1 << 11;
-OBJJ_PREPROCESSOR_SYNTAX = 1 << 12;
-
-function exec(/*Array*/ command, /*Boolean*/ showOutput)
-{
- var line = "",
- output = "",
-
- process = Packages.java.lang.Runtime.getRuntime().exec(command),//jsArrayToJavaArray(command));
- reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getInputStream(), "UTF-8"));
-
- while (line = reader.readLine())
- {
- if (showOutput)
- System.out.println(line);
-
- output += line + '\n';
- }
-
- reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getErrorStream(), "UTF-8"));
-
- while (line = reader.readLine())
- System.out.println(line);
-
- try
- {
- if (process.waitFor() != 0)
- System.err.println("exit value = " + process.exitValue());
- }
- catch (anException)
- {
- System.err.println(anException);
- }
-
- return output;
-}
-
-function compress(/*String*/ aCode, /*Object*/ flags, /*File*/ tmpFile)
-{
- File.write(tmpFile, aCode, { charset:"UTF-8" });
-
- return exec(["java", "-Dfile.encoding=UTF-8", "-classpath", OBJJ_HOME + "/lib/js.jar" + ":" + OBJJ_HOME + "/lib/shrinksafe.jar", "org.dojotoolkit.shrinksafe.Main", tmpFile.getCanonicalPath()]);
-}
-
-//#define SET_CONTEXT(aFragment, aContext) aFragment.context = aContext
-//#define GET_CONTEXT(aFragment) aFragment.context
-
-//#define SET_TYPE(aFragment, aType) aFragment.type = (aType)
-//#define GET_TYPE(aFragment) aFragment.type
-
-function GET_CODE(aFragment) { return aFragment.info; }
-//#define SET_CODE(aFragment, aCode) aFragment.info = (aCode)
-
-function GET_PATH(aFragment) { return aFragment.info; }
-//#define SET_PATH(aFragment, aPath) aFragment.info = aPath
-
-//#define GET_BUNDLE(aFragment) aFragment.bundle
-//#define SET_BUNDLE(aFragment, aBundle) aFragment.bundle = aBundle
-
-//#define GET_FILE(aFragment) aFragment.file
-//#define SET_FILE(aFragment, aFile) aFragment.file = aFile
-
-function IS_FILE(aFragment) { return (aFragment.type & FRAGMENT_FILE); }
-function IS_LOCAL(aFragment) { return (aFragment.type & FRAGMENT_LOCAL); }
-//#define IS_IMPORT(aFragment) (aFragment.type & FRAGMENT_IMPORT)
-
-function preprocess(aFilePath, outFilePath, gccArgs, flags)
-{
- print("Statically Preprocessing " + aFilePath);
-
- var shouldObjjPreprocess = flags & OBJJ_PREPROCESSOR_PREPROCESS,
- shouldCheckSyntax = flags & OBJJ_PREPROCESSOR_SYNTAX,
- shouldCompress = flags & OBJJ_PREPROCESSOR_COMPRESS;
-
- // FIXME: figure out why this doesn't work on Windows/Cygwin
- //var tmpFile = java.io.File.createTempFile("OBJJC", "");
- var tmpFile = new java.io.File(outFilePath + ".tmp");
- tmpFile.deleteOnExit();
-
- // -E JUST preprocess.
- // -x c Interpret language as C -- closest thing to JavaScript.
- // -P Don't generate #line directives
- var gccComponents = ["gcc", "-E", "-x", "c", "-P", aFilePath, "-o", shouldObjjPreprocess ? tmpFile.getAbsolutePath() : outFilePath],
- index = gccArgs.length;
-
- // Add custom gcc arguments.
- while (index--)
- gccComponents.splice(5, 0, gccArgs[index]);
-
- exec(gccComponents);
-
- if (!shouldObjjPreprocess)
- return;
-
- // Read file and preprocess it.
- var fileContents = File.read(tmpFile, { charset: "UTF-8" });
-
- // Preprocess contents into fragments.
- var filePath = new String(new java.io.File(aFilePath).getName()),
- fragments = objj_preprocess(fileContents, { path:"/x" }, {path:filePath}, flags),
- index = 0,
- count = fragments.length,
- preprocessed = "";
-
- // Writer preprocessed fragments out.
- for (; index < count; ++index)
- {
- var fragment = fragments[index];
-
- if (IS_FILE(fragment))
- preprocessed += (IS_LOCAL(fragment) ? MARKER_IMPORT_LOCAL : MARKER_IMPORT_STD) + ';' + GET_PATH(fragment).length + ';' + GET_PATH(fragment);
- else
- {
- var code = GET_CODE(fragment);
-
- if (shouldCheckSyntax)
- {
- try
- {
- new Function(GET_CODE(fragment));
- }
- catch (e)
- {
- var lines = e.fragment.info.split("\n"),
- PAD = 3;
-
- System.out.println(
- "Syntax error in "+e.fragment.file.path+
- " on preprocessed line number "+e.lineNumber+"\n"+
- "\t"+lines.slice(e.lineNumber-1-PAD<0 ? 0 : e.lineNumber-1-PAD, e.lineNumber+PAD).join("\n\t"));
-
- System.exit(1);
- }
- }
-
- if (shouldCompress)
- {
- code = compress("function(){" + code + '}', 0, tmpFile);
-
- code = code.substr("function(){".length, code.length - "function(){};\n\n".length);
- }
-
- preprocessed += MARKER_CODE + ';' + code.length + ';' + code;
- }
- }
-
- // Write file.
- File.write(outFilePath, preprocessed, { charset: "UTF-8" });
-}
-
-function main()
-{
- var filePaths = [],
- outFilePaths = [],
-
- index = 0,
- count = system.args.length,
-
- gccArgs = [],
-
- flags = OBJJ_PREPROCESSOR_PREPROCESS | OBJJ_PREPROCESSOR_SYNTAX;
-
-
- for (; index < count; ++index)
- {
- var argument = system.args[index];
-
- if (argument === "-o")
- {
- if (++index < count)
- outFilePaths.push(system.args[index]);
- }
-
- else if (argument.indexOf("-D") === 0)
- gccArgs.push(argument)
-
- else if (argument.indexOf("-U") === 0)
- gccArgs.push(argument);
-
- else if (argument.indexOf("-E") === 0)
- flags &= ~OBJJ_PREPROCESSOR_PREPROCESS;
-
- else if (argument.indexOf("-S") === 0)
- flags &= ~OBJJ_PREPROCESSOR_SYNTAX;
-
- else if (argument.indexOf("-g") === 0)
- flags |= OBJJ_PREPROCESSOR_DEBUG_SYMBOLS;
-
- else if (argument.indexOf("-O") === 0)
- flags |= OBJJ_PREPROCESSOR_COMPRESS;
-
- else
- filePaths.push(argument);
- }
-
- for (index = 0, count = filePaths.length; index < count; ++index)
- preprocess(filePaths[index], outFilePaths[index], gccArgs, flags);
-}
-
-main();
-
-}
\ No newline at end of file
+require("objj/objjc").main(system.args);
diff --git a/Objective-J/Tools/objj/lib-js/objj/loader.js b/Objective-J/Tools/objj/lib-js/objj/loader.js
new file mode 100644
index 000000000..47265122e
--- /dev/null
+++ b/Objective-J/Tools/objj/lib-js/objj/loader.js
@@ -0,0 +1,23 @@
+var objj = null;
+
+function ObjectiveJLoader() {
+ var loader = {};
+ var factories = {};
+
+ loader.reload = function(topId, path) {
+ if (!objj) objj = require("objj/objj");
+
+ //print("loading objective-j: " + topId + " (" + path + ")");
+ factories[topId] = objj.make_narwhal_factory(system.fs.read(path), path);
+ }
+
+ loader.load = function(topId, path) {
+ if (!factories.hasOwnProperty(topId))
+ loader.reload(topId, path);
+ return factories[topId];
+ }
+
+ return loader;
+};
+
+require.loader.loaders.unshift([".j", ObjectiveJLoader()]);
diff --git a/Objective-J/Tools/objj/lib-js/objj/objj.js b/Objective-J/Tools/objj/lib-js/objj/objj.js
new file mode 100644
index 000000000..2338a73f5
--- /dev/null
+++ b/Objective-J/Tools/objj/lib-js/objj/objj.js
@@ -0,0 +1,182 @@
+var file = require("file"),
+ readline = require("readline").readline;
+
+var window = require("browser/window");
+window.isRhino = true
+
+if (window.isRhino) {
+ window.__parent__ = null;
+ window.__proto__ = global;
+}
+
+// setup OBJJ_HOME, OBJJ_INCLUDE_PATHS, etc
+window.OBJJ_HOME = exports.OBJJ_HOME = file.resolve(module.path, "..", "..");
+
+var frameworksPath = file.resolve(window.OBJJ_HOME, "lib/", "Frameworks/"),
+ objectivejPath = file.resolve(frameworksPath, "Objective-J/", "rhino.platform/", "Objective-J.js");
+
+window.OBJJ_INCLUDE_PATHS = [frameworksPath];
+if (system.env["OBJJ_INCLUDE_PATHS"])
+ window.OBJJ_INCLUDE_PATHS = system.env["OBJJ_INCLUDE_PATHS"].split(":").concat(window.OBJJ_INCLUDE_PATHS);
+
+// bring the "window" object into scope.
+// TODO: somehow make window object the top scope?
+with (window)
+{
+ // read and eval Objective-J.js with the module's scope
+ if (window.isRhino)
+ Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(window, file.read(objectivejPath, { charset:"UTF-8" }), "Objective-J.js", 0, null);
+ else
+ eval(file.read(objectivejPath, { charset:"UTF-8" }));
+
+ // export desired variables. must eval variable name to obtain a reference.
+ [
+ "objj_preprocess",
+ "FRAGMENT_FILE", "FRAGMENT_LOCAL",
+ "MARKER_CODE", "MARKER_IMPORT_STD", "MARKER_IMPORT_LOCAL",
+ "OBJJ_PREPROCESSOR_DEBUG_SYMBOLS",
+ "objj_data",
+ "CPPropertyListCreateData", "CPPropertyListCreateFromData",
+ "kCFPropertyListXMLFormat_v1_0", "kCFPropertyList280NorthFormat_v1_0"
+ ].forEach(function(v) {
+ exports[v] = eval(v);
+ });
+
+ // extra macros
+ exports.SET_CONTEXT = function(aFragment, aContext) { aFragment.context = aContext; }
+ exports.GET_CONTEXT = function(aFragment) { return aFragment.context; }
+
+ exports.SET_TYPE = function(aFragment, aType) { aFragment.type = aType; }
+ exports.GET_TYPE = function(aFragment) { return aFragment.type; }
+
+ exports.GET_CODE = function(aFragment) { return aFragment.info; }
+ exports.SET_CODE = function(aFragment, aCode) { aFragment.info = aCode; }
+
+ exports.GET_PATH = function(aFragment) { return aFragment.info; }
+ exports.SET_PATH = function(aFragment, aPath) { aFragment.info = aPath; }
+
+ exports.GET_BUNDLE = function(aFragment) { return aFragment.bundle; }
+ exports.SET_BUNDLE = function(aFragment, aBundle) { aFragment.bundle = aBundle; }
+
+ exports.GET_FILE = function(aFragment) { return aFragment.file; }
+ exports.SET_FILE = function(aFragment, aFile) { aFragment.file = aFile; }
+
+ exports.IS_FILE = function(aFragment) { return (aFragment.type & FRAGMENT_FILE); }
+ exports.IS_LOCAL = function(aFragment) { return (aFragment.type & FRAGMENT_LOCAL); }
+ exports.IS_IMPORT = function(aFragment) { return (aFragment.type & FRAGMENT_IMPORT); }
+
+/*
+ objj_set_evaluator(function(code) {
+ return function(OBJJ_CURRENT_BUNDLE) {
+ with (window) {
+ return eval("function(OBJJ_CURRENT_BUNDLE){"+code+"}");
+ }
+ }
+ });
+*/
+
+// runs the objj repl or file provided in args
+exports.run = function(args)
+{
+ args = args || [];
+ window.args = args;
+
+ // FIXME: ARGS
+ args.shift();
+
+ if (args.length > 0)
+ {
+ while (args.length && args[0].indexOf('-I') === 0)
+ OBJJ_INCLUDE_PATHS = args.shift().substr(2).split(':').concat(OBJJ_INCLUDE_PATHS);
+
+ var mainFilePath = file.canonical(args.shift());
+
+ objj_import(mainFilePath, YES, function() {
+ if (typeof main === "function")
+ main.apply(main, args);
+ });
+ }
+ else
+ {
+ while (true)
+ {
+ try {
+ system.stdout.write("objj> ").flush();
+
+ var input = readline(),
+ result = objj_eval(input);
+
+ if (result !== undefined)
+ print(result);
+
+ } catch (e) {
+ print(e);
+ }
+
+ require("browser/timeout").serviceTimeouts();
+ }
+ }
+
+ require("browser/timeout").serviceTimeouts();
+}
+
+// synchronously evals Objective-J code
+var objj_eval = exports.objj_eval = function(code)
+{
+ if (window.isRhino)
+ var result = Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(window, objj_preprocess_sync(code), "objj_eval", 0, null);
+ else
+ var result = eval(objj_preprocess_sync(code));
+
+ //require("browser/timeout").serviceTimeouts();
+
+ return result;
+}
+
+// prepocesses Objective-J code into JavaScript, which will perform imports synchronously when eval'd
+var objj_preprocess_sync = function(code, path)
+{
+ var fragments = objj_preprocess(code, new objj_bundle(), new objj_file(), OBJJ_PREPROCESSOR_DEBUG_SYMBOLS)
+
+ var preprocessed = [];
+
+ fragments.forEach(function(fragment) {
+ if (fragment.type & FRAGMENT_CODE)
+ preprocessed.push(fragment.info);
+ else if (fragment.type & FRAGMENT_LOCAL)
+ preprocessed.push("objj_import_sync('"+(path ? file.join(file.dirname(path), fragment.info) : fragment.info)+"',YES);");
+ else
+ preprocessed.push("objj_import_sync('"+fragment.info+"',NO);");
+ });
+
+ return preprocessed.join("\n");
+}
+
+// synchronously perform an import
+var objj_import_sync = function(pathOrPaths, isLocal)
+{
+ var context = new objj_context();
+ context.pushFragment(fragment_create_file(pathOrPaths, new objj_bundle(), isLocal, NULL));
+ context.evaluate();
+
+ // HACK: need a real synchronous require
+ // FIXME: this is bad. not really synchronous. shouldn't have to call serviceTimeouts.
+ require("browser/timeout").serviceTimeouts();
+}
+
+// creates a narwhal factory function in the objj module scope
+exports.make_narwhal_factory = function(code, path) {
+ var OBJJ_CURRENT_BUNDLE = new objj_bundle();
+
+ var factoryText = "(function(require,exports,module,system,print){" + objj_preprocess_sync(code, path) + "/**/\n})";
+
+ if (window.isRhino)
+ return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(window, factoryText, path, 0, null);
+ else
+ return eval(factoryText);
+}
+
+} // end "with"
+
+if (require.main == module.id)
+ exports.run(system.args);
diff --git a/Objective-J/Tools/objj/lib-js/objj/objjc.js b/Objective-J/Tools/objj/lib-js/objj/objjc.js
new file mode 100644
index 000000000..6e532d89e
--- /dev/null
+++ b/Objective-J/Tools/objj/lib-js/objj/objjc.js
@@ -0,0 +1,163 @@
+var file = require("file"),
+ os = require("os")
+ objj = require("./objj");
+
+require("objj/regexp-rhino-patch");
+
+var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = exports.OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = objj.OBJJ_PREPROCESSOR_DEBUG_SYMBOLS;
+var OBJJ_PREPROCESSOR_TYPE_SIGNATURES = exports.OBJJ_PREPROCESSOR_TYPE_SIGNATURES = objj.OBJJ_PREPROCESSOR_TYPE_SIGNATURES;
+var OBJJ_PREPROCESSOR_PREPROCESS = exports.OBJJ_PREPROCESSOR_PREPROCESS = 1 << 10;
+var OBJJ_PREPROCESSOR_COMPRESS = exports.OBJJ_PREPROCESSOR_COMPRESS = 1 << 11;
+var OBJJ_PREPROCESSOR_SYNTAX = exports.OBJJ_PREPROCESSOR_SYNTAX = 1 << 12;
+
+var SHRINKSAFE_PATH = file.join(objj.OBJJ_HOME, "shrinksafe", "shrinksafe.jar"),
+ RHINO_PATH = file.join(objj.OBJJ_HOME, "shrinksafe", "js.jar")
+
+function compress(/*String*/ aCode, /*Object*/ flags, /*String*/ tmpFile)
+{
+ file.write(tmpFile, aCode, { charset:"UTF-8" });
+
+ return os.command(["java", "-Dfile.encoding=UTF-8", "-classpath", [RHINO_PATH, SHRINKSAFE_PATH].join(":"), "org.dojotoolkit.shrinksafe.Main", tmpFile]);
+}
+
+exports.preprocess = function(inFile, outFile, flags, gccArgs)
+{
+ with(objj)
+ {
+
+ print("Statically Preprocessing " + inFile);
+
+ if (flags === undefined)
+ flags = OBJJ_PREPROCESSOR_PREPROCESS | OBJJ_PREPROCESSOR_SYNTAX;
+
+ var shouldObjjPreprocess = flags & OBJJ_PREPROCESSOR_PREPROCESS,
+ shouldCheckSyntax = flags & OBJJ_PREPROCESSOR_SYNTAX,
+ shouldCompress = flags & OBJJ_PREPROCESSOR_COMPRESS;
+
+ // FIXME: figure out why this doesn't work on Windows/Cygwin
+ //var tmpFile = java.io.File.createTempFile("OBJJC", "");
+ var tmpFile = new java.io.File(outFile + ".tmp");
+ tmpFile.deleteOnExit();
+ tmpFile = tmpFile.getAbsolutePath();
+
+ // -E JUST preprocess.
+ // -x c Interpret language as C -- closest thing to JavaScript.
+ // -P Don't generate #line directives
+ var gccComponents = ["gcc"]
+ .concat("-E", "-x", "c", "-P", inFile)
+ .concat(gccArgs || [])
+ .concat("-o", shouldObjjPreprocess ? tmpFile : outFile);
+
+ os.system(gccComponents);
+
+ if (!shouldObjjPreprocess)
+ return;
+
+ // Read file and preprocess it.
+ var fileContents = file.read(tmpFile, { charset: "UTF-8" });
+
+ // Preprocess contents into fragments.
+ var fragments = objj_preprocess(fileContents, { path : "/x" }, { path: file.basename(inFile) }, flags),
+ preprocessed = "";
+
+ // Writer preprocessed fragments out.
+ for (var index = 0; index < fragments.length; index++)
+ {
+ var fragment = fragments[index];
+
+ if (IS_FILE(fragment))
+ preprocessed += (IS_LOCAL(fragment) ? MARKER_IMPORT_LOCAL : MARKER_IMPORT_STD) + ';' + GET_PATH(fragment).length + ';' + GET_PATH(fragment);
+ else
+ {
+ var code = GET_CODE(fragment);
+
+ if (shouldCheckSyntax)
+ {
+ try
+ {
+ new Function(GET_CODE(fragment));
+ }
+ catch (e)
+ {
+ var lines = code.split("\n"),
+ PAD = 3;
+
+ print("Syntax error in "+GET_FILE(fragment).path+
+ " on preprocessed line number "+e.lineNumber+"\n"+
+ "\t"+lines.slice(Math.max(0, e.lineNumber - 1 - PAD), e.lineNumber+PAD).join("\n\t"));
+
+ os.exit(1);
+ }
+ }
+
+ if (shouldCompress)
+ {
+ code = compress("function(){" + code + '}', 0, tmpFile);
+
+ code = code.substr("function(){".length, code.length - "function(){};\n\n".length);
+ }
+
+ preprocessed += MARKER_CODE + ';' + code.length + ';' + code;
+ }
+ }
+
+ // Write file.
+ file.write(outFile, preprocessed, { charset: "UTF-8" });
+
+ }
+}
+
+exports.main = function(args)
+{
+ // FIXME: ARGS
+ args.shift();
+
+ var filePaths = [],
+ outFilePaths = [],
+
+ index = 0,
+ count = args.length,
+
+ gccArgs = [],
+
+ flags = OBJJ_PREPROCESSOR_PREPROCESS | OBJJ_PREPROCESSOR_SYNTAX;
+
+
+ for (; index < count; ++index)
+ {
+ var argument = args[index];
+
+ if (argument === "-o")
+ {
+ if (++index < count)
+ outFilePaths.push(args[index]);
+ }
+
+ else if (argument.indexOf("-D") === 0)
+ gccArgs.push(argument)
+
+ else if (argument.indexOf("-U") === 0)
+ gccArgs.push(argument);
+
+ else if (argument.indexOf("-E") === 0)
+ flags &= ~OBJJ_PREPROCESSOR_PREPROCESS;
+
+ else if (argument.indexOf("-S") === 0)
+ flags &= ~OBJJ_PREPROCESSOR_SYNTAX;
+
+ else if (argument.indexOf("-g") === 0)
+ flags |= OBJJ_PREPROCESSOR_DEBUG_SYMBOLS;
+
+ else if (argument.indexOf("-O") === 0)
+ flags |= OBJJ_PREPROCESSOR_COMPRESS;
+
+ else
+ filePaths.push(argument);
+ }
+
+ for (index = 0, count = filePaths.length; index < count; ++index)
+ exports.preprocess(filePaths[index], outFilePaths[index], flags, gccArgs);
+}
+
+if (require.main == module.id)
+ exports.main(system.args);
\ No newline at end of file
diff --git a/Objective-J/Tools/objj/lib-js/objj/plist.js b/Objective-J/Tools/objj/lib-js/objj/plist.js
new file mode 100644
index 000000000..fd6e88e3e
--- /dev/null
+++ b/Objective-J/Tools/objj/lib-js/objj/plist.js
@@ -0,0 +1,15 @@
+var file = require("file"),
+ objj = require("./objj"),
+ CPPropertyListCreateData = objj.CPPropertyListCreateData,
+ kCFPropertyListXMLFormat_v1_0 = objj.kCFPropertyListXMLFormat_v1_0;
+
+exports.readPlist = function(path) {
+ var plistData = new objj.objj_data();
+ plistData.string = file.read(path);
+ return objj.CPPropertyListCreateFromData(plistData);
+}
+
+exports.writePlist = function(path, plist, format) {
+ format = format || objj.kCFPropertyListXMLFormat_v1_0;
+ file.write(path, objj.CPPropertyListCreateData(plist, format).string);
+}
diff --git a/Objective-J/Tools/objj/lib/objj/regexp-rhino-patch.js b/Objective-J/Tools/objj/lib-js/objj/regexp-rhino-patch.js
similarity index 100%
rename from Objective-J/Tools/objj/lib/objj/regexp-rhino-patch.js
rename to Objective-J/Tools/objj/lib-js/objj/regexp-rhino-patch.js
diff --git a/Objective-J/Tools/objj/lib/objj/objj.js b/Objective-J/Tools/objj/lib/objj/objj.js
deleted file mode 100644
index 3882c51bc..000000000
--- a/Objective-J/Tools/objj/lib/objj/objj.js
+++ /dev/null
@@ -1,75 +0,0 @@
-var File = require("file");
-var window = require("browser/window");
-
-var OBJJ_HOME = system.prefix + "/..";
-
-window.OBJJ_INCLUDE_PATHS = [OBJJ_HOME+"/lib/Frameworks/"];
-if (system.env["OBJJ_INCLUDE_PATHS"])
- window.OBJJ_INCLUDE_PATHS = system.env["OBJJ_INCLUDE_PATHS"].split(":").concat(window.OBJJ_INCLUDE_PATHS);
-
-//if (system.args.length > 0)
-// window.OBJJ_MAIN_FILE = String((new Packages.java.io.File(args.shift())).getAbsolutePath());
-
-window.args = system.args;
-
-with (window)
-{
- eval(File.read(OBJJ_HOME + "/lib/Frameworks/Objective-J/rhino.platform/Objective-J.js", { charset:"UTF-8" }));
-
- if (system.args.length > 0)
- {
- while (system.args.length && system.args[0].indexOf('-I') === 0)
- OBJJ_INCLUDE_PATHS = system.args.shift().substr(2).split(':').concat(OBJJ_INCLUDE_PATHS);
-
- var mainFilePath = String((new Packages.java.io.File(args.shift())).getAbsolutePath());
-
- objj_import(mainFilePath, YES, function() {
- if (typeof main === "function")
- main.apply(main, args);
- });
- }
- else
- {
- var br = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(Packages.java.lang.System["in"], "UTF-8"));
-
- while (true)
- {
- try {
- Packages.java.lang.System.out.print("objj> ");
-
- var input = String(br.readLine()),
- fragments = objj_preprocess(input, new objj_bundle(), new objj_file(), OBJJ_PREPROCESSOR_DEBUG_SYMBOLS),
- count = fragments.length,
- ctx = (new objj_context);
-
- if (count == 1 && (fragments[0].type & FRAGMENT_CODE))
- {
- var fragment = fragments[0];
- var result = eval(fragment.info);
- if (result != undefined)
- print(result);
- }
- else if (count > 0)
- {
- while (count--)
- {
- var fragment = fragments[count];
-
- if (fragment.type & FRAGMENT_FILE)
- objj_request_file(fragment.info, (fragment.type & FRAGMENT_LOCAL), NULL);
-
- ctx.pushFragment(fragment);
- }
-
- ctx.schedule();
- }
-
- require("browser/timeout").serviceTimeouts();
- } catch (e) {
- print(e);
- }
- }
- }
-
- require("browser/timeout").serviceTimeouts();
-}
diff --git a/Objective-J/Tools/objj/lib/objj/objjc.js b/Objective-J/Tools/objj/lib/objj/objjc.js
deleted file mode 100644
index 9d9357f1c..000000000
--- a/Objective-J/Tools/objj/lib/objj/objjc.js
+++ /dev/null
@@ -1,19 +0,0 @@
-var File = require("file");
-var window = require("browser/window");
-
-require("./regexp-rhino-patch");
-
-var exported = ["OBJJ_HOME", "objj_preprocess",
- "FRAGMENT_FILE", "FRAGMENT_LOCAL",
- "MARKER_CODE", "MARKER_IMPORT_STD", "MARKER_IMPORT_LOCAL",
- "OBJJ_PREPROCESSOR_DEBUG_SYMBOLS"];
-
-var OBJJ_HOME = system.prefix + "/..";
-
-with (window)
-{
- eval(File.read(OBJJ_HOME + "/lib/Frameworks/Objective-J/rhino.platform/Objective-J.js", { charset:"UTF-8" }).toString());
-
- for (var i = 0; i < exported.length; i++)
- exports[exported[i]] = eval(exported[i]);
-}
diff --git a/Objective-J/Tools/objj/package.json b/Objective-J/Tools/objj/package.json
index c4a5826f5..55159a857 100644
--- a/Objective-J/Tools/objj/package.json
+++ b/Objective-J/Tools/objj/package.json
@@ -1,6 +1,15 @@
{
- "author": "Tom Robinson",
- "dependencies": [],
- "js": "lib",
- "jars": "jars/"
+ "name": "objj",
+ "dependencies": ["narwhal", "jack", "browserjs"],
+ "lib": "lib-js",
+ "preload": ["objj/loader"],
+ "description": "Objective-J and Cappuccino tools",
+ "keywords": ["Objective-J", "Cappuccino"],
+ "author": "280 North (http://280north.com/)",
+ "contributors": [
+ "Francisco Tolmasky (http://tolmasky.com/)",
+ "Ross Boucher (http://rossboucher.com/)",
+ "Tom Robinson (http://tlrobinson.net/)",
+ "Numerous others (http://contributors.cappuccino.org/)"
+ ]
}
diff --git a/Objective-J/Tools/objj/shrinksafe/js.jar b/Objective-J/Tools/objj/shrinksafe/js.jar
new file mode 100644
index 000000000..c081d16b8
Binary files /dev/null and b/Objective-J/Tools/objj/shrinksafe/js.jar differ
diff --git a/Objective-J/Tools/objj/shrinksafe/shrinksafe.jar b/Objective-J/Tools/objj/shrinksafe/shrinksafe.jar
new file mode 100644
index 000000000..516fc7f5f
Binary files /dev/null and b/Objective-J/Tools/objj/shrinksafe/shrinksafe.jar differ
diff --git a/Objective-J/debug.js b/Objective-J/debug.js
index 9702e00c8..2c7624464 100644
--- a/Objective-J/debug.js
+++ b/Objective-J/debug.js
@@ -1,173 +1,184 @@
-function objj_backtrace_format(aReceiver, aSelector)
+// formatting helpers
+
+function objj_debug_object_format(aReceiver)
{
- return "[<" + GETMETA(aReceiver).name + " " + (typeof sprintf == "function" ? sprintf("%#08x", aReceiver.__address) : aReceiver.__address.toString(16)) + "> " + aSelector + "]";
+ return (aReceiver && aReceiver.isa) ? sprintf("<%s %#08x>", GETMETA(aReceiver).name, aReceiver.__address) : String(aReceiver);
}
-function objj_msgSend_Backtrace(/*id*/ aReceiver, /*SEL*/ aSelector)
+function objj_debug_message_format(aReceiver, aSelector)
{
- if (aReceiver == nil)
- return nil;
-
- objj_debug_backtrace.push(objj_backtrace_format(aReceiver, aSelector));
-
- try
- {
- var result = class_getMethodImplementation(aReceiver.isa, aSelector).apply(aReceiver, arguments);
- }
- catch (anException)
- {
- CPLog.error("Exception " + anException + " in " + objj_backtrace_format(aReceiver, aSelector));
- objj_debug_print_backtrace();
- }
-
- objj_debug_backtrace.pop();
-
- return result;
+ return sprintf("[%s %s]", objj_debug_object_format(aReceiver), aSelector);
}
-function objj_msgSendSuper_Backtrace(/*id*/ aSuper, /*SEL*/ aSelector)
+
+// save the original msgSend implementations so we can restore them later
+var objj_msgSend_original = objj_msgSend,
+ objj_msgSendSuper_original = objj_msgSendSuper;
+
+
+// decorator management functions
+
+// reset to default objj_msgSend* implementations
+function objj_msgSend_reset()
{
- objj_debug_backtrace.push(objj_backtrace_format(aSuper.receiver, aSelector));
- var super_class = aSuper.super_class;
-
- arguments[0] = aSuper.receiver;
-
- try
- {
- var result = class_getMethodImplementation(super_class, aSelector).apply(aSuper.receiver, arguments);
- }
- catch (anException)
- {
- CPLog.error("Exception " + anException + " in " + objj_backtrace_format(aSuper.receiver, aSelector));
- objj_debug_print_backtrace();
- }
-
- objj_debug_backtrace.pop();
-
- return result;
+ objj_msgSend = objj_msgSend_original;
+ objj_msgSendSuper = objj_msgSendSuper_original;
}
-function objj_msgSend_Profile(/*id*/ aReceiver, /*SEL*/ aSelector)
+// decorate both objj_msgSend and objj_msgSendSuper
+function objj_msgSend_decorate()
{
- if (aReceiver == nil)
- return nil;
-
- // profiling book keeping
- var profileRecord = {
- parent : objj_debug_profile,
- receiver : GETMETA(aReceiver).name,
- selector : aSelector,
- calls : []
- }
- objj_debug_profile.calls.push(profileRecord);
- objj_debug_profile = profileRecord;
- profileRecord.start = new Date();
-
- var result = class_getMethodImplementation(aReceiver.isa, aSelector).apply(aReceiver, arguments);
-
- profileRecord.end = new Date();
- objj_debug_profile = profileRecord.parent;
-
- return result;
-}
-
-function objj_msgSendSuper_Profile(/*id*/ aSuper, /*SEL*/ aSelector)
-{
- // profiling book keeping
- var profileRecord = {
- parent : objj_debug_profile,
- receiver : GETMETA(aReceiver).name,
- selector : aSelector,
- calls : []
- }
- objj_debug_profile.calls.push(profileRecord);
- objj_debug_profile = profileRecord;
- profileRecord.start = new Date();
-
- var super_class = aSuper.super_class;
-
- arguments[0] = aSuper.receiver;
-
- var result = class_getMethodImplementation(super_class, aSelector).apply(aSuper.receiver, arguments);
-
- profileRecord.end = new Date();
- objj_debug_profile = profileRecord.parent;
-
- return result;
-}
-
-var objj_msgSend_Standard = objj_msgSend,
- objj_msgSendSuper_Standard = objj_msgSendSuper;
-
-// FIXME: This could be much better.
-var objj_debug_backtrace;
-
-function objj_backtrace_set_enabled(enabled)
-{
- if (enabled)
+ for (var i = 0; i < arguments.length; i++)
{
- objj_debug_backtrace = [];
- objj_msgSend = objj_msgSend_Backtrace;
- objj_msgSendSuper = objj_msgSendSuper_Backtrace;
+ objj_msgSend = arguments[i](objj_msgSend);
+ objj_msgSendSuper = arguments[i](objj_msgSendSuper);
+ }
+}
+
+// reset then decorate both objj_msgSend and objj_msgSendSuper
+function objj_msgSend_set_decorators()
+{
+ objj_msgSend_reset();
+ objj_msgSend_decorate.apply(null, arguments);
+}
+
+
+// backtrace decorator
+
+var objj_backtrace = [];
+
+function objj_backtrace_print(stream) {
+ for (var i = 0; i < objj_backtrace.length; i++)
+ objj_fprintf(stream, objj_debug_message_format(objj_backtrace[i].receiver, objj_backtrace[i].selector));
+}
+
+function objj_backtrace_decorator(msgSend)
+{
+ return function(aReceiverOrSuper, aSelector)
+ {
+ var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
+
+ // push the receiver and selector onto the backtrace stack
+ objj_backtrace.push({ receiver: aReceiver, selector : aSelector });
+ try
+ {
+ return msgSend.apply(null, arguments);
+ }
+ catch (anException)
+ {
+ // print the exception and backtrace
+ objj_fprintf(warning_stream, "Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector));
+ objj_backtrace_print(warning_stream);
+ }
+ finally
+ {
+ // make sure to always pop
+ objj_backtrace.pop();
+ }
+ }
+}
+
+// type checking decorator
+
+var objj_typechecks_reported = {},
+ objj_typecheck_prints_backtrace = false;
+
+function objj_typecheck_decorator(msgSend)
+{
+ return function(aReceiverOrSuper, aSelector)
+ {
+ var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
+
+ if (!aReceiver)
+ return msgSend.apply(null, arguments);
+
+ var types = aReceiver.isa.method_dtable[aSelector].types;
+ for (var i = 2; i < arguments.length; i++)
+ {
+ try
+ {
+ objj_debug_typecheck(types[i-1], arguments[i]);
+ }
+ catch (e)
+ {
+ var key = [GETMETA(aReceiver).name, aSelector, i, e].join(";");
+ if (!objj_typechecks_reported[key]) {
+ objj_typechecks_reported[key] = true;
+ objj_fprintf(warning_stream, "Type check failed on argument " + (i-2) + " of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
+ if (objj_typecheck_prints_backtrace)
+ objj_backtrace_print(warning_stream);
+ }
+ }
+ }
+
+ var result = msgSend.apply(null, arguments);
+
+ try
+ {
+ objj_debug_typecheck(types[0], result);
+ }
+ catch (e)
+ {
+ var key = [GETMETA(aReceiver).name, aSelector, "ret", e].join(";");
+ if (!objj_typechecks_reported[key]) {
+ objj_typechecks_reported[key] = true;
+ objj_fprintf(warning_stream, "Type check failed on return val of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
+ if (objj_typecheck_prints_backtrace)
+ objj_backtrace_print(warning_stream);
+ }
+ }
+
+ return result;
+ }
+}
+
+// type checking logic:
+function objj_debug_typecheck(expectedType, object)
+{
+ var objjClass;
+
+ if (!expectedType)
+ {
+ return;
+ }
+ else if (expectedType === "id")
+ {
+ if (object !== undefined)
+ return;
+ }
+ else if (expectedType === "void")
+ {
+ if (object === undefined)
+ return;
+ }
+ else if (objjClass = objj_getClass(expectedType))
+ {
+ if (object === nil)
+ {
+ return;
+ }
+ else if (object && object.isa)
+ {
+ var theClass = object.isa;
+ for (; theClass; theClass = theClass.super_class)
+ if (theClass === objjClass)
+ return;
+ }
}
else
{
- objj_msgSend = objj_msgSend_Standard;
- objj_msgSendSuper = objj_msgSendSuper_Standard;
- }
-}
-
-function objj_debug_print_backtrace()
-{
- print(objj_debug_backtrace_string());
-}
-
-function objj_debug_backtrace_string()
-{
- return objj_debug_backtrace ? objj_debug_backtrace.join("\n") : "";
-}
-
-var objj_debug_profile = null,
- objj_currently_profiling = false,
- objj_profile_cleanup;
-
-function objj_profile(title)
-{
- if (objj_currently_profiling)
return;
-
- var objj_msgSend_profile_saved = objj_msgSend,
- objj_msgSendSuper_profile_saved = objj_msgSendSuper;
-
- objj_msgSend = objj_msgSend_Profile;
- objj_msgSendSuper = objj_msgSendSuper_Profile;
-
- var root = { calls: [] };
- objj_debug_profile = root;
-
- var context = {
- start : new Date(),
- title : title,
- profile : root
- };
-
- objj_profile_cleanup = function() {
- objj_msgSend = objj_msgSend_profile_saved;
- objj_msgSendSuper = objj_msgSendSuper_profile_saved;
- context.end = new Date();
- return context;
}
- objj_currently_profiling = true;
-}
-
-function objj_profileEnd()
-{
- if (!objj_currently_profiling)
- return;
-
- objj_debug_profile = null;
- objj_currently_profiling = false;
-
- return objj_profile_cleanup();
+ var actualType;
+ if (object === null)
+ actualType = "null";
+ else if (object === undefined)
+ actualType = "void";
+ else if (object.isa)
+ actualType = GETMETA(object).name;
+ else
+ actualType = typeof object;
+
+ throw ("expected=" + expectedType + ", actual=" + actualType);
}
diff --git a/Objective-J/dictionary.js b/Objective-J/dictionary.js
index 488994e1d..43bc30b03 100644
--- a/Objective-J/dictionary.js
+++ b/Objective-J/dictionary.js
@@ -28,6 +28,13 @@ function objj_dictionary()
this.__address = _objj_generateObjectHash();
}
+
+objj_dictionary.prototype.containsKey = function(aKey) { return dictionary_containsKey(this, aKey); }
+objj_dictionary.prototype.getCount = function() { return dictionary_getCount(this); }
+objj_dictionary.prototype.getValue = function(aKey) { return dictionary_getValue(this, aKey); }
+objj_dictionary.prototype.setValue = function(aKey, aValue) { return dictionary_setValue(this, aKey, aValue); }
+objj_dictionary.prototype.removeValue = function(aKey) { return dictionary_removeValue(this, aKey); }
+
function dictionary_containsKey(aDictionary, aKey)
{
return aDictionary._buckets[aKey] != NULL;
@@ -116,4 +123,4 @@ function dictionary_description(aDictionary)
str += " }";
return str;
-}
+}
\ No newline at end of file
diff --git a/Objective-J/evaluate.js b/Objective-J/evaluate.js
index 70929d87e..6bd4d6979 100644
--- a/Objective-J/evaluate.js
+++ b/Objective-J/evaluate.js
@@ -158,10 +158,23 @@ function fragment_evaluate_code(aFragment)
try
{
#if RHINO
- compiled = eval("function(){"+GET_CODE(aFragment)+"}");
- //compiled = Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(window, "function(){"+GET_CODE(aFragment)+"}", GET_FILE(aFragment).path, 0, null);
+ var functionText = "function(){"+GET_CODE(aFragment)+"/**/\n}";
+ if (window.isRhino)
+ compiled = Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(window, functionText, GET_FILE(aFragment).path, 0, null);
+ else
+ compiled = eval(functionText);
#else
- compiled = new Function(GET_CODE(aFragment));
+ // "//@ sourceURL=" at the end lets us name our eval'd files for debuggers, etc.
+ // * WebKit: http://pmuellr.blogspot.com/2009/06/debugger-friendly.html
+ // * Firebug: http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
+ //if (true) {
+ var functionText = GET_CODE(aFragment)+"/**/\n//@ sourceURL="+GET_FILE(aFragment).path;
+ compiled = new Function(functionText);
+ //} else {
+ // // Firebug only does it for "eval()", not "new Function()". Ugh. Slower.
+ // var functionText = "(function(){"+GET_CODE(aFragment)+"/**/\n})\n//@ sourceURL="+GET_FILE(aFragment).path;
+ // compiled = eval(functionText);
+ //}
compiled.displayName = GET_FILE(aFragment).path;
#endif
}
@@ -170,6 +183,9 @@ function fragment_evaluate_code(aFragment)
objj_exception_report(anException, GET_FILE(aFragment));
}
+#if RHINO
+ compiled();
+#else
try
{
compiled();
@@ -178,6 +194,7 @@ function fragment_evaluate_code(aFragment)
{
objj_exception_report(anException, GET_FILE(aFragment));
}
+#endif
return NO;
}
diff --git a/Objective-J/file.js b/Objective-J/file.js
index 748c3cf46..2299e5f52 100644
--- a/Objective-J/file.js
+++ b/Objective-J/file.js
@@ -301,7 +301,9 @@ objj_search.prototype.request = function(aFilePath, aMethod)
try
{
- request.open("GET", aFilePath.replace(/\+/g, "%2B"), YES);
+ // unclear whether plusses are reserved in the URI path
+ //request.open("GET", aFilePath.replace(/\+/g, "%2B"), YES);
+ request.open("GET", aFilePath, YES);
request.send("");
}
catch (anException)
diff --git a/Objective-J/json2.js b/Objective-J/json2.js
new file mode 100644
index 000000000..7e27df518
--- /dev/null
+++ b/Objective-J/json2.js
@@ -0,0 +1,478 @@
+/*
+ http://www.JSON.org/json2.js
+ 2009-04-16
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or ' '),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the object holding the key.
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+*/
+
+/*jslint evil: true */
+
+/*global JSON */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+*/
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (!this.JSON) {
+ JSON = {};
+}
+(function () {
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ?
+ '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+}());
diff --git a/Objective-J/preprocess.js b/Objective-J/preprocess.js
index 0032ed203..44478a14e 100644
--- a/Objective-J/preprocess.js
+++ b/Objective-J/preprocess.js
@@ -20,7 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = 1 << 0;
+var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = 1 << 0,
+ OBJJ_PREPROCESSOR_TYPE_SIGNATURES = 1 << 1;
function objj_preprocess(/*String*/ aString, /*objj_bundle*/ aBundle, /*objj_file*/ aSourceFile, /*unsigned*/ flags)
{
@@ -168,8 +169,10 @@ objj_stringBuffer.prototype.isEmpty = function()
var objj_preprocessor = function(aString, aSourceFile, aBundle, flags)
{
+ this._currentSelector = "";
this._currentClass = "";
this._currentSuperClass = "";
+ this._currentSuperMetaClass = "";
this._file = aSourceFile;
this._fragments = [];
@@ -177,6 +180,7 @@ var objj_preprocessor = function(aString, aSourceFile, aBundle, flags)
this._tokens = new objj_lexer(aString);
this._flags = flags;
this._bundle = aBundle;
+ this._classMethod = false;
this.preprocess(this._tokens, this._preprocessed);
//alert(this._preprocessed + "");
@@ -206,19 +210,19 @@ objj_preprocessor.prototype.accessors = function(tokens)
value = true;
if (!IS_WORD(name))
- objj_exception_throw(new objj_exception(OBJJParseException, "*** @property attribute name not valid."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** @property attribute name not valid.")));
if ((token = tokens.skip_whitespace()) == TOKEN_EQUAL)
{
value = tokens.skip_whitespace();
if (!IS_WORD(value))
- objj_exception_throw(new objj_exception(OBJJParseException, "*** @property attribute value not valid."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** @property attribute value not valid.")));
if (name == "setter")
{
if ((token = tokens.next()) != TOKEN_COLON)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** @property setter attribute requires argument with \":\" at end of selector name."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** @property setter attribute requires argument with \":\" at end of selector name.")));
value += ":";
}
@@ -232,7 +236,7 @@ objj_preprocessor.prototype.accessors = function(tokens)
break;
if (token != TOKEN_COMMA)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected ',' or ')' in @property attribute list."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected ',' or ')' in @property attribute list.")));
}
return attributes;
@@ -262,8 +266,7 @@ objj_preprocessor.prototype.brackets = function(/*objj_lexer*/ tokens, /*objj_st
if (tuples[0][0].atoms[0] == TOKEN_SUPER)
{
CONCAT(aStringBuffer, "objj_msgSendSuper(");
- CONCAT(aStringBuffer, "{ receiver:self, super_class:" + this._currentSuperClass + " }");
-
+ CONCAT(aStringBuffer, "{ receiver:self, super_class:" + (this._classMethod ? this._currentSuperMetaClass : this._currentSuperClass ) + " }");
}
else
{
@@ -350,38 +353,46 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
category = NO,
class_name = tokens.skip_whitespace(),
superclass_name = "Nil",
-
+
instance_methods = new objj_stringBuffer(),
class_methods = new objj_stringBuffer();
if (!(/^\w/).test(class_name))
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected class name, found \"" + class_name + "\"."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected class name, found \"" + class_name + "\".")));
this._currentSuperClass = NULL;
+ this._currentSuperMetaClass = NULL;
this._currentClass = class_name;
-
+ this._currentSelector = "";
+
// If we reach an open parenthesis, we are declaring a category.
if((token = tokens.skip_whitespace()) == TOKEN_OPEN_PARENTHESIS)
{
token = tokens.skip_whitespace();
if (token == TOKEN_CLOSE_PARENTHESIS)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Can't Have Empty Category Name for class \"" + class_name + "\"."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Can't Have Empty Category Name for class \"" + class_name + "\".")));
if (tokens.skip_whitespace() != TOKEN_CLOSE_PARENTHESIS)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Improper Category Definition for class \"" + class_name + "\"."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Improper Category Definition for class \"" + class_name + "\".")));
CONCAT(buffer, "{\nvar the_class = objj_getClass(\"" + class_name + "\")\n");
CONCAT(buffer, "if(!the_class) objj_exception_throw(new objj_exception(OBJJClassNotFoundException, \"*** Could not find definition for class \\\"" + class_name + "\\\"\"));\n");
CONCAT(buffer, "var meta_class = the_class.isa;");
var superclass_name = dictionary_getValue(SUPER_CLASSES, class_name);
-
+
// FIXME: We should have a better solution for this case, although it's actually not much slower than the real case.
if (!superclass_name)
+ {
this._currentSuperClass = "objj_getClass(\"" + class_name + "\").super_class";
+ this._currentSuperMetaClass = "objj_getMetaClass(\"" + class_name + "\").super_class";
+ }
else
+ {
this._currentSuperClass = "objj_getClass(\"" + superclass_name + "\")";
+ this._currentSuperMetaClass = "objj_getMeraClass(\"" + superclass_name + "\")";
+ }
}
else
{
@@ -391,10 +402,12 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
token = tokens.skip_whitespace();
if (!TOKEN_IDENTIFIER.test(token))
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected class name, found \"" + token + "\"."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected class name, found \"" + token + "\".")));
superclass_name = token;
+
this._currentSuperClass = "objj_getClass(\"" + superclass_name + "\")";
+ this._currentSuperMetaClass = "objj_getMetaClass(\"" + superclass_name + "\")";
dictionary_setValue(SUPER_CLASSES, class_name, superclass_name);
@@ -442,13 +455,13 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
// If we have objects in our declaration, the user forgot a ';'.
if (declaration.length)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected ';' in ivar declaration, found '}'."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected ';' in ivar declaration, found '}'.")));
if (ivar_count)
CONCAT(buffer, "]);\n");
if (!token)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected '}'"));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected '}'")));
for (ivar_name in accessors)
{
@@ -503,6 +516,8 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
{
if (token == TOKEN_PLUS)
{
+ this._classMethod = true;
+
if (IS_NOT_EMPTY(class_methods))
CONCAT(class_methods, ", ");
@@ -511,6 +526,8 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
else if (token == TOKEN_MINUS)
{
+ this._classMethod = false;
+
if (IS_NOT_EMPTY(instance_methods))
CONCAT(instance_methods, ", ");
@@ -525,7 +542,7 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
break;
else
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected \"@end\", found \"@" + token + "\"."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected \"@end\", found \"@" + token + "\".")));
}
}
@@ -544,6 +561,8 @@ objj_preprocessor.prototype.implementation = function(tokens, /*objj_stringBuffe
}
CONCAT(buffer, '}');
+
+ this._currentClass = "";
}
objj_preprocessor.prototype._import = function(tokens)
@@ -561,14 +580,14 @@ objj_preprocessor.prototype._import = function(tokens)
path += token;
if(!token)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Unterminated import statement."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Unterminated import statement.")));
}
else if (token.charAt(0) == TOKEN_DOUBLE_QUOTE)
path = token.substr(1, token.length - 2);
else
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Expecting '<' or '\"', found \"" + token + "\"."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expecting '<' or '\"', found \"" + token + "\".")));
this._fragments.push(fragment_create_file(path, NULL, isLocal, this._file));
}
@@ -578,12 +597,15 @@ objj_preprocessor.prototype.method = function(tokens)
var buffer = new objj_stringBuffer(),
token,
selector = "",
- parameters = [];
+ parameters = [],
+ types = [null];
while((token = tokens.skip_whitespace()) && token != TOKEN_OPEN_BRACE)
{
if (token == TOKEN_COLON)
{
+ var type = "";
+
// Colons are part of the selector name
selector += token;
@@ -592,25 +614,37 @@ objj_preprocessor.prototype.method = function(tokens)
if (token == TOKEN_OPEN_PARENTHESIS)
{
// Swallow parameter/return type. Perhaps later we can use this for debugging?
- while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS) ;
+ while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS)
+ type += token;
token = tokens.skip_whitespace();
}
+ // Add the type. If it's empty, add null instead.
+ types[parameters.length+1] = type || null;
+
// Since this follows a colon, this must be the parameter name.
parameters[parameters.length] = token;
}
else if (token == TOKEN_OPEN_PARENTHESIS)
+ {
+ var type = "";
+
// Since :( is handled above, this must be the return type, just swallow it.
- while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS) ;
+ while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS)
+ type += token;
+
+ // types[0] is the return argument
+ types[0] = type || null;
+ }
// Argument list ", ..."
else if (token == TOKEN_COMMA)
{
// At this point, "..." MUST follow.
if ((token = tokens.skip_whitespace()) != TOKEN_PERIOD || tokens.next() != TOKEN_PERIOD || tokens.next() != TOKEN_PERIOD)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Argument list expected after ','."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Argument list expected after ','.")));
// FIXME: Shouldn't allow any more after this.
}
@@ -626,7 +660,9 @@ objj_preprocessor.prototype.method = function(tokens)
CONCAT(buffer, "new objj_method(sel_getUid(\"");
CONCAT(buffer, selector);
CONCAT(buffer, "\"), function");
-
+
+ this._currentSelector = selector;
+
if (this._flags & OBJJ_PREPROCESSOR_DEBUG_SYMBOLS)
CONCAT(buffer, " $" + this._currentClass + "__" + selector.replace(/:/g, "_"));
@@ -640,7 +676,13 @@ objj_preprocessor.prototype.method = function(tokens)
CONCAT(buffer, ")\n{ with(self)\n{");
CONCAT(buffer, this.preprocess(tokens, NULL, TOKEN_CLOSE_BRACE, TOKEN_OPEN_BRACE));
- CONCAT(buffer, "}\n})");
+ CONCAT(buffer, "}\n}");
+ // TODO: actually use OBJJ_PREPROCESSOR_TYPE_SIGNATURES flag instead of tying to OBJJ_PREPROCESSOR_DEBUG_SYMBOLS
+ if (this._flags & OBJJ_PREPROCESSOR_DEBUG_SYMBOLS) //OBJJ_PREPROCESSOR_TYPE_SIGNATURES)
+ CONCAT(buffer, ","+JSON.stringify(types));
+ CONCAT(buffer, ")");
+
+ this._currentSelector = "";
return buffer;
}
@@ -850,7 +892,7 @@ objj_preprocessor.prototype.preprocess = function(tokens, /*objj_stringBuffer*/
// If we get this far and we're parsing an objj_msgSend (or array), then we have a problem.
if (tuple)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected ']' - Unterminated message send or array."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected ']' - Unterminated message send or array.")));
if (!aStringBuffer)
return buffer;
@@ -864,13 +906,13 @@ objj_preprocessor.prototype.selector = function(tokens, aStringBuffer)
// Swallow open parenthesis.
if (tokens.skip_whitespace() != TOKEN_OPEN_PARENTHESIS)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Expected '('"));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Expected '('")));
// Eat leading whitespace
var selector = tokens.skip_whitespace();
if (selector == TOKEN_CLOSE_PARENTHESIS)
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Unexpected ')', can't have empty @selector()"));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Unexpected ')', can't have empty @selector()")));
CONCAT(aStringBuffer, selector);
@@ -886,9 +928,9 @@ objj_preprocessor.prototype.selector = function(tokens, aStringBuffer)
if (tokens.skip_whitespace() == TOKEN_CLOSE_PARENTHESIS)
break;
else
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Unexpected whitespace in @selector()."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Unexpected whitespace in @selector().")));
else
- objj_exception_throw(new objj_exception(OBJJParseException, "*** Illegal character '" + token + "' in @selector()."));
+ objj_exception_throw(new objj_exception(OBJJParseException, this.error_message("*** Illegal character '" + token + "' in @selector().")));
}
CONCAT(buffer, token);
@@ -900,3 +942,10 @@ objj_preprocessor.prototype.selector = function(tokens, aStringBuffer)
if (!aStringBuffer)
return buffer;
}
+
+objj_preprocessor.prototype.error_message = function(errorMessage)
+{
+ return errorMessage + " ";
+}
diff --git a/Objective-J/runtime.js b/Objective-J/runtime.js
index 5ed505846..365ab725a 100644
--- a/Objective-J/runtime.js
+++ b/Objective-J/runtime.js
@@ -177,8 +177,8 @@ function class_addMethod(/*Class*/ aClass, /*SEL*/ aName, /*IMP*/ anImplementati
// FIXME: Should this be done here?
// If this is a root class...
if (!ISMETA(aClass) && GETMETA(aClass).isa === GETMETA(aClass))
- class_addMethods(GETMETA(aClass), methods);
-
+ class_addMethod(GETMETA(aClass), method);
+
return YES;
}
diff --git a/Rakefile b/Rakefile
index 4f0a3da62..05a81dfee 100644
--- a/Rakefile
+++ b/Rakefile
@@ -33,12 +33,14 @@ $STARTER_DOWNLOAD = File.join($BUILD_DIR, 'Cappuccino', 'Start
$STARTER_DOWNLOAD_APPLICATION = File.join($STARTER_DOWNLOAD, 'NewApplication')
$STARTER_DOWNLOAD_README = File.join($STARTER_DOWNLOAD, 'README')
-task :downloads => [:starter_download, :tools_download]
+$NARWHAL_PACKAGE = File.join($BUILD_DIR, 'Cappuccino', 'objj')
+
+task :downloads => [:starter_download, :tools_download, :narwhal_package]
file_d $TOOLS_DOWNLOAD_ENV => [:debug, :release] do
rm_rf($TOOLS_DOWNLOAD_ENV)
- cp_r(File.join($RELEASE_ENV, '.'), $TOOLS_DOWNLOAD_ENV)
- cp_r(File.join($DEBUG_ENV, 'lib', 'Frameworks', '.'), File.join($TOOLS_DOWNLOAD_ENV, 'lib', 'Frameworks', 'Debug'))
+ cp_r(File.join($RELEASE_ENV), $TOOLS_DOWNLOAD_ENV)
+ cp_r(File.join($DEBUG_ENV, 'packages', 'objj', 'lib', 'Frameworks'), File.join($TOOLS_DOWNLOAD_ENV, 'packages', 'objj', 'lib', 'Frameworks', 'Debug'))
end
file_d $TOOLS_DOWNLOAD_EDITORS => [$TOOLS_EDITORS] do
@@ -61,6 +63,11 @@ task :tools_download => [$TOOLS_DOWNLOAD_ENV, $TOOLS_DOWNLOAD_EDITORS, $TOOLS_DO
task :starter_download => [$STARTER_DOWNLOAD_APPLICATION, $STARTER_DOWNLOAD_README]
+task :narwhal_package => [$TOOLS_DOWNLOAD_ENV] do
+ rm_rf($NARWHAL_PACKAGE)
+ cp_r(File.join($TOOLS_DOWNLOAD_ENV, 'packages', 'objj'), $NARWHAL_PACKAGE)
+end
+
task :deploy => [:downloads, :docs] do
#copy the docs into the starter pack
cp_r(File.join($DOCUMENTATION_BUILD, 'html', '.'), File.join($STARTER_DOWNLOAD, 'Documentation'))
@@ -86,7 +93,9 @@ file_d $STARTER_DOWNLOAD_APPLICATION => [$TOOLS_DOWNLOAD_ENV] do
rm_rf($STARTER_DOWNLOAD_APPLICATION)
mkdir_p($STARTER_DOWNLOAD)
+
system %{capp gen #{$STARTER_DOWNLOAD_APPLICATION} -t Application --noconfig }
+ rake abort if ($? != 0)
# No tools means no objective-j gem
rm(File.join($STARTER_DOWNLOAD_APPLICATION, 'Rakefile'))
@@ -103,7 +112,9 @@ task :install => [:tools_download] do
else
prefix = ''
end
+
system %{cd #{$TOOLS_DOWNLOAD} && sudo sh ./install-tools #{prefix} }
+ rake abort if ($? != 0)
end
task :test => [:build] do
@@ -122,6 +133,8 @@ end
task :docs do
if executable_exists? "doxygen"
system %{doxygen #{$DOXYGEN_CONFIG} }
+ rake abort if ($? != 0)
+
rm_rf $DOCUMENTATION_BUILD
mv "debug.txt", "Documentation"
mv "Documentation", $DOCUMENTATION_BUILD
@@ -133,6 +146,7 @@ end
task :submodules do
if executable_exists? "git"
system %{git submodule init && git submodule update}
+ rake abort if ($? != 0)
else
puts "Git not installed"
rake abort
diff --git a/Tests/AppKit/CPCollectionViewTest.j b/Tests/AppKit/CPCollectionViewTest.j
new file mode 100644
index 000000000..fc6eeafe2
--- /dev/null
+++ b/Tests/AppKit/CPCollectionViewTest.j
@@ -0,0 +1,16 @@
+// Just doing @import failed on CPWindow not being defined somewhere.
+@import
+
+@implementation CPCollectionViewTest : OJTestCase
+
+- (void)testItemPrototypeActuallyReturnsTheItemPrototype
+{
+ var propertiesCollectionView = [[CPCollectionView alloc] initWithFrame:CGRectMakeZero()],
+ itemPrototype = [[CPCollectionViewItem alloc] init];
+
+ [propertiesCollectionView setItemPrototype:itemPrototype];
+
+ [self assert:[CPCollectionViewItem class] equals:[[propertiesCollectionView itemPrototype] class]];
+}
+
+@end
diff --git a/Tests/AppKit/CPScrollViewTest.j b/Tests/AppKit/CPScrollViewTest.j
new file mode 100644
index 000000000..428268c09
--- /dev/null
+++ b/Tests/AppKit/CPScrollViewTest.j
@@ -0,0 +1,177 @@
+@import
+
+@implementation CPScrollViewTest : OJTestCase
+{
+}
+
+- (void)testBothScrollersVisible
+{
+ var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 100.0)];
+
+ [scrollView setAutohidesScrollers:NO];
+ [scrollView setHasHorizontalScroller:YES];
+ [scrollView setHasVerticalScroller:YES];
+
+ var documentView = [[CPView alloc] init];
+
+ [scrollView setDocumentView:documentView];
+
+ // Test document view size smaller than scroll view size.
+ [documentView setFrameSize:CGSizeMake(50.0, 50.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+
+ // Test document view size much larger than scroll view size.
+ [documentView setFrameSize:CGSizeMake(1000.0, 1000.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:YES];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:YES];
+
+ // Test document view size much taller than scroll view size.
+ [documentView setFrameSize:CGSizeMake(50.0, 1000.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:YES];
+
+ // Test document view size much wider than scroll view size.
+ [documentView setFrameSize:CGSizeMake(1000.0, 50.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:YES];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+
+ // Test document view size equal to scroll view size.
+ [documentView setFrameSize:CGSizeMake(100.0, 100.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:YES];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:YES];
+
+ // Test document view size taller than scroll view size only because of scrollers.
+ [documentView setFrameSize:CGSizeMake(50.0, 100.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:YES];
+
+ // Test document view size wider than scroll view size only because of scrollers.
+ [documentView setFrameSize:CGSizeMake(100.0, 50.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:YES];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+
+ // Test document view size exactly the right size relative to the scroll view size.
+ [documentView setFrameSize:CGSizeMake(100.0 - 17.0, 100.0 - 17.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+}
+
+- (void)testAutoHidesScrollers
+{
+ var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 100.0)];
+
+ [scrollView setAutohidesScrollers:YES];
+ [scrollView setHasHorizontalScroller:YES];
+ [scrollView setHasVerticalScroller:YES];
+
+ var documentView = [[CPView alloc] init];
+
+ [scrollView setDocumentView:documentView];
+
+ // Test document view size smaller than scroll view size.
+ [documentView setFrameSize:CGSizeMake(50.0, 50.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+
+ // Test document view size much larger than scroll view size.
+ [documentView setFrameSize:CGSizeMake(1000.0, 1000.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:YES];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:YES];
+
+ // Test document view size much taller than scroll view size.
+ [documentView setFrameSize:CGSizeMake(50.0, 1000.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:YES];
+
+ // Test document view size much wider than scroll view size.
+ [documentView setFrameSize:CGSizeMake(1000.0, 50.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:NO];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:YES];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+
+ // Test document view size equal to scroll view size.
+ [documentView setFrameSize:CGSizeMake(100.0, 100.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+
+ // Test document view size taller than scroll view size only because of scrollers.
+ [documentView setFrameSize:CGSizeMake(50.0, 100.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+
+ // Test document view size wider than scroll view size only because of scrollers.
+ [documentView setFrameSize:CGSizeMake(100.0, 50.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+
+ // Test document view size exactly the right size relative to the scroll view size.
+ [documentView setFrameSize:CGSizeMake(100.0 - 17.0, 100.0 - 17.0)];
+
+ [self assert:[[scrollView horizontalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView horizontalScroller] isEnabled] equals:NO];
+
+ [self assert:[[scrollView verticalScroller] isHidden] equals:YES];
+ [self assert:[[scrollView verticalScroller] isEnabled] equals:NO];
+}
+
+@end
\ No newline at end of file
diff --git a/Tests/AppKit/CPSearchFieldTest.j b/Tests/AppKit/CPSearchFieldTest.j
new file mode 100644
index 000000000..0ee5ff3a1
--- /dev/null
+++ b/Tests/AppKit/CPSearchFieldTest.j
@@ -0,0 +1,28 @@
+@import
+
+@implementation CPSearchFieldTest : OJTestCase
+{
+ CPSearchField _searchField;
+}
+
+- (void)setUp
+{
+ _searchField = [[CPSearchField alloc] initWithFrame:CGRectMakeZero()];
+}
+
+- (void)testMakeCPSearchFieldInstance
+{
+ [self assertNotNull:_searchField];
+}
+
+- (void)testRecentSearchesStartsEmpty
+{
+ [self assertTrue:[[_searchField recentSearches] count] == 0 message:@"After instance creation we shouldn't have any recent searches."];
+}
+
+- (void)testSetRecentSearches
+{
+ searches = ["foo", "bar", "baz"];
+ [_searchField setRecentSearches:searches]
+ [self assertTrue:[[_searchField recentSearches] count] == 3 message:@"After setRecentSearches array doesn't include results"];
+}
diff --git a/Tests/AppKit/CPSegmentedControlTest.j b/Tests/AppKit/CPSegmentedControlTest.j
new file mode 100644
index 000000000..ffd794113
--- /dev/null
+++ b/Tests/AppKit/CPSegmentedControlTest.j
@@ -0,0 +1,33 @@
+@import
+
+// TODO: Maybe create one test file for each tracking mode so they can be tested separately without confusion.
+@implementation CPSegmentedControlTest : OJTestCase
+{
+ CPSegmentedControlTest _segmentedControl;
+}
+
+- (void)setUp
+{
+ _segmentedControl = [[CPSegmentedControl alloc] initWithFrame:CGRectMakeZero()];
+ [_segmentedControl setSegmentCount:3];
+}
+
+- (void)testMakeCPSegmentedControlInstance
+{
+ [self assertNotNull:_segmentedControl];
+}
+
+- (void)testDefaultsToSelectOneTrackingMode
+{
+ [self assert:[_segmentedControl trackingMode] equals:CPSegmentSwitchTrackingSelectOne];
+}
+
+- (void)testSelectsOneSegmentStartingAtBlankState
+{
+ [self assert:[_segmentedControl selectedSegment] equals:-1];
+ [_segmentedControl setSelectedSegment:1];
+ [self assert:[_segmentedControl selectedSegment] equals:1];
+}
+
+@end
+
diff --git a/Tests/AppKit/CPTableViewTest.j b/Tests/AppKit/CPTableViewTest.j
new file mode 100644
index 000000000..a7f93d1b8
--- /dev/null
+++ b/Tests/AppKit/CPTableViewTest.j
@@ -0,0 +1,24 @@
+@import
+
+@implementation CPTableViewTest : OJTestCase
+{
+}
+
+- (void)setUp
+{
+ // setup a reasonable table
+ _tableView = [[CPTableView alloc] initWithFrame:CGRectMakeZero()];
+ _tableColumn = [[CPTableColumn alloc] initWithIdentifier:@"Foo"];
+ [_tableView addTableColumn:_tableColumn];
+}
+/*
+// Failing test for issue 112, See:http://github.com/280north/cappuccino/issues/#issue/112
+- (void)testCPTableDoubleAction
+{
+ // CPEvent with 2 clickCount
+ var dblClk = [CPEvent mouseEventWithType:CPLeftMouseUp location:CGPointMakeZero() modifierFlags:0
+ timestamp:0 windowNumber:0 context:nil eventNumber:0 clickCount:2 pressure:0];
+
+ [_tableView trackSelection:dblClk];
+}
+*/
\ No newline at end of file
diff --git a/Tests/Foundation/CPArrayTest.j b/Tests/Foundation/CPArrayTest.j
index d14632902..04ea56486 100644
--- a/Tests/Foundation/CPArrayTest.j
+++ b/Tests/Foundation/CPArrayTest.j
@@ -1,6 +1,7 @@
@import
@import
@import
+@import
@implementation CPArrayTest : OJTestCase
@@ -92,4 +93,79 @@
[self assert:array equals:[@"one", @"two", @"four"]];
}
+
+- (void)testIndexOfObjectSortedByFunction
+{
+ var array = [0, 1, 2, 3, 4, 7];
+
+ [self assert:[array indexOfObject:3 sortedByFunction:function(a, b){ return a - b; }] equals:3];
+ [self assert:[[array arrayByReversingArray] indexOfObject:3 sortedByFunction:function(a, b){ return b - a; }] equals:2];
+}
+
+- (void)testIndexOfObjectSortedByDescriptors
+{
+ var array = [0, 1, 2, 3, 4, 7];
+
+ [self assert:[array indexOfObject:3
+ sortedByDescriptors:[[[CPSortDescriptor alloc] initWithKey:@"intValue" ascending:YES]]]
+ equals:3];
+
+ [self assert:[[array arrayByReversingArray] indexOfObject:3
+ sortedByDescriptors:[[[CPSortDescriptor alloc] initWithKey:@"intValue" ascending:NO]]]
+ equals:2];
+}
+
+- (void)testIndexOutOfBounds
+{
+ try
+ {
+ [[] objectAtIndex:0];
+ [self assert:false];
+ }
+ catch (anException)
+ {
+ [self assert:[anException name] equals:CPRangeException];
+ [self assert:[anException reason] equals:@"index (0) beyond bounds (0)"];
+ }
+
+ [[0, 1, 2] objectAtIndex:0];
+ [[0, 1, 2] objectAtIndex:1];
+ [[0, 1, 2] objectAtIndex:2];
+
+ try
+ {
+ [[0, 1, 2] objectAtIndex:3];
+ [self assert:false];
+ }
+ catch (anException)
+ {
+ [self assert:[anException name] equals:CPRangeException];
+ [self assert:[anException reason] equals:@"index (3) beyond bounds (3)"];
+ }
+
+ try
+ {
+ [[0, 1, 2] objectAtIndex:4];
+ [self assert:false];
+ }
+ catch (anException)
+ {
+ [self assert:[anException name] equals:CPRangeException];
+ [self assert:[anException reason] equals:@"index (4) beyond bounds (3)"];
+ }
+}
+
+@end
+
+@implementation CPArray (reverse)
+
+- (CPArray)arrayByReversingArray
+{
+ var a = [];
+ for (i = length - 1; i>0; --i)
+ a.push(self[i]);
+
+ return a;
+}
+
@end
diff --git a/Tests/Foundation/CPIndexSetTest.j b/Tests/Foundation/CPIndexSetTest.j
new file mode 100644
index 000000000..b4d05ae9d
--- /dev/null
+++ b/Tests/Foundation/CPIndexSetTest.j
@@ -0,0 +1,362 @@
+@import
+
+function descriptionWithoutEntity(aString)
+{
+ var descriptionWithEntity = [aString description];
+//print(descriptionWithEntity);
+ return descriptionWithEntity.substr(descriptionWithEntity.indexOf('>') + 1);
+}
+
+@implementation CPIndexSetTest : OJTestCase
+{
+ CPIndexSet _set;
+}
+
+- (void)testAddIndexes
+{
+ var indexSet = [CPIndexSet indexSet];
+
+ // Test no indexes
+ [self assert:descriptionWithoutEntity(indexSet) equals:@"(no indexes)"];
+
+ // Test adding initial range
+ [indexSet addIndexesInRange:CPMakeRange(30,10)];
+
+ [self assert:@"[number of indexes: 10 (in 1 range), indexes: (30-39)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test adding range after existing ranges.
+ [indexSet addIndexesInRange:CPMakeRange(50,10)];
+
+ [self assert:@"[number of indexes: 20 (in 2 ranges), indexes: (30-39 50-59)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test adding range before existing ranges.
+ [indexSet addIndexesInRange:CPMakeRange(10,10)];
+
+ [self assert:@"[number of indexes: 30 (in 3 ranges), indexes: (10-19 30-39 50-59)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test adding range inbetween existing ranges.
+ [indexSet addIndexesInRange:CPMakeRange(45,2)];
+
+ [self assert:@"[number of indexes: 32 (in 4 ranges), indexes: (10-19 30-39 45-46 50-59)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test adding single index inbetween existing ranges.
+ [indexSet addIndexesInRange:CPMakeRange(23,1)];
+
+ [self assert:@"[number of indexes: 33 (in 5 ranges), indexes: (10-19 23 30-39 45-46 50-59)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test adding range inbetween existing ranges that forces a combination
+ [indexSet addIndexesInRange:CPMakeRange(47,3)];
+
+ [self assert:@"[number of indexes: 36 (in 4 ranges), indexes: (10-19 23 30-39 45-59)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test adding range across ranges forcing a combination
+ [indexSet addIndexesInRange:CPMakeRange(35,15)];
+
+ [self assert:@"[number of indexes: 41 (in 3 ranges), indexes: (10-19 23 30-59)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test adding range across two empty slots forcing a combination
+ [indexSet addIndexesInRange:CPMakeRange(5,70)];
+
+ [self assert:@"[number of indexes: 70 (in 1 range), indexes: (5-74)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test adding to extend the beginning of the first range
+ [indexSet addIndex:4];
+
+ [self assert:@"[number of indexes: 71 (in 1 range), indexes: (4-74)]" equals:descriptionWithoutEntity(indexSet)];
+}
+
+- (void)testRemoveIndexes
+{
+ var indexSet = [CPIndexSet indexSet];
+
+ // Test no indexes
+ [self assert:descriptionWithoutEntity(indexSet) equals:@"(no indexes)"];
+
+ // Test adding initial range
+ [indexSet addIndexesInRange:CPMakeRange(0, 70)];
+
+ [self assert:@"[number of indexes: 70 (in 1 range), indexes: (0-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test remove range that is subset of existing range, causing a split.
+ [indexSet removeIndexesInRange:CPMakeRange(30, 10)];
+
+ [self assert:@"[number of indexes: 60 (in 2 ranges), indexes: (0-29 40-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test remove range that is subset of existing range, causing a split.
+ [indexSet removeIndexesInRange:CPMakeRange(50, 5)];
+
+ [self assert:@"[number of indexes: 55 (in 3 ranges), indexes: (0-29 40-49 55-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test remove index that is subset of existing range, causing a split.
+ [indexSet removeIndex:57];
+
+ [self assert:@"[number of indexes: 54 (in 4 ranges), indexes: (0-29 40-49 55-56 58-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test remove range that is an exactly represented in the set.
+ [indexSet removeIndexesInRange:CPMakeRange(40, 10)];
+
+ [self assert:@"[number of indexes: 44 (in 3 ranges), indexes: (0-29 55-56 58-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test remove range that isn't in the set.
+ [indexSet removeIndexesInRange:CPMakeRange(35, 3)];
+
+ [self assert:@"[number of indexes: 44 (in 3 ranges), indexes: (0-29 55-56 58-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test remove range that is partially in a left range.
+ [indexSet removeIndexesInRange:CPMakeRange(25, 7)];
+
+ [self assert:@"[number of indexes: 39 (in 3 ranges), indexes: (0-24 55-56 58-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test remove range that is partially in a left range.
+ [indexSet removeIndexesInRange:CPMakeRange(57, 3)];
+
+ [self assert:@"[number of indexes: 37 (in 3 ranges), indexes: (0-24 55-56 60-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Test remove range that is partially in a left and right range.
+ [indexSet removeIndexesInRange:CPMakeRange(20, 36)];
+
+ [self assert:@"[number of indexes: 31 (in 3 ranges), indexes: (0-19 56 60-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Remove single index that represents an entire range.
+ [indexSet removeIndex:56];
+
+ [self assert:@"[number of indexes: 30 (in 2 ranges), indexes: (0-19 60-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Remove index set that is subset of existing range, causing a split.
+ [indexSet removeIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(5, 10)]];
+
+ [self assert:@"[number of indexes: 20 (in 3 ranges), indexes: (0-4 15-19 60-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Remove indexes that are partially in 2 ranges and contains intermediate range.
+ [indexSet removeIndexesInRange:CPMakeRange(2, 62)];
+
+ [self assert:@"[number of indexes: 8 (in 2 ranges), indexes: (0-1 64-69)]" equals:descriptionWithoutEntity(indexSet)];
+
+ // Remove indexes that fit exactly in 2 ranges.
+ [indexSet removeIndexesInRange:CPMakeRange(0, 70)];
+
+ [self assert:@"(no indexes)" equals:descriptionWithoutEntity(indexSet)];
+
+ indexSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, 30)];
+
+ // Remove indexes from left hand of single range
+ [indexSet removeIndexesInRange:CPMakeRange(0, 29)];
+
+ [self assert:@"[number of indexes: 1 (in 1 range), indexes: (29)]" equals:descriptionWithoutEntity(indexSet)];
+
+ indexSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, 30)];
+
+ // Remove indexes from right hand of single range
+ [indexSet removeIndexesInRange:CPMakeRange(1, 29)];
+
+ [self assert:@"[number of indexes: 1 (in 1 range), indexes: (0)]" equals:descriptionWithoutEntity(indexSet)];
+}
+
+- (void)testGetIndexes
+{
+ var indexSet = [CPIndexSet indexSet];
+
+ // Test no indexes
+ [self assert:descriptionWithoutEntity(indexSet) equals:@"(no indexes)"];
+
+ // Test adding initial range
+ [indexSet addIndexesInRange:CPMakeRange(0, 10)];
+
+ [indexSet addIndexesInRange:CPMakeRange(15, 1)];
+
+ [indexSet addIndexesInRange:CPMakeRange(20, 10)];
+
+ [indexSet addIndexesInRange:CPMakeRange(50, 10)];
+
+ [self assert:@"[number of indexes: 31 (in 4 ranges), indexes: (0-9 15 20-29 50-59)]" equals:descriptionWithoutEntity(indexSet)];
+
+ var array = [];
+
+ [indexSet getIndexes:array maxCount:1000 inIndexRange:nil];
+
+ [self assert:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59] equals:array];
+}
+
+- (void)setUp
+{
+ _set = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)];
+}
+
+- (void)tearDown
+{
+ _set = nil;
+}
+
+- (void)testIndexSet:(CPIndexSet)set containsRange:(CPRange)range
+{
+ [self assertFalse:[set containsIndex:range.location -1]];
+
+ for (var i=range.location, max=CPMaxRange(range); i
+
+
+@implementation AppController : CPObject
+{
+ CPWindow theWindow; //this "outlet" is connected automatically by the Cib
+}
+
+- (void)applicationDidFinishLaunching:(CPNotification)aNotification
+{
+ // This is called when the application is done loading.
+}
+
+- (void)awakeFromCib
+{
+ // This is called when the cib is done loading.
+ // You can implement this method on any object instantiated from a Cib.
+ // It's a useful hook for setting up current UI values, and other things.
+
+ // In this case, we want the window from Cib to become our full browser window
+ [theWindow setFullBridge:YES];
+}
+
+- (int)numberOfRowsInTableView:(CPTableView)tableView
+{
+ return 700000;
+}
+
+- (id)tableView:(CPTableView)tableView objectValueForTableColumn:(CPTableColumn)tableColumn row:(int)row
+{
+ if ([tableColumn identifier] === "icons")
+ return iconImage;
+ else
+ return String((row + 1) * [[tableColumn identifier] intValue]);
+}
+
+@end
diff --git a/Tests/TableCibTest/Info.plist b/Tests/TableCibTest/Info.plist
new file mode 100644
index 000000000..f2ebe529d
--- /dev/null
+++ b/Tests/TableCibTest/Info.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ Main cib file base name
+ MainMenu.cib
+ CPBundleName
+ TableCibTest
+ CPPrincipalClass
+ CPApplication
+
+
diff --git a/Tests/TableCibTest/Rakefile b/Tests/TableCibTest/Rakefile
new file mode 100644
index 000000000..ead2456ce
--- /dev/null
+++ b/Tests/TableCibTest/Rakefile
@@ -0,0 +1,25 @@
+
+require 'objective-j'
+require 'objective-j/bundletask'
+
+if !ENV['CONFIG']
+ ENV['CONFIG'] = 'Debug'
+end
+
+ObjectiveJ::BundleTask.new(:TableCibTest) do |t|
+ t.name = 'TableCibTest'
+ t.identifier = 'com.280n.TableCibTest'
+ t.version = '1.0'
+ t.author = '280 North, Inc.'
+ t.email = 'feedback @nospam@ 280north.com'
+ t.summary = 'TableCibTest'
+ t.sources = FileList['*.j']
+ t.resources = FileList['Resources/*']
+ t.index_file = 'index.html'
+ t.info_plist = 'Info.plist'
+ t.build_path = File.join('Build', ENV['CONFIG'], 'TableCibTest')
+ t.flag = '-DDEBUG' if ENV['CONFIG'] == 'Debug'
+ t.flag = '-O' if ENV['CONFIG'] == 'Release'
+end
+
+task :default => [:TableCibTest]
diff --git a/Tests/TableCibTest/Resources/MainMenu.cib b/Tests/TableCibTest/Resources/MainMenu.cib
new file mode 100644
index 000000000..da5e6b7a9
--- /dev/null
+++ b/Tests/TableCibTest/Resources/MainMenu.cib
@@ -0,0 +1 @@
+280NPLIST;1.0;D;K;4;$topD;K;18;CPCibObjectDataKeyD;K;6;CP$UIDd;1;2E;E;K;8;$objectsA;S;5;$nullD;K;10;$classnameS;16;_CPCibObjectDataK;8;$classesA;S;16;_CPCibObjectDataS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;1E;K;28;_CPCibObjectDataNamesKeysKeyD;K;6;CP$UIDd;1;4E;K;30;_CPCibObjectDataNamesValuesKeyD;K;6;CP$UIDd;1;5E;K;30;_CPCibObjectDataClassesKeysKeyD;K;6;CP$UIDd;1;6E;K;32;_CPCibObjectDataClassesValuesKeyD;K;6;CP$UIDd;1;7E;K;30;_CPCibObjectDataConnectionsKeyD;K;6;CP$UIDd;1;8E;K;28;_CPCibObjectDataFrameworkKeyD;K;6;CP$UIDd;1;9E;K;26;_CPCibObjectDataNextOidKeyD;K;6;CP$UIDd;2;10E;K;30;_CPCibObjectDataObjectsKeysKeyD;K;6;CP$UIDd;2;11E;K;32;_CPCibObjectDataObjectsValuesKeyD;K;6;CP$UIDd;2;12E;K;26;_CPCibObjectDataOidKeysKeyD;K;6;CP$UIDd;2;13E;K;28;_CPCibObjectDataOidValuesKeyD;K;6;CP$UIDd;2;14E;K;28;_CPCibObjectDataFileOwnerKeyD;K;6;CP$UIDd;2;16E;K;33;_CPCibObjectDataVisibleWindowsKeyD;K;6;CP$UIDd;2;18E;E;D;K;10;$classnameS;7;CPArrayK;8;$classesA;S;7;CPArrayS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;28E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;57E;D;K;6;CP$UIDd;2;58E;D;K;6;CP$UIDd;2;59E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;62E;D;K;6;CP$UIDd;2;63E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;65E;D;K;6;CP$UIDd;2;66E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;67E;D;K;6;CP$UIDd;2;68E;D;K;6;CP$UIDd;2;69E;D;K;6;CP$UIDd;2;70E;D;K;6;CP$UIDd;2;71E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;74E;D;K;6;CP$UIDd;2;75E;D;K;6;CP$UIDd;2;76E;D;K;6;CP$UIDd;2;77E;D;K;6;CP$UIDd;2;78E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;80E;D;K;6;CP$UIDd;2;81E;D;K;6;CP$UIDd;2;82E;D;K;6;CP$UIDd;2;83E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;85E;D;K;6;CP$UIDd;2;86E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;88E;D;K;6;CP$UIDd;2;89E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;93E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;95E;D;K;6;CP$UIDd;2;96E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;2;98E;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;3;100E;D;K;6;CP$UIDd;3;101E;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;103E;D;K;6;CP$UIDd;3;104E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;106E;D;K;6;CP$UIDd;3;107E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;112E;D;K;6;CP$UIDd;3;113E;D;K;6;CP$UIDd;3;114E;D;K;6;CP$UIDd;3;115E;D;K;6;CP$UIDd;3;116E;D;K;6;CP$UIDd;3;117E;D;K;6;CP$UIDd;3;118E;D;K;6;CP$UIDd;3;119E;D;K;6;CP$UIDd;3;120E;D;K;6;CP$UIDd;3;121E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;3;122E;D;K;6;CP$UIDd;3;123E;D;K;6;CP$UIDd;3;124E;D;K;6;CP$UIDd;3;125E;D;K;6;CP$UIDd;3;126E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;3;128E;D;K;6;CP$UIDd;3;129E;D;K;6;CP$UIDd;3;130E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;3;131E;D;K;6;CP$UIDd;3;132E;D;K;6;CP$UIDd;3;133E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;3;134E;D;K;6;CP$UIDd;3;135E;D;K;6;CP$UIDd;3;136E;D;K;6;CP$UIDd;3;137E;D;K;6;CP$UIDd;3;138E;D;K;6;CP$UIDd;3;139E;D;K;6;CP$UIDd;3;140E;D;K;6;CP$UIDd;3;141E;D;K;6;CP$UIDd;3;142E;D;K;6;CP$UIDd;3;143E;D;K;6;CP$UIDd;3;144E;D;K;6;CP$UIDd;3;145E;D;K;6;CP$UIDd;3;146E;D;K;6;CP$UIDd;3;147E;D;K;6;CP$UIDd;3;148E;D;K;6;CP$UIDd;3;149E;D;K;6;CP$UIDd;3;150E;D;K;6;CP$UIDd;3;151E;D;K;6;CP$UIDd;3;152E;D;K;6;CP$UIDd;3;153E;D;K;6;CP$UIDd;3;154E;D;K;6;CP$UIDd;3;155E;D;K;6;CP$UIDd;3;156E;D;K;6;CP$UIDd;3;158E;D;K;6;CP$UIDd;3;159E;D;K;6;CP$UIDd;3;160E;D;K;6;CP$UIDd;3;161E;D;K;6;CP$UIDd;3;162E;D;K;6;CP$UIDd;3;163E;D;K;6;CP$UIDd;3;164E;D;K;6;CP$UIDd;3;165E;D;K;6;CP$UIDd;3;166E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;167E;D;K;6;CP$UIDd;3;168E;D;K;6;CP$UIDd;3;169E;D;K;6;CP$UIDd;3;170E;D;K;6;CP$UIDd;3;171E;D;K;6;CP$UIDd;3;172E;D;K;6;CP$UIDd;3;173E;D;K;6;CP$UIDd;3;174E;D;K;6;CP$UIDd;3;175E;D;K;6;CP$UIDd;3;176E;D;K;6;CP$UIDd;3;177E;D;K;6;CP$UIDd;3;178E;D;K;6;CP$UIDd;3;179E;D;K;6;CP$UIDd;3;180E;D;K;6;CP$UIDd;3;181E;D;K;6;CP$UIDd;3;182E;D;K;6;CP$UIDd;3;183E;D;K;6;CP$UIDd;3;184E;D;K;6;CP$UIDd;3;185E;D;K;6;CP$UIDd;3;186E;D;K;6;CP$UIDd;3;187E;D;K;6;CP$UIDd;3;188E;D;K;6;CP$UIDd;3;189E;D;K;6;CP$UIDd;3;190E;D;K;6;CP$UIDd;3;191E;D;K;6;CP$UIDd;3;192E;D;K;6;CP$UIDd;3;193E;D;K;6;CP$UIDd;3;194E;D;K;6;CP$UIDd;3;195E;D;K;6;CP$UIDd;3;196E;D;K;6;CP$UIDd;3;197E;D;K;6;CP$UIDd;3;198E;D;K;6;CP$UIDd;3;199E;D;K;6;CP$UIDd;3;200E;D;K;6;CP$UIDd;3;201E;D;K;6;CP$UIDd;3;202E;D;K;6;CP$UIDd;3;203E;D;K;6;CP$UIDd;3;204E;D;K;6;CP$UIDd;3;205E;D;K;6;CP$UIDd;3;206E;D;K;6;CP$UIDd;3;207E;D;K;6;CP$UIDd;3;208E;D;K;6;CP$UIDd;3;209E;D;K;6;CP$UIDd;3;210E;D;K;6;CP$UIDd;3;211E;D;K;6;CP$UIDd;3;212E;D;K;6;CP$UIDd;3;213E;D;K;6;CP$UIDd;3;214E;D;K;6;CP$UIDd;3;215E;D;K;6;CP$UIDd;3;216E;D;K;6;CP$UIDd;3;217E;D;K;6;CP$UIDd;3;218E;D;K;6;CP$UIDd;3;219E;D;K;6;CP$UIDd;3;220E;D;K;6;CP$UIDd;3;221E;D;K;6;CP$UIDd;3;222E;D;K;6;CP$UIDd;3;223E;D;K;6;CP$UIDd;3;224E;D;K;6;CP$UIDd;3;225E;D;K;6;CP$UIDd;3;226E;D;K;6;CP$UIDd;3;227E;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;229E;D;K;6;CP$UIDd;3;230E;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;232E;D;K;6;CP$UIDd;3;233E;D;K;6;CP$UIDd;3;234E;D;K;6;CP$UIDd;3;235E;D;K;6;CP$UIDd;3;236E;D;K;6;CP$UIDd;3;237E;D;K;6;CP$UIDd;3;238E;D;K;6;CP$UIDd;3;239E;D;K;6;CP$UIDd;3;240E;D;K;6;CP$UIDd;3;241E;D;K;6;CP$UIDd;3;242E;D;K;6;CP$UIDd;3;243E;D;K;6;CP$UIDd;3;244E;D;K;6;CP$UIDd;3;245E;D;K;6;CP$UIDd;3;246E;D;K;6;CP$UIDd;3;247E;D;K;6;CP$UIDd;3;248E;D;K;6;CP$UIDd;3;249E;D;K;6;CP$UIDd;3;250E;D;K;6;CP$UIDd;3;251E;D;K;6;CP$UIDd;3;252E;D;K;6;CP$UIDd;3;253E;D;K;6;CP$UIDd;3;254E;D;K;6;CP$UIDd;3;255E;D;K;6;CP$UIDd;3;256E;D;K;6;CP$UIDd;3;257E;D;K;6;CP$UIDd;3;258E;D;K;6;CP$UIDd;3;259E;D;K;6;CP$UIDd;3;260E;D;K;6;CP$UIDd;3;261E;D;K;6;CP$UIDd;3;262E;D;K;6;CP$UIDd;3;263E;D;K;6;CP$UIDd;3;264E;D;K;6;CP$UIDd;3;265E;D;K;6;CP$UIDd;3;266E;D;K;6;CP$UIDd;3;267E;D;K;6;CP$UIDd;3;268E;D;K;6;CP$UIDd;3;269E;D;K;6;CP$UIDd;3;270E;D;K;6;CP$UIDd;3;271E;D;K;6;CP$UIDd;3;272E;D;K;6;CP$UIDd;3;273E;D;K;6;CP$UIDd;3;274E;D;K;6;CP$UIDd;3;275E;D;K;6;CP$UIDd;3;276E;D;K;6;CP$UIDd;3;277E;D;K;6;CP$UIDd;3;278E;D;K;6;CP$UIDd;3;279E;D;K;6;CP$UIDd;3;280E;D;K;6;CP$UIDd;3;281E;D;K;6;CP$UIDd;3;282E;D;K;6;CP$UIDd;3;283E;D;K;6;CP$UIDd;3;284E;D;K;6;CP$UIDd;3;285E;D;K;6;CP$UIDd;3;286E;D;K;6;CP$UIDd;3;287E;D;K;6;CP$UIDd;3;288E;D;K;6;CP$UIDd;3;289E;D;K;6;CP$UIDd;3;290E;D;K;6;CP$UIDd;3;291E;D;K;6;CP$UIDd;3;292E;D;K;6;CP$UIDd;3;293E;D;K;6;CP$UIDd;3;294E;D;K;6;CP$UIDd;3;295E;D;K;6;CP$UIDd;3;296E;D;K;6;CP$UIDd;3;297E;D;K;6;CP$UIDd;3;298E;D;K;6;CP$UIDd;3;299E;D;K;6;CP$UIDd;3;300E;D;K;6;CP$UIDd;3;301E;D;K;6;CP$UIDd;3;302E;D;K;6;CP$UIDd;3;303E;D;K;6;CP$UIDd;3;304E;D;K;6;CP$UIDd;3;305E;D;K;6;CP$UIDd;3;306E;D;K;6;CP$UIDd;3;307E;D;K;6;CP$UIDd;3;308E;D;K;6;CP$UIDd;3;309E;D;K;6;CP$UIDd;3;310E;D;K;6;CP$UIDd;3;311E;D;K;6;CP$UIDd;3;312E;D;K;6;CP$UIDd;3;313E;D;K;6;CP$UIDd;3;314E;D;K;6;CP$UIDd;3;315E;D;K;6;CP$UIDd;3;316E;D;K;6;CP$UIDd;3;317E;D;K;6;CP$UIDd;3;318E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;320E;D;K;6;CP$UIDd;3;321E;D;K;6;CP$UIDd;3;322E;D;K;6;CP$UIDd;3;324E;D;K;6;CP$UIDd;3;325E;D;K;6;CP$UIDd;3;326E;D;K;6;CP$UIDd;3;327E;D;K;6;CP$UIDd;3;328E;D;K;6;CP$UIDd;3;329E;D;K;6;CP$UIDd;3;330E;D;K;6;CP$UIDd;3;331E;D;K;6;CP$UIDd;3;332E;D;K;6;CP$UIDd;3;333E;D;K;6;CP$UIDd;3;334E;D;K;6;CP$UIDd;3;335E;D;K;6;CP$UIDd;3;336E;D;K;6;CP$UIDd;3;337E;D;K;6;CP$UIDd;3;338E;D;K;6;CP$UIDd;3;339E;D;K;6;CP$UIDd;3;340E;D;K;6;CP$UIDd;3;341E;D;K;6;CP$UIDd;3;342E;D;K;6;CP$UIDd;3;343E;D;K;6;CP$UIDd;3;344E;D;K;6;CP$UIDd;3;345E;D;K;6;CP$UIDd;3;346E;D;K;6;CP$UIDd;3;347E;D;K;6;CP$UIDd;3;348E;D;K;6;CP$UIDd;3;349E;D;K;6;CP$UIDd;3;350E;D;K;6;CP$UIDd;3;351E;D;K;6;CP$UIDd;3;352E;D;K;6;CP$UIDd;3;353E;D;K;6;CP$UIDd;3;354E;D;K;6;CP$UIDd;3;355E;D;K;6;CP$UIDd;3;356E;D;K;6;CP$UIDd;3;357E;D;K;6;CP$UIDd;3;358E;D;K;6;CP$UIDd;3;359E;D;K;6;CP$UIDd;3;360E;D;K;6;CP$UIDd;3;361E;D;K;6;CP$UIDd;3;362E;D;K;6;CP$UIDd;3;363E;D;K;6;CP$UIDd;3;364E;D;K;6;CP$UIDd;3;365E;D;K;6;CP$UIDd;3;366E;D;K;6;CP$UIDd;3;367E;D;K;6;CP$UIDd;3;368E;D;K;6;CP$UIDd;3;369E;D;K;6;CP$UIDd;3;370E;D;K;6;CP$UIDd;3;371E;D;K;6;CP$UIDd;3;372E;D;K;6;CP$UIDd;3;373E;D;K;6;CP$UIDd;3;374E;D;K;6;CP$UIDd;3;375E;D;K;6;CP$UIDd;3;376E;D;K;6;CP$UIDd;3;377E;D;K;6;CP$UIDd;3;378E;D;K;6;CP$UIDd;3;379E;D;K;6;CP$UIDd;3;380E;D;K;6;CP$UIDd;3;381E;D;K;6;CP$UIDd;3;382E;D;K;6;CP$UIDd;3;383E;D;K;6;CP$UIDd;3;384E;E;E;S;16;IBCocoaFrameworkD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;28E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;57E;D;K;6;CP$UIDd;2;58E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;59E;D;K;6;CP$UIDd;2;62E;D;K;6;CP$UIDd;2;63E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;65E;D;K;6;CP$UIDd;2;66E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;67E;D;K;6;CP$UIDd;2;68E;D;K;6;CP$UIDd;2;69E;D;K;6;CP$UIDd;2;70E;D;K;6;CP$UIDd;2;71E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;74E;D;K;6;CP$UIDd;2;75E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;77E;D;K;6;CP$UIDd;2;78E;D;K;6;CP$UIDd;2;82E;D;K;6;CP$UIDd;2;80E;D;K;6;CP$UIDd;2;81E;D;K;6;CP$UIDd;2;83E;D;K;6;CP$UIDd;2;76E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;85E;D;K;6;CP$UIDd;2;86E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;88E;D;K;6;CP$UIDd;2;89E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;93E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;95E;D;K;6;CP$UIDd;2;96E;D;K;6;CP$UIDd;2;98E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;3;100E;D;K;6;CP$UIDd;3;101E;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;103E;D;K;6;CP$UIDd;3;106E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;104E;D;K;6;CP$UIDd;3;107E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;112E;D;K;6;CP$UIDd;3;113E;D;K;6;CP$UIDd;3;114E;D;K;6;CP$UIDd;3;115E;D;K;6;CP$UIDd;3;116E;D;K;6;CP$UIDd;3;117E;D;K;6;CP$UIDd;3;118E;D;K;6;CP$UIDd;3;119E;D;K;6;CP$UIDd;3;120E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;3;121E;D;K;6;CP$UIDd;3;122E;D;K;6;CP$UIDd;3;123E;D;K;6;CP$UIDd;3;124E;D;K;6;CP$UIDd;3;125E;D;K;6;CP$UIDd;3;126E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;3;128E;D;K;6;CP$UIDd;3;129E;D;K;6;CP$UIDd;3;130E;D;K;6;CP$UIDd;3;135E;D;K;6;CP$UIDd;3;131E;D;K;6;CP$UIDd;3;132E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;3;134E;D;K;6;CP$UIDd;3;133E;D;K;6;CP$UIDd;3;136E;D;K;6;CP$UIDd;3;137E;D;K;6;CP$UIDd;3;139E;D;K;6;CP$UIDd;3;138E;D;K;6;CP$UIDd;3;140E;D;K;6;CP$UIDd;3;145E;D;K;6;CP$UIDd;3;142E;D;K;6;CP$UIDd;3;143E;D;K;6;CP$UIDd;3;144E;D;K;6;CP$UIDd;3;141E;D;K;6;CP$UIDd;3;146E;D;K;6;CP$UIDd;3;147E;D;K;6;CP$UIDd;3;148E;D;K;6;CP$UIDd;3;149E;D;K;6;CP$UIDd;3;151E;D;K;6;CP$UIDd;3;150E;D;K;6;CP$UIDd;3;153E;D;K;6;CP$UIDd;3;152E;D;K;6;CP$UIDd;3;154E;D;K;6;CP$UIDd;3;155E;D;K;6;CP$UIDd;3;156E;D;K;6;CP$UIDd;3;158E;D;K;6;CP$UIDd;3;159E;D;K;6;CP$UIDd;3;160E;D;K;6;CP$UIDd;3;161E;D;K;6;CP$UIDd;3;162E;D;K;6;CP$UIDd;3;163E;D;K;6;CP$UIDd;3;164E;D;K;6;CP$UIDd;3;165E;D;K;6;CP$UIDd;3;166E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;161E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;158E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;2;62E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;89E;D;K;6;CP$UIDd;2;85E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;3;107E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;2;76E;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;135E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;3;137E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;62E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;3;135E;D;K;6;CP$UIDd;3;141E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;3;121E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;3;154E;D;K;6;CP$UIDd;3;137E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;3;143E;D;K;6;CP$UIDd;3;154E;D;K;6;CP$UIDd;3;160E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;3;148E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;3;142E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;95E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;66E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;3;114E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;3;104E;D;K;6;CP$UIDd;3;137E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;3;154E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;3;160E;D;K;6;CP$UIDd;3;122E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;114E;D;K;6;CP$UIDd;3;135E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;63E;D;K;6;CP$UIDd;2;62E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;67E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;59E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;3;138E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;135E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;3;150E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;3;154E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;68E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;3;114E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;3;136E;D;K;6;CP$UIDd;2;88E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;127E;D;K;6;CP$UIDd;3;137E;D;K;6;CP$UIDd;2;90E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;10;$classnameS;18;_CPCibCustomObjectK;8;$classesA;S;18;_CPCibCustomObjectS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;3;385E;E;D;K;10;$classnameS;5;CPSetK;8;$classesA;S;5;CPSetS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;17E;K;15;CPSetObjectsKeyD;K;6;CP$UIDd;3;386E;E;D;K;10;$classnameS;10;CPMenuItemK;8;$classesA;S;10;CPMenuItemS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;387E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;161E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;388E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;10;$classnameS;10;CPScrollerK;8;$classesA;S;10;CPScrollerS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;22E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;62E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;389E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;390E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;62E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;391E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;392E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;393E;K;18;CPControlTargetKeyD;K;6;CP$UIDd;2;62E;K;18;CPControlActionKeyD;K;6;CP$UIDd;3;394E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;395E;K;21;CPScrollerControlSizeD;K;6;CP$UIDd;3;393E;K;24;CPScrollerKnobProportionD;K;6;CP$UIDd;3;396E;E;D;K;10;$classnameS;6;CPMenuK;8;$classesA;S;6;CPMenuS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;397E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;398E;E;D;K;10;$classnameS;6;CPViewK;8;$classesA;S;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;26E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;399E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;399E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;400E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;392E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;404E;K;13;CPMenuNameKeyD;K;6;CP$UIDd;3;405E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;406E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;407E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;408E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;409E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;410E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;411E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;30E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;3;385E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;412E;K;13;CPMenuNameKeyD;K;6;CP$UIDd;3;413E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;414E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;415E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;416E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;135E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;417E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;418E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;137E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;419E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;90E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;420E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;79E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;421E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;422E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;417E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;2;38E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;424E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;79E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;425E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;426E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;79E;E;D;K;10;$classnameS;13;CPTableColumnK;8;$classesA;S;13;CPTableColumnS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;241E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;427E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;429E;E;D;K;10;$classnameS;11;CPTableViewK;8;$classesA;S;11;CPTableViewS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;50E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;3;430E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;431E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;431E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;3;430E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;392E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;395E;K;24;CPTableViewDataSourceKeyD;K;6;CP$UIDd;1;0E;K;22;CPTableViewDelegateKeyD;K;6;CP$UIDd;1;0E;K;23;CPTableViewRowHeightKeyD;K;6;CP$UIDd;3;432E;K;30;CPTableViewIntercellSpacingKeyD;K;6;CP$UIDd;3;433E;K;31;CPTableViewMultipleSelectionKeyD;K;6;CP$UIDd;3;403E;K;28;CPTableViewEmptySelectionKeyD;K;6;CP$UIDd;3;401E;K;26;CPTableViewTableColumnsKeyD;K;6;CP$UIDd;3;434E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;435E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;436E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;135E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;437E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;2;56E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;35E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;437E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;438E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;439E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;79E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;316E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;427E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;429E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;440E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;427E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;429E;E;D;K;10;$classnameS;12;CPScrollViewK;8;$classesA;S;12;CPScrollViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;61E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;27E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;441E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;442E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;443E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;27E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;444E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;392E;K;23;CPScrollViewContentViewD;K;6;CP$UIDd;3;430E;K;21;CPScrollViewVScrollerD;K;6;CP$UIDd;3;128E;K;21;CPScrollViewHScrollerD;K;6;CP$UIDd;2;23E;K;23;CPScrollViewVLineScrollD;K;6;CP$UIDd;3;428E;K;23;CPScrollViewVPageScrollD;K;6;CP$UIDd;3;428E;K;23;CPScrollViewHLineScrollD;K;6;CP$UIDd;3;428E;K;23;CPScrollViewHPageScrollD;K;6;CP$UIDd;3;428E;K;24;CPScrollViewHasVScrollerD;K;6;CP$UIDd;3;401E;K;24;CPScrollViewHasHScrollerD;K;6;CP$UIDd;3;401E;K;29;CPScrollViewAutohidesScrollerD;K;6;CP$UIDd;3;403E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;446E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;127E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;35E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;447E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;38E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;448E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;449E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;105E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;35E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;450E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;135E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;451E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;154E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;452E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;453E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;454E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;455E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;154E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;456E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;137E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;457E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;38E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;246E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;427E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;429E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;458E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;154E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;459E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;160E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;460E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;461E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;462E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;463E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;464E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;30E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;465E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;90E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;466E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;79E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;407E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;2;30E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;467E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;148E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;468E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;469E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;161E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;404E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;2;29E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;56E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;470E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;471E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;472E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;473E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;474E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;475E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;103E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;476E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;470E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;2;90E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;477E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;90E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;478E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;38E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;479E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;480E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;25E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;475E;K;13;CPMenuNameKeyD;K;6;CP$UIDd;3;481E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;482E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;483E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;114E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;449E;K;13;CPMenuNameKeyD;K;6;CP$UIDd;3;484E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;485E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;486E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;25E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;251E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;429E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;182E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;427E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;429E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;237E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;427E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;429E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;397E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;2;25E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;204E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;427E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;429E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;487E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;114E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;488E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;483E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;489E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;490E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;137E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;491E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;79E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;492E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;154E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;493E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;79E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;494E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;160E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;301E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;427E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;428E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;429E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;303E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;495E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;496E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;497E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;416E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;114E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;498E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;135E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;499E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;446E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;500E;E;D;K;6;$classD;K;6;CP$UIDd;2;22E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;62E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;501E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;502E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;62E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;391E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;503E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;393E;K;18;CPControlTargetKeyD;K;6;CP$UIDd;2;62E;K;18;CPControlActionKeyD;K;6;CP$UIDd;3;504E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;395E;K;21;CPScrollerControlSizeD;K;6;CP$UIDd;3;393E;K;24;CPScrollerKnobProportionD;K;6;CP$UIDd;3;505E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;506E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;507E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;508E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;30E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;3;509E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;510E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;450E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;511E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;512E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;160E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;35E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;513E;K;13;CPMenuNameKeyD;K;6;CP$UIDd;3;514E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;515E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;513E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;137E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;35E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;516E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;48E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;517E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;518E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;496E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;497E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;473E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;2;92E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;35E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;460E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;2;79E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;56E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;519E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;30E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;419E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;135E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;520E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;521E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;30E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;522E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;523E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;522E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;423E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;20;CPMenuItemSubmenuKeyD;K;6;CP$UIDd;3;148E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;35E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;524E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;154E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;525E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;79E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;526E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;90E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;451E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;527E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;528E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;419E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;114E;E;D;K;10;$classnameS;20;_CPCibWindowTemplateK;8;$classesA;S;20;_CPCibWindowTemplateS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;157E;K;30;_CPCibWindowTemplateMaxSizeKeyD;K;6;CP$UIDd;3;529E;K;32;_CPCibWindowTemplateViewClassKeyD;K;6;CP$UIDd;1;0E;K;34;_CPCibWindowTemplateWindowClassKeyD;K;6;CP$UIDd;3;530E;K;33;_CPCibWindowTemplateWindowRectKeyD;K;6;CP$UIDd;3;531E;K;30;_CPCibWindowTempatStyleMaskKeyD;K;6;CP$UIDd;3;532E;K;34;_CPCibWindowTemplateWindowTitleKeyD;K;6;CP$UIDd;3;513E;K;33;_CPCibWindowTemplateWindowViewKeyD;K;6;CP$UIDd;2;27E;K;41;_CPCibWindowTemplateWindowIsFullBridgeKeyD;K;6;CP$UIDd;3;403E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;533E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;512E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;534E;E;D;K;6;$classD;K;6;CP$UIDd;2;24E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;469E;K;13;CPMenuNameKeyD;K;6;CP$UIDd;3;535E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;536E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;537E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;24;CPMenuItemIsSeparatorKeyD;K;6;CP$UIDd;3;401E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;402E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;22;CPMenuItemIsEnabledKeyD;K;6;CP$UIDd;3;403E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;538E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;127E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;539E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;3;137E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;540E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;1;0E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;1;0E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;90E;E;S;22;Menu Item (Clear Menu)S;32;Menu Item (About NewApplication)S;19;Horizontal ScrollerS;13;Menu (Speech)S;12;Content ViewS;11;Separator-7S;27;Text Field Cell (Text Cell)S;11;Menu (Font)S;11;Menu (Find)S;22;Menu Item (Copy Style)S;29;Text Field Cell (Text Cell)-4S;21;Menu Item (Underline)S;34;Menu Item (Use Selection for Find)S;11;ApplicationS;8;MainMenuS;1;9S;29;Text Field Cell (Text Cell)-3S;29;Text Field Cell (Text Cell)-5S;29;Text Field Cell (Text Cell)-6S;29;Text Field Cell (Text Cell)-7S;20;Menu Item (Use None)S;20;Menu (Substitutions)S;11;Separator-4S;25;Menu Item (Use Default)-1S;18;Menu Item (Center)S;19;Menu Item (Smaller)S;31;Menu Item (Hide NewApplication)S;25;Menu Item (Substitutions)S;12;File's OwnerS;23;Menu Item (Align Right)S;20;Menu Item (Show All)S;22;Menu Item (Show Ruler)S;16;Table Column (3)S;10;Table ViewS;3;121S;19;Menu Item (Tighten)S;30;Text Field Cell (Text Cell)-10S;1;7S;18;Menu Item (Format)S;13;Menu (Format)S;22;Menu Item (Align Left)S;11;Separator-5S;16;Table Column (5)S;16;Table Column (4)S;33;Bordered Scroll View (Table View)S;16;Menu Item (File)S;24;Menu Item (Smart Quotes)S;16;Menu Item (Copy)S;26;Menu Item (NewApplication)S;29;Text Field Cell (Text Cell)-8S;16;Menu Item (Kern)S;32;Menu Item (Spelling and Grammar)S;23;Menu Item (Paste Style)S;18;Menu Item (Italic)S;22;Menu Item (Show Fonts)S;26;Menu Item (Show Spelling…)S;20;Menu Item (Minimize)S;9;SeparatorS;23;Menu Item (Smart Links)S;16;Table Column (6)S;26;Menu Item (Check Spelling)S;30;Menu Item (Customize Toolbar…)S;11;Menu (Text)S;4;1111S;22;Menu Item (Select All)S;25;Menu Item (Find Previous)S;17;Menu Item (Raise)S;22;Menu Item (Copy Ruler)S;16;Menu Item (Find)S;31;Menu Item (NewApplication Help)S;1;8S;23;Menu Item (Open Recent)S;16;Menu Item (Font)S;15;Menu (Baseline)S;1;3S;11;Menu (Edit)S;3;2-1S;11;Separator-8S;20;Menu Item (Services)S;1;6S;20;Menu Item (Baseline)S;21;Menu Item (Subscript)S;28;Menu Item (Smart Copy/Paste)S;11;Separator-9S;2;10S;26;Menu Item (Start Speaking)S;15;Menu (Services)S;20;Menu Item (Ligature)S;21;Menu (NewApplication)S;25;Menu Item (Stop Speaking)S;17;Table Column (10)S;16;Table Column (9)S;16;Table Column (8)S;18;Menu Item (Speech)S;16;Table Column (7)S;19;Menu Item (Use All)S;17;Menu Item (Open…)S;15;Menu (Ligature)S;30;Menu Item (Bring All to Front)S;19;Menu Item (Justify)S;39;Menu Item (Check Grammar With Spelling)S;23;Menu Item (Hide Others)S;12;Separator-11S;24;Menu Item (Show Toolbar)S;16;Table Column (2)S;29;Text Field Cell (Text Cell)-9S;16;Table Column (1)S;11;Separator-1S;22;Menu Item (Use None)-1S;18;Menu Item (Loosen)S;17;Menu Item (Paste)S;11;Menu (File)S;17;Vertical ScrollerS;15;Menu Item (Cut)S;12;Separator-10S;29;Text Field Cell (Text Cell)-1S;16;Menu Item (Undo)S;29;Menu Item (Jump to Selection)S;14;App ControllerS;29;Text Field Cell (Text Cell)-2S;18;Menu Item (Bigger)S;11;Menu (Kern)S;16;Menu Item (View)S;13;Menu (Window)S;18;Menu Item (Window)S;16;Menu Item (Bold)S;11;Separator-2S;16;Table Column (0)S;16;Menu Item (Edit)S;16;Menu Item (Text)S;17;Menu Item (Find…)S;23;Menu Item (Use Default)S;18;Menu Item (Delete)S;21;Menu Item (Find Next)S;1;2S;11;Separator-6S;1;1S;39;Menu Item (Check Spelling While Typing)S;23;Menu Item (Paste Ruler)S;17;Menu Item (Lower)S;27;Menu (Spelling and Grammar)S;16;Menu Item (Redo)S;25;Menu Item (Use Default)-2S;15;Window (Window)S;3;1-1S;11;Menu (View)S;18;Menu (Open Recent)S;23;Menu Item (Show Colors)S;11;Separator-3S;1;5S;16;Menu Item (Zoom)S;23;Menu Item (Superscript)D;K;10;$classnameS;20;CPCibOutletConnectorK;8;$classesA;S;20;CPCibOutletConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;319E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;16E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;3;133E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;541E;E;D;K;6;$classD;K;6;CP$UIDd;3;319E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;133E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;3;158E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;542E;E;D;K;6;$classD;K;6;CP$UIDd;3;319E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;51E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;3;133E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;543E;E;D;K;10;$classnameS;21;CPCibControlConnectorK;8;$classesA;S;21;CPCibControlConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;115E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;544E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;73E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;545E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;21E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;16E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;546E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;113E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;547E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;159E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;548E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;91E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;549E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;164E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;550E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;96E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;551E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;87E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;552E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;36E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;553E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;86E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;554E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;101E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;555E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;20E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;556E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;43E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;557E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;80E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;34E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;558E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;118E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;559E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;46E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;560E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;106E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;561E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;102E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;562E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;65E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;563E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;81E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;564E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;129E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;565E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;77E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;566E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;146E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;567E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;126E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;568E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;72E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;569E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;131E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;570E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;144E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;571E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;132E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;572E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;155E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;573E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;151E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;574E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;165E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;575E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;120E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;576E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;78E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;577E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;117E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;578E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;99E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;579E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;64E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;580E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;75E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;581E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;57E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;582E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;41E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;583E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;116E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;584E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;45E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;585E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;47E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;586E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;84E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;587E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;152E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;588E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;32E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;589E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;162E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;590E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;31E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;591E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;69E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;592E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;40E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;593E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;166E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;594E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;98E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;595E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;83E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;596E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;153E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;597E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;156E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;598E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;124E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;599E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;112E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;600E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;145E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;601E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;37E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;602E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;53E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;603E;E;D;K;6;$classD;K;6;CP$UIDd;3;323E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;3;125E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;1;0E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;604E;E;S;13;CPApplicationD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;158E;E;E;S;10;Clear MenuS;20;About NewApplicationS;19;{{1, 1}, {476, 15}}S;19;{{0, 0}, {476, 15}}d;1;8S;6;normald;1;0S;29;_horizontalScrollerDidScroll:d;1;4f;18;0.6888567293777135S;6;SpeechD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;106E;E;E;S;20;{{0, 0}, {491, 363}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;62E;E;E;T;S;0;F;S;4;FontS;11;_CPFontMenuD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;71E;D;K;6;CP$UIDd;3;139E;D;K;6;CP$UIDd;2;70E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;28E;D;K;6;CP$UIDd;3;134E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;3;130E;D;K;6;CP$UIDd;2;67E;D;K;6;CP$UIDd;3;104E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;3;100E;D;K;6;CP$UIDd;3;162E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;69E;E;E;S;4;FindD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;144E;D;K;6;CP$UIDd;3;147E;D;K;6;CP$UIDd;2;82E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;3;132E;E;E;S;10;Copy StyleS;9;UnderlineS;22;Use Selection for FindS;9;AMainMenuS;11;_CPMainMenuD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;66E;D;K;6;CP$UIDd;2;63E;D;K;6;CP$UIDd;3;142E;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;3;136E;D;K;6;CP$UIDd;3;138E;D;K;6;CP$UIDd;3;150E;E;E;S;3;NewS;8;Use NoneS;13;SubstitutionsD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;75E;E;E;S;11;Use DefaultS;6;CenterS;7;SmallerS;19;Hide NewApplicationS;14;submenuAction:S;11;Align RightS;8;Show AllS;10;Show Rulerd;2;64d;2;10d;12;3.402823e+38D;K;6;$classD;K;6;CP$UIDd;3;445E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;62E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;605E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;606E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;607E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;62E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;391E;K;21;CPViewBackgroundColorD;K;6;CP$UIDd;3;609E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;392E;K;24;CPScrollViewDocumentViewD;K;6;CP$UIDd;2;51E;E;S;20;{{0, 0}, {691, 348}}d;2;17S;6;{3, 2}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;141E;D;K;6;CP$UIDd;3;122E;D;K;6;CP$UIDd;3;121E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;59E;D;K;6;CP$UIDd;2;76E;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;107E;E;E;S;12;Preferences…S;7;TightenS;6;FormatD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;89E;D;K;6;CP$UIDd;3;143E;E;E;S;10;Align LeftS;1;4S;22;{{-1, -1}, {493, 365}}S;20;{{0, 0}, {493, 365}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;430E;D;K;6;CP$UIDd;3;128E;D;K;6;CP$UIDd;2;23E;E;E;d;2;18D;K;10;$classnameS;10;CPClipViewK;8;$classesA;S;10;CPClipViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;S;4;FileS;12;Smart QuotesS;4;CopyS;14;NewApplicationS;4;KernS;20;Spelling and GrammarS;11;Paste StyleS;6;ItalicS;10;Show FontsS;14;Show Spelling…S;8;MinimizeS;11;Smart LinksS;14;Check SpellingS;18;Customize Toolbar…S;4;TextD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;57E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;3;116E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;3;119E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;3;152E;E;E;S;19;Quit NewApplicationS;10;Select AllS;13;Find PreviousS;5;RaiseS;10;Copy RulerS;19;NewApplication HelpS;8;Save As…S;11;Open RecentS;8;BaselineD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;3;166E;D;K;6;CP$UIDd;2;98E;D;K;6;CP$UIDd;2;83E;D;K;6;CP$UIDd;3;153E;E;E;S;4;SaveS;4;EditD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;131E;D;K;6;CP$UIDd;3;155E;D;K;6;CP$UIDd;2;58E;D;K;6;CP$UIDd;3;129E;D;K;6;CP$UIDd;2;65E;D;K;6;CP$UIDd;3;126E;D;K;6;CP$UIDd;3;146E;D;K;6;CP$UIDd;2;81E;D;K;6;CP$UIDd;3;149E;D;K;6;CP$UIDd;2;85E;D;K;6;CP$UIDd;2;68E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;3;110E;E;E;S;8;ServicesS;6;Print…S;9;SubscriptS;16;Smart Copy/PasteS;15;Revert to SavedS;14;Start SpeakingS;15;_CPServicesMenuD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;S;8;LigatureS;18;_CPApplicationMenuD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;74E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;3;163E;D;K;6;CP$UIDd;2;95E;D;K;6;CP$UIDd;3;123E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;3;118E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;3;140E;D;K;6;CP$UIDd;2;80E;E;E;S;13;Stop SpeakingS;7;Use AllS;5;Open…D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;156E;D;K;6;CP$UIDd;3;124E;D;K;6;CP$UIDd;3;112E;E;E;S;18;Bring All to FrontS;7;JustifyS;27;Check Grammar With SpellingS;11;Hide OthersS;12;Show Toolbard;2;67d;2;40d;4;1000S;6;LoosenS;5;PasteD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;3;113E;D;K;6;CP$UIDd;2;88E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;3;159E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;3;101E;D;K;6;CP$UIDd;2;93E;D;K;6;CP$UIDd;3;164E;D;K;6;CP$UIDd;2;96E;E;E;S;22;{{477, 16}, {15, 348}}S;19;{{0, 0}, {15, 348}}S;17;disabled+verticalS;27;_verticalScrollerDidScroll:f;9;0.9971429S;3;CutS;4;UndoS;17;Jump to SelectionS;13;AppControllerS;6;BiggerD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;145E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;3;125E;E;E;S;4;ViewS;6;WindowS;14;_CPWindowsMenuD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;3;165E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;3;115E;E;E;S;4;BoldS;1;0d;2;69S;5;Find…S;6;DeleteS;9;Find NextS;4;HelpD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;86E;E;E;S;27;Check Spelling While TypingS;11;Paste RulerS;5;LowerD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;77E;D;K;6;CP$UIDd;3;151E;D;K;6;CP$UIDd;3;117E;E;E;S;4;RedoS;28;{1.79769e+308, 1.79769e+308}S;8;CPWindowS;24;{{335, 128}, {491, 363}}d;1;7S;5;CloseD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;120E;D;K;6;CP$UIDd;2;78E;E;E;S;22;_CPRecentDocumentsMenuD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;20E;E;E;S;11;Show ColorsS;13;Page Setup...S;4;ZoomS;11;SuperscriptS;8;delegateS;9;theWindowS;10;dataSourceS;15;arrangeInFront:S;19;performMiniaturize:S;29;orderFrontStandardAboutPanel:S;13;openDocument:S;13;performClose:S;13;saveDocument:S;14;runPageLayout:S;6;print:S;15;saveDocumentAs:S;12;newDocument:S;9;showHelp:S;22;revertDocumentToSaved:S;21;clearRecentDocuments:S;5;hide:S;10;terminate:S;22;hideOtherApplications:S;22;unhideAllApplications:S;13;stopSpeaking:S;14;startSpeaking:S;5;copy:S;10;selectAll:S;4;cut:S;14;checkSpelling:S;7;delete:S;6;paste:S;15;showGuessPanel:S;5;undo:S;23;performFindPanelAction:S;29;centerSelectionInVisibleArea:S;5;redo:S;30;toggleContinuousSpellChecking:S;12;performZoom:S;19;toggleToolbarShown:S;31;runToolbarCustomizationPalette:S;22;toggleGrammarChecking:S;24;toggleSmartInsertDelete:S;33;toggleAutomaticQuoteSubstitution:S;29;toggleAutomaticLinkDetection:S;10;alignLeft:S;12;alignCenter:S;15;alignJustified:S;11;alignRight:S;12;toggleRuler:S;10;copyRuler:S;11;pasteRuler:S;10;underline:S;21;orderFrontColorPanel:S;9;copyFont:S;10;pasteFont:S;9;unscript:S;12;superscript:S;10;subscript:S;14;raiseBaseline:S;14;lowerBaseline:S;21;useStandardLigatures:S;17;turnOffLigatures:S;16;useAllLigatures:S;19;useStandardKerning:S;15;turnOffKerning:S;15;tightenKerning:S;14;loosenKerning:S;21;{{1, 16}, {476, 348}}S;20;{{0, 0}, {476, 348}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;51E;E;E;D;K;10;$classnameS;7;CPColorK;8;$classesA;S;7;CPColorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;608E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;610E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;611E;D;K;6;CP$UIDd;3;611E;D;K;6;CP$UIDd;3;611E;D;K;6;CP$UIDd;3;611E;E;E;d;1;1E;K;9;$archiverS;15;CPKeyedArchiverK;8;$versionS;6;100000E;
\ No newline at end of file
diff --git a/Tests/TableCibTest/Resources/MainMenu.xib b/Tests/TableCibTest/Resources/MainMenu.xib
new file mode 100644
index 000000000..69234c332
--- /dev/null
+++ b/Tests/TableCibTest/Resources/MainMenu.xib
@@ -0,0 +1,3712 @@
+
+
+
+ 1050
+ 9J61
+ 677
+ 949.46
+ 353.00
+
+
+
+
+ YES
+
+ NSApplication
+
+
+ FirstResponder
+
+
+ NSApplication
+
+
+ AMainMenu
+
+ YES
+
+
+ NewApplication
+
+ 1048576
+ 2147483647
+
+ NSImage
+ NSMenuCheckmark
+
+
+ NSImage
+ NSMenuMixedState
+
+ submenuAction:
+
+ NewApplication
+
+ YES
+
+
+ About NewApplication
+
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ UHJlZmVyZW5jZXPigKY
+ ,
+ 1048576
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Services
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ Services
+
+ YES
+
+ _NSServicesMenu
+
+
+
+
+ YES
+ YES
+
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Hide NewApplication
+ h
+ 1048576
+ 2147483647
+
+
+
+
+
+ Hide Others
+ h
+ 1572864
+ 2147483647
+
+
+
+
+
+ Show All
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Quit NewApplication
+ q
+ 1048576
+ 2147483647
+
+
+
+
+ _NSAppleMenu
+
+
+
+
+ File
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ File
+
+ YES
+
+
+ New
+ n
+ 1048576
+ 2147483647
+
+
+
+
+
+ T3BlbuKApg
+ o
+ 1048576
+ 2147483647
+
+
+
+
+
+ Open Recent
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ Open Recent
+
+ YES
+
+
+ Clear Menu
+
+ 1048576
+ 2147483647
+
+
+
+
+ _NSRecentDocumentsMenu
+
+
+
+
+ YES
+ YES
+
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Close
+ w
+ 1048576
+ 2147483647
+
+
+
+
+
+ Save
+ s
+ 1048576
+ 2147483647
+
+
+
+
+
+ U2F2ZSBBc+KApg
+ S
+ 1179648
+ 2147483647
+
+
+
+
+
+ Revert to Saved
+
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Page Setup...
+ P
+ 1179648
+ 2147483647
+
+
+
+
+
+
+ UHJpbnTigKY
+ p
+ 1048576
+ 2147483647
+
+
+
+
+
+
+
+
+ Edit
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ Edit
+
+ YES
+
+
+ Undo
+ z
+ 1048576
+ 2147483647
+
+
+
+
+
+ Redo
+ Z
+ 1179648
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Cut
+ x
+ 1048576
+ 2147483647
+
+
+
+
+
+ Copy
+ c
+ 1048576
+ 2147483647
+
+
+
+
+
+ Paste
+ v
+ 1048576
+ 2147483647
+
+
+
+
+
+ Delete
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Select All
+ a
+ 1048576
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Find
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ Find
+
+ YES
+
+
+ RmluZOKApg
+ f
+ 1048576
+ 2147483647
+
+
+ 1
+
+
+
+ Find Next
+ g
+ 1048576
+ 2147483647
+
+
+ 2
+
+
+
+ Find Previous
+ G
+ 1179648
+ 2147483647
+
+
+ 3
+
+
+
+ Use Selection for Find
+ e
+ 1048576
+ 2147483647
+
+
+ 7
+
+
+
+ Jump to Selection
+ j
+ 1048576
+ 2147483647
+
+
+
+
+
+
+
+
+ Spelling and Grammar
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ Spelling and Grammar
+
+ YES
+
+
+ U2hvdyBTcGVsbGluZ+KApg
+ :
+ 1048576
+ 2147483647
+
+
+
+
+
+ Check Spelling
+ ;
+ 1048576
+ 2147483647
+
+
+
+
+
+ Check Spelling While Typing
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Check Grammar With Spelling
+
+ 1048576
+ 2147483647
+
+
+
+
+
+
+
+
+ Substitutions
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ Substitutions
+
+ YES
+
+
+ Smart Copy/Paste
+ f
+ 1048576
+ 2147483647
+
+
+ 1
+
+
+
+ Smart Quotes
+ g
+ 1048576
+ 2147483647
+
+
+ 2
+
+
+
+ Smart Links
+ G
+ 1179648
+ 2147483647
+
+
+ 3
+
+
+
+
+
+
+ Speech
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ Speech
+
+ YES
+
+
+ Start Speaking
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Stop Speaking
+
+ 1048576
+ 2147483647
+
+
+
+
+
+
+
+
+
+
+
+ Format
+
+ 2147483647
+
+
+ submenuAction:
+
+ Format
+
+ YES
+
+
+ Font
+
+ 2147483647
+
+
+ submenuAction:
+
+ Font
+
+ YES
+
+
+ Show Fonts
+ t
+ 1048576
+ 2147483647
+
+
+
+
+
+ Bold
+ b
+ 1048576
+ 2147483647
+
+
+ 2
+
+
+
+ Italic
+ i
+ 1048576
+ 2147483647
+
+
+ 1
+
+
+
+ Underline
+ u
+ 1048576
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 2147483647
+
+
+
+
+
+ Bigger
+ +
+ 1048576
+ 2147483647
+
+
+ 3
+
+
+
+ Smaller
+ -
+ 1048576
+ 2147483647
+
+
+ 4
+
+
+
+ YES
+ YES
+
+
+ 2147483647
+
+
+
+
+
+ Kern
+
+ 2147483647
+
+
+ submenuAction:
+
+ Kern
+
+ YES
+
+
+ Use Default
+
+ 2147483647
+
+
+
+
+
+ Use None
+
+ 2147483647
+
+
+
+
+
+ Tighten
+
+ 2147483647
+
+
+
+
+
+ Loosen
+
+ 2147483647
+
+
+
+
+
+
+
+
+ Ligature
+
+ 2147483647
+
+
+ submenuAction:
+
+ Ligature
+
+ YES
+
+
+ Use Default
+
+ 2147483647
+
+
+
+
+
+ Use None
+
+ 2147483647
+
+
+
+
+
+ Use All
+
+ 2147483647
+
+
+
+
+
+
+
+
+ Baseline
+
+ 2147483647
+
+
+ submenuAction:
+
+ Baseline
+
+ YES
+
+
+ Use Default
+
+ 2147483647
+
+
+
+
+
+ Superscript
+
+ 2147483647
+
+
+
+
+
+ Subscript
+
+ 2147483647
+
+
+
+
+
+ Raise
+
+ 2147483647
+
+
+
+
+
+ Lower
+
+ 2147483647
+
+
+
+
+
+
+
+
+ YES
+ YES
+
+
+ 2147483647
+
+
+
+
+
+ Show Colors
+ C
+ 1048576
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 2147483647
+
+
+
+
+
+ Copy Style
+ c
+ 1572864
+ 2147483647
+
+
+
+
+
+ Paste Style
+ v
+ 1572864
+ 2147483647
+
+
+
+
+ _NSFontMenu
+
+
+
+
+ Text
+
+ 2147483647
+
+
+ submenuAction:
+
+ Text
+
+ YES
+
+
+ Align Left
+ {
+ 1048576
+ 2147483647
+
+
+
+
+
+ Center
+ |
+ 1048576
+ 2147483647
+
+
+
+
+
+ Justify
+
+ 2147483647
+
+
+
+
+
+ Align Right
+ }
+ 1048576
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 2147483647
+
+
+
+
+
+ Show Ruler
+
+ 2147483647
+
+
+
+
+
+ Copy Ruler
+ c
+ 1310720
+ 2147483647
+
+
+
+
+
+ Paste Ruler
+ v
+ 1310720
+ 2147483647
+
+
+
+
+
+
+
+
+
+
+
+ View
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ View
+
+ YES
+
+
+ Show Toolbar
+ t
+ 1572864
+ 2147483647
+
+
+
+
+
+ Q3VzdG9taXplIFRvb2xiYXLigKY
+
+ 1048576
+ 2147483647
+
+
+
+
+
+
+
+
+ Window
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ Window
+
+ YES
+
+
+ Minimize
+ m
+ 1048576
+ 2147483647
+
+
+
+
+
+ Zoom
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ YES
+ YES
+
+
+ 1048576
+ 2147483647
+
+
+
+
+
+ Bring All to Front
+
+ 1048576
+ 2147483647
+
+
+
+
+ _NSWindowsMenu
+
+
+
+
+ Help
+
+ 1048576
+ 2147483647
+
+
+ submenuAction:
+
+ Help
+
+ YES
+
+
+ NewApplication Help
+ ?
+ 1048576
+ 2147483647
+
+
+
+
+
+
+
+ _NSMainMenu
+
+
+ 7
+ 2
+ {{335, 387}, {491, 363}}
+ 1946157056
+ Window
+ NSWindow
+
+ {3.40282e+38, 3.40282e+38}
+
+
+ 256
+
+ YES
+
+
+ 274
+
+ YES
+
+
+ 2304
+
+ YES
+
+
+ 256
+ {691, 348}
+
+ YES
+
+
+ 256
+ {{477, 0}, {16, 17}}
+
+
+ YES
+
+ 0
+ 6.900000e+01
+ 4.000000e+01
+ 1.000000e+03
+
+ 75628032
+ 0
+
+
+ LucidaGrande
+ 1.100000e+01
+ 3100
+
+
+ 3
+ MC4zMzMzMzI5OQA
+
+
+ 6
+ System
+ headerTextColor
+
+ 3
+ MAA
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+ LucidaGrande
+ 1.300000e+01
+ 1044
+
+
+
+ 6
+ System
+ controlBackgroundColor
+
+ 3
+ MC42NjY2NjY2OQA
+
+
+
+ 6
+ System
+ controlTextColor
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 1
+ 6.700000e+01
+ 4.000000e+01
+ 1.000000e+03
+
+ 75628032
+ 0
+
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 2
+ 6.400000e+01
+ 1.000000e+01
+ 3.402823e+38
+
+ 75628032
+ 0
+
+
+
+ 6
+ System
+ headerColor
+
+ 3
+ MQA
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 3
+ 6.400000e+01
+ 1.000000e+01
+ 3.402823e+38
+
+ 75628032
+ 0
+
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 4
+ 6.400000e+01
+ 1.000000e+01
+ 3.402823e+38
+
+ 75628032
+ 0
+
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 5
+ 6.400000e+01
+ 1.000000e+01
+ 3.402823e+38
+
+ 75628032
+ 0
+
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 6
+ 6.400000e+01
+ 1.000000e+01
+ 3.402823e+38
+
+ 75628032
+ 0
+
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 7
+ 6.400000e+01
+ 1.000000e+01
+ 3.402823e+38
+
+ 75628032
+ 0
+
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 8
+ 6.400000e+01
+ 1.000000e+01
+ 3.402823e+38
+
+ 75628032
+ 0
+
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 9
+ 6.400000e+01
+ 1.000000e+01
+ 3.402823e+38
+
+ 75628032
+ 0
+
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 10
+ 1.000000e+01
+ 1.000000e+01
+ 3.402823e+38
+
+ 75628032
+ 0
+
+
+
+
+
+
+ 337772096
+ 2048
+ Text Cell
+
+
+
+
+
+ 3
+ YES
+ YES
+
+
+
+ 3.000000e+00
+ 2.000000e+00
+
+
+ 6
+ System
+ gridColor
+
+ 3
+ MC41AA
+
+
+ 1.700000e+01
+ -698351616
+ 4
+ 15
+ 0
+ YES
+
+
+ {{1, 1}, {476, 348}}
+
+
+
+
+ 4
+
+
+
+ 256
+ {{477, 1}, {15, 348}}
+
+
+ _doScroller:
+ 9.971429e-01
+
+
+
+ 256
+ {{1, 349}, {476, 15}}
+
+ YES
+ 1
+
+ _doScroller:
+ 6.888567e-01
+
+
+ {{-1, -1}, {493, 365}}
+
+
+ 178
+
+
+
+ QSAAAEEgAABBmAAAQZgAAA
+
+
+ {491, 363}
+
+
+ {{0, 0}, {1440, 878}}
+ {3.40282e+38, 3.40282e+38}
+
+
+ AppController
+
+
+
+
+ YES
+
+
+ performMiniaturize:
+
+
+
+ 37
+
+
+
+ arrangeInFront:
+
+
+
+ 39
+
+
+
+ print:
+
+
+
+ 86
+
+
+
+ runPageLayout:
+
+
+
+ 87
+
+
+
+ clearRecentDocuments:
+
+
+
+ 127
+
+
+
+ orderFrontStandardAboutPanel:
+
+
+
+ 142
+
+
+
+ performClose:
+
+
+
+ 193
+
+
+
+ toggleContinuousSpellChecking:
+
+
+
+ 222
+
+
+
+ undo:
+
+
+
+ 223
+
+
+
+ copy:
+
+
+
+ 224
+
+
+
+ checkSpelling:
+
+
+
+ 225
+
+
+
+ paste:
+
+
+
+ 226
+
+
+
+ stopSpeaking:
+
+
+
+ 227
+
+
+
+ cut:
+
+
+
+ 228
+
+
+
+ showGuessPanel:
+
+
+
+ 230
+
+
+
+ redo:
+
+
+
+ 231
+
+
+
+ selectAll:
+
+
+
+ 232
+
+
+
+ startSpeaking:
+
+
+
+ 233
+
+
+
+ delete:
+
+
+
+ 235
+
+
+
+ performZoom:
+
+
+
+ 240
+
+
+
+ performFindPanelAction:
+
+
+
+ 241
+
+
+
+ centerSelectionInVisibleArea:
+
+
+
+ 245
+
+
+
+ toggleGrammarChecking:
+
+
+
+ 347
+
+
+
+ toggleSmartInsertDelete:
+
+
+
+ 355
+
+
+
+ toggleAutomaticQuoteSubstitution:
+
+
+
+ 356
+
+
+
+ toggleAutomaticLinkDetection:
+
+
+
+ 357
+
+
+
+ showHelp:
+
+
+
+ 360
+
+
+
+ saveDocument:
+
+
+
+ 362
+
+
+
+ saveDocumentAs:
+
+
+
+ 363
+
+
+
+ revertDocumentToSaved:
+
+
+
+ 364
+
+
+
+ runToolbarCustomizationPalette:
+
+
+
+ 365
+
+
+
+ toggleToolbarShown:
+
+
+
+ 366
+
+
+
+ hide:
+
+
+
+ 367
+
+
+
+ hideOtherApplications:
+
+
+
+ 368
+
+
+
+ unhideAllApplications:
+
+
+
+ 370
+
+
+
+ newDocument:
+
+
+
+ 373
+
+
+
+ openDocument:
+
+
+
+ 374
+
+
+
+ raiseBaseline:
+
+
+
+ 426
+
+
+
+ lowerBaseline:
+
+
+
+ 427
+
+
+
+ copyFont:
+
+
+
+ 428
+
+
+
+ subscript:
+
+
+
+ 429
+
+
+
+ superscript:
+
+
+
+ 430
+
+
+
+ tightenKerning:
+
+
+
+ 431
+
+
+
+ underline:
+
+
+
+ 432
+
+
+
+ orderFrontColorPanel:
+
+
+
+ 433
+
+
+
+ useAllLigatures:
+
+
+
+ 434
+
+
+
+ loosenKerning:
+
+
+
+ 435
+
+
+
+ pasteFont:
+
+
+
+ 436
+
+
+
+ unscript:
+
+
+
+ 437
+
+
+
+ useStandardKerning:
+
+
+
+ 438
+
+
+
+ useStandardLigatures:
+
+
+
+ 439
+
+
+
+ turnOffLigatures:
+
+
+
+ 440
+
+
+
+ turnOffKerning:
+
+
+
+ 441
+
+
+
+ alignLeft:
+
+
+
+ 442
+
+
+
+ alignJustified:
+
+
+
+ 443
+
+
+
+ copyRuler:
+
+
+
+ 444
+
+
+
+ alignCenter:
+
+
+
+ 445
+
+
+
+ toggleRuler:
+
+
+
+ 446
+
+
+
+ alignRight:
+
+
+
+ 447
+
+
+
+ pasteRuler:
+
+
+
+ 448
+
+
+
+ terminate:
+
+
+
+ 449
+
+
+
+ delegate
+
+
+
+ 451
+
+
+
+ theWindow
+
+
+
+ 459
+
+
+
+ dataSource
+
+
+
+ 488
+
+
+
+
+ YES
+
+ 0
+
+ YES
+
+
+
+
+
+ -2
+
+
+ RmlsZSdzIE93bmVyA
+
+
+ -1
+
+
+ First Responder
+
+
+ -3
+
+
+ Application
+
+
+ 29
+
+
+ YES
+
+
+
+
+
+
+
+
+
+ MainMenu
+
+
+ 19
+
+
+ YES
+
+
+
+
+
+ 56
+
+
+ YES
+
+
+
+
+
+ 103
+
+
+ YES
+
+
+
+ 1
+
+
+ 217
+
+
+ YES
+
+
+
+
+
+ 83
+
+
+ YES
+
+
+
+
+
+ 81
+
+
+ YES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 75
+
+
+ 3
+
+
+ 80
+
+
+ 8
+
+
+ 78
+
+
+ 6
+
+
+ 72
+
+
+
+
+ 82
+
+
+ 9
+
+
+ 124
+
+
+ YES
+
+
+
+
+
+ 77
+
+
+ 5
+
+
+ 73
+
+
+ 1
+
+
+ 79
+
+
+ 7
+
+
+ 112
+
+
+ 10
+
+
+ 74
+
+
+ 2
+
+
+ 125
+
+
+ YES
+
+
+
+
+
+ 126
+
+
+
+
+ 205
+
+
+ YES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 202
+
+
+
+
+ 198
+
+
+
+
+ 207
+
+
+
+
+ 214
+
+
+
+
+ 199
+
+
+
+
+ 203
+
+
+
+
+ 197
+
+
+
+
+ 206
+
+
+
+
+ 215
+
+
+
+
+ 218
+
+
+ YES
+
+
+
+
+
+ 216
+
+
+ YES
+
+
+
+
+
+ 200
+
+
+ YES
+
+
+
+
+
+
+
+
+ 219
+
+
+
+
+ 201
+
+
+
+
+ 204
+
+
+
+
+ 220
+
+
+ YES
+
+
+
+
+
+
+
+
+
+ 213
+
+
+
+
+ 210
+
+
+
+
+ 221
+
+
+
+
+ 208
+
+
+
+
+ 209
+
+
+
+
+ 106
+
+
+ YES
+
+
+
+ 2
+
+
+ 111
+
+
+
+
+ 57
+
+
+ YES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 58
+
+
+
+
+ 134
+
+
+
+
+ 150
+
+
+
+
+ 136
+
+
+ 1111
+
+
+ 144
+
+
+
+
+ 129
+
+
+ 121
+
+
+ 143
+
+
+
+
+ 236
+
+
+
+
+ 131
+
+
+ YES
+
+
+
+
+
+ 149
+
+
+
+
+ 145
+
+
+
+
+ 130
+
+
+
+
+ 24
+
+
+ YES
+
+
+
+
+
+
+
+
+ 92
+
+
+
+
+ 5
+
+
+
+
+ 239
+
+
+
+
+ 23
+
+
+
+
+ 295
+
+
+ YES
+
+
+
+
+
+ 296
+
+
+ YES
+
+
+
+
+
+
+ 297
+
+
+
+
+ 298
+
+
+
+
+ 211
+
+
+ YES
+
+
+
+
+
+ 212
+
+
+ YES
+
+
+
+
+
+
+ 195
+
+
+
+
+ 196
+
+
+
+
+ 346
+
+
+
+
+ 348
+
+
+ YES
+
+
+
+
+
+ 349
+
+
+ YES
+
+
+
+
+
+
+
+ 350
+
+
+
+
+ 351
+
+
+
+
+ 354
+
+
+
+
+ 371
+
+
+ YES
+
+
+
+
+
+ 372
+
+
+ YES
+
+
+
+
+
+ 375
+
+
+ YES
+
+
+
+
+
+ 376
+
+
+ YES
+
+
+
+
+
+
+ 377
+
+
+ YES
+
+
+
+
+
+ 378
+
+
+ YES
+
+
+
+
+
+ 379
+
+
+ YES
+
+
+
+
+
+
+
+
+
+
+
+
+ 380
+
+
+
+
+ 381
+
+
+
+
+ 382
+
+
+
+
+ 383
+
+
+
+
+ 384
+
+
+
+
+ 385
+
+
+
+
+ 386
+
+
+
+
+ 387
+
+
+
+
+ 388
+
+
+ YES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 389
+
+
+
+
+ 390
+
+
+
+
+ 391
+
+
+
+
+ 392
+
+
+
+
+ 393
+
+
+
+
+ 394
+
+
+
+
+ 395
+
+
+
+
+ 396
+
+
+
+
+ 397
+
+
+ YES
+
+
+
+
+
+ 398
+
+
+ YES
+
+
+
+
+
+ 399
+
+
+ YES
+
+
+
+
+
+ 400
+
+
+
+
+ 401
+
+
+
+
+ 402
+
+
+
+
+ 403
+
+
+
+
+ 404
+
+
+
+
+ 405
+
+
+ YES
+
+
+
+
+
+
+
+
+
+ 406
+
+
+
+
+ 407
+
+
+
+
+ 408
+
+
+
+
+ 409
+
+
+
+
+ 410
+
+
+
+
+ 411
+
+
+ YES
+
+
+
+
+
+
+
+ 412
+
+
+
+
+ 413
+
+
+
+
+ 414
+
+
+
+
+ 415
+
+
+ YES
+
+
+
+
+
+
+
+
+ 416
+
+
+
+
+ 417
+
+
+
+
+ 418
+
+
+
+
+ 419
+
+
+
+
+ 450
+
+
+
+
+ 460
+
+
+ YES
+
+
+
+
+
+
+
+ 461
+
+
+
+
+ 462
+
+
+
+
+ 463
+
+
+ YES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 465
+
+
+ YES
+
+
+
+
+
+ 466
+
+
+ YES
+
+
+
+
+
+ 467
+
+
+
+
+ 468
+
+
+
+
+ 469
+
+
+ YES
+
+
+
+
+
+ 470
+
+
+
+
+ 471
+
+
+ YES
+
+
+
+
+
+ 472
+
+
+
+
+ 473
+
+
+ YES
+
+
+
+
+
+ 474
+
+
+
+
+ 475
+
+
+ YES
+
+
+
+
+
+ 476
+
+
+
+
+ 477
+
+
+ YES
+
+
+
+
+
+ 478
+
+
+
+
+ 479
+
+
+ YES
+
+
+
+
+
+ 480
+
+
+
+
+ 481
+
+
+ YES
+
+
+
+
+
+ 482
+
+
+
+
+ 483
+
+
+ YES
+
+
+
+
+
+ 484
+
+
+
+
+ 485
+
+
+ YES
+
+
+
+
+
+ 486
+
+
+
+
+
+
+ YES
+
+ YES
+ -1.IBPluginDependency
+ -2.IBPluginDependency
+ -3.IBPluginDependency
+ 103.IBPluginDependency
+ 103.ImportedFromIB2
+ 106.IBPluginDependency
+ 106.ImportedFromIB2
+ 106.editorWindowContentRectSynchronizationRect
+ 111.IBPluginDependency
+ 111.ImportedFromIB2
+ 112.IBPluginDependency
+ 112.ImportedFromIB2
+ 124.IBPluginDependency
+ 124.ImportedFromIB2
+ 125.IBPluginDependency
+ 125.ImportedFromIB2
+ 125.editorWindowContentRectSynchronizationRect
+ 126.IBPluginDependency
+ 126.ImportedFromIB2
+ 129.IBPluginDependency
+ 129.ImportedFromIB2
+ 130.IBPluginDependency
+ 130.ImportedFromIB2
+ 130.editorWindowContentRectSynchronizationRect
+ 131.IBPluginDependency
+ 131.ImportedFromIB2
+ 134.IBPluginDependency
+ 134.ImportedFromIB2
+ 136.IBPluginDependency
+ 136.ImportedFromIB2
+ 143.IBPluginDependency
+ 143.ImportedFromIB2
+ 144.IBPluginDependency
+ 144.ImportedFromIB2
+ 145.IBPluginDependency
+ 145.ImportedFromIB2
+ 149.IBPluginDependency
+ 149.ImportedFromIB2
+ 150.IBPluginDependency
+ 150.ImportedFromIB2
+ 19.IBPluginDependency
+ 19.ImportedFromIB2
+ 195.IBPluginDependency
+ 195.ImportedFromIB2
+ 196.IBPluginDependency
+ 196.ImportedFromIB2
+ 197.IBPluginDependency
+ 197.ImportedFromIB2
+ 198.IBPluginDependency
+ 198.ImportedFromIB2
+ 199.IBPluginDependency
+ 199.ImportedFromIB2
+ 200.IBPluginDependency
+ 200.ImportedFromIB2
+ 200.editorWindowContentRectSynchronizationRect
+ 201.IBPluginDependency
+ 201.ImportedFromIB2
+ 202.IBPluginDependency
+ 202.ImportedFromIB2
+ 203.IBPluginDependency
+ 203.ImportedFromIB2
+ 204.IBPluginDependency
+ 204.ImportedFromIB2
+ 205.IBPluginDependency
+ 205.ImportedFromIB2
+ 205.editorWindowContentRectSynchronizationRect
+ 206.IBPluginDependency
+ 206.ImportedFromIB2
+ 207.IBPluginDependency
+ 207.ImportedFromIB2
+ 208.IBPluginDependency
+ 208.ImportedFromIB2
+ 209.IBPluginDependency
+ 209.ImportedFromIB2
+ 210.IBPluginDependency
+ 210.ImportedFromIB2
+ 211.IBPluginDependency
+ 211.ImportedFromIB2
+ 212.IBPluginDependency
+ 212.ImportedFromIB2
+ 212.editorWindowContentRectSynchronizationRect
+ 213.IBPluginDependency
+ 213.ImportedFromIB2
+ 214.IBPluginDependency
+ 214.ImportedFromIB2
+ 215.IBPluginDependency
+ 215.ImportedFromIB2
+ 216.IBPluginDependency
+ 216.ImportedFromIB2
+ 217.IBPluginDependency
+ 217.ImportedFromIB2
+ 218.IBPluginDependency
+ 218.ImportedFromIB2
+ 219.IBPluginDependency
+ 219.ImportedFromIB2
+ 220.IBPluginDependency
+ 220.ImportedFromIB2
+ 220.editorWindowContentRectSynchronizationRect
+ 221.IBPluginDependency
+ 221.ImportedFromIB2
+ 23.IBPluginDependency
+ 23.ImportedFromIB2
+ 236.IBPluginDependency
+ 236.ImportedFromIB2
+ 239.IBPluginDependency
+ 239.ImportedFromIB2
+ 24.IBPluginDependency
+ 24.ImportedFromIB2
+ 24.editorWindowContentRectSynchronizationRect
+ 29.IBEditorWindowLastContentRect
+ 29.IBPluginDependency
+ 29.ImportedFromIB2
+ 29.WindowOrigin
+ 29.editorWindowContentRectSynchronizationRect
+ 295.IBPluginDependency
+ 296.IBPluginDependency
+ 296.editorWindowContentRectSynchronizationRect
+ 297.IBPluginDependency
+ 298.IBPluginDependency
+ 346.IBPluginDependency
+ 346.ImportedFromIB2
+ 348.IBPluginDependency
+ 348.ImportedFromIB2
+ 349.IBPluginDependency
+ 349.ImportedFromIB2
+ 349.editorWindowContentRectSynchronizationRect
+ 350.IBPluginDependency
+ 350.ImportedFromIB2
+ 351.IBPluginDependency
+ 351.ImportedFromIB2
+ 354.IBPluginDependency
+ 354.ImportedFromIB2
+ 371.IBEditorWindowLastContentRect
+ 371.IBWindowTemplateEditedContentRect
+ 371.NSWindowTemplate.visibleAtLaunch
+ 371.editorWindowContentRectSynchronizationRect
+ 371.windowTemplate.maxSize
+ 372.IBPluginDependency
+ 375.IBPluginDependency
+ 376.IBEditorWindowLastContentRect
+ 376.IBPluginDependency
+ 377.IBPluginDependency
+ 378.IBPluginDependency
+ 379.IBPluginDependency
+ 380.IBPluginDependency
+ 381.IBPluginDependency
+ 382.IBPluginDependency
+ 383.IBPluginDependency
+ 384.IBPluginDependency
+ 385.IBPluginDependency
+ 386.IBPluginDependency
+ 387.IBPluginDependency
+ 388.IBEditorWindowLastContentRect
+ 388.IBPluginDependency
+ 389.IBPluginDependency
+ 390.IBPluginDependency
+ 391.IBPluginDependency
+ 392.IBPluginDependency
+ 393.IBPluginDependency
+ 394.IBPluginDependency
+ 395.IBPluginDependency
+ 396.IBPluginDependency
+ 397.IBPluginDependency
+ 398.IBPluginDependency
+ 399.IBPluginDependency
+ 400.IBPluginDependency
+ 401.IBPluginDependency
+ 402.IBPluginDependency
+ 403.IBPluginDependency
+ 404.IBPluginDependency
+ 405.IBPluginDependency
+ 406.IBPluginDependency
+ 407.IBPluginDependency
+ 408.IBPluginDependency
+ 409.IBPluginDependency
+ 410.IBPluginDependency
+ 411.IBPluginDependency
+ 412.IBPluginDependency
+ 413.IBPluginDependency
+ 414.IBPluginDependency
+ 415.IBPluginDependency
+ 416.IBPluginDependency
+ 417.IBPluginDependency
+ 418.IBPluginDependency
+ 419.IBPluginDependency
+ 450.IBPluginDependency
+ 460.IBPluginDependency
+ 461.IBPluginDependency
+ 462.IBPluginDependency
+ 463.IBPluginDependency
+ 465.IBPluginDependency
+ 466.IBPluginDependency
+ 467.IBPluginDependency
+ 468.IBPluginDependency
+ 469.IBPluginDependency
+ 470.IBPluginDependency
+ 471.IBPluginDependency
+ 472.IBPluginDependency
+ 473.IBPluginDependency
+ 474.IBPluginDependency
+ 475.IBPluginDependency
+ 476.IBPluginDependency
+ 477.IBPluginDependency
+ 478.IBPluginDependency
+ 479.IBPluginDependency
+ 480.IBPluginDependency
+ 481.IBPluginDependency
+ 482.IBPluginDependency
+ 483.IBPluginDependency
+ 484.IBPluginDependency
+ 485.IBPluginDependency
+ 486.IBPluginDependency
+ 5.IBPluginDependency
+ 5.ImportedFromIB2
+ 56.IBPluginDependency
+ 56.ImportedFromIB2
+ 57.IBEditorWindowLastContentRect
+ 57.IBPluginDependency
+ 57.ImportedFromIB2
+ 57.editorWindowContentRectSynchronizationRect
+ 58.IBPluginDependency
+ 58.ImportedFromIB2
+ 72.IBPluginDependency
+ 72.ImportedFromIB2
+ 73.IBPluginDependency
+ 73.ImportedFromIB2
+ 74.IBPluginDependency
+ 74.ImportedFromIB2
+ 75.IBPluginDependency
+ 75.ImportedFromIB2
+ 77.IBPluginDependency
+ 77.ImportedFromIB2
+ 78.IBPluginDependency
+ 78.ImportedFromIB2
+ 79.IBPluginDependency
+ 79.ImportedFromIB2
+ 80.IBPluginDependency
+ 80.ImportedFromIB2
+ 81.IBPluginDependency
+ 81.ImportedFromIB2
+ 81.editorWindowContentRectSynchronizationRect
+ 82.IBPluginDependency
+ 82.ImportedFromIB2
+ 83.IBPluginDependency
+ 83.ImportedFromIB2
+ 92.IBPluginDependency
+ 92.ImportedFromIB2
+
+
+ YES
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilderKit
+ com.apple.InterfaceBuilderKit
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{596, 852}, {216, 23}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{522, 812}, {146, 23}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{436, 809}, {64, 6}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{608, 612}, {275, 83}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{187, 434}, {243, 243}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{608, 612}, {167, 43}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{608, 612}, {241, 103}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{525, 802}, {197, 73}}
+ {{143, 285}, {478, 20}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {74, 862}
+ {{6, 978}, {478, 20}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ {{475, 832}, {234, 43}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{608, 612}, {215, 63}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{83, 84}, {491, 363}}
+ {{83, 84}, {491, 363}}
+
+ {{33, 99}, {480, 360}}
+ {3.40282e+38, 3.40282e+38}
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ {{437, 242}, {86, 43}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ {{523, 2}, {178, 283}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{155, 102}, {245, 183}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{23, 794}, {245, 183}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ {{145, 474}, {199, 203}}
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+ com.apple.InterfaceBuilder.CocoaPlugin
+
+
+
+
+ YES
+
+ YES
+
+
+ YES
+
+
+
+
+ YES
+
+ YES
+
+
+ YES
+
+
+
+ 488
+
+
+
+ YES
+
+ AppController
+
+ theWindow
+ NSWindow
+
+
+ IBUserSource
+
+
+
+
+
+ 0
+ ../adsfsdf.xcodeproj
+ 3
+
+
diff --git a/Tests/TableCibTest/Resources/spinner.gif b/Tests/TableCibTest/Resources/spinner.gif
new file mode 100644
index 000000000..06dbc2bc2
Binary files /dev/null and b/Tests/TableCibTest/Resources/spinner.gif differ
diff --git a/Tests/TableCibTest/index-debug.html b/Tests/TableCibTest/index-debug.html
new file mode 100644
index 000000000..218ae015c
--- /dev/null
+++ b/Tests/TableCibTest/index-debug.html
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+ TableCibTest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/TableTest/main.j b/Tests/TableTest/main.j
new file mode 100755
index 000000000..ee431dc77
--- /dev/null
+++ b/Tests/TableTest/main.j
@@ -0,0 +1,18 @@
+/*
+ * AppController.j
+ * TableTest
+ *
+ * Created by You on June 7, 2009.
+ * Copyright 2009, Your Company All rights reserved.
+ */
+
+@import
+@import
+
+@import "AppController.j"
+
+
+function main(args, namedArgs)
+{
+ CPApplicationMain(args, namedArgs);
+}
diff --git a/Tools/Documentation/Cappuccino.doxygen b/Tools/Documentation/Cappuccino.doxygen
index 5c81778b3..f0ca1337a 100644
--- a/Tools/Documentation/Cappuccino.doxygen
+++ b/Tools/Documentation/Cappuccino.doxygen
@@ -247,7 +247,7 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
diff --git a/Tools/Editors/Emacs/README.txt b/Tools/Editors/Emacs/README.txt
new file mode 100644
index 000000000..2e4d9e506
--- /dev/null
+++ b/Tools/Editors/Emacs/README.txt
@@ -0,0 +1,32 @@
+Description
+===========
+A simple Emacs mode for editing Objective-J (Cappuccino) files.
+
+Author
+======
+Geoffrey Grosenbach, PeepCode Screencasts
+http://peepcode.com
+
+Features
+========
+* Syntax highlighting thanks to objc-c-mode.el.
+* Some adherence to Objective-J coding style guidelines (indentation).
+* Automatic loading of objj-mode when .j files are opened.
+
+Installation
+============
+Add objc-c-mode.el and objj-mode.el to your load path and require
+objj-mode.
+
+ (add-to-list 'load-path "/path/to/objc-c-mode.el")
+ (add-to-list 'load-path "/path/to/objj-mode.el")
+ (require 'objj-mode)
+
+Other
+=====
+If you use yasnippet (http://code.google.com/p/yasnippet/), you can define
+tab-triggered snippet templates specifically for Objective-J.
+
+Put your snippets in the "snippets/text-mode/objj-mode" directory where
+you keep your other yasnippets.
+
diff --git a/Tools/Editors/Emacs/objc-c-mode.el b/Tools/Editors/Emacs/objc-c-mode.el
new file mode 100644
index 000000000..8fc07871a
--- /dev/null
+++ b/Tools/Editors/Emacs/objc-c-mode.el
@@ -0,0 +1,284 @@
+;;; objc-c-mode.el --- improvements for the XEmacs Objective-C mode
+
+;; Author: Michael Weber
+;; Version: 20020527
+;; Keywords: Objective-C, ObjC
+;; Depends: cc-mode, font-lock
+;; Tested with: XEmacs 21.4 (patch 6) "Common Lisp" [Lucid]
+
+;;; Documentation:
+;;; ==============
+;;; To use this style for your Objective-C buffers, just add
+;;; (require 'objc-c-mode)
+;;;
+;;; to your XEmacs dot-file. It creates a new style `objc',
+;;; which is set as default for all objc-mode buffers.
+;;;
+;;; To further customize, try this:
+
+;;; (defconst my-c-style
+;;; '("objc"
+;;; (c-indent-comments-syntactically-p . t)
+;;; (c-comment-only-line-offset . 0)
+;;; ;;; whatever else here...
+;;;
+;;; (c-cleanup-list . (brace-else-brace
+;;; brace-elseif-brace
+;;; empty-defun-braces
+;;; defun-close-semi
+;;; compact-empty-funcall
+;;; )))
+;;; "My C Programming style")
+;;;
+;;; (defun my-c-mode-common-hook ()
+;;; (c-add-style "PERSONAL" my-c-style t)
+;;; (setq comment-column 40
+;;; tab-width 4
+;;; c-basic-offset tab-width)
+;;;
+;;; (c-toggle-auto-state 1))
+;;;
+;;; ;; activate customizations for all cc-mode derived modes
+;;; (add-hook 'c-mode-common-hook 'my-c-mode-common-hook)
+
+;;; If you want to specifically change the "objc" style,
+;;; probably use something like:
+
+;;; (defconst my-objc-style
+;;; '(("objc"
+;;; (...)
+;;; "My ObjC style")))
+;;; (defun my-objc-mode-hook ()
+;;; (c-add-style "objc" my-objc-style))
+;;; (add-hook 'objc-mode-hook 'my-objc-mode-hook)
+
+
+;;; Code:
+;;; =====
+
+(require 'cc-mode)
+
+;;; Default values. Do not change them here, instead change them like
+;;; any other style variable in your customized style.
+;;; NOTE: These numbers are ignored anyway, below they are set based on
+;;; `c-basic-offset' which is usually what one wants anyway...
+(defcustom-c-stylevar objc-method-arg-min-delta-to-bracket 2
+ "*Minimun number of chars to the opening bracket.
+
+Consider this ObjC snippet:
+
+ [foo blahBlah: fred
+ |<-x->|barBaz: barney
+
+If `x' is less than this number then `c-lineup-ObjC-method-call-colons'
+will defer the indentation decision to the next function. By default
+this is `c-lineup-ObjC-method-call', which would align it like:
+
+ [foo blahBlahBlah: fred
+ thisIsTooDamnLong: barney
+
+This behaviour can be overridden by customizing the indentation of
+`objc-method-call-cont' in the \"objc\" style."
+ :group 'c)
+
+(defcustom-c-stylevar objc-method-arg-unfinished-offset 4
+ "*Offset relative to bracket if first selector is on a new line.
+
+ [aaaaaaaaa
+ |<-x->|bbbbbbb: cccccc
+ ddddd: eeee];"
+ :group 'c)
+
+(defcustom-c-stylevar objc-method-parameter-offset 4
+ "*Offset for selector parameter on a new line (relative to first selector.
+
+ [aaaaaaa bbbbbbbbbb:
+ |<-x->|cccccccc
+ ddd: eeee
+ ffff: ggg];"
+ :group 'c)
+
+;; These are the real defaults (set here, because otherwise the
+;; indentation whines about them not being defined... *shrug*
+(setq c-style-variables (append
+ '(objc-method-arg-min-delta-to-bracket
+ objc-method-arg-unfinished-offset
+ objc-method-parameter-offset)
+ c-style-variables)
+
+ c-offsets-alist (append
+ '((objc-method-arg-min-delta-to-bracket . *)
+ (objc-method-arg-unfinished-offset . +)
+ (objc-method-parameter-offset . +))
+ c-offsets-alist))
+
+
+(defun c-lineup-ObjC-method-call-colons (langelem)
+ "Line up the colons of selector args with the first selector.
+
+If no decision can be made return NIL, so that other lineup methods can be
+tried. This is typically chained with `c-lineup-ObjC-method-call'."
+
+ (save-excursion
+ (catch 'no-idea
+ (let* ((method-arg-len (progn
+ (back-to-indentation)
+ (if (search-forward ":" (c-point 'eol) 'move)
+ (- (point) (c-point 'boi))
+ ; no complete argument to indent yet
+ (throw 'no-idea nil))))
+
+ (extra (save-excursion
+ ; indent parameter to argument if needed
+ (back-to-indentation)
+ (c-backward-syntactic-ws (cdr langelem))
+ (if (eq ?: (char-before))
+ (c-get-offset '(objc-method-parameter-offset . nil))
+ 0)))
+
+ (open-bracket-col (c-langelem-col langelem))
+
+ (arg-ralign-colon-ofs (progn
+ (forward-char) ; skip over '['
+ ; skip over object/class name
+ ; and first argument
+ (c-forward-sexp 2)
+ (if (search-forward ":" (c-point 'eol) 'move)
+ (- (current-column) open-bracket-col
+ method-arg-len extra)
+ ; previous arg has no param
+ (c-get-offset '(objc-method-arg-unfinished-offset . nil))))))
+
+ (if (>= arg-ralign-colon-ofs
+ (c-get-offset '(objc-method-arg-min-delta-to-bracket . nil)))
+ (+ arg-ralign-colon-ofs extra)
+ (throw 'no-idea nil)
+ )))))
+
+
+;;; create and add style
+(c-add-style "objc"
+ '("gnu"
+ (c-offsets-alist . ((objc-method-call-cont .
+ (c-lineup-ObjC-method-call-colons
+ c-lineup-ObjC-method-call
+ +))
+ ))
+ ))
+
+(setq c-default-style (cons '(objc-mode . "objc")
+ c-default-style))
+
+
+;;
+;; Now for the font-locking part... :)
+;;
+(require 'font-lock)
+
+(put 'objc-mode 'font-lock-defaults
+ '((objc-font-lock-keywords
+ objc-font-lock-keywords-1
+ objc-font-lock-keywords-2
+ objc-font-lock-keywords-3)
+ ;; TODO: ?_ is not a good idea in ObjC specifiers...
+ nil nil ((?_ . "w")) beginning-of-defun))
+
+(let* ((ctoken "\\(?:\\sw\\|\\s_\\|[:~*&]\\)+")
+ (objc-keywords "YES\\|NO\\|[Nn]il\\|self\\|super")
+ (objc-type-types "id\\|Class\\|SEL\\|IMP\\|BOOL")
+ (addon-objc-font-lock-keywords-1
+ (list ;; nothing to do here...
+ ))
+ (addon-objc-font-lock-keywords-2
+ (append addon-objc-font-lock-keywords-1
+ (list
+ ;; first part of selector (in a declaration)
+ (list (concat "^[+-][ \t]*"
+ "\\((" ctoken "[ \t]*[*]*)\\)?[ \t]*"
+ "\\(\\sw+\\)"
+ )
+ '(2 font-lock-function-name-face))
+ ;; part of a selector
+ '("\\sw*:" 0 font-lock-function-name-face t)
+ ;; Fontify all type specifiers.
+ (cons (concat "\\<\\(" objc-type-types "\\)\\>")
+ 'font-lock-type-face)
+ ;; Fontify all builtin keywords
+ (cons (concat "\\<\\(" objc-keywords "\\)\\>")
+ 'font-lock-keyword-face)
+ ;; Fontify specific keywords
+ (cons (concat "^" (regexp-opt (list
+ "@implementation" "@interface"
+ "@protocol" "@end" "@public"
+ "@private" "@protected"
+ ) t))
+ 'font-lock-keyword-face)
+
+ (list (concat "\\("
+ (regexp-opt (list
+ "@class" "@defs" "@encode" "@selector"
+ "@protocol"
+ ))
+ "\\)[ \t]*(")
+ 1 'font-lock-keyword-face)
+
+ '("^#[ \t]*import[ \t]+\\(<[^>\"\n]+>\\)"
+ 1 font-lock-string-face)
+ )
+ ))
+ (addon-objc-font-lock-keywords-3
+ (append addon-objc-font-lock-keywords-2
+ (list
+ ;; get argument-less selectors' highlighting right
+ ;; [[foo _bar_] _baz_] -> bar, baz are highlighted
+ (cons (concat "\\(\\sw+\\)" "[ \t]*" "[]]")
+ '(1 (let ((non-ws-before-match (char-before
+ (save-excursion
+ (goto-char (match-beginning 1))
+ ;; expensive!
+ (c-backward-syntactic-ws (c-point 'bol))
+ ))))
+ (unless (or (eq ?: non-ws-before-match)
+ (eq ?\[ non-ws-before-match))
+ 'font-lock-function-name-face))))
+
+ (cons (concat "\\<\\(" objc-type-types "\\)\\>"
+ "\\([ \t*&]+\\sw+\\>\\)*")
+ ;; taken verbatim from font-lock.el
+ '(font-lock-match-c++-style-declaration-item-and-skip-to-next
+ (goto-char (or (match-beginning 8) (match-end 1)))
+ (goto-char (match-end 1))
+ (1 (if (match-beginning 4)
+ font-lock-function-name-face
+ font-lock-variable-name-face))))
+ (cons (concat "\\<"
+ (regexp-opt (list
+ "NS_DURING" "NS_HANDLER" "NS_ENDHANDLER"
+ "RECREATE_AUTORELEASE_POOL"
+ "CREATE_AUTORELEASE_POOL"
+ "ASSIGNCOPY" "ASSIGN" "RETAIN"
+ "DESTROY" "AUTORELEASE" "RELEASE"
+ ) t)
+ "\\>")
+ 'font-lock-preprocessor-face)
+ )))
+ )
+
+ (setq objc-font-lock-keywords-1 (append c-font-lock-keywords-1
+ addon-objc-font-lock-keywords-1)
+
+ objc-font-lock-keywords-2 (append c-font-lock-keywords-2
+ addon-objc-font-lock-keywords-2)
+
+ objc-font-lock-keywords-3 (append c-font-lock-keywords-3
+ addon-objc-font-lock-keywords-3)
+ ))
+
+
+(defvar objc-font-lock-keywords objc-font-lock-keywords-1
+ "Default expressions to highlight in ObjC mode.")
+
+
+(provide 'objc-c-mode)
+
+;;; objc-c-mode.el ends here
diff --git a/Tools/Editors/Emacs/objj-mode.el b/Tools/Editors/Emacs/objj-mode.el
new file mode 100644
index 000000000..6ffea6da0
--- /dev/null
+++ b/Tools/Editors/Emacs/objj-mode.el
@@ -0,0 +1,31 @@
+;;; objj-mode.el --- Major mode for editing Objective-J (Cappuccino) files
+;;; Written by Geoffrey Grosenbach http://peepcode.com
+
+;;; Builds on the excellent objc-mode from http://www.foldr.org/~michaelw/objective-c/objc-c-mode.el
+
+;;; To install, save this somewhere and add the following to your .emacs file:
+;;;
+;;; (add-to-list 'load-path "/path/to/objc-c-mode.el")
+;;; (add-to-list 'load-path "/path/to/objj-mode.el")
+;;; (require 'objj-mode)
+;;;
+;;; Features:
+;;; * Syntax highlighting
+;;; * Indentation (minimal adherence to Obj-J coding style guidelines)
+
+(require 'objc-c-mode)
+
+(define-derived-mode objj-mode objc-mode
+ "Objective-J"
+ "Major mode for editing Objective-J files."
+ (setq c-basic-offset 4) ;; 4 spaces for tab
+ (setq indent-tabs-mode nil) ;; Spaces, not tabs
+ (c-set-offset 'substatement-open 0) ;; Curly brace on next line
+ )
+
+;; TODO: Define more syntax settings to comply with http://cappuccino.org/contribute/coding-style.php
+
+(add-to-list 'auto-mode-alist '("\\.j$" . objj-mode))
+
+(provide 'objj-mode)
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle.zip b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle.zip
deleted file mode 100644
index e26fd961c..000000000
Binary files a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle.zip and /dev/null differ
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/.gitignore b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/.gitignore
new file mode 100644
index 000000000..90ec22bee
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/.gitignore
@@ -0,0 +1 @@
+.svn
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/CPLog() for Current Method.tmCommand b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/CPLog() for Current Method.tmCommand
new file mode 100644
index 000000000..ec6f3d84f
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/CPLog() for Current Method.tmCommand
@@ -0,0 +1,70 @@
+
+
+
+
+ beforeRunningCommand
+ nop
+ command
+ #!/usr/bin/env ruby
+
+proto_re = /
+ ^\s* # Start of the line and optional space
+ [+-]\s* # a plus or minus for method specifier
+ \([^)]+\) # the return type in brackets
+ ((?:\n|[^{])*)
+ (?m:.*?)
+ \{
+ /x
+
+previous_lines = STDIN.readlines[1..ENV['TM_LINE_NUMBER'].to_i - 1]
+invocation_line = previous_lines[-1]
+
+proto = previous_lines.join.scan(proto_re)[-1]
+
+exit if proto.nil? or proto.empty?
+
+last_proto_sel_with_types = proto[0].strip.sub(/^\s+/, '').sub(%r{\s*//.*$}, '').gsub(/\n\s*/, ' ')
+
+params = []
+params = last_proto_sel_with_types.scan(/(.+?):\((.+?)\)(\w+)/)
+
+def format_specifier_for_type(type)
+ %w[int bool BOOL long].each { |t| return('%d') if type.include? t }
+ return '%c' if type == 'char'
+ return '%C' if type == 'unichar'
+ return '%s' if type == 'char*'
+ '%@'
+end
+
+def transformer_for(type, name)
+ return "CPStringFromRect(#{name})" if type == 'CPRect'
+ return "CPStringFromPoint(#{name})" if type == 'CPPoint'
+ return "CPStringFromSize(#{name})" if type == 'CPSize'
+ return "CPStringFromSelector(#{name})" if type == 'SEL'
+ name
+end
+
+print 'CPLog("[%@ '
+if params.empty?
+ print last_proto_sel_with_types
+else
+ print params.map { |param, type, name| param + ':' + format_specifier_for_type(type) }.join
+end
+print ']", [self class]'
+print ', ' + params.map { |param, type, name| transformer_for(type, name) }.join(', ') unless params.empty?
+print ");"
+
+ input
+ document
+ name
+ CPLog() for Current Method
+ output
+ insertAsSnippet
+ scope
+ source.js.objj meta.scope.implementation
+ tabTrigger
+ logm
+ uuid
+ F220FEE6-6522-4281-8091-CF8C66AED44F
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Help.tmCommand b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Help.tmCommand
new file mode 100644
index 000000000..43f1a9784
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Help.tmCommand
@@ -0,0 +1,29 @@
+
+
+
+
+ beforeRunningCommand
+ nop
+ command
+
+. "$TM_SUPPORT_PATH/lib/webpreview.sh"
+
+html_header "Objective-J Bundle Help" "Objective-J"
+
+"$TM_SUPPORT_PATH/lib/markdown_to_help.rb" "$TM_BUNDLE_SUPPORT/help/help.markdown"
+
+html_footer
+ input
+ none
+ keyEquivalent
+ ï†
+ name
+ Help
+ output
+ showAsHTML
+ scope
+ source.js.objj
+ uuid
+ AF27A8B3-C87F-410A-915B-D83271FDDC00
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Insert Matching Start Bracket.tmCommand b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Insert Matching Start Bracket.tmCommand
new file mode 100644
index 000000000..2fa24f653
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Insert Matching Start Bracket.tmCommand
@@ -0,0 +1,320 @@
+
+
+
+
+ beforeRunningCommand
+ nop
+ bundleUUID
+ 4679484F-6227-11D9-BFB1-000D93589AF6
+ command
+ #!/usr/bin/env ruby
+require "#{ENV['TM_SUPPORT_PATH']}/lib/escape"
+require ENV['TM_SUPPORT_PATH'] + "/lib/exit_codes"
+
+class Lexer
+ include Enumerable
+ def initialize
+ @label = nil
+ @pattern = nil
+ @handler = nil
+ @input = nil
+
+ reset
+
+ yield self if block_given?
+ end
+
+ def input(&reader)
+ if @input.is_a? self.class
+ @input.input(&reader)
+ else
+ class << reader
+ alias_method :next, :call
+ end
+
+ @input = reader
+ end
+ end
+
+ def add_token(label, pattern, &handler)
+ unless @label.nil?
+ @input = clone
+ end
+
+ @label = label
+ @pattern = /(#{pattern})/
+ @handler = handler || lambda { |label, match| [label, match] }
+
+ reset
+ end
+
+ def next(peek = false)
+ while @tokens.empty? and not @finished
+ new_input = @input.next
+ if new_input.nil? or new_input.is_a? String
+ @buffer += new_input unless new_input.nil?
+ new_tokens = @buffer.split(@pattern)
+ while new_tokens.size > 2 or (new_input.nil? and not new_tokens.empty?)
+ @tokens << new_tokens.shift
+ @tokens << @handler[@label, new_tokens.shift] unless new_tokens.empty?
+ end
+ @buffer = new_tokens.join
+ @finished = true if new_input.nil?
+ else
+ separator, new_token = @buffer.split(@pattern)
+ new_token = @handler[@label, new_token] unless new_token.nil?
+ @tokens.push( *[ separator,
+ new_token,
+ new_input ].select { |t| not t.nil? and t != "" } )
+ reset(:buffer)
+ end
+ end
+ peek ? @tokens.first : @tokens.shift
+ end
+
+ def peek
+ self.next(true)
+ end
+
+ def each
+ while token = self.next
+ yield token
+ end
+ end
+
+ private
+
+ def reset(*attrs)
+ @buffer = String.new if attrs.empty? or attrs.include? :buffer
+ @tokens = Array.new if attrs.empty? or attrs.include? :tokens
+ @finished = false if attrs.empty? or attrs.include? :finished
+ end
+end
+
+
+class ObjcParser
+
+ attr_reader :list
+ def initialize(args)
+ @list = args
+ end
+
+ def get_position
+ return nil,nil if @list.empty?
+ has_message = true
+
+ a = @list.pop
+ endings = [:close,:post_op,:at_string,:at_selector,:identifier]
+openings = [:open,:return,:control]
+ if a.tt == :identifier && !@list.empty? && endings.include?(@list[-1].tt)
+ insert_point = find_object_start
+ else
+ @list << a
+ has_message = false unless methodList
+ insert_point = find_object_start
+ end
+return insert_point, has_message
+ end
+
+ def methodList
+ old = Array.new(@list)
+
+ a = selector_loop(@list)
+ if !a.nil? && a.tt == :selector
+ if file_contains_selector? a.text
+ return true
+ else
+ internal = Array.new(@list)
+ b = a.text
+ until internal.empty?
+ tmp = selector_loop(internal)
+ return true if tmp.nil?
+ b = tmp.text + b
+ if file_contains_selector? b
+ @list = internal
+ return true
+ end
+ end
+ end
+ else
+ end
+@list = old
+return false
+ end
+
+ def file_contains_selector?(methodName)
+ fileNames = ["#{ENV['TM_BUNDLE_SUPPORT']}/cocoa.txt.gz"]
+ userMethods = "#{ENV['TM_PROJECT_DIRECTORY']}/.methods.TM_Completions.txt.gz"
+
+ fileNames += [userMethods] if File.exists? userMethods
+ candidates = []
+ fileNames.each do |fileName|
+ zGrepped = %x{zgrep ^#{e_sh methodName }[[:space:]] #{e_sh fileName }}
+ candidates += zGrepped.split("\n")
+ end
+
+ return !candidates.empty?
+ end
+
+ def selector_loop(l)
+ until l.empty?
+ obj = l.pop
+ case obj.tt
+ when :selector
+ return obj
+ when :close
+ return nil if match_bracket(obj.text,l).nil?
+ when :open
+ return nil
+ end
+ end
+ return nil
+ end
+
+ def match_bracket(type,l)
+ partner = {"]"=>"[",")"=>"(","}"=>"{"}[type]
+ up = 1
+ until l.empty?
+ obj = l.pop
+ case obj.text
+ when type
+ up +=1
+ when partner
+ up -=1
+ end
+ return obj.beg if up == 0
+ end
+ end
+
+ def find_object_start
+ openings = [:operator,:selector,:open,:return,:control]
+ until @list.empty? || openings.include?(@list[-1].tt)
+ obj = @list.pop
+ case obj.tt
+ when :close
+ tmp = match_bracket(obj.text, @list)
+ b = tmp unless tmp.nil?
+ when :star
+ b, ate = eat_star(b,obj.beg)
+ return b unless ate
+ when :nil
+ b = nil
+ else
+ b = obj.beg
+ end
+ end
+ return b
+ end
+
+ def eat_star(prev, curr)
+ openings = [:operator,:selector,:open,:return,:control,:star]
+ if @list.empty? || openings.include?(@list[-1].tt)
+ return curr, true
+ else
+ return prev, false
+ end
+ end
+end
+
+if __FILE__ == $PROGRAM_NAME
+ require "stringio"
+ line = ENV['TM_CURRENT_LINE']
+ caret_placement =ENV['TM_LINE_INDEX'].to_i - 1
+
+ up = 0
+ pat = /"(?:\\.|[^"\\])*"|\[|\]/
+ line.scan(pat).each do |item|
+ case item
+ when "["
+ up+=1
+ when "]"
+ up -=1
+ end
+ end
+ if caret_placement ==-1
+ print "]$0" + e_sn(line[caret_placement+1..-1])
+ TextMate.exit_insert_snippet
+ end
+
+ if up != 0
+ print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
+ TextMate.exit_insert_snippet
+ end
+
+ to_parse = StringIO.new(line[0..caret_placement])
+ lexer = Lexer.new do |l|
+ l.add_token(:return, /\breturn\b/)
+ l.add_token(:nil, /\bnil\b/)
+ l.add_token(:control, /\b(?:if|while|for|do)(?:\s*)\(/)# /\bif|while|for|do(?:\s*)\(/)
+ l.add_token(:at_string, /"(?:\\.|[^"\\])*"/)
+ l.add_token(:selector, /\b[A-Za-z_0-9]+:/)
+ l.add_token(:identifier, /\b[A-Za-z_0-9]+\b/)
+ l.add_token(:bind, /(?:->)|\./)
+ l.add_token(:post_op, /\+\+|\-\-/)
+ l.add_token(:at, /@/)
+ l.add_token(:star, /\*/)
+ l.add_token(:close, /\)|\]|\}/)
+ l.add_token(:open, /\(|\[|\{/)
+ l.add_token(:operator, /[&-+\/=%!:\,\?;<>\|\~\^]/)
+
+ l.add_token(:terminator, /;\n*|\n+/)
+ l.add_token(:whitespace, /\s+/)
+ l.add_token(:unknown, /./)
+
+ l.input { to_parse.gets }
+ #l.input {STDIN.read}
+ end
+
+ offset = 0
+ tokenList = []
+ A = Struct.new(:tt, :text, :beg)
+
+ lexer.each do |token|
+ tokenList << A.new(*(token<<offset)) unless [:whitespace,:terminator].include? token[0]
+ offset +=token[1].length
+ end
+ if tokenList.empty?
+ print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
+ TextMate.exit_insert_snippet
+ end
+
+ par = ObjcParser.new(tokenList)
+ b, has_message = par.get_position
+
+ if !line[caret_placement+1].nil? && line[caret_placement+1].chr == "]"
+ if b.nil? || par.list.empty? || par.list[-1].text == "["
+ print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+2..-1])
+ TextMate.exit_insert_snippet
+ end
+ end
+
+ if b.nil?
+ print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
+ elsif !has_message && (b < caret_placement )
+ print e_sn(line[0..b-1]) unless b == 0
+ ins = (/\s/ =~ line[caret_placement].chr ? "$0]" : " $0]")
+ print "[" +e_sn(line[b..caret_placement]) + ins +e_sn(line[caret_placement+1..-1])
+ elsif b < caret_placement
+ print e_sn(line[0..b-1]) unless b == 0
+ print "[" +e_sn(line[b..caret_placement]) +"]$0"+e_sn(line[caret_placement+1..-1])
+ else
+ print e_sn(line[0..caret_placement])+"]$0"+e_sn(line[caret_placement+1..-1])
+ end
+end
+
+ fallbackInput
+ line
+ input
+ selection
+ keyEquivalent
+ ]
+ name
+ Insert Matching Start Bracket
+ output
+ insertAsSnippet
+ scope
+ source.js.objj
+ uuid
+ CD025B3E-36B9-4E16-A81E-8DB6E8466CD1
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Insert [[… alloc] init].tmCommand b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Insert [[… alloc] init].tmCommand
new file mode 100644
index 000000000..2b3137e5e
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Insert [[… alloc] init].tmCommand
@@ -0,0 +1,42 @@
+
+
+
+
+ beforeRunningCommand
+ nop
+ command
+ #!/usr/bin/env ruby
+
+def e (str); str.gsub(/[$`\\]/, '\\\\\0'); end
+
+line = STDIN.read
+col = ENV['TM_LINE_INDEX'].to_i
+
+left, right = line[0...col], line[col..-1]
+
+if left =~ /(.*?)(\[)?(\w+)\s+$/ then
+ lead, bracket, cl = $1, $2, $3
+ right = line[col+1..-1] unless bracket.nil?
+ print "#{e lead}${1/.+/[/}[[#{e cl} alloc] init$0]"
+ print right.empty? ? ";" : "#{e right}"
+else
+ # this is only if we were not able to interpret the line
+ print "#{e left}$0#{e right}"
+end
+
+ fallbackInput
+ line
+ input
+ selection
+ name
+ Insert [[… alloc] init]
+ output
+ insertAsSnippet
+ scope
+ source.js.objj
+ tabTrigger
+ alloc
+ uuid
+ DF55A80D-E733-4CE2-A318-D56789B18406
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Open Document in Running Browser(s).tmCommand b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Open Document in Running Browser(s).tmCommand
new file mode 100644
index 000000000..c36fb7301
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Open Document in Running Browser(s).tmCommand
@@ -0,0 +1,67 @@
+
+
+
+
+ beforeRunningCommand
+ nop
+ command
+ #!/usr/bin/env ruby -wKU
+#
+# Open Document in Running Browser(s)
+# v3 - November 22, 2007
+#
+# Now supports multiple running versions of a single browser along
+# with a range of new/old browsers. Bring back support for Firefox.
+#
+# Options: Set TM_PROJECT_SITEURL in your TM Project Window Info Button
+# in the following form: "http://example.com/"
+
+require "#{ENV['TM_SUPPORT_PATH']}/lib/escape.rb"
+
+if ENV['TM_PROJECT_SITEURL']
+ url = "#{ENV['TM_PROJECT_SITEURL']}" + ENV['TM_FILEPATH'].sub(/^#{Regexp.escape(ENV['TM_PROJECT_DIRECTORY'])}\//, '')
+else
+ url = "file://#{ENV['TM_PROJECT_DIRECTORY']}/index.html"
+end
+
+proclist = `ps -x -o command`
+active = []
+os = `defaults read /System/Library/CoreServices/SystemVersion ProductVersion`
+
+browsers = %w[ Safari OmniWeb Camino Shiira firefox-bin Xyle\ scope Opera Internet\ Explorer flock-bin iCab Sunrise seamonkey-bin navigator-bin ].join('|')
+
+# Build paths to each active browser
+#
+# Notes:
+# - 'WebKit' look ahead is to rule it out so we can use the working
+# rule below.
+# - 'LaunchCFMApp' portion is so iCab works.
+active = proclist.scan(%r{^(?:/.*LaunchCFMApp )?(/.*\.app)(?=/Contents/MacOS/(?:#{browsers})\b(?!\s-WebKit))})
+
+# Special check for WebKit as it appears as Safari
+# Note: Only supports one running instance of WebKit, picked at random.
+if proclist =~ %r{/Contents/MacOS/Safari.*-WebKit(DeveloperExtras|ScriptDebuggerEnabled)}
+ active << "WebKit"
+end
+
+# TODO: Change when Leopard Only
+# On Leopard use the -g option to open in background.
+if os =~ /^10\.(5|6)/
+ active.each {|p| `open -g -a #{e_sh(p)} #{e_sh(url)}` }
+else
+ active.each {|p| `open -a #{e_sh(p)} #{e_sh(url)}` }
+end
+ input
+ none
+ keyEquivalent
+ @R
+ name
+ Run in Browsers
+ output
+ discard
+ scope
+ source.js.objj
+ uuid
+ 36FD3695-1051-401E-8536-89FB9CEEEAB4
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Refresh Running Browser(s).tmCommand b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Refresh Running Browser(s).tmCommand
new file mode 100644
index 000000000..8de201dcd
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Refresh Running Browser(s).tmCommand
@@ -0,0 +1,49 @@
+
+
+
+
+ beforeRunningCommand
+ nop
+ command
+ ### Refresh All Active Browsers - OmniWeb, Safari, Firefox & IE
+### v1.0. 2005-03-29
+###
+
+# Check if Internet Explorer is running, if so refresh
+ps -xc|grep -sq "Internet Explorer" && osascript -e 'tell app "Internet Explorer"' -e 'activate' -e 'OpenURL "JavaScript:window.location.reload();" toWindow -1' -e 'end tell'
+
+# Check if OmniWeb is running, if so refresh
+ps -xc|grep -sq OmniWeb && osascript -e 'tell app "OmniWeb"' -e 'activate' -e 'reload first browser' -e 'end tell'
+
+# Check if Firefox is running, if so refresh
+ps -xc|grep -sqi firefox && osascript <<'APPLESCRIPT'
+ tell app "Firefox" to activate
+ tell app "System Events"
+ if UI elements enabled then
+ keystroke "r" using command down
+ -- Fails if System Preferences > Universal access > "Enable access for assistive devices" is not on
+ else
+ tell app "Firefox" to Get URL "JavaScript:window.location.reload();" inside window 1
+ -- Fails if Firefox is set to open URLs from external apps in new tabs.
+ end if
+ end tell
+APPLESCRIPT
+
+# Check if Safari is running, if so refresh
+ps -xc|grep -sq Safari && osascript -e 'tell app "Safari"' -e 'activate' -e 'do JavaScript "window.location.reload();" in first document' -e 'end tell'
+
+# Check if Camino is running, if so refresh
+ps -xc|grep -sq Camino && osascript -e 'tell app "Camino"' -e 'activate' -e 'tell app "System Events" to keystroke "r" using {command down}' -e 'end tell'
+
+ input
+ none
+ name
+ Refresh Running Browser(s)
+ output
+ discard
+ scope
+ source.js.objj
+ uuid
+ 033BC36A-97DA-4F48-9ACB-B58C80D1A689
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Run.tmCommand b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Run.tmCommand
new file mode 100644
index 000000000..ad231d9a0
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Run.tmCommand
@@ -0,0 +1,60 @@
+
+
+
+
+ beforeRunningCommand
+ saveActiveFile
+ command
+
+[[ ! -z $TM_OBJJ_MASTER_FILE ]] && INDEXFILE="$TM_OBJJ_MASTER_FILE"
+
+[[ ! -z $TM_PROJECT_DIRECTORY ]] && INDEXFILE="$TM_PROJECT_DIRECTORY/index.html"
+
+[[ ! -z $TM_DIRECTORY ]] && INDEXFILE="$TM_DIRECTORY/index.html"
+
+if [ -z "$INDEXFILE" ]; then
+ D=`dirname "$TM_FILEPATH"`
+ while [ -z `find "$D" -name index.html` ]; do
+ D=`dirname "$D"`
+ done
+ INDEXFILE="${D}/index.html"
+fi
+
+[[ -z $INDEXFILE ]] && echo "No start file found. Please set the shell variable 'OBJJ_MASTER_FILE'" && exit 206
+
+cat <<-HTML
+ <script type="text/javascript" charset="utf-8">
+ try {
+ if (TextMate.system("", function (task) { })) {
+ var __TM_confirm_Status;
+ alert = function(s){TextMate.system("\"$DIALOG\" -e -p '{messageTitle=\"JavaScript\";informativeText=\""+s.toString().replace(/\x27/g,"’").replace(/\"/g,'\\\"')+"\";}'",null);};
+ confirm = function(s){TextMate.system("\"$DIALOG\" -e -p '{messageTitle=\"JavaScript\";informativeText=\""+s.toString().replace(/\x27/g,"’").replace(/\"/g,'\\\"')+"\";buttonTitles=(\"OK\",\"Cancel\");}'",null).onreadoutput=function(s){__TM_confirm_Status = s != 1;};return(__TM_confirm_Status)};
+ }
+ } catch(e) {}
+ </script>
+<base href="file://${INDEXFILE// /%20}">
+HTML
+cat "$INDEXFILE"
+[[ ! -z $(grep 'objj_exception_setOutputStream' "$INDEXFILE") ]] && exit 205
+cat <<-JS
+<script type="text/javascript" charset="utf-8">
+objj_exception_setOutputStream(function(aString) { console.log(aString);alert(aString) });
+</script>
+JS
+
+exit 205
+
+ input
+ none
+ keyEquivalent
+ @r
+ name
+ Run
+ output
+ showAsTooltip
+ scope
+ source.js.objj
+ uuid
+ 0C55A19B-3B2D-418F-B7FD-7E64B736F379
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Show Documentation.tmCommand b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Show Documentation.tmCommand
new file mode 100644
index 000000000..7c80f41e4
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Show Documentation.tmCommand
@@ -0,0 +1,27 @@
+
+
+
+
+ beforeRunningCommand
+ nop
+ command
+ cat <<-HTM
+<body onload='javascript:window.location.href="http://cappuccino.org/learn/documentation/"'>
+</body>
+HTM
+exit 205
+
+ input
+ none
+ keyEquivalent
+ ^H
+ name
+ Show Documentation
+ output
+ showAsTooltip
+ scope
+ source.js.objj
+ uuid
+ 344244D8-67A3-4F23-8270-397BD1696AC4
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Show Obj-J Documentation for Word.tmCommand b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Show Obj-J Documentation for Word.tmCommand
new file mode 100644
index 000000000..e639d6888
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Commands/Show Obj-J Documentation for Word.tmCommand
@@ -0,0 +1,214 @@
+
+
+
+
+ beforeRunningCommand
+ nop
+ command
+ [[ -z $OBJJ_HOME ]] && echo "OBJJ_HOME wasn't set!" && exit 206
+[[ ! -d "$OBJJ_HOME/Documentation" ]] && echo "Please copy the folder ‘Documentation’ to $OBJJ_HOME" && exit 206
+
+function showUpClassPage {
+cat <<-HTM
+<body onload='javascript:window.location.href="tm-file://$OBJJ_HOME/Documentation/class$1"'>
+</body>
+HTM
+exit 205
+}
+
+function showUpPage {
+cat <<-HTM
+<body onload='javascript:window.location.href="tm-file://$1"'>
+</body>
+HTM
+exit 205
+}
+
+
+DOCHEAD=$(perl -e '
+ #$line_nr = defined($ENV{"TM_INPUT_START_LINE"}) ? $ENV{"TM_INPUT_START_LINE"} : 1;
+ $line_nr = 1;
+ $cur_line_nr = $ENV{"TM_LINE_NUMBER"};
+ $header = "";
+ while($cur_line_nr-->$line_nr) {$header.=<>;}
+ $tail = <>;
+ $header .= substr($tail,0,$ENV{"TM_LINE_INDEX"});
+ print $header;
+')
+
+# caret is inside of a class name
+if [ `echo $TM_SCOPE | grep -c 'support.class.cappuccino'` -gt 0 ]; then
+ n=$(echo $TM_CURRENT_WORD | perl -pe 's/(.)(.)(.*)/_$1_$2_$3/;s/(?<!_)([A-Z])(?!_)/_$1/g;s/_{2,}/_/g')
+ showUpClassPage "$n.html"
+fi
+
+# caret is inside of a foundation class name
+if [ `echo $TM_SCOPE | grep -c 'support.variable.cappuccino.foundation'` -gt 0 ]; then
+ [[ "$TM_CURRENT_WORD" == "CPApp" ]] && showUpClassPage "_C_P_Application.html"
+fi
+
+# caret is inside of a objj function
+if [ `echo $TM_SCOPE | grep -c 'support.function.cappuccino'` -gt 0 ]; then
+ FILE=$(ruby -e '
+ require File.join(ENV["TM_SUPPORT_PATH"], "lib/ui.rb")
+ require File.join(ENV["TM_SUPPORT_PATH"], "lib/exit_codes.rb")
+ cur_word = ""
+ cur_word << ENV["TM_CURRENT_WORD"]
+ cur_word.sub!("CG", "C[GP]") if cur_word[0..1] == "CG" or cur_word[0..1] == "CP"
+ lg = %x{egrep -rl "C[GP]RectMake" '$OBJJ_HOME/Documentation'}
+ urls = lg.split(/\n/).sort
+ if urls.length == 1
+ print urls.first
+ else
+ display = urls.map{|x| x.split("/").last.sub!(".html","")}
+ index=TextMate::UI.menu(display)
+ if index != nil
+ print urls[index]
+ else
+ TextMate.exit_discard()
+ end
+ end
+ ')
+ FUNC=$(echo -en $TM_CURRENT_WORD | perl -pe 's/^(C[PG])(.*)/C[PG]$2/')
+ ANKER=`cat "$FILE" | egrep -o "\"#$FUNC.*?\"" | sed -e 's/^"//;s/".*//' | head -n 1`
+ [[ ! -z "$ANKER" ]] && showUpPage "$FILE$ANKER"
+ [[ ! -z $FILE ]] && showUpPage "$FILE" && exit 206
+fi
+
+# caret is inside of a constant
+if [ `echo $TM_SCOPE | grep -c 'support.constant.cappuccino'` -gt 0 ]; then
+ FILE=$(ruby -e '
+ require File.join(ENV["TM_SUPPORT_PATH"], "lib/ui.rb")
+ require File.join(ENV["TM_SUPPORT_PATH"], "lib/exit_codes.rb")
+ lg = %x{egrep -rl #{ENV["TM_CURRENT_WORD"]} '$OBJJ_HOME/Documentation'}
+ urls = lg.split(/\n/).sort
+ if urls.length == 1
+ print urls.first
+ else
+ display = urls.map{|x| x.split("/").last.sub!(".html","")}
+ index=TextMate::UI.menu(display)
+ if index != nil
+ print urls[index]
+ else
+ TextMate.exit_discard()
+ end
+ end
+ ')
+ [[ ! -z $FILE ]] && showUpPage "$FILE" && exit 206
+fi
+
+# caret is inside of [method]
+if [ `echo $TM_SCOPE | grep -c 'meta.bracketed.js.objj'` -gt 0 ]; then
+ # find []
+ DECL=$(echo -en "$DOCHEAD" | perl -e '
+ undef $/;
+ $header = <>;
+ $header=~s/\n/ /g;
+ @arr=split(//,$header);$c=0;
+ for($i=$#arr;$i>-1;$i--){$c-- if($arr[$i] eq "]");$c++ if($arr[$i] eq "[");last if $c>0;}
+ if($i==-1) {
+ print "";
+ } else {
+ print substr($header,$i+1);
+ }
+ ')
+
+ # find the class for a method
+ CLASS=$(echo -en "$DECL" | perl -e '
+ undef $/;
+ $header = <>;
+ substr($header,0) =~ m/^\s*(\w+).*/;
+ $f = $1;
+ if (defined($f)) {
+ if($f=~m/CPApp/) {
+ print "CPApplication";
+ } else {
+ print $f;
+ }
+ } else {
+ substr($header,1) =~ m/^\s*(\w+).*/;
+ $f = $1;
+ if(defined($f)) {
+ if($f=~m/CPApp/) {
+ print "CPApplication";
+ } else {
+ print $f;
+ }
+ }
+ }
+ ')
+ if [ ! -e "$OBJJ_HOME/Documentation/classes/$CLASS.html" ]; then
+ CLASS=$(echo -en "$DOCHEAD" | ruby -e '
+ require File.join(ENV["TM_SUPPORT_PATH"], "lib/ui.rb")
+ require File.join(ENV["TM_SUPPORT_PATH"], "lib/exit_codes.rb")
+ known_classes = []
+ classes = []
+ lg = %x{cd '$OBJJ_HOME/Documentation/classes'; egrep -rl #{ENV["TM_CURRENT_WORD"]} .}
+ known_classes = lg.split(/\n/).map{|x| x.sub("\.html","").sub("./","") }.sort
+ if known_classes.empty?
+ lg = %x{ls '$OBJJ_HOME/Documentation/classes'}
+ known_classes = lg.split(/\n/).map{|x| x.sub("\.html","").sub("./","") }.sort
+ end
+ STDIN.read().scan(/\b[_]{0,2}[NC][APS]\w+(?=[^\.])\b/) {|c| classes << c if ! classes.include?(c) && known_classes.include?(c)}
+ classes.sort!
+ if classes != known_classes
+ classes << "--"
+ classes += known_classes
+ end
+ if classes.length == 1
+ if classes.first != "--"
+ print classes.first
+ else
+ TextMate.exit_discard()
+ end
+ else
+ index=TextMate::UI.menu(classes)
+ if index != nil
+ print classes[index]
+ else
+ TextMate.exit_discard()
+ end
+ end
+ ')
+ fi
+ [[ -z $CLASS ]] && exit 200
+ [[ ! -e "$OBJJ_HOME/Documentation/classes/$CLASS.html" ]] && echo "Nothing for '$CLASS'!" && exit 206
+ # tries to find only the first method for 'method1: method2: etc'
+ FIRSTMETHOD=$(echo -en "$DECL" | perl -e '
+ undef $/;$d = <>;
+ $d=~m/\s*(\w+):/m;
+ print $1;
+ ')
+ METHOD=${FIRSTMETHOD:-$TM_CURRENT_WORD}
+
+ # find the correct anker within CLASS.html
+ ANKER=`cat "$OBJJ_HOME/Documentation/classes/$CLASS.html" | egrep -o "\"#$METHOD.*?\"" | sed -e 's/^"//;s/".*//' | head -n 1`
+ [[ ! -z "$ANKER" ]] && showUpClassPage "$CLASS.html$ANKER"
+
+ # check for inherited methods
+ ANKER=`cat "$OBJJ_HOME/Documentation/classes/$CLASS.html" | egrep -o "[^#\"]+?html#$METHOD" | head -n 1`
+# echo $CLASS; echo $METHOD; echo $ANKER; exit 206
+
+ CLASS=$(echo -en "$ANKER" | perl -pe 's/(.*?)\.html.*/$1/;')
+ # find the correct anker within the new CLASS.html
+ ANKER=`cat "$OBJJ_HOME/Documentation/classes/$CLASS.html" | egrep -o "\"#$METHOD.*?\"" | sed -e 's/^"//;s/".*//' | head -n 1`
+ [[ ! -z "$ANKER" ]] && showUpClassPage "$CLASS.html$ANKER"
+ # [[ ! -z "$ANKER" ]] && showUpClassPage "$ANKER"
+
+fi
+
+exit 205
+ input
+ selection
+ keyEquivalent
+ ^h
+ name
+ Documentation for Word
+ output
+ replaceSelectedText
+ scope
+ support.class.cappuccino, support.variable.cappuccino.foundation, meta.bracketed.js.objj, support.function.cappuccino
+ uuid
+ 2D05A28A-2ED7-4A9A-9A5C-8625466BC77C
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Preferences/Symbol List: Method.tmPreferences b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Preferences/Symbol List: Method.tmPreferences
new file mode 100644
index 000000000..5a9a01fda
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Preferences/Symbol List: Method.tmPreferences
@@ -0,0 +1,23 @@
+
+
+
+
+ name
+ Symbol List: Method
+ scope
+ meta.function.js.objj
+ settings
+
+ showInSymbolList
+ 1
+ symbolTransformation
+
+ s/^([-+])\s*\(.*?\)\s*/ $1 /; # strip result type
+ s/:\s*\(.*?\)\s*\w+\s*/:/g; # strip argument variables
+ s/\s*;?$//g; # strip terminating ws + semi-colon
+
+
+ uuid
+ E65A721C-192D-4BCC-AD35-5ED5CB0DA5BE
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/@selector(…).tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/@selector(…).tmSnippet
new file mode 100644
index 000000000..71e84bbe0
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/@selector(…).tmSnippet
@@ -0,0 +1,16 @@
+
+
+
+
+ content
+ @selector(${1:method}:)
+ name
+ @selector(…)
+ scope
+ source.js.objj
+ tabTrigger
+ sel
+ uuid
+ 13D9F280-A78F-4A4C-BE99-0DE13235738D
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Accessors.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Accessors.tmSnippet
new file mode 100644
index 000000000..af1db66ff
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Accessors.tmSnippet
@@ -0,0 +1,24 @@
+
+
+
+
+ content
+ - (${1:id})${2:thing}
+{
+ return $2;
+}
+
+- (void)set${2/./\u$0/}:($1)aValue
+{
+ $2 = aValue;
+}
+ name
+ Accessors
+ scope
+ source.js.objj
+ tabTrigger
+ acc
+ uuid
+ AA41BEF8-5F81-4A5A-85DE-2E81A112778B
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Archiving.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Archiving.tmSnippet
new file mode 100644
index 000000000..d54419fb4
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Archiving.tmSnippet
@@ -0,0 +1,31 @@
+
+
+
+
+ content
+ @implementation ${1:CLASS} (CPCoding)
+
+- (id)initWithCoder:(CPCoder)aCoder
+{
+ if (self = [super initWithCoder:aCoder])
+ {
+ ${2:IVAR} = [aCoder decodeObjectForKey:${3:KEY}];
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(CPCoder)aCoder
+{
+ [super encodeWithCoder:aCoder];
+
+ [aCoder encodeObject:${2:IVAR} forKey:${3:KEY}];
+}
+
+@end
+
+ name
+ Archiving
+ uuid
+ A840A98A-0C5B-49CB-8235-2CCD1BF7AFC1
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/CPLog(…).tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/CPLog(…).tmSnippet
new file mode 100644
index 000000000..29cfad4db
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/CPLog(…).tmSnippet
@@ -0,0 +1,16 @@
+
+
+
+
+ content
+ CPLog("$1"${1/[^%]*(%)?.*/(?1:, :\);)/}$2${1/[^%]*(%)?.*/(?1:\);)/}
+ name
+ CPLog(…)
+ scope
+ source.js.objj
+ tabTrigger
+ log
+ uuid
+ C268A928-5C8E-4284-9BAB-4FDFB07B983A
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Category.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Category.tmSnippet
new file mode 100644
index 000000000..a85cfcf16
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Category.tmSnippet
@@ -0,0 +1,21 @@
+
+
+
+
+ content
+ @interface ${1:NSObject} (${2:Category})
+@end
+
+@implementation ${1:NSObject} (${2:Category})
+$0
+@end
+ name
+ Category
+ scope
+ source.js.objj
+ tabTrigger
+ cat
+ uuid
+ 8C001067-8A50-4BAB-9A88-BA957A84E8CF
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Class.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Class.tmSnippet
new file mode 100644
index 000000000..4877a2ca8
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Class.tmSnippet
@@ -0,0 +1,29 @@
+
+
+
+
+ content
+ @implementation ${1:class} : ${2:CPObject}
+{
+}
+
+- (id)init
+{
+ if(self = [super init])
+ {$0
+ }
+ return self;
+}
+
+@end
+
+ name
+ Class
+ scope
+ source.js.objj
+ tabTrigger
+ objj
+ uuid
+ 96C39647-4346-4750-9F96-58070F24EDE6
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Delegate Responds to Selector.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Delegate Responds to Selector.tmSnippet
new file mode 100644
index 000000000..6cebd060f
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Delegate Responds to Selector.tmSnippet
@@ -0,0 +1,18 @@
+
+
+
+
+ content
+ if([${1:[self delegate]} respondsToSelector:@selector(${2:selfDidSomething:})])
+ [$1 ${3:${2/((^\s*([A-Za-z0-9_]*:)\s*)|(:\s*$)|(:\s*))/(?2:$2self :\:<>)(?4::)(?5: :)/g}}];
+
+ name
+ Delegate Responds to Selector
+ scope
+ source.js.objj
+ tabTrigger
+ delegate
+ uuid
+ 3B5B858C-645E-499C-813B-BBEEED943E9B
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Delegate.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Delegate.tmSnippet
new file mode 100644
index 000000000..e897bfe8e
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Delegate.tmSnippet
@@ -0,0 +1,24 @@
+
+
+
+
+ content
+ - (id)delegate
+{
+ return $1;
+}
+
+- (void)setDelegate:(id)aDelegate
+{
+ ${1:delegate} = aDelegate;
+}
+ name
+ Delegate
+ scope
+ source.js.objj
+ tabTrigger
+ delacc
+ uuid
+ 0B3D4C4C-7D75-49E6-9CEC-E4BF4069223A
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/New CPTextField.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/New CPTextField.tmSnippet
new file mode 100644
index 000000000..e6c258d1d
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/New CPTextField.tmSnippet
@@ -0,0 +1,21 @@
+
+
+
+
+ content
+ ${1:name} = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
+[$1 setStringValue:${2:@"${3:string}"}];
+${4:[$1 setEditable:${5:YES}];
+}${6:[$1 setFont:[CPFont systemFontOfSize:${7:12.0}]];
+}${8:[$1 sizeToFit];
+}${0:}
+ name
+ New CPTextField
+ scope
+ source.js.objj
+ tabTrigger
+ textf
+ uuid
+ C7340B17-F9EC-403F-9781-E2487023ED01
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Responds to Selector.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Responds to Selector.tmSnippet
new file mode 100644
index 000000000..0adcd9e64
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/Responds to Selector.tmSnippet
@@ -0,0 +1,20 @@
+
+
+
+
+ content
+ ${TM_COMMENT_START} ${4:Send $2 to $1, if $1 supports it}${TM_COMMENT_END}
+if ([${1:self} respondsToSelector:@selector(${2:someSelector:})])
+{
+ [$1 ${3:${2/((:\s*$)|(:\s*))/:<>(?3: )/g}}];
+}
+ name
+ Responds to Selector
+ scope
+ source.js.objj
+ tabTrigger
+ responds
+ uuid
+ D79EC699-9839-406E-AF60-DE51F78153CB
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/_Accessors.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/_Accessors.tmSnippet
new file mode 100644
index 000000000..424a7c2e8
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/_Accessors.tmSnippet
@@ -0,0 +1,24 @@
+
+
+
+
+ content
+ - (${1:id})${2:thing}
+{
+ return _$2;
+}
+
+- (void)set${2/./\u$0/}:($1)aValue
+{
+ _$2 = aValue;
+}
+ name
+ _Accessors
+ scope
+ source.js.objj
+ tabTrigger
+ _acc
+ uuid
+ 85B0746B-AE1C-47B3-8B9A-2B9A95F4C71E
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/import <…>.tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/import <…>.tmSnippet
new file mode 100644
index 000000000..6ebc31bc9
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/import <…>.tmSnippet
@@ -0,0 +1,17 @@
+
+
+
+
+ content
+ @import <${1:`"$DIALOG" -u -p "{menuItems=({title=Foundation;},{title=AppKit;});}" | perl -e 'undef $/;$a=<>;$a=~m/<key>title(.|\n)+?<string>(.*?)</;print $2;'`}/${2:CP}$3.j>
+
+ name
+ import <…>
+ scope
+ source.js.objj
+ tabTrigger
+ Imp
+ uuid
+ BE0553C0-B73B-4160-814C-840FC2B84C32
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/import … (with File Menu).tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/import … (with File Menu).tmSnippet
new file mode 100644
index 000000000..3e6738852
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/import … (with File Menu).tmSnippet
@@ -0,0 +1,17 @@
+
+
+
+
+ content
+ @import "${1:`"$TM_BUNDLE_SUPPORT/bin/import_FileMenu.sh" ".j"`}"
+
+ name
+ import "…" (with File Menu)
+ scope
+ source.js.objj
+ tabTrigger
+ impp
+ uuid
+ 9BABD784-3DBE-4DA3-8A70-4E32FC7FDBB8
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/import ….tmSnippet b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/import ….tmSnippet
new file mode 100644
index 000000000..f06d97c36
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Snippets/import ….tmSnippet
@@ -0,0 +1,17 @@
+
+
+
+
+ content
+ @import "${1:}"
+
+ name
+ import "…"
+ scope
+ source.js.objj
+ tabTrigger
+ imp
+ uuid
+ 686B995F-3183-418B-A15F-CA517DFEFE2E
+
+
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Support/bin/import_FileMenu.sh b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Support/bin/import_FileMenu.sh
new file mode 100755
index 000000000..298e062a9
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Support/bin/import_FileMenu.sh
@@ -0,0 +1,36 @@
+EXTENSION="$1"
+
+CURRENTDIR=`dirname $TM_FILEPATH`
+
+if [ -z $TM_PROJECT_DIRECTORY ]; then
+
+ L=$((${#CURRENTDIR}+1))
+
+ MENUITEMS=$(find -s "$CURRENTDIR" -name "*$EXTENSION" | perl -pe "s/^.{$L}(.*?)$/{title=\"\$1\";}/" | paste -sd ',' -)
+ [[ -z $MENUITEMS ]] && exit 200
+ "$DIALOG" -u -p "{menuItems=($MENUITEMS);}" | perl -e 'undef $/;$a=<>;$a=~m/title(.|\n)+?(.*?);print $2;'
+
+else
+
+ FILES=$(find -s "$TM_PROJECT_DIRECTORY" -name "*$EXTENSION")
+
+ FILES=$(echo "$FILES" | perl -pe "s!$CURRENTDIR/!!")
+
+ if [ "$CURRENTDIR" != "$TM_PROJECT_DIRECTORY" ]; then
+ CURRENTDIR=$(dirname $CURRENTDIR)
+ REPLACE=""
+ while [ "$CURRENTDIR" != "$TM_PROJECT_DIRECTORY" ]; do
+ REPLACE="$REPLACE../"
+ FILES=$(echo "$FILES" | perl -pe "s!$CURRENTDIR/!$REPLACE!")
+ CURRENTDIR=$(dirname $CURRENTDIR)
+ done
+ REPLACE="$REPLACE../"
+ FILES=$(echo "$FILES" | perl -pe "s!$CURRENTDIR/!$REPLACE!")
+ fi
+
+ MENUITEMS=$(echo "$FILES" | perl -pe "s/^(.*?)$/{title=\"\$1\";}/" | paste -sd ',' -)
+ [[ -z $MENUITEMS ]] && exit 200
+ "$DIALOG" -u -p "{menuItems=($MENUITEMS);}" | perl -e 'undef $/;$a=<>;$a=~m/title(.|\n)+?(.*?);print $2;'
+
+
+fi
\ No newline at end of file
diff --git a/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Support/help/help.markdown b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Support/help/help.markdown
new file mode 100644
index 000000000..9ec519ece
--- /dev/null
+++ b/Tools/Editors/TextMate/JavaScript Objective-J.tmbundle/Support/help/help.markdown
@@ -0,0 +1,41 @@
+
+
Any feedback about bugs or improvements is highly welcomed!
+
+# Introduction
+
+Cappuccino cappuccino.org is an open source framework that makes it easy to build desktop-caliber applications that run in a web browser.
+
+# Commands
+
+## Run
+
+Run the current cappuccino web application in TextMate's HTML output window.
+
+If you are inside of an Objective-J file (file extension .j) this command will look for a file `index.html` starting at the current folder and upwards within the file hierarchy or if you are working with a project it will look for it at the project's root path.
+
+If the start HTML site differs you can set the shell variable `TM_OBJJ_MASTER_FILE` within a project.
+
+## Run in Browser
+
+Run the current cappuccino web application in the default web browser.
+
+If you are inside of an Objective-J file (file extension .j) this command will look for a file `index.html` starting at the current folder and upwards within the file hierarchy or if you are working with a project it will look for it at the project's root path.
+
+If the start HTML site differs you can set the shell variable `TM_OBJJ_MASTER_FILE` within a project.
+
+# Shell Variables #
+
+## TM_OBJJ_MASTER_FILE ##
+
+This variable contains the path to the application's start HTML site.
+
+
+# Main Bundle Maintainer
+
+***Date: Sep 7 2009***
+
+