
/*
   MiscController.m
*/

// RCS identification information
static char *rcsID = "$Id:$";
static void __AvoidCompilerWarning(void) {if(!rcsID)__AvoidCompilerWarning();}

// NeXT Headers
#import <AppKit/AppKit.h>

// System Headers

// Other Headers
#import "MiscControllerManager.h"

// Superclass/Class Headers
#import "MiscController.h"

// Constants
NSString* MiscControllerDidEditNotification = 
			@"MiscControllerDidEditNotification";


@implementation MiscController

/*"
   MiscController is the abstract superclass for all controllers.
   (Controllers being somewhat like the controllers in a
   model-view-controller setup). We also implement the interface 
   between controllers and controller managers.
   Since MiscController is abstract, it shouldn't be instantiated
   directly.
   
   To become a part of the document framework we need a controller
   manager. This is usually set in IB, though you can also use
   #setControllerManager:. Inside #setControllerManager: we send
   a message to our new controller manager to let it know about
   ourselves. Once you have a controller manager you can ask it for 
   other controllers it knows about.
   
   In the next verison, I will explain in detail the #isDirty,
   #isEditable, #didEdit and #controllerDidEdit: methods. Most of
   them are used in the little Adder miniexample if you just 
   can't wait for me to formally document them :-).
"*/


//-------------------------------------------------------------------
//	Initialization/deallocation
//-------------------------------------------------------------------

- (id) init
/*"
	Our designated initializer. Doesn't do much right now.
"*/
{
    BOOL error = ([super init] == nil);

    return error ? nil : self;
}


- (void) dealloc
/*"
	Removes ourselve as an observer from the default notification
	center, then releases any other resources we have. We don't
	release our controller manager though, since we didn't retain
	it.
"*/
{
    // Stops the center from sending notification to what's going to be
    // a freed object.
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    [_name release];
    [super dealloc];
}


//-------------------------------------------------------------------
// 	Accessor methods
//-------------------------------------------------------------------

- (MiscControllerManager*) controllerManager
/*"
    Returns our controller manager. From it you can get all kinds of
    information, like other controllers it knows about, or information
    about our window, etc.
"*/
{
    return _controllerManager;
}


- (void) setControllerManager:(MiscControllerManager*)newManager
/*"
   Sets our controller manager to aManager. If we had an old
   controller manager we first send it a #removeController:
   method. We then add ourself to our new manager's controller
   list via #addController. We don't retain our controller manager,
   since that would introduce a cyclic reference. Raises an
   NSInvalidArgumentException if the argument isn't a
   MiscControllerManager or a subclass. (Maybe I shouldn't).
"*/
{
    BOOL error = NO;
    
    // Check arguments.
    if (!error && newManager == nil) {
        error = YES;
    }
    
    // Raise an exception if the argument is not nil but is also not a
    // MiscControllerManager (or subclass).
    if (!error && ![newManager isKindOfClass:[MiscControllerManager class]]) {
        [NSException raise:NSInvalidArgumentException
                    format:@"The manager of a MiscController subclass must "
            @"be an instance of a MiscControllerManager subclass. The "
            @"instance presented was of class %@", [newManager class]];
        error = YES;
    }

    if (!error) {
        // If we have an old manager, let it know we have moved
        // on.
        [[self controllerManager] removeController:self];
        
        // Let our new controller know about us.
        [newManager addController:self];
        
        // Set our own ivar, but don't retain it since that would create
        // a cyclic reference.
        _controllerManager = newManager;
    }
}


- (BOOL) isDirty
/*"
	Returns YES if we've changed in any way since we were last saved.
"*/
{
    return _dirty;
}


- (void) setDirty:(BOOL)nowDirty
/*"
    This will usually only be set by the controller itself. Calls on our
    controller manager to update it's document edited status.
"*/
{
    _dirty = nowDirty;
    
    // The status of our controller manager may have changed
    [[self controllerManager] updateDocumentEdited];
}


- (BOOL) isEditable
/*"
    Not implemeted yet. Always returns YES.
"*/
{
    return YES;
}


- (void) setEditable:(BOOL)nowEditable
/*"
   Not implmented yet. For this to work correctly subclasses that
   are going to be switching between editable and not editable
   should extend this method to make their accompanying UI elements
   either editable or not.
"*/
{
}


//-------------------------------------------------------------------
//	MiscControllerDidEditNotification sender
//-------------------------------------------------------------------

- (void) didEdit
/*"
   Posts a MiscControllerDidEditNotification with the receiver as
   the notification's object. We also send a #setDirty:YES message to
   ourself since editing usually makes us dirty. You should call this
   method (or #didEditWithUserInfo:) any time you or one of your
   UI elemetes are edited so other interested objects will know about it.
"*/
{
	[self didEditWithUserInfo:nil]; 
}


- (void) didEditWithUserInfo:(NSDictionary*)userInfo
/*"
   Does the same thing as #didEdit except it allows you to send along
   userInfo with the posted notification. Of course the receivers of
   the notification will have to be aware of the extra information and
   what keys the NSDictionary contains (but then you probably already
   knew that :-).
"*/
{
    [self _postControllerDidEditNotificationWithUserInfo:userInfo];
    [self setDirty:YES];	
}


//-------------------------------------------------------------------
//	Edit notification
//-------------------------------------------------------------------

- (void) controllerDidEdit:(NSNotification*)notification
/*"
	Sent if you used our protected method
	#_registerForControllerDidEditNotification: to register for notification 
	when another MiscController edits. Of course you can always register for
	the MiscControllerDidEditNotification yourself through NSNotificationCenter 
	and use a method of your own choosing. This method currently does nothing 	
	and is meant to be overridden in subclasses.
"*/
{
}


//-------------------------------------------------------------------
// 	Revert/Save (subclass responsibility)
//-------------------------------------------------------------------

- (BOOL) save
/*"
   It is up to subclasses to override this method if their controller is
   saveable (or you are going to use our controller manager's save method).
   Return YES if the save was successful and NO otherwise. If for some
   reason the save fails it is up to the controller to let the user know
   why the failure occurred (through an alert panel I suppose). Also if the
   save is successful make sure to call #setDirtry:NO in your implementation 
   of #save.
"*/
{
    // This method needs to be overridden in a subclass.
    [self doesNotRecognizeSelector:_cmd];	
    // To keep the compiler happy.
    return NO;
}


- (BOOL) revert
/*"
   See the description of #save for more useful information on saving
   and reverting. This method must be overridden if the controller can
   be reverted. It should return YES if the revert was successful and
   NO otherwise. Make sure to call #setDirty:NO if the revert was
   successful.
"*/
{
    // This method needs to be overridden in a subclass.
    [self doesNotRecognizeSelector:_cmd];	
    // To keep the compiler happy.
    return NO;
}	


//-------------------------------------------------------------------
// 	Support for named controllers
//-------------------------------------------------------------------

- (NSString*) name
/*"
    Returns our controller's name.
"*/
{
    return _name;
}


- (void) setName:(NSString*)newName
/*"
    Sets our name to be newName. This allows you to ask a controller
    manager for a controller without keeping an outlet to it (See
	MiscControllerManager's #{controller(s)WithName:}). We copy
    newName and autorelease the previous name.
"*/
{
    [_name autorelease];
    _name = [newName copy];
}

@end


