ページ

2008年11月3日月曜日

アプリケーションを開く(6)ソートする

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

アプリの並びをソートする。ソートはアプリケーションの URLではなく名前で行う。現状名前のリストは持っていない。そこでアプリのURL、名前、アイコンを保持する小さなモデルクラスを用意し、ここに compare: メソッドを実装することにした。

AppEntry.h

@interface AppEntry : NSObject
{
NSURL* _url;
NSString* _name;
NSImage* _image;
}
@property (retain) NSURL* url;
@property (retain) NSString* name;
@property (retain) NSImage* image;


#compre: は nameで比較すれば良い。
- (NSComparisonResult)compare:(AppEntry*)entry
{
return [_name compare:entry.name];
}


その上で Launch Services API から取得したアプリ一覧を元に一旦 AppEntryのインスタンスを作り、配列へ入れておく。そしてその配列へ sortedArrayUsingSelector: を投げてやる。
NSArray* sorted_entry_list = [entry_list sortedArrayUsingSelector:@selector(compare:)];


できた。


サンプル:FindingAllApps-4.zip

2008年11月2日日曜日

アプリケーションを開く(5)デフォルトアプリ表示

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

次にデフォルトアプリケーションを一番上にくるようにする。デフォルトアプリは Launch Services API の LSGetApplicationForURL が使える。

こんな感じ。

 FSRef outAppRef;
NSURL* default_url;
LSGetApplicationForURL((CFURLRef)target_url, kLSRolesAll, &outAppRef, (CFURLRef*)&default_url);



セパレータ(NSMenuItem#separatorItem)も入れてできあがり。


サンプル:FindingAllApps-3.zip

- - - -
ファインダの「このアプリケーションで開く」では、デフォルトアプリに「(デフォルト)」と入れたり、同じアプリケーション名称が存在する場合(図の Firefox)はバージョン番号を加えたりとなかなか芸が細かい。

2008年11月1日土曜日

アプリケーションを開く(4)アプリの一覧表示

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

さて利用可能なアプリケーションの一覧を取得する方法がわかったので今度はこれを NSPopUpButtonで表示してみる。
Cocoa Bindings を使いたいところだが、今回はアイコン画像を表示したいので普通にコーディングすることにした(*)。

サンプル:FindingAllApps-2.zip

バンドル内に用意した dummy.jpg を扱えるアプリの一覧がアイコン付きで表示される。


コードはこんな感じ。主要な検証は前回までで済んでいるので、NSPopUpButtonとNSMenuのセットアップが中心。

- (NSArray*)menuItems
{
NSString* path = [[NSBundle mainBundle] pathForImageResource:@"dummy.jpg"];
NSURL* target_url = [NSURL fileURLWithPath:path];
NSArray* app_list = [(NSArray*)LSCopyApplicationURLsForURL((CFURLRef)target_url, kLSRolesAll) autorelease];

NSMutableArray* item_list = [NSMutableArray array];
NSString* display_name;
NSImage * image;

for (NSURL* url in app_list) {
LSCopyDisplayNameForURL((CFURLRef)url, (CFStringRef *)&display_name);
image = [[NSWorkspace sharedWorkspace] iconForFile:[url path]];
[image setSize:NSMakeSize(16, 16)];

NSMenuItem* item = [[[NSMenuItem alloc] init] autorelease];
[item setTitle:display_name];
[item setImage:image];
[item setTarget:self];
[item setAction:@selector(selectApplication:)];
[item setRepresentedObject:
[NSDictionary dictionaryWithObjectsAndKeys:url, @"url", nil]];
[item_list addObject:item];
[display_name release];
}

return item_list;
}



(*) NSPopUpButton+CocoaBindings で画像を表示する。
CocoaBindingsで画像が扱えないことに不満を持った人が他にも居たみたいで、poseAsClass で無理くり?対応させた強者がいた。
Cocoatech: Bindings and NSPopUpButton hack
なるほど。面白い(まねしないけど)。
掲載された画像を見るとどうも同じこと(あるファイルを扱うことのできるアプリ一覧)をやっているようだ。
(ああ PathFinderの作者のページか!)

2008年10月31日金曜日

アプリケーションを開く(3)拡張子から利用可能なアプリを調べる?

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

前回は Launch Services API の LSCopyApplicationURLsForURLを使ってオープン可能なアプリケーションの一覧を取得した。
例えば pro.jpg というファイルの場合、次のリストが取得できた。

    file://localhost/Applications/QuickTime%20Player.app/,
file://localhost/Developer/Applications/Xcode.app/,
file://localhost/Applications/Gimp.app/,
file://localhost/Applications/OpenOffice.org%202.1.app/,
file://localhost/Applications/Safari.app/,
file://localhost/Applications/Preview.app/,
file://localhost/Developer/Applications/Graphics%20Tools/Core%20Image%20Fun%20House.app/,
file://localhost/Applications/Adobe%20Illustrator%20CS2/Adobe%20Illustrator.app/,
file://localhost/Applications/%E3%83%84%E3%83%BC%E3%83%AB/Firefox.2.app/,
file://localhost/Applications/tools/Firefox.app/,
file://localhost/Applications/Utilities/ColorSync%20Utility.app/,
file://localhost/Users/hashi/development/study/package/build/Release/package.app/,
file://localhost/Applications/Firefox.app/


SimpleCapで扱うファイルは GIF/JPEG/PNG なので、特定のファイルを開けるアプリの一覧よりは、これらの種類を開けるアプリの一覧が欲しい。API の中に LSCopyAllRoleHandlersForContentType があったのでこれを使ってみる。結果は下記の通り。
    "com.apple.CoreImageFunHouse.app",
"org.gimp.Gimp",
"com.apple.Preview",
"com.apple.ColorSyncUtility"


むむ。返される形式が異なるのは別として、アプリの数が少ない。

これは結局2つの関数の検索条件が異なることに起因しているようだ。前者は拡張子かクリエータを対象に、後者は Info.plistのLSCopyDefaultRoleHandlerForContentTypeエントリを対象として検索している。

この話題はメーリングリストでも取り上げられていた。
Re: Get a list of all Apps for a File


なるほど。

だったらダミーファイルを GIF/JPEG/PNGの3種類、バンドル内に用意してこれを使って対応アプリを取得することにしよう。

かなり安易だが。。

#ちなみに試しに実在しないファイルを LSCopyApplicationURLsForURL を渡したところ nullが返ってきた。

2008年10月30日木曜日

アプリケーションを開く(2)「このアプリ..で開く」

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

プレビューは開くことができたので、こんどは起動するアプリケーションを環境設定で自由に選べるようにする。

イメージはファインダの「このアプリケーションで開く」


さてこれを実現するにはファイルを開くのに適したアプリケーションを取得する必要がある。デフォルトのアプリは NSWorkspace#getInfoForFile:application:type: で取れそうだが、オープン可能なアプリ一覧となると NSWorkspace では役不足のようだ。

MacOSXには Launch Services という API が用意されていれていて、このあたりを扱うことができる。

Launch Services Programming Guide

このAPIの中に LSCopyApplicationURLsForURL という関数が用意されていて、これが使えそうだ。

(参考)Re: Get list of possible applications


早速サンプルアプリを作って試してみる。

サンプル:FindingAllApps-1.zip

実行するとソースに付随している画像ファイル pro.jpg を開くことができるアプリの一覧がコンソールへ出力される。


コードはこんな感じ。

 NSString* path = [[NSBundle mainBundle] pathForImageResource:@"pro"];
NSURL* url = [NSURL fileURLWithPath:path];
NSArray* array = [(NSArray*)LSCopyApplicationURLsForURL((CFURLRef)url, kLSRolesAll) autorelease];
NSLog(@"%@", array);


実行結果。

2008年10月29日水曜日

アプリケーションを開く(1)Preview.appで開く

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

キャプチャ後に特定のアプリケーションを開く様にする。まずはプレビュー(Preview.app)で開いてみよう。
これは NSWorkspace#openFile:withApplication: を使えば簡単にできる。

[[NSWorkspace sharedWorkspace] openFile:filename withApplication:@"Preview.app"];


これをキャプチャコントローラのファイル保存後の位置に差し込んでやる。ただ開くかどうかはプリファレンスで制御したいので IB で制御用のチェックボックスを追加し、この値によって開く制御を行う。


キャプチャを行うと直後にプレビューで画像が表示されるようになった。

2008年10月28日火曜日

範囲選択履歴(その9)履歴の保存

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

履歴を NSUserDefaultsに保存する。その為に履歴のモデルにあたる SelectionHistoryに手を入れる。
履歴は NSSize を NSValueでラップし、これを NSArray で持っている。NSUserDefaultsは NSSizeを扱えないので NSStringに変換して保存する。とりだすときはその逆に NSStringから NSSizeへ戻してやる。標準でその為の関数が用意されている。

NSStringFromSize( )
NSSizeFromString


これらを使って読み込みと保存のメソッドを用意する。
SelectionHistory
- (void)load
{
if (_history_list) {
[_history_list release];
}
_history_list = [[NSMutableArray alloc] init];
NSArray* array = [UserDefaults valueForKey:UDKEY_SELECTION_HISTORY];
for (NSString* str in array) {
NSSize size = NSSizeFromString(str);
[_history_list addObject:[NSValue valueWithSize:size]];
}
}
- (void)save
{
NSMutableArray* array = [NSMutableArray array];
for (NSValue* value in _history_list) {
NSString* size = NSStringFromSize([value sizeValue]);
[array addObject:size];
}
[UserDefaults setValue:array forKey:UDKEY_SELECTION_HISTORY];
[UserDefaults save];
}


それぞれを適切な位置で呼出せば履歴の永続化が完了する。
NSUserDefaulsへのアクセスには以前作成した NSUserDefaultsController のラッパークラス UserDefaults を使う。
NSUserDefaultsController を使う場合は(デフォルトでは)しかるべきタイミングで save: を投げてやる必要がある。UserDefaultsにはその為のメソッド #saveを用意した。

UserDefaults
+ (void)save
{
[(NSUserDefaultsController*)[NSUserDefaultsController sharedUserDefaultsController] save:self];
}