Revision 96082 of Displaying Places information using views

  • リビジョンの URL スラグ: Displaying_Places_information_using_views
  • リビジョンのタイトル: Displaying Places information using views
  • リビジョンの ID: 96082
  • 作成日:
  • 作成者: saneyuki
  • 現行リビジョン いいえ
  • コメント 382 words added, 1165 words removed

このリビジョンの内容

{{ 翻訳中() }} {{ Firefox3() }}

ビューは、Places model-view-controllerコンポーネントのひとつです。ユーザーに向けて{{ Interface("nsINavHistoryContainerResult") }}オブジェクトを表示するために使用します。  Placesのクエリでは、nsINavHistoryResult オブジェクトについての情報を保持し、使用しています。nsINavHistoryResultオブジェクトの使い方と保持の仕方については、Querying Placesを参照してください。このページでは、既にこれらについて知っているものとして話を進めます。

nsINavHistoryResult インスタンスはビューのデータを提供します。ビューは、このインスタンスの{{ Interface("nsINavHistoryContainerResultNode") }}を展開し、その時点で含んでいる{{ Interface("nsINavHistoryResultNode") }}オブジェクトを表示する機能を持ちます。

組み込みのビュー

もし、あなたの拡張機能やアプリケーションでブックマークまたは履歴の内容を表示する必要がある場合、あなたは組み込みのPlacesビューを使用することができます。それらを使用することで、基礎的な箇所を記述する作業時間を抑え、あなたの拡張機能もしくはアプリケーションの構築に注力することができるでしょう。

Placesでは以下の組み込みのビューが使用できます。

インスタンス化

3つの組み込みビューは、単純かつ標準的なXUL要素に特殊なtype属性の値として"places"を設定します。

いかなるXULドキュメントも、組み込みビューを含む場合、スタイルシート({{ Source("browser/components/places/content/places.css") }})を読み込み、ファイル({{ Source("browser/components/places/content/placesOverlay.xul") }})をオーバーレイさせなければなりません。

<?xml-stylesheet href="chrome://browser/content/places/places.css" ?>
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul" ?>

このスタイルシートが、特殊なtype属性を持った要素に、ビューの一つをバインディングします。オーバーレイはビューによって要求されるJavaScriptを含んでいます。また、組み込みのコンテクストメニュー及びコマンドも含んでおり、ビューを利用する際に、有利な点が得られるかもしれません。

ビューとデータの接続

組み込みビューとデータを接続するために、ビューの特殊なplace属性を使用します。あなたは直接XUL中の属性に値を指定するか、JavaScrptを使用して対応するプロパティに値を設定してください。その値はビューに表示するデータがクエリの結果となるようなクエリのURIにしてください。ビューが終了するまで変更されないような単純なクエリの場合は、XUL中のplace属性に直接指定したほうが良いかもしれません。より複雑なクエリの場合、またはクエリのURIが変わる予定のある場合は、JavaScriptを用いてビューのplaceプロパティに、動的に値を設定したほうが良いでしょう。後者の場合では、要素の属性にsetAttributeを用いて値を設定する手法では十分ではないということを記して起きます。代わりに要素のplaceプロパティを使用してください。クエリURIの情報については、Querying PlacesおよびPlaces query URIsを参照してください。

下記の例では、タイトルまたはURLに"mozilla"を含むブックマークを表示するために、組み込みのツリービューを使用しています。XULはXMLであり、クエリURI中のいかなるアンパサンドも単純な&ではなく、実体参照の&amp;で記述されなければならないということを思い出してください。

<tree type="places" place="place:terms=mozilla&amp;onlyBookmarked=1&amp;queryType=1">
  <treecols>
    <treecol id="title" label="My Bookmarks" flex="1" primary="true" />
  </treecols>
  <treechildren />
</tree>

次の例では、最終的な表示は同じですが、JavaScriptを用いてツリーのplace属性の値を設定しています。

var histServ =
  Cc["@mozilla.org/browser/nav-history-service;1"].
  getService(Ci.nsINavHistoryService);

var query = histServ.getNewQuery();
query.searchTerms = "mozilla";
query.onlyBookmarked = true;

var opts = histServ.getNewQueryOptions();
opts.queryType = opts.QUERY_TYPE_BOOKMARKS;

var uri = histServ.queriesToQueryString([query], 1, opts);
var tree = document.getElementById("mytree");
tree.place = uri;

これら2つの例では組み込みのツリービューを使用していますが、重要なのはplace属性とplaceプロパティの使用についての実演という点です。組み込みのメニューやツールバーにおいても違いはないと考えてください。

基本的なデータの変更のとき、ビューは自動で更新され、新たなデータを表示します。この更新は、論理的なビューと結果の違いによって処理されます。すべてのPlacesビューの部品、または{{ Interface("nsINavHistoryResultViewer") }}インターフェイスのインスタンスにおいて、ビューと結果の間には相互作用する点が存在します。検索結果はPlacesの変更を受け取り、もしPlacesの変更がデータの明確な変更がなされたと確定された検索結果は、nsINavHistoryResultViewerの適切なメソッドによってビューに通知されます。通知を受けると、ビューは自身を更新します。

ツリービュー

 ツリー要素のtype属性に"places"が設定されることによって組み込みのツリービューは生成されます。treechildrenは空要素にしてください。

<tree type="places">
  <treecols>
    <treecol id="title" flex="1" primary="true" />
    <treecol id="url" flex="1" />
  </treecols>
  <treechildren />
</tree>

ツリービューは{{ Source("browser/components/places/content/tree.xml") }}で実装されています。ツリーについての一般的な情報は、treeリファレンスと、Treesチュートリアルを参照してください。

もし、あなたのツリービューに、Firefoxにおいて通常使われているスタイルを適用したい場合は、以下のスタイルシートを読み込ませてください。注意点として、このスタイルシートは上述の、組み込みのPlacesビューに読み込まれたものとは違います。下記のスタイルシートはオプションであり、スタイルとアイコンは、組み込みのツリービューにしか適用されません。

<?xml-stylesheet href="chrome://browser/skin/places/places.css" ?>

XULというよりも、JavaScriptによるツリービューのインスタンス化の例は、Programmatic generation of the built-in tree viewを参照してください。

列のバインディング

組み込みのツリービューでは、treecol要素のid属性に特定の値を設定することによって、検索結果の特定のプロパティと、ツリービューの特定の列の接続を行えます。検索結果のプロパティは、列のid属性によって、列と結び付けられています。例えば、列のidを"title"に設定すると、列中のどの行もnsINavHistoryResultNode  のtitleプロパティを表示します。

下記の表は、列のidと値が、{{ Interface("nsINavHistoryResultNode") }}のプロパティのどれに関連付けられているかを示しています。

treecol id または anonid 対応する nsINavHistoryResultNode プロパティ
title title
url
uri
date
time
visitCount
accessCount
keyword *
description *
dateAdded
dateAdded
lastModified
lastModified
tags
tags
** icon

*keyword とdescriptionは、nsINavHistoryResultNode のitemIdプロパティを用いてPlacesデータベースから検索されます。

**title列は自動的に nsINavHistoryResultNode iconプロパティによって参照されているfaviconを受け取ります。(ただしtitle列に限ります)

あなたのツリーが、十分な数の列を持っているならば、複数の列に上記の特殊な値を設定することも可能です。また、treecolid属性を設定する代わりに、anonid 属性を設定することも可能です。anonid属性の設定は、id属性を別の目的に使用するとき、またはtreecolが、XBLなどによる匿名コンテンツを含む場合に役立ちます。id属性とanonid属性の両方を指定した場合、anonid属性が使用されます。

組み込みのツリービューは、一般的な使用の範囲においては便利な機能を提供しています。もし追加のデータを表示したい、またはビュー上において別の操作方法を必要とする場合は、あなた自身の手で実装を行う必要があります。下記のカスタムビューの作成を参照してください 。

ツリービューの使い方

組み込みのツリービューの使用の準備ができました。どうやって表示されるデータを扱うのでしょうか?

はじめに、{{ Interface("nsIPlacesView") }}を参照してください。全てのPlacesビューと同様に、組み込みのツリービューもこのインターフェイスを実装しており、ビューの{{ Interface("nsINavHistoryResult") }}インスタンスを取得し、ビューの選択部を調べるための幅広い手段を提供しています。

第2に、ツリーについて話す場合において、"view"とは多くの意味を持つ言葉であるということを知っておいてください。この文書では、Placesビューについて述べています。 上で述べたように、組み込みのPlacesツリービューは、type属性に"places"が設定されたtree要素なのです。しかし、Placesビューであるかどうかに関わらず、全てのツリーは、nsITreeViewを使用して、それぞれのデータを表示しているということを思い出してください。そのため組み込みのPlacesツリービューは、viewの値に自分自身を持ちます。このビューは、{{ Interface("nsINavHistoryResultTreeViewer") }}、{{ Interface("nsINavHistoryResultViewer") }}、そして {{ Interface("nsITreeView") }}といった3つのインターフェイスを実装したオブジェクトです。nsINavHistoryResultTreeViewerはそれぞれの行のindexと、それぞれの列内のnsINavHistoryResultNodeを配置します。nsINavHistoryResultViewer は根本的なデータの変更があった際に、ビューを更新します。ですが、ここでの私たちの目的としてはあまり便利ではありません。一般的に、ツリーにおいての高レベルのインターフェイスは、nsITreeViewが提供しています。

そして、組み込みのツリービューは、便利なメソッドプロパティを実装しています。

そのため、組み込みのPlacesビューでは、相互に作用する4通りの手段が存在します。

  1. ビュー自身に直接実装された便利なメソッドプロパティ
  2. ビュー自身の{{ Interface("nsIPlacesView") }}インターフェイス。
  3. ビューがviewに持つ、{{ Interface("nsINavHistoryResultTreeViewer") }}インターフェイス。
  4. ビューがviewに持つ、{{ Interface("nsITreeView") }} インターフェイス。

nsITreeView によって提供されているインターフェイスは非常に一般的なものであるのですが、ビューに直接実装されたメソッドとプロパティは非常に特殊なものです。時々、相互に作用する4つの手段のうち、主に使用している手段とは別の手段を使用することが必要となることがあります。

JavaScriptでは以下のように、あなたのPlacesツリービューを参照するためにtreeViewという名前の変数を宣言してください。

var treeView = document.getElementById("myPlacesTreeView");

手段1と手段2が、この変数に対して適用できます。

ツリービューのviewは、treeView.viewが持っているオブジェクトです。手段3と手段4をこのオブジェクトに適用できます。

var treeViewView = treeView.view;

便利なメソッド

組み込みのツリービューは幅広く使用されるものの複雑であるので、よく使われる処理を簡単に記述するために、いくつかの便利なメソッドがツリービューに直接実装されています。

警告: {{ Bug("476952") }} が修正されるまでは、 place属性やplaceプロパティと併用して、これらのメソッドを使用することによって問題が発生するかもしれません。
applyFilter()

特定の検索条件とフォルダに合致した新規クエリを読み込みます。

void applyFilter(
  string filterString,
  array folderRestrict
);
パラメータ
filterString
新規クエリのsearchTermsプロパティに設定される文字列。
folderRestrict
フォルダIDの配列に基づき、新規クエリのsetFolders関数が呼び出されます。省略可。
load()

ビューの表示のクエリを設定します。このメソッドは上で述べられているツリーのplaceプロパティを設定するための代わりの手段としても使われます。

void load(
  array queries,
  nsINavHistoryQueryOptions options
);
パラメータ
queries
{{ Interface("nsINavHistoryQuery") }} オブジェクトの配列。
options
{{ Interface("nsINavHistoryQueryOptions") }} オブジェクト。
selectItems()

与えられたアイテムIDのそれぞれに合致した、ツリー中の最初のノードを選択します。選択されたアイテムを表示する必要があるため、選択されたアイテムの親ノードを展開します。

void selectItems(
  array aIDs,
  array aOpenContainers
);
パラメータ
aIDs
アイテムIDの配列。
aOpenContainers
真または未定義の場合、閉じられたフォルダも同様に検索されます。そうでない場合、閉じられたフォルダは検索されません。省略可。
selectNode()

ツリー中で選択された特定のノードの祖先である全てのコンテナが展開され、選択されたノードが見えるようになります。

void selectNode(
  nsINavHistoryNode node
);
パラメータ
node
選択された{{ Interface("nsINavHistoryResultNode") }}。
selectPlaceURI()

ツリー中で、特定のplaceURIに一致するノードが選択され、そのノードの祖先である全てのコンテナが展開されることにより、選択されたノードが見えるようになります。

void selectPlaceURI(
  string placeURI
);
パラメータ
placeURI
選択する{{ Interface("nsINavHistoryResultNode") }}のURI(文字列型)。

 

便利なプロパティ

上述のメソッドのように、いくつかの便利なプロパティが組み込みのツリービューに直接実装されています。

警告: {{ Bug("476952") }} が修正されるまでは、 place属 性やplaceプロパティと併用して、これらのメソッドを使用することによって問題が発生するかもしれません。
プロパティ 詳細
flatList boolean If true the view does not recurse into containers. The action to take when a container is toggled can be set via the onOpenFlatContainer property. At least one of flatList and showRoot must be false.
onOpenFlatContainer string The body of function that will be called when a container is toggled. Only applies if property flatList is true. The function will be passed one {{ Interface("nsINavHistoryResultNode") }} argument named aContainer. You can QueryInterface aContainer to an {{ Interface("nsINavHistoryContainerResultNode") }}.
showRoot boolean If true the root {{ Interface("nsINavHistoryContainerResultNode") }} is shown as the first row in the tree. At least one of showRoot and flatList must be false.

使用例

特定の行の{{ Interface("nsINavHistoryResultNode") }}を取得する。

var treeView = document.getElementById("myPlacesTreeView");
var rowIndex = 0;
var historyResultNode = treeView.view.nodeForTreeIndex(rowIndex);

特定の nsINavHistoryResultNodeの行のindexを取得する。

var treeView = document.getElementById("myPlacesTreeView"); 
var rowIndex = treeView.view.treeIndexForNode(historyResultNode);

ツリー中で特定のURIを持つ行を選択する。

var treeView = document.getElementById("myPlacesTreeView");
treeView.selectPlaceURI("some place URI");

ツリー中で特定のnsINavHistoryResultNodeを含む列を選択する。

var treeView = document.getElementById("myPlacesTreeView");
treeView.selectNode(someHistoryResultNode); 

Placesツリービュー

註: この節では、Placesツリービューの実装の方法について述べています。

組み込みツリービューの実態はPlacesTreeViewのインスタンスであり、プロトタイプは{{ Source("browser/components/places/content/treeView.js") }}で定義されています。PlacesTreeViewの挙動は組み込みツリービューにおいて、{{ Interface("nsITreeView") }}、及びPlacesビューに必要な機能の多くを実装するという2つの機能をなします。後者においては、具体的には{{ Interface("nsINavHistoryResultViewer") }}を継承したnsINavHistoryRe{{ Interface("nsINavHistoryResultTreeViewer") }}sultTreeViewerが実装されています。

以下のようにPlacesTreeViewが2つの機能をなすために、検索結果とツリー要素の表示のブリッジを可能としています。

var result = historyService.executeQuery(query, opts); // あなたのPlaces検索クエリ
var tree = document.getElementById("mytree");          // あなたのツリー要素

var showRootNodeInTree = true;
var view = new PlacesTreeView(showRootNodeInTree);

// ブリッジを行う
result.viewer = view.QueryInterface(Components.interfaces.nsINavHistoryResultViewer);
tree.view = view.QueryInterface(Components.interfaces.nsITreeView);

実際に、組み込みツリービューはこのように機能しています。上で述べたように、placeプロパティを設定したり、loadメソッドを呼び出した際も同様に機能しています。

ツリービューをあなた自身によって実装する場合は自由であるのですが、組み込みツリービューを使用する場合において、place属性の使用はあまり推奨されません。place属性はビューの更新を回避してしまい、ビューの検索結果との同期に失敗する原因となってします。そのかわりにビューのloadメソッドもしくはplaceプロパティを使用するようにしてください。もし、カスタムツリービューをあなた自身の手で実装した場合、いくつかの点で似たようなコードを記述する必要があります。

(いくつかのmenu要素の子孫である)空のmenupopup要素のtype属性に"places"という値を設定することで、組み込みメニュービューは生成されます。

<menu>
  <menupopup type="places" />
</menu>

place属性またはplaceプロパティは、menupopup要素に設定してください。

メニュービューは{{ Source("browser/components/places/content/menu.xml") }}で実装されています。メニューについての一般的な情報はmenupopupmenuのリファレンス及びPopup Menusチュートリアルを参照してください。

ツールバービュー

toolbar要素の子孫であるいくつかのtoolbaritem要素の子孫である)空のhbox要素のtype属性に"places"という値を設定することで、組み込みツールバービューは生成されます。

<toolbar>
  <toolbaritem>
    <hbox type="places" />
  </toolbaritem>
</toolbar>

place属性またはplaceプロパティは、hbox要素に設定してください。

ツールバービューは{{ Source("browser/components/places/content/toolbar.xml") }}で実装されています。ツールバーについての一般的な情報はtoolbaritemtoolbarのリファレンス及びToolbarsチュートリアルを参照してください。

ビューの使い方

Placesビューの使用の準備ができました。どうやって使用するのでしょうか?

複雑であるため、組み込みツリービューは簡単に捜査できるように特別なインターフェイスを提供しています。もし、あなた自身の手で複雑なビューを実装した場合、似たようなインターフェイスも実装しているかもしれません。

ですが、矛盾無く一般的な捜査を行えるように全てのPlacesビューが最低限のインターフェイスを提供するべきです。この理由から、{{ Interface("nsIPlacesView") }}インターフェイスは実装されています。ビューを表示し、選択したノードを実行する{{ Interface("nsINavHistoryResult") }} インスタンスを取得すると言ったことが可能です。事実、上で述べらていた特殊なplaceプロパティは、このインターフェイスのプロパティです。

カスタムビューの作成

もし、提供されている組み込みビュー以上の柔軟性を必要をする場合、カスタムビューの作成が可能です。カスタムビューを必要とする場合は以下のようなものです。(もちろん、これだけに限定されるわけではありませんが)

  • 組み込みビューによって提供されるカラムのとなりに、独自のカラムを表示したい。
  • 組み込みビューによる、日付や他のデータのデータの表示方法を変更したい。
  • 基底部データに定義されていない情報の表示をしたい。
  • 組み込みのビューで提供されていない要素にって、Placesの情報を表示したい。

潜在的に悪い理由として、カスタムビューが推奨されないのは以下の場合です。(これもまた、これだけに限定されるわけではありませんが)

  • 新たなコンテンツを表示するというよりも、組み込みビューの表面的な外見を変更したい場合。CSSを適用してください。
  • 組み込みツリービューの列を隠したい場合。treecol要素を除外してください。
  • クリックやコマンド操作、他のユーザーの操作を受け取ったビューの挙動の管理をしたい場合。この不満を別の問題として捉えないでください。表示されているデータにとってのビューであり、ロジックにとっての操作方法です。あなたは標準的なPlacesのコマンドやコンテクストメニューを組み込みビューに接続したり、独自のコマンドを操作するためのコントローラーの作成が可能です。詳しくは、View Controllerを参照してください。

あなたが書いたビューの種類に関わらず、{{ Interface("nsIPlacesView") }}インターフェイスを実装してください。(現在、nsIPlacesViewは実際にはインターフェイスではありません。組み込みビューは単純に、メソッド及び属性を直接実装しています) 上述されたビューの使い方のとおり、このインターフェイスは、ビューを扱う一般的な方法に矛盾しないコントローラや呼び出しを提供します。

あなたのビューにおいては、同様の実装を行うか、ビューを{{ Interface("nsINavHistoryResultViewer") }}のインスタンスとして保持してください。あなたのビューと{{ Interface("nsINavHistoryResult") }}オブジェクトを接続するため、nsINavHistoryResultViewerのインスタンスであるオブジェクトのviewerプロパティを設定してください。もし、あなたのビューがnsINavHistoryResultViewerを実装しているのであれば、viewerプロパティにビュー自身を設定できます。代わりに、もしあなたのビューがnsINavHistoryResultViewerのインスタンスを内部的に持つのであれば、そのインスタンスをviewerプロパティに設定してください。(3種類の組み込みビューもこの方法をとっています) 表示する結果のオブジェクトはこのインスタンスによって、あなたのビューと連絡を取り、基底データ変更の通知を受けた場合に表示を更新するのです。

var bmServ =
    Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"].
    getService(Components.interfaces.nsINavBookmarksService);
var histServ =
  Components.classes["@mozilla.org/browser/nav-history-service;1"].
  getService(Components.interfaces.nsINavHistoryService);

var opts = histServ.getNewQueryOptions();
var query = histServ.getNewQuery();
query.setFolders([bmServ.placesRoot], 1);
var result = histServ.executeQuery(query, opts);

// Here myView is your view, and myView.viewer is some object implementing nsINavHistoryResultViewer.
// このmyViewとはあなたのviewです。そしてmyView.viewerはnsINavHistoryResultViewerを実装したオブジェクトです。
result.viewer = myView.viewer;

より本質的な意味において、上述したコードは、あなたのビューのメソッドへと送信されます。呼び出し元は検索結果または検索クエリを通過させ、あなたは検索クエリを実行し、あなたのresultオブジェクトのviewerプロパティに設定します。(組み込みツリービューのloadメソッドでの処理の手法です) 同様に、あなたのビューのplaceプロパティの設定は、クエリURIから結果を生成し、resultオブジェクトのviewerプロパティに設定しているのです。

nsINavHistoryResultviewerプロパティを設定したとき、結果は与えられたnsINavHistoryResultViewerresultプロパティに設定されます。あなたはresultプロパティを明確に設定するべきではありません。nsINavHistoryResultviewerプロパティにnullを設定したことで、結果とビューが接続できなくなります。これは、nsINavHistoryResultViewerresultプロパティにnullが設定されることによって引き起こされます。

循環参照に注意してください。ビューと結果は、両方とも互いへの参照を持ちます。JavaScriptのガベージコレクションによってこれらのオブジェクトが解放されるためには、result.viewerをnullに設定することによって、この循環を消去しなければなりません。(例えば、組み込みツリービューでは自動的にこの作業を行っています。ツリーが破棄された、または別の{{ Interface("nsITreeView") }}とツリーが関連付けられた場合、ツリーは古い方のnsITreeViewtreeプロパティをnullに設定します。なぜなら、nsITreeViewを実装したオブジェクトは、nsINavHistoryResultViewerも実装しているため、resultオブジェクトのviewerプロパティをnullに設定することによって、resultオブジェクトから自身を非接続状態になるのです)

カスタムツリービューの作成

カスタムPlacesツリービューは多くのことができます。要求するアイディアを得るには、上述のツリービューの使い方を参照してください。一般的に、カスタムnsITreeView
多くの作業を要します。カスタムnsITreeViewにに慣れ親しんでいない場合は、XULチュートリアルのCustom Tree ViewsTree View Detailsのページを参照してください。ここには関連情報について述べます。

幸運にも、あなたの目的に合致した組み込みツリービューの一部を拝借することが可能です。組み込みビューであるPlacesTreeViewの実態であるJavaScriptプロトタイプは、特に役立つ{{ Interface("nsINavHistoryResultTreeViewer") }}、{{ Interface("nsINavHistoryResultViewer") }}、{{ Interface("nsITreeView") }}の3種を実装しています。そのため、非カスタム機能と退屈な作業を肩代わりさせるために、PlacesTreeView上にあなたのカスタム機能を実装することができます。ひとつの方策としては、カスタム機能を提供するオブジェクトにこれらのインターフェイスを全て実装して、これらカスタムされた振る舞いを全てサポートすることで、カスタムオブジェクトをPlacesTreeViewのインスタンスに偽装するというものがあります。ですが、おそらくより簡単な方策としては、下記のサンプルのように、既に存在するPlacesTreeViewインスタンスを修正するものがあります。

下記のJavaScriptでは、新たにPlacesTreeViewインスタンスを作成していますが、組み込みツリービューに表示されていない列を表示するために、nsITreeViewのメソッドを二つ上書きしています。

var view = new PlacesTreeView();

view._getCellText = view.getCellText;
view.getCellText = function (aRowIndex, aCol) {
  // 特殊な列を操作する。PlacesTreeViewとして、列のidまたはanonidを認識する。
  switch (aCol.id || aCol.element.getAttribute("anonid"))
  {
  // (ブックマークのような)URIノードでなく、(フォルダのような)すべてのノードのURI
  case "fullURI":
    return this.nodeForTreeIndex(aRowIndex).uri;
    break;
  // 親コンテナ内でのノードのindex
  case "indexInParent":
    return this.nodeForTreeIndex(aRowIndex).bookmarkIndex;
    break;
  // 偶数列かそれとも奇数列か
  case "parity":
    return (aRowIndex % 2 === 0 ? "even" : "odd");
    break;
  }
  // そうでない場合、オリジナルのgetCellTextメソッドに偽装する
  return this._getCellText(aRowIndex, aCol);
};

view._cycleHeader = view.cycleHeader;
view.cycleHeader = function (aCol) {
  switch (aCol.id || aCol.element.getAttribute("anonid"))
  {
  case "fullURI":
  case "indexInParent":
  case "parity":
    // ここで列のサイソートが可能
    break;
  default:
    this._cycleHeader(aCol);
    break;
  }
};

// クエリの実行と検索結果の取得
var bmServ =
    Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"].
    getService(Components.interfaces.nsINavBookmarksService);
var histServ =
  Components.classes["@mozilla.org/browser/nav-history-service;1"].
  getService(Components.interfaces.nsINavHistoryService);
var opts = histServ.getNewQueryOptions();
var query = histServ.getNewQuery();
query.setFolders([bmServ.placesRoot], 1);
var result = histServ.executeQuery(query, opts);

// result's viewerとカスタムビューのツリーのnsITreeViewの接続
var treeView = document.getElementById("myTreeView");
result.viewer = view;
treeView.view = view;

下記のXULでは、JavaScript中から参照されmyTreeView要素を定義しています。

<tree id="myTreeView" flex="1">
  <treecols>
    <treecol id="title" label="title" flex="1" primary="true" />
    <splitter class="tree-splitter" />
    <treecol anonid="fullURI" label="fullURI" flex="1" />
    <splitter class="tree-splitter" />
    <treecol id="indexInParent" label="indexInParent" />
    <splitter class="tree-splitter" />
    <treecol id="parity" label="parity" />
  </treecols>
  <treechildren />
</tree>

このページ下部のファイルの項目に、コードの全文が挙げられています。

上記のツリー要素には、組み込みビューの際の特殊なtype属性を持たないことを注記しておきます。上記のツリーは、あなたがPlacesクエリと接続した通常のツリーであって、組み込みツリービューのような便利なプロパティメソッドは存在しません。もし、カスタムビューがあなたのアプリケーションにおいてのみ使用されるのであれば、コードは上述したようなもので十分でしょう。上記のコードでは、PlacesTreeViewオブジェクトを1つ作成し、修正を加え、通常のツリーに組み込むのに十分です。しかしながらもし、あなたのビューが幅広く使われるのであれば、組み込みビューを見習ってPlacesTreeViewに似通ったJavaScriptプロトタイプとXBLツリーバインディングを作成し、ビューと表示と接続作成に多くの作業を費やすことになるでしょう。

nsINavHistoryResultNode.viewIndex属性は、ビューを使用することによって、明白に提供されます。この値は、それぞれのノードが生成されたときは-1に初期化されています。あなたは、この値を可視ノードの追跡を保存するためにこの値を使用します。PlacesTreeViewは、列中で有効になっているノードのindexを保存するために、この値を使用します。

関連記事

{{ languages( { "en": "en/Displaying_Places_information_using_views" } ) }}

このリビジョンのソースコード

<p>{{ 翻訳中() }} {{ Firefox3() }}</p>
<p>ビューは、Places <a class="external" href="http://ja.wikipedia.org/wiki/Model_View_Controller" title="http://ja.wikipedia.org/wiki/Model_View_Controller">model-view-controller</a>コンポーネントのひとつです。ユーザーに向けて{{ Interface("nsINavHistoryContainerResult") }}オブジェクトを表示するために使用します。  Placesのクエリでは、<code>nsINavHistoryResult </code>オブジェクトについての情報を保持し、使用しています。<code>nsINavHistoryResultオブジェクトの使い方と保持の仕方については、</code><a class="internal" href="/ja/Querying_Places" title="ja/Querying
Places">Querying Places</a>を参照してください。このページでは<span style="font-family: monospace;">、既にこれら</span><code>について知っているものとして話を進めます。</code></p>
<p><code>nsINavHistoryResult </code>インスタンスはビューのデータを提供します。ビューは、このインスタンスの{{ Interface("nsINavHistoryContainerResultNode") }}を展開し、その時点で含んでいる{{ Interface("nsINavHistoryResultNode") }}オブジェクトを表示する機能を持ちます。</p>
<h2 name="The_built-in_views">組み込みのビュー</h2>
<p>もし、あなたの拡張機能やアプリケーションでブックマークまたは履歴の内容を表示する必要がある場合、あなたは組み込みのPlacesビューを使用することができます。それらを使用することで、基礎的な箇所を記述する作業時間を抑え、あなたの拡張機能もしくはアプリケーションの構築に注力することができるでしょう。</p>
<p>Placesでは以下の組み込みのビューが使用できます。</p>
<ul> <li><a href="#Tree_view">ツリー</a></li> <li><a href="#Menu_view">メニュー</a></li> <li><a href="#Toolbar_view">ツールバー</a></li>
</ul>
<h3 name="Instantiating_in_XUL">インスタンス化</h3>
<p>3つの組み込みビューは、単純かつ標準的なXUL要素に特殊な<code>type</code>属性の値として"places"を設定します。</p>
<p>いかなるXULドキュメントも、組み込みビューを含む場合、スタイルシート({{ Source("browser/components/places/content/places.css") }})を読み込み、ファイル({{ Source("browser/components/places/content/placesOverlay.xul") }})をオーバーレイさせなければなりません。</p>
<pre class="brush: xml">&lt;?xml-stylesheet href="chrome://browser/content/places/places.css" ?&gt;
&lt;?xul-overlay href="chrome://browser/content/places/placesOverlay.xul" ?&gt;</pre>
<p>このスタイルシートが、特殊な<code>type</code>属性を持った要素に、ビューの一つをバインディングします。オーバーレイはビューによって要求されるJavaScriptを含んでいます。また、組み込みのコンテクストメニュー及びコマンドも含んでおり、ビューを利用する際に、有利な点が得られるかもしれません。</p>
<h3>ビューとデータの接続</h3>
<p>組み込みビューとデータを接続するために、ビューの特殊な<code>place</code>属性を使用します。あなたは直接XUL中の属性に値を指定するか、JavaScrptを使用して対応するプロパティに値を設定してください。その値はビューに表示するデータがクエリの結果となるようなクエリのURIにしてください。ビューが終了するまで変更されないような単純なクエリの場合は、XUL中の<code>place</code>属性に直接指定したほうが良いかもしれません。より複雑なクエリの場合、またはクエリのURIが変わる予定のある場合は、JavaScriptを用いてビューの<code>place</code>プロパティに、動的に値を設定したほうが良いでしょう。後者の場合では、要素<span style="font-family: monospace;">の属性に</span><code>setAttribute</code>を用いて値を設定する手法では十分ではないということを記して起きます。代わりに要素の<code>place</code>プロパティを使用してください。クエリURIの情報については、<a class="internal" href="/ja/Querying_Places#Serializing_queries" title="ja/Querying Places">Querying Places</a>および<a class="internal" href="/ja/Places_query_URIs" title="ja/Places query URIs">Places query URIs</a>を参照してください。</p>
<p>下記の例では、タイトルまたはURLに"mozilla"を含むブックマークを表示するために、<a href="#Tree_view">組み込みのツリービュー</a>を使用しています。XULはXMLであり、クエリURI中のいかなるアンパサンドも単純な<code>&amp;</code>ではなく、実体参照の<code>&amp;amp;</code>で記述されなければならないということを思い出してください。</p>
<pre class="brush: xml">&lt;tree type="places" place="place:terms=mozilla&amp;amp;onlyBookmarked=1&amp;amp;queryType=1"&gt;
  &lt;treecols&gt;
    &lt;treecol id="title" label="My Bookmarks" flex="1" primary="true" /&gt;
  &lt;/treecols&gt;
  &lt;treechildren /&gt;
&lt;/tree&gt;
</pre>
<p>次の例では、最終的な表示は同じですが、JavaScriptを用いてツリーの<code>place</code>属性の値を設定しています。</p>
<pre class="brush: js">var histServ =
  Cc["@mozilla.org/browser/nav-history-service;1"].
  getService(Ci.nsINavHistoryService);

var query = histServ.getNewQuery();
query.searchTerms = "mozilla";
query.onlyBookmarked = true;

var opts = histServ.getNewQueryOptions();
opts.queryType = opts.QUERY_TYPE_BOOKMARKS;

var uri = histServ.queriesToQueryString([query], 1, opts);
var tree = document.getElementById("mytree");
tree.place = uri;</pre>
<p>これら2つの例では組み込みのツリービューを使用していますが、重要なのは<code>place</code>属性と<code>place</code>プロパティの使用についての実演という点です。組み込みのメニューやツールバーにおいても違いはないと考えてください。</p>
<p>基本的なデータの変更のとき、ビューは自動で更新され、新たなデータを表示します。この更新は、論理的なビューと結果の違いによって処理されます。すべてのPlacesビューの部品、または{{ Interface("nsINavHistoryResultViewer") }}インターフェイスのインスタンスにおいて、ビューと結果の間には相互作用する点が存在します。検索結果はPlacesの変更を受け取り、もしPlacesの変更がデータの明確な変更がなされたと確定された検索結果は、<code>nsINavHistoryResultViewer</code>の適切なメソッドによってビューに通知されます。通知を受けると、ビューは自身を更新します。</p>
<h3 id="Tree_view">ツリービュー</h3>
<p> ツリー要素の<code>type</code>属性に"places"が設定されることによって組み込みのツリービューは生成されます。<code>treechildren</code>は空要素にしてください。</p>
<pre class="brush: xml">&lt;tree type="places"&gt;
  &lt;treecols&gt;
    &lt;treecol id="title" flex="1" primary="true" /&gt;
    &lt;treecol id="url" flex="1" /&gt;
  &lt;/treecols&gt;
  &lt;treechildren /&gt;
&lt;/tree&gt;
</pre>
<p>ツリービューは{{ Source("browser/components/places/content/tree.xml") }}で実装されています。ツリーについての一般的な情報は、<a class="internal" href="/ja/XUL/tree" title="ja/XUL/Tree">tree</a>リファレンスと、<a class="internal" href="/ja/XUL_Tutorial/Trees" title="ja/XUL
Tutorial/Trees">Trees</a>チュートリアルを参照してください。</p>
<p><span class="lang lang-en">もし、あなたのツリービューに、Firefoxにおいて通常使われているスタイルを適用したい場合は、以下のスタイルシートを読み込ませてください。注意点として、このスタイルシートは</span><span class="lang lang-en"><a href="#Instantiating">上述</a></span><span class="lang lang-en">の、組み込みのPlacesビューに読み込まれたものとは違います。下記のスタイルシートはオプションであり、スタイルとアイコンは、組み込みのツリービューにしか適用されません。</span></p>
<pre class="brush: xml"><span class="lang lang-en">&lt;?xml-stylesheet href="chrome://browser/skin/places/places.css" ?&gt;</span>
</pre>
<p>XULというよりも、JavaScriptによるツリービューのインスタンス化の例は、<a class="internal" href="/ja/Places/Programmatic_generation_of_the_built-in_tree_view" title="ja/Places/Programmatic generation of the built-in tree view">Programmatic generation of the built-in tree view</a>を参照してください。</p>
<h4>列のバインディング</h4>
<p>組み込みのツリービューでは、<code>treecol</code>要素の<code>id</code>属性に特定の値を設定することによって、検索結果の特定のプロパティと、ツリービューの特定の列の接続を行えます。検索結果のプロパティは、列の<code>id</code>属性によって、列と結び付けられています。例えば、列の<code>id</code>を"title"に設定すると、列中のどの行もnsINavHistoryResultNode  のtitleプロパティを表示します。</p>
<p>下記の表は、列の<code>id</code>と値が、{{ Interface("nsINavHistoryResultNode") }}のプロパティのどれに関連付けられているかを示しています。</p>
<table class="standard-table" style="margin-left: 40px;"> <tbody> <tr> <td class="header"><code>treecol</code> <code>id</code> または <code>anonid</code></td> <td class="header">対応する <code>nsINavHistoryResultNode</code> プロパティ</td> </tr> <tr> <td>title</td> <td><code>title</code></td> </tr> <tr> <td>url<code><br> </code></td> <td><code>uri</code></td> </tr> <tr> <td>date<code><br> </code></td> <td><code>time</code></td> </tr> <tr> <td>visitCount<code><br> </code></td> <td><code>accessCount</code></td> </tr> <tr> <td>keyword</td> <td>*</td> </tr> <tr> <td>description</td> <td>*</td> </tr> <tr> <td>dateAdded<code><br> </code></td> <td><code>dateAdded</code></td> </tr> <tr> <td>lastModified<code><br> </code></td> <td><code>lastModified</code></td> </tr> <tr> <td>tags<code><br> </code></td> <td><code>tags</code></td> </tr> <tr> <td>**</td> <td><code>icon</code></td> </tr> </tbody>
</table>
<p style="margin-left: 40px;">*keyword とdescriptionは、<code>nsINavHistoryResultNode</code> の<code>itemId</code>プロパティを用いてPlacesデータベースから検索されます。</p>
<p style="margin-left: 40px;">**title列は自動的に <code>nsINavHistoryResultNode </code>の <code>icon</code>プロパティによって参照されているfaviconを受け取ります。(ただしtitle列に限ります)</p>
<p>あなたのツリーが、十分な数の列を持っているならば、複数の列に上記の特殊な値を設定することも可能です。また、<code>treecol</code>に<code>id</code>属性を設定する代わりに、<code>anonid </code>属性を設定することも可能です。<code>anonid</code>属性の設定は、<code>id</code>属性を別の目的に使用するとき、または<code>treecol</code>が、<a class="internal" href="/ja/XBL" title="ja/XBL">XBL</a>などによる匿名コンテンツを含む場合に役立ちます。<code>id</code>属性と<code>anonid</code>属性の両方を指定した場合、<code>anonid</code>属性が使用されます。</p>
<p>組み込みのツリービューは、一般的な使用の範囲においては便利な機能を提供しています。もし追加のデータを表示したい、またはビュー上において別の操作方法を必要とする場合は、あなた自身の手で実装を行う必要があります。下記の<a href="#Creating_custom_views">カスタムビューの作成</a>を参照してください 。</p>
<h4>ツリービューの使い方</h4>
<p>組み込みのツリービューの使用の準備ができました。どうやって表示されるデータを扱うのでしょうか?</p>
<p>はじめに、{{ Interface("nsIPlacesView") }}を参照してください。全てのPlacesビューと同様に、組み込みのツリービューもこのインターフェイスを実装しており、ビューの{{ Interface("nsINavHistoryResult") }}インスタンスを取得し、ビューの選択部を調べるための幅広い手段を提供しています。</p>
<p>第2に、ツリーについて話す場合において、"view"とは多くの意味を持つ言葉であるということを知っておいてください。この文書では、Placesビューについて述べています。 <a href="#Tree_view">上で述べたように</a>、組み込みのPlacesツリービューは、<code>type</code>属性に"places"が設定されたtree要素なのです。しかし、Placesビューであるかどうかに関わらず、全てのツリーは、<span class="lang lang-en"><code><a href="../../../../ja/nsITreeView" rel="internal">nsITreeView</a></code></span>を使用して、それぞれのデータを表示しているということを思い出してください。そのため組み込みのPlacesツリービューは、viewの値に自分自身を持ちます。このビューは、{{ Interface("nsINavHistoryResultTreeViewer") }}、{{ Interface("nsINavHistoryResultViewer") }}、そして {{ Interface("nsITreeView") }}といった3つのインターフェイスを実装したオブジェクトです。<code>nsINavHistoryResultTreeViewer</code>はそれぞれの行のindexと、それぞれの列内の<code>nsINavHistoryResultNode</code>を配置します。<code>nsINavHistoryResultViewer </code>は根本的なデータの変更があった際に、ビューを更新します。ですが、ここでの私たちの目的としてはあまり便利ではありません。一般的に、ツリーにおいての高レベルのインターフェイスは、<code>nsITreeView</code>が提供しています。</p>
<p>そして、組み込みのツリービューは、便利な<a href="#Convenience_methods">メソッド</a>と<a href="#Convenience_properties">プロパティ</a>を実装しています。</p>
<p>そのため、組み込みのPlacesビューでは、相互に作用する4通りの手段が存在します。</p>
<ol> <li>ビュー自身に直接実装された便利な<a href="#Convenience_methods">メソッド</a>と<a href="#Convenience_properties">プロパティ</a>。</li> <li>ビュー自身の{{ Interface("nsIPlacesView") }}インターフェイス。</li> <li>ビューがviewに持つ、{{ Interface("nsINavHistoryResultTreeViewer") }}インターフェイス。</li> <li>ビューがviewに持つ、{{ Interface("nsITreeView") }} インターフェイス。</li>
</ol>
<p><code>nsITreeView</code> <code><span style="font-family: Verdana,Tahoma,sans-serif;">によって提供されているインターフェイスは非常に一般的なものであるのですが、ビューに直接実装されたメソッドとプロパティは非常に特殊なものです。時々、相互に作用する4つの手段のうち、主に使用している手段とは別の手段を使用することが必要となることがあります。</span></code></p>
<p>JavaScriptでは以下のように、あなたのPlacesツリービューを参照するために<code>treeView</code>という名前の変数を宣言してください。</p>
<pre class="brush: js">var treeView = document.getElementById("myPlacesTreeView");
</pre>
<p>手段1と手段2が、この変数に対して適用できます。</p>
<p>ツリービューのviewは、<code>treeView.view</code>が持っているオブジェクトです。手段3と手段4をこのオブジェクトに適用できます。</p>
<pre class="brush: js">var treeViewView = treeView.view;
</pre>
<h4>便利なメソッド</h4>
<p>組み込みのツリービューは幅広く使用されるものの複雑であるので、よく使われる処理を簡単に記述するために、いくつかの便利なメソッドがツリービューに直接実装されています。</p>
<div class="warning"><strong>警告:</strong> {{ Bug("476952") }} が修正されるまでは、 <code>place</code>属性や<code>place</code>プロパティと併用して、これらのメソッドを使用することによって問題が発生するかもしれません。</div>
<h5>applyFilter()</h5>
<p>特定の検索条件とフォルダに合致した新規クエリを読み込みます。</p>
<pre>void applyFilter(
  string filterString,
  array folderRestrict
);
</pre>
<h6>パラメータ</h6>
<dl> <dt><code>filterString</code></dt> <dd>新規クエリの<code>searchTerms</code>プロパティに設定される文字列。</dd> <dt><code>folderRestrict</code></dt> <dd>フォルダIDの配列に基づき、新規クエリの<code>setFolders</code>関数が呼び出されます。省略可。</dd>
</dl>
<h5>load()</h5>
<p>ビューの表示のクエリを設定します。このメソッドは上で述べられているツリーの<code>place</code>プロパティを設定するための代わりの手段としても使われます。</p>
<pre>void load(
  array queries,
  nsINavHistoryQueryOptions options
);
</pre>
<h6>パラメータ</h6>
<dl> <dt><code>queries</code></dt> <dd>{{ Interface("nsINavHistoryQuery") }} オブジェクトの配列。</dd> <dt><code>options</code></dt> <dd>{{ Interface("nsINavHistoryQueryOptions") }} オブジェクト。</dd>
</dl>
<h5>selectItems()</h5>
<p>与えられたアイテムIDのそれぞれに合致した、ツリー中の最初のノードを選択します。選択されたアイテムを表示する必要があるため、選択されたアイテムの親ノードを展開します。</p>
<pre>void selectItems(
  array aIDs,
  array aOpenContainers
);
</pre>
<h6>パラメータ</h6>
<dl> <dt><code>aIDs</code></dt> <dd>アイテムIDの配列。</dd> <dt><code>aOpenContainers</code></dt> <dd>真または未定義の場合、閉じられたフォルダも同様に検索されます。そうでない場合、閉じられたフォルダは検索されません。省略可。</dd>
</dl>
<h5>selectNode()</h5>
<p>ツリー中で選択された特定のノードの祖先である全てのコンテナが展開され、選択されたノードが見えるようになります。</p>
<pre>void selectNode(
  nsINavHistoryNode node
);
</pre>
<h6>パラメータ</h6>
<dl> <dt><code>node</code></dt> <dd>選択された{{ Interface("nsINavHistoryResultNode") }}。</dd>
</dl>
<h5>selectPlaceURI()</h5>
<p>ツリー中で、特定のplaceURIに一致するノードが選択され、そのノードの祖先である全てのコンテナが展開されることにより、選択されたノードが見えるようになります。</p>
<pre>void selectPlaceURI(
  string placeURI
);
</pre>
<h6>パラメータ</h6>
<dl> <dt><code>placeURI</code></dt> <dd>選択する{{ Interface("nsINavHistoryResultNode") }}のURI(文字列型)。</dd>
</dl>
<p> </p>
<h4>便利なプロパティ</h4>
<p>上述のメソッドのように、いくつかの便利なプロパティが組み込みのツリービューに直接実装されています。</p>
<div class="warning"><strong>警告:</strong> {{ Bug("476952") }} が修正されるまでは、 <code>place</code>属 性や<code>place</code>プロパティと併用して、これらのメソッドを使用することによって問題が発生するかもしれません。</div>
<table class="standard-table"> <tbody> <tr> <td class="header">プロパティ</td> <td class="header">型</td> <td class="header">詳細</td> </tr> <tr> <td><code>flatList</code></td> <td><code>boolean</code></td> <td>If true the view does not recurse into containers. The action to take when a container is toggled can be set via the <code>onOpenFlatContainer</code> property. At least one of <code>flatList</code> and <code>showRoot</code> must be false.</td> </tr> <tr> <td><code>onOpenFlatContainer</code></td> <td><code>string</code></td> <td>The body of function that will be called when a container is toggled. Only applies if property <code>flatList</code> is true. The function will be passed one {{ Interface("nsINavHistoryResultNode") }} argument named <code>aContainer</code>. You can QueryInterface <code>aContainer</code> to an {{ Interface("nsINavHistoryContainerResultNode") }}.</td> </tr> <tr> <td><code>showRoot</code></td> <td><code>boolean</code></td> <td>If true the root {{ Interface("nsINavHistoryContainerResultNode") }} is shown as the first row in the tree. At least one of <code>showRoot</code> and <code>flatList</code> must be false.</td> </tr> </tbody>
</table>
<h4>使用例</h4>
<p>特定の行の{{ Interface("nsINavHistoryResultNode") }}を取得する。</p>
<pre class="brush: js">var treeView = document.getElementById("myPlacesTreeView");
var rowIndex = 0;
var historyResultNode = treeView.view.nodeForTreeIndex(rowIndex);</pre>
<p>特定の <code>nsINavHistoryResultNode</code>の行のindexを取得する。</p>
<pre class="brush: js"><span><span class="keyword">var</span><span> treeView = document.getElementById(</span><span class="string">"myPlacesTreeView"</span><span>); </span></span>
var rowIndex = treeView.view.treeIndexForNode(historyResultNode);
</pre>
<p>ツリー中で特定のURIを持つ行を選択する。</p>
<pre class="brush: js"><span><span class="keyword">var</span><span> treeView = document.getElementById(</span><span class="string">"myPlacesTreeView"</span><span>);</span></span>
<span><span>treeView.selectPlaceURI("some place URI");</span></span></pre>
<p>ツリー中で特定の<code>nsINavHistoryResultNode</code>を含む列を選択する。</p>
<pre class="brush: js"><span><span class="keyword">var</span><span> treeView = document.getElementById(</span><span class="string">"myPlacesTreeView"</span><span>);</span></span>
<span><span>treeView.selectNode(someHistoryResultNode);</span></span> 
</pre>
<h4>Placesツリービュー</h4>
<div class="note"><strong>註:</strong> この節では、Placesツリービューの実装の方法について述べています。</div>
<p>組み込みツリービューの実態は<code>PlacesTreeView</code>のインスタンスであり、プロトタイプは{{ Source("browser/components/places/content/treeView.js") }}で定義されています。<code>PlacesTreeView</code>の挙動は組み込みツリービューにおいて、{{ Interface("nsITreeView") }}、及びPlacesビューに必要な機能の多くを実装するという2つの機能をなします。後者においては、具体的には{{ Interface("nsINavHistoryResultViewer") }}を継承したnsINavHistoryRe{{ Interface("nsINavHistoryResultTreeViewer") }}sultTreeViewerが実装されています。<br>
<br>
以下のようにPlacesTreeViewが2つの機能をなすために、検索結果とツリー要素の表示のブリッジを可能としています。</p>
<pre class="brush: js">var result = historyService.executeQuery(query, opts); // あなたのPlaces検索クエリ
var tree = document.getElementById("mytree");          // あなたのツリー要素

var showRootNodeInTree = true;
var view = new PlacesTreeView(showRootNodeInTree);

// ブリッジを行う
result.viewer = view.QueryInterface(Components.interfaces.nsINavHistoryResultViewer);
tree.view = view.QueryInterface(Components.interfaces.nsITreeView);
</pre>
<p>実際に、組み込みツリービューはこのように機能しています。上で述べたように、<code>place</code>プロパティを設定したり、<code>load</code>メソッドを呼び出した際も同様に機能しています。</p>
<p>ツリービューをあなた自身によって実装する場合は自由であるのですが、組み込みツリービューを使用する場合において、<code>place</code>属性の使用はあまり推奨されません。<code>place</code>属性はビューの更新を回避してしまい、ビューの検索結果との同期に失敗する原因となってします。そのかわりにビューの<code>load</code>メソッドもしくは<code>place</code>プロパティを使用するようにしてください。もし、<a href="#Creating_custom_views">カスタムツリービュー</a>をあなた自身の手で実装した場合、いくつかの点で似たようなコードを記述する必要があります。</p>
<h3 id="Menu_view">メニュービュー</h3>
<p>(いくつかの<code>menu</code>要素の子孫である)空の<code>menupopup</code>要素の<code>type</code>属性に"places"という値を設定することで、組み込みメニュービューは生成されます。</p>
<pre class="brush: xml">&lt;menu&gt;
  &lt;menupopup type="places" /&gt;
&lt;/menu&gt;
</pre>
<p><code>place</code>属性または<code>place</code>プロパティは、<code>menupopup</code>要素に設定してください。</p>
<p>メニュービューは{{ Source("browser/components/places/content/menu.xml") }}で実装されています。メニューについての一般的な情報は<a class="internal" href="/ja/XUL/menupopup" title="ja/XUL/Menupopup">menupopup</a>と<a class="internal" href="/ja/XUL/menu" title="ja/XUL/Menu">menu</a>のリファレンス及び<a class="internal" href="/ja/XUL_Tutorial/Popup_Menus" title="ja/XUL Tutorial/Popup Menus">Popup Menus</a>チュートリアルを参照してください。</p>
<h3 id="Toolbar_view">ツールバービュー</h3>
<p>(<code>toolbar</code>要素の子孫であるいくつかの<code>toolbaritem</code>要素の子孫である)空の<code>hbox</code>要素の<code>type</code>属性に"places"という値を設定することで、組み込みツールバービューは生成されます。</p>
<pre class="brush: xml">&lt;toolbar&gt;
  &lt;toolbaritem&gt;
    &lt;hbox type="places" /&gt;
  &lt;/toolbaritem&gt;
&lt;/toolbar&gt;
</pre>
<p><code>place</code>属性または<code>place</code>プロパティは、<code>hbox</code>要素に設定してください。</p>
<p>ツールバービューは{{ Source("browser/components/places/content/toolbar.xml") }}で実装されています。ツールバーについての一般的な情報は<a class="internal" href="/ja/XUL/toolbaritem" title="ja/XUL/Toolbaritem">toolbaritem</a>と<a class="internal" href="/ja/XUL/toolbar" title="ja/XUL/Toolbar">toolbar</a>のリファレンス及び<a href="/ja/XUL_Tutorial/Toolbars" title="ja/XUL_Tutorial/Toolbars">Toolbars</a>チュートリアルを参照してください。</p>
<h2>ビューの使い方</h2>
<p>Placesビューの使用の準備ができました。どうやって使用するのでしょうか?</p>
<p>複雑であるため、<a href="/#Using_the_tree_view" title="#Using the tree view">組み込みツリービュー</a>は簡単に捜査できるように特別なインターフェイスを提供しています。もし、あなた自身の手で複雑なビューを実装した場合、似たようなインターフェイスも実装しているかもしれません。</p>
<p>ですが、矛盾無く一般的な捜査を行えるように全てのPlacesビューが最低限のインターフェイスを提供するべきです。この理由から、{{ Interface("nsIPlacesView") }}インターフェイスは実装されています。ビューを表示し、選択したノードを実行する{{ Interface("nsINavHistoryResult") }} インスタンスを取得すると言ったことが可能です。事実、上で述べらていた特殊な<a href="/#Connecting_a_view_to_its_data" title="#Connecting a view to its data"><code>place</code>プロパティ</a>は、このインターフェイスのプロパティです。</p>
<h2 name="Creating_custom_views">カスタムビューの作成</h2>
<p>もし、提供されている組み込みビュー以上の柔軟性を必要をする場合、カスタムビューの作成が可能です。カスタムビューを必要とする場合は以下のようなものです。(もちろん、これだけに限定されるわけではありませんが)</p>
<ul> <li>組み込みビューによって提供されるカラムのとなりに、独自のカラムを表示したい。</li> <li>組み込みビューによる、日付や他のデータのデータの表示方法を変更したい。</li> <li>基底部データに定義されていない情報の表示をしたい。</li> <li>組み込みのビューで提供されていない要素にって、Placesの情報を表示したい。</li>
</ul>
<p>潜在的に悪い理由として、カスタムビューが推奨されないのは以下の場合です。(これもまた、これだけに限定されるわけではありませんが)</p>
<ul> <li>新たなコンテンツを表示するというよりも、組み込みビューの表面的な外見を変更したい場合。CSSを適用してください。</li> <li>組み込みツリービューの列を隠したい場合。<code>treecol</code>要素を除外してください。</li> <li>クリックやコマンド操作、他のユーザーの操作を受け取ったビューの挙動の管理をしたい場合。この不満を別の問題として捉えないでください。表示されているデータにとってのビューであり、ロジックにとっての操作方法です。あなたは標準的なPlacesのコマンドやコンテクストメニューを組み込みビューに接続したり、独自のコマンドを操作するためのコントローラーの作成が可能です。詳しくは、<a class="internal" href="/ja/Places/View_Controller" title="ja/Places/View Controller">View Controller</a>を参照してください。</li>
</ul>
<p>あなたが書いたビューの種類に関わらず、{{ Interface("nsIPlacesView") }}インターフェイスを実装してください。(現在、<code>nsIPlacesView</code>は実際にはインターフェイスではありません。組み込みビューは単純に、メソッド及び属性を直接実装しています) 上述された<a href="/#Using_a_view" title="#Using a view">ビューの使い方</a>のとおり、このインターフェイスは、ビューを扱う一般的な方法に矛盾しないコントローラや呼び出しを提供します。</p>
<p>あなたのビューにおいては、同様の実装を行うか、ビューを{{ Interface("nsINavHistoryResultViewer") }}のインスタンスとして保持してください。あなたのビューと{{ Interface("nsINavHistoryResult") }}オブジェクトを接続するため、<code>nsINavHistoryResultViewer</code>のインスタンスであるオブジェクトの<code>viewer</code>プロパティを設定してください。もし、あなたのビューが<code>nsINavHistoryResultViewer</code>を実装しているのであれば、<code>viewer</code>プロパティにビュー自身を設定できます。代わりに、もしあなたのビューが<code>nsINavHistoryResultViewer</code>のインスタンスを内部的に持つのであれば、そのインスタンスを<code>viewer</code>プロパティに設定してください。(3種類の組み込みビューもこの方法をとっています) 表示する結果のオブジェクトはこのインスタンスによって、あなたのビューと連絡を取り、基底データ変更の通知を受けた場合に表示を更新するのです。</p>
<pre class="brush: js">var bmServ =
    Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"].
    getService(Components.interfaces.nsINavBookmarksService);
var histServ =
  Components.classes["@mozilla.org/browser/nav-history-service;1"].
  getService(Components.interfaces.nsINavHistoryService);

var opts = histServ.getNewQueryOptions();
var query = histServ.getNewQuery();
query.setFolders([bmServ.placesRoot], 1);
var result = histServ.executeQuery(query, opts);

// Here myView is your view, and myView.viewer is some object implementing nsINavHistoryResultViewer.
// このmyViewとはあなたのviewです。そしてmyView.viewerはnsINavHistoryResultViewerを実装したオブジェクトです。
result.viewer = myView.viewer;
</pre>
<p>より本質的な意味において、上述したコードは、あなたのビューのメソッドへと送信されます。呼び出し元は検索結果または検索クエリを通過させ、あなたは検索クエリを実行し、あなたのresultオブジェクトの<code>viewer</code>プロパティに設定します。(組み込みツリービューの<a href="/#load()" title="#load()">loadメソッド</a>での処理の手法です) 同様に、あなたのビューのplaceプロパティの設定は、クエリURIから結果を生成し、resultオブジェクトの<code>viewer</code>プロパティに設定しているのです。</p>
<p><code>nsINavHistoryResult</code>の<code>viewer</code>プロパティを設定したとき、結果は与えられた<code>nsINavHistoryResultViewer</code>の<code>result</code>プロパティに設定されます。<em>あなたは<code>result</code>プロパティを明確に設定するべきではありません。</em><code>nsINavHistoryResult</code>の<code>viewer</code>プロパティにnullを設定したことで、結果とビューが接続できなくなります。これは、<code>nsINavHistoryResultViewer</code>の<code>result</code>プロパティにnullが設定されることによって引き起こされます。</p>
<p>循環参照に注意してください。ビューと結果は、両方とも互いへの参照を持ちます。JavaScriptのガベージコレクションによってこれらのオブジェクトが解放されるためには、<code>result.viewer</code>をnullに設定することによって、この循環を消去しなければなりません。(例えば、組み込みツリービューでは自動的にこの作業を行っています。ツリーが破棄された、または別の{{ Interface("nsITreeView") }}とツリーが関連付けられた場合、ツリーは古い方の<code>nsITreeView</code>の<code>tree</code>プロパティをnullに設定します。なぜなら、<code>nsITreeView</code>を実装したオブジェクトは、<code>nsINavHistoryResultViewer</code>も実装しているため、resultオブジェクトの<code>viewer</code>プロパティをnullに設定することによって、resultオブジェクトから自身を非接続状態になるのです)</p>
<h3>カスタムツリービューの作成</h3>
<p>カスタムPlacesツリービューは多くのことができます。要求するアイディアを得るには、上述の<a href="/#Using_the_tree_view" title="#Using the tree view">ツリービューの使い方</a>を参照してください。一般的に、カスタム<code>nsITreeView</code>は<br>
多くの作業を要します。カスタム<code>nsITreeView</code>にに慣れ親しんでいない場合は、XULチュートリアルの<a class="internal" href="/ja/XUL_Tutorial/Custom_Tree_Views" title="ja/XUL Tutorial/Custom Tree Views">Custom Tree Views</a>と<a class="internal" href="/ja/XUL_Tutorial/Tree_View_Details" title="ja/XUL Tutorial/Tree View Details">Tree View Details</a>のページを参照してください。ここには関連情報について述べます。</p>
<p>幸運にも、あなたの目的に合致した組み込みツリービューの一部を拝借することが可能です。組み込みビューである<a href="#PlacesTreeView"><code>PlacesTreeView</code></a>の実態であるJavaScriptプロトタイプは、特に役立つ{{ Interface("nsINavHistoryResultTreeViewer") }}、{{ Interface("nsINavHistoryResultViewer") }}、{{ Interface("nsITreeView") }}の3種を実装しています。そのため、非カスタム機能と退屈な作業を肩代わりさせるために、<code>PlacesTreeView</code>上にあなたのカスタム機能を実装することができます。ひとつの方策としては、カスタム機能を提供するオブジェクトにこれらのインターフェイスを全て実装して、これらカスタムされた振る舞いを全てサポートすることで、カスタムオブジェクトを<code>PlacesTreeView</code>のインスタンスに偽装するというものがあります。ですが、おそらくより簡単な方策としては、下記のサンプルのように、既に存在する<code>PlacesTreeView</code>インスタンスを修正するものがあります。</p>
<p>下記のJavaScriptでは、新たに<code>PlacesTreeView</code>インスタンスを作成していますが、組み込みツリービューに表示されていない列を表示するために、<code>nsITreeView</code>のメソッドを二つ上書きしています。</p>
<pre class="brush: js">var view = new PlacesTreeView();

view._getCellText = view.getCellText;
view.getCellText = function (aRowIndex, aCol) {
  // 特殊な列を操作する。PlacesTreeViewとして、列のidまたはanonidを認識する。
  switch (aCol.id || aCol.element.getAttribute("anonid"))
  {
  // (ブックマークのような)URIノードでなく、(フォルダのような)すべてのノードのURI
  case "fullURI":
    return this.nodeForTreeIndex(aRowIndex).uri;
    break;
  // 親コンテナ内でのノードのindex
  case "indexInParent":
    return this.nodeForTreeIndex(aRowIndex).bookmarkIndex;
    break;
  // 偶数列かそれとも奇数列か
  case "parity":
    return (aRowIndex % 2 === 0 ? "even" : "odd");
    break;
  }
  // そうでない場合、オリジナルの<span><span class="comment">getCellTextメソッドに偽装する</span></span>
  return this._getCellText(aRowIndex, aCol);
};

view._cycleHeader = view.cycleHeader;
view.cycleHeader = function (aCol) {
  switch (aCol.id || aCol.element.getAttribute("anonid"))
  {
  case "fullURI":
  case "indexInParent":
  case "parity":
    // ここで列のサイソートが可能
    break;
  default:
    this._cycleHeader(aCol);
    break;
  }
};

// クエリの実行と検索結果の取得
var bmServ =
    Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"].
    getService(Components.interfaces.nsINavBookmarksService);
var histServ =
  Components.classes["@mozilla.org/browser/nav-history-service;1"].
  getService(Components.interfaces.nsINavHistoryService);
var opts = histServ.getNewQueryOptions();
var query = histServ.getNewQuery();
query.setFolders([bmServ.placesRoot], 1);
var result = histServ.executeQuery(query, opts);

// result's viewerとカスタムビューのツリーのnsITreeViewの接続
var treeView = document.getElementById("myTreeView");
result.viewer = view;
treeView.view = view;
</pre>
<p>下記のXULでは、JavaScript中から参照され<span style="font-family: monospace;">る</span><code>myTreeView</code><span style="font-family: monospace;">要素を定義しています。</span></p>
<pre class="brush: xml">&lt;tree id="myTreeView" flex="1"&gt;
  &lt;treecols&gt;
    &lt;treecol id="title" label="title" flex="1" primary="true" /&gt;
    &lt;splitter class="tree-splitter" /&gt;
    &lt;treecol anonid="fullURI" label="fullURI" flex="1" /&gt;
    &lt;splitter class="tree-splitter" /&gt;
    &lt;treecol id="indexInParent" label="indexInParent" /&gt;
    &lt;splitter class="tree-splitter" /&gt;
    &lt;treecol id="parity" label="parity" /&gt;
  &lt;/treecols&gt;
  &lt;treechildren /&gt;
&lt;/tree&gt;
</pre>
<p>このページ下部のファイルの項目に、コードの全文が挙げられています。</p>
<p>上記のツリー要素には、組み込みビューの際の特殊な<code>type</code>属性を持たないことを注記しておきます。上記のツリーは、あなたがPlacesクエリと接続した通常のツリーであって、組み込みツリービューのような便利な<a href="/#Convenience_properties" title="#Convenience properties">プロパティ</a>や<a href="/#Convenience_methods" title="#Convenience methods">メソッド</a>は存在しません。もし、カスタムビューがあなたのアプリケーションにおいてのみ使用されるのであれば、コードは上述したようなもので十分でしょう。上記のコードでは、<code>PlacesTreeView</code>オブジェクトを1つ作成し、修正を加え、通常のツリーに組み込むのに十分です。しかしながらもし、あなたのビューが幅広く使われるのであれば、組み込みビューを見習って<code>PlacesTreeView</code>に似通ったJavaScriptプロトタイプと<a href="/ja/XBL" title="ja/XBL">XBL</a>ツリーバインディングを作成し、ビューと表示と接続作成に多くの作業を費やすことになるでしょう。</p>
<p><code>nsINavHistoryResultNode.viewIndex</code>属性は、ビューを使用することによって、明白に提供されます。この値は、それぞれのノードが生成されたときは<code>-1</code>に初期化されています。あなたは、この値を可視ノードの追跡を保存するためにこの値を使用します。<code>PlacesTreeView</code>は、列中で有効になっているノードのindexを保存するために、この値を使用します。</p>
<h2>関連記事</h2>
<ul> <li>{{ Interface("nsIPlacesView") }}</li> <li><a class="internal" href="/ja/Querying_Places" title="ja/Querying Places">Querying Places</a></li> <li><a class="internal" href="/ja/Places/View_Controller" title="ja/Places/View Controller">View Controller</a> </li>
</ul>
<p>{{ languages( { "en": "en/Displaying_Places_information_using_views" } ) }}</p>
このリビジョンへ戻す