mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-11-01 21:07:36 +00:00
Merge remote-tracking branch 'cappuccino/master' into CPArray-arrayByApplyingBlock-replace
This commit is contained in:
commit
0327f6b1ea
17 files changed
+796
-265
No files matched your search
+14
-2
@@ -616,8 +616,20 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePosition];
|
||||
_titleView = [aCoder decodeObjectForKey:CPBoxTitleView] || [CPTextField labelWithTitle:_title];
|
||||
|
||||
_contentView = [aCoder decodeObjectForKey:CPBoxContentView] || [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[self replaceSubview:_contentView with:[self subviews][0]];
|
||||
if (_boxType != CPBoxSeparator)
|
||||
{
|
||||
// FIXME: we have a problem with CIB decoding here.
|
||||
// We should be able to simply add : _contentView = [self subviews][0]
|
||||
// but first box subview seems to be malformed (badly decoded).
|
||||
// For example, when deployed, this view doesn't have its _trackingAreas array initialized.
|
||||
// As a (temporary) workaround, we encode/decode the _contentView property. We then transfer the subview hierarchy
|
||||
// and replace the first (and only) box subview with this _contentView
|
||||
|
||||
_contentView = [aCoder decodeObjectForKey:CPBoxContentView] || [[CPView alloc] initWithFrame:[self bounds]];
|
||||
var malformedContentView = [self subviews][0];
|
||||
[_contentView setSubviews:[malformedContentView subviews]];
|
||||
[self replaceSubview:malformedContentView with:_contentView];
|
||||
}
|
||||
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
+20
-20
@@ -805,13 +805,13 @@ var CPViewHighDPIDrawingEnabled = YES;
|
||||
[_window _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
||||
[aWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
|
||||
}
|
||||
|
||||
|
||||
// View must be removed from the current window viewsWithTrackingAreas
|
||||
if (_window && (_trackingAreas.length > 0))
|
||||
[_window _removeTrackingAreaView:self];
|
||||
|
||||
_window = aWindow;
|
||||
|
||||
|
||||
if (_window)
|
||||
{
|
||||
var owners;
|
||||
@@ -3456,16 +3456,16 @@ setBoundsOrigin:
|
||||
// Consistency check
|
||||
if (!trackingArea || [_trackingAreas containsObjectIdenticalTo:trackingArea])
|
||||
return;
|
||||
|
||||
|
||||
if ([trackingArea view])
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Tracking area has already been added to another view."];
|
||||
|
||||
[_trackingAreas addObject:trackingArea];
|
||||
[trackingArea setView:self];
|
||||
|
||||
|
||||
if (_window)
|
||||
[_window _addTrackingArea:trackingArea];
|
||||
|
||||
|
||||
[trackingArea _updateWindowRect];
|
||||
}
|
||||
|
||||
@@ -3474,14 +3474,14 @@ setBoundsOrigin:
|
||||
// Consistency check
|
||||
if (!trackingArea)
|
||||
return;
|
||||
|
||||
|
||||
if (![_trackingAreas containsObjectIdenticalTo:trackingArea])
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Trying to remove unreferenced trackingArea"];
|
||||
|
||||
[self _removeTrackingArea:trackingArea];
|
||||
}
|
||||
|
||||
/*!
|
||||
/*!
|
||||
Invoked automatically when the view’s geometry changes such that its tracking areas need to be recalculated.
|
||||
|
||||
You should override this method to remove out of date tracking areas and add recomputed tracking areas;
|
||||
@@ -3527,7 +3527,7 @@ setBoundsOrigin:
|
||||
{
|
||||
if (_window)
|
||||
[_window _removeTrackingArea:trackingArea];
|
||||
|
||||
|
||||
[trackingArea setView:nil];
|
||||
[_trackingAreas removeObjectIdenticalTo:trackingArea];
|
||||
}
|
||||
@@ -3535,16 +3535,16 @@ setBoundsOrigin:
|
||||
- (void)_updateTrackingAreas
|
||||
{
|
||||
_inhibitUpdateTrackingAreas = YES;
|
||||
|
||||
|
||||
[self _recursivelyUpdateTrackingAreas];
|
||||
|
||||
|
||||
_inhibitUpdateTrackingAreas = NO;
|
||||
}
|
||||
|
||||
- (void)_recursivelyUpdateTrackingAreas
|
||||
{
|
||||
[self _updateTrackingAreasForOwners:[self _calcTrackingAreaOwners]];
|
||||
|
||||
|
||||
for (var i = 0; i < _subviews.length; i++)
|
||||
[_subviews[i] _recursivelyUpdateTrackingAreas];
|
||||
}
|
||||
@@ -3554,25 +3554,25 @@ setBoundsOrigin:
|
||||
// First search all owners that must be notified
|
||||
// Remark: 99.99% of time, the only owner will be the view itself
|
||||
// In the same time, update the rects of InVisibleRect tracking areas
|
||||
|
||||
|
||||
var owners = [];
|
||||
|
||||
|
||||
for (var i = 0; i < _trackingAreas.length; i++)
|
||||
{
|
||||
var trackingArea = _trackingAreas[i];
|
||||
|
||||
|
||||
if ([trackingArea options] & CPTrackingInVisibleRect)
|
||||
[trackingArea _updateWindowRect];
|
||||
|
||||
|
||||
else
|
||||
{
|
||||
var owner = [trackingArea owner];
|
||||
|
||||
|
||||
if (![owners containsObjectIdenticalTo:owner])
|
||||
[owners addObject:owner];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return owners;
|
||||
}
|
||||
|
||||
@@ -3603,7 +3603,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
CPViewScaleKey = @"CPViewScaleKey",
|
||||
CPViewSizeScaleKey = @"CPViewSizeScaleKey",
|
||||
CPViewIsScaledKey = @"CPViewIsScaledKey",
|
||||
CPViewAppearanceKey = @"CPViewAppearanceKey";
|
||||
CPViewAppearanceKey = @"CPViewAppearanceKey",
|
||||
CPViewTrackingAreasKey = @"CPViewTrackingAreasKey";
|
||||
|
||||
@implementation CPView (CPCoding)
|
||||
@@ -3633,10 +3633,10 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
if (self)
|
||||
{
|
||||
_trackingAreas = [aCoder decodeObjectForKey:CPViewTrackingAreasKey];
|
||||
|
||||
|
||||
if (!_trackingAreas)
|
||||
_trackingAreas = [];
|
||||
|
||||
|
||||
// We have to manually check because it may be 0, so we can't use ||
|
||||
_tag = [aCoder containsValueForKey:CPViewTagKey] ? [aCoder decodeIntForKey:CPViewTagKey] : -1;
|
||||
_identifier = [aCoder decodeObjectForKey:CPReuseIdentifierKey];
|
||||
|
||||
+236
-150
@@ -198,8 +198,13 @@ var CPWindowActionMessageKeys = [
|
||||
CPView _contentView;
|
||||
CPView _toolbarView;
|
||||
|
||||
BOOL _handlingTrackingAreaEvent;
|
||||
BOOL _restartHandlingTrackingAreaEvent;
|
||||
CPArray _previousMouseEnteredStack;
|
||||
CPArray _previousCursorUpdateStack;
|
||||
CPArray _mouseEnteredStack;
|
||||
CPArray _cursorUpdateStack;
|
||||
CPArray _queuedEvents;
|
||||
CPArray _trackingAreaViews;
|
||||
id _activeCursorTrackingArea;
|
||||
CPArray _queuedTrackingEvents;
|
||||
@@ -340,9 +345,14 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
[self setLevel:CPNormalWindowLevel];
|
||||
|
||||
_handlingTrackingAreaEvent = NO;
|
||||
_restartHandlingTrackingAreaEvent = NO;
|
||||
_trackingAreaViews = [];
|
||||
_previousMouseEnteredStack = [];
|
||||
_previousCursorUpdateStack = [];
|
||||
_mouseEnteredStack = [];
|
||||
_cursorUpdateStack = [];
|
||||
_queuedEvents = [];
|
||||
_queuedTrackingEvents = [];
|
||||
_activeCursorTrackingArea = nil;
|
||||
|
||||
@@ -1980,7 +1990,7 @@ CPTexturedBackgroundWindowMask
|
||||
// First, we search for any tracking area requesting CPTrackingEnabledDuringMouseDrag.
|
||||
// At the same time, we update the entered stack.
|
||||
[self _handleTrackingAreaEvent:anEvent];
|
||||
|
||||
|
||||
// Normal mouseDragged workflow
|
||||
if (!_leftMouseDownView)
|
||||
return [[_windowView hitTest:point] mouseDragged:anEvent];
|
||||
@@ -2004,7 +2014,7 @@ CPTexturedBackgroundWindowMask
|
||||
// Ignore mouse moves for parents of sheets
|
||||
if (!_acceptsMouseMovedEvents || sheet)
|
||||
return;
|
||||
|
||||
|
||||
[self _handleTrackingAreaEvent:anEvent];
|
||||
}
|
||||
}
|
||||
@@ -3824,7 +3834,7 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
- (void)_addTrackingAreaView:(CPView)aView
|
||||
{
|
||||
var trackingAreas = [aView trackingAreas];
|
||||
|
||||
|
||||
for (var i = 0; i < trackingAreas.length; i++)
|
||||
[self _addTrackingArea:trackingAreas[i]];
|
||||
}
|
||||
@@ -3832,7 +3842,7 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
- (void)_removeTrackingAreaView:(CPView)aView
|
||||
{
|
||||
var trackingAreas = [aView trackingAreas];
|
||||
|
||||
|
||||
for (var i = 0; i < trackingAreas.length; i++)
|
||||
[self _removeTrackingArea:trackingAreas[i]];
|
||||
}
|
||||
@@ -3840,63 +3850,143 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
- (void)_addTrackingArea:(CPTrackingArea)trackingArea
|
||||
{
|
||||
var trackingAreaView = [trackingArea view];
|
||||
|
||||
|
||||
if (![_trackingAreaViews containsObjectIdenticalTo:trackingAreaView])
|
||||
[_trackingAreaViews addObject:trackingAreaView];
|
||||
|
||||
// If CPTrackingAssumeInside option is set, put the tracking area in the _mouseEnteredStack
|
||||
|
||||
if ([trackingArea options] & CPTrackingAssumeInside)
|
||||
[_mouseEnteredStack addObject:trackingArea];
|
||||
|
||||
// If CPTrackingAssumeInside option is set, insert the tracking area in the events management system
|
||||
// in order to have the first event sent only when mouse leaves the tracking area
|
||||
|
||||
[self _insertTrackingArea:trackingArea assumeInside:([trackingArea options] & CPTrackingAssumeInside)];
|
||||
}
|
||||
|
||||
- (void)_removeTrackingArea:(CPTrackingArea)trackingArea
|
||||
{
|
||||
// If mouse is in the tracking area, we remove it from the stack to avoid to fire a future mouseExited event
|
||||
|
||||
[_mouseEnteredStack removeObjectIdenticalTo:trackingArea];
|
||||
|
||||
|
||||
[self _purgeTrackingArea:trackingArea];
|
||||
|
||||
var trackingAreaView = [trackingArea view];
|
||||
|
||||
|
||||
[_trackingAreaViews removeObjectIdenticalTo:trackingAreaView];
|
||||
}
|
||||
|
||||
- (void)_insertTrackingArea:(CPTrackingArea)trackingArea assumeInside:(BOOL)assumeInside
|
||||
{
|
||||
if (_handlingTrackingAreaEvent)
|
||||
_restartHandlingTrackingAreaEvent = YES;
|
||||
|
||||
if (assumeInside)
|
||||
{
|
||||
if (_handlingTrackingAreaEvent)
|
||||
[_mouseEnteredStack addObject:trackingArea];
|
||||
else
|
||||
[_previousMouseEnteredStack addObject:trackingArea];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_purgeTrackingArea:(CPTrackingArea)trackingArea
|
||||
{
|
||||
if (_handlingTrackingAreaEvent)
|
||||
{
|
||||
[_mouseEnteredStack removeObjectIdenticalTo:trackingArea];
|
||||
|
||||
var i = _queuedEvents.length;
|
||||
|
||||
while (i--)
|
||||
if ([_queuedEvents[i] trackingArea] === trackingArea)
|
||||
[_queuedEvents removeObjectAtIndex:i];
|
||||
|
||||
_cursorUpdateStack = [];
|
||||
_activeCursorTrackingArea = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
[_previousMouseEnteredStack removeObjectIdenticalTo:trackingArea];
|
||||
[_previousCursorUpdateStack removeObjectIdenticalTo:trackingArea];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_handleTrackingAreaEvent:(CPEvent)anEvent
|
||||
{
|
||||
var mouseEnteredStack = [],
|
||||
cursorUpdateStack = [],
|
||||
point = [anEvent locationInWindow],
|
||||
dragging = ([anEvent type] !== CPMouseMoved);
|
||||
_handlingTrackingAreaEvent = YES;
|
||||
|
||||
// Handle mouse entering tracking areas (and calc mouseEnteredStack and cursorUpdateStack)
|
||||
|
||||
[self _handleMouseMovedAndEnteredEventsForEvent:anEvent atPoint:point dragging:dragging mouseEnteredStack:mouseEnteredStack cursorUpdateStack:cursorUpdateStack];
|
||||
var point = [anEvent locationInWindow],
|
||||
dragging = ([anEvent type] !== CPMouseMoved);
|
||||
|
||||
// Handle mouse exiting tracking areas
|
||||
|
||||
[self _handleMouseExitedEventsForEvent:anEvent atPoint:point dragging:dragging mouseEnteredStack:mouseEnteredStack];
|
||||
|
||||
// Cursor update
|
||||
|
||||
if (cursorUpdateStack.length > 0)
|
||||
do
|
||||
{
|
||||
[self _handleCursorUpdateEventsForEvent:anEvent atPoint:point dragging:dragging cursorUpdateStack:cursorUpdateStack];
|
||||
}
|
||||
else if (!dragging)
|
||||
{
|
||||
// Here, we are outsite the window content view tracking area, so let _windowView set the cursor (resize cursor, ...)
|
||||
// Initialize this run
|
||||
_restartHandlingTrackingAreaEvent = NO;
|
||||
|
||||
[_windowView setCursorForLocation:point resizing:NO];
|
||||
_activeCursorTrackingArea = nil;
|
||||
}
|
||||
_mouseEnteredStack = [];
|
||||
_cursorUpdateStack = [];
|
||||
|
||||
// Prepare for next call
|
||||
|
||||
_mouseEnteredStack = mouseEnteredStack;
|
||||
_cursorUpdateStack = cursorUpdateStack;
|
||||
// Important remark: we must queue events to avoid running conditions when a view uses a mouse event to modify view hierarchy
|
||||
|
||||
_queuedEvents = [];
|
||||
|
||||
// Handle mouse entering tracking areas (and calc _mouseEnteredStack and _cursorUpdateStack)
|
||||
|
||||
[self _handleMouseMovedAndEnteredEventsForEvent:anEvent atPoint:point dragging:dragging];
|
||||
|
||||
// Handle mouse exiting tracking areas
|
||||
|
||||
[self _handleMouseExitedEventsForEvent:anEvent atPoint:point dragging:dragging];
|
||||
|
||||
// Cursor update
|
||||
|
||||
if (_cursorUpdateStack.length > 0)
|
||||
{
|
||||
[self _handleCursorUpdateEventsForEvent:anEvent atPoint:point dragging:dragging];
|
||||
}
|
||||
else if (!dragging)
|
||||
{
|
||||
// Here, we are outside the window content view tracking area, so let _windowView set the cursor (resize cursor, ...)
|
||||
|
||||
[_windowView setCursorForLocation:point resizing:NO];
|
||||
_activeCursorTrackingArea = nil;
|
||||
}
|
||||
|
||||
// Send all queued events
|
||||
// Important remark : as an event can modify the view hierarchy, the events queue could be modified while processing it
|
||||
|
||||
while (_queuedEvents.length > 0)
|
||||
{
|
||||
var queuedEvent = _queuedEvents[0],
|
||||
trackingArea = [queuedEvent trackingArea],
|
||||
trackingOwner = [trackingArea owner];
|
||||
|
||||
switch ([queuedEvent type])
|
||||
{
|
||||
case CPMouseEntered:
|
||||
[trackingOwner mouseEntered:queuedEvent];
|
||||
break;
|
||||
|
||||
case CPMouseExited:
|
||||
[trackingOwner mouseExited:queuedEvent];
|
||||
break;
|
||||
|
||||
case CPCursorUpdate:
|
||||
[trackingOwner cursorUpdate:queuedEvent];
|
||||
break;
|
||||
}
|
||||
|
||||
if (queuedEvent === _queuedEvents[0])
|
||||
[_queuedEvents removeObjectAtIndex:0];
|
||||
}
|
||||
|
||||
// Prepare for next call
|
||||
|
||||
_previousMouseEnteredStack = _mouseEnteredStack;
|
||||
_previousCursorUpdateStack = _cursorUpdateStack;
|
||||
}
|
||||
while (_restartHandlingTrackingAreaEvent)
|
||||
|
||||
_handlingTrackingAreaEvent = NO;
|
||||
}
|
||||
|
||||
- (void)_handleMouseMovedAndEnteredEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging mouseEnteredStack:(CPArray)mouseEnteredStack cursorUpdateStack:(CPArray)cursorUpdateStack
|
||||
- (void)_handleMouseMovedAndEnteredEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging
|
||||
{
|
||||
var isKeyWindow = [self isKeyWindow];
|
||||
|
||||
@@ -3923,9 +4013,9 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
continue;
|
||||
}
|
||||
|
||||
[mouseEnteredStack addObject:aTrackingArea];
|
||||
[_mouseEnteredStack addObject:aTrackingArea];
|
||||
|
||||
if ([_mouseEnteredStack containsObjectIdenticalTo:aTrackingArea])
|
||||
if ([_previousMouseEnteredStack containsObjectIdenticalTo:aTrackingArea])
|
||||
{
|
||||
// Mouse was already in this rect so it's a mouseMoved
|
||||
|
||||
@@ -3946,32 +4036,33 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
if (dragging && !(trackingOptions & CPTrackingEnabledDuringMouseDrag))
|
||||
[self _queueTrackingEvent:mouseEnteredEvent];
|
||||
else
|
||||
[[aTrackingArea owner] mouseEntered:mouseEnteredEvent];
|
||||
[_queuedEvents addObject:mouseEnteredEvent];
|
||||
}
|
||||
|
||||
if ((trackingOptions & CPTrackingCursorUpdate) && (trackingImplementedMethods & CPTrackingOwnerImplementsCursorUpdate))
|
||||
[cursorUpdateStack addObject:aTrackingArea];
|
||||
[_cursorUpdateStack addObject:aTrackingArea];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_handleMouseExitedEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging mouseEnteredStack:(CPArray)mouseEnteredStack
|
||||
- (void)_handleMouseExitedEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging
|
||||
{
|
||||
// Search for exited views (were in _mouseEnteredStack but no more in mouseEnteredStack)
|
||||
// Search for exited views (were in _previousMouseEnteredStack but no more in _mouseEnteredStack)
|
||||
|
||||
for (var i = 0; i < _mouseEnteredStack.length; i++)
|
||||
for (var i = 0; i < _previousMouseEnteredStack.length; i++)
|
||||
{
|
||||
var aTrackingArea = _mouseEnteredStack[i],
|
||||
var aTrackingArea = _previousMouseEnteredStack[i],
|
||||
trackingOptions = [aTrackingArea options];
|
||||
|
||||
if ([mouseEnteredStack containsObjectIdenticalTo:aTrackingArea])
|
||||
if ([_mouseEnteredStack containsObjectIdenticalTo:aTrackingArea])
|
||||
continue;
|
||||
|
||||
// Mouse is no more in this area so it's a mouseExited
|
||||
|
||||
if ((trackingOptions & CPTrackingMouseEnteredAndExited) && ([aTrackingArea implementedOwnerMethods] & CPTrackingOwnerImplementsMouseExited))
|
||||
{
|
||||
var mouseExitedEvent = [CPEvent enterExitEventWithType:CPMouseExited
|
||||
var theView = [aTrackingArea owner],
|
||||
mouseExitedEvent = [CPEvent enterExitEventWithType:CPMouseExited
|
||||
location:point
|
||||
modifierFlags:[anEvent modifierFlags]
|
||||
timestamp:[anEvent timestamp]
|
||||
@@ -3983,132 +4074,127 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
if (dragging && !(trackingOptions & CPTrackingEnabledDuringMouseDrag))
|
||||
[self _queueTrackingEvent:mouseExitedEvent];
|
||||
else
|
||||
[[aTrackingArea owner] mouseExited:mouseExitedEvent];
|
||||
[_queuedEvents addObject:mouseExitedEvent];
|
||||
}
|
||||
|
||||
// If this is the active cursor area, we reset _cursorUpdateStack so a new active area will be computed
|
||||
// If this is the active cursor area, we reset _previousCursorUpdateStack so a new active area will be computed
|
||||
|
||||
if (aTrackingArea === _activeCursorTrackingArea)
|
||||
{
|
||||
_cursorUpdateStack = [];
|
||||
_previousCursorUpdateStack = [];
|
||||
_activeCursorTrackingArea = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_handleCursorUpdateEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging cursorUpdateStack:(CPArray)cursorUpdateStack
|
||||
- (void)_handleCursorUpdateEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging
|
||||
{
|
||||
var overlappingTrackingAreas = [];
|
||||
|
||||
for (var i = 0; i < cursorUpdateStack.length; i++)
|
||||
for (var i = 0; i < _cursorUpdateStack.length; i++)
|
||||
{
|
||||
var aTrackingArea = cursorUpdateStack[i];
|
||||
var aTrackingArea = _cursorUpdateStack[i];
|
||||
|
||||
if ((![_cursorUpdateStack containsObjectIdenticalTo:aTrackingArea]) || (aTrackingArea === _activeCursorTrackingArea))
|
||||
if ((![_previousCursorUpdateStack containsObjectIdenticalTo:aTrackingArea]) || (aTrackingArea === _activeCursorTrackingArea))
|
||||
[overlappingTrackingAreas addObject:aTrackingArea];
|
||||
}
|
||||
|
||||
var nbOverlappingTrackingAreas = overlappingTrackingAreas.length;
|
||||
var frontmostTrackingArea = overlappingTrackingAreas[0],
|
||||
frontmostView = [frontmostTrackingArea view];
|
||||
|
||||
if (nbOverlappingTrackingAreas > 0)
|
||||
for (var i = 1; i < overlappingTrackingAreas.length; i++)
|
||||
{
|
||||
var frontmostTrackingArea = overlappingTrackingAreas[0],
|
||||
frontmostView = [frontmostTrackingArea view];
|
||||
var aTrackingArea = overlappingTrackingAreas[i],
|
||||
aView = [aTrackingArea view];
|
||||
|
||||
for (var i = 1; i < nbOverlappingTrackingAreas; i++)
|
||||
// First, if aView is _windowView, skip to next overlapping tracking area
|
||||
// as _windowView can't be the frontmost view if there's multiple overlapping tracking areas.
|
||||
|
||||
if (aView === _windowView)
|
||||
continue;
|
||||
|
||||
// Then, if frontmostView is _windowView, aView must become frontmostView
|
||||
|
||||
if (frontmostView === _windowView)
|
||||
{
|
||||
var aTrackingArea = overlappingTrackingAreas[i],
|
||||
aView = [aTrackingArea view];
|
||||
frontmostTrackingArea = aTrackingArea;
|
||||
frontmostView = aView;
|
||||
|
||||
// First, if aView is _windowView, skip to next overlapping tracking area
|
||||
// as _windowView can't be the frontmost view if there's multiple overlapping tracking areas.
|
||||
|
||||
if (aView === _windowView)
|
||||
continue;
|
||||
|
||||
// Then, if frontmostView is _windowView, aView must become frontmostView
|
||||
|
||||
if (frontmostView === _windowView)
|
||||
{
|
||||
frontmostTrackingArea = aTrackingArea;
|
||||
frontmostView = aView;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Next verify if aView is a subview of frontmostView
|
||||
// If so, it's our new frontmost view
|
||||
|
||||
var searchingView = aView;
|
||||
|
||||
while ((searchingView !== _contentView) && ([searchingView superview] !== frontmostView))
|
||||
searchingView = [searchingView superview];
|
||||
|
||||
if (searchingView !== _contentView)
|
||||
{
|
||||
frontmostTrackingArea = aTrackingArea;
|
||||
frontmostView = aView;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// aView is not a subview of frontmostView
|
||||
// Search in view hierarchy which one will be over the other
|
||||
// (this is done by comparing their draw order)
|
||||
|
||||
var firstView = frontmostView,
|
||||
firstSuperview = [firstView superview];
|
||||
|
||||
while (firstView !== _contentView)
|
||||
{
|
||||
var secondView = aView,
|
||||
secondSuperview = [secondView superview];
|
||||
|
||||
while ((secondSuperview !== _contentView) && (firstSuperview !== secondSuperview))
|
||||
{
|
||||
secondView = secondSuperview;
|
||||
secondSuperview = [secondView superview];
|
||||
}
|
||||
|
||||
if (firstSuperview === secondSuperview)
|
||||
break;
|
||||
|
||||
firstView = firstSuperview;
|
||||
firstSuperview = [firstView superview];
|
||||
}
|
||||
|
||||
if (firstSuperview !== secondSuperview)
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Problem with view hierarchy"];
|
||||
|
||||
var firstSuperviewSubviews = [firstSuperview subviews],
|
||||
firstViewIndex = [firstSuperviewSubviews indexOfObject:firstView],
|
||||
secondViewIndex = [firstSuperviewSubviews indexOfObject:secondView];
|
||||
|
||||
if (secondViewIndex > firstViewIndex)
|
||||
{
|
||||
frontmostTrackingArea = aTrackingArea;
|
||||
frontmostView = aView;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (frontmostTrackingArea !== _activeCursorTrackingArea)
|
||||
// Next verify if aView is a subview of frontmostView
|
||||
// If so, it's our new frontmost view
|
||||
|
||||
var searchingView = aView;
|
||||
|
||||
while ((searchingView !== _contentView) && ([searchingView superview] !== frontmostView))
|
||||
searchingView = [searchingView superview];
|
||||
|
||||
if (searchingView !== _contentView)
|
||||
{
|
||||
var cursorUpdateEvent = [CPEvent enterExitEventWithType:CPCursorUpdate
|
||||
location:point
|
||||
modifierFlags:[anEvent modifierFlags]
|
||||
timestamp:[anEvent timestamp]
|
||||
windowNumber:_windowNumber
|
||||
context:nil
|
||||
eventNumber:-1
|
||||
trackingArea:frontmostTrackingArea];
|
||||
frontmostTrackingArea = aTrackingArea;
|
||||
frontmostView = aView;
|
||||
|
||||
if (dragging)
|
||||
[self _queueTrackingEvent:cursorUpdateEvent];
|
||||
else
|
||||
[[frontmostTrackingArea owner] cursorUpdate:cursorUpdateEvent];
|
||||
|
||||
_activeCursorTrackingArea = frontmostTrackingArea;
|
||||
continue;
|
||||
}
|
||||
|
||||
// aView is not a subview of frontmostView
|
||||
// Search in view hierarchy which one will be over the other
|
||||
// (this is done by comparing their draw order)
|
||||
|
||||
var firstView = frontmostView,
|
||||
firstSuperview = [firstView superview];
|
||||
|
||||
while (firstView !== _contentView)
|
||||
{
|
||||
var secondView = aView,
|
||||
secondSuperview = [secondView superview];
|
||||
|
||||
while ((secondSuperview !== _contentView) && (firstSuperview !== secondSuperview))
|
||||
{
|
||||
secondView = secondSuperview;
|
||||
secondSuperview = [secondView superview];
|
||||
}
|
||||
|
||||
if (firstSuperview === secondSuperview)
|
||||
break;
|
||||
|
||||
firstView = firstSuperview;
|
||||
firstSuperview = [firstView superview];
|
||||
}
|
||||
|
||||
if (firstSuperview !== secondSuperview)
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Problem with view hierarchy"];
|
||||
|
||||
var firstSuperviewSubviews = [firstSuperview subviews],
|
||||
firstViewIndex = [firstSuperviewSubviews indexOfObject:firstView],
|
||||
secondViewIndex = [firstSuperviewSubviews indexOfObject:secondView];
|
||||
|
||||
if (secondViewIndex > firstViewIndex)
|
||||
{
|
||||
frontmostTrackingArea = aTrackingArea;
|
||||
frontmostView = aView;
|
||||
}
|
||||
}
|
||||
|
||||
if (frontmostTrackingArea !== _activeCursorTrackingArea)
|
||||
{
|
||||
var cursorUpdateEvent = [CPEvent enterExitEventWithType:CPCursorUpdate
|
||||
location:point
|
||||
modifierFlags:[anEvent modifierFlags]
|
||||
timestamp:[anEvent timestamp]
|
||||
windowNumber:_windowNumber
|
||||
context:nil
|
||||
eventNumber:-1
|
||||
trackingArea:frontmostTrackingArea];
|
||||
|
||||
if (dragging)
|
||||
[self _queueTrackingEvent:cursorUpdateEvent];
|
||||
else
|
||||
[_queuedEvents addObject:cursorUpdateEvent];
|
||||
|
||||
_activeCursorTrackingArea = frontmostTrackingArea;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4181,7 +4267,7 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
case CPMouseExited:
|
||||
[trackingOwner mouseExited:queuedEvent];
|
||||
break;
|
||||
|
||||
|
||||
case CPCursorUpdate:
|
||||
[trackingOwner updateTrackingAreas];
|
||||
|
||||
|
||||
@@ -28,3 +28,5 @@
|
||||
@import "_CPAggregateExpression.j"
|
||||
@import "_CPSetExpression.j"
|
||||
@import "_CPSubqueryExpression.j"
|
||||
@import "_CPBlockExpression.j"
|
||||
@import "_CPConditionalExpression.j"
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
@implementation _CPAggregateExpression : CPExpression
|
||||
{
|
||||
CPArray _aggregate;
|
||||
CPArray _aggregate @accessors(getter=collection);
|
||||
}
|
||||
|
||||
- (id)initWithAggregate:(CPArray)collection
|
||||
@@ -49,11 +49,6 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)collection
|
||||
{
|
||||
return _aggregate;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
return [_aggregate arrayByApplyingBlock:function(exp, _)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* _CPBlockExpression.j
|
||||
*
|
||||
* Created by cacaodev.
|
||||
* Copyright 2015.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "_CPExpression.j"
|
||||
|
||||
@implementation _CPBlockExpression : CPExpression
|
||||
{
|
||||
Function _block @accessors(getter=expressionBlock);
|
||||
CPArray _arguments @accessors(getter=arguments);
|
||||
}
|
||||
|
||||
- (id)initWithBlock:(Function)aBlock arguments:(CPArray)arguments
|
||||
{
|
||||
self = [super initWithExpressionType:CPBlockExpressionType];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_block = aBlock;
|
||||
_arguments = arguments;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (self === object)
|
||||
return YES;
|
||||
|
||||
if (object === nil || object.isa !== self.isa || [object expressionBlock] !== _block || ![[object arguments] isEqual:_arguments])
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
var args = [];
|
||||
|
||||
[_arguments enumerateObjectsUsingBlock:function(exp, idx)
|
||||
{
|
||||
[args addObject:[exp expressionValueWithObject:object context:context]];
|
||||
}];
|
||||
|
||||
return _block(object, args, context);
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)bindings
|
||||
{
|
||||
var args = [];
|
||||
|
||||
[_arguments enumerateObjectsUsingBlock:function(exp, idx)
|
||||
{
|
||||
[args addObject:[exp _expressionWithSubstitutionVariables:bindings]];
|
||||
}];
|
||||
|
||||
return [[_CPBlockExpression alloc] initWithBlock:_block arguments:args];
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [CPString stringWithFormat:@"Block(function, %@)", [_arguments description]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* _CPConditionalExpression.j
|
||||
*
|
||||
* Created by cacaodev.
|
||||
* Copyright 2015.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
@import "_CPPredicate.j"
|
||||
@import "_CPExpression.j"
|
||||
|
||||
@implementation _CPConditionalExpression : CPExpression
|
||||
{
|
||||
CPPredicate _predicate @accessors(getter=predicate);
|
||||
CPExpression _trueExpression @accessors(getter=trueExpression);
|
||||
CPExpression _falseExpression @accessors(getter=falseExpression);
|
||||
}
|
||||
|
||||
- (id)initWithPredicate:(CPPredicate)aPredicate trueExpression:(CPExpression)trueExpression falseExpression:(CPExpression)falseExpression
|
||||
{
|
||||
self = [super initWithExpressionType:CPConditionalExpressionType];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_predicate = aPredicate;
|
||||
_trueExpression = trueExpression;
|
||||
_falseExpression = falseExpression;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (self === object)
|
||||
return YES;
|
||||
|
||||
if (object === nil || object.isa !== self.isa || ![[object predicate] isEqual:_predicate] || ![[object trueExpression] isEqual:_trueExpression] || ![[object falseExpression] isEqual:_falseExpression])
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
var eval = [_predicate evaluateWithObject:object substitutionVariables:context],
|
||||
exp = eval ? _trueExpression : _falseExpression;
|
||||
|
||||
return [exp expressionValueWithObject:object context:context];
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)bindings
|
||||
{
|
||||
var predicate = [_predicate predicateWithSubstitutionVariables:bindings],
|
||||
trueExp = [_trueExpression _expressionWithSubstitutionVariables:bindings],
|
||||
falseExp = [_falseExpression _expressionWithSubstitutionVariables:bindings];
|
||||
|
||||
return [[_CPConditionalExpression alloc] initWithPredicate:predicate trueExpression:trueExp falseExpression:falseExp];
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [CPString stringWithFormat:@"TERNARY(%@,%@,%@)", [_predicate predicateFormat], [_trueExpression description], [_falseExpression description]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
@implementation _CPConstantValueExpression : CPExpression
|
||||
{
|
||||
id _value;
|
||||
id _value @accessors(getter=constantValue);
|
||||
}
|
||||
|
||||
- (id)initWithValue:(id)value
|
||||
@@ -51,11 +51,6 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)constantValue
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
return _value;
|
||||
|
||||
@@ -65,6 +65,14 @@ CPIntersectSetExpressionType = 8;
|
||||
An expression that combines two nested expression results by set subtraction.
|
||||
*/
|
||||
CPMinusSetExpressionType = 9;
|
||||
/*!
|
||||
An expression that returns the result of evaluating a block.
|
||||
*/
|
||||
CPBlockExpressionType = 10;
|
||||
/*!
|
||||
An expression that returns an expression that depends on the evaluation of a predicate.
|
||||
*/
|
||||
CPConditionalExpressionType = 11;
|
||||
|
||||
/*!
|
||||
@ingroup foundation
|
||||
@@ -259,6 +267,32 @@ CPMinusSetExpressionType = 9;
|
||||
return [[_CPSubqueryExpression alloc] initWithExpression:expression usingIteratorVariable:variable predicate:predicate];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns Creates an NSExpression object that will use the Block for evaluating objects.
|
||||
@param aBlock The Block is applied to the object to be evaluated.
|
||||
|
||||
The Block takes three arguments and returns a value:
|
||||
|
||||
evaluatedObject
|
||||
The object to be evaluated.
|
||||
expressions
|
||||
An array of predicate expressions that evaluates to a collection.
|
||||
context
|
||||
A dictionary that the expression can use to store temporary state for one predicate evaluation.
|
||||
|
||||
@discussion Note that context is mutable, and that it can only be accessed during the evaluation of the expression.
|
||||
@param arguments An array containing NSExpression objects that will be used as parameters during the invocation of the block.
|
||||
*/
|
||||
+ (CPExpression)expressionForBlock:(Function)aBlock arguments:(CPArray)args
|
||||
{
|
||||
return [[_CPBlockExpression alloc] initWithBlock:aBlock arguments:args];
|
||||
}
|
||||
|
||||
+ (CPExpression)expressionForConditional:(CPPredicate)aPredicate trueExpression:(CPExpression)trueExpression falseExpression:(CPExpression)falseExpression
|
||||
{
|
||||
return [[_CPConditionalExpression alloc] initWithPredicate:aPredicate trueExpression:trueExpression falseExpression:falseExpression];
|
||||
}
|
||||
|
||||
// Getting Information About an Expression
|
||||
/*!
|
||||
Returns the expression type for the receiver.
|
||||
@@ -316,7 +350,7 @@ CPMinusSetExpressionType = 9;
|
||||
|
||||
/*!
|
||||
Returns the arguments for the receiver.
|
||||
@return The arguments for the receiver—that is, the array of expressions that will be passed as parameters during invocation of the selector on the operand of a function expression.
|
||||
@return The arguments for the receiver—that is, the array of expressions that will be passed as parameters during invocation of the selector on the operand of a function expression or as a parameter of the block of a block expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPArray)arguments
|
||||
@@ -337,8 +371,8 @@ CPMinusSetExpressionType = 9;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the predicate in a subquery expression.
|
||||
@return The predicate in a subquery expression..
|
||||
Returns the predicate in a subquery expression or a conditional expression.
|
||||
@return The predicate in a subquery expression or a conditional expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPPredicate)predicate
|
||||
@@ -380,6 +414,39 @@ CPMinusSetExpressionType = 9;
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the block of a block expression.
|
||||
@return The block of a block expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (Function)expressionBlock
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the true expression of a conditional expression.
|
||||
@return The true expression of a conditional expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPExpression)trueExpression
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the false expression of a conditional expression.
|
||||
@return The false expression of a conditional expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPExpression)falseExpression
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
|
||||
{
|
||||
return self;
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
|
||||
@implementation _CPFunctionExpression : CPExpression
|
||||
{
|
||||
CPExpression _operand;
|
||||
CPExpression _operand @accessors(getter=operand);
|
||||
SEL _selector;
|
||||
CPArray _arguments;
|
||||
CPArray _arguments @accessors(getter=arguments);
|
||||
int _argc;
|
||||
int _maxargs;
|
||||
}
|
||||
@@ -88,16 +88,6 @@
|
||||
return [self _function];
|
||||
}
|
||||
|
||||
- (CPArray)arguments
|
||||
{
|
||||
return _arguments;
|
||||
}
|
||||
|
||||
- (CPExpression)operand
|
||||
{
|
||||
return _operand;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
var target = [_operand expressionValueWithObject:object context:context],
|
||||
|
||||
@@ -744,16 +744,43 @@
|
||||
|
||||
if (![self scanString:@"," intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
variableExpression = [self parseExpression];
|
||||
|
||||
if (![self scanString:@"," intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
subpredicate = [self parsePredicate];
|
||||
|
||||
if (![self scanString:@")" intoString:NULL])
|
||||
CPRaiseParseError(self, @"predicate");
|
||||
|
||||
return [[_CPSubqueryExpression alloc] initWithExpression:collection usingIteratorExpression:variableExpression predicate:subpredicate];
|
||||
}
|
||||
|
||||
if ([self scanString:@"TERNARY" intoString:NULL])
|
||||
{
|
||||
if (![self scanString:@"(" intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
var predicate = [self parsePredicate],
|
||||
trueExpression,
|
||||
falseExpression;
|
||||
|
||||
if (![self scanString:@"," intoString:NULL])
|
||||
CPRaiseParseError(self, @"predicate");
|
||||
|
||||
trueExpression = [self parseExpression];
|
||||
|
||||
if (![self scanString:@"," intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
falseExpression = [self parseExpression];
|
||||
|
||||
if (![self scanString:@")" intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
return [[_CPSubqueryExpression alloc] initWithExpression:collection usingIteratorExpression:variableExpression predicate:subpredicate];
|
||||
return [CPExpression expressionForConditional:predicate trueExpression:trueExpression falseExpression:falseExpression];
|
||||
}
|
||||
|
||||
if ([self scanString:@"FUNCTION" intoString:NULL])
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
@implementation _CPSetExpression : CPExpression
|
||||
{
|
||||
CPExpression _left;
|
||||
CPExpression _right;
|
||||
CPExpression _left @accessors(getter=leftExpression);
|
||||
CPExpression _right @accessors(getter=rightExpression);
|
||||
}
|
||||
|
||||
- (id)initWithType:(int)type left:(CPExpression)left right:(CPExpression)right
|
||||
@@ -88,16 +88,6 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPExpression)leftExpression
|
||||
{
|
||||
return _left;
|
||||
}
|
||||
|
||||
- (CPExpression)rightExpression
|
||||
{
|
||||
return _right;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
var desc;
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
@implementation _CPSubqueryExpression : CPExpression
|
||||
{
|
||||
CPExpression _collection;
|
||||
CPExpression _collection @accessors(getter=collection);
|
||||
CPExpression _variableExpression;
|
||||
CPPredicate _subpredicate;
|
||||
CPPredicate _subpredicate @accessors(getter=predicate);
|
||||
}
|
||||
|
||||
- (id)initWithExpression:(CPExpression)collection usingIteratorVariable:(CPString)variable predicate:(CPPredicate)subpredicate
|
||||
@@ -81,21 +81,11 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPExpression)collection
|
||||
{
|
||||
return _collection;
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
return [[_CPSubqueryExpression alloc] initWithExpression:[_collection copy] usingIteratorExpression:[_variableExpression copy] predicate:[_subpredicate copy]];
|
||||
}
|
||||
|
||||
- (CPPredicate)predicate
|
||||
{
|
||||
return _subpredicate;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [self predicateFormat];
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
@implementation _CPVariableExpression : CPExpression
|
||||
{
|
||||
CPString _variable;
|
||||
CPString _variable @accessors(getter=variable);
|
||||
}
|
||||
|
||||
- (id)initWithVariable:(CPString)variable
|
||||
@@ -54,11 +54,6 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPString)variable
|
||||
{
|
||||
return _variable;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:object context:(CPDictionary)context
|
||||
{
|
||||
var expression = [self _expressionWithSubstitutionVariables:context];
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ with the complexities of traditional web technologies like HTML, CSS, or even
|
||||
the DOM. The unpleasantries of building complex cross browser applications are
|
||||
abstracted away for you.
|
||||
|
||||
For more information, see <http://cappuccino-project.org>.
|
||||
For more information, see <http://cappuccino-project.org>. Follow [@cappuccino](https://twitter.com/cappuccino) on Twitter for updates on the project.
|
||||
|
||||
System Requirements
|
||||
-------------------
|
||||
|
||||
+212
-34
@@ -1127,34 +1127,32 @@ var updateTrackingAreasCalls,
|
||||
|
||||
// Complex test for cursor update frontmost tracking area detection
|
||||
|
||||
var viewA = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(0, 30, 40, 40)];
|
||||
var viewB = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(30, 20, 40, 40)];
|
||||
var viewC = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(10, 0, 40, 40)];
|
||||
var viewA = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(0, 30, 40, 40)],
|
||||
viewB = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(30, 20, 40, 40)],
|
||||
viewC = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(10, 0, 40, 40)];
|
||||
|
||||
[contentView setSubviews:[CPArray array]];
|
||||
[contentView addSubview:viewA];
|
||||
[contentView addSubview:viewB];
|
||||
[contentView addSubview:viewC];
|
||||
|
||||
var subviewA = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(20, 0, 20, 20)];
|
||||
var subviewB = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
|
||||
var subviewC = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(0, 20, 40, 20)];
|
||||
var subviewA = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(20, 0, 20, 20)],
|
||||
subviewB = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)],
|
||||
subviewC = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(0, 20, 40, 20)];
|
||||
|
||||
[viewA addSubview:subviewA];
|
||||
[viewB addSubview:subviewB];
|
||||
[viewC addSubview:subviewC];
|
||||
|
||||
var options = CPTrackingCursorUpdate | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect;
|
||||
var options2 = CPTrackingMouseEnteredAndExited | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect;
|
||||
var options3 = CPTrackingCursorUpdate | CPTrackingActiveInActiveApp;
|
||||
|
||||
var viewATrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewA userInfo:nil];
|
||||
var viewBTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewB userInfo:nil];
|
||||
var viewCTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options2 owner:viewC userInfo:nil];
|
||||
|
||||
var subviewATrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:subviewA userInfo:nil];
|
||||
var subviewBTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:subviewB userInfo:nil];
|
||||
var subviewCtrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMake(20, 0, 20, 20) options:options3 owner:subviewC userInfo:nil];
|
||||
var options = CPTrackingCursorUpdate | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect,
|
||||
options2 = CPTrackingMouseEnteredAndExited | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect,
|
||||
options3 = CPTrackingCursorUpdate | CPTrackingActiveInActiveApp,
|
||||
viewATrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewA userInfo:nil],
|
||||
viewBTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewB userInfo:nil],
|
||||
viewCTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options2 owner:viewC userInfo:nil],
|
||||
subviewATrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:subviewA userInfo:nil],
|
||||
subviewBTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:subviewB userInfo:nil],
|
||||
subviewCtrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMake(20, 0, 20, 20) options:options3 owner:subviewC userInfo:nil];
|
||||
|
||||
[viewA addTrackingArea:viewATrackingArea];
|
||||
[viewB addTrackingArea:viewBTrackingArea];
|
||||
@@ -1222,18 +1220,18 @@ var updateTrackingAreasCalls,
|
||||
|
||||
// Cursor tests
|
||||
|
||||
var viewA = [[CPTrackingAreaViewWithCursorUpdate alloc] initWithFrame:CGRectMake(20, 20, 40, 40)];
|
||||
var viewB = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(10, 10, 80, 80)];
|
||||
var viewC = [[CPTrackingAreaViewWithoutCursorUpdate alloc] initWithFrame:CGRectMake(10, 10, 80, 80)];
|
||||
var viewA = [[CPTrackingAreaViewWithCursorUpdate alloc] initWithFrame:CGRectMake(20, 20, 40, 40)],
|
||||
viewB = [[CPTrackingAreaView alloc] initWithFrame:CGRectMake(10, 10, 80, 80)],
|
||||
viewC = [[CPTrackingAreaViewWithoutCursorUpdate alloc] initWithFrame:CGRectMake(10, 10, 80, 80)];
|
||||
|
||||
[contentView setSubviews:[CPArray array]];
|
||||
[contentView addSubview:viewA];
|
||||
|
||||
var options = CPTrackingCursorUpdate | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect;
|
||||
|
||||
var viewATrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewA userInfo:nil];
|
||||
var viewBTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewB userInfo:nil];
|
||||
var viewCTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewC userInfo:nil];
|
||||
var viewATrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewA userInfo:nil],
|
||||
viewBTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewB userInfo:nil],
|
||||
viewCTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewC userInfo:nil];
|
||||
|
||||
[viewA addTrackingArea:viewATrackingArea];
|
||||
[viewB addTrackingArea:viewBTrackingArea];
|
||||
@@ -1360,6 +1358,141 @@ var updateTrackingAreasCalls,
|
||||
|
||||
}
|
||||
|
||||
- (void)testTrackingAreasLiveViewHierarchyModification
|
||||
{
|
||||
// 1. viewB inside viewA with mouseEntered removing itself
|
||||
|
||||
var viewA = [[CPTrackingAreaViewWithCursorUpdate alloc] initWithFrame:CGRectMake(20, 20, 40, 40)]
|
||||
viewB = [[CPTrackingAreaViewLiveRemoval alloc] initWithFrame:CGRectMake(10, 10, 20, 20)];
|
||||
|
||||
[[window contentView] setSubviews:[CPArray arrayWithObject:viewA]];
|
||||
[viewA addSubview:viewB];
|
||||
|
||||
var options = CPTrackingMouseEnteredAndExited | CPTrackingCursorUpdate | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect,
|
||||
viewATrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewA userInfo:nil],
|
||||
viewBTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewB userInfo:nil];
|
||||
|
||||
[viewA addTrackingArea:viewATrackingArea];
|
||||
[viewB addTrackingArea:viewBTrackingArea];
|
||||
|
||||
// Step 1.1 : enter viewA
|
||||
|
||||
[self moveMouseAtPoint:CGPointMake(25, 25) dragging:NO];
|
||||
|
||||
[self assert:1 equals:mouseEnteredCalls message:@"1.1 There should be one and only one mouseEntered call"];
|
||||
[self assert:0 equals:mouseExitedCalls message:@"1.1 There should be no mouseExited call"];
|
||||
[self assert:0 equals:mouseMovedCalls message:@"1.1 There should be no mouseMoved call"];
|
||||
[self assert:1 equals:cursorUpdateCalls message:@"1.1 There should be one and only one cursorUpdate call"];
|
||||
|
||||
[self assert:viewA equals:involvedViewForMouseEntered message:@"1.1 viewA should receive mouseEntered"];
|
||||
[self assert:viewA equals:involvedViewForCursorUpdate message:@"1.1 viewA should receive cursorUpdate"];
|
||||
|
||||
// Step 1.2 : enter viewB
|
||||
|
||||
[self moveMouseAtPoint:CGPointMake(40, 40) dragging:NO];
|
||||
|
||||
[self assert:1 equals:mouseEnteredCalls message:@"1.2 There should be one and only one mouseEntered call"];
|
||||
[self assert:0 equals:mouseExitedCalls message:@"1.2 There should be no mouseExited call"];
|
||||
[self assert:0 equals:mouseMovedCalls message:@"1.2 There should be no mouseMoved call"];
|
||||
[self assert:0 equals:cursorUpdateCalls message:@"1.2 There should be no cursorUpdate call"];
|
||||
|
||||
[self assert:viewB equals:involvedViewForMouseEntered message:@"1.2 viewB should receive mouseEntered"];
|
||||
|
||||
// Step 1.3 : move back to viewA (there should be no more viewB)
|
||||
|
||||
[self moveMouseAtPoint:CGPointMake(25, 25) dragging:NO];
|
||||
|
||||
[self assert:0 equals:mouseEnteredCalls message:@"1.3 There should be no mouseEntered call"];
|
||||
[self assert:0 equals:mouseExitedCalls message:@"1.3 There should be no mouseExited call"];
|
||||
[self assert:0 equals:mouseMovedCalls message:@"1.3 There should be no mouseMoved call"];
|
||||
[self assert:1 equals:cursorUpdateCalls message:@"1.3 There should be one and only one cursorUpdate call"];
|
||||
|
||||
[self assert:viewA equals:involvedViewForCursorUpdate message:@"1.3 viewA should receive cursorUpdate"];
|
||||
|
||||
// Step 1.4 : exit viewA
|
||||
|
||||
[self moveMouseAtPoint:CGPointMake(5, 5) dragging:NO];
|
||||
|
||||
[self assert:0 equals:mouseEnteredCalls message:@"1.4 There should be one and only one mouseEntered call"];
|
||||
[self assert:1 equals:mouseExitedCalls message:@"1.4 There should be one and only on mouseExited call"];
|
||||
[self assert:0 equals:mouseMovedCalls message:@"1.4 There should be no mouseMoved call"];
|
||||
[self assert:0 equals:cursorUpdateCalls message:@"1.4 There should be no cursorUpdate call"];
|
||||
|
||||
[self assert:viewA equals:involvedViewForMouseExited message:@"1.4 viewA should receive mouseExited"];
|
||||
|
||||
// 2. viewA with mouseEntered adding viewB inside it. Testing if viewB receive mouseEntered & cursorUpdate
|
||||
|
||||
var viewA = [[CPTrackingAreaViewLiveAddition alloc] initWithFrame:CGRectMake(20, 20, 40, 40)];
|
||||
|
||||
[[window contentView] setSubviews:[CPArray arrayWithObject:viewA]];
|
||||
|
||||
var options = CPTrackingMouseEnteredAndExited | CPTrackingCursorUpdate | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect,
|
||||
viewATrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewA userInfo:nil];
|
||||
|
||||
[viewA addTrackingArea:viewATrackingArea];
|
||||
|
||||
// Step 2.1 : enter viewA (then add viewB thus enter also viewB)
|
||||
|
||||
[self moveMouseAtPoint:CGPointMake(25, 25) dragging:NO];
|
||||
|
||||
[self assert:2 equals:mouseEnteredCalls message:@"2.1 There should be two mouseEntered calls"];
|
||||
[self assert:0 equals:mouseExitedCalls message:@"2.1 There should be no mouseExited call"];
|
||||
[self assert:0 equals:mouseMovedCalls message:@"2.1 There should be no mouseMoved call"];
|
||||
[self assert:2 equals:cursorUpdateCalls message:@"2.1 There should be two cursorUpdate calls"];
|
||||
|
||||
[self assert:[[viewA subviews] firstObject] equals:involvedViewForMouseEntered message:@"2.1 viewB should receive mouseEntered"];
|
||||
[self assert:[[viewA subviews] firstObject] equals:involvedViewForCursorUpdate message:@"2.1 viewB should receive cursorUpdate"];
|
||||
[self assert:[CPCursor crosshairCursor] equals:[CPCursor currentCursor] message:@"2.1 Final cursor should be crosshair cursor, determined by viewB"];
|
||||
|
||||
// Step 2.2 : exit viewA (thus also viewB)
|
||||
|
||||
[self moveMouseAtPoint:CGPointMake(5, 5) dragging:NO];
|
||||
|
||||
[self assert:0 equals:mouseEnteredCalls message:@"2.2 There should be no mouseEntered calls"];
|
||||
[self assert:2 equals:mouseExitedCalls message:@"2.2 There should be two mouseExited call"];
|
||||
[self assert:0 equals:mouseMovedCalls message:@"2.2 There should be no mouseMoved call"];
|
||||
[self assert:0 equals:cursorUpdateCalls message:@"2.2 There should be no cursorUpdate calls"];
|
||||
|
||||
[self assert:[[viewA subviews] firstObject] equals:involvedViewForMouseExited message:@"2.2 viewB should receive mouseExited"];
|
||||
[self assert:[CPCursor arrowCursor] equals:[CPCursor currentCursor] message:@"2.2 Cursor should be an arrow"];
|
||||
|
||||
// 3. viewA with mouseEntered adding viewB inside it BUT with CPTrackingAssumeInside. Testing if viewB receive only cursorUpdate
|
||||
|
||||
var viewA = [[CPTrackingAreaViewLiveAddition2 alloc] initWithFrame:CGRectMake(20, 20, 40, 40)];
|
||||
|
||||
[[window contentView] setSubviews:[CPArray arrayWithObject:viewA]];
|
||||
|
||||
var options = CPTrackingMouseEnteredAndExited | CPTrackingCursorUpdate | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect,
|
||||
viewATrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:options owner:viewA userInfo:nil];
|
||||
|
||||
[viewA addTrackingArea:viewATrackingArea];
|
||||
|
||||
// Step 3.1 : enter viewA (then add viewB thus enter also viewB)
|
||||
|
||||
[self moveMouseAtPoint:CGPointMake(25, 25) dragging:NO];
|
||||
|
||||
[self assert:1 equals:mouseEnteredCalls message:@"3.1 There should be two mouseEntered calls"];
|
||||
[self assert:0 equals:mouseExitedCalls message:@"3.1 There should be no mouseExited call"];
|
||||
[self assert:0 equals:mouseMovedCalls message:@"3.1 There should be no mouseMoved call"];
|
||||
[self assert:2 equals:cursorUpdateCalls message:@"3.1 There should be two cursorUpdate calls"];
|
||||
|
||||
[self assert:viewA equals:involvedViewForMouseEntered message:@"3.1 viewB should receive mouseEntered"];
|
||||
[self assert:[[viewA subviews] firstObject] equals:involvedViewForCursorUpdate message:@"3.1 viewB should receive cursorUpdate"];
|
||||
[self assert:[CPCursor crosshairCursor] equals:[CPCursor currentCursor] message:@"3.1 Final cursor should be crosshair cursor, determined by viewB"];
|
||||
|
||||
// Step 3.2 : exit viewA (thus also viewB)
|
||||
|
||||
[self moveMouseAtPoint:CGPointMake(5, 5) dragging:NO];
|
||||
|
||||
[self assert:0 equals:mouseEnteredCalls message:@"3.2 There should be no mouseEntered calls"];
|
||||
[self assert:2 equals:mouseExitedCalls message:@"3.2 There should be two mouseExited call"];
|
||||
[self assert:0 equals:mouseMovedCalls message:@"3.2 There should be no mouseMoved call"];
|
||||
[self assert:0 equals:cursorUpdateCalls message:@"3.2 There should be no cursorUpdate calls"];
|
||||
|
||||
[self assert:[[viewA subviews] firstObject] equals:involvedViewForMouseExited message:@"3.2 viewB should receive mouseExited"];
|
||||
[self assert:[CPCursor arrowCursor] equals:[CPCursor currentCursor] message:@"3.2 Cursor should be an arrow"];
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
updateTrackingAreasCalls++;
|
||||
@@ -1414,21 +1547,16 @@ var updateTrackingAreasCalls,
|
||||
@end
|
||||
|
||||
@implementation CPTrackingAreaView : CPView
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
mouseEnteredCalls++;
|
||||
|
||||
involvedViewForMouseEntered = [[anEvent trackingArea] view];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)anEvent
|
||||
{
|
||||
mouseExitedCalls++;
|
||||
|
||||
involvedViewForMouseExited = [[anEvent trackingArea] view];
|
||||
}
|
||||
|
||||
@@ -1440,7 +1568,6 @@ var updateTrackingAreasCalls,
|
||||
- (void)cursorUpdate:(CPEvent)anEvent
|
||||
{
|
||||
cursorUpdateCalls++;
|
||||
|
||||
involvedViewForCursorUpdate = [[anEvent trackingArea] view];
|
||||
}
|
||||
|
||||
@@ -1452,22 +1579,73 @@ var updateTrackingAreasCalls,
|
||||
@end
|
||||
|
||||
@implementation CPTrackingAreaViewWithCursorUpdate : CPTrackingAreaView
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)cursorUpdate:(CPEvent)anEvent
|
||||
{
|
||||
[[CPCursor crosshairCursor] set];
|
||||
|
||||
[super cursorUpdate:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPTrackingAreaViewWithoutCursorUpdate : CPView
|
||||
{
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPTrackingAreaViewLiveRemoval : CPTrackingAreaView
|
||||
|
||||
- (void)cursorUpdate:(CPEvent)anEvent
|
||||
{
|
||||
[[CPCursor pointingHandCursor] set];
|
||||
[super cursorUpdate:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
[self removeFromSuperview];
|
||||
[super mouseEntered:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPTrackingAreaViewLiveAddition : CPTrackingAreaView
|
||||
|
||||
- (void)cursorUpdate:(CPEvent)anEvent
|
||||
{
|
||||
[[CPCursor pointingHandCursor] set];
|
||||
[super cursorUpdate:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
var viewB = [[CPTrackingAreaViewWithCursorUpdate alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
|
||||
|
||||
[self addSubview:viewB];
|
||||
|
||||
[viewB addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:CPTrackingMouseEnteredAndExited | CPTrackingCursorUpdate | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect owner:viewB userInfo:nil]];
|
||||
|
||||
[super mouseEntered:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPTrackingAreaViewLiveAddition2 : CPTrackingAreaView
|
||||
|
||||
- (void)cursorUpdate:(CPEvent)anEvent
|
||||
{
|
||||
[[CPCursor pointingHandCursor] set];
|
||||
[super cursorUpdate:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
var viewB = [[CPTrackingAreaViewWithCursorUpdate alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
|
||||
|
||||
[self addSubview:viewB];
|
||||
|
||||
[viewB addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero() options:CPTrackingMouseEnteredAndExited | CPTrackingCursorUpdate | CPTrackingActiveInActiveApp | CPTrackingInVisibleRect | CPTrackingAssumeInside owner:viewB userInfo:nil]];
|
||||
|
||||
[super mouseEntered:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -79,6 +79,17 @@
|
||||
|
||||
var expression_minusset = [CPExpression expressionForMinusSet:set with:array];
|
||||
[self assertNotNull:expression_minusset message:"MinusSet Expression should not be nil"];
|
||||
|
||||
var expression_block = [CPExpression expressionForBlock:function(obj, args, bindings)
|
||||
{
|
||||
return obj;
|
||||
} arguments:nil];
|
||||
|
||||
[self assertNotNull:expression_block message:"Block Expression should not be nil"];
|
||||
|
||||
var expression_conditional = [CPExpression expressionForConditional:[CPPredicate predicateWithValue:YES] trueExpression:expression_minusset falseExpression:expression_block];
|
||||
|
||||
[self assertNotNull:expression_conditional message:"Conditional Expression should not be nil"];
|
||||
}
|
||||
|
||||
- (void)testSetExpressionEvaluation
|
||||
@@ -147,6 +158,27 @@
|
||||
[self assertTrue:([eval isEqual:expected]) message:"'" + [expression predicateFormat] + "' result is "+ eval + "but should be " + expected];
|
||||
}
|
||||
|
||||
- (void)testBlockExpressionEvaluation
|
||||
{
|
||||
var block = function(obj, args, bindings)
|
||||
{
|
||||
return [obj stringByAppendingString:[args componentsJoinedByString:"-"]];
|
||||
};
|
||||
|
||||
var expression = [CPExpression expressionForBlock:block arguments:[[CPExpression expressionForConstantValue:"A"], [CPExpression expressionForConstantValue:"B"]]];
|
||||
|
||||
var eval = [expression expressionValueWithObject:"OBJ" context:@{}];
|
||||
[self assertTrue:([eval isEqual:"OBJA-B"]) message:"'" + [expression description] + "' result is "+ eval + "but should be " + "OBJA-B"];
|
||||
}
|
||||
|
||||
- (void)testConditionalExpressionEvaluation
|
||||
{
|
||||
var expression = [CPExpression expressionForConditional:[CPPredicate predicateWithFormat:"SELF = $variable"] trueExpression:[CPExpression expressionForConstantValue:"TRUE_EXP"] falseExpression:[CPExpression expressionForConstantValue:"FALSE_EXP"]];
|
||||
|
||||
var eval = [expression expressionValueWithObject:"OBJ" context:@{"variable":"OBJ"}];
|
||||
[self assertTrue:([eval isEqual:"TRUE_EXP"]) message:"'" + [expression description] + "' result is "+ eval + "but should be " + "TRUE_EXP"];
|
||||
}
|
||||
|
||||
- (void)testOptions
|
||||
{
|
||||
var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"àa"] rightExpression:[CPExpression expressionForConstantValue:@"aà"] modifier:CPDirectPredicateModifier type:CPLikePredicateOperatorType options:3];
|
||||
@@ -381,6 +413,9 @@
|
||||
predicate = [CPPredicate predicateWithFormat:@"a UNION {'b'} = {'a','b'}"];
|
||||
var left = [[predicate leftExpression] expressionValueWithObject:object context:nil];
|
||||
[self assertTrue:[left isEqualToSet:result] message:"Expression eval " + left + " should be " + result];
|
||||
|
||||
predicate = [CPPredicate predicateWithFormat:@"TERNARY(Record1.Children[SIZE] = 1, 'Single', Record1.Name) = 'John'"];
|
||||
[self assertTrue:[predicate evaluateWithObject:dict] message:"Predicate " + predicate + " should evaluate to TRUE"];
|
||||
}
|
||||
|
||||
- (void)testExpressionAndPredicateIsEqual
|
||||
@@ -439,6 +474,10 @@
|
||||
pred1 = [CPPredicate predicateWithFormat:@"a = 'a' AND b = 'b'"];
|
||||
pred2 = [CPPredicate predicateWithFormat:@"a = 'a' AND b = 'b'"];
|
||||
[self assert:pred1 equals:pred2];
|
||||
|
||||
pred1 = [CPPredicate predicateWithFormat:@"TERNARY(Record1.Children[FIRST] BEGINSWITH Record1.Name, 'SAME', 'DIFFERENT') = 'DIFFERENT'"];
|
||||
pred2 = [CPPredicate predicateWithFormat:@"TERNARY(Record1.Children[FIRST] BEGINSWITH Record1.Name, 'SAME', 'DIFFERENT') = 'DIFFERENT'"];
|
||||
[self assert:pred1 equals:pred2];
|
||||
}
|
||||
|
||||
- (void)testExpressionAndPredicateIsNotEqualToNil
|
||||
@@ -490,6 +529,10 @@
|
||||
|
||||
[self assert:pred1 notEqual:nil];
|
||||
|
||||
pred1 = [CPPredicate predicateWithFormat:@"TERNARY(Record1.Children[FIRST] BEGINSWITH Record1.Name, 'SAME', 'DIFFERENT') = 'DIFFERENT'"];
|
||||
|
||||
[self assert:pred1 notEqual:nil];
|
||||
|
||||
pred1 = [CPPredicate predicateWithFormat:@"$x CONTAINS 'a'"];
|
||||
|
||||
[self assert:pred1 notEqual:nil];
|
||||
|
||||
Reference in new issue
Block a user