Merge remote branch 'refs/remotes/280north/master' into my_master

Conflicts:
	AppKit/CPButton.j
	AppKit/Themes/Aristo/ThemeDescriptors.j
	AppKit/Themes/BlendKit/BKThemeDescriptor.j
	Foundation/CPArray.j
	Jakefile
	Tests/Foundation/CPArrayPerformanceTest.j
	Tools/Documentation/Cappuccino.doxygen
	Tools/Documentation/cleanup_headers
	Tools/Documentation/make_headers
This commit is contained in:
Aparajita Fishman committed 2010-08-22 09:03:12 -04:00
commit 89ce904850
36 files changed
+1606 -771

No files matched your search

+148 -110
View File
@@ -39,26 +39,22 @@
@global
@group CPAlertStyle
*/
CPWarningAlertStyle = 0;
CPWarningAlertStyle = 0;
/*
@global
@group CPAlertStyle
*/
CPInformationalAlertStyle = 1;
CPInformationalAlertStyle = 1;
/*
@global
@group CPAlertStyle
*/
CPCriticalAlertStyle = 2;
CPCriticalAlertStyle = 2;
var CPAlertWarningImage,
CPAlertInformationImage,
CPAlertErrorImage;
/*!
@ingroup appkit
CPAlert is an alert panel that can be displayed modally to present the
user with a message and one or more options.
@@ -74,11 +70,11 @@ var CPAlertWarningImage,
@delegate -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode;
Called when the user dismisses the alert by clicking one of the buttons.
@param theAlert the alert panel that the user dismissed
@param returnCode the index of the button that the user clicked (starting from 0,
@param returnCode the index of the button that the user clicked (starting from 0,
representing the first button added to the alert which appears on the
right, 1 representing the next button to the left and so on)
*/
@implementation CPAlert : CPObject
@implementation CPAlert : CPView
{
CPPanel _alertPanel;
@@ -89,27 +85,34 @@ var CPAlertWarningImage,
CPAlertStyle _alertStyle;
CPString _windowTitle;
int _windowStyle;
int _buttonCount;
CPArray _buttons;
id _delegate;
}
+ (void)initialize
+ (CPString)themeClass
{
if (self != CPAlert)
return;
return @"alert";
}
var bundle = [CPBundle bundleForClass:[self class]];
CPAlertWarningImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-warning.png"]
size:CGSizeMake(32.0, 32.0)];
CPAlertInformationImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-information.png"]
size:CGSizeMake(32.0, 32.0)];
CPAlertErrorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-error.png"]
size:CGSizeMake(32.0, 32.0)];
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[CGSizeMake(400.0, 110.0), CGInsetMake(15, 15, 15, 50), 6, 10,
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont boldSystemFontOfSize:13.0], [CPNull null], CGSizeMakeZero(),
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont systemFontOfSize:12.0], [CPNull null], CGSizeMakeZero(),
CGPointMake(15, 12),
[CPNull null],
[CPNull null],
[CPNull null]
]
forKeys:[@"size", @"content-inset", @"informative-offset", @"button-offset",
@"message-text-alignment", @"message-text-color", @"message-text-font", @"message-text-shadow-color", @"message-text-shadow-offset",
@"informative-text-alignment", @"informative-text-color", @"informative-text-font", @"informative-text-shadow-color", @"informative-text-shadow-offset",
@"image-offset",
@"information-image",
@"warning-image",
@"error-image"
]];
}
/*!
@@ -119,64 +122,52 @@ var CPAlertWarningImage,
{
if (self = [super init])
{
_buttonCount = 0;
_buttons = [CPArray array];
_alertStyle = CPWarningAlertStyle;
_alertPanel = nil;
_windowStyle = nil;
[self setWindowStyle:nil];
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
_informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
}
return self;
}
/*!
Sets the window appearance.
Sets the window appearance. If CPHUDBackgroundWindowMask is set, the default HUD theme
will be activated.
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
*/
- (void)setWindowStyle:(int)styleMask
{
_windowStyle = styleMask;
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 400.0, 110.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
[_alertPanel setFloatingPanel:YES];
[_alertPanel center];
var count = [_buttons count];
for(var i=0; i < count; i++)
{
var button = _buttons[i];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[self setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
[[_alertPanel contentView] addSubview:button];
}
// We'll need to recreate the panel to get the new window style.
_alertPanel = nil;
}
[self _layoutButtons];
- (void)_createPanel
{
var frame = CGRectMakeZero();
frame.size = [self currentValueForThemeAttribute:@"size"];
_alertPanel = [[CPPanel alloc] initWithContentRect:frame styleMask:_windowStyle ? _windowStyle | CPTitledWindowMask : CPTitledWindowMask];
if (!_messageLabel)
{
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
[_messageLabel setAlignment:CPJustifiedTextAlignment];
[_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
var contentView = [_alertPanel contentView],
count = [_buttons count];
while (count--)
[contentView addSubview:_buttons[count]];
[contentView addSubview:_messageLabel];
[contentView addSubview:_alertImageView];
[contentView addSubview:_informativeLabel];
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
_informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_informativeLabel setFont:[CPFont systemFontOfSize:12.0]];
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
[_informativeLabel setAlignment:CPJustifiedTextAlignment];
[_informativeLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
}
[_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
[_informativeLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
[[_alertPanel contentView] addSubview:_messageLabel];
[[_alertPanel contentView] addSubview:_alertImageView];
[[_alertPanel contentView] addSubview:_informativeLabel];
[self _layoutMessage];
// For reference: does not actually work since this 'view' is not in the hierarchy.
// [self setNeedsLayout];
}
/*!
@@ -228,6 +219,9 @@ var CPAlertWarningImage,
- (void)setAlertStyle:(CPAlertStyle)style
{
_alertStyle = style;
// For reference: does not actually work since this 'view' is not in the hierarchy.
// [self setNeedsLayout];
}
/*!
@@ -245,7 +239,9 @@ var CPAlertWarningImage,
- (void)setMessageText:(CPString)messageText
{
[_messageLabel setStringValue:messageText];
[self _layoutMessage];
// For reference: does not actually work since this 'view' is not in the hierarchy.
// [self setNeedsLayout];
}
/*!
@@ -288,18 +284,16 @@ var CPAlertWarningImage,
- (void)addButtonWithTitle:(CPString)title
{
var bounds = [[_alertPanel contentView] bounds],
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()];
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()],
_buttonCount = [_buttons count];
[button setTitle:title];
[button setTarget:self];
[button setTag:_buttonCount];
[button setAction:@selector(_notifyDelegate:)];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
[[_alertPanel contentView] addSubview:button];
if (_buttonCount == 0)
[button setKeyEquivalent:CPCarriageReturnCharacter];
else if ([title lowercaseString] === "cancel")
@@ -307,42 +301,102 @@ var CPAlertWarningImage,
else
[button setKeyEquivalent:nil];
_buttonCount++;
[_buttons addObject:button];
[self _layoutButtons];
// For reference: does not actually work since this 'view' is not in the hierarchy.
// [self setNeedsLayout];
}
- (void)_layoutButtons
- (void)layoutSubviews
{
var bounds = [[_alertPanel contentView] bounds],
count = [_buttons count],
offsetX = CGRectGetWidth(bounds),
offsetY = CGRectGetHeight(bounds) - 34.0;
for(var i=0; i < count; i++)
{
var button = _buttons[i];
if (!_alertPanel)
[self _createPanel];
var inset = [self currentValueForThemeAttribute:@"content-inset"],
iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
theTitle,
theImage;
switch (_alertStyle)
{
case CPWarningAlertStyle: theImage = [self currentValueForThemeAttribute:@"warning-image"];
theTitle = @"Warning";
break;
case CPInformationalAlertStyle: theImage = [self currentValueForThemeAttribute:@"information-image"];
theTitle = @"Information";
break;
case CPCriticalAlertStyle: theImage = [self currentValueForThemeAttribute:@"error-image"];
theTitle = @"Error";
break;
}
[_alertImageView setImage:theImage];
var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
[_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
[_alertPanel setFloatingPanel:YES];
[_alertPanel center];
[_messageLabel setTextColor:[self currentValueForThemeAttribute:@"message-text-color"]];
[_messageLabel setFont:[self currentValueForThemeAttribute:@"message-text-font"]];
[_messageLabel setTextShadowColor:[self currentValueForThemeAttribute:@"message-text-shadow-color"]];
[_messageLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"message-text-shadow-offset"]];
[_messageLabel setAlignment:[self currentValueForThemeAttribute:@"message-text-alignment"]];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
[_informativeLabel setTextColor:[self currentValueForThemeAttribute:@"informative-text-color"]];
[_informativeLabel setFont:[self currentValueForThemeAttribute:@"informative-text-font"]];
[_informativeLabel setTextShadowColor:[self currentValueForThemeAttribute:@"informative-text-shadow-color"]];
[_informativeLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
// FIXME sizeWithFontCorrection shouldn't be needed.
var bounds = [[_alertPanel contentView] bounds],
offsetX = CGRectGetWidth(bounds) - inset.right,
informativeOffset = [self currentValueForThemeAttribute:@"informative-offset"],
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
textWidth = offsetX - inset.left,
messageSize = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel font] inWidth:textWidth],
informationString = [_informativeLabel stringValue],
informativeSize = [(informationString || " ") sizeWithFont:[_informativeLabel font] inWidth:textWidth],
sizeWithFontCorrection = 6.0;
[_messageLabel setFrame:CGRectMake(inset.left, inset.top, textWidth, messageSize.height + sizeWithFontCorrection)];
[_informativeLabel setFrame:CGRectMake(inset.left, CGRectGetMaxY([_messageLabel frame]) + informativeOffset, textWidth, informativeSize.height + sizeWithFontCorrection)];
// Don't let an empty informative label partially cover the buttons.
[_informativeLabel setHidden:!informationString];
var aRepresentativeButton = _buttons[0],
buttonY = MAX(CGRectGetMaxY([_alertImageView frame]), CGRectGetMaxY(informationString ? [_informativeLabel frame] : [_messageLabel frame])) + buttonOffset; // the lower of the bottom of the text and the bottom of the icon.
[aRepresentativeButton setTheme:[self theme]];
[aRepresentativeButton sizeToFit];
// Make the window just tall enough to fit everything. Bit of a hack really.
var minimumSize = [self currentValueForThemeAttribute:@"size"],
desiredHeight = MAX(minimumSize.height, buttonY + CGRectGetHeight([aRepresentativeButton bounds]) + inset.bottom),
deltaY = desiredHeight - CGRectGetHeight(bounds),
frameSize = CGSizeMakeCopy([_alertPanel frame].size);
frameSize.height += deltaY;
[_alertPanel setFrameSize:frameSize];
var count = [_buttons count];
while (count--)
{
var button = _buttons[count];
[button setTheme:[self theme]];
[button sizeToFit];
var buttonBounds = [button bounds],
width = MAX(80.0, CGRectGetWidth(buttonBounds)),
height = CGRectGetHeight(buttonBounds);
offsetX -= (width + 10);
[button setFrame:CGRectMake(offsetX, offsetY, width, height)];
offsetX -= width;
[button setFrame:CGRectMake(offsetX, buttonY, width, height)];
offsetX -= 10;
}
}
- (void)_layoutMessage
{
var bounds = [[_alertPanel contentView] bounds],
width = CGRectGetWidth(bounds) - 73.0,
size = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel currentValueForThemeAttribute:@"font"] inWidth:width],
contentInset = [_messageLabel currentValueForThemeAttribute:@"content-inset"],
height = size.height + contentInset.top + contentInset.bottom;
[_messageLabel setFrame:CGRectMake(57.0, 10.0, width, height)];
[_informativeLabel setFrame:CGRectMake(57.0, 10.0 + height + 6.0, width, CGRectGetHeight(bounds) - height - 50.0)];
}
/*!
@@ -352,23 +406,7 @@ var CPAlertWarningImage,
*/
- (void)runModal
{
var theTitle;
switch (_alertStyle)
{
case CPWarningAlertStyle: [_alertImageView setImage:CPAlertWarningImage];
theTitle = @"Warning";
break;
case CPInformationalAlertStyle: [_alertImageView setImage:CPAlertInformationImage];
theTitle = @"Information";
break;
case CPCriticalAlertStyle: [_alertImageView setImage:CPAlertErrorImage];
theTitle = @"Error";
break;
}
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
[self layoutSubviews];
[CPApp runModalForWindow:_alertPanel];
}
+68 -18
View File
@@ -365,29 +365,29 @@
//Moving selection
-(BOOL)canSelectPrevious
- (BOOL)canSelectPrevious
{
return [[self selectionIndexes] firstIndex] > 0
}
-(BOOL)canSelectNext
-(void)selectPrevious:(id)sender
{
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] -1;
}
var index = [[self selectionIndexes] firstIndex] - 1;
-(void)selectNext:(id)sender
{
var index = [[self selectionIndexes] firstIndex] + 1 || 0;
if (index < [[self arrangedObjects] count])
if (index >= 0)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
-(void)selectPrevious:(id)sender
- (BOOL)canSelectNext
{
var index = [[self selectionIndexes] firstIndex] - 1 || [[self arrangedObjects] count] - 1;
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1;
}
if (index >= 0)
- (void)selectNext:(id)sender
{
var index = [[self selectionIndexes] firstIndex] + 1;
if (index < [[self arrangedObjects] count])
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
@@ -424,6 +424,33 @@
[self rearrangeObjects];
}
- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex
{
if (![self canAdd])
return;
[self willChangeValueForKey:@"content"];
[_contentObject insertObject:anObject atIndex:anIndex];
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
[self setFilterPredicate:nil];
[[self arrangedObjects] insertObject:anObject atIndex:anIndex];
if ([self selectsInsertedObjects])
[self setSelectionIndex:anIndex];
else
{
[self willChangeValueForKey:@"selectionIndexes"]
[[self selectionIndexes] shiftIndexesStartingAtIndex:anIndex by:1];
[self didChangeValueForKey:@"selectionIndexes"];
}
if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
}
- (void)removeObject:(id)object
{
if (![self canRemove])
@@ -433,12 +460,14 @@
[_contentObject removeObject:object];
[self didChangeValueForKey:@"content"];
if ([_filterPredicate evaluateWithObject:object])
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
[self willChangeValueForKey:@"selectionIndexes"];
var pos = [_arrangedObjects indexOfObject:object];
[_arrangedObjects removeObjectAtIndex:pos];
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
[self didChangeValueForKey:@"selectionIndexes"];
}
}
@@ -496,13 +525,34 @@
- (void)_removeObjects:(CPArray)objects
{
var contentArray = [self contentArray],
count = [objects count];
[self willChangeValueForKey:@"content"];
[_contentObject removeObjectsInArray:objects];
[self didChangeValueForKey:@"content"];
for (var i=0; i<count; i++)
[contentArray removeObject:[objects objectAtIndex:i]];
var arrangedObjects = [self arrangedObjects],
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
[self setContent:contentArray];
[arrangedObjects removeObjectsInArray:objects];
var objectsCount = [arrangedObjects count],
selectionIndexes = [CPIndexSet indexSet];
if ([self preservesSelection] || [self avoidsEmptySelection])
{
selectionIndexes = [CPIndexSet indexSetWithIndex:position];
// Remove the selection if there are no objects
if (objectsCount <= 0)
selectionIndexes = [CPIndexSet indexSet];
// Shift selection to last object if position is out of bounds
else if (position >= objectsCount)
selectionIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
}
[self willChangeValueForKey:@"selectionIndexes"];
_selectionIndexes = selectionIndexes;
[self didChangeValueForKey:@"selectionIndexes"];
}
- (BOOL)canInsert
+16 -19
View File
@@ -145,7 +145,7 @@ CPButtonStateMixed = CPThemeState("mixed");
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalent = "";
_keyEquivalentModifierMask = 0;
// [self setBezelStyle:CPRoundRectBezelStyle];
@@ -569,28 +569,25 @@ CPButtonStateMixed = CPThemeState("mixed");
*/
- (void)setKeyEquivalent:(CPString)aString
{
if (_keyEquivalent === aString)
return;
_keyEquivalent = aString || @"";
// Check if the key equivalent is the enter key
// Treat \r and \n as the same key equivalent. See issue #710.
if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter)
{
[[self window] setDefaultButton:self];
[self setDefaultButton:YES];
else
}
else if ([[self window] defaultButton] === self)
{
[[self window] setDefaultButton:nil];
[self setDefaultButton:NO];
_keyEquivalent = aString || @"";
}
}
- (void)viewWillMoveToWindow:(CPWindow)aWindow
{
var selfWindow = [self window];
if (selfWindow === aWindow || aWindow === nil)
return;
if ([selfWindow defaultButton] === self)
[selfWindow setDefaultButton:nil];
if ([[self window] defaultButton] === self)
[[self window] setDefaultButton:nil];
if ([self keyEquivalent] === CPNewlineCharacter || [self keyEquivalent] === CPCarriageReturnCharacter)
[aWindow setDefaultButton:self];
@@ -675,18 +672,18 @@ var CPButtonImageKey = @"CPButtonImageKey",
{
_controlSize = CPRegularControlSize;
_image = [aCoder decodeObjectForKey:CPButtonImageKey];
_alternateImage = [aCoder decodeObjectForKey:CPButtonAlternateImageKey];
[self setImage:[aCoder decodeObjectForKey:CPButtonImageKey]];
[self setAlternateImage:[aCoder decodeObjectForKey:CPButtonAlternateImageKey]];
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
[self setTitle:[aCoder decodeObjectForKey:CPButtonTitleKey]];
[self setAlternateTitle:[aCoder decodeObjectForKey:CPButtonAlternateTitleKey]];
[self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]];
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
_keyEquivalentModifierMask = [aCoder decodeObjectForKey:CPButtonKeyEquivalentMaskKey];
[self setKeyEquivalentModifierMask:[aCoder decodeObjectForKey:CPButtonKeyEquivalentMaskKey]];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
+12
View File
@@ -181,7 +181,19 @@ var CPBindingOperationAnd = 0,
valueTransformer;
if (valueTransformerName)
{
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
if (!valueTransformer)
{
var valueTransformerClass = CPClassFromString(valueTransformerName);
if (valueTransformerClass)
{
valueTransformer = [[valueTransformerClass alloc] init];
[valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName];
}
}
}
else
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
+12 -9
View File
@@ -226,12 +226,12 @@ CPTableColumnUserResizingMask = 1 << 1;
/*!
This method set's the "prototype" view which will be used to create all table cells in this column.
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
Example:
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
@@ -291,7 +291,7 @@ CPTableColumnUserResizingMask = 1 << 1;
// make sure only we have control over the size and placement
[newDataView setAutoresizingMask:CPViewNotSizable];
return newDataView;
}
@@ -350,9 +350,9 @@ CPTableColumnUserResizingMask = 1 << 1;
shouldBeHidden = !!shouldBeHidden
if (_isHidden === shouldBeHidden)
return;
_isHidden = shouldBeHidden;
[[self headerView] setHidden:shouldBeHidden];
[[self tableView] _tableColumnVisibilityDidChange:self];
}
@@ -407,7 +407,8 @@ CPTableColumnUserResizingMask = 1 << 1;
{
var bindingName = keys[i],
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
bindingInfo = [bindingsDictionary objectForKey:bindingName]._info,
binding = [bindingsDictionary objectForKey:bindingName],
bindingInfo = binding._info,
destination = [bindingInfo objectForKey:CPObservedObjectKey],
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
dotIndex = keyPath.lastIndexOf("."),
@@ -438,6 +439,8 @@ CPTableColumnUserResizingMask = 1 << 1;
value = [[firstValue valueForKeyPath:secondPart] objectAtIndex:aRow];
}
value = [binding transformValue:value withOptions:[bindingInfo objectForKey:CPOptionsKey]];
// console.log(bindingName+" : "+keyPath+" : "+aRow+" : "+[[destination valueForKeyPath:keyPath] objectAtIndex:aRow]);
[aDataView setValue:value forKey:bindingPath];
}
@@ -488,7 +491,7 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
_isEditable = [aCoder decodeBoolForKey:CPTableColumnIsEditableKey];
_sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey];
}
@@ -509,7 +512,7 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey];
[aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey];
[aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey];
}
+7
View File
@@ -2474,6 +2474,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[self drawBackgroundInClipRect:exposedRect];
[self drawGridInClipRect:exposedRect];
[self highlightSelectionInClipRect:exposedRect];
if (_implementsCustomDrawRow)
[self _drawRows:_exposedRows clipRect:exposedRect];
}
- (void)drawBackgroundInClipRect:(CGRect)aRect
@@ -3308,6 +3311,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
if (![_delegate tableView:self shouldSelectRow:index])
[newSelection removeIndex:index];
}
// as per cocoa
if ([newSelection count] === 0)
return;
}
// if empty selection is not allowed and the new selection has nothing selected, abort
+33 -11
View File
@@ -24,8 +24,9 @@
@import <Foundation/CPString.j>
@import <Foundation/CPKeyedUnarchiver.j>
var CPThemesByName = { },
CPThemeDefaultTheme = nil;
var CPThemesByName = { },
CPThemeDefaultTheme = nil,
CPThemeDefaultHudTheme = nil;
/*!
@@ -48,6 +49,27 @@ var CPThemesByName = { },
return CPThemeDefaultTheme;
}
/*!
Set the default HUD theme. If set to nil, the default described in defaultHudTheme
will be used.
*/
+ (void)setDefaultHudTheme:(CPTheme)aTheme
{
CPThemeDefaultHudTheme = aTheme;
}
/*!
The default HUD theme is (sometimes) used for windows with the CPHUDBackgroundWindowMask
style mask. The default is theme with the name of the default theme with -HUD appended
at the end.
*/
+ (CPTheme)defaultHudTheme
{
if (!CPThemeDefaultHudTheme)
CPThemeDefaultHudTheme = [CPTheme themeNamed:[[self defaultTheme] name] + "-HUD"];
return CPThemeDefaultHudTheme;
}
+ (CPTheme)themeNamed:(CPString)aName
{
return CPThemesByName[aName];
@@ -474,15 +496,15 @@ CPThemeStateCircular = CPThemeState("circular");
@end
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
6 /*111111*/ ];
var numberOfOnes = function(aNumber)
+6 -2
View File
@@ -162,8 +162,6 @@ var CPViewControllerCachedCibs;
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
[cibOwner viewControllerDidLoadCib:self];
[self viewDidLoad];
}
return _view;
@@ -189,7 +187,13 @@ var CPViewControllerCachedCibs;
*/
- (void)setView:(CPView)aView
{
var viewWasLoaded = !_view;
_view = aView;
// Make sure the viewDidLoad method is called if the view is set directly
if (viewWasLoaded)
[self viewDidLoad];
}
@end
+46 -45
View File
@@ -50,23 +50,23 @@ CPWebViewScrollNative = 2;
{
CPScrollView _scrollView;
CPView _frameView;
IFrame _iframe;
CPString _mainFrameURL;
CPArray _backwardStack;
CPArray _forwardStack;
BOOL _ignoreLoadStart;
BOOL _ignoreLoadEnd;
id _downloadDelegate;
id _frameLoadDelegate;
id _policyDelegate;
id _resourceLoadDelegate;
id _UIDelegate;
CPWebScriptObject _wso;
CPString _url;
CPString _html;
@@ -95,10 +95,10 @@ CPWebViewScrollNative = 2;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
[self _initDOMWithFrame:aFrame];
}
return self;
}
@@ -106,52 +106,52 @@ CPWebViewScrollNative = 2;
{
_ignoreLoadStart = YES;
_ignoreLoadEnd = YES;
_iframe = document.createElement("iframe");
_iframe.name = "iframe_" + Math.floor(Math.random()*10000);
_iframe.style.width = "100%";
_iframe.style.height = "100%";
_iframe.style.borderWidth = "0px";
_iframe.frameBorder = "0";
[self setDrawsBackground:YES];
_loadCallback = function() {
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
if (!_ignoreLoadStart)
{
// post the start load notification
[self _startedLoading];
if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL];
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
_mainFrameURL = _iframe.src;
_mainFrameURL = _iframe.src;
// clear the forward
[_forwardStack removeAllObjects];
}
else
_ignoreLoadStart = NO;
if (!_ignoreLoadEnd)
{
[self _finishedLoading];
}
else
_ignoreLoadEnd = NO;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
if (_iframe.addEventListener)
_iframe.addEventListener("load", _loadCallback, false);
else if (_iframe.attachEvent)
_iframe.attachEvent("onload", _loadCallback);
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
@@ -159,9 +159,9 @@ CPWebViewScrollNative = 2;
[_scrollView setAutohidesScrollers:YES];
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_scrollView setDocumentView:_frameView];
_frameView._DOMElement.appendChild(_iframe);
[self _setScrollMode:_scrollMode];
[self addSubview:_scrollView];
@@ -169,7 +169,7 @@ CPWebViewScrollNative = 2;
- (void)setFrameSize:(CPSize)aSize
{
{
[super setFrameSize:aSize];
[self _resizeWebFrame];
}
@@ -211,7 +211,7 @@ CPWebViewScrollNative = 2;
{
var visibleRect = [_frameView visibleRect];
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
// try to get the document size so we can correctly set the frame
var win = null;
try { win = [self DOMWindow]; } catch (e) {}
@@ -229,7 +229,7 @@ CPWebViewScrollNative = 2;
else
{
CPLog.warn("using default size 800*1600");
[_frameView setFrameSize:CGSizeMake(800, 1600)];
}
@@ -242,7 +242,7 @@ CPWebViewScrollNative = 2;
{
if (_scrollMode == aScrollMode)
return;
[self _setScrollMode:aScrollMode];
}
@@ -252,7 +252,7 @@ CPWebViewScrollNative = 2;
_scrollMode = CPWebViewScrollNative;
else
_scrollMode = aScrollMode;
_ignoreLoadStart = YES;
_ignoreLoadEnd = YES;
@@ -263,16 +263,16 @@ CPWebViewScrollNative = 2;
{
[_scrollView setHasHorizontalScroller:YES];
[_scrollView setHasVerticalScroller:YES];
_iframe.setAttribute("scrolling", "no");
}
else
{
[_scrollView setHasHorizontalScroller:NO];
[_scrollView setHasVerticalScroller:NO];
_iframe.setAttribute("scrolling", "auto");
[_frameView setFrameSize:[_scrollView bounds].size];
}
@@ -293,13 +293,13 @@ CPWebViewScrollNative = 2;
[_frameView setFrameSize:[_scrollView contentSize]];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = null;
_html = aString;
[self _load];
}
@@ -308,13 +308,13 @@ CPWebViewScrollNative = 2;
[self _setScrollMode:CPWebViewScrollNative];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = _mainFrameURL;
_html = null;
[self _load];
}
@@ -335,12 +335,13 @@ CPWebViewScrollNative = 2;
_loadHTMLStringTimer = nil;
}
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
_loadHTMLStringTimer = window.setTimeout(function()
{
var win = [self DOMWindow];
win.document.write(_html);
if (win)
win.document.write(_html);
window.setTimeout(_loadCallback, 1);
}, 0);
@@ -372,7 +373,7 @@ CPWebViewScrollNative = 2;
}
- (void)setMainFrameURL:(CPString)URLString
{
{
if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL];
_mainFrameURL = URLString;
@@ -389,9 +390,9 @@ CPWebViewScrollNative = 2;
[_forwardStack addObject:_mainFrameURL];
_mainFrameURL = [_backwardStack lastObject];
[_backwardStack removeLastObject];
[self _loadMainFrameURL];
return YES;
}
return NO;
@@ -405,9 +406,9 @@ CPWebViewScrollNative = 2;
[_backwardStack addObject:_mainFrameURL];
_mainFrameURL = [_forwardStack lastObject];
[_forwardStack removeLastObject];
[self _loadMainFrameURL];
return YES;
}
return NO;
@@ -630,7 +631,7 @@ CPWebViewScrollNative = 2;
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
// FIXME: encode/decode these?
@@ -638,14 +639,14 @@ CPWebViewScrollNative = 2;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
#if PLATFORM(DOM)
[self _initDOMWithFrame:[self frame]];
#endif
[self setBackgroundColor:[CPColor whiteColor]];
}
return self;
}
+2 -1
View File
@@ -2413,7 +2413,8 @@ CPTexturedBackgroundWindowMask
_defaultButton = aButton;
[_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter)
[_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
}
- (CPButton)defaultButton
-58
View File
@@ -1,58 +0,0 @@
These graphics come from the Tango Desktop Project (http://tango.freedesktop.org/Tango_Desktop_Project).
They are released under the Creative Commons Attribution Share-Alike license, full text below.
(license available from CC here: http://creativecommons.org/licenses/by-sa/2.5/)
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
1. Definitions
"Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
"Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
"Licensor" means the individual or entity that offers the Work under the terms of this License.
"Original Author" means the individual or entity who created the Work.
"Work" means the copyrightable work of authorship offered under the terms of this License.
"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
"License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.
2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
to create and reproduce Derivative Works;
to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
For the avoidance of doubt, where the work is a musical composition:
Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.
Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).
Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).
The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.
4. Restrictions.The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested.
You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License.
If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
8. Miscellaneous
Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

File diff suppressed because it is too large. Load diff
+31 -23
View File
@@ -177,14 +177,14 @@ var ItemSizes = { },
}
+ (void)registerThemeValues:(CPArray)themeValues forView:(CPView)aView
{
{
for (var i = 0; i < themeValues.length; ++i)
{
var attributeValueState = themeValues[i],
attribute = attributeValueState[0],
value = attributeValueState[1],
state = attributeValueState[2];
if (state)
[aView setValue:value forThemeAttribute:attribute inState:state];
else
@@ -218,9 +218,9 @@ var ItemSizes = { },
value = attributeValueState[1],
state = attributeValueState[2],
pattern = nil;
if (typeof(value) === "object" &&
value.hasOwnProperty("isa") &&
if (typeof(value) === "object" &&
value.hasOwnProperty("isa") &&
[value isKindOfClass:CPColor] &&
(pattern = [value patternImage]))
{
@@ -228,16 +228,16 @@ var ItemSizes = { },
{
var slices = [pattern imageSlices],
newSlices = [];
for (var sliceIndex = 0; sliceIndex < slices.length; ++sliceIndex)
{
var slice = slices[sliceIndex],
filename = themePath + [[slice filename] lastPathComponent],
size = [slice size];
newSlices.push([filename, size.width, size.height]);
}
if ([pattern isThreePartImage])
value = PatternColor(newSlices, [pattern isVertical]);
else
@@ -247,11 +247,11 @@ var ItemSizes = { },
{
var filename = themePath + [[pattern filename] lastPathComponent],
size = [pattern size];
value = PatternColor(filename, size.width, size.height);
}
}
if (state)
[aView setValue:value forThemeAttribute:attribute inState:state];
else
@@ -259,7 +259,7 @@ var ItemSizes = { },
}
}
}
if (themeValues)
[self registerThemeValues:themeValues forView:aView];
}
@@ -268,7 +268,7 @@ var ItemSizes = { },
function BKLabelFromIdentifier(anIdentifier)
{
var string = anIdentifier.substr("themed".length);
var string = anIdentifier.substr("themed".length),
index = 0,
count = string.length,
label = "",
@@ -281,7 +281,7 @@ function BKLabelFromIdentifier(anIdentifier)
isCapital = /^[A-Z]/.test(character);
if (isCapital)
{
{
if (!isLeadingCapital)
{
if (lastCapital === null)
@@ -311,21 +311,21 @@ function BKLabelFromIdentifier(anIdentifier)
PatternIsVertical = YES,
PatternIsHorizontal = NO;
/*
To create a simple color with a pattern image:
PatternColor(name, width, height)
To create a color with a three part pattern image:
PatternColor(slices, orientation)
where slices is an array of three [name, width, height] arrays,
and orientation is PatternIsVertical or PatternIsHorizontal.
To create a color with a nine part pattern image:
PatternColor(slices);
where slices is an array of nine [name, width, height] arrays.
where slices is an array of nine [name, width, height] arrays.
*/
function PatternColor()
{
@@ -333,14 +333,14 @@ function PatternColor()
{
var slices = arguments[0],
imageSlices = [];
for (var i = 0; i < slices.length; ++i)
{
var slice = slices[i];
imageSlices.push(slice ? [_CPCibCustomResource imageResourceWithName:slice[0] size:CGSizeMake(slice[1], slice[2])] : nil);
}
if (arguments.length == 2)
return [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:imageSlices isVertical:arguments[1]]];
else
@@ -348,10 +348,18 @@ function PatternColor()
}
else if (arguments.length == 3)
{
return [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:arguments[0] size:CGSizeMake(arguments[1], arguments[2])]];
return [CPColor colorWithPatternImage:PatternImage(arguments[0], arguments[1], arguments[2])];
}
else
{
return nil;
}
}
/*
Like the 3 argument PatternColor, but return an image instead of a color.
*/
function PatternImage(name, width, height)
{
return [_CPCibCustomResource imageResourceWithName:name size:CGSizeMake(width, height)];
}
+11
View File
@@ -130,6 +130,17 @@
return self;
}
- (BOOL)isEqual:(id)anObject
{
if (self === anObject)
return YES;
if (!anObject || ![anObject isKindOfClass:[CPIndexSet class]])
return NO;
return [self isEqualToIndexSet:anObject];
}
// Querying an Index Set
/*!
Compares the receiver with the provided index set.
+23 -36
View File
@@ -90,41 +90,28 @@ task ("docs", ["documentation"]);
task ("documentation", function()
{
var doxygen = null,
DoxygenAppPath = "/Applications/Doxygen.app/Contents/Resources";
// try to find a doxygen executable in the PATH;
var doxygen = executableExists("doxygen");
// If the Doxygen application is installed on Mac OS X, use that
if (executableExists("mdfind"))
if (!doxygen && executableExists("mdfind"))
{
OS.system("mdfind \"kMDItemContentType == 'com.apple.application-bundle' && kMDItemCFBundleIdentifier == 'org.doxygen'\" > doxygen_app");
if (FILE.exists("doxygen_app"))
var p = OS.popen(["mdfind", "kMDItemContentType == 'com.apple.application-bundle' && kMDItemCFBundleIdentifier == 'org.doxygen'"]);
if (p.wait() === 0)
{
doxygen = FILE.join(UTIL.trimEnd(FILE.read("doxygen_app")), "Contents/Resources/doxygen");
FILE.remove("doxygen_app");
var doxygenApps = p.stdout.read().split("\n");
if (doxygenApps[0])
doxygen = FILE.join(doxygenApps[0], "Contents/Resources/doxygen");
}
}
else
if (doxygen && FILE.exists(doxygen))
{
SYSTEM.env["PATH"].split(':').some(function(/*String*/ aPath)
{
var path = FILE.join(aPath, "doxygen");
if (FILE.exists(path))
{
doxygen = path;
return true;
}
});
}
if (doxygen)
{
print("Using " + doxygen + " for doxygen binary.");
stream.print("\0green(Using " + doxygen + " for doxygen binary.\0)");
var documentationDir = FILE.join("Tools", "Documentation");
if (OS.system(["ruby", FILE.join(documentationDir, "make_headers.sh")]))
if (OS.system(["ruby", FILE.join(documentationDir, "make_headers")]))
OS.exit(1); //rake abort if ($? != 0)
if (!OS.system([doxygen, FILE.join(documentationDir, "Cappuccino.doxygen")]))
@@ -133,11 +120,11 @@ task ("documentation", function()
mv("debug.txt", FILE.join("Documentation", "debug.txt"));
mv("Documentation", $DOCUMENTATION_BUILD);
}
OS.system(["ruby", FILE.join(documentationDir, "cleanup_headers")]);
}
else
print("doxygen not installed, skipping documentation generation.");
stream.print("\0yellow(Doxygen not installed, skipping documentation generation.\0)");
});
// Downloads
@@ -225,17 +212,17 @@ task ("demos", function()
return this._plist.valueForKey(key);
return this._plist;
}
Demo.prototype.name = function()
{
return this.plist("CPBundleName");
}
Demo.prototype.path = function()
{
return this._path;
}
Demo.prototype.excluded = function()
{
return !!this.plist("CPDemoExcluded");
@@ -245,7 +232,7 @@ task ("demos", function()
{
return this.name();
}
FILE.glob(FILE.join(demosDir, "demos", "**/Info.plist")).map(function(demoPath){
return new Demo(FILE.dirname(demoPath))
}).filter(function(demo){
@@ -259,7 +246,7 @@ task ("demos", function()
var outputPath = demo.name().replace(/\s/g, "-")+".zip";
OS.system("cd "+OS.enquote(FILE.dirname(demo.path()))+" && zip -ry -8 "+OS.enquote(outputPath)+" "+OS.enquote(FILE.basename(demo.path())));
// remove the frameworks
// remove the frameworks
rm_rf(FILE.join(demo.path(), "Frameworks"));
});
});
@@ -343,7 +330,7 @@ function pushPackage(path, remote, branch)
cmd.push(["git", "tag", "rev-"+pkg["cappuccino-revision"].slice(0,6)]);
OS.system(buildCmd(cmd));
if (OS.system(buildCmd([
["cd", packagePath],
["git", "push", "--tags", "origin", "HEAD:"+branch]
+51 -51
View File
@@ -53,20 +53,20 @@ DISPLAY_NAME(objj_method);
GLOBAL(objj_class) = function(displayName)
{
this.isa = NULL;
this.super_class = NULL;
this.sub_classes = [];
this.name = NULL;
this.info = 0;
this.ivars = [];
this.method_list = [];
this.method_hash = {};
this.method_store = function() { };
this.method_dtable = this.method_store.prototype;
#if DEBUG
// naming the allocator allows the WebKit heap snapshot tool to display object class names correctly
// HACK: displayName property is not respected so we must eval a function to name it
@@ -94,7 +94,7 @@ GLOBAL(class_getName) = function(/*Class*/ aClass)
{
if (aClass == Nil)
return "";
return aClass.name;
}
@@ -104,7 +104,7 @@ GLOBAL(class_isMetaClass) = function(/*Class*/ aClass)
{
if (!aClass)
return NO;
return ISMETA(aClass);
}
@@ -114,7 +114,7 @@ GLOBAL(class_getSuperclass) = function(/*Class*/ aClass)
{
if (aClass == Nil)
return Nil;
return aClass.super_class;
}
@@ -132,13 +132,13 @@ DISPLAY_NAME(class_setSuperclass);
GLOBAL(class_addIvar) = function(/*Class*/ aClass, /*String*/ aName, /*String*/ aType)
{
var thePrototype = aClass.allocator.prototype;
if (typeof thePrototype[aName] != "undefined")
return NO;
aClass.ivars.push(new objj_ivar(aName, aType));
aClass.ivars.push(new objj_ivar(aName, aType));
thePrototype[aName] = NULL;
return YES;
}
@@ -149,7 +149,7 @@ GLOBAL(class_addIvars) = function(/*Class*/ aClass, /*Array*/ivars)
var index = 0,
count = ivars.length,
thePrototype = aClass.allocator.prototype;
for (; index < count; ++index)
{
var ivar = ivars[index],
@@ -157,7 +157,7 @@ GLOBAL(class_addIvars) = function(/*Class*/ aClass, /*Array*/ivars)
if (typeof thePrototype[name] === "undefined")
{
aClass.ivars.push(ivar);
aClass.ivars.push(ivar);
thePrototype[name] = NULL;
}
}
@@ -180,10 +180,10 @@ GLOBAL(class_addMethod) = function(/*Class*/ aClass, /*SEL*/ aName, /*IMP*/ anIm
{
if (aClass.method_hash[aName])
return NO;
var method = new objj_method(aName, anImplementation, types);
aClass.method_list.push(method);
aClass.method_list.push(method);
aClass.method_dtable[aName] = method;
#if DEBUG
@@ -205,18 +205,18 @@ GLOBAL(class_addMethods) = function(/*Class*/ aClass, /*Array*/ methods)
{
var index = 0,
count = methods.length,
method_list = aClass.method_list,
method_dtable = aClass.method_dtable;
for (; index < count; ++index)
{
var method = methods[index];
if (aClass.method_hash[method.name])
continue;
method_list.push(method);
method_list.push(method);
method_dtable[method.name] = method;
#if DEBUG
@@ -236,9 +236,9 @@ GLOBAL(class_getInstanceMethod) = function(/*Class*/ aClass, /*SEL*/ aSelector)
{
if (!aClass || !aSelector)
return NULL;
var method = aClass.method_dtable[aSelector];
return method ? method : NULL;
}
@@ -250,7 +250,7 @@ GLOBAL(class_getClassMethod) = function(/*Class*/ aClass, /*SEL*/ aSelector)
return NULL;
var method = GETMETA(aClass).method_dtable[aSelector];
return method ? method : NULL;
}
@@ -284,17 +284,17 @@ DISPLAY_NAME(class_replaceMethod);
var _class_initialize = function(/*Class*/ aClass)
{
var meta = GETMETA(aClass);
if (GETINFO(aClass, CLS_META))
aClass = objj_getClass(aClass.name);
if (aClass.super_class && !ISINITIALIZED(aClass.super_class))
_class_initialize(aClass.super_class);
if (!GETINFO(meta, CLS_INITIALIZED) && !GETINFO(meta, CLS_INITIALIZING))
{
SETINFO(meta, CLS_INITIALIZING);
objj_msgSend(aClass, "initialize");
CHANGEINFO(meta, CLS_INITIALIZED, CLS_INITIALIZING);
@@ -321,7 +321,7 @@ var _objj_forward = new objj_method("forward", function(self, _cmd)
GLOBAL(class_getMethodImplementation) = function(/*Class*/ aClass, /*SEL*/ aSelector)
{
CLASS_GET_METHOD_IMPLEMENTATION(var implementation, aClass, aSelector);
return implementation;
}
@@ -335,25 +335,25 @@ GLOBAL(objj_allocateClassPair) = function(/*Class*/ superclass, /*String*/ aName
var classObject = new objj_class(aName),
metaClassObject = new objj_class(aName),
rootClassObject = classObject;
// If we don't have a superclass, we are the root class.
if (superclass)
{
rootClassObject = superclass;
while (rootClassObject.superclass)
rootClassObject = rootClassObject.superclass;
// Give our current allocator all the instance variables of our super class' allocator.
classObject.allocator.prototype = new superclass.allocator;
// "Inheret" parent methods.
classObject.method_store.prototype = new superclass.method_store;
classObject.method_dtable = classObject.method_store.prototype;
metaClassObject.method_store.prototype = new superclass.isa.method_store;
metaClassObject.method_dtable = metaClassObject.method_store.prototype;
// Set up the actual class hierarchy.
classObject.super_class = superclass;
metaClassObject.super_class = superclass.isa;
@@ -406,7 +406,7 @@ GLOBAL(class_createInstance) = function(/*Class*/ aClass)
DISPLAY_NAME(class_createInstance);
// Opera 9.5.1 has a bug where prototypes "inheret" members from instances when "with" is used.
// Given that the Opera team is so fond of bug-testing instead of version-testing, we'll go
// Given that the Opera team is so fond of bug-testing instead of version-testing, we'll go
// ahead and do that.
var prototype_bug = function() { }
@@ -417,7 +417,7 @@ with (new prototype_bug())
member = true;
// If the bug exists, go down the slow path.
if (new prototype_bug().member)
if (new prototype_bug().member)
{
var fast_class_createInstance = class_createInstance;
@@ -425,23 +425,23 @@ var fast_class_createInstance = class_createInstance;
class_createInstance = function(/*Class*/ aClass)
{
var object = fast_class_createInstance(aClass);
if (object)
{
var theClass = object.isa,
actualClass = theClass;
while (theClass)
{
var ivars = theClass.ivars;
count = ivars.length;
while (count--)
object[ivars[count].name] = NULL;
theClass = theClass.super_class;
}
object.isa = actualClass;
}
@@ -464,11 +464,11 @@ GLOBAL(object_getClassName) = function(/*id*/ anObject)
DISPLAY_NAME(object_getClassName);
//objc_getClassList
//objc_getClassList
GLOBAL(objj_lookUpClass) = function(/*String*/ aName)
{
var theClass = REGISTERED_CLASSES[aName];
return theClass ? theClass : Nil;
}
@@ -477,22 +477,22 @@ DISPLAY_NAME(objj_lookUpClass);
GLOBAL(objj_getClass) = function(/*String*/ aName)
{
var theClass = REGISTERED_CLASSES[aName];
if (!theClass)
{
// class handler callback???
}
return theClass ? theClass : Nil;
}
DISPLAY_NAME(objj_getClass);
//objc_getRequiredClass
//objc_getRequiredClass
GLOBAL(objj_getMetaClass) = function(/*String*/ aName)
{
var theClass = objj_getClass(aName);
return GETMETA(theClass);
}
@@ -569,9 +569,9 @@ DISPLAY_NAME(method_getImplementation);
GLOBAL(method_setImplementation) = function(/*Method*/ aMethod, /*IMP*/ anImplementation)
{
var oldImplementation = aMethod.method_imp;
aMethod.method_imp = anImplementation;
return oldImplementation;
}
+157
View File
@@ -0,0 +1,157 @@
@implementation CPArrayControllerTest : OJTestCase
{
CPArrayController _arrayController @accessors(property=arrayController);
CPArray _contentArray @accessors(property=contentArray);
}
- (void)setUp
{
_contentArray = [];
[_contentArray addObject:[Person personWithName:@"Francisco" age:21]];
[_contentArray addObject:[Person personWithName:@"Ross" age:30]];
[_contentArray addObject:[Person personWithName:@"Tom" age:15]];
// Copy the array since we'll reuse the original array later. Also see issue #795.
_arrayController = [[CPArrayController alloc] initWithContent:[[self contentArray] copy]];
}
- (void)testInitWithContent
{
[self assert:[self contentArray] equals:[[self arrayController] contentArray]];
[self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]];
}
- (void)testSetContent
{
otherContent = [@"5", @"6"];
[[self arrayController] setContent:otherContent];
// This has not been decided on yet. See Issue #795.
// [self assertFalse:otherContent === [[self arrayController] contentArray] message:@"array controller should copy it's content"];
[self assert:otherContent equals:[[self arrayController] contentArray]];
[self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]];
}
- (void)testInsertObjectAtArrangedObjectIndex
{
var object = [Person personWithName:@"Klaas Pieter" age:24],
arrayController = [self arrayController];
[arrayController setSortDescriptors:[[CPSortDescriptor sortDescriptorWithKey:@"age" ascending:YES]]];
[arrayController insertObject:object atArrangedObjectIndex:1];
[self assert:object equals:[[arrayController arrangedObjects] objectAtIndex:1]];
}
- (void)testSelectPrevious
{
var arrayController = [self arrayController];
// Selection index: 1
[arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:1]];
[self assertTrue:[arrayController canSelectPrevious] message:@"index > 0; canSelectPrevious should return YES"]
[arrayController selectPrevious:self];
[self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]];
// Selection index: 0
[self assertFalse:[arrayController canSelectPrevious] message:@"index <= 0; canSelectPrevious should return NO"];
[arrayController selectPrevious:self];
[self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]];
}
- (void)testSelectNext
{
var arrayController = [self arrayController],
count = [[arrayController arrangedObjects] count];
// Selection index: count - 2
[arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:count - 2]];
[self assertTrue:[arrayController canSelectNext] message:@"index < (count - 1); canSelectNext should return YES"];
[arrayController selectNext:self];
[self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]];
// Selection index: count - 1
[self assertFalse:[arrayController canSelectNext] message:@"index >= (count - 1) canSelectNext should return NO"];
[arrayController selectNext:self];
[self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]];
}
- (void)testRemoveObjects
{
var arrayController = [self arrayController];
[arrayController setPreservesSelection:NO];
[arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(1, 2)]];
[arrayController removeObjects:[arrayController selectedObjects]]
[self assert:[CPIndexSet indexSet] equals:[arrayController selectionIndexes]
message:@"selection should be empty if arraycontroller doesn't preserve selection"];
arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]];
[arrayController setPreservesSelection:YES];
// Remove from middle
var selectionIndexes = [CPIndexSet indexSetWithIndex:1];
[arrayController setSelectionIndexes:selectionIndexes];
[arrayController removeObjects:[arrayController selectedObjects]];
[self assert:selectionIndexes equals:[arrayController selectionIndexes] message:@"selection should stay the same"];
// Remove from end
[arrayController removeObjects:[[[arrayController content] objectAtIndex:1]]];
[self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]
message:@"last object removed; selection should shift to first available index"];
// Remove from all
[arrayController removeObjects:[[[arrayController content] objectAtIndex:0]]];
[self assert:[CPIndexSet indexSet] equals:[arrayController selectionIndexes] message:@"no objects left, selection should disappear"];
}
- (void)testContentBinding
{
[[self arrayController] bind:@"contentArray" toObject:self withKeyPath:@"contentArray" options:0];
[self assert:[[self arrayController] contentArray] equals:[self contentArray]];
[[self mutableArrayValueForKey:@"contentArray"] addObject:@"4"];
[self assert:[self contentArray] equals:[[self arrayController] contentArray]
message:@"object 4 was added; contentArray should reflect this"];
[[self arrayController] insertObject:@"2" atArrangedObjectIndex:1];
[self assert:[[self arrayController] contentArray] equals:[self contentArray]];
}
@end
@implementation Person : CPObject
{
CPString _name @accessors(property=name);
int _age @accessors(property=age);
}
+ (id)personWithName:(CPString)aName age:(int)anAge
{
return [[self alloc] initWithName:aName age:anAge];
}
- (id)initWithName:(CPString)aName age:(int)anAge
{
if (self = [super init])
{
_name = aName;
_age = anAge;
}
return self;
}
- (CPString)description
{
return [CPString stringWithFormat:@"%@ : %@", [self name], [self age]];
}
@end
+93
View File
@@ -0,0 +1,93 @@
@import <Foundation/CPArray.j>
@import <Foundation/CPString.j>
@import <Foundation/CPNumber.j>
@import <Foundation/CPSortDescriptor.j>
var ELEMENTS = 100,
REPEATS = 10;
@implementation CPArrayPerformanceTest : OJTestCase
- (void)testSortUsingDescriptorsSpeed
{
var array = [self makeUnsorted];
var descriptors = [
[CPSortDescriptor sortDescriptorWithKey:"a" ascending:NO],
[CPSortDescriptor sortDescriptorWithKey:"b" ascending:YES]
];
var start = (new Date).getTime();
for (var i=0; i<REPEATS; i++)
{
var sorted = [array sortedArrayUsingDescriptors:descriptors];
[self checkSorted:sorted];
}
var end = (new Date).getTime();
CPLog.warn(_cmd+": "+(end-start)+"ms");
}
- (void)testSortUsingNativeSort
{
var array = [self makeUnsorted];
var descriptors = [
[CPSortDescriptor sortDescriptorWithKey:"a" ascending:NO],
[CPSortDescriptor sortDescriptorWithKey:"b" ascending:YES]
];
function sortFunction(lhs, rhs) {
return ([lhs a] === [rhs a]) ? ([lhs b] - [rhs b]) : ([rhs a] - [lhs a]);
}
var start = (new Date).getTime();
for (var i=0; i<REPEATS; i++)
{
var sorted = [array copy];
sorted.sort(sortFunction)
[self checkSorted:sorted];
}
var end = (new Date).getTime();
CPLog.warn(_cmd+": "+(end-start)+"ms");
}
- (CPArray)makeUnsorted
{
var array = [];
for (var i=0; i<ELEMENTS; i++) {
var s = [Sortable new];
[s setA:(i % 5)];
[s setB:(ELEMENTS-i)];
array.push(s);
}
return array;
}
- (void)checkSorted:(CPArray)sorted
{
// Verify it really got sorted.
for (var j=0; j<ELEMENTS; j++) {
var expectedA = 4-FLOOR(j * 5 / ELEMENTS);
if (sorted[j].a != expectedA)
[self fail:"a out of order: "+expectedA+" != "+sorted[j].a];
var expectedB = (5-expectedA) + 5 * (j % (ELEMENTS / 5))
if (sorted[j].b != expectedB)
[self fail:"b out of order: "+expectedB+" != "+sorted[j].b];
}
}
@end
@implementation Sortable : CPObject
{
int a @accessors;
int b @accessors;
}
@end
+21
View File
@@ -389,6 +389,27 @@ function descriptionWithoutEntity(aString)
[self assertTrue:[_set lastIndex] === 0];
}
- (void)testIsEqual
{
var differentSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 11)],
equalSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)];
[self assertFalse:[_set isEqual:nil]];
[self assertFalse:[_set isEqual:differentSet]];
[self assertTrue:[_set isEqual:equalSet]];
[self assertTrue:[_set isEqual:_set]];
}
- (void)testIsEqualToIndexSet
{
var differentSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 11)],
equalSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)];
[self assertFalse:[_set isEqualToIndexSet:differentSet]];
[self assertTrue:[_set isEqualToIndexSet:equalSet]];
[self assertTrue:[_set isEqualToIndexSet:_set]];
}
- (void)tearDown
{
_set = nil;
+62 -26
View File
@@ -21,7 +21,7 @@ CPLogRegister(CPLogConsole);
//CPTextField selectedNameField;
//CPTextField selectedPriceField;
CPTextField totalCountField;
CPArrayController arrayController;
}
@@ -31,14 +31,16 @@ CPLogRegister(CPLogConsole);
//create our non ui objects
itemsArray = [[Item new]];
var notWrongItem = [Item new];
[notWrongItem setRightOrWrong:"also right"];
itemsArray = [[Item new], notWrongItem];
arrayController = [[CPArrayController alloc] init];
[arrayController setEditable:YES];
[arrayController setObjectClass:Item];
[arrayController setAutomaticallyPreparesContent:YES];
[arrayController setSelectsInsertedObjects:YES];
[arrayController setAvoidsEmptySelection:YES];
@@ -47,19 +49,23 @@ CPLogRegister(CPLogConsole);
tableView = [[CPTableView alloc] initWithFrame:CGRectMake(0, 0, 400, 200)];
//[tableView setCenter:[contentView center]];
[tableView setBackgroundColor:[CPColor redColor]];
var column = [[CPTableColumn alloc] initWithIdentifier:@"name"];
[tableView addTableColumn:column];
column = [[CPTableColumn alloc] initWithIdentifier:@"price"];
[tableView addTableColumn:column];
column = [[CPTableColumn alloc] initWithIdentifier:@"all right"];
[tableView addTableColumn:column];
//[tableView setDataSource:self];
[contentView addSubview:tableView];
//create our bindings
[self createBindings];
@@ -96,9 +102,10 @@ CPLogRegister(CPLogConsole);
[arrayController bind:@"contentArray" toObject:self
withKeyPath:@"itemsArray" options:nil];
// bind the total field -- no options on this one
[totalCountField bind:CPValueBinding toObject:arrayController
withKeyPath:@"arrangedObjects.@sum.price" options:nil];
// bind the total field -- no options on this one
// Currently broken, crashes the app as it tries to pull valueForKey @sum at some point.
//[totalCountField bind:CPValueBinding toObject:arrayController
// withKeyPath:@"arrangedObjects.@sum.price" options:nil];
var bindingOptions = [CPDictionary dictionary];
@@ -108,54 +115,60 @@ CPLogRegister(CPLogConsole);
// binding for selected "name" field
//[selectedNameField bind: @"value" toObject: arrayController
// withKeyPath:@"selection.name" options:bindingOptions];
// binding for "name" column
var tableColumn = [tableView tableColumnWithIdentifier:@"name"];
[tableColumn bind:@"value" toObject: arrayController
withKeyPath:@"arrangedObjects.name" options:bindingOptions];
// binding options for "price"
// no need for placeholder as overridden by formatters
//[bindingOptions removeObjectForKey:@"NSNullPlaceholder"];
//[bindingOptions setObject:YES
// forKey:CPValidatesImmediatelyBindingOption];
// binding for selected "price" field
//[selectedPriceField bind: @"value" toObject: arrayController
// withKeyPath:@"selection.price" options:bindingOptions];
// binding for "price" column
tableColumn = [tableView tableColumnWithIdentifier:@"price"];
[tableColumn bind:@"value" toObject: arrayController
withKeyPath:@"arrangedObjects.price" options:bindingOptions];
tableColumn = [tableView tableColumnWithIdentifier:@"all right"];
var bindingOptions = [CPDictionary dictionaryWithObject:[WLWrongToRightTransformer new] forKey:CPValueTransformerBindingOption];
[tableColumn bind:@"value" toObject:arrayController withKeyPath:@"arrangedObjects.rightOrWrong" options:bindingOptions];
}
- (unsigned int)countOfItemsArray
- (unsigned int)countOfItemsArray
{
return [itemsArray count];
}
- (id)objectInItemsArrayAtIndex:(unsigned int)index
- (id)objectInItemsArrayAtIndex:(unsigned int)index
{
return [itemsArray objectAtIndex:index];
}
- (void)insertObject:(id)anObject inItemsArrayAtIndex:(unsigned int)index
- (void)insertObject:(id)anObject inItemsArrayAtIndex:(unsigned int)index
{
[itemsArray insertObject:anObject atIndex:index];
}
- (void)removeObjectFromItemsArrayAtIndex:(unsigned int)index
- (void)removeObjectFromItemsArrayAtIndex:(unsigned int)index
{
[itemsArray removeObjectAtIndex:index];
}
- (void)replaceObjectInItemsArrayAtIndex:(unsigned int)index withObject:(id)anObject
- (void)replaceObjectInItemsArrayAtIndex:(unsigned int)index withObject:(id)anObject
{
[itemsArray replaceObjectAtIndex:index withObject:anObject];
}
@@ -166,6 +179,7 @@ CPLogRegister(CPLogConsole);
{
float price @accessors;
CPString name @accessors;
CPString rightOrWrong @accessors;
}
- (id)init
@@ -173,6 +187,7 @@ CPLogRegister(CPLogConsole);
self = [super init];
price = 7.0;
name = "bob";
rightOrWrong = "wrong";
return self;
}
@@ -185,3 +200,24 @@ CPLogRegister(CPLogConsole);
}
@end
@implementation WLWrongToRightTransformer : CPValueTransformer
{
}
+ (BOOL)allowsReverseTransformation
{
return NO;
}
+ (Class)transformedValueClass
{
return [CPString class];
}
- (id)transformedValue:(id)aValue
{
return aValue == "wrong" ? "right" : aValue;
}
@end
+93
View File
@@ -0,0 +1,93 @@
/*
* AppController.j
* CPAlertTest
*
* Created by Alexander Ljungberg on August 19, 2010.
* Copyright 2010, WireLoad, LLC All rights reserved.
*/
@import <Foundation/CPObject.j>
@implementation AppController : CPObject
{
CPTextField label;
CPArray variations;
CPArray messages;
int messageIndex;
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
messages = [
[@"Are you sure you want to theorise before you have data?",
@"Invariably, you end up twisting facts to suit theories, instead of theories to suit facts.",
"Theorise", "Cancel"],
[@"Snakes. Why did it have to be snakes?",
nil,
"Torch", "Cancel"],
[@"Sometimes a message can be really long and just appear to go on and on. It could be a speech. It could be the television.",
nil,
"Off", "Cancel"]
];
messageIndex = 0;
variations = [
[nil, CPWarningAlertStyle],
[nil, CPInformationalAlertStyle],
[nil, CPCriticalAlertStyle],
[CPHUDBackgroundWindowMask, CPWarningAlertStyle],
[CPHUDBackgroundWindowMask, CPInformationalAlertStyle],
[CPHUDBackgroundWindowMask, CPCriticalAlertStyle],
];
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
contentView = [theWindow contentView];
label = [[CPTextField alloc] initWithFrame:CGRectMake(15, 15, 400, 24)];
[label setStringValue:"Respond to the alert dialog with the mouse or the keyboard."];
[contentView addSubview:label];
[theWindow orderFront:self];
[self showNextAlertVariation];
// Uncomment the following line to turn on the standard menu bar.
//[CPMenu setMenuBarVisible:YES];
}
- (void)alertDidEnd:(CPAlert)anAlert returnCode:(id)returnCode
{
if (returnCode === 0)
[label setStringValue:"You chose the default action."];
else
[label setStringValue:"You cancelled the dialog."];
[self showNextAlertVariation];
}
- (void)showNextAlertVariation
{
if (![variations count])
return;
var variation = variations[0],
message = messages[messageIndex],
alert = [[CPAlert alloc] init];
messageIndex = (messageIndex + 1) % messages.length;
[variations removeObjectAtIndex:0];
[alert setDelegate:self];
[alert setMessageText:message[0]];
[alert setInformativeText:message[1]];
[alert addButtonWithTitle:message[2]];
[alert addButtonWithTitle:message[3]];
[alert setWindowStyle:variation[0]];
[alert setAlertStyle:variation[1]];
[alert runModal];
}
@end
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CPApplicationDelegateClass</key>
<string>AppController</string>
<key>CPBundleName</key>
<string>CPAlertTest</string>
<key>CPPrincipalClass</key>
<string>CPApplication</string>
</dict>
</plist>
+93
View File
@@ -0,0 +1,93 @@
/*
* Jakefile
* CPAlertTest
*
* Created by Alexander Ljungberg on August 19, 2010.
* Copyright 2010, WireLoad, LLC All rights reserved.
*/
var ENV = require("system").env,
FILE = require("file"),
JAKE = require("jake"),
task = JAKE.task,
FileList = JAKE.FileList,
app = require("cappuccino/jake").app,
configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug",
OS = require("os");
app ("CPAlertTest", function(task)
{
task.setBuildIntermediatesPath(FILE.join("Build", "CPAlertTest.build", configuration));
task.setBuildPath(FILE.join("Build", configuration));
task.setProductName("CPAlertTest");
task.setIdentifier("com.yourcompany.CPAlertTest");
task.setVersion("1.0");
task.setAuthor("WireLoad, LLC");
task.setEmail("feedback @nospam@ yourcompany.com");
task.setSummary("CPAlertTest");
task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**")));
task.setResources(new FileList("Resources/**"));
task.setIndexFilePath("index.html");
task.setInfoPlistPath("Info.plist");
if (configuration === "Debug")
task.setCompilerFlags("-DDEBUG -g");
else
task.setCompilerFlags("-O");
});
task ("default", ["CPAlertTest"], function()
{
printResults(configuration);
});
task ("build", ["default"]);
task ("debug", function()
{
ENV["CONFIGURATION"] = "Debug";
JAKE.subjake(["."], "build", ENV);
});
task ("release", function()
{
ENV["CONFIGURATION"] = "Release";
JAKE.subjake(["."], "build", ENV);
});
task ("run", ["debug"], function()
{
OS.system(["open", FILE.join("Build", "Debug", "CPAlertTest", "index.html")]);
});
task ("run-release", ["release"], function()
{
OS.system(["open", FILE.join("Build", "Release", "CPAlertTest", "index.html")]);
});
task ("deploy", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Deployment", "CPAlertTest"));
OS.system(["press", "-f", FILE.join("Build", "Release", "CPAlertTest"), FILE.join("Build", "Deployment", "CPAlertTest")]);
printResults("Deployment")
});
task ("desktop", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Desktop", "CPAlertTest"));
require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "CPAlertTest"), FILE.join("Build", "Desktop", "CPAlertTest", "CPAlertTest.app"));
printResults("Desktop")
});
task ("run-desktop", ["desktop"], function()
{
OS.system([FILE.join("Build", "Desktop", "CPAlertTest", "CPAlertTest.app", "Contents", "MacOS", "NativeHost"), "-i"]);
});
function printResults(configuration)
{
print("----------------------------");
print(configuration+" app built at path: "+FILE.join("Build", configuration, "CPAlertTest"));
print("----------------------------");
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+104
View File
@@ -0,0 +1,104 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!--
index-debug.html
CPAlertTest
Created by Alexander Ljungberg on August 19, 2010.
Copyright 2010, WireLoad, LLC All rights reserved.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="apple-touch-icon" href="Resources/icon.png" />
<link rel="apple-touch-startup-image" href="Resources/default.png" />
<title>CPAlertTest</title>
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks", "SomethingElse"];
</script>
<script src="Frameworks/Debug/Objective-J/Objective-J.js" type="text/javascript" charset="UTF-8"></script>
<script type="text/javascript">
objj_msgSend_reset();
// DEBUG OPTIONS:
// Uncomment to enable printing of backtraces on exceptions:
//objj_msgSend_decorate(objj_backtrace_decorator);
// Uncomment to supress exceptions that take place inside a message
//objj_msgSend_decorate(objj_supress_exceptions_decorator)
// Uncomment to enable runtime type checking:
//objj_msgSend_decorate(objj_typecheck_decorator);
// Uncomment (along with both above) to print backtraces on type check errors:
//objj_typecheck_prints_backtrace = true;
// Uncomment to disable the default logger (CPLogConsole if window.console exists, CPLogPopup otherwise):
//CPLogUnregister(CPLogDefault);
// Uncomment to enable a specific logger:
//CPLogRegister(CPLogConsole);
//CPLogRegister(CPLogPopup);
</script>
<style type="text/css">
body{margin:0; padding:0;}
#container {position: absolute; top:50%; left:50%;}
#content {width:800px; text-align:center; margin-left: -400px; height:50px; margin-top:-25px; line-height: 50px;}
#content {font-family: "Helvetica", "Arial", sans-serif; font-size: 18px; color: black; text-shadow: 0px 1px 0px white; }
#loadgraphic {margin-right: 0.2em; margin-bottom:-2px;}
</style>
<!--[if lt IE 7]>
<STYLE type="text/css">
#container { position: relative; top: 50%; }
#content { position: relative;}
</STYLE>
<![endif]-->
</head>
<body style="">
<div id="cappuccino-body">
<div id="loadingcontainer" style="background-color: #eeeeee; overflow:hidden; width:100%; height:100%; position: absolute; top: 0; left: 0;">
<script type="text/javascript">
document.write("<div id='container'><p id='content'>" +
"<img id='loadgraphic' width='16' height='16' src='Resources/spinner.gif' /> " +
"Loading CPAlertTest...</p></div>");
</script>
<noscript>
<div id="container">
<div style="width: 440px; padding: 10px 25px 20px 25px; font-family: sans-serif; background-color: #ffffff; position: relative; left: -245px; top: -120px; text-align: center; -moz-border-radius: 20px; -webkit-border-radius: 20px; color: #555555">
<p style="line-height: 1.4em;">JavaScript is required for this site to work correctly but is either disabled or not supported by your browser.</p>
<p style="font-size:120%; padding:10px;"><a href="http://cappuccino.org/noscript">Show me how to enable JavaScript</a></p>
<p style="font-size:80%;">You may want to upgrade to a newer browser while you're at it:</p>
<ul style="margin:0;padding:0; text-align: center; font-size:80%;" >
<li style="display: inline;"><a href="http://www.apple.com/safari/download/">Safari</a></li>
<li style="display: inline;"><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a></li>
<li style="display: inline;"><a href="http://www.google.com/chrome/">Chrome</a></li>
<li style="display: inline;"><a href="http://www.opera.com/download/">Opera</a></li>
<li style="display: inline;"><a href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer</a></li>
</ul>
</div>
</div>
</noscript>
</div>
</div>
</body>
</html>
+79
View File
@@ -0,0 +1,79 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!--
index.html
CPAlertTest
Created by Alexander Ljungberg on August 19, 2010.
Copyright 2010, WireLoad, LLC All rights reserved.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="apple-touch-icon" href="Resources/icon.png" />
<link rel="apple-touch-startup-image" href="Resources/default.png" />
<title>CPAlertTest</title>
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
</script>
<script type="text/javascript" src="Frameworks/Objective-J/Objective-J.js" charset="UTF-8"></script>
<style type="text/css">
body{margin:0; padding:0;}
#container {position: absolute; top:50%; left:50%;}
#content {width:800px; text-align:center; margin-left: -400px; height:50px; margin-top:-25px; line-height: 50px;}
#content {font-family: "Helvetica", "Arial", sans-serif; font-size: 18px; color: black; text-shadow: 0px 1px 0px white; }
#loadgraphic {margin-right: 0.2em; margin-bottom:-2px;}
</style>
<!--[if lt IE 7]>
<STYLE type="text/css">
#container { position: relative; top: 50%; }
#content { position: relative;}
</STYLE>
<![endif]-->
</head>
<body style="">
<div id="cappuccino-body">
<div id="loadingcontainer" style="background-color: #eeeeee; overflow:hidden; width:100%; height:100%; position: absolute; top: 0; left: 0;">
<script type="text/javascript">
document.write("<div id='container'><p id='content'>" +
"<img id='loadgraphic' width='16' height='16' src='Resources/spinner.gif' /> " +
"Loading CPAlertTest...</p></div>");
</script>
<noscript>
<div id="container">
<div style="width: 440px; padding: 10px 25px 20px 25px; font-family: sans-serif; background-color: #ffffff; position: relative; left: -245px; top: -120px; text-align: center; -moz-border-radius: 20px; -webkit-border-radius: 20px; color: #555555">
<p style="line-height: 1.4em;">JavaScript is required for this site to work correctly but is either disabled or not supported by your browser.</p>
<p style="font-size:120%; padding:10px;"><a href="http://cappuccino.org/noscript">Show me how to enable JavaScript</a></p>
<p style="font-size:80%;">You may want to upgrade to a newer browser while you're at it:</p>
<ul style="margin:0;padding:0; text-align: center; font-size:80%;" >
<li style="display: inline;"><a href="http://www.apple.com/safari/download/">Safari</a></li>
<li style="display: inline;"><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a></li>
<li style="display: inline;"><a href="http://www.google.com/chrome/">Chrome</a></li>
<li style="display: inline;"><a href="http://www.opera.com/download/">Opera</a></li>
<li style="display: inline;"><a href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer</a></li>
</ul>
</div>
</div>
</noscript>
</div>
</div>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
/*
* AppController.j
* CPAlertTest
*
* Created by Alexander Ljungberg on August 19, 2010.
* Copyright 2010, WireLoad, LLC All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import "AppController.j"
function main(args, namedArgs)
{
CPApplicationMain(args, namedArgs);
}
+124 -122
View File
@@ -217,14 +217,15 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it parses.
# With this tag you can assign which parser to use for a given extension.
# Doxygen has a built-in mapping, but you can override or extend it using this tag.
# The format is ext=language, where ext is a file extension, and language is one of
# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given extension.
# Doxygen has a built-in mapping, but you can override or extend it using this
# tag. The format is ext=language, where ext is a file extension, and language
# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
EXTENSION_MAPPING = j=Objective-C
@@ -255,7 +256,7 @@ SIP_SUPPORT = NO
# setting a simple type. If this is not the case, or you want to show the
# methods anyway, you should set this option to NO.
IDL_PROPERTY_SUPPORT = YES
IDL_PROPERTY_SUPPORT = NO
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES, then doxygen will reuse the documentation of the first
@@ -396,13 +397,13 @@ HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
# will list include files with double quotes in the documentation
# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
# will list include files with double quotes in the documentation
# rather than with sharp brackets.
FORCE_LOCAL_INCLUDES = NO
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
INLINE_INFO = YES
@@ -421,12 +422,13 @@ SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = YES
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
# (brief and detailed) documentation of class members so that constructors and
# destructors are listed first. If set to NO (the default) the constructors will
# appear in the respective orders defined by SORT_MEMBER_DOCS and
# SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is
# set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
# will sort the (brief and detailed) documentation of class members so that
# constructors and destructors are listed first. If set to NO (the default)
# the constructors will appear in the respective orders defined by
# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
SORT_MEMBERS_CTORS_1ST = NO
@@ -504,8 +506,7 @@ SHOW_DIRECTORIES = NO
SHOW_FILES = YES
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
# Namespaces page.
# This will remove the Namespaces entry from the Quick Index
# Namespaces page. This will remove the Namespaces entry from the Quick Index
# and from the Folder Tree View (if specified). The default is YES.
SHOW_NAMESPACES = YES
@@ -520,12 +521,12 @@ SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
# doxygen. The layout file controls the global structure of the generated output files
# in an output format independent way. The create the layout file that represents
# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
# file name after the option, if omitted DoxygenLayout.xml will be used as the name
# of the layout file.
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. The create the layout file
# that represents doxygen's defaults, run doxygen with the -l option.
# You can optionally specify a file name after the option, if omitted
# DoxygenLayout.xml will be used as the name of the layout file.
LAYOUT_FILE =
@@ -589,8 +590,8 @@ WARN_LOGFILE = debug.txt
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = AppKit.doc \
Foundation.doc
INPUT = AppKit \
Foundation
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -650,7 +651,7 @@ RECURSIVE = YES
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE = AppKit.doc/Themes
EXCLUDE = AppKit/Themes
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix filesystem feature) are excluded
@@ -706,17 +707,14 @@ IMAGE_PATH =
# by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes
# to standard output.
# If FILTER_PATTERNS is specified, this tag will be
# to standard output. If FILTER_PATTERNS is specified, this tag will be
# ignored.
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis.
# Doxygen will compare the file name with each pattern and apply the
# filter if there is a match.
# The filters are a list of the form:
# basis. Doxygen will compare the file name with each pattern and apply the
# filter if there is a match. The filters are a list of the form:
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
# is applied to all files.
@@ -766,8 +764,7 @@ REFERENCES_RELATION = NO
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
# link to the source code.
# Otherwise they will link to the documentation.
# link to the source code. Otherwise they will link to the documentation.
REFERENCES_LINK_SOURCE = YES
@@ -839,7 +836,7 @@ HTML_HEADER =
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
HTML_FOOTER =
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
@@ -848,41 +845,41 @@ HTML_FOOTER =
# the style sheet file to the HTML output directory, so don't put your own
# stylesheet in the HTML output directory as well, or it will be erased!
HTML_STYLESHEET =
HTML_STYLESHEET =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
# Doxygen will adjust the colors in the stylesheet and background images
# according to this color. Hue is specified as an angle on a colorwheel,
# see http://en.wikipedia.org/wiki/Hue for more information.
# For instance the value 0 represents red, 60 is yellow, 120 is green,
# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
# Doxygen will adjust the colors in the stylesheet and background images
# according to this color. Hue is specified as an angle on a colorwheel,
# see http://en.wikipedia.org/wiki/Hue for more information.
# For instance the value 0 represents red, 60 is yellow, 120 is green,
# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
# The allowed range is 0 to 359.
HTML_COLORSTYLE_HUE = 220
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
# the colors in the HTML output. For a value of 0 the output will use
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
# the colors in the HTML output. For a value of 0 the output will use
# grayscales only. A value of 255 will produce the most vivid colors.
HTML_COLORSTYLE_SAT = 98
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
# the luminance component of the colors in the HTML output. Values below
# 100 gradually make the output lighter, whereas values above 100 make
# the output darker. The value divided by 100 is the actual gamma applied,
# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
# the luminance component of the colors in the HTML output. Values below
# 100 gradually make the output lighter, whereas values above 100 make
# the output darker. The value divided by 100 is the actual gamma applied,
# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
# and 100 does not change the gamma.
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting
# this to NO can help when comparing the output of multiple runs.
HTML_TIMESTAMP = YES
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
@@ -903,7 +900,8 @@ HTML_DYNAMIC_SECTIONS = YES
# directory and running "make install" will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
# it at startup.
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
GENERATE_DOCSET = NO
@@ -921,8 +919,8 @@ DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
# string, e.g. com.mycompany.MyDocSet.documentation.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
@@ -931,9 +929,9 @@ DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
# of the generated HTML documentation.
GENERATE_HTMLHELP = NO
@@ -975,10 +973,10 @@ BINARY_TOC = NO
TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
# are set, an additional index file will be generated that can be used as input for
# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
# HTML documentation.
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
# that can be used as input for Qt's qhelpgenerator to generate a
# Qt Compressed Help (.qch) of the generated HTML documentation.
GENERATE_QHP = NO
@@ -992,7 +990,7 @@ QCH_FILE =
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#namespace
QHP_NAMESPACE =
QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
@@ -1000,47 +998,47 @@ QHP_NAMESPACE =
QHP_VIRTUAL_FOLDER = doc
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
# For more information please see
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
# add. For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
# Qt Help Project / Custom Filters</a>.
QHP_CUST_FILTER_ATTRS =
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's
# filter section matches.
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's
# filter section matches.
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
# Qt Help Project / Filter Attributes</a>.
QHP_SECT_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
# be used to specify the location of Qt's qhelpgenerator.
# If non-empty doxygen will try to run qhelpgenerator on the generated
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
# be used to specify the location of Qt's qhelpgenerator.
# If non-empty doxygen will try to run qhelpgenerator on the generated
# .qhp file.
QHG_LOCATION =
QHG_LOCATION =
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
# will be generated, which together with the HTML files, form an Eclipse help
# plugin. To install this plugin and make it available under the help contents
# menu in Eclipse, the contents of the directory containing the HTML and XML
# files needs to be copied into the plugins directory of eclipse. The name of
# the directory within the plugins directory should be the same as
# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
# will be generated, which together with the HTML files, form an Eclipse help
# plugin. To install this plugin and make it available under the help contents
# menu in Eclipse, the contents of the directory containing the HTML and XML
# files needs to be copied into the plugins directory of eclipse. The name of
# the directory within the plugins directory should be the same as
# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
# the help appears.
GENERATE_ECLIPSEHELP = NO
# A unique identifier for the eclipse help plugin. When installing the plugin
# the directory name containing the HTML and XML files should also have
# A unique identifier for the eclipse help plugin. When installing the plugin
# the directory name containing the HTML and XML files should also have
# this name.
ECLIPSE_DOC_ID = org.doxygen.Project
@@ -1077,7 +1075,7 @@ USE_INLINE_TREES = NO
TREEVIEW_WIDTH = 250
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
# links to external symbols imported via tag files in a separate window.
EXT_LINKS_IN_WINDOW = NO
@@ -1090,30 +1088,30 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are
# not supported properly for IE 6.0, but are supported on all modern browsers.
# Note that when changing this option you need to delete any form_*.png files
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are
# not supported properly for IE 6.0, but are supported on all modern browsers.
# Note that when changing this option you need to delete any form_*.png files
# in the HTML output before the changes have effect.
FORMULA_TRANSPARENT = YES
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
# for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using
# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
# (GENERATE_DOCSET) there is already a search function so this one should
# typically be disabled. For large projects the javascript based search engine
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
# for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using
# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
# (GENERATE_DOCSET) there is already a search function so this one should
# typically be disabled. For large projects the javascript based search engine
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a PHP enabled web server instead of at the web client
# using Javascript. Doxygen will generate the search PHP script and index
# file to put on the web server. The advantage of the server
# based approach is that it scales better to large projects and allows
# full text search. The disadvances is that it is more difficult to setup
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a PHP enabled web server instead of at the web client
# using Javascript. Doxygen will generate the search PHP script and index
# file to put on the web server. The advantage of the server
# based approach is that it scales better to large projects and allows
# full text search. The disadvances is that it is more difficult to setup
# and does not have live searching capabilities.
SERVER_BASED_SEARCH = NO
@@ -1135,6 +1133,9 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked. If left blank `latex' will be used as the default command name.
# Note that when enabling USE_PDFLATEX this option is only used for
# generating bitmaps for formulas in the HTML output, but not in the
# Makefile that is written to the output directory.
LATEX_CMD_NAME = latex
@@ -1194,7 +1195,10 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
# If LATEX_SOURCE_CODE is set to YES then doxygen will include
# source code with syntax highlighting in the LaTeX output.
# Note that which sources are shown also depends on other settings
# such as SOURCE_BROWSER.
LATEX_SOURCE_CODE = NO
@@ -1333,10 +1337,10 @@ GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
# nicely formatted so it can be parsed by a human reader. This is useful
# if you want to understand what is going on. On the other hand, if this
# tag is set to NO the size of the Perl module output will be much smaller
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
# nicely formatted so it can be parsed by a human reader. This is useful
# if you want to understand what is going on. On the other hand, if this
# tag is set to NO the size of the Perl module output will be much smaller
# and Perl will parse it just the same.
PERLMOD_PRETTY = YES
@@ -1363,7 +1367,7 @@ ENABLE_PREPROCESSING = YES
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = YES
MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
@@ -1422,11 +1426,9 @@ SKIP_FUNCTION_MACROS = YES
# Optionally an initial location of the external documentation
# can be added for each tagfile. The format of a tag file without
# this location is as follows:
#
# TAGFILES = file1 file2 ...
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
#
# TAGFILES = file1=loc1 "file2 = loc2" ...
# TAGFILES = file1=loc1 "file2 = loc2" ...
# where "loc1" and "loc2" can be relative or absolute paths or
# URLs. If a location is present for each tag, the installdox tool
# does not have to be run to correct the links.
@@ -1494,10 +1496,10 @@ HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
# allowed to run in parallel. When set to 0 (the default) doxygen will
# base this on the number of processors available in the system. You can set it
# explicitly to a value larger than 0 to get control over the balance
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
# allowed to run in parallel. When set to 0 (the default) doxygen will
# base this on the number of processors available in the system. You can set it
# explicitly to a value larger than 0 to get control over the balance
# between CPU load and processing speed.
DOT_NUM_THREADS = 0
+4 -4
View File
@@ -3,7 +3,7 @@
def makeHeaderFileFrom(fileName)
# Grab the entire file (text)
data = File.new(fileName).read
# Extract out all the "implementation" lines. Note, there may be
# more than on in a given .j file.
m = data.scan(/.*?(@implementation.*?\{.*?\})/m)
@@ -11,16 +11,16 @@ def makeHeaderFileFrom(fileName)
if m.length > 0
for i in 0...m.length
line = m[i][0]
# Skip category definitions
if not /.*?\(.*?\).*?\{/m.match(line)
# Extract the class name
m2 = line.scan(/.*?@implementation(.*?):.*/m)
if !m2.nil? && !m2[0].nil?
className = m2[0][0].strip()
# Change "implementation" to "interface", create the .h file, and write the interface
newLine = line.sub("implementation", "interface")
newFileName = File.dirname(fileName) + "/" + className + ".h"
+8 -5
View File
@@ -266,12 +266,15 @@ global.subjake = function(/*Array<String>*/ directories, /*String*/ aTaskName)
});
}
global.executableExists = function(/*String*/ aFileName)
global.executableExists = function(/*String*/ executableName)
{
return SYSTEM.env["PATH"].split(':').some(function(/*String*/ aPath)
{
return FILE.exists(FILE.join(aPath, aFileName));
});
var paths = SYSTEM.env["PATH"].split(':');
for (var i = 0; i < paths.length; i++) {
var path = FILE.join(paths[i], executableName);
if (FILE.exists(path))
return path;
}
return null;
}
$OBJJ_TEMPLATE_EXECUTABLE = FILE.join($HOME_DIR, "Objective-J", "CommonJS", "objj-executable");