NSRuleEditorのローカライズ(その2)

前回のエントリで書いたようにNSRurleEditorではルールを作成に際してDelegateメソッドを通じて細かい制御をおこなうことができます。必須のDelegeteメソッドは3つ、

  1. ruleEditor:numberOfChildrenForCriterion:withRowType:
  2. ruleEditor:child:forCriterion:withRowType:
  3. ruleEditor:displayValueForCriterion:inRow:

NSRuleEditorのaddRowメソッド呼び出しのタイミングで左辺・述部・右辺についてそれぞれ呼び出されます。今回のサンプルで言えば初回時(ルート)では price/color/sizeの3つの選択肢があるので返す数は3。NSRuleEditorではこの数に基づいて、ruleEditor:child:forCriterion:withRowType:メソッドが3回呼び出します。このメソッドでは左辺3つの情報をNSDictionary形式にパックして返します。パラメータchild:(NSInteger)indexで表示位置を指定してきますのでindex(0)でpriceの情報を、index(1)でcolorの情報・index(2)でsizeの情報を返します。

ややこしくなるのですが、ここで返したpriceに対してNSRuleEditorはまたruleEditor:numberOfChildrenForCriterion:withRowType:メソッドを呼び出してきます。今度はpriceに対する述部の数を聞いてくるわけです。priceをcriterion(規準)とした子アイテムの数は、演算子(</=/>)の3つですからここでも3を返します。そしてまた<|=|>に対してruleEditor:child:forCriterion:withRowType:が呼び出され、またまたこれら演算子オブジェクトの情報を返すことになります。そしてもちろん、またまたまた演算子(<)オブジェクトに対してruleEditor:numberOfChildrenForCriterion:withRowType:が呼び出され...ruleEditor:numberOfChildrenForCriterion:withRowType:がゼロ(条件式が右端に到達)するまで呼び出しのループは続くわけです。(ruleEditor:displayValueForCriterion:inRow:はここでは省略していますがやっぱり同じように呼び出されます)

なので、懸案の述部(安い|等しい|高い)と右辺(1000円|1500円)を入れ替えるには数学思考的ツリーから和風ツリーへの変換が必要になります。

上記のように、priceをcriterionとした子アイテムに1000|1500を、1000/1500をcriterionとした子アイテムに</=/>を指定します。問題は、ツリー構造を変更した時、Editorが最終的に正しい条件式(NSPreicateオブジェクト)を作成できるかにあります。NSPredicateEditor(+NSPredicateEditorRowTemplate)ではこの順序を固定的に扱っていて、かつこれをカスタマイズすることができないため最終的に作成すべき条件式が正しく生成できませんでした。

そこで、NSRuleEditorのdelegeteメソッドを調べてみるとruleEditor:predicatePartsForCriterion:withDisplayValue:inRowというのがあります。このメソッドでは、

Returns a dictionary representing the parts of the predicate determined by the given criterion and value."

とあるように、条件式を生成するための情報をdictionary形式で返します。パラメタでruleEditor:child:forCriterion:withRowType:で返したdictionary)がcriterionとして与えられますのでその情報をもとにNSPredicateオブジェクト生成のための情報(NSDictionary)を生成して返します。ここでは、Rowに対して順序は関係なくCriterion毎にNSPredicate作成のための条件を問い合わせてくるので表示上の順序からは解放されるはずです!

で、トライ。

googleのサンプルでは、criterionの情報をplistで定義して使っていますのでそいつに倣って和風ツリーのplistを作成、ruleEditor:child:forCriterion:withRowType:ではこのplistをcriterion毎に返します。このとき返す情報(dictionary)はruleEditor:predicatePartsForCriterion:withDisplayValue:inRowでNSPredicateオブジェクト生成のための情報として"Predicate part key"と表示用(ruleEditor:displayValueForCriterion:inRow:メソッドで使用する)の値(サンプルではvaluer)も仕込んであります。これらは基本的にNSExpressionの作成のための情報と一致するはずですが、それほど難しくはないのでサンプルのplistを参照しながら作成すればそれほど難しくはないかと思います。

ここに書いてある以外にも複合条件の扱いなども考慮にいれる必要があるのですが、やりたいことはこれで概ね実装できました。なかなか全体像が掴みにくく自信のない箇所もいくつかある(乞う突っ込み!)のですがとりあえず当初の目的を達したので良しとします\(^o^)/(チカレタ...やりたいことは別にあったのだけれど遠回りしまスた。)

添付サイズ
myRule.zip55.9 KB

この記事のトラックバックURL:

http://hippos-lab.com/blog/trackback/316

返信