2011年5月31日火曜日

Cocoa NSTreeControllerを調べる(4)

FileManagerでOutlineViewにマウントされているデバイスのディレクトリを表示する。デベロッパドキュメントに載っていたサンプル通りのままだと、外付けHDDなどがマウントされた時にどうすればいいかわからない。そんなんでNSTreeControllerについて調べている。

NSTreeControllerでFileSystemを表示しようとする場合、NSTreeNodeを使わないで直接modelのArrayをNSTreeControllerのContentにしたほうがよいみたいだ、というのが昨日の結論。それなら、さらにNSTreeControllerも使わずにOutlineViewのdatasourceでコードを書いてしまえばいいのでは、となんとなく思ったが、bindingを使ったほうがやはり何かと便利そうだ。コードの量が少なければbugも少なくなるはずだし。

というわけで、本日は昨日の状態からさらに

1,[[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:nil options:NSVolumeEnumerationSkipHiddenVolumes]でマウントされたVolumesを取得する。(そうするとHide属性のVolumeを拾わないですむ)
2,volumesというNSMutableArrayをメンバにして、読み書き可能なプロバティにしてNSTreeControllerのcontentにbindingさせる
3,NSWorkspaceDidMountNotification、NSWorkspaceDidUnmountNotificationを使ってマウント時、アンマウント時の処理をしてみる

以上をやってみた。

この状態から外付けHDD「for_mac」をマウントすると、


最後尾に追加される。

コードはこうなった。
#import "Controller.h"
#import "FileSystemItem.h"

@implementation Controller
@synthesize volumes;
- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
        volumes=[NSMutableArray array];
    }
    
    return self;
}

- (void)dealloc
{
    [volumes release];
    [super dealloc];
}
-(void)setVolume{
    NSArray* mountedVols=[[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:nil options:NSVolumeEnumerationSkipHiddenVolumes];
    NSMutableArray *roots=[NSMutableArray array];
    if ([mountedVols count] > 0){
  for (NSURL *element in mountedVols){
            FileSystemItem* item,*parent;
            if([[element path ]isEqualToString:@"/"]){
                item=[[FileSystemItem alloc] initWithPath:[element path] parent:nil];
            }
            else{
                parent=[[FileSystemItem alloc]initWithPath:[[element path] stringByDeletingLastPathComponent] parent:nil];
                item=[[FileSystemItem alloc] initWithPath:[element path] parent:parent];
                [parent release];
                
            }
            [roots addObject:item];
            [item release];
            
        }
  [self setVolumes:roots]; 
 }

    
}
-(void)awakeFromNib{
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(didMount:) name:NSWorkspaceDidMountNotification object:nil];
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(didUnmount:) name:NSWorkspaceDidUnmountNotification object:nil];
    [self setVolume];

}
-(void)didMount:(id)sender{
    NSLog(@"Mount! %@",sender);
    NSDictionary* info=[sender userInfo];
    NSURL* url=[info objectForKey:NSWorkspaceVolumeURLKey];
    FileSystemItem* parent=[[FileSystemItem alloc]initWithPath:[[url path] stringByDeletingLastPathComponent] parent:nil];
    FileSystemItem* item=[[FileSystemItem alloc] initWithPath:[url path] parent:parent];
    [parent release];
    [volumes addObject:item];
    [item release];
    [treeController rearrangeObjects];
  
    
}
-(void)didUnmount:(id)sender{
    NSLog(@"UnMount! %@",sender);
    NSDictionary* info=[sender userInfo];
    NSURL* url=[info objectForKey:NSWorkspaceVolumeURLKey];
    NSUInteger deleteNo;
    for (NSInteger i=0; i<[volumes count]; i++) {
        FileSystemItem* item=[volumes objectAtIndex:i];
        if ([[item fullPath] isEqualToString:[url path]]) {
           deleteNo=i;
        }
    }
    [volumes removeObjectAtIndex:deleteNo];
    [treeController rearrangeObjects];

}
@end

treeControllerのbindingなどはこうなっている。

これでほぼ考えていた動作が実現できた。次はEseに組み込んでみる。これはちょっと苦労するところがあると予想している。@"/"を期待した動作、などを書いているので。

0 件のコメント:

コメントを投稿