WizardKit  0.1
WKWizardPanel.m
00001 /*
00002  * WKWizardPanel.m
00003  *
00004  * Implementation of the WKWizardPanel class for the WizardKit framework
00005  *
00006  * Copyright (c) 2006, by Saso Kiselkov
00007  *
00008  * For license details please see the file COPYING included with this
00009  * source distribution package.
00010  */
00011 
00012 #import "WKWizardPanel.h"
00013 
00014 #import <Foundation/NSString.h>
00015 #import <Foundation/NSBundle.h>
00016 #import <Foundation/NSArray.h>
00017 #import <Foundation/NSDictionary.h>
00018 #import <Foundation/NSException.h>
00019 #import <Foundation/NSNotification.h>
00020 #import <Foundation/NSCoder.h>
00021 
00022 #import <AppKit/NSApplication.h>
00023 
00029 NSString * const WKWizardPanelDidChangeCurrentStageNotification
00030  = @"WKWizardPanelDidChangeCurrentStageNotification";
00031 
00032 @interface WKWizardPanel (Private)
00033 
00034 - (void) setupForStage: (NSString *) aStage;
00035 
00036 @end
00037 
00063 @implementation WKWizardPanel
00064 
00065 - (void) dealloc
00066 {
00067   TEST_RELEASE(stages);
00068   TEST_RELEASE(initialStage);
00069 
00070   [super dealloc];
00071 }
00072 
00082 - (void) setStages: (NSArray *) someStages
00083 {
00084   if (isActive == YES)
00085     {
00086       [NSException raise: NSInternalInconsistencyException
00087                   format: _(@"-[WKWizardPanel setStages:]: panel already "
00088         @"active - stages must be set before activating the panel.")];
00089     }
00090 
00091   ASSIGNCOPY(stages, someStages);
00092   DESTROY(initialStage);
00093 }
00094 
00102 - (NSArray *) stages
00103 {
00104   return stages;
00105 }
00106 
00115 - (void) setRunsInModalSession: (BOOL) flag
00116 {
00117   if (isActive == YES)
00118     {
00119       [NSException raise: NSInternalInconsistencyException
00120                   format: _(@"-[WKWizardPanel setRunsInModalSession:] "
00121         @"panel already active - modality must be set before activating "
00122         @"the panel.")];
00123     }
00124 
00125   runsInModalSession = flag;
00126 }
00127 
00135 - (BOOL) runsInModalSession
00136 {
00137   return runsInModalSession;
00138 }
00139 
00146 - (void) setInitialStage: (NSString *) aStageName
00147 {
00148   if (aStageName != nil && [stages containsObject: aStageName] == NO)
00149     {
00150       [NSException raise: NSInvalidArgumentException
00151                   format: _(@"-[WKWizardPanel setInitialStage:]: "
00152         @"invalid stage name passed. Stage \"%@\" not in stages list: %@."),
00153         aStageName, stages];
00154     }
00155 
00156   ASSIGN(initialStage, aStageName);
00157 }
00158 
00166 - (NSString *) initialStage
00167 {
00168   return initialStage;
00169 }
00170 
00177 - (void) setCentersBeforeActivating: (BOOL) flag
00178 {
00179   centersBeforeActivating = flag;
00180 }
00181 
00189 - (BOOL) centersBeforeActivating
00190 {
00191   return centersBeforeActivating;
00192 }
00193 
00205 - (void) setCurrentStage: (NSString *) aStageName
00206 {
00207   currentStage = [stages indexOfObject: aStageName];
00208   if (currentStage == NSNotFound)
00209     {
00210       [NSException raise: NSInvalidArgumentException
00211                   format: _(@"-[WKWizardPanel setCurrentStage:]: "
00212         @"invalid stage name passed. Stage \"%@\" not in stages list: %@."),
00213         aStageName, stages];
00214     }
00215 
00216   [self setupForStage: aStageName];
00217 
00218   [[NSNotificationCenter defaultCenter]
00219     postNotificationName: WKWizardPanelDidChangeCurrentStageNotification
00220                   object: self
00221                 userInfo: [NSDictionary dictionaryWithObject: aStageName
00222                                                       forKey: @"Stage"]];
00223 }
00224 
00232 - (NSArray *) currentStage
00233 {
00234   return [stages objectAtIndex: currentStage];
00235 }
00236 
00243 - (void) nextStage: (id) sender
00244 {
00245   if (currentStage + 1 < [stages count])
00246     {
00247       [self setCurrentStage: [stages objectAtIndex: currentStage + 1]];
00248     }
00249 }
00250 
00257 - (void) previousStage: (id) sender
00258 {
00259   if (currentStage > 0)
00260     {
00261       [self setCurrentStage: [stages objectAtIndex: currentStage - 1]];
00262     }
00263 }
00264 
00281 - (int) activate: (id) sender
00282 {
00283   if (isActive)
00284     {
00285       [NSException raise: NSInternalInconsistencyException
00286                   format: _(@"-[WKWizardPanel activate:]: panel "
00287         @"already active.")];
00288     }
00289 
00290   if ([stages count] == 0)
00291     {
00292       [NSException raise: NSInternalInconsistencyException
00293                   format: _(@"-[WKWizardPanel activate:]: no stages "
00294         @"set. You must set the panel's stages before activating it.")];
00295     }
00296 
00297   isActive = YES;
00298 
00299   if (initialStage != nil)
00300     {
00301       [self setCurrentStage: initialStage];
00302     }
00303   else
00304     {
00305       [self setCurrentStage: [stages objectAtIndex: 0]];
00306     }
00307 
00308   if (centersBeforeActivating)
00309     {
00310       [self center];
00311     }
00312 
00313   if (runsInModalSession)
00314     {
00315       int code;
00316 
00317       code = [NSApp runModalForWindow: self];
00318 
00319       [self close];
00320 
00321       return code;
00322     }
00323   else
00324     {
00325       [self makeKeyAndOrderFront: nil];
00326 
00327       return NSRunStoppedResponse;
00328     }
00329 }
00330 
00342 - (void) deactivate: (id) sender
00343 {
00344   if (isActive == NO)
00345     {
00346       [NSException raise: NSInternalInconsistencyException
00347                   format: _(@"-[WKWizardPanel deactivate:]: panel "
00348         @"not active.")];
00349     }
00350 
00351   isActive = NO;
00352 
00353   if (runsInModalSession)
00354     {
00355       [NSApp stopModal];
00356     }
00357   else
00358     {
00359       [self close];
00360     }
00361 }
00362 
00372 - (void) deactivateWithCode: (int) code
00373 {
00374   if (isActive == NO)
00375     {
00376       [NSException raise: NSInternalInconsistencyException
00377                   format: _(@"-[WKWizardPanel deactivateWithCode:]: "
00378                             @"panel not active.")];
00379     }
00380 
00381   if (runsInModalSession == NO)
00382     {
00383       [NSException raise: NSInternalInconsistencyException
00384                   format: _(@"-[WKWizardPanel deactivateWithCode]: "
00385         @"panel was not run in modal session. Use \"-deactivate:\" to "
00386         @"deactivate a non-modal panel instead.")];
00387     }
00388 
00389   isActive = NO;
00390 
00391   [NSApp stopModalWithCode: code];
00392 }
00393 
00399 - (BOOL) isActive
00400 {
00401   return isActive;
00402 }
00403 
00404 // NSCoding protocol
00405 
00406 - (void) encodeWithCoder: (NSCoder*) aCoder
00407 {
00408   [super encodeWithCoder: aCoder];
00409 
00410   if ([aCoder allowsKeyedCoding])
00411     {
00412       [aCoder encodeBool: runsInModalSession
00413                   forKey: @"WKRunsInModalSessionFlag"];
00414       [aCoder encodeBool: runsInModalSession
00415                   forKey: @"WKCentersBeforeActivatingFlag"];
00416 
00417       [aCoder encodeObject: stages forKey: @"WKStages"];
00418       [aCoder encodeObject: initialStage forKey: @"WKInitialStage"];
00419     }
00420   else
00421     {
00422       [aCoder encodeValueOfObjCType: @encode(BOOL)
00423                                  at: &runsInModalSession];
00424       [aCoder encodeValueOfObjCType: @encode(BOOL)
00425                                  at: &centersBeforeActivating];
00426 
00427       [aCoder encodeObject: stages];
00428       [aCoder encodeObject: initialStage];
00429     }
00430 }
00431 
00432 - (id) initWithCoder: (NSCoder*) aDecoder
00433 {
00434   if ((self = [super initWithCoder: aDecoder]) != nil)
00435     {
00436       if ([aDecoder allowsKeyedCoding])
00437         {
00438           runsInModalSession = [aDecoder decodeBoolForKey:
00439             @"WKRunsInModalSessionFlag"];
00440           runsInModalSession = [aDecoder decodeBoolForKey:
00441             @"WKCentersBeforeActivatingFlag"];
00442 
00443           ASSIGN(stages, [aDecoder decodeObjectForKey: @"WKStages"]);
00444           ASSIGN(initialStage, [aDecoder
00445             decodeObjectForKey: @"WKInitialStage"]);
00446         }
00447       else
00448         {
00449           [aDecoder decodeValueOfObjCType: @encode(BOOL)
00450                                      at: &runsInModalSession];
00451           [aDecoder decodeValueOfObjCType: @encode(BOOL)
00452                                      at: &centersBeforeActivating];
00453 
00454           ASSIGN(stages, [aDecoder decodeObject]);
00455           ASSIGN(initialStage, [aDecoder decodeObject]);
00456         }
00457     }
00458 
00459   return self;
00460 }
00461 
00462 @end
00463 
00469 @implementation WKWizardPanel (Private)
00470 
00476 - (void) setupForStage: (NSString *) aStage
00477 {
00478   [self setContentView: [[self delegate] wizardPanel: self
00479                                         viewForStage: aStage]];
00480   [self setInitialFirstResponder: [[self delegate] wizardPanel: self
00481                                  initialFirstResponderForStage: aStage]];
00482 }
00483 
00484 @end
00485 
00490 @implementation NSObject (WKWizardPanelDelegate)
00491 
00506 - (NSView *) wizardPanel: (WKWizardPanel *) sender
00507             viewForStage: (NSString *) aStageName
00508 {
00509   [NSException raise: NSInternalInconsistencyException
00510               format: _(@"Wizard delegate %@ didn't override %@."),
00511     [self className], NSStringFromSelector(_cmd)];
00512 
00513   return nil;
00514 }
00515 
00525 - (NSView *)       wizardPanel: (WKWizardPanel *) sender
00526  initialFirstResponderForStage: (NSString *) aStageName
00527 {
00528   return nil;
00529 }
00530 
00531 @end