New: CPAlert supports custom didEnd selector or block.

Previously, unless you were using a sheet alert, there was no way to set a custom dismissal handler for an alert. In Cocoa alerts are synchronous, in Cappuccino they are asynchronous, which meant that a single dismissal handler had to handle all possible non-sheet alerts.

This commit adds several methods which add two ways to specify a custom dismissal handler: via delegate/selector, and via a block (function). The new methods are:

setDidEndSelector:
runModalWithDidEndBlock:
beginSheetModalForWindow:didEndBlock:

Note that didEnd blocks are transient and take precedence over didEnd selectors.

The CPAlertTest demo was updated to fix some bugs and added the ability to run the tests using blocks.
This commit is contained in:
Aparajita Fishman committed 2013-07-29 13:06:57 -04:00
1 parent 1df1c1e9ab
commit 2b23374ec7
2 files changed
+112 -29

No files matched your search

+64 -23
View File
@@ -96,7 +96,8 @@ var bottomHeight = 71;
id _delegate @accessors(property=delegate);
id _modalDelegate;
SEL _didEndSelector;
SEL _didEndSelector @accessors(property=didEndSelector);
Function _didEndBlock;
_CPAlertThemeView _themeView @accessors(property=themeView, readonly);
CPWindow _window @accessors(property=window, readonly);
@@ -224,16 +225,15 @@ var bottomHeight = 71;
}
/*! @deprecated
*/
- (void)setWindowStyle:(int)aStyle
/*! @deprecated */
- (void)setWindowStyle:(int)style
{
CPLog.warn("DEPRECATED: setWindowStyle: is deprecated. use setTheme: instead");
[self setTheme:(aStyle === CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
[self setTheme:(style === CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
}
/*! @deprecated
*/
/*! @deprecated */
- (int)windowStyle
{
CPLog.warn("DEPRECATED: windowStyle: is deprecated. use theme instead");
@@ -242,18 +242,19 @@ var bottomHeight = 71;
/*!
set the text of the alert's message
Set the text of the alert's message.
@param aText CPString containing the text
*/
- (void)setMessageText:(CPString)aText
- (void)setMessageText:(CPString)text
{
[_messageLabel setStringValue:aText];
[_messageLabel setStringValue:text];
_needsLayout = YES;
}
/*!
return the content of the message text
Return the content of the message text.
@return CPString containing the message text
*/
- (CPString)messageText
@@ -262,13 +263,13 @@ var bottomHeight = 71;
}
/*!
set the text of the alert's informative text
Set the text of the alert's informative text.
@param aText CPString containing the informative text
*/
- (void)setInformativeText:(CPString)aText
- (void)setInformativeText:(CPString)text
{
[_informativeLabel setStringValue:aText];
[_informativeLabel setStringValue:text];
_needsLayout = YES;
}
@@ -285,6 +286,7 @@ var bottomHeight = 71;
/*!
Sets the title of the alert window.
This API is not present in Cocoa.
@param aTitle CPString containing the window title
*/
- (void)setTitle:(CPString)aTitle
@@ -294,7 +296,7 @@ var bottomHeight = 71;
}
/*!
set the accessory view
Set the accessory view.
@param aView the accessory view
*/
@@ -305,7 +307,7 @@ var bottomHeight = 71;
}
/*!
set if alert shows the suppression button
Set if the alert shows the suppression button.
@param shouldShowSuppressionButton YES or NO
*/
@@ -596,6 +598,17 @@ var bottomHeight = 71;
[CPApp runModalForWindow:_window];
}
/*!
The same as \c runModal, but executes the code in \c block when the
alert is dismissed.
*/
- (void)runModalWithDidEndBlock:(Function /*(CPAlert alert, int returnCode)*/)block
{
_didEndBlock = block;
[self runModal];
}
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
@@ -630,6 +643,20 @@ var bottomHeight = 71;
[self beginSheetModalForWindow:aWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
}
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
Executes the code in \c block when the alert is dismissed.
@param window The parent window for the sheet.
@param block Code block to execute on dismissal
*/
- (void)beginSheetModalForWindow:(CPWindow)aWindow didEndBlock:(Function /*(CPAlert alert, int returnCode)*/)block
{
_didEndBlock = block;
[self beginSheetModalForWindow:aWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
}
#pragma mark Private
/*!
@@ -697,14 +724,28 @@ var bottomHeight = 71;
*/
- (void)_alertDidEnd:(CPWindow)aWindow returnCode:(int)returnCode contextInfo:(id)contextInfo
{
if (_didEndSelector)
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
if (_didEndBlock)
{
if (typeof(_didEndBlock) === "function")
_didEndBlock(self, returnCode);
else
CPLog.warn("%s: didEnd block is not a function", [self description]);
_modalDelegate = nil;
_didEndSelector = nil;
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:returnCode];
// didEnd blocks are transient
_didEndBlock = nil;
}
else if (_modalDelegate)
{
if (_didEndSelector)
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
}
else if (_delegate)
{
if (_didEndSelector)
objj_msgSend(_delegate, _didEndSelector, self, returnCode);
else if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:returnCode];
}
}
@end
+48 -6
View File
@@ -16,9 +16,10 @@
CPArray variations;
CPArray messages;
int messageIndex;
BOOL useBlocks;
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
- (void)_init
{
messages = [
[@"Are you sure you want to theorise before you have data?",
@@ -30,6 +31,7 @@
[@"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]
];
messageIndex = 0;
variations = [
@@ -43,6 +45,11 @@
[CPDocModalWindowMask, CPInformationalAlertStyle],
[CPDocModalWindowMask, CPCriticalAlertStyle]
];
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
[self _init];
theWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(100, 100, 500, 500) styleMask:CPTitledWindowMask];
[theWindow setTitle:@"CPAlert Test"];
@@ -54,6 +61,13 @@
[label setStringValue:"Respond to the alert dialog with the mouse or the keyboard."];
[contentView addSubview:label];
var button = [CPButton buttonWithTitle:@"Start again using didEnd blocks"];
[button setTarget:self];
[button setAction:@selector(testWithBlocks:)];
[button setCenter:[contentView center]];
[contentView addSubview:button];
[theWindow orderFront:self];
[self showNextAlertVariation];
@@ -62,9 +76,17 @@
//[CPMenu setMenuBarVisible:YES];
}
- (@action)testWithBlocks:(id)sender
{
useBlocks = YES;
[self _init];
[self showNextAlertVariation];
}
- (void)alertDidEnd:(CPAlert)anAlert returnCode:(CPInteger)returnCode
{
CPLogConsole(_cmd);
CPLog.info("%s alert = %s, code = %d", _cmd, [anAlert description], returnCode);
if (returnCode === 0)
[label setStringValue:"You chose the default action."];
else
@@ -75,7 +97,7 @@
- (void)customDidEnd:(CPAlert)anAlert code:(id)code context:(id)context
{
CPLogConsole(_cmd + anAlert + code + context);
CPLog.info("%s alert = %s, code = %d, context = %s", _cmd, [anAlert description], code, context);
}
- (void)showNextAlertVariation
@@ -92,17 +114,37 @@
var windowStyle = variation[0];
[alert setDelegate:self];
[alert setMessageText:message[0]];
[alert setInformativeText:message[1]];
[alert setMessageText:message[0] || @""];
[alert setInformativeText:message[1] || @""];
if (message.length > 2)
[alert addButtonWithTitle:message[2]];
if (message.length > 3)
[alert addButtonWithTitle:message[3]];
[alert setTheme:(windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
[alert setAlertStyle:variation[1]];
if (windowStyle & CPDocModalWindowMask)
[alert beginSheetModalForWindow:theWindow modalDelegate:self didEndSelector:@selector(customDidEnd:code:context:) contextInfo:@"here is some context"];
{
if (useBlocks)
[alert beginSheetModalForWindow:theWindow didEndBlock:function(alert, returnCode)
{
CPLog.info("didEndBlock: alert = %s, code = %d", [alert description], returnCode);
[self showNextAlertVariation];
}];
else
[alert beginSheetModalForWindow:theWindow modalDelegate:self didEndSelector:@selector(customDidEnd:code:context:) contextInfo:@"here is some context"];
}
else if (useBlocks)
[alert runModalWithDidEndBlock:function(alert, returnCode)
{
CPLog.info("didEndBlock: alert = %s, code = %d", [alert description], returnCode);
[self showNextAlertVariation];
}];
else
[alert runModal];
}