カスタムツリービューの基本的な使い方(その4~並び替え)

ツリーカラム(”Name” と表示されている部分)をクリックしたときに、ツリーの表示内容を並び替えする機能を追加する。
ベースとなるソースコードはその1~表示を参照。

3つのソート状態

一般的に、ツリーカラムをクリックするたびに下表に挙げた3通りのソート状態が循環される(例えば「ブックマークの管理」)。
RDF データソースから生成するツリーの場合、treecol 要素の sort 属性へ並び替えのキーとなるプロパティの URI を記述するだけで半自動的に並び替えが可能となるが、カスタムツリービューを使用したツリーの場合、ツリーカラムがクリックされるたびに treecol 要素の sortDirection 属性を変更してツリーカラムの表示を変更し、なおかつ適切な順序で内部的に保持しているデータ自体も並び替えてツリーの表示を更新してやる必要がある。

ソート状態 sortDirection 属性 ツリーカラムの表示
未ソート natural マークなし
昇順 (A – Z) ascending ▽マーク表示
降順 (Z – A) descending △マーク表示

fruits.js

ツリーカラムがクリックされると nsITreeView#cycleHeader メソッドが呼び出される。
引数 col にはクリックしたツリーカラムに対応する nsITreeColumn 型オブジェクトが渡されるので、ここから treecol 要素の sortDirection 属性値を取得し、新しいソート状態へ変更する。実際の並び替え処理は、後述する自前のメソッド sortItems で行う。

    cycleHeader: function(col) {
        // change sort direction
        var sortDir = col.element.getAttribute("sortDirection");
        switch (sortDir) {
            case "ascending" : sortDir = "descending"; break;
            case "descending": sortDir = "natural"   ; break;
            default          : sortDir = "ascending" ; break;
        }
        col.element.setAttribute("sortDirection", sortDir);
        // sort data
        this.sortItems(sortDir);
    },

FruitsTreeView.prototype へ sortItems メソッドを追加する。このメソッドは、引数 aDirection で指定された順序で内部的に保持しているデータ _data を並び替える。
ここで一つ問題があり、配列のデータを昇順なり降順なりで一度並び替えを行ってしまうと、元の順序がわからなくなってしまう。そこで、やむを得ず _originalData として元の順序の配列データをコピーしてバックアップするようにする。最後に、 nsITreeBoxObject.invalidate を呼び出すことでツリーの描画を更新する。

    /**
     * sort items in an order specified as aDirection
     * @param String aDirection "ascending", "descending" or "natural".
     */
    sortItems: function(aDirection) {
        // clone data to backup
        if (!this._originalData)
            this._originalData = this._data.concat();
        switch (aDirection) {
            case "ascending": 
                this._data.sort();
                break;
            case "descending": 
                this._data.sort();
                this._data.reverse();
                break;
            case "natural": 
                // restore from original data
                this._data = this._originalData.concat();
                this._originalData = null;
                break;
        }
        // refresh tree
        this._treeBoxObject.invalidate();
    },

isSorted メソッドの実装

nsITreeView インタフェースにはツリーが現在並び替えされた状態にあるかどうかを示す isSorted メソッドが定義されており、 IDL の説明によればドラッグ&ドロップ時のフィードバック(ドロップ先を示すインジケータ)関連で使用されるらしい。詳細は不明だが、とりあえずこのメソッドを実装してみる。
効率化のために FruitsTreeView へ自前のプロパティ _sorted を追加し、 cycleHeader が呼び出されたタイミングでこれの値を変更する。そうすれば isSorted メソッドは _sorted の値を返すだけでよい。

    _sorted: false,
    isSorted: function() {
        return this._sorted;
    },
    cycleHeader: function(col) {
        
        /* snip */
        
        this._sorted = (sortDir != "natural");
    },

isSorted メソッドの使い道として、並び替えされた状態でのドラッグ&ドロップによるアイテム移動を禁止するといった使い道が考えられる。並び替えされた状態でのドラッグ&ドロップによる移動を許可すると、ややこしいことになるため、ドラッグしようとした際に isSorted で並び替えされた状態かどうかをチェックし、そうであればドラッグを禁止する。

関連記事

TOP

TOP