From ee4802e5130ee3abd41c7f8df730a3c5b38e0d83 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Tue, 24 Aug 2010 00:32:26 +0200 Subject: [PATCH] CPAlert: Attached alerts. Added a new method -beginSheetModalForWindow: that calls -alertDidEnd:returnCode: on ending. CPAlertTest update testing it. Fixed a bug in CPWindow where the didEndSelector was reset too early. This bug was visible only when trying to chain sheet alerts. Fixed a local/instance variable conflict in AttachedSheet/AppController.j --- AppKit/CPAlert.j | 68 ++++++++++++++++++---- AppKit/CPWindow/CPWindow.j | 23 +++++--- Tests/Manual/AttachedSheet/AppController.j | 27 ++++----- Tests/Manual/CPAlertTest/AppController.j | 26 +++++++-- 4 files changed, 105 insertions(+), 39 deletions(-) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 22e166a53..d82dcb2a4 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -51,7 +51,6 @@ CPInformationalAlertStyle = 1; */ CPCriticalAlertStyle = 2; - /*! @ingroup appkit @@ -88,6 +87,8 @@ CPCriticalAlertStyle = 2; CPArray _buttons; id _delegate; + SEL _didEndSelector; + id _modalDelegate; } + (CPString)themeClass @@ -126,6 +127,7 @@ CPCriticalAlertStyle = 2; _alertStyle = CPWarningAlertStyle; _alertPanel = nil; _windowStyle = nil; + _alertDidEndSelector = nil; _messageLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; _alertImageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()]; @@ -145,7 +147,7 @@ CPCriticalAlertStyle = 2; { _windowStyle = styleMask; - [self setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]]; + [self setTheme:(_windowStyle & CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]]; // We'll need to recreate the panel to get the new window style. _alertPanel = nil; @@ -281,7 +283,7 @@ CPCriticalAlertStyle = 2; [button setTitle:title]; [button setTarget:self]; [button setTag:_buttonCount]; - [button setAction:@selector(_notifyDelegate:)]; + [button setAction:@selector(_dismissAlert:)]; [[_alertPanel contentView] addSubview:button]; @@ -397,14 +399,60 @@ CPCriticalAlertStyle = 2; [CPApp runModalForWindow:_alertPanel]; } -/* @ignore */ -- (void)_notifyDelegate:(id)button -{ - [CPApp abortModal]; - [_alertPanel close]; +/* + Runs the receiver modally as an alert sheet attached to a specified window. - if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)]) - [_delegate alertDidEnd:self returnCode:[button tag]]; + @param window The parent window for the sheet. + @param modalDelegate The delegate for the modal-dialog session. + @param alertDidEndSelector Message the alert sends to modalDelegate after the sheet is dismissed. + @param contextInfo Contextual data passed to modalDelegate in didEndSelector message. +*/ +- (void)beginSheetModalForWindow:(CPWindow)window modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(void)contextInfo +{ + [self layoutPanel]; + + _didEndSelector = alertDidEndSelector; + _modalDelegate = modalDelegate; + + [CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo]; +} + +/* + Runs the receiver modally as an alert sheet attached to a specified window. + + @param window The parent window for the sheet. +*/ +- (void)beginSheetModalForWindow:(CPWindow)window +{ + [self layoutPanel]; + + [CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:nil]; +} + +- (void)_alertDidEnd:(CPWindow)aSheet returnCode:(CPInteger)returnCode contextInfo:(id)contextInfo +{ + if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)]) + [_delegate alertDidEnd:self returnCode:returnCode]; + + if (_didEndSelector) + objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo); + + _didEndSelector = nil; + _modalDelegate = nil; +} + +/* @ignore */ +- (void)_dismissAlert:(CPButton)button +{ + if ([_alertPanel isSheet]) + [CPApp endSheet:_alertPanel returnCode:[button tag]]; + else + { + [CPApp abortModal]; + [_alertPanel close]; + + [self _alertDidEnd:nil returnCode:[button tag] contextInfo:nil]; + } } @end diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 71210c9a3..aa4e5e817 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -199,6 +199,8 @@ var SHADOW_MARGIN_LEFT = 20.0, var CPWindowSaveImage = nil, CPWindowSavingImage = nil; + +var CPWindowResizeTime = 0.2; /*! @ingroup appkit @@ -2098,6 +2100,11 @@ CPTexturedBackgroundWindowMask [_frameAnimation startAnimation]; } +- (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame +{ + return CPWindowResizeTime; +} + /* @ignore */ - (void)_setAttachedSheetFrameOrigin { @@ -2146,7 +2153,7 @@ CPTexturedBackgroundWindowMask [aSheet setFrame:startFrame display:YES animate:NO]; _sheetContext["opened"] = YES; - [aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut]; + [aSheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut]; // Should run the main loop here until _isAnimating = FALSE [aSheet becomeKeyWindow]; @@ -2167,7 +2174,7 @@ CPTexturedBackgroundWindowMask [self _setUpMasksForView:sheetContent]; _sheetContext["opened"] = NO; - [sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn]; + [sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn]; } /* @ignore */ @@ -2196,13 +2203,15 @@ CPTexturedBackgroundWindowMask [self _restoreMasksForView:sheetContent]; var delegate = _sheetContext["modalDelegate"], - endSelector = _sheetContext["endSelector"]; - - if (delegate != nil && endSelector != nil) - objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]); + endSelector = _sheetContext["endSelector"], + returnCode = _sheetContext["returnCode"], + contextInfo = _sheetContext["contextInfo"]; _sheetContext = nil; sheet._parentView = nil; + + if (delegate != nil && endSelector != nil) + objj_msgSend(delegate, endSelector, sheet, returnCode, contextInfo); } - (void)_setUpMasksForView:(CPView)aView @@ -2673,7 +2682,7 @@ var interpolate = function(fromValue, toValue, progress) - (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame { - self = [super initWithDuration:0.2 animationCurve:CPAnimationLinear]; + self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear]; if (self) { diff --git a/Tests/Manual/AttachedSheet/AppController.j b/Tests/Manual/AttachedSheet/AppController.j index 1c50847ea..152197203 100644 --- a/Tests/Manual/AttachedSheet/AppController.j +++ b/Tests/Manual/AttachedSheet/AppController.j @@ -22,28 +22,28 @@ [window setMinSize:CGSizeMake(300, 200)]; sheet = [[CPWindow alloc] initWithContentRect:CGRectMake(0,0,300,100) styleMask:CPDocModalWindowMask|CPResizableWindowMask]; [sheet setMinSize:CGSizeMake(300,100)]; - + var sheetContent = [sheet contentView]; - + textField = [[CPTextField alloc] initWithFrame:CGRectMake(10,30,280,30)]; [textField setEditable:YES]; [textField setBezeled:YES]; [textField setAutoresizingMask:CPViewWidthSizable]; - + var okButton = [[CPButton alloc] initWithFrame:CGRectMake(230,70,50,24)]; [okButton setTitle:"OK"]; [okButton setTarget:self]; [okButton setTag:1]; [okButton setAction:@selector(closeSheet:)]; - [okButton setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin]; + [okButton setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin]; var cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(120,70,100,24)]; [cancelButton setTitle:"Cancel"]; [cancelButton setTarget:self]; [cancelButton setTag:0]; - [cancelButton setAction:@selector(closeSheet:)]; - [cancelButton setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin]; - + [cancelButton setAction:@selector(closeSheet:)]; + [cancelButton setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin]; + [sheetContent addSubview:textField]; [sheetContent addSubview:okButton]; [sheetContent addSubview:cancelButton]; @@ -51,9 +51,9 @@ var displayButton = [[CPButton alloc] initWithFrame:CGRectMake(200,150,100,24)]; [displayButton setTitle:"Display Sheet"]; [displayButton setTarget:self]; - [displayButton setAction:@selector(displaySheet:)]; + [displayButton setAction:@selector(displaySheet:)]; [contentView addSubview:displayButton]; - + [window orderFront:self] } @@ -65,20 +65,15 @@ [CPApp beginSheet:sheet modalForWindow:window modalDelegate:self didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) contextInfo:nil]; } -- (void)alertDidEnd:(CPWindow)sheet returnCode:(int)returnCode contextInfo:(id)contextInfo -{ - CPLogConsole(_cmd+" returnCode " + returnCode); -} - - (void)closeSheet:(id)sender { [CPApp endSheet:sheet returnCode:[sender tag]]; } -- (void)didEndSheet:(CPWindow)sheet returnCode:(int)returnCode contextInfo:(id)contextInfo +- (void)didEndSheet:(CPWindow)aSheet returnCode:(int)returnCode contextInfo:(id)contextInfo { var str = [textField stringValue]; - + [sheet orderOut:self]; if (returnCode == CPOKButton && [str length] > 0) { diff --git a/Tests/Manual/CPAlertTest/AppController.j b/Tests/Manual/CPAlertTest/AppController.j index 1b7ffe44c..d8d557b5c 100644 --- a/Tests/Manual/CPAlertTest/AppController.j +++ b/Tests/Manual/CPAlertTest/AppController.j @@ -11,6 +11,7 @@ @implementation AppController : CPObject { + CPWindow theWindow; CPTextField label; CPArray variations; CPArray messages; @@ -21,7 +22,7 @@ { 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.", + @"Invariably, you end up twisting facts to suit theories, instead of theories to suit facts. lkjhdlkfjhlekjhglkjrshlkjfhsglksrjhfsmlgkjfskljhgkljflkjmlgkhjùlrkjhlmkjmrlekjghmlkjermlgkhjmlfekjghmlkjremlkjghmlkerjmlghkjmlerkjgmlhkjmerlkjgmhlkjmelrkjhmlkjrgmlkjhmlkrjgmlhkjrmelkgjhmlkrejhmlkjrgmlhkjmrlkgjhlmkrzj", "Theorise", "Cancel"], [@"Snakes. Why did it have to be snakes?", nil, @@ -39,10 +40,13 @@ [CPHUDBackgroundWindowMask, CPWarningAlertStyle], [CPHUDBackgroundWindowMask, CPInformationalAlertStyle], [CPHUDBackgroundWindowMask, CPCriticalAlertStyle], + [CPDocModalWindowMask, CPWarningAlertStyle], + [CPDocModalWindowMask, CPInformationalAlertStyle], + [CPDocModalWindowMask, CPCriticalAlertStyle] ]; - var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], - contentView = [theWindow contentView]; + theWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(100,100,500,500) styleMask:CPTitledWindowMask]; + var contentView = [theWindow contentView]; label = [[CPTextField alloc] initWithFrame:CGRectMake(15, 15, 400, 24)]; @@ -57,8 +61,9 @@ //[CPMenu setMenuBarVisible:YES]; } -- (void)alertDidEnd:(CPAlert)anAlert returnCode:(id)returnCode +- (void)alertDidEnd:(CPAlert)anAlert returnCode:(CPInteger)returnCode { +CPLogConsole(_cmd); if (returnCode === 0) [label setStringValue:"You chose the default action."]; else @@ -67,6 +72,11 @@ [self showNextAlertVariation]; } +- (void)customDidEnd:(CPAlert)anAlert code:(id)code context:(id)context +{ + CPLogConsole(_cmd + anAlert + code + context); +} + - (void)showNextAlertVariation { if (![variations count]) @@ -79,15 +89,19 @@ messageIndex = (messageIndex + 1) % messages.length; [variations removeObjectAtIndex:0]; + var windowStyle = variation[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 setWindowStyle:windowStyle]; [alert setAlertStyle:variation[1]]; - [alert runModal]; + if (windowStyle & CPDocModalWindowMask) + [alert beginSheetModalForWindow:theWindow modalDelegate:self didEndSelector:@selector(customDidEnd:code:context:) contextInfo:@"here is some context"]; + else + [alert runModal]; } @end