/* MiscSwapViewItem.m				 
 *
 * A very simple class for controlling swapAble views. A subclass is a must 
 * to easily work with the MiscSwapView classes.
 *
 * For more interface-info see the header file. In depth information
 * can be found here in the source-code.
 *
 * Written by: 		Thomas Engel
 * Created:    		24.01.1994 (Copyleft)
 * Last Modified: 	27.07.1997
 * Copyright (C) 1995 Thomas Engel
 */

#import "MiscSwapView.h"
#import "MiscSwapViewItem.h"

// The following are for keeping track of versions when archiving instances
// of this class. If you change the encodeWithCoder: method, make sure to
// bump up the version below and make the appropriate changes to the initWithCoder:
// method so all previously archived instances will be unarchivable.

#define MISC_SVI_VERSION 		2
#define MISC_SVI_CLASSNAME  	@"MiscSwapViewItem"


@implementation MiscSwapViewItem

+ (void)initialize
{
    // Sets the version of this class for archiving purposes.

    if( self == [MiscSwapViewItem class] ) [self setVersion:MISC_SVI_VERSION];
}

- (id)init
{
    return [self initWithIdentifier:nil];
}

- (id)initWithIdentifier:(id)anObject
{
    self = [super init];
    if( !self ) return nil;

    // There are no instance vars to be preset..they all can remain at 0

    identifier = [anObject retain];
    
    return self;
}

- (void)dealloc
{
    [view release];							
    [identifier release];				
    [initialFirstResponder release];	

    [super dealloc];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    int  version;

    version = [aDecoder versionForClassName:MISC_SVI_CLASSNAME];

    switch (version)
    {
        case 0:
            // <<HACK>> We should never get that one since this was the encoding of the NeXTSTEP version of this class.
            break;

        case 1:
            // We skip this version so that we can start of with encoding #2 since this is
            // mapping a lot better MiscKit 2.0
            break;

        case 2:
            swapView = [aDecoder decodeObject];						// Attention... we are not retaining that guy !
            view = [[aDecoder decodeObject] retain];
            identifier = [[aDecoder decodeObject] retain];
            initialFirstResponder = [[aDecoder decodeObject] retain];
            [aDecoder decodeValueOfObjCType:"i" at:&tag];
            break;
        default:
            break;
    }

    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeConditionalObject:swapView];						// This might go away once we no longer need it
    [aCoder encodeConditionalObject:view];
    [aCoder encodeConditionalObject:identifier];
    [aCoder encodeConditionalObject:initialFirstResponder];
    [aCoder encodeValueOfObjCType:"i" at:&tag];
}

- (void)setView:(NSView *)aView
{
    [view autorelease];
    view = [aView retain];
}

- (NSView *)view
{
    return view;
}

- (void)setInitialFirstResponder:(NSView *)aView
{
    [aView retain];
    [initialFirstResponder release];
    initialFirstResponder = aView;
}

- (id)initialFirstResponder
{
    return initialFirstResponder;
}

- (void)setIdentifier:(id)anObject
{
    // The identifier is the object we are related to. By default we try to set
    // the tag according to that object.
    // Activating the identifier object (or an object with this tag) will cause
    // us to swap in.

    [identifier autorelease];
    identifier = [anObject retain];
}

- (id)identifier
{
    return identifier;
}
 
- (void)setTag:(int)anInt
/*"
    Sets our internal tag value which is used for tag comparison. Fro tag matching this value has to be different from 0.
"*/
{
    tag = anInt;
}

- (int)tag
/*"
    If we have an identifier object whcih can deliver a tag value we will return its value instead of our internal value. Beware that the internal tag value and the value of the identifier can be different and you should be careful about using identifiers in combination with internal tag values.
"*/
{
    if( identifier &&
        [identifier respondsToSelector:@selector(tag)] )
        return [identifier tag];

    return tag;
}

- (BOOL)matchesIdentifier:(id)anObject comparingTags:(BOOL)flag
/*"
    Returns YES or NO depending on fact if we match a given identifier or not. With the <I>flag</I> set to YES only our tag is matched against the identifiers tag. For tag matching the tag has to different from 0.
    Working with tags frees us from having to know what typ of object caused the action (TextCell, ButtonCell, Matrix or what ever..) as long as the tags are handled the right way.
"*/
{
    if( flag == YES )
    {
        if( [self tag] != 0 &&
            [anObject respondsToSelector:@selector(tag)] &&
            [self tag] == [anObject tag] )
            return YES;
    }
    else
    {
        if( [anObject isEqual:[self identifier]] ) return YES;
    }
    return NO;
}

- (void)ok:(id)sender
/*"
    Gets called whenever changes made inside the item should be saved. This method currently does nothing by default but gets called by our swapViewItemWillGetDeselected: method.
    If sender is set to "self" then this call was generate by the program and not some UI "ok" button widget. This can provide some information about what kind of revert is required. However, in most cases there shouldn't be a reason to distinguish between them.
"*/
{
   // This method does nothing and is only present to allow calling it without havingto explicitly check
}

- (void)revert:(id)sender
/*"
    Gets called whenever the item should preset the displayed data to its default values. This method currently does nothing by default but gets called by our swapViewItemWillGetSelected: method.
    If sender is set to "self" then this call was generate by the program and not some UI "revert" button widget. This can provide some information about what kind of revert is required. However, in most cases there shouldn't be a reason to distinguish between them.
"*/
{
    // This method does nothing and is only present to allow calling it without havingto explicitly check
}

- (void)swapViewItemWillGetSelected:(NSNotification *)notification
/*"
    If the notification tell us the we are about to get selected then we will send ouself a <B>revert:</B> message with sender set to self. You usually subclass <B>revert:</B> and not this notification.
"*/
/*" @References: revert:
"*/
{
    if( [[notification userInfo] objectForKey:@"Item"] == self )
        [self revert:self];
}

- (void)swapViewItemWillGetDeselected:(NSNotification *)notification
/*"
    If the notification tell us the we are about to get deselected then we will send ouself an <B>ok:</B> message with sender set to self. You usually subclass <B>ok:</B> and not this notification.
"*/
/*" @References: ok:
"*/
{
    if( [[notification userInfo] objectForKey:@"Item"] == self )
        [self ok:self];
}

@end


@implementation MiscSwapViewItem (IBHelperMethods)

- (void)setSwapView:(MiscSwapView *)aView
{
    // <<HACK>> This is an evil hack since there is no easy way to maintain
    // a list of swapView items right inside IB. So we will missuse this method
    // to preconfigure the item array. this works becasue IB uses a method to
    // set an IVAR if it can find one.
    // However...this method might (should) go away once we find a easier way to handle this.
    // Beware..it can disappear.

    // <<NOTE>> We are not release/retaining the swapView since that could end up in a circle and
    // the reference currently should remain valid...however..its not a perfct solution !
    
    if( swapView )
    {
        [swapView removeSwapViewItem:self];
    }

    swapView = aView;
    [swapView addSwapViewItem:self];
}

- (MiscSwapView *)swapView
{
    return swapView;
}

@end

/*
 * History: 	29.06.97 Ported it to OPENSTEP. Switched to identifier and changed the name to MiscSwapViewItem
 *
 *		25.09.94 Added archiving (read:, write:, +initialize).
 *		Added a delegate so this class could be on a palette
 *					 and would not require subclassing. Also took away
 *					 the awakeFromNib method since you can now register a
 *					 controller without having a identifier set.
 *
 *		14.02.94 Changed the classes name to MiscSwapViewItem
 *			from the MiscSwapSubviewController becauses it fits better
 *			to what it really is.
 *
 *		24.01.94 Made it a Misc object and changed it to work with the
 *			new Misc stuff.
 *
 *		09.01.94 Added the ok/revert stuff.
 *
 *		08.01.94 Derived from my old swapViewdelegate. The code+methods
 *					 were cleaned up a bit.
 *
 *
 * Bugs: - no read/write; (not anymore)
 *
 *		 - Maybe I should do more responds to or class checking.. hmm ??
 *
 *		 - Not a bug but: I don't love the double registry made by awakeFromNib
 *		   and setSwapView. It works but it's not elegant. (not anymore)
 */