うさぎ駆動開発

UWP, Xamarin.Macを中心によしなしごとを書いていきます。

<週刊 自分のごちうサーチを作る> #5 コントロールとのやりとり,ドラッグ&ドロップ

前回はこちら。

aile.hatenablog.com

今回のお品書き。

検索レベルの設定

0 から 10 まで検索レベルを設定できるようにします。 f:id:ailen0ada:20160529115444p:plain

  1. 0から10までの項目を追加する
  2. クリックされたとき,選択された項目の数値をフィールドにセットする

これでいけそうです。ではまず,WindowDidLoad にメッセージボックス表示のコードを記述してある場合は削除しましょう。
検索レベルを保持するフィールドを用意して,コントロールの初期化を行うメソッドを作ってWindowDidLoadから呼び出します。

一般的なコンボボックスとは異なり,NSPopupButton の項目は NSMenu すなわちメニューです。

  1. ルートとなるメニューを作る
  2. サブメニューアイテムを10個作る
  3. サブメニューアイテムのクリック時に検索レベルをセット

という流れになります。実装例がこちら。

8行目の Activated が項目選択時のイベントハンドラです。ただしSelectItem メソッドでコードから選択項目を変更したときにはトリガーされません。1行目で初期値を設定しているのはそのためです。

チェックボックスの状態を取得

「自動的にニコニコ動画を開く」チェックボックスは簡単です。これもフィールドを用意して,クリックされたときのイベントで変更することとします。

NSCellStateValue には On, Off, Mixed の3状態があります。この辺はWindows Formsとさほど変わりません。もちろんActivatedイベントのsenderをキャストして状態を取得してもかまいません。

ドラッグ&ドロップの実装

前回作成したAcceptDropImageViewに実装していきます。いろいろ方法はありますが,今回は

  • ローカルファイル がドロップされた
  • URL がドロップされた

の2つのイベントを作成します。まずはURLまたはパスを通知するクラスを作っておきます。場所は参照できればどこでもかまいません。

もしひとつのイベントで済ませるなら,このクラスに種別をつけるか,Payloadを改めて解析し,ローカルパスなのかURLなのかを判別することになります。
ではイベントを作成し,ドラッグ操作の受け入れ設定を行います。

RegisterForDraggedTypes で受け入れを行うNSPasteBoardのタイプを指定します。Cocoaの世界ではアプリケーション間のデータのやりとりはPasteboard Serverを経由して行われています。このビューが受け入れるタイプを指定しておくことで,データの転送対象であることを明示できます。

ではドラッグ操作がビュー内に進入してきたときに,受け入れ可能かどうか判別していきましょう。判別結果により,マウスポインタを変更します。

DraggingEntered がドラッグ操作の進入時にトリガーされます。もちろん複数のファイルをドラッグされる可能性があるので,ここでは最初のものをターゲットにしています(3行目)。このメソッドが呼ばれた際には必ずPasteboard内に項目が存在するので,項目数のチェックを行う必要は特にありません。

NSPasteboardItem クラスにはドラッグ操作内のアイテムの種別が設定されています。例えばFinderからファイルをドラッグ&ドロップするとこんな感じに。 f:id:ailen0ada:20160529124758p:plain

これはアイテムのメタデータのキーになっています。この場合はpublic.file-url キーでデータを引く(12行目GetStringForType)とファイル参照パスを取得することができます。
12行目では参照パスから通常のファイルパスに変換するため,いったんNSUrlにしてからPathプロパティでパスを取得しています。10.10以降では必ず行います。

戻り値NSDragOperation によってシステムがマウスポインタの形状を変更します。ここでは受け入れを行う際にはCopyとしてマウスポインタの右下にプラス記号が表示されるようにしています。受け入れない場合はNoneで無視します。

さて,実際に判定を行っているのはCanConformsToImageUTI というメソッドです。OSX 10.4から導入された,Uniform Type Identifierという識別子を使って,画像ファイルっぽいかどうかを判定しています。
ここではNSString.PathExtensionで取得した拡張子部分が,システムの組み込みUTIのうち,public.imageUTIを継承しているかどうかを調べ,継承している場合にtrueを返します。24行目で拡張子から最も近いUTIを得て,25行目で組み込みUTIを継承しているかどうか調べています。

Uniform Type Identifierの概要

では次に,ドロップがビュー内で行われた時の処理を実装していきます。

こちらのほうがシンプルです。判定部分はほとんど同じで,その中でイベントを発動させているだけです。受け入れを行った場合はtrueを返すようにします。この戻り値はOSX のドロップアニメーションの挙動に影響します。falseの時はドラッグ開始位置にぐいっと戻るようなアニメーションが行われます。

コード全体はこのような感じになります。

次回予告

  • ImageSearchEngine の初期化
  • 画像,またはURLがドロップされたときの動作をコントローラに実装