/* GWViewerShelf.h * * Copyright (C) 2004 Free Software Foundation, Inc. * * Author: Enrico Sersale * Date: July 2004 * * This file is part of the GNUstep GWorkspace application * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. */ #include #include #include "GWViewerShelf.h" #include "GWViewer.h" #include "GWorkspace.h" #include "FSNBrowser.h" #include "FSNIconsView.h" #include "FSNIcon.h" #include "FSNFunctions.h" #define DEF_ICN_SIZE 48 #define DEF_TEXT_SIZE 12 #define DEF_ICN_POS NSImageAbove #define DEF_GRID_WIDTH 90 #define Y_MARGIN (4) #define EDIT_MARGIN (4) @implementation GWViewerShelf - (void)dealloc { [self unsetWatchers]; RELEASE (watchedPaths); RELEASE (icons); TEST_RELEASE (extInfoType); if (grid != NULL) { NSZoneFree (NSDefaultMallocZone(), grid); } TEST_RELEASE (dragIcon); RELEASE (focusedIconLabel); RELEASE (backColor); RELEASE (textColor); RELEASE (disabledTextColor); [super dealloc]; } - (id)initWithFrame:(NSRect)frameRect forViewer:(id)vwr { self = [super initWithFrame: frameRect]; if (self) { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; id defentry; fsnodeRep = [FSNodeRep sharedInstance]; defentry = [defaults dictionaryForKey: @"backcolor"]; if (defentry) { float red = [[(NSDictionary *)defentry objectForKey: @"red"] floatValue]; float green = [[(NSDictionary *)defentry objectForKey: @"green"] floatValue]; float blue = [[(NSDictionary *)defentry objectForKey: @"blue"] floatValue]; float alpha = [[(NSDictionary *)defentry objectForKey: @"alpha"] floatValue]; ASSIGN (backColor, [NSColor colorWithCalibratedRed: red green: green blue: blue alpha: alpha]); } else { ASSIGN (backColor, [[NSColor windowBackgroundColor] colorUsingColorSpaceName: NSDeviceRGBColorSpace]); } defentry = [defaults dictionaryForKey: @"textcolor"]; if (defentry) { float red = [[(NSDictionary *)defentry objectForKey: @"red"] floatValue]; float green = [[(NSDictionary *)defentry objectForKey: @"green"] floatValue]; float blue = [[(NSDictionary *)defentry objectForKey: @"blue"] floatValue]; float alpha = [[(NSDictionary *)defentry objectForKey: @"alpha"] floatValue]; ASSIGN (textColor, [NSColor colorWithCalibratedRed: red green: green blue: blue alpha: alpha]); } else { ASSIGN (textColor, [[NSColor controlTextColor] colorUsingColorSpaceName: NSDeviceRGBColorSpace]); } ASSIGN (disabledTextColor, [textColor highlightWithLevel: NSDarkGray]); iconSize = DEF_ICN_SIZE; defentry = [defaults objectForKey: @"labeltxtsize"]; labelTextSize = defentry ? [defentry intValue] : DEF_TEXT_SIZE; ASSIGN (labelFont, [NSFont systemFontOfSize: labelTextSize]); iconPosition = DEF_ICN_POS; defentry = [defaults objectForKey: @"fsn_info_type"]; infoType = defentry ? [defentry intValue] : FSNInfoNameType; extInfoType = nil; if (infoType == FSNInfoExtendedType) { defentry = [defaults objectForKey: @"extended_info_type"]; if (defentry) { NSArray *availableTypes = [fsnodeRep availableExtendedInfoNames]; if ([availableTypes containsObject: defentry]) { ASSIGN (extInfoType, defentry); } } if (extInfoType == nil) { infoType = FSNInfoNameType; } } defentry = [defaults objectForKey: @"shelfcellswidth"]; gridSize.width = defentry ? [defentry intValue] : DEF_GRID_WIDTH; icons = [NSMutableArray new]; viewer = vwr; gworkspace = [GWorkspace gworkspace]; dragIcon = nil; focusedIcon = nil; [self calculateGridSize]; [self makeIconsGrid]; [self registerForDraggedTypes: [NSArray arrayWithObject: NSFilenamesPboardType]]; watchedPaths = [[NSCountedSet alloc] initWithCapacity: 1]; focusedIconLabel = [NSTextField new]; [focusedIconLabel setFont: [NSFont systemFontOfSize: 12]]; [focusedIconLabel setBezeled: NO]; [focusedIconLabel setAlignment: NSCenterTextAlignment]; [focusedIconLabel setEditable: NO]; [focusedIconLabel setSelectable: NO]; [focusedIconLabel setBackgroundColor: backColor]; [focusedIconLabel setTextColor: [NSColor controlTextColor]]; [focusedIconLabel setFrame: NSMakeRect(0, 0, 0, 14)]; } return self; } - (void)setContents:(NSArray *)iconsInfo { FSNode *baseNode = [viewer baseNode]; int i; for (i = 0; i < [iconsInfo count]; i++) { NSDictionary *info = [iconsInfo objectAtIndex: i]; NSArray *paths = [info objectForKey: @"paths"]; int index = [[info objectForKey: @"index"] intValue]; NSMutableArray *icnnodes = [NSMutableArray array]; int j; for (j = 0; j < [paths count]; j++) { FSNode *node = [FSNode nodeWithPath: [paths objectAtIndex: j]]; if ([node isValid] && [baseNode isParentOfNode: node]) { [icnnodes addObject: node]; } } if ([icnnodes count] && (index != -1)) { if ([icnnodes count] == 1) { [self addIconForNode: [icnnodes objectAtIndex: 0] atIndex: index]; } else { [self addIconForSelection: icnnodes atIndex: index]; } } } [self tile]; } - (NSArray *)contentsInfo { NSMutableArray *iconsInfo = [NSMutableArray array]; int i; for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; NSMutableDictionary *dict = [NSMutableDictionary dictionary]; if ([icon isShowingSelection]) { NSArray *selection = [icon selection]; NSMutableArray *paths = [NSMutableArray array]; int j; for (j = 0; j < [selection count]; j++) { [paths addObject: [[selection objectAtIndex: j] path]]; } [dict setObject: paths forKey: @"paths"]; } else { [dict setObject: [NSArray arrayWithObject: [[icon node] path]] forKey: @"paths"]; } [dict setObject: [NSNumber numberWithInt: [icon gridIndex]] forKey: @"index"]; [iconsInfo addObject: dict]; } return iconsInfo; } - (id)addIconForNode:(FSNode *)node atIndex:(int)index { FSNIcon *icon = [[FSNIcon alloc] initForNode: node nodeInfoType: infoType extendedType: extInfoType iconSize: iconSize iconPosition: iconPosition labelFont: labelFont textColor: textColor gridIndex: index dndSource: YES acceptDnd: YES slideBack: NO]; [icons addObject: icon]; [self addSubview: icon]; RELEASE (icon); { NSString *watched = [node parentPath]; if ([watchedPaths containsObject: watched] == NO) { [self setWatcherForPath: watched]; } [watchedPaths addObject: watched]; } return icon; } - (id)addIconForSelection:(NSArray *)selection atIndex:(int)index { FSNIcon *icon = [self addIconForNode: [selection objectAtIndex: 0] atIndex: index]; [icon showSelection: selection]; return icon; } - (id)iconForNode:(FSNode *)node { int i; for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; if ([[icon node] isEqual: node] && ([icon selection] == nil)) { return icon; } } return nil; } - (id)iconForPath:(NSString *)path { int i; for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; if ([[[icon node] path] isEqual: path] && ([icon selection] == nil)) { return icon; } } return nil; } - (id)iconForNodesSelection:(NSArray *)selection { int i; for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; NSArray *selnodes = [icon selection]; if (selnodes && [selnodes isEqual: selection]) { return icon; } } return nil; } - (id)iconForPathsSelection:(NSArray *)selection { int i; for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; NSArray *selnodes = [icon selection]; if (selnodes) { NSMutableArray *selpaths = [NSMutableArray array]; int j; for (j = 0; j < [selnodes count]; j++) { [selpaths addObject: [[selnodes objectAtIndex: j] path]]; } if ([selpaths isEqual: selection]) { return icon; } } } return nil; } - (void)calculateGridSize { NSSize highlightSize = NSZeroSize; NSSize labelSize = NSZeroSize; highlightSize.width = ceil(iconSize / 3 * 4); highlightSize.height = ceil(highlightSize.width * [fsnodeRep highlightHeightFactor]); if ((highlightSize.height - iconSize) < 4) { highlightSize.height = iconSize + 4; } labelSize.height = myrintf([fsnodeRep heighOfFont: labelFont]); labelSize.width = gridSize.width; gridSize.height = highlightSize.height + labelSize.height; } - (void)makeIconsGrid { NSRect gridrect = [self bounds]; NSPoint gpnt; int i; if (grid != NULL) { NSZoneFree (NSDefaultMallocZone(), grid); } colcount = (int)(gridrect.size.width / gridSize.width); rowcount = (int)(gridrect.size.height / gridSize.height); gridcount = colcount * rowcount; grid = NSZoneMalloc (NSDefaultMallocZone(), sizeof(NSRect) * gridcount); gpnt.x = 0; gpnt.y = gridrect.size.height - gridSize.height - Y_MARGIN; for (i = 0; i < gridcount; i++) { if (i > 0) { gpnt.x += gridSize.width; } if (gpnt.x >= (gridrect.size.width - gridSize.width)) { gpnt.x = 0; gpnt.y -= (gridSize.height + Y_MARGIN); } grid[i].origin = gpnt; grid[i].size = gridSize; grid[i] = NSIntegralRect(grid[i]); } } - (int)firstFreeGridIndex { int i; for (i = 0; i < gridcount; i++) { if ([self isFreeGridIndex: i]) { return i; } } return -1; } - (int)firstFreeGridIndexAfterIndex:(int)index { int newind = index; while (1) { newind++; if (newind >= gridcount) { return [self firstFreeGridIndex]; } if ([self isFreeGridIndex: newind]) { return newind; } } return -1; } - (BOOL)isFreeGridIndex:(int)index { int i; if ((index < 0) || (index >= gridcount)) { return NO; } for (i = 0; i < [icons count]; i++) { if ([[icons objectAtIndex: i] gridIndex] == index) { return NO; } } return YES; } - (id)iconWithGridIndex:(int)index { int i; for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; if ([icon gridIndex] == index) { return icon; } } return nil; } - (int)indexOfGridRectContainingPoint:(NSPoint)p { int i; for (i = 0; i < gridcount; i++) { if (NSPointInRect(p, grid[i])) { return i; } } return -1; } - (NSRect)iconBoundsInGridAtIndex:(int)index { NSRect icnBounds = NSMakeRect(grid[index].origin.x, grid[index].origin.y, iconSize, iconSize); NSRect hlightRect = NSZeroRect; hlightRect.size.width = ceil(iconSize / 3 * 4); hlightRect.size.height = ceil(hlightRect.size.width * [fsnodeRep highlightHeightFactor]); hlightRect.origin.x = ceil((gridSize.width - hlightRect.size.width) / 2); hlightRect.origin.y = floor([fsnodeRep heighOfFont: labelFont]); icnBounds.origin.x += hlightRect.origin.x + ((hlightRect.size.width - iconSize) / 2); icnBounds.origin.y += hlightRect.origin.y + ((hlightRect.size.height - iconSize) / 2); return icnBounds; } - (void)tile { NSArray *subviews = [self subviews]; int i; [self makeIconsGrid]; for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; int index = [icon gridIndex]; if (index < gridcount) { if ([subviews containsObject: icon] == NO) { [self addSubview: icon]; } if (NSEqualRects(grid[index], [icon frame]) == NO) { [icon setFrame: grid[index]]; } } else { if (focusedIcon == icon) { focusedIcon = nil; } [icon removeFromSuperview]; } } [self updateFocusedIconLabel]; } - (void)updateFocusedIconLabel { if ([[self subviews] containsObject: focusedIconLabel]) { NSRect rect = [focusedIconLabel frame]; [focusedIconLabel removeFromSuperview]; [self setNeedsDisplayInRect: rect]; } if (focusedIcon) { NSRect icnr = [focusedIcon frame]; float centerx = icnr.origin.x + (icnr.size.width / 2); NSRect edrect = [self convertRect: [focusedIcon labelRect] fromView: focusedIcon]; int margin = [fsnodeRep labelMargin]; float bw = [self bounds].size.width - EDIT_MARGIN; NSString *nodeDescr = [focusedIcon shownInfo]; float edwidth = [[focusedIconLabel font] widthOfString: nodeDescr]; edwidth += margin; if ((centerx + (edwidth / 2)) >= bw) { centerx -= (centerx + (edwidth / 2) - bw); } else if ((centerx - (edwidth / 2)) < margin) { centerx += fabs(centerx - (edwidth / 2)) + margin; } edrect.origin.x = centerx - (edwidth / 2); edrect.size.width = edwidth; edrect = NSIntegralRect(edrect); [focusedIconLabel setFrame: edrect]; [focusedIconLabel setStringValue: nodeDescr]; if ([focusedIcon isLocked] == NO) { [focusedIconLabel setTextColor: [NSColor controlTextColor]]; } else { [focusedIconLabel setTextColor: [NSColor disabledControlTextColor]]; } [focusedIcon setNameEdited: YES]; [self addSubview: focusedIconLabel]; [self setNeedsDisplayInRect: edrect]; } } - (void)setWatcherForPath:(NSString *)path { [gworkspace addWatcherForPath: path]; } - (void)unsetWatcherForPath:(NSString *)path { [gworkspace removeWatcherForPath: path]; } - (void)unsetWatchers { NSEnumerator *enumerator = [watchedPaths objectEnumerator]; NSString *wpath; while ((wpath = [enumerator nextObject])) { [self unsetWatcherForPath: wpath]; } } - (NSArray *)watchedPaths { return [watchedPaths allObjects]; } - (void)checkIconsAfterDotsFilesChange { int count = [icons count]; BOOL updated = NO; int i; for (i = 0; i < count; i++) { FSNIcon *icon = [icons objectAtIndex: i]; int j; if ([icon isShowingSelection] == NO) { if ([[[icon node] path] rangeOfString: @"."].location != NSNotFound) { [self removeRep: icon]; updated = YES; count--; i--; } } else { NSArray *iconpaths = [icon pathsSelection]; for (j = 0; j < [iconpaths count]; j++) { NSString *iconpath = [iconpaths objectAtIndex: j]; if ([iconpath rangeOfString: @"."].location != NSNotFound) { [self removeRep: icon]; updated = YES; count--; i--; break; } } } } if (updated) { [self tile]; [self setNeedsDisplay: YES]; } } - (void)checkIconsAfterHidingOfPaths:(NSArray *)hpaths { int count = [icons count]; BOOL updated = NO; int i; for (i = 0; i < count; i++) { FSNIcon *icon = [icons objectAtIndex: i]; int j, m; if ([icon isShowingSelection] == NO) { NSString *iconpath = [[icon node] path]; for (m = 0; m < [hpaths count]; m++) { NSString *hpath = [hpaths objectAtIndex: m]; if (isSubpathOfPath(hpath, iconpath) || [hpath isEqual: iconpath]) { [self removeRep: icon]; updated = YES; count--; i--; break; } } } else { NSArray *iconpaths = [icon pathsSelection]; BOOL removed = NO; for (j = 0; j < [iconpaths count]; j++) { NSString *iconpath = [iconpaths objectAtIndex: j]; for (m = 0; m < [hpaths count]; m++) { NSString *hpath = [hpaths objectAtIndex: m]; if (isSubpathOfPath(hpath, iconpath) || [hpath isEqual: iconpath]) { [self removeRep: icon]; updated = YES; count--; i--; removed = YES; break; } } if (removed) { break; } } } } if (updated) { [self tile]; [self setNeedsDisplay: YES]; } } - (void)resizeWithOldSuperviewSize:(NSSize)oldFrameSize { [self tile]; } - (void)setFrame:(NSRect)frameRect { [super setFrame: frameRect]; [self tile]; } - (void)drawRect:(NSRect)rect { [super drawRect: rect]; if (dragIcon) { [dragIcon dissolveToPoint: dragPoint fraction: 0.3]; } } @end @implementation GWViewerShelf (NodeRepContainer) - (void)removeRep:(id)arep { NSString *watched = [[arep node] parentPath]; if ([watchedPaths containsObject: watched]) { [watchedPaths removeObject: watched]; if ([watchedPaths containsObject: watched] == NO) { [self unsetWatcherForPath: watched]; } } if ([[self subviews] containsObject: arep]) { [arep removeFromSuperviewWithoutNeedingDisplay]; } if (focusedIcon == arep) { focusedIcon = nil; [self updateFocusedIconLabel]; } [icons removeObject: arep]; } - (void)removeUndepositedRep:(id)arep { [self removeRep: arep]; [self setNeedsDisplay: YES]; } - (void)repSelected:(id)arep { [viewer shelfDidSelectIcon: arep]; [arep unselect]; } - (void)unselectOtherReps:(id)arep { int i; for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; if (icon != arep) { [icon unselect]; } } } - (NSArray *)selectedPaths { NSMutableArray *selectedPaths = [NSMutableArray array]; int i, j; for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; if ([icon isSelected]) { NSArray *selection = [icon selection]; if (selection) { for (j = 0; j < [selection count]; j++) { [selectedPaths addObject: [[selection objectAtIndex: j] path]]; } } else { [selectedPaths addObject: [[icon node] path]]; } } } return [NSArray arrayWithArray: selectedPaths]; } - (void)nodeContentsWillChange:(NSDictionary *)info { [self checkLockedReps]; } - (void)nodeContentsDidChange:(NSDictionary *)info { NSString *operation = [info objectForKey: @"operation"]; NSString *source = [info objectForKey: @"source"]; NSString *destination = [info objectForKey: @"destination"]; NSArray *files = [info objectForKey: @"files"]; int i; if ([operation isEqual: @"NSWorkspaceRecycleOperation"]) { files = [info objectForKey: @"origfiles"]; } if ([operation isEqual: @"GWorkspaceRenameOperation"]) { for (i = 0; i < [icons count]; i++) { FSNIcon *icon = [icons objectAtIndex: i]; if ([icon isShowingSelection] == NO) { if ([[[icon node] path] isEqual: source]) { [icon setNode: [FSNode nodeWithPath: destination]]; break; } } } } if ([operation isEqual: @"GWorkspaceRenameOperation"]) { files = [NSArray arrayWithObject: [source lastPathComponent]]; source = [source stringByDeletingLastPathComponent]; } if ([operation isEqual: @"NSWorkspaceMoveOperation"] || [operation isEqual: @"NSWorkspaceDestroyOperation"] || [operation isEqual: @"GWorkspaceRenameOperation"] || [operation isEqual: @"NSWorkspaceRecycleOperation"] || [operation isEqual: @"GWorkspaceRecycleOutOperation"] || [operation isEqual: @"GWorkspaceEmptyRecyclerOperation"]) { NSMutableArray *oppaths = [NSMutableArray array]; int count = [icons count]; BOOL updated = NO; for (i = 0; i < [files count]; i++) { NSString *fname = [files objectAtIndex: i]; NSString *fpath = [source stringByAppendingPathComponent: fname]; [oppaths addObject: fpath]; } for (i = 0; i < count; i++) { FSNIcon *icon = [icons objectAtIndex: i]; int j, m; if ([icon isShowingSelection] == NO) { NSString *iconpath = [[icon node] path]; for (m = 0; m < [oppaths count]; m++) { if ([iconpath hasPrefix: [oppaths objectAtIndex: m]]) { [self removeRep: icon]; updated = YES; count--; i--; break; } } } else { NSArray *iconpaths = [icon pathsSelection]; BOOL removed = NO; for (j = 0; j < [iconpaths count]; j++) { NSString *iconpath = [iconpaths objectAtIndex: j]; for (m = 0; m < [oppaths count]; m++) { if ([iconpath hasPrefix: [oppaths objectAtIndex: m]]) { [self removeRep: icon]; updated = YES; count--; i--; removed = YES; break; } } if (removed) { break; } } } } if (updated) { [self tile]; [self setNeedsDisplay: YES]; } } } - (void)watchedPathChanged:(NSDictionary *)info { NSString *path = [info objectForKey: @"path"]; NSString *event = [info objectForKey: @"event"]; NSEnumerator *enumerator; NSString *wpath; BOOL contained = NO; if ([event isEqual: @"GWFileCreatedInWatchedDirectory"]) { return; } enumerator = [watchedPaths objectEnumerator]; while ((wpath = [enumerator nextObject])) { if (([wpath isEqual: path]) || (isSubpathOfPath(path, wpath))) { contained = YES; break; } } if (contained) { int count = [icons count]; BOOL updated = NO; FSNIcon *icon; int i; if ([event isEqual: @"GWWatchedPathDeleted"]) { for (i = 0; i < count; i++) { icon = [icons objectAtIndex: i]; if ([[icon node] isSubnodeOfPath: path]) { [self removeRep: icon]; updated = YES; count--; i--; } } if (updated) { [self tile]; [self setNeedsDisplay: YES]; } return; } if ([event isEqual: @"GWFileDeletedInWatchedDirectory"]) { NSArray *files = [info objectForKey: @"files"]; for (i = 0; i < count; i++) { int j; icon = [icons objectAtIndex: i]; if ([icon isShowingSelection] == NO) { FSNode *node = [icon node]; for (j = 0; j < [files count]; j++) { NSString *fname = [files objectAtIndex: j]; NSString *fpath = [path stringByAppendingPathComponent: fname]; if ([[node path] isEqual: fpath] || [node isSubnodeOfPath: fpath]) { [self removeRep: icon]; updated = YES; count--; i--; break; } } } else { FSNode *node = [icon node]; NSArray *selection = [icon selection]; for (j = 0; j < [files count]; j++) { NSString *fname = [files objectAtIndex: j]; NSString *fpath = [path stringByAppendingPathComponent: fname]; BOOL deleted = NO; int m; if (deleted) { break; } if ([node isSubnodeOfPath: fpath]) { [self removeRep: icon]; updated = YES; count--; i--; break; } for (m = 0; m < [selection count]; m++) { node = [selection objectAtIndex: m]; if ([[node path] isEqual: fpath]) { [self removeRep: icon]; updated = YES; count--; i--; deleted = YES; break; } } } } } if (updated) { [self tile]; [self setNeedsDisplay: YES]; } } } } - (void)checkLockedReps { int i; for (i = 0; i < [icons count]; i++) { [[icons objectAtIndex: i] checkLocked]; } } - (FSNSelectionMask)selectionMask { return NSSingleSelectionMask; } - (void)restoreLastSelection { [self unselectOtherReps: nil]; } - (void)setFocusedRep:(id)arep { if (arep == nil) { if (focusedIcon) { [focusedIcon setNameEdited: NO]; } } focusedIcon = arep; [self updateFocusedIconLabel]; } - (NSColor *)backgroundColor { return backColor; } - (NSColor *)textColor { return textColor; } - (NSColor *)disabledTextColor { return disabledTextColor; } @end @implementation GWViewerShelf (DraggingDestination) - (NSDragOperation)draggingEntered:(id )sender { NSPasteboard *pb = [sender draggingPasteboard]; NSDragOperation sourceDragMask = [sender draggingSourceOperationMask]; DESTROY (dragIcon); isDragTarget = NO; dragLocalIcon = NO; if ((sourceDragMask == NSDragOperationCopy) || (sourceDragMask == NSDragOperationLink)) { return NSDragOperationNone; } if (pb && [[pb types] containsObject: NSFilenamesPboardType]) { NSArray *sourcePaths = [pb propertyListForType: NSFilenamesPboardType]; int count = [sourcePaths count]; FSNode *baseNode = [viewer baseNode]; NSString *basePath; int i; if (count == 0) { return NSDragOperationNone; } for (i = 0; i < count; i++) { NSString *path = [sourcePaths objectAtIndex: i]; if ([baseNode isParentOfPath: path] == NO) { return NSDragOperationNone; } } basePath = [[sourcePaths objectAtIndex: 0] stringByDeletingLastPathComponent]; if ([basePath isEqual: [gworkspace trashPath]]) { return NSDragOperationNone; } if (count == 1) { dragLocalIcon = ([self iconForPath: [sourcePaths objectAtIndex: 0]] != nil); } else { dragLocalIcon = ([self iconForPathsSelection: sourcePaths] != nil); } isDragTarget = YES; dragPoint = NSZeroPoint; DESTROY (dragIcon); insertIndex = -1; return NSDragOperationAll; } return NSDragOperationNone; } - (NSDragOperation)draggingUpdated:(id )sender { NSDragOperation sourceDragMask; NSPoint dpoint; int index; if (isDragTarget == NO) { return NSDragOperationNone; } sourceDragMask = [sender draggingSourceOperationMask]; if ((sourceDragMask == NSDragOperationCopy) || (sourceDragMask == NSDragOperationLink)) { if (dragIcon) { DESTROY (dragIcon); if (insertIndex != -1) { [self setNeedsDisplayInRect: grid[insertIndex]]; } } return NSDragOperationNone; } dpoint = [sender draggingLocation]; dpoint = [self convertPoint: dpoint fromView: nil]; index = [self indexOfGridRectContainingPoint: dpoint]; if ((index != -1) && ([self isFreeGridIndex: index])) { NSImage *img = [sender draggedImage]; NSSize sz = [img size]; NSRect irect = [self iconBoundsInGridAtIndex: index]; dragPoint.x = ceil(irect.origin.x + ((irect.size.width - sz.width) / 2)); dragPoint.y = ceil(irect.origin.y + ((irect.size.height - sz.height) / 2)); if (dragIcon == nil) { ASSIGN (dragIcon, img); } if (insertIndex != index) { [self setNeedsDisplayInRect: grid[index]]; if (insertIndex != -1) { [self setNeedsDisplayInRect: grid[insertIndex]]; } } insertIndex = index; } else { DESTROY (dragIcon); if (insertIndex != -1) { [self setNeedsDisplayInRect: grid[insertIndex]]; } insertIndex = -1; return NSDragOperationNone; } if ((sourceDragMask == NSDragOperationCopy) || (sourceDragMask == NSDragOperationLink)) { return NSDragOperationNone; } return NSDragOperationAll; } - (void)draggingExited:(id )sender { DESTROY (dragIcon); if (insertIndex != -1) { [self setNeedsDisplayInRect: grid[insertIndex]]; } isDragTarget = NO; } - (BOOL)prepareForDragOperation:(id )sender { return isDragTarget; } - (BOOL)performDragOperation:(id )sender { return YES; } - (void)concludeDragOperation:(id )sender { NSPasteboard *pb = [sender draggingPasteboard]; NSMutableArray *sourcePaths = [pb propertyListForType: NSFilenamesPboardType]; int count = [sourcePaths count]; id icon; DESTROY (dragIcon); isDragTarget = NO; if (insertIndex != -1) { if (dragLocalIcon) { if (count == 1) { icon = [self iconForPath: [sourcePaths objectAtIndex: 0]]; } else { icon = [self iconForPathsSelection: sourcePaths]; } if (icon) { [icon setGridIndex: insertIndex]; } } else { FSNode *baseNode = [viewer baseNode]; NSMutableArray *icnnodes = [NSMutableArray array]; int i; for (i = 0; i < [sourcePaths count]; i++) { FSNode *node = [FSNode nodeWithPath: [sourcePaths objectAtIndex: i]]; if ([node isValid] && [baseNode isParentOfNode: node]) { [icnnodes addObject: node]; } } if ([icnnodes count]) { if ([icnnodes count] == 1) { [self addIconForNode: [icnnodes objectAtIndex: 0] atIndex: insertIndex]; } else { [self addIconForSelection: icnnodes atIndex: insertIndex]; } } } } [self tile]; [self setNeedsDisplay: YES]; } @end