从NSTableView拖放到Finder的问题

时间:2011-07-13 05:45:59

标签: objective-c cocoa macos drag-and-drop

我创建了一个具有NSTableView的应用程序,它代表了一系列文件。从这里,我希望能够将一行(即文件名)从我的NSTableView拖到Finder,并在该文件夹中创建文件。但是,我无法解决的问题是,在将其复制到Finder之前,我需要修改原始文件的内容。

我添加了以下行,因此我可以拖到我的NSTableView之外:

[self.tableView setDraggingSourceOperationMask:NSDragOperationCopy forLocal:NO];    

如果我使用以下方法将当前文件位置添加到粘贴板,我可以将其复制到实际文件中:

- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard {
    [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil];        
    NSMutableArray* dragfiles = [[NSMutableArray alloc] init];
    NSString* file = [self.files objectAtIndex:row];
    NSString* filepath = [[[self.pathControl URL] path] stringByAppendingPathComponent:file];
    [dragfiles addObject:filepath];
    [pboard setPropertyList:dragfiles forType: NSFilenamesPboardType];
    [dragfiles release];
} 

但是,因为我想修改文件的内容,所以我不想将文件路径放到粘贴板上。我尝试过使用NSFileWrapper,但Finder似乎并不接受这种格式。

我已经检查了Google,我发现了一些建议,您可以创建一个临时文件并使用该文件路径。但是,这感觉很难看。

是否可以向Finder发送数据?有办法解决这个问题吗?

2 个答案:

答案 0 :(得分:20)

您很可能希望使用承诺文件,或NSFilesPromisePboardType而不是NSFilenamesPboardType。 (注意:该文档所述的promise文件方法dragPromisedFilesOfTypes:fromRect:source:slideBack:event:namesOfPromisedFilesDroppedAtDestination:是通用的NSView方法。NSTableView定义了更方便的方法,而不是通用的。那就是说,那应该仍然提供有关承诺文件拖动如何工作的信息)。 NSTableView使用tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes:,您可以在此处理文件。在tableView:writeRowsWithIndexes:toPasteboard:方法中,您将声明NSFilesPromisePboardType,然后为您计划编写的文件类型设置文件扩展名数组。以下是伪代码,概述了如何处理它:

- (BOOL)tableView:(NSTableView *)aTableView
     writeRowsWithIndexes:(NSIndexSet *)rowIndexes
        toPasteboard:(NSPasteboard *)pboard {
     [pboard declareTypes:[NSArray arrayWithObjects:NSFilesPromisePboardType, nil]];

     NSMutableArray *filenameExtensions = [NSMutableArray array];
     NSArray *draggedFilenames = [self.files objectsAtIndexes:rowIndexes];
     for (NSString *filename in draggedFilenames) {
          NSString *filenameExtension = [filename pathExtension];
          if (filenameExtension.length) {
              [filenameExtensions addObject:filenameExtension];
          }
     }
     [pboard setPropertyList:filenameExtensions
                 forType:NSFilesPromisePboardType];
     return YES;
}

然后在你的promisedFiles名字方法中:

- (NSArray *)tableView:(NSTableView *)aTableView
       namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
       forDraggedRowsWithIndexes:(NSIndexSet *)indexSet {

     NSArray *draggedFilenames = [self.files objectsAtIndexes:indexSet];

     for (NSString *filename in draggedFilenames) {
           // do your processing of files in here
          // if it may take a long time, you might need to do it on a background
          // thread

         NSString *fullPathToOriginal = nil;
          NSString *destPath =
         [[dropDestination path] stringByAppendingPathComponent:filename];


     }
     return draggedFilenames;
}

您应该能够计算原始文件路径(不确定您是如何确定它的,所以我将其保留在上面的代码中nil)和目标文件路径(使用上面代码中的内容) )。

答案 1 :(得分:6)

需要注意的事项。

NSPasteboard.h中有评论说:

/* Use of pboard types should be replaced with use of UTIs.  
   Pboard types will be deprecated in a future release. */

NSFilesPromisePboardType定义后说:

// Use (NSString *)kPasteboardTypeFileURLPromise

我只是花了几个小时撞到一堵砖墙,因为我在一些地方传递了(NSString *)kPasteboardTypeFileURLPromise而不是NSFilesPromisePboardType

看起来他们并没有做同样的事情。我无法理解为什么:

tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes 

没被打电话。当我切换回NSFilesPromisePboardType时,
突然间它被召唤了。