/***************************************************************************
 * CLASS:		MiscIconWell
 *
 *	See the header file for more information.
 *
 * This object is included in the MiscKit by permission from the author
 * and its use is governed by the MiscKit license, found in the file
 * "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
 * for a list of all applicable permissions and restrictions.
 ***************************************************************************/

#import <misckit/MiscString.h>
#import <misckit/MiscIconWell.h>

/*
 * A proper implementation of versioning. If you add ivars to the class (or
 * just want to dork with the reading/writing) check out the comments tagged
 * "Archiving: READ ME". BJM 5/24/94
 */
 
/*
 * **** Archiving: READ ME **** This is the current and defined version of the
 * class. It is used to identify what data will be written and how that will
 * happen. If the read/write stuff is modified AT ALL, this must be bumped up
 * (I always bump by one) and the other comments must be followed. Failure to
 * do so will result in palettes and nibs that cannot be read. BJM 5/24/94
 */
#define MISC_ICON_WELL_VERSION 0
 
@implementation MiscIconWell
 
+ initialize
{
    if (self == [MiscIconWell class]) 
	{
		/*
		 * **** Archiving: READ ME **** After bumping the _VERSION, it is
		 * considered common practice to add a comment line indicating the new
		 * version number, date, and modifier. Optionally, the reason for the
		 * change. There is no need to modify the setVersion message. BJM
		 * 5/24/94 
		 */
		// version 0: initial.  (bjm)
   		[[MiscIconWell class] setVersion:MISC_ICON_WELL_VERSION];
    }
    
    return self;
}

- initFrame: (const NXRect *)frameRect
{
  const char *const types[] = {NXFilenamePboardType};
  
  	[super initFrame: frameRect];
	[self registerForDraggedTypes: (const char *const *)&types count: 1];
	
	filename = [ [MiscString alloc] init];
	[self setAllowDoubleClickLaunch: YES];
	
	return self;
}



- awake
{ 
  const char *const types[] = {NXFilenamePboardType};
  
	[super awake];	
	[self registerForDraggedTypes: (const char *const *)&types count: 1];
	
	return self;
}



- free
{
	[filename free];
	return [super free];
}


// Return the filename associated with the image. Kind of a hack to return
// nil if no filename set, I suppose.

- (const char *)filename
{   
	/*
	 * convert an empty string (because the filename ivar is always valid) to a
	 * return value of NULL. BJM 5/24/94
	 */
 	if ( [filename length] == 0)
		return NULL;
	else
  		return [filename stringValue];
}



// Overridden from MiscDragView so the icon representation of the file
// is fetched instead of the image itself (likely the filename is not
// an image). It also has a small hack that if there are more than one
// filename that it steals that multiple.tiff from Librarian.app. 

- setImageByFilename: (const char *)aFilename
{
	[filename setStringValue: aFilename];
	
	/*
	 * Multiple filenames are separated by tabs. We can't use -numWords because
	 * numWords checks for any NXIsSpace which includes spaces. Result: if we
	 * use numWords, it treats any filename with spaces as "multiple". BJM
	 * 5/24/94    
	 */
	if ([filename index:'\t'] != NULL)
		[super setImageByFilename: "/NextApps/Librarian.app/multiple.tiff"];
	else	
		[self setImage: [ [Application workspace] getIconForFile: aFilename] ];
	
	return self;
}



// Add additional options that only apply to MiscIconWell.

- setAllowDoubleClickLaunch: (BOOL)aBool
{
	allowDoubleClickLaunch = aBool;
	return self;
}



- (BOOL)allowDoubleClickLaunch
{
	return allowDoubleClickLaunch;
}


/*
 * Launch/open file in WS: BJM 5/24/94
 */
- launch:sender
{
	if ([filename length])
		[[Application workspace] openFile:[filename stringValue]];
	return self;
}

// Override mouseDown to check if the icon was double clicked. If so, then
// launch it from workspace, else let super handle it.

- mouseDown: (NXEvent *)theEvent
{
	/*
	 * Only attempt to open file if there (1) DC is allowed, (2) this is a DC
	 * event, and (3) there is a file to open. BJM 5/24/94
	 */
	if ([self allowDoubleClickLaunch] && theEvent->data.mouse.click == 2)
		[self launch:self];
		
	else
		[super mouseDown: theEvent];
	return self;
}



// Make the dragPoint be the middle of the image, so it looks nice.

- calculateDragPoint: (NXPoint *)dragPoint andOffset: (NXPoint *)offset
{
	dragPoint->x -= imageSize.width/2.0;
    dragPoint->y -= imageSize.width/2.0;

	return self;
}


	
// Put the data on the pasteboard when a source drag takes place, and
// also choose the image to drag. 

- (BOOL)setupForSourceDrag
{
	/*
	 * only if there is something to drag... BJM 5/24/94
	 */
	if ([filename length] > 0)
	{
		id dragPB = [Pasteboard newName: NXDragPboard];
		
		[dragPB declareTypes:&NXFilenamePboardType num:1 owner:self];
		
		[dragPB writeType:NXFilenamePboard 
			data:[filename stringValue]
			length:[filename length] ];
			
		dragImage = theImage;
		
		return YES;
	}
	
	return NO;
}




// Check if an incoming dragged icon is using the NXFilenamePboardType. If
// not, then don't accept the drag.

- (BOOL)performDragOperation: sender
{
  id  dragPB = [Pasteboard newName: NXDragPboard];
  char  *pbData;
  int  pbLength;

	if ([dragPB readType: NXFilenamePboardType data: &pbData 
			length: &pbLength] == nil)
		return NO;	
	 
	return YES;
}


// Take the data from the pasteboard and set the new image.

- concludeDragOperation: sender
{
  id  dragPB = [Pasteboard newName: NXDragPboard];
  char  *pbData;
  int  pbLength;
  
	[dragPB readType: NXFilenamePboardType data: &pbData 
			length: &pbLength];

	[self setImageByFilename: pbData];
			
	[dragPB deallocatePasteboardData: pbData length: pbLength];
	
	[super concludeDragOperation: sender];
	
    return self;
}



/*********** Archiving *************/

- read:(NXTypedStream *)stream
{
    int version;

    [super read:stream];
    
	version = NXTypedStreamClassVersion(stream, "MiscIconWell");
        
	/*
	 * **** Archiving: READ ME **** This code (and its analogue in write:) is
	 * critical. When you bump MISC_ICON_WELL_VERSION, copy the whole _current_
	 * case ("case MISC_ICON_WELL_VERSION: ... break;"), and duplicate it.
	 * Change the "MISC_ICON_WELL_VERSION" in the old case to the OLD
	 * (pre-bump) version number. Now, dork the "new current" version into
	 * whatever you want. See how this code can now read EITHER version out of
	 * the typed stream?
	 *
	 * If you are adding yet another version, leave the previous versionS in
	 * place. That way you can still read archived objects that are more than
	 * one version old. Don't forget to take whatever actions are necessary to
	 * harmonize those old values. For example, if you converted an "int" ivar
	 * to "double", you'd need to (in the old version) to read the int version
	 * into a temp variable, and convert it in to the double var. BJM 5/24/94
	 */
    switch (version)
    {
    case MISC_ICON_WELL_VERSION:
		filename = NXReadObject (stream);
		NXReadTypes (stream, "c", 
			&allowDoubleClickLaunch
		);
		break;

    default:
		NXLogError("[%s %s] - unknown version of %s in typed stream",
			[[self class] name], sel_getName(_cmd), [[self class] name]);
		break;
    }

    return self;
}

- write:(NXTypedStream *)stream
{
    [super write:stream];
    
	/*
	 * **** Archiving: READ ME **** Home stretch. Now (just like read:)
	 * duplicate the current case ("case MISC_ICON_WELL_VERSION: ... break;").
	 * Once again, change the "MISC_ICON_WELL_VERSION" of the first one to the
	 * OLD version number. Now adjust the new/current MISC_ICON_WELL_VERSION
	 * (remember, you've bumped it) to the new way of writing vars. See how
	 * this code (because the constant is in the switch statement) always
	 * writes out ONLY the current version, but leaves the old version(s)
	 * around to posterity. DO NOT DELETE THE OLD VERSIONS. Leave them to
	 * clutter up the world. BJM 5/24/94  
	 */
    switch (MISC_ICON_WELL_VERSION)
    {
    case MISC_ICON_WELL_VERSION:
		NXWriteObject(stream, filename);
		NXWriteTypes (stream, "c", 
			&allowDoubleClickLaunch
		);
		break;

    default:
		NXLogError("[%s %s] - unknown version of %s in typed stream",
			[[self class] name], sel_getName(_cmd), [[self class] name]);
		break;
    }

    return self;
}

@end