Re: NSWorkspaceRecycleOperation and auto-renaming items moved to Trash
Re: NSWorkspaceRecycleOperation and auto-renaming items moved to Trash
- Subject: Re: NSWorkspaceRecycleOperation and auto-renaming items moved to Trash
- From: Kurt Revis <email@hidden>
- Date: Thu, 28 Feb 2002 09:38:27 -0800
Speaking of code, here is a huge pile of it which is ANOTHER way of
working around the renaming bug in NSWorkspaceRecycleOperation. This
method will move one file to the trash; if you want to override
NSWorkspace's method with a category, and stick this code in there, feel
free.
Note that it still doesn't consistently update the Trash icon in the
Dock, or the Finder's Trash window -- I still don't know how to do that,
if there is a way.
Note: I've checked that this works for moving a afile to the trash on an
HFS+ volume (the same volume as my user account). I haven't tested it
with other filesystems or with files on other volumes, although it
should work fine. I also don't know what it will do if you have
symlinks in your path, and like all of NSFileManager, it will probably
fail miserably if your path is >= 1024 characters. In other words, this
code is worth exactly what you paid for it--nothing. Use at your own
risk. If you rely on it and it fails, that's your problem, not mine.
Is that enough disclaimers yet?
Any corrections and improvements are welcome, of course. I just bashed
this out very quickly...
---------------------------------------------------------------------------------
static OSErr PathToFSRef(CFStringRef inPath, FSRef *outRef);
static CFStringRef FSRefToPathCopy(const FSRef *inRef);
static NSString *trashPathForFile(NSString *filePath);
static NSString *destinationNameForFileInTrash(NSString *fileName,
NSString *trashPath);
static void notifyThatTrashChanged(NSString *trashPath);
- (BOOL)moveFileToTrash:(NSString *)filePath;
{
NSString *trashPath;
NSString *fileName;
NSString *destinationName;
NSString *destinationPath;
trashPath = trashPathForFile(filePath);
if (!trashPath)
return NO;
fileName = [filePath lastPathComponent];
destinationName = destinationNameForFileInTrash(fileName, trashPath);
destinationPath = [trashPath
stringByAppendingPathComponent:destinationName];
if (![[NSFileManager defaultManager] movePath:filePath
toPath:destinationPath handler:nil])
return NO;
// Update the Dock's trash icon, if possible.
notifyThatTrashChanged(trashPath);
return YES;
}
// PathToFSRef and FSRefToPathCopy are borrowed from BDAlias:
//
http://bdistributed.com/Projects/BDAlias/
//
// Here's the necessary legalese.
/*
Copyright (c) 2001, bDistributed.com, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
* Neither the name of bDistributed.com, Inc. nor the names of
its contributors may be used to endorse or promote products
derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
static OSErr PathToFSRef(CFStringRef inPath, FSRef *outRef)
{
CFURLRef tempURL = NULL;
Boolean gotRef = false;
tempURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, inPath,
kCFURLPOSIXPathStyle, false);
if (tempURL == NULL) {
return fnfErr;
}
gotRef = CFURLGetFSRef(tempURL, outRef);
CFRelease(tempURL);
if (gotRef == false) {
return fnfErr;
}
return noErr;
}
static CFStringRef FSRefToPathCopy(const FSRef *inRef)
{
CFURLRef tempURL = NULL;
CFStringRef result = NULL;
if (inRef != NULL) {
tempURL = CFURLCreateFromFSRef(kCFAllocatorDefault, inRef);
if (tempURL == NULL) {
return NULL;
}
result = CFURLCopyFileSystemPath(tempURL, kCFURLPOSIXPathStyle);
CFRelease(tempURL);
}
return result;
}
static NSString *trashPathForFile(NSString *filePath)
{
OSErr err;
FSRef fileRef;
FSCatalogInfo catalogInfo;
FSRef trashRef;
NSString *trashPath;
// Find the volume the file is on.
err = PathToFSRef((CFStringRef)filePath, &fileRef);
if (err != noErr) {
#if DEBUG
NSLog(@"trashPathForFile(%@): PathToFSRef failed: %hd",
filePath, err);
#endif
return nil;
}
err = FSGetCatalogInfo(&fileRef, kFSCatInfoVolume, &catalogInfo,
NULL, NULL, NULL);
if (err != noErr) {
#if DEBUG
NSLog(@"trashPathForFile(%@): FSGetCatalogInfo failed: %hd",
filePath, err);
#endif
return nil;
}
// Find the trash for that volume.
err = FSFindFolder(catalogInfo.volume, kTrashFolderType,
kCreateFolder, &trashRef);
if (err != noErr) {
#if DEBUG
NSLog(@"trashPathForFile(%@): FSFindFolder failed: %hd",
filePath, err);
#endif
return nil;
}
// Translate the trash's FSRef back to a path so we can use it.
trashPath = [(NSString *)FSRefToPathCopy(&trashRef) autorelease];
if (!trashPath) {
#if DEBUG
NSLog(@"trashPathForFile(%@): FSRefToPathCopy failed!",
filePath);
#endif
return nil;
}
return trashPath;
}
static NSString *destinationNameForFileInTrash(NSString *fileName,
NSString *trashPath)
{
NSFileManager *fileManager;
NSString *destinationName;
NSString *fileNameWithoutExtension;
NSString *fileNameExtension;
unsigned int suffix = 0;
fileManager = [NSFileManager defaultManager];
// Check the common case first
if (![fileManager fileExistsAtPath:[trashPath
stringByAppendingPathComponent:fileName]])
return fileName;
fileNameWithoutExtension = [fileName stringByDeletingPathExtension];
fileNameExtension = [fileName pathExtension];
do {
NSString *suffixString;
suffix++;
if (suffix == 1)
suffixString = @" copy";
else
suffixString = [NSString stringWithFormat:@" copy %u",
suffix];
// TODO The word "copy" should be localized
destinationName = [[fileNameWithoutExtension
stringByAppendingString:suffixString]
stringByAppendingPathExtension:fileNameExtension];
} while ([fileManager fileExistsAtPath:[trashPath
stringByAppendingPathComponent:destinationName]]);
return destinationName;
}
static void notifyThatTrashChanged(NSString *trashPath)
{
OSStatus status;
// TODO This doesn't work in Mac OS X 10.1.3. The Trash icon in the
Dock, and the Finder's view of the Trash,
// does not update consistently. Sometimes the Dock icon will update
when it is clicked on, sometimes not.
// Sometimes the files appear in the Finder's Trash window,
sometimes not.
status = FNNotifyByPath([trashPath fileSystemRepresentation],
kFNDirectoryModifiedMessage, kNilOptions);
if (status != noErr) {
#if DEBUG
NSLog(@"FNNotifyByPath(%@) failed: %ld", trashPath, status);
#endif
}
}
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.