Cocoa-Javaでのファイル処理クラスを紹介したが、それを受けて、Document-basedアプリケーションで、ファイルタイプやクリエイタを設定する方法を説明したい。文書ファイルを保存するという機能はNSDocumentクラスに組み込まれているが、少々複雑であるもの、ファイル書き込み処理はカスタマイズできるようになっている。NSDocumentでは、ある文書を保存するときに、指定したファイルにいきなり書き込むのではなく、一時的に別のフォルダにファイルを書き込んで、その後に、書き込んだファイルをユーザが指定したフォルダ位置にあるファイルとして移動するという作業を行なう。したがって、一時的に書き込むファイルをそのまま適当に残しておけば、バックアップファイルを作成すると言う機能までも組み込めるのである。 こうした仕組みは、NDDocumentでは次のようなメソッドで処理される。ファイルの書き込みを行うときには、writeWithBackupToFileというメソッドが実行され、そこからwriteToFileの4つの引数があるメソッドが呼び出され、さらにそこからwriteToFileの2つの引数のあるメソッドが呼び出される。その後に、以前に説明したdataRepresentationOfTypeメソッドが呼び出されるのである。以下は、NSDocumentに組み込まれている機能としてまとめておく。
☆文書の内容を指定したファイルに保存する boolean 〈NSDocument〉.writeWithBackupToFile( String fullDocumentPath, String documentTypeName, int saveOperationType); 戻り値: 引数:fullDocumentPath:保存する書類ファイルのフルパス documentTypeName:ドキュメントの種類を示す文字列 saveOperationType:保存か名前を付けて保存かなどを示す
☆文書ファイルのバックアップを残すかどうかを判定する boolean 〈NSDocument〉.keepBackupFile(); 戻り値:falseを戻す
writeWithBackupToFileは、もし、keepBackupFileメソッドの戻り値がfalseなら、バックアップファイルは残さない。NSDocumentに定義されたkeepBackupFileはfalseを戻すのであるが、これをtrueを戻してバックアップファイルを残すようにしたいのなら、NSDocumentを継承したクラス(ここではMyDocumentクラス)で、keepBackupFileメソッドをオーバーライドして、単にtrueをモドすようにすればいい。
☆文書をファイルに書き込む boolean 〈NSDocument〉.writeToFile( String fullDocumentPath, String documentTypeName, String fullOriginalDocumentPath, int saveOperationType); 戻り値:書き込みが成功したらtrue、失敗したらfalse 引数:fullDocumentPath:実際に書き込みを行う文書ファイルのパス名 documentTypeName:文書の種類を示す文字列 fullOriginalDocumentPath:ユーザが指定した文書ファイルのパス saveOperationType:保存か名前を付けて保存かなどを示す
☆文書をファイルに書き込む boolean 〈NSDocument〉.writeToFile( String fileName, String type); 戻り値:書き込みが成功したらtrue、失敗したらfalse 引数:fileName:実際に書き込みを行う文書ファイルのパス名 type:文書の種類を示す文字列
要は、次のようなメソッドの連鎖が行われるのである。
writeWithBackupToFile └→writeToFile(4) └→writeToFile(2) └→dataRepresentationOfType ┌─┘ ┌─┘ ┌─┘ └→keepBackupFile ┌─┘
これらのうち、dataRepresentationOfTypeは必ずオーバーライドして定義しないといけないメソッドだが、あとは必要に応じてオーバーライドする。その意味ではデフォルトの動作を知っておく必要はあるだろう。ここで、ユーザは実施に保存したいファイルのファイル名とフォルダを指定するのだが、それは、writeToFileでの引数fullOriginalDocumentPathとしては得られる。一方、writeToFileでの引数fullDocumentPathあるいはfileNameでは、実際に保存を行う一時的なファイルの名前が得られるのである。たとえば、保存するファイルが、
/Users/msyk/b.medit
だったとした場合、たとえば、fileName引数で得られる実際に書き込みを行うファイルのパスは、
/private/tmp/501/Temporary Items/com.apple.NSDocument_6567_32252318_1/b.medit
といったものだ。/tmpディレクトリにあることや、ファイル名自体は実際のファイル名と同じであるあたりがポイントになるだろう。 dataRepresentationOfTypeではファイルに保存すべきデータはNSData型で作っておくが、writeToFileでは、そのNSData型データを、ファイルに保存するというわけである。 もし、NSDocumentで想定されているような、ファイルを開いたときにファイルの全データをロードし、保存時には全データをストアするというような場合には、特に上記のメソッドはオーバーライドする必要はないだろう。一方、ファイルへのストレージを併用するような場合だと、書き込みはもちろん、読み込み時にも関連するメソッドをオーバーライドして、必要な情報だけを取り込むということを実現しなければならない。また、文書ファイルが複数のファイルで構成されるような場合でも、writeToFileあたりのメソッドをオーバーライドする必要がある。なお、writeToFileなどのメソッドをオーバーライドしたときには、必要に応じて元になっているクラスの同名のメソッドを呼び出しておくことは忘れないようにしよう。
では、ファイルタイプとクリエイタを保存したファイルに設定するには、writeToFileの引数が2つのメソッドをオーバーライドして…と思ってなんとなくうまく動きかけたのだが、上書き保存するとファイルタイプが消えてしまう。どうやら、一時的なファイルに対してファイルタイプやクリエイタを設定するのはできているけどもそれをコピーする段階で、BSDレベルのコールを使っているせいだろうか(?〜想像だが)、情報がすべてコピーされていないような気がする。そこで、MyDocumentクラスに次のように、メソッドをオーバーライドした
public boolean writeWithBackupToFile( String fullDocumentPath, String documentTypeName, int saveOperationType) { boolean retVal = super.writeWithBackupToFile(fullDocumentPath, documentTypeName, saveOperationType); int fTypeInt; if(documentTypeName.equals("MOSAEditor Document")) fTypeInt = NSHFSFileTypes.hfsTypeCodeFromFileType("‘rtf ’"); else fTypeInt = NSHFSFileTypes.hfsTypeCodeFromFileType("‘TEXT’"); Integer values[] = { new Integer(NSHFSFileTypes.hfsTypeCodeFromFileType("‘ome9’")), new Integer(fTypeInt)}; String keys[] = {"NSFileHFSCreatorCode", "NSFileHFSTypeCode"}; NSDictionary attributes = new NSDictionary(values, keys); NSPathUtilities.setFileAttributes(fullDocumentPath, attributes); return retVal; };
(上記のソース中‘’の部分は実際には半角のシングルクォート)
まず最初に、一連のNSDocumentで定義されたデフォルトの作業をやらないといけないので、super.writeWithBackupToFileによって、元のメソッドの呼び出しを行う。その後に、保存された文書ファイルに対して、ファイルタイプとクリエイタの設定を行っているのである。文書のsh類に応じてファイルタイプが異なる。ファイルタイプやクリエイタは、NSDictionaryクラスのオブジェクトで指定するが、タイプやクリエイタは整数値でなければならない。その整数値は、NSHFSFileTypesクラスのhfsTypeCodeFromFileTypeメソッド(長い!)で得られる。なお、ファイルタイプとクリエイタだけを指定したいので、NSDictionaryのキーにはそれに相当する文字列だけを指定しておけばいいというわけである。 (この項、続く) |