ページ

ラベル Application List の投稿を表示しています。 すべての投稿を表示
ラベル Application List の投稿を表示しています。 すべての投稿を表示

2010年4月22日木曜日

APplication List (8) リストの永続化 / NSUserDefaultsへ保存

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

(連載)Cocoaの日々: Application List

アプリケーションリストを NSUserDefaults へ保存する。

今回は更新される度に保存するようにした。
AppListAppDelegate.m

- (void)rearrangeList
{
[arrayController_ rearrangeObjects];
NSUserDefaults* userDefaults =
[[NSUserDefaultsController sharedUserDefaultsController] values];
NSMutableArray* pathList = [NSMutableArray array];
for (ApplicationEntry* entry in appList_) {
[pathList addObject:entry.path];
}
[userDefaults setValue:pathList forKey:UDKEY_HELPER_APPLICATION_LIST];
}


特に工夫無くパス名を配列へ書き出し、それを NSUserDeafults へ保存している。カスタムクラス(ApplicationEntry) は NSUserDeafults の書き出しに対応していない。NSUserDefaultsController をわざわざ使っているのは SimpleCap で使っているのでそれに合わせただけ。

起動時に NSUserDefaults からこれを読み出してリスト表示へ反映させる。

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
:
NSUserDefaults* userDefaults =
[[NSUserDefaultsController sharedUserDefaultsController] values];
NSArray* pathList = [userDefaults valueForKey:UDKEY_HELPER_APPLICATION_LIST];
for (NSString* path in pathList) {
[appList_ addObject:[[[ApplicationEntry alloc] initWithPath:path] autorelease]];
}
[arrayController_ rearrangeObjects];
:
}


実行してみよう。
操作を行うと ~/Library/Preferences 配下にファイルが作成される。

中身はこんな感じ。
次回起動時には直前のリストが復元された。

(メモ)SimpleCapの場合、ビューア(SimpleViewer)がNSUserDefaults のアプリケーション設定の変更を監視している。設定が変更されたらアプリケーションアイコンの表示を書き換える必要がある。

2010年4月21日水曜日

Application List (7) + - ボタンの実装

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

(連載中)Cocoaの日々: Application List

まずは [ー] ボタンの実装。これは Interface Builder 上でボタンのターゲット&アクションを、-[NSArrayController remove] へ接続すればいい。

たったこれだけで選択した行を削除することができる。



次に[+]ボタン。NSOpenPanel を開くコードを実装する。こんな感じ。
AppListAppDelegate.m

- (IBAction)addApplication:(id)sender
{
NSString* path = @"/Applications";
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel setCanChooseFiles:YES];
[openPanel setCanChooseDirectories:NO];
[openPanel setCanCreateDirectories:NO];
[openPanel setAllowsMultipleSelection:YES];
[openPanel setDirectory:path];

int result = [openPanel runModalForDirectory:path
file:nil
types:nil];
if (result == NSOKButton) {
for (NSString* filename in [openPanel filenames]) {
ApplicationEntry* entry =
 [[[ApplicationEntry alloc] initWithPath:filename] autorelease];
[appList_ addObject:entry];
}
[arrayController_ rearrangeObjects];
}
}


動かしてみよう。

[+]を押すとパネルが開く。
選ぶと
出た。


ソースコードは GitHub からどうぞ
xcatsan's SampleCode at 2010-04-21 - GitHub

- - - -
ほぼ完成。後はこれに NSUserDefaults を使った永続化の機能を加える。

2010年4月20日火曜日

Application List (6) ドラッグ&ドロップ#3 モデル内データを移動する

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

(連載中)Cocoaの日々: Application List

前回ドラッグ&ドロップができるようになった。ただ見た目だけでドロップしても何も起こらない。今回はドロップした時にモデル内でデータを移動して、最終的に並び替えができるようにする。

モデルは NSMutableArray で管理している。ドロップ時にこの配列内で並び替えをやればいいだろう。


まずドロップ時の処理から。-[NSTableViewDataSource tableView:acceptDrop:row:dropOperation:] を実装する。
AppListAppDelegate.m

- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info
  row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation
{
    NSPasteboard* pboard = [info draggingPasteboard];
NSArray* pboardTypes = [pboard types];

if ([pboardTypes containsObject:AppListTableViewDataType]) {

NSData* data = [pboard dataForType:AppListTableViewDataType];
NSIndexSet *rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:data];

NSArray* srcArray = [appList_ objectsAtIndexes:rowIndexes];
NSUInteger srcCount = [srcArray count];

if ([rowIndexes firstIndex] < row) {
row = row - srcCount;
}
NSIndexSet* newIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row, srcCount)];

[appList_ removeObjectsAtIndexes:rowIndexes];
[appList_ insertObjects:srcArray atIndexes:newIndexes];
[arrayController_ rearrangeObjects];

return YES;

} else if ([pboardTypes containsObject:NSFilenamesPboardType]) {
NSArray*filenames = [pboard propertyListForType:NSFilenamesPboardType];

for (NSString* filename in filenames) {
ApplicationEntry* entry = [[[ApplicationEntry alloc] initWithPath:filename] autorelease];

[appList_ insertObject:entry atIndex:row];
}
[arrayController_ rearrangeObjects];
return YES;
} else {
return NO;
}
}


ドラッグは、ファインダからのケース(NSFilenamesPboardType)と、テーブル内からの移動のケース(AppListTableViewDataType: オリジナルのタイプ)の2種類がある。今回は後者の方の実装。

ドラッグ開始時に、ドラッグ対象の行情報(NSIndexSet)がペーストボードに入れられるので、これを取り出して処理する。

NSData* data = [pboard dataForType:AppListTableViewDataType];
NSIndexSet *rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:data];


移動処理は単純に元のデータを削除し、これらを新たな位置へ挿入する。削除後に挿入位置が変わるケースがあるのでその調整が入れてある。

if ([rowIndexes firstIndex] < row) {
row = row - srcCount;
}


NSMutableArray を操作した後、-[NSArrayController rearrangeObjects] を呼び出して、NSTableViewへ表示を反映させる。

[appList_ removeObjectsAtIndexes:rowIndexes];
[appList_ insertObjects:srcArray atIndexes:newIndexes];
[arrayController_ rearrangeObjects];



動かしてみよう。
ドラッグして..
ドロップする。
移動できた。

ソースは GitHub からどうぞ。
AppList at 2010-04-20c from xcatsan's SampleCode - GitHub


- - - -
あとは + ー ボタンの実装ぐらいか。

2010年4月19日月曜日

Application List (5) ドラッグ&ドロップ#2

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

(前回)Cocoaの日々: Application List (4) ドラッグ&ドロップ

前回ドラッグ&ドロップができるようになったが描画がおかしかった。


コードを見直すと原因は描画方法にあることがわかった。
ApplicationCell.m

- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
ApplicationEntry* entry = [self objectValue];

[controlView lockFocus];
NSPoint p1 = cellFrame.origin;
p1.x += 0;
p1.y += 0 + [entry.icon size].height;
[entry.icon compositeToPoint:p1 operation:NSCompositeSourceOver];
NSPoint p2 = cellFrame.origin;
p2.x += 20;
p2.y += 0;
NSDictionary* attrs = [NSDictionary dictionary];
[entry.name drawAtPoint:p2 withAttributes:attrs];
[controlView unlockFocus];
}

controlView を lockFocus して描いているのが問題。ドラッグ&ドロップ時にもセルの drawIneriorWithFrame:inView: が呼び出されるが、この時渡される controlView は NSTableView内のビュー。つまりドラッグ中のファイルを描画するビューではない。なのに、上記コードではドラッグ&ドロップ時の描画でも NSTableView内のビューに lockFocus をかけて描画しているためにおかしなことになった。

原因がわかれば対応は簡単。lockFocus を使わずに描画すればいい。


- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
ApplicationEntry* entry = [self objectValue];
NSSize iconSize = [entry.icon size];
NSPoint p1 = cellFrame.origin;
if ([controlView isFlipped]) {
p1.y += iconSize.height;
}
[entry.icon compositeToPoint:p1 operation:NSCompositeSourceOver];
NSRect nameRect = cellFrame;
nameRect.origin.x += iconSize.width + 4.0;
nameRect.size.width -= iconSize.width;

NSDictionary* attrs = [NSDictionary dictionary];
[entry.name drawInRect:nameRect withAttributes:attrs];
}


さて実行してみよう。


出た。ちょっとうれしい。


ソースは GitHub からどうぞ。
AppList at 2010-04-20 from xcatsan's SampleCode - GitHub

- - - -
GUI はできたが並び替えの処理はまだ書いていない。次回はこれを実装しよう。

2010年4月17日土曜日

Application List (4) ドラッグ&ドロップ

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

(前回)Cocoaの日々: Application List (3) アイコン表示

NSTableView 内でドラッグ&ドロップを使った並び替えの機能を実装する。

再びリファレンスを見て必要な実装を入れる。
Table View Programming Guide: Using Drag and Drop in Tables

1. registerForDraggedTypes: でサポートするデータタイプを定義
2. tableView:writeRowsWithIndexes:toPasteboard: でドラッグ開始
3. tableView:validateDrop:proposedRow:propsedDropOperation: でドロップ受け入れ準備
4. tableView:acceptDrop:row:dropOperation: でドロップ処理


まずデータタイプを定義。


#define AppListTableViewDataType @"AppListTableViewDataType"
 :


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[tableView_ registerForDraggedTypes:
[NSArray arrayWithObjects:
  NSFilenamesPboardType, AppListTableViewDataType, nil]];
            :
}



次にドラッグ開始時の処理。ドラッグ対象の行データを NSKeyedArchiver を使い  NSData に変換し、ペーストボードへ登録する。

- (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard
{
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
    [pboard declareTypes:[NSArray arrayWithObject:AppListTableViewDataType] owner:self];
    [pboard setData:data forType:AppListTableViewDataType];
    return YES;
}


ドロップ受け入れ判定。NSTableView 内の場合、NSDragOperationMove (移動) とする。

- (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id < NSDraggingInfo >)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation
{
[aTableView setDropRow:row dropOperation:NSTableViewDropAbove];
if ([info draggingSource] == tableView_) {
return NSDragOperationMove;
return NSDragOperationEvery;
}


最後はドロップ時の処理だが、とりあえずここまでで動かしてみる。

ん?ドラッグしても選択されるだけで、行をドラッグできない。なぜだろう。



いろいろ調べていると NSTableView はドラッグ時に -[NSCell hitTestForEvent:inRect:ofView:] を呼び出し、この結果でドラッグするかを判断しているらしい (v10.5から)。

情報源:

reordering table cells with 10.5 sdk | Cocoabuilder

上記に掲載されていた情報を引用すると:
NSTableView/NSOutlineView - Cell Hit Testing, Drag and Drop, and
Cell EditingNSTableView now uses the new NSCell hit testing API to
perform certain actions. Custom NSCell subclasses in applications
that link on or after Leopard should properly implement -
hitTestForEvent:inRect:ofView:; see NSCell.h for more information.

NSTableView performs hit testing in the cells to do the following
actions:
 - Drag and Drop: NSTableView calls hitTestForEvent:inRect:ofView in
 canDragRowsWithIndexes:atPoint. If the hit cell returns
 NSCellHitTrackableArea, the particular row will be tracked instead
 of dragged.
 - Cell Editing: When NSTableView recieves a mouse down, single-click
 editing of text (like Finder) will happen if there is only one row
 selected, and the cell returns NSCellHitEditableTextArea.

 See the DragNDropOutlineView demo application for an example of how
 to properly implement the NSCell methods.
※上記は developer.apple.com の releaesnotes に掲載されていたらしいが、みつからなかった。


関連情報:

NSCell Class Reference - Hit Testing

NSCell Class Reference - hitTestForEvent:inRect:ofView:

DragNDropOutlineView


そこで NSCell のサブクラスで hitTestForEvent:inRect:ofView: を実装してみた。といっても単純に NSCellHitContentArea を返すだけ。
ApplicationCell.m

- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView {
return NSCellHitContentArea;
}



これでどうだろう。
ドラッグできた。挿入位置に横線が入るようになった。ただ描画がおかしい。何故かドラッグしている行が一番上の行に描画されている。うーむ。

2010年4月16日金曜日

Application List (3) アイコン表示

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

(前回)Cocoaの日々: Application List (2) ファイルパスからアプリ名に変換して表示 - LSCopyDisplayNameForURL

前回はアプリ名を表示した。今回はアイコンを表示してみよう。

まずアイコン画像の用意から。ファイルのアイコン画像は -[NSWorkspace iconForFile:] で取得できる。
NSWorkspace Class Reference - iconForFile:

パスから決めることができるので前回同様 -[ApplicationEntry initWithPath:] 内に仕込む。

ApplicationEntry.m

-(id)initWithPath:(NSString*)aPath
{
self = [super init];
if (self != nil) {
self.path = aPath;
   :
   :
self.icon = [[NSWorkspace sharedWorkspace] iconForFile:path];
[icon setSize:NSMakeSize(16, 16)];
}
return self;
}


取得後に表示用のサイズ(16x16)を設定しておく。



次にこの画像を表示する実装。

NSTableView で画像を表示するには NSImageCell を使うのが簡単だが、これでは同じセル内でアプリ名が表示できない。カスタムセルを作って自前で描画する必要がある。この辺り iPhone では標準のセルで簡単にできるので AppKit の方にも用意して欲しい。

自前描画は以前扱ったことがある。
Cocoaの日々: NSTableView にカスタムビューを表示する (6)カスタムセルにモデルオブジェクトの内容を描画する

関連:
Cocoaの日々: NSTableView にカスタムビューを表示する (5)カスタムセルへ bindings経由でモデルオブジェクトを渡す



描画方法について改めてまとめてみる。

1. NSCell のサブクラスを作る(カスタムセルと呼ぶことにする)

2. 表示したい NSTableColumn にカスタムセルのインスタンスを設定する。

3. NSTableColumn の Value に モデルを bindする

4. カスタムセルに2つのメソッドを実装する
-(void) drawInteriorWithFrame:inView:
-(id)copyWithZone:


詳しく見ていこう。





1. NSCell のサブクラスを作る。

ApplicationCell という名のクラスを作る。

@interface ApplicationCell : NSCell {

}

@end


2. 表示したい NSTableColumn にカスタムセルのインスタンスを設定する

今回は AppListAppDelegate に NSTableColumn へのアウトレットを用意し、アプリ起動時に -[NSTableColumn setDataCell:] で設定してやる。

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
:
[tableColumn_ setDataCell:
[[[ApplicationCell allocinitautorelease]];
}





3. NSTableColumn の Value に モデルを bindする

今回は ArrayController を介してモデルとつながっている。
AppListAppDelegate.appList ← Array Controller ← NSTableColumn

Interface Builder で NSTableColumn の Bindings設定を開き、Bind to を Array Controller へ、Key は arrangedObjects、Model Key Path を空にしておく。

Model Key Path を空にしておくのがポイントで、これによって ArrayController が扱う ApplicationEntry のインスタンスを直接セルへ渡せる。

なお ArrayController の方はこうなっている。
appList は AppListAppDelegate で定義されている NSMutableArray を指している。


4. カスタムセルに2つのメソッドを実装する

ApplicationCell.m
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
ApplicationEntry* entry = [self objectValue];
[controlView lockFocus];
NSPoint p1 = cellFrame.origin;
p1.x += 0;
p1.y += 0 + [entry.icon size].height;
[entry.icon compositeToPoint:p1 operation:NSCompositeSourceOver];
NSPoint p2 = cellFrame.origin;
p2.x += 20;
p2.y += 0;
NSDictionary* attrs = [NSDictionary dictionary];
[entry.name drawAtPoint:p2 withAttributes:attrs];
[controlView unlockFocus];
}

- (id)copyWithZone:(NSZone *)zone
{
ApplicationCell* cell = (ApplicationCell*)[super copyWithZone:zone];
return cell;
}



-[NSCell objectValue] でArrayController から渡される ApplicationEntry のインスタンスを取得することができる。
copyWithZone: は必須。これが実装さていないと実行時にエラーとなる(NSTableColumn が使う)。



これで、できあがり。

動かしてみよう。
出た。いい感じだ。

ソースコードは GitHub からどうぞ
AppList at 2010-04-15c from xcatsan's SampleCode - GitHub


(参考)セルに画像とテキストを描く情報はHMDT でも紹介されている。参考まで。

この中の「セルに画像とテキストを描く」の箇所。カスタムセルを用意して drawInteriorWithFrame:inView: をオーバーライドすれば良い。


----
次はドラッグ&ドロップによる並び替え。


2010年4月15日木曜日

Application List (2) ファイルパスからアプリ名に変換して表示 - LSCopyDisplayNameForURL

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

(前回)Cocoaの日々: Application List (1) 雛形作成

前回はドラッグ&ドロップされたファイルパスのファイル名をそのまま表示していた。


アプリケーションの場合、これをファイル名ではなくアプリケーションの名前にしたい。Launch Service API の LSCopyDisplayNameForURL() を使うと取得できる。
Launch Services Reference - LSCopyDisplayNameForURL


前回のサンプルではモデルクラス ApplicationEntry の nameプロパティを(ArrayControllerを介して) NSTableColumn へbindしていた。ここにアプリ名を入れれば bindingsを通じて表示される。

ApplicationEntry.h

@interface ApplicationEntry : NSObject {

NSString* name;
NSString* path;
NSImage* icon;
}
@property (copy) NSString* name;
@property (copy) NSString* path;
@property (retain) NSImage* icon;
@end

path から name を決められる(後日やる iconも同じ)ので pathを引数に取るイニシャライザを追加する。

ApplicationEntry.m

-(id)initWithPath:(NSString*)aPath
{
self = [super init];
if (self != nil) {
self.path = aPath;
NSString* appName;
LSCopyDisplayNameForURL((CFURLRef)[NSURL fileURLWithPath:path], (CFStringRef *)&appName);
if (!appName) {
appName = @"(not found)";
}
self.name = appName;
}
return self;
}


ドロップ処理でこのイニシャライザを使う。
AppListAppDelegate.m

- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info
  row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation
{
NSPasteboard* pboard = [info draggingPasteboard];
NSArray*filenames = [pboard propertyListForType:NSFilenamesPboardType];

for (NSString* filename in filenames) {
ApplicationEntry* entry = [[[ApplicationEntry alloc] initWithPath:filename] autorelease];
[arrayController_ insertObject:entry atArrangedObjectIndex:row];
}

return YES;
}



動かしてみる。
出た。

2010年4月14日水曜日

Application List (1) 雛形作成

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

SimpleCap で要望が出ているプリファレンス内のヘルパーアプリ登録の UI改善に乗り出す。

現在はこんな感じ。

今見るとちょっとトホホ感がある。。

これを Mac用アプリでよくあるインターフェイスに変える。たとえば OS X のシステム環境設定にあるアカウントのログイン項目の UI:

[+] [ー] でアプリの増減が行える他、Finderからのドラッグ&ドロップでも登録ができる。SimpleCap の場合、並び替えもできた方がいいだろう。

この UI の実装に取り組む。いつも通りサンプルを作って色々試した後、SimpleCap へ組み込むアプローチを取る。今回はドラッグ&ドロップできるところまで実装してみた。こんな感じ。
リスト表示には NSTableView を使い、ボタンは 23x20の NSButton を使い、 Imageに NSAddTemplate/NSRemoveTemplate、Bezel に Gradient を割り当てるとそれっぽいものができた。

アーキテクチャはいつもの通り Cocoa bindings を使った MVCを採用。今回モデルは NSMutableArray で管理し、これを Array Controller を通じて NSTableViewへ接続(bind)する。
表示一件分を表すモデル用のクラスとして ApplicationEntry を定義した。
ApplicationEntry.h

@interface ApplicationEntry : NSObject {

NSString* name;
NSString* path;
NSImage* icon;
}
@property (copy) NSString* name;
@property (copy) NSString* path;
@property (retain) NSImage* icon;
@end


これらを配列として管理する NSMutableArray は(サンプルなので)AppListAppDelegate の appList_ で管理している(InterfaceBuilder上の App List App...)。
AppListAppDelegate.h

@interface AppListAppDelegate : NSObject {
    NSWindow *window;
IBOutlet NSTableView* tableView_;
IBOutlet NSArrayController* arrayController_;
NSMutableArray* appList_;
}
@property (assign) IBOutlet NSWindow *window;
@property (retain) NSMutableArray* appList;



Interface Builder を使い、これらをつなげ(bind)て行く。

イメージ:
AppListAppDelegate.appList <-- Array Controller <-- NSTableColumn

NSTableColum の bindings の設定はこう。arrangedObjects は配列(appList)内のオブジェクト(ApplicationEntry)を表し、そのプロパティ name を表の表示データとして割り当てる。
ArrayController の bindings。AppListAppDelegate.appList へ bind してある。

MVC がつながった。
Model: appLisst
View: NSTableColumn
Controller: ArrayController

これだけで基本的な表示はおしまい。表示に関するコードを書かずにここまでできる。


次はドラッグ&ドロップの実装。NSTableView のドラッグ&ドロップ実装についてはリファレンスが用意されている。
Table View Programming Guide: Using Drag and Drop in Tables

ここに最小限の実装方法が載っている。
1. registerForDraggedTypes: でサポートするデータタイプを定義
2. tableView:writeRowsWithIndexes:toPasteboard: でドラッグ開始
3. tableView:validateDrop:proposedRow:propsedDropOperation: でドロップ受け入れ準備
4. tableView:acceptDrop:row:dropOperation: でドロップ処理

今回は、まずファインダからのドラッグ&ドロップだけを受け入れるので 1, 3, 4 を実装する。なお 3, 4 のメソッドは NSTableViewDataSource プロトコルで定義されていて NSTableView の DataSourceに対して呼び出しがかかる。この為、この DataSource で実装を書く必要がある。

今回は AppListAppDelegate を NSTableView の DataSource として Interface Builder で設定した。1, 3, 4 の実装は次の通り。

AppListAppDelegate.m

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application 
[tableView_ registerForDraggedTypes:
[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
}

NSFilenamesPboardType でファイル名の配列を受け取るようにする。


- (NSDragOperation)tableView:(NSTableView*)tv
 validateDrop:(id <NSDraggingInfo>)info
 proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)op
{
    return NSDragOperationEvery;
}

続いて 3.ドロップ受け入れ準備ではすべてのドラッグを受け入れることを返す。

最後に 4. ドロップ処理。

- (BOOL)tableView:(NSTableView *)aTableView
 acceptDrop:(id <NSDraggingInfo>)info
 row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation
{
    NSPasteboard* pboard = [info draggingPasteboard];
NSArray*filenames = [pboard propertyListForType:NSFilenamesPboardType];

for (NSString* filename in filenames) {
ApplicationEntry* entry = [[[ApplicationEntry alloc] init] autorelease];
entry.path = filename;
entry.name = [filename lastPathComponent];
[arrayController_ insertObject:entry atArrangedObjectIndex:row];
}

return YES;
}


NSPaseboard からドラッグ&ドロップされたファイル名配列を取得し、1つ1つを ApplicationEntry のインスタンスに割り当てる。そのインスタンスを ArrayController を通じて配列へ追加する。appList (NSMutableArray) へ直接追加しないのは、ArrayController を通した方が NSTableColumn の再描画が自動的に行われる為。appList 追加だけだと NSTableColumn は再描画されずドラッグ&ドロップしても何も表示が変わらない。

これで雛形がラフなものだができた。
コードを書く量がほんと少ない。bindings を使う度に毎回Cocoa のすごさを感じる。

- - - -
現状はファイル名を表示しているが、これをアイコン画像付きで、表示もアプリ名にする必要がある。次回取り組んでみよう。