/* DockTileView.m created by fred on Wed 22-Sep-1999 */

#import "DockTileView.h"

#import "Dock.h"

//	----------------------------------------------------------------------------

#define DOCK_ASPECT	24

@interface DockTileView(Private)

- (NSImageRep *)_fbScaleRep:(NSImageRep *)aSourceRep toSize:(NSSize)aSize;
- (NSImage *)_sdMiniImageForFile:(NSString *)aFullPath ofSize:(NSSize)aSize;

@end

//	----------------------------------------------------------------------------

@implementation DockTileView

- initWithFrame:(NSRect)aFrame
{	[super initWithFrame:aFrame];

	itsPath = nil;
	itsTitle = nil;
	itsSlotIndex = NSNotFound;

	[self setBordered:NO];
	[self setButtonType:NSMomentaryChangeButton];


	[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
//		No gradient in Mac OS X Server ?
//	[[self cell] setGradientType:NSGradientConvexStrong];

	return self;
}

//	----------------------------------------------------------------------------

- (void)dealloc
{	[itsPath release];
	[itsTitle release];
	[itsTitleColor release];
	[itsTitleColorName release];
	[itsApplicationFullPath release];
	[itsMessageWindow release];
	[itsHighlightedImage release];
	[super dealloc];
}

//	----------------------------------------------------------------------------

- (void)setSlotIndex:(unsigned)anIndex
{	itsSlotIndex = anIndex;
}

//	----------------------------------------------------------------------------

- (Dock *)dock
{	return itsDock;
}

//	----------------------------------------------------------------------------

- (void)setDock:(Dock *)aDock
{	itsDock = aDock;
		//	Hope the sender does the job of moving the view...
}

//	----------------------------------------------------------------------------

- (NSDictionary *)propertyList
{	NSMutableDictionary *theDictionary = [NSMutableDictionary dictionary];

	if ([self path])
		[theDictionary setObject:[[self path] stringByAbbreviatingWithTildeInPath] forKey:@"Path"];

	if ([self title])
		[theDictionary setObject:[self title] forKey:@"Title"];

	if ([self titleColorName])
		[theDictionary setObject:[self titleColorName] forKey:@"TitleColorName"];

	return theDictionary;
}

//	----------------------------------------------------------------------------

- initFromPropertyList:(NSDictionary *)aPropertyList
{	[self init];

	[self setPath:[[aPropertyList objectForKey:@"Path"] stringByExpandingTildeInPath]];
	[self setTitle:[aPropertyList objectForKey:@"Title"]];
	[self setTitleColorName:[aPropertyList objectForKey:@"TitleColorName"]];

	return self;
}

//	----------------------------------------------------------------------------

- (NSString *)path
{	return itsPath;
}

//	----------------------------------------------------------------------------

- (NSString *)title
{	return itsTitle;
}

//	----------------------------------------------------------------------------

- (void)setTitle:(NSString *)aTitle
{	[itsTitle autorelease];
	itsTitle = [aTitle copy];
}

//	----------------------------------------------------------------------------

- (NSString *)titleColorName
{	return itsTitleColorName;
}

//	----------------------------------------------------------------------------

- (void)_takeColorFromTitleColorName
{	if (!itsTitleColorName)
		[self _setTitleColor:nil];
	else
	{	NSArray *theArray = [itsTitleColorName componentsSeparatedByString:@"."];
		if ([theArray count]==2)
		{	NSColorList *theColorList = [NSColorList colorListNamed:[theArray objectAtIndex:0]];
			NSString *theColorName  = [theArray objectAtIndex:1];

			if (!theColorList)
			{	NSLog( @"No color list named [%@]", [theArray objectAtIndex:0] );
				if (YES)
				{	NSEnumerator *e = [[NSColorList availableColorLists] objectEnumerator];
					id o;
					while (o=[e nextObject])
						NSLog( @"-> [%@]", [o name] );
				}
			}
			else
			{	NSColor *theColor = [theColorList colorWithKey: theColorName];

				if (!theColor)
				{	NSEnumerator *e = [[theColorList allKeys] objectEnumerator];
					id o;

					while (o=[e nextObject])
						if ([[[theColorList colorWithKey:o] localizedColorNameComponent] isEqual: theColorName])
						{	NSLog( @"Use '[%@]' instead of '[%@]' for color name", o, theColorName );
							break;
						}
					theColor = [theColorList colorWithKey:o];
				}

				if (!theColor)
				{	NSLog( @"No color named [%@] in color list [%@]", theColorName, [theArray objectAtIndex:0] );
					if (YES)
						NSLog( @"%@", [theColorList allKeys] );
				}
				else
					[self _setTitleColor:theColor];
			}
		}
		else
			NSLog( @"Cannot grok color named '[%@]' Format is ListName.ColorName", itsTitleColorName );
	}
}

//	----------------------------------------------------------------------------

- (void)setTitleColorName:(NSString *)aTitleColorName
{	[itsTitleColorName autorelease];
	itsTitleColorName = [aTitleColorName copy];
	[self _takeColorFromTitleColorName];
}

//	----------------------------------------------------------------------------

- (NSColor *)titleColor
{	return itsTitleColor?itsTitleColor:[NSColor blackColor];
}

//	----------------------------------------------------------------------------

- (void)_setTitleColor:(NSColor *)aColor
{	[itsTitleColor autorelease];
	itsTitleColor = [aColor retain];
}

//	----------------------------------------------------------------------------

- (void)setTitleColor:(NSColor *)aColor
{	[self setTitleColorName:nil];
	[self _setTitleColor:aColor];
}

//	----------------------------------------------------------------------------

- (void)update
{	
	if (itsPath)
	{	if (![[NSFileManager defaultManager] fileExistsAtPath:[self path]])
		{
			itsfExists = NO;
		}
		else
		{
			itsfExists = YES;
		}
//		[self setImage:[self _sdMiniImageForFile:itsPath ofSize:NSMakeSize( [itsDock imageSize]-2, [itsDock imageSize]-2 )]];
	}
//	else

	[self setImage:nil];

	[itsApplicationFullPath autorelease];
	if (itsPath)
		if ([self isApplication])
			 itsApplicationFullPath = [itsPath retain];
		else
			itsApplicationFullPath = [[[NSWorkspace sharedWorkspace] fullPathForApplication:[self applicationName]] retain];
	else
		itsApplicationFullPath = nil;
}

- (void)setPath:(NSString *)aPath
{	[itsPath autorelease];
	itsPath = [aPath retain];
	[self update];
}

//	----------------------------------------------------------------------------

- (BOOL)isLaunched
{	if (![self path])
		return NO;

	return [[self dock] applicationLaunched:[self applicationFullPath]];
}

//	----------------------------------------------------------------------------

- (BOOL)doesExists
{	return itsfExists;
}

- (NSString *)applicationFullPath
{	return itsApplicationFullPath;
}

//	----------------------------------------------------------------------------

- (void)removeMessage
{	[itsMessageWindow orderOut:self];
	[itsMessageWindow release];
	itsMessageWindow = nil;
}

//	----------------------------------------------------------------------------

- (void)putMessage:(NSString *)aMessage
{		//	Put a message on screen, so the user can know which appplication is destination of a drop (as the tiles are too small to be visible when the drop occurs)
	NSTextField *theMessageField;
	NSPoint theWindowOrigin;

	[self removeMessage];

	theMessageField = [[[NSTextField alloc] init] autorelease];
	[theMessageField setBordered:YES];
	[theMessageField setSelectable:NO];
	[theMessageField setBackgroundColor:[NSColor colorWithCalibratedRed:1 green:1 blue:196.0/255 alpha:1.0]];
	[theMessageField setStringValue:aMessage];
	[theMessageField sizeToFit];

	theWindowOrigin = [[self window] convertBaseToScreen:[self convertRect:[self bounds] toView:nil].origin];

		//	If on right of the screen, move widow to the left
	if (theWindowOrigin.x > NSMidX( [[NSScreen mainScreen] frame] ))
	{	theWindowOrigin.x -= NSWidth( [theMessageField frame] );
		theWindowOrigin.x -= 16;
	}
	else
		theWindowOrigin.x += 48;

	theWindowOrigin.y += 0;

	itsMessageWindow = [[NSWindow alloc] initWithContentRect: NSMakeRect( theWindowOrigin.x, theWindowOrigin.y, NSWidth( [theMessageField frame] ), NSHeight( [theMessageField frame] ) ) styleMask:NSBorderlessWindowMask backing: NSBackingStoreBuffered defer:YES screen:[NSScreen mainScreen]];

	[itsMessageWindow setContentView:theMessageField];
	[itsMessageWindow setLevel:NSStatusWindowLevel];

	[itsMessageWindow makeKeyAndOrderFront:self];
}

//	----------------------------------------------------------------------------

- (void)_sdLaunch:sender
{	if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
		[[NSWorkspace sharedWorkspace] hideOtherApplications];
	[[NSWorkspace sharedWorkspace] openFile:[self path]];
}

@end

//	----------------------------------------------------------------------------

@implementation DockTileView(NSResponder_Overrides)

//	Not correct. The double-click executes its action on mouseUp, which is bad. (Better just test for double-click at the beginning, and execute in that case. If we can drag on a double-click, well, dosn't matter...)
- (void)doMouseDown:(NSEvent *)anEvent
{	NSPoint theOrigin = [self convertPoint:[anEvent locationInWindow] fromView:nil];
	NSEvent *theMouseDown = anEvent;
	NSEvent *theEvent = anEvent;
	BOOL thefDoubleClick = [anEvent clickCount]==2;
	NSImage *theDragImage = [[[self cell] image] retain];		//	We keep it because it will be removed when the drag starts
	BOOL thefMayLaunch = YES;

	assert( theDragImage );

	do
	{	NSPoint theCurrentPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];

			//	If neccessary, we change hightlighting
		if (NSPointInRect( theCurrentPoint, [self bounds] ))
		{	if (![[self cell] isHighlighted])
			{	[[self cell] setCellAttribute:NSCellHighlighted to:1];
				[self display];

					//	In one second, we'll show the path
				[NSEvent startPeriodicEventsAfterDelay:1 withPeriod:1];
			}
		}
		else
		{	if ([[self cell] isHighlighted])
			{	[[self cell] setCellAttribute:NSCellHighlighted to:0];
				[self display];
				[self removeMessage];

				[NSEvent stopPeriodicEvents];
			}
		}

			//	Oh, oh, time to show the path
		if ([theEvent type]==NSPeriodic)
		{	[self putMessage:[self path]];
			thefMayLaunch = NO;		//	Cancel eventual launch

			[NSEvent stopPeriodicEvents];
		}

			//	If we go away, then we start a drag
		if ([theEvent type]==NSLeftMouseDragged)
			if (fabs(theOrigin.x-theCurrentPoint.x)+fabs(theOrigin.y-theCurrentPoint.y)>64)
			{	NSPasteboard *thePasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];

				[thePasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil];
				[thePasteboard setPropertyList:[NSArray arrayWithObject:[self path]] forType:NSFilenamesPboardType];

				thefMayLaunch = NO;		//	Cancel eventual launch

					//	We remove the path, unless alt key is pressed
				if (!([theEvent modifierFlags] & NSAlternateKeyMask))
				{	[self setPath:nil];
					[self display];
				}
//NSLog( @"%@", theDragImage );
				[self dragImage:theDragImage
							at:NSMakePoint( 0, NSMaxY( [self bounds] ) )
							offset:NSMakeSize( theCurrentPoint.x-theOrigin.x, theCurrentPoint.y-theOrigin.y )
							event:theMouseDown
							pasteboard:thePasteboard
							source:self
							slideBack:!!([theEvent modifierFlags] & NSAlternateKeyMask)];
				break;
			}

		theEvent = [[self window] nextEventMatchingMask:NSLeftMouseUpMask|NSLeftMouseDraggedMask|NSPeriodicMask];

	}	while ([theEvent type]!=NSLeftMouseUp);

	[self removeMessage];	//	Just in case

		//	Eventual one/two click activation
	if (![[NSUserDefaults standardUserDefaults] boolForKey:@"OneClickActivation"])
		thefMayLaunch = thefDoubleClick;

		//	If the last event is a mouse up, we (eventually) execute the action
	if ([theEvent type]==NSLeftMouseUp
		&& NSPointInRect( [self convertPoint:[theEvent locationInWindow] fromView:nil], [self bounds] )
//		&& thefDoubleClick)
		&& thefMayLaunch)
			[self _sdLaunch:nil];

	if ([[self cell] isHighlighted])
	{	[[self cell] setCellAttribute:NSCellHighlighted to:0];
		[self display];
	}

	[NSEvent stopPeriodicEvents];
}

//	----------------------------------------------------------------------------

//	Should go in a category
- (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)flag
{	return NSDragOperationAll;
}

//	----------------------------------------------------------------------------

- (void)mouseDown:(NSEvent *)anEvent
{
	if (![self path])
		return ;

		//	First, we highlight ourself

	[self doMouseDown:anEvent];

		//	Remove the highlight
/*
	//	if ([anEvent
	if ([self path])
		[self putMessage:[self path]];
	[super mouseDown:anEvent];
	[self removeMessage];
*/
}

- (NSMenu *)menuForEvent:(NSEvent *)event
{	NSMenu *theMenu;
	NSMenu *theSizeMenu;

	theMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];

	[theMenu addItemWithTitle:@"Open" action:@selector(open:) keyEquivalent:@""];
	[theMenu addItemWithTitle:@"Remove" action:@selector(remove:) keyEquivalent:@""];
	[theMenu addItemWithTitle:@"Copy path" action:@selector(copyPath:) keyEquivalent:@""];

	[theMenu addItemWithTitle:@"Kill" action:@selector(kill:) keyEquivalent:@""];
	[theMenu addItemWithTitle:@"Force launch" action:@selector(forceLaunch:) keyEquivalent:@""];
	[theMenu addItemWithTitle:@"Select in Workspace" action:@selector(selectInWorkspace:) keyEquivalent:@""];
	[theMenu addItemWithTitle:@"Add..." action:@selector(add:) keyEquivalent:@""];

/*	We could have a few more, like insert, delete, lock, unlock
*/

	theSizeMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
	[[theSizeMenu addItemWithTitle:@"12x12" action:@selector(takeImageSizeFromTag:) keyEquivalent:@""] setTag:12];
	[[theSizeMenu addItemWithTitle:@"16x16" action:@selector(takeImageSizeFromTag:) keyEquivalent:@""] setTag:16];
	[[theSizeMenu addItemWithTitle:@"20x20" action:@selector(takeImageSizeFromTag:) keyEquivalent:@""] setTag:20];
	[[theSizeMenu addItemWithTitle:@"24x24" action:@selector(takeImageSizeFromTag:) keyEquivalent:@""] setTag:24];
	[[theSizeMenu addItemWithTitle:@"32x32" action:@selector(takeImageSizeFromTag:) keyEquivalent:@""] setTag:32];
	[[theSizeMenu addItemWithTitle:@"48x48" action:@selector(takeImageSizeFromTag:) keyEquivalent:@""] setTag:48];

	[theMenu setSubmenu:theSizeMenu forItem:[theMenu addItemWithTitle:@"Size" action:NULL keyEquivalent:@""]];

	return theMenu;
}

//	----------------------------------------------------------------------------

- (BOOL)validateMenuItem:(id <NSMenuItem>)menuItem
{	SEL theSel = [menuItem action];

	if (theSel==@selector(open:) || theSel==@selector(selectInWorkspace:))
		return [self path]!=nil /* And exists ? */;

	if (theSel==@selector(remove:) || theSel==@selector(copyPath:))
		return [self path]!=nil;

	if (theSel==@selector(kill:))
		return [self isApplication] && [self isLaunched];

	if (theSel==@selector(forceLaunch:))
		return [self isApplication];

	if (theSel==@selector(add:))
		return [self path]==nil;

	return NO;
}

//	----------------------------------------------------------------------------

- (void)open:sender
{	[self _sdLaunch:nil];
}

//	----------------------------------------------------------------------------

- (void)remove:sender
{	[self setPath:nil];
	[itsDock tileChanged:self];
}

//	----------------------------------------------------------------------------

- (void)copyPath:sender
{	[[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObjects: NSStringPboardType , nil] owner:nil];

	[[NSPasteboard generalPasteboard] setString:[self path] forType: NSStringPboardType];
}

//	----------------------------------------------------------------------------

- (void)kill:sender
{	NSTask *theTask = [NSTask launchedTaskWithLaunchPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"KillApplication" ofType:@"sh"] arguments:[NSArray arrayWithObject:[self path]]];
	[theTask waitUntilExit];
}

//	----------------------------------------------------------------------------

- (void)forceLaunch:sender
{	NSString *thePath = [self path];

	thePath = [thePath stringByAppendingPathComponent:[[thePath lastPathComponent] stringByDeletingPathExtension]];

	[NSTask launchedTaskWithLaunchPath:thePath arguments:[NSArray array]];
		//	Should we do something else ?
}

//	----------------------------------------------------------------------------

- (void)selectInWorkspace:sender
{	[[NSWorkspace sharedWorkspace] selectFile:[self path] inFileViewerRootedAtPath:@"/"];
}

//	----------------------------------------------------------------------------

- (void)add:sender
{	NSOpenPanel *thePanel = [NSOpenPanel openPanel];

	[thePanel setAllowsMultipleSelection:NO];
	[thePanel setCanChooseDirectories:YES];
	[thePanel setCanChooseFiles:YES];

	if ([thePanel runModalForTypes:nil]==NSOKButton)
	{	[self setPath:[thePanel filename]];
		[self display];
		[itsDock tileChanged:self];
	}
}

//	----------------------------------------------------------------------------

/*
- (void)mouseUp:(NSEvent *)anEvent
{	[self removeMessage];
}
*/

@end

//	----------------------------------------------------------------------------

@implementation DockTileView(NSView_Overrides)

- (BOOL)shouldFrame
{		//	We frame if empty or temporary
	//	return (itsfTemporary || !itsPath)

		//	We frame if not an application
	return ![self isApplication];	
}

- (void)drawRect:(NSRect)aRect
{	if ([self path])
	{
//		[[NSColor lightGrayColor] set];
//		NSRectFill ( aRect );

			//	Not very elegant...
		if (![[self cell] image])
			[self setImage:[self _sdMiniImageForFile:itsPath ofSize:NSMakeSize( [itsDock imageSize], [itsDock imageSize] )]];

		if (![[self cell] isHighlighted])
			[[[self cell] image] compositeToPoint:NSMakePoint( 1, NSMaxY( [self bounds] )-1 ) operation:NSCompositeSourceOver];
		else
			[itsHighlightedImage compositeToPoint:NSMakePoint( 1, NSMaxY( [self bounds] )-1 ) operation:NSCompositeSourceOver];

		if (![self isLaunched])
		{	//	Non launched applications get a dot in the bottom corner
			static NSRectEdge theSides[] = { NSMinXEdge, NSMinYEdge, NSMaxXEdge, NSMaxYEdge };
			static float theGrays[sizeof( theSides )/sizeof( theSides[0] )] = { 0, 0, 1, 1 };
			NSRect theRect;

			#define DOT_SIZE	3

			theRect = NSMakeRect( NSMaxX( [self bounds] )-DOT_SIZE-1, NSMaxY( [self bounds] )-DOT_SIZE-1, DOT_SIZE, DOT_SIZE );
			NSDrawTiledRects( theRect, aRect, theSides, theGrays, sizeof( theSides )/sizeof( theSides[0] ));
			theRect = NSOffsetRect( theRect, -4, 0 );
			NSDrawTiledRects( theRect, aRect, theSides, theGrays, sizeof( theSides )/sizeof( theSides[0] ));
			theRect = NSOffsetRect( theRect, -4, 0 );
			NSDrawTiledRects( theRect, aRect, theSides, theGrays, sizeof( theSides )/sizeof( theSides[0] ));
		}
	}
	else
	{
//		[[NSColor lightGrayColor] set];
		[[NSColor darkGrayColor] set];
		NSRectFill( aRect );
	}

		//	Little overlapped text, by martin request
		//	Slow and ugly
	{	NSRect theRect = aRect;
		NSString *theTitle = [self title];

		if (theTitle)
		{
			theRect.origin.y = NSMaxY( theRect )-13;
			theRect.size.height = 10;
			theRect.origin.x += 2;
			theRect.size.width -= 5;
			[theTitle drawInRect:theRect withAttributes:
				[NSDictionary dictionaryWithObjectsAndKeys:
					[NSFont systemFontOfSize:10], NSFontAttributeName,
					[self titleColor], NSForegroundColorAttributeName,
					nil ]
			];
/*			theRect.origin.x += 1;
			theRect.origin.y += 1;
			[theTitle drawInRect:theRect withAttributes:
				[NSDictionary dictionaryWithObjectsAndKeys:
					[NSFont systemFontOfSize:10], NSFontAttributeName,
					[NSColor redColor], NSForegroundColorAttributeName,
					nil ]
			];
*/
		}
	}

	if ([self shouldFrame])
	{
		static NSRectEdge theSides[] = { NSMinXEdge, NSMinYEdge, NSMaxXEdge, NSMaxYEdge };
		static float theGrays[sizeof( theSides )/sizeof( theSides[0] )] = { 0, 0, 1, 1 };


		NSDrawTiledRects( [self bounds], aRect, theSides, theGrays, sizeof( theSides )/sizeof( theSides[0] ));
	}

}

- (void)setImage:(NSImage *)anImage
{	[itsHighlightedImage release];
	itsHighlightedImage = nil;

		//	Not wise. Better to pass an already grayed image in setImage:
	if (anImage && ![self doesExists])
	{	anImage = [[anImage copy] autorelease];
		[anImage lockFocus];
		PSsetalpha( 0.5 );
		PScompositerect( 0, 0, [anImage size].width, [anImage size].height, NSCompositeDestinationIn );
		[anImage unlockFocus];
	}

		//	Create highlighted image
	if (anImage)
	{	itsHighlightedImage = [anImage copy];
		[itsHighlightedImage lockFocus];
		PSsetalpha( 0.5 );
		PSsetgray( 0 );
		PScompositerect( 0, 0, [anImage size].width, [anImage size].height, NSCompositeSourceAtop );
		[itsHighlightedImage unlockFocus];
	}
	[super setImage:anImage];
}

@end

//	----------------------------------------------------------------------------

@implementation DockTileView(NSDraggingDestination)

- (BOOL)isApplication
{	NSString *theExtension = [[itsPath lastPathComponent] pathExtension];
	if ([theExtension isEqual:@"app"] || [theExtension isEqual:@"debug"])
		return YES;
	return NO;
}

- (NSString *)applicationName
{	NSString *theAppName = nil;

	if ([self isApplication])
		return [[itsPath lastPathComponent] stringByDeletingPathExtension];

	if ([[NSWorkspace sharedWorkspace] getInfoForFile:itsPath application:&theAppName type:NULL])
		return theAppName;

	return nil;
}

- (unsigned int)draggingEntered:(id <NSDraggingInfo>)sender
{
	[self doCommandBySelector:@selector(backgroundEntered:)];

	if (itsPath)
	{	[self putMessage:[NSString stringWithFormat:@"Open with %@", [self applicationName]]];
	}
	else
	{	NSString *theFile = [[[sender draggingPasteboard] propertyListForType:NSFilenamesPboardType] objectAtIndex:0];

//		[self putMessage:[NSString stringWithFormat:@"Add"]];
		itsfTemporary = YES;
		[self setPath:theFile];
		[self display];
	}
	return NSDragOperationGeneric;
}

- (unsigned int)draggingUpdated:(id <NSDraggingInfo>)sender
{	return NSDragOperationGeneric;
}

- (void)draggingExited:(id <NSDraggingInfo>)sender
{	[self doCommandBySelector:@selector(backgroundExited:)];

	if (itsfTemporary)
	{	[self setPath:nil];
		[self display];
		itsfTemporary = NO;
	}
	[self removeMessage];
}

- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{	[self removeMessage];
	return YES;
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{	return YES;
}

- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
{
	if (!itsfTemporary && itsPath)
	{	NSArray *theFilenames = [[sender draggingPasteboard] propertyListForType:NSFilenamesPboardType];
		NSEnumerator *e = [theFilenames objectEnumerator];
		id o;

			//	We activate, so the andDeactivate:YES works
			//	Classic scenario is dragging a file from the Workspace to an application tile on the dock. If we don't activate, then the application is launched in background, which is quite disturbing. So we activate ourself, and the openFile: will deactivate us. As there is no app active, the launching app will be front, unless the user click somewhere. 
		[NSApp activateIgnoringOtherApps:YES];

		while (o=[e nextObject])
			if (![[NSWorkspace sharedWorkspace] openFile:o withApplication:[self applicationName] andDeactivate:YES])
				NSLog( @"Cannot open [%@] with [%@]", o, [self applicationFullPath] );
	}
	else
	{	NSArray *theFilenames = [[sender draggingPasteboard] propertyListForType:NSFilenamesPboardType];
		itsfTemporary = NO;
		[self setPath:[theFilenames objectAtIndex:0]];
	}

		//	Inform our dock
	[itsDock tileChanged:self];
}

@end


@implementation DockTileView(Private)

/*
	The manipulations of image rep may be a little confusing at first. Here are a few explanations:
	The original image rep is a pure AppKit object. It is just a bunch of bytes in memory, or a reference to a file, or postscript code that generate an image, or anything else [private NSImageRep subclass]. In one word, we just don't know its format.
	First, we build an NSImage with that representation and ask that the reps are scaled. It is a pure AppKit-side manipulation.
	We can just do one thing with such an image: draw it (ie: ask its only rep to render itself).
	It should be kept in mind that the AppKit don't know how to draw anything, only the windowserver have such knowledge (because the AppKit have no devices)
	So we have to ask the windowserver to draw this image somewhere. But we need much more than a simple scaled rendering: we want it to do a color conversion for us (ie: we'd like to have a 32bits RGBA image, so our algorithm work).
	So we create an NSImage with a NSCachedImageRep of the correct depth and lock focus on this representation. (If we didn't specify a depth, then it may have used a inferior depth if the none of the screens was 24bits)
	So, when the image is drawn, we have it scaled and converted to 24bits, but in a NSCachedImageRep (ie: on the windowserver side), so we have to transform it in a bunch of bytes on the application side. This is why we create an NSBitmapImageRep via initWithFocusedViewRect.
	Lastly, we just have to average the pixels from this image rep to the destination one.
*/
- (NSImageRep *)_fbScaleRep:(NSImageRep *)aSourceRep toSize:(NSSize)aSize
{		//	We do a poor man anti-aliasing by scaling the image to 4 times the target size and averaging blocks of 16 pixels.
		//	We loose a lot of contrast in the process, but the result is much less ugly than with a simple scale
	NSBitmapImageRep *theAliasedRep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
			pixelsWide:aSize.width
			pixelsHigh:aSize.height
			bitsPerSample:8
			samplesPerPixel:4
			hasAlpha:YES
			isPlanar:NO
			colorSpaceName:NSDeviceRGBColorSpace
			bytesPerRow:0
			bitsPerPixel:0] autorelease]; 

	NSBitmapImageRep *theDestRep;
	int x,y,channel;

		//	We build an destination image for scaling the source
	NSImage *theDestImage = [[[NSImage alloc] initWithSize:NSMakeSize( aSize.width*4, aSize.height*4 )] autorelease];
	NSCachedImageRep *the24bitsRep = [[[NSCachedImageRep alloc] initWithSize: NSMakeSize( aSize.width*4, aSize.height*4 ) depth:24 separate:YES alpha:YES] autorelease];

		//	We build a scaled image for the source rep (the scaling operation will be ugly, but will be corrected by the antialiasing)
	NSImage *theSourceImage = [[[NSImage alloc] initWithSize:NSMakeSize( aSize.width*4, aSize.height*4 )] autorelease];

assert( aSourceRep );

	[theSourceImage setScalesWhenResized:YES];
	[theSourceImage addRepresentation:aSourceRep];

		//	Now, we draw the (scaled) source in the destination
	[theDestImage addRepresentation:the24bitsRep];
	[theDestImage lockFocusOnRepresentation:the24bitsRep];

			//	This is to ensure that it get promoted to 24bits alpha (the windowserver seems real smart, and will notice if the 24bits device have never received non 24bits value, and then will only image at 12 bits)
		PSsetrgbcolor( 1.0/255, 0, 0 ); PSmoveto( 0, 0 ); PSlineto( 0, 0 ); PSstroke();
		PSsetalpha( 0 ); PSsetrgbcolor( 0, 0, 0 ); PSmoveto( 0, 0 ); PSlineto( 0, 0 ); PSstroke();

		[theSourceImage drawRepresentation:aSourceRep inRect:NSMakeRect( 0,0, aSize.width*4, aSize.height*4 )];

			//	Now, we get an bitmap image rep from this scaled data
		theDestRep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect( 0,0, aSize.width*4, aSize.height*4 )] autorelease];
	[theDestImage unlockFocus];

		//	Mmmm. I don't beleive that the windowserver may return a planar image
	assert( ![theDestRep isPlanar] );

		//	We build a resulting rep by antialiasing the big one
	{	unsigned char *s = [theDestRep bitmapData];
		unsigned char *p = [theAliasedRep bitmapData];

		for (y=0;y!= aSize.width;y++)
			for (x=0;x!= aSize.height;x++)
				for (channel=0;channel!=4;channel++)
				{	int theValue = 0;
					int theSubLine;
					for (theSubLine=0;theSubLine!=4;theSubLine++)
					{	unsigned char *s0 = s + (x*4+(y*4+theSubLine)*(int)(aSize.width)*4)*4+channel;
						theValue += s0[0];
						theValue += s0[4];
						theValue += s0[8];
						theValue += s0[12];
					}
					*p++ = (theValue+8)/16;
				}
	}

	return theAliasedRep;
}

- (NSImage *)_sdMiniImageForFile:(NSString *)aFullPath ofSize:(NSSize)aSize
{	NSImage *theIcon = [[NSWorkspace sharedWorkspace] iconForFile:aFullPath];
	NSImage *theImage;

	NSImageRep *theBestRep = nil;
	NSEnumerator *e;
	NSImageRep *theRep;

	int theBps = 0;

	if (!theIcon)
		theIcon = [[NSWorkspace sharedWorkspace] iconForFileType:[aFullPath pathExtension]];

	if (!theIcon)
	{	NSString *theTempFile = [NSString stringWithFormat:@"/tmp/%@.%@", [[NSProcessInfo processInfo] globallyUniqueString], [aFullPath pathExtension]];
		[[NSFileManager defaultManager] createFileAtPath:theTempFile contents:nil attributes:nil];
		theIcon = [[NSWorkspace sharedWorkspace] iconForFile:theTempFile];
		[[NSFileManager defaultManager] removeFileAtPath:theTempFile handler:nil];
	}

	theImage = [[[NSImage alloc] initWithSize:aSize] autorelease];
	e = [[theIcon representations] objectEnumerator];

	while (theRep = [e nextObject])
		if (NSEqualSizes( [theRep size], aSize ))
			if ( [theRep bitsPerSample] > theBps )
			{	theBestRep = theRep;
				theBps = [theRep bitsPerSample];
			}

//	[theImage setScalesWhenResized:YES];

	if (!theBestRep)
		theBestRep = [self _fbScaleRep:[theIcon bestRepresentationForDevice:nil] toSize:aSize];

	[theImage addRepresentation:theBestRep];

	return theImage;
}

@end
