ページ

2010年1月26日火曜日

NSWorkspace - recycleURLs:completionHandler:(ゴミ箱に捨てる/復活させる)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

ファイルをゴミ箱へ捨てるメソッドが Mac OS X v10.6 から NSWorkspace に追加された。

Mac Dev Center: NSWorkspace Class Reference - recycleURLs:completionHandler:

シグネチャはこんな感じ。

- (void)recycleURLs:(NSArray *)URLs completionHandler:(void (^)(NSDictionary *newURLs, NSError *error))handler

ブロックを引数に取るようになっていて、ゴミ箱へファイルを移動した後の処理を書けるようになっている。


ゴミ箱にファイルを捨てる処理は以前紹介したことがある。
Cocoaの日々: 直前のキャプチャ画像をゴミ箱へ捨てる

10.5 まではこんなコードでゴミ箱へファイルを移動していた。

[[NSWorkspace sharedWorkspace]
   performFileOperation:NSWorkspaceRecycleOperation
   source:dir destination:@""
   files:files tag:nil];

難点は一旦ゴミ箱へファイルを移動すると、それを取りやめて元に戻す(復活させる)ことが難しいこと。これはゴミ箱に入るとファイルの URLが変わってしまうため(見た目は変わっていないが、同名のファイルが捨てられても区別できるように内部的には別名で管理されている)。

これが 10.6 から導入された recycleURLs:completionHandler: を使うと、ゴミ箱へ移動すると同時にゴミ箱内でのURLを取得することができる。この URL を使うことで後でゴミ箱から元のファイル探し出して復活させることができる。


動作を見るためにサンプルを作ってみた。

(1)ボタンでデスクトップにplistファイルを作り、(2)ボタンでゴミ箱へ移動する。最後に(3)ボタンでゴミ箱からデスクトップへファイルを復活させる。


ソースコードは次の通り。XcodeのテンプレートでCocoaアプリを作る。

RecycleStudyAppDelegate.h

@interface RecycleStudyAppDelegate : NSObject {
    NSWindow *window;

IBOutlet NSTextField* filenameField;
IBOutlet NSTextField* urlField;

NSURL* originalURL;
NSURL* newURL;
}

@property (assign) IBOutlet NSWindow *window;

-(IBAction)generate:(id)sender;
-(IBAction)moveToTrash:(id)sender;
-(IBAction)undo:(id)sender;

@end


最初にテスト用に作るファイル名のURLを作っておく。
RecycleStudyAppDelegate.m

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application

NSString* path = [NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES) objectAtIndex:0];
path = [path stringByAppendingPathComponent:@"RecycleSample.plist"];

originalURL = [[NSURL alloc] initFileURLWithPath:path];
}


(1)generate : テスト用のファイルをデスクトップに作成する。

-(IBAction)generate:(id)sender
{
NSDictionary* sampleDict = [NSDictionary
dictionaryWithObjectsAndKeys:[NSDate date], @"now", nil];
[sampleDict writeToURL:originalURL atomically:YES];
[filenameField setStringValue:[originalURL description]];
}

中身は現在時刻を詰めてある(特に意味なし)。

(2)move to trash:続いてゴミ箱への移動。

-(IBAction)moveToTrash:(id)sender
{
NSArray* urls = [NSArray arrayWithObject:originalURL];

[[NSWorkspace sharedWorkspace] recycleURLs:urls
completionHandler:^(NSDictionary *newURLs, NSError *error) {
if (error != nil) {
NSLog(@"error: %@", error);
} else {
NSLog(@"newURLs: %@", newURLs);
newURL = [[newURLs objectForKey:originalURL] retain];
[urlField setStringValue:[newURL description]];
}
}];
}

ブロック内で渡される NSDictionary *newURLs にはキーにオリジナルのURL、値にゴミ箱内でのURLが入っている。こんな感じ。

RecycleStudy[18476:80f] newURLs: {
    "file://localhost/Users/hashi/Desktop/RecycleSample.plist" = "file://localhost/Users/hashi/.Trash/RecycleSample.plist";
}


上記ではゴミ箱内でのURLを newURLにとって置いてある。

(3)undo : ゴミ箱からデスクトップへ戻す。


-(IBAction)undo:(id)sender
{
NSError* error = nil;
BOOL result = [[NSFileManager defaultManager]
  moveItemAtURL:newURL toURL:originalURL error:&error];
if (!result) {
NSLog(@"error: %@", error);
}
}


ゴミ箱から復活させる時にはファイルの移動を行えばいい。10.6 からは -[NSFileManager moveItemAtURL:toURL:error:] が用意されたので今回の場合のように URLベースでファイル移動を扱うのには好都合。これを使う。
Mac Dev Center: NSFileManager Class Reference - moveItemAtURL:toURL:error:


さて動かしてみよう。

まずテスト用ファイルを生成する - (1)generate。

デスクトップにファイルが作られる。


次にゴミ箱へ移動する - (2) move to trash

デスクトップからファイルが消えてゴミ箱にファイルが入る。

最後に復活 - (3)undo
デスクトップに再びファイルが出てくる。

ゴミ箱のファイルはなくなる。




なお同名のファイルを複数回ゴミ箱へ捨てると、2個目以降のゴミ箱内のURLには数字がついてユニークになる。



おまけ

ついでに duplicateURLs:completionHandler: も試してみた。
Mac Dev Center: NSWorkspace Class Reference - duplicateURLs:completionHandler:

先程のサンプルプログラムに duplicate ボタンを追加する。

コードはこんな感じ
-(IBAction)duplicate:(id)sender
{
NSArray* urls = [NSArray arrayWithObject:originalURL];

[[NSWorkspace sharedWorkspace] duplicateURLs:urls
  completionHandler:^(NSDictionary *newURLs, NSError *error) {
  if (error != nil) {
  NSLog(@"error: %@", error);
  } else {
  NSLog(@"newURLs: %@", newURLs);
  NSURL* url = [newURLs objectForKey:originalURL];
  [dupField setStringValue:[url description]];
  }
  }];
}

実行してみる。

こんな感じで複製が作られる。複製されたファイル名は「〜のコピー」と日本語にはならず英語("copy")になるようだ。



ソースコード
GitHubからどうぞ
RecycleStudy at master from xcatsan's SampleCode - GitHub

- - - -
recycleURLs:completionHandler: は "Finder-Like Operations" として duplicateURLs:completionHandler: と共に紹介されている。
Mac Dev Center: Low-Level File Management Programming Topics: File Management