/* NAME:
**	IconView:View
**
** 	COPYRIGHT 1992, BY PLEXUS SOFTWARE
**	ALL RIGHTS RESERVED.
**
** SOURCE:
**	IconView.m
** 	By Jayson Adams, NeXT Developer Support Team
**
** REVISION HISTORY:
**	92/04/16	Mark Onyschuk	starting point
**
** DESCRIPTION:
**	IconView is a view which accepts icons dragged from the desktop.
**
*/


#import "CopyIcon.h"
#import "IconView.h"


/* APPKIT INCLUDES ******************************************************/


#import <appkit/NXImage.h>

#import <appkit/Speaker.h>
#import <appkit/Listener.h>

#import <appkit/Application.h>

#import <appkit/publicWraps.h>


/* OTHER INCLUDES *******************************************************/


#import <stdlib.h>
#import <strings.h>

#import <dpsclient/psops.h>
#import <dpsclient/wraps.h>


/* IMPLEMENTATION *******************************************************/


@implementation IconView

static NXRect fileRect = {{8.0, 8.0}, {48.0, 48.0}};


/* CONSTRUCTOR, DESTRUCTOR **********************************************/


/* NAME:
**	- initFrame:(const NXRect *)frameRect;
**
** DESCRIPTION:
**	Initializes the receiver by allocating an NXImage to contain
**	icon images, and a Listener to listen for mice entering the
**	receiver's parent window.
**
** RETURNS:
**	self.
*/

- initFrame:(const NXRect *)frameRect
{
    NXSize myImageSize = {48.0, 48.0};
    
    [super initFrame:frameRect];
    
    myListener = [[Listener alloc] init];
    myImage    = [[NXImage alloc] initSize:&myImageSize];

    delegate   = nil;
    
    [self clear];
    return self;
}



/* NAME:
**	- free;
**
** DESCRIPTION:
**	Frees the NXImage and Listener associated with the receiver.
**
** RETURNS:
**	nil.
*/

- free
{
    [myListener free];
    [myImage    free];
    
    return [super free];
}


/* ACTION METHODS ********************************************************/


/* NAME:
**	- (BOOL)acceptsFirstMouse;
**
** DESCRIPTION:
**	Indicates that the receiver accepts mouse-down events.
**
** RETURNS:
**	YES.
*/

- (BOOL)acceptsFirstMouse
{
    return YES;
}



/* NAMES:
**	- setDelegate:anObject;
**	- delegate;
**
** DESCRIPTION:
**	Sets and returns the receiver's delegate.
**
** RETURNS:
**	self, in the first case.
**
**	the receiver's delegate in the second if a delegate exists, or
**	nil otherwise.
**
*/

- setDelegate:anObject
{
    delegate = anObject;
    return self;
}

- delegate
{
    return delegate;
}



/* NAME:
**	- beginListening;
**
** DESCRIPTION:
**	Instructs the receiver to initialize its Listener and so, begin
**	allowing the user to drag items into its window.
**
** RETURNS:
**	self.
*/

- beginListening
{
    unsigned int myWindowID;

    [myListener setDelegate:self];
    [myListener usePrivatePort];
    [myListener addPort];


    NXConvertWinNumToGlobal([[self window] windowNum], &myWindowID);

    
    [[NXApp appSpeaker]    setSendPort:
				NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
    [[NXApp appSpeaker] registerWindow: myWindowID
                                toPort: [myListener listenPort]];

    return self;
}


/* NAME:
**	- setFilename:(const char *)fileName andRedraw:(BOOL)redraw;
**
** DESCRIPTION:
**	Sets the filePath associated with the receiver to <name>.
**	If <redraw> is set to YES, then setFilename attempts to obtain
**	icon information from Workspace Manager. Be sure not to call
**	setFilename with <redraw> set to YES while inside an
**	iconEntered::::::::: or iconDropped::: method.
**
** OUTLINE:
**	if filePath is not NULL
**	    free filePath
**	set it to NULL
**
**	if fileName is NULL
**	    clear the image and redraw
**	else
**	    get a new image from the Workspace Manager and redraw
**	    set filePath to fileName
**      return self
**
** RETURNS:
** 	self.
*/

- setFilename:(const char *)filename andRedraw:(BOOL)redraw
{
    if(filePath)
        free(filePath);

    filePath = NULL;
    
    if(filename == NULL)
    {
	[myImage lockFocus];
	PSsetgray(NX_LTGRAY); NXRectFill(&bounds);
	[myImage unlockFocus];

	[self display];
    }
    else
    {
        int	  ok,
		  length;
	
	char	 *tiffData;
	NXStream *imageStream;
	

	if(redraw)
	{
	    [[NXApp appSpeaker] setSendPort:
				NXPortFromName(NX_WORKSPACEREQUEST, NULL)];

	    [[NXApp appSpeaker] getFileIconFor: filename
	                                  TIFF: &tiffData
	                            TIFFLength: &length
	                                    ok: &ok];
	
	    if(!ok)
	        return self;
	    
	    imageStream = NXOpenMemory(tiffData,length,NX_READONLY);
	    
	    if(!imageStream)
	        return self;

	    [myImage free];

	    myImage = [[NXImage alloc] initFromStream:imageStream];

	    NXClose(imageStream);

	    [self display];
	}
	
	filePath = (char *)malloc(sizeof(char) * (strlen(filename) + 1));
	strcpy(filePath, filename);
    }
    
    return self;
}



/* NAME:
**	- (const char *)filename;
**
** DESCRIPTION:
**	Reports the filename associated with the receiver. Multiple files
**	are returned as a tab-separated list of pathnames.
**
** RETURNS:
**	filename associated with the receiver, or
**	null if the receiver is empty.
*/

- (const char *)filename
{
    return filePath;
}



/* NAME:
**	- clear;
**
** DESCRIPTION:
**	Clears <myImage> and sets <filePath> to NULL, then redisplays the
**	receiver.
**
** RETURNS:
**	self.
*/

- clear
{
    [self setFilename: NULL
            andRedraw: YES];

    return self;
}


/* PRIVATE METHODS *****************************************************/


/* NAME:
**	- takeIconFromWindow:(int)windowNumber
**	                    :(float)x :(float)y
**			    :(float)width :(float)height;
**
** DESCRIPTION:
**	Copies the icon from the window numbered <windowNumber> at
**	coordinates <x>, <y>, <width>, <height>, into <myImage>, then
**	redisplays the receiver.
**
** RETURNS:
** 	self.
*/

- takeIconFromWindow:(int)windowNumber
                    :(float)x :(float)y
		    :(float)width :(float)height
{
    [myImage lockFocus];
    copyIconPicture(windowNumber, x, y, width, height);
    [myImage unlockFocus];
    
    [self display];
    return self;
}



/* NAME:
**	- mouseDown:(NXEvent *)theEvent;
**
** RETURNS:
**	self.
*/
	
- mouseDown:(NXEvent *)theEvent
{
    if(filePath)
	[self    dragFile: filePath
		 fromRect: &fileRect
		slideBack: YES
		    event: theEvent];

    return self;
}



/* NAME:
**	- drawSelf:(NXRect *)rects :(int)rectCount;
**
** RETURNS:
**	self.
*/

- drawSelf:(NXRect *)rects :(int)rectCount
{    
    NXDrawGrayBezel(&bounds, NULL);
    [myImage composite:NX_SOVER toPoint:&(fileRect.origin)];
	
    return self;
}


/* LISTENER DELEGATE METHODS *******************************************/


-  (int)iconEntered: (int)windowNum

                 at: (double)x
	 	   : (double)y

         iconWindow: (int)iconWindowNum
	
	      iconX: (double)iconX
	      iconY: (double)iconY
          iconWidth: (double)iconWidth
 	 iconHeight: (double)iconHeight

           pathList: (char *)pathList;
{
    /* Here we don't redraw to avoid deadlock where the Workspace Manager
    ** waits to hear back from us while we wait to hear back from it.
    */
    
    [self setFilename: pathList
            andRedraw: NO];
       
       
    [self takeIconFromWindow: iconWindowNum
    			    : (float)iconX
			    : (float)iconY
			    : (float)iconWidth
			    : (float)iconHeight];
    
    return 0;
}


- (int)iconReleasedAt: (double)x
                     : (double)y
		     
		   ok: (int*)flag;
{
    if([delegate respondsTo:@selector(willAcceptIcon:ok:)])
    {  
	[delegate willAcceptIcon:self ok:flag];
	
	if(!*flag)
	    [self setFilename: NULL
	            andRedraw: YES];
    }
    else
    	*flag = 1;

    return 0;
}

@end