Displaying Places information using views

  • リビジョンの URL スラッグ: Displaying_Places_information_using_views
  • リビジョンのタイトル: Displaying Places information using views
  • リビジョンの ID: 319027
  • 作成日:
  • 作成者: ethertank
  • 現行リビジョン いいえ
  • コメント

このリビジョンの内容

{{ Fx_minversion_header(3) }}

ビューは、Places model-view-controllerデザインにおけるコンポーネントのひとつです。ユーザーに向けて{{ Interface("nsINavHistoryResult") }}オブジェクトを表示するために使用します。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属性を使用します。

{{ gecko_callout_heading("2.0") }}

Gecko 2.0 {{ geckoRelease("2.0") }} 以降では、メニュービューにおいて places 属性を使用することができません。 詳しくはメニュービューを参照してください。

あなたは直接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の適切なメソッドによってビューに通知されます。通知を受けると、ビューは自身を更新します。

{{ gecko_callout_heading("2.0") }}

Gecko 2.0 {{ geckoRelease("2.0") }}以降では、nsINavHistoryResultViewer はさらに強力な{{ interface("nsINavHistoryResultObserver") }}によって置き換えられています。

ツリービュー

ツリー要素の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"に設定すると、列中のどの行も{{ Interface("nsINavHistoryResultNode") }}のtitleプロパティを表示します。/p>

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

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

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

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

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

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

ツリービューの使い方

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

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

次に、ツリーについて話す場合において、"view"とは多くの意味を持つ言葉であるということを知っておいてください。この文書ではPlacesビューについて述べています。PlacesビューはまさしくXUL要素であり、上で述べたように、ビルトインPlacesツリービューは、type属性に"places"が設定されたtree要素なのです。ですが、Placesビューであるかどうかに関わらず、全てのツリーはnsITreeViewを使用して、それぞれのデータを表示しているということを思い出してください。そのためビルトインPlacesツリービューは、viewの値に自分自身を持ちます。このビューは、最も一般的かつ最も具体的なものから順に、{{ Interface("nsINavHistoryResultTreeViewer") }}、{{ Interface("nsINavHistoryResultObserver") }} {{ gecko_minversion_inline("2.0") }}、そして{{ Interface("nsITreeView") }}といった3つのインターフェイスを実装したオブジェクトです。nsINavHistoryResultTreeViewerは、それぞれの行の索引と、それぞれの列中に含まれている{{ Interface("nsINavHistoryResultNode") }}を配置します。nsINavHistoryResultObserverは、基底データの変更があった際、その更新について観察しているクライアントに通知します。ですが、ここでの私たちの目的としてはあまり便利ではありません。通常、ツリーにおいての高レベルのインターフェイスは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 trueであれば、コンテナの内部を表示しません。 onOpenFlatContainerプロパティによってコンテナの開閉が設定されている際に機能します。 少なくともflatList及びshowRootの一方はfalseである必要があります。
onOpenFlatContainer string コンテナが開閉された際に呼び出されます。 flatList プロパティがtrueである場合のみ適用されます。 aContainerという名前の引数として{{ Interface("nsINavHistoryResultNode") }} を渡します。 aContainer に{{ Interface("nsINavHistoryContainerResultNode") }}をQueryInterfaceします。
showRoot boolean trueであれば、ルートの{{ Interface("nsINavHistoryContainerResultNode") }}をツリー最初の列に表示します。 少なくとも showRoot 及び flatList の一方は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); 

PlacesTreeView

註: この節では、PlacesTreeViewの実装の方法について述べています。

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

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

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

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

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

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

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

メニュービュー

ポップアップメニューにおける Places ビューについての情報が記述されています。

{{ h3_gecko_minversion("Firefox 3.6 以前", "1.9.2") }}

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

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

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

{{ h3_gecko_minversion("Firefox 4", "2.0") }}

以下のようにすることで、ポップアップのように Places の情報を追加することができます:

<menu id="bookmarksMenu">
  <menupopup placespopup="true">
    onpopupshowing="if (!document.getElementById('bookmarksMenu')._placesView)
                        new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
  </menupopup>
</menu> 

メニュービューは{{ 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("nsINavHistoryResultObserver") }}のインスタンスとして保持してください。あなたのviewと{{ Interface("nsINavHistoryResult") }}オブジェクトを接続するため、結果のaddObserver()メソッドを呼び出し、nsINavHistoryResultObserverのインスタンスであるviewerオブジェクトを渡してください。もし、あなたのviewがnsINavHistoryResultObserverを実装しているのであれば、viewerオブジェクトを渡す事ができます。もし、あなたのviewがnsINavHistoryResultObserverのインスタンスを内部に含んでいるならば、代わりにそれを渡すことができます。(3種類の組み込みビューもこのアプローチを採用しています) resultオブジェクトはこのインスタンスを通じてあなたのviewと連絡を取り、基底データの変更の通知を受けた場合に表示を更新するのです。

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);

// このmyViewとはあなたのviewです。そしてmyView.viewerはnsINavHistoryResultObserverを実装したオブジェクトです。
result.addObserver(myView.viewer);

より本質的な意味において、上述したコードは、あなたのviewのメソッドへと送信されます。呼び出し元は検索結果または検索クエリを渡し、あなたは検索クエリを実行し、addObserver()を使用して観察対象のクライアントとしてあなたのviewを追加します。(ビルトインツリービューのloadメソッドでの処理手法です)

あなたのviewが結果を観察した時、resultは与えられたnsINavHistoryResultObserverresultプロパティに設定されます。あなたはresultプロパティを明確に設定するべきではありません。resultとビューの接続を解除するには、 あなたの結果からremoveObserver(view)を呼び出してください。

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

nsINavHistoryResultObserverが使用されている場合でも正確な内容でしょうか?

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

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

幸運にも、あなたの目的に合致したビルトインツリービューの一部を拝借することが可能です。ビルトインビューであるPlacesTreeViewの実態であるJavaScriptプロトタイプは、特に役立つ{{ Interface("nsINavHistoryResultTreeViewer") }}、{{ Interface("nsINavHistoryResultObserver") }}、{{ 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.addObserver(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 属性を持たないことを注記しておきます。I上記のツリーはあなたがPlacesクエリと接続した通常のツリーであって、ビルトインツリービューのような便利なプロパティメソッドは存在しません。もし、カスタムビューがあなたのアプリケーションにおいてのみ使用されるのであれば、コードは上述したようなもので十分でしょう。上記のコードでは、PlacesTreeViewオブジェクトを1つ作成し、修正を加え、通常のツリーに組み込むのに十分です。しかしながらもし、あなたのビューが幅広く使われるのであればビルトインビューのようにPlacesTreeViewに似通ったJavaScriptプロトタイプとXBLツリーバインディングを作成し、ビューと表示と接続作成に多くの作業を費やすべきでしょう。

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

関連記事

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

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

<p>{{ Fx_minversion_header(3) }}</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("nsINavHistoryResult") }}オブジェクトを表示するために使用します。Placesのクエリでは、<code>nsINavHistoryResult</code> オブジェクトについての情報を保持し、使用しています。<code>nsINavHistoryResult</code> オブジェクトの保持および扱い方については、<a class="internal" href="/ja/Querying_Places" title="ja/Querying
Places">Querying Places</a> を参照してください。このページでは、既にこれらについて知っているものとして話を進めます。</p>
<p><code>nsINavHistoryResult </code>のインスタンスはビューのデータを提供します。ビューは、このインスタンスのルートである{{ Interface("nsINavHistoryContainerResultNode") }}を展開し、その時点で含んでいる{{ Interface("nsINavHistoryResultNode") }}オブジェクトを表示する機能を持ちます。</p>
<h2 id="The_built-in_views" 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 id="Instantiating_in_XUL" 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 id=".E3.83.93.E3.83.A5.E3.83.BC.E3.81.A8.E3.83.87.E3.83.BC.E3.82.BF.E3.81.AE.E6.8E.A5.E7.B6.9A">ビューとデータの接続</h3>
<p>ビルトインビューとデータを接続するためには、ビューの特殊な<code>place</code>属性を使用します。</p>
<div class="geckoVersionNote">
  <p>{{ gecko_callout_heading("2.0") }}</p>
  <p>Gecko 2.0 {{ geckoRelease("2.0") }} 以降では、メニュービューにおいて places 属性を使用することができません。 詳しくは<a href="/ja/Displaying_Places_information_using_views#Menu_view" title="ja/Displaying Places information using views#Menu view">メニュービュー</a>を参照してください。</p>
</div>
<p>あなたは直接XUL中の属性に値を指定するか、JavaScrptを使用して対応するプロパティに値を設定しなければなりません。その値は、ビューに表示するデータがクエリの結果となるようなクエリ形式のURIにしてください。ビューが終了するまで変更されないような単純なクエリの場合は、XUL中の<code>place</code>属性に直接指定したほうが良いかもしれません。より複雑なクエリの場合、またはクエリのURIが変わる予定のある場合は、JavaScriptを用いてビューの<code>place</code>プロパティに動的に値を設定したほうが良いでしょう。後者の場合では、要素の属性に<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;
&nbsp; &lt;treecols&gt;
&nbsp;&nbsp;&nbsp; &lt;treecol id="title" label="My Bookmarks" flex="1" primary="true" /&gt;
&nbsp; &lt;/treecols&gt;
&nbsp; &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>
<div class="geckoVersionNote">
  <p>{{ gecko_callout_heading("2.0") }}</p>
  <p>Gecko 2.0 {{ geckoRelease("2.0") }}以降では、<code>nsINavHistoryResultViewer </code>はさらに強力な<code>{{ interface("nsINavHistoryResultObserver") }}</code>によって置き換えられています。</p>
</div>
<h3 id=".E3.83.84.E3.83.AA.E3.83.BC.E3.83.93.E3.83.A5.E3.83.BC">ツリービュー</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>もし、あなたのツリービューにFirefoxにおいて通常使われているスタイルを適用したい場合は以下のスタイルシートを読み込ませてください。注意すべきこととしては、このスタイルシートは<a href="#Instantiating">上述</a>の、ビルトイン Places ビューを使用する際に<em>読み込まなければならない</em>ものとは違います。下記のスタイルシートはオプションであり、スタイルとアイコンはビルトインツリービューにしか適用されません。</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 id=".E5.88.97.E3.81.AE.E3.83.90.E3.82.A4.E3.83.B3.E3.83.87.E3.82.A3.E3.83.B3.E3.82.B0">列のバインディング</h4>
<p><code>ビルトインツリービュー</code>は、あなたのツリーの特定の列と結果の特定のプロパティの接続を簡単に行えます。それは、あなたの <code>treecol</code> 要素の<code>id</code> 属性に与えられた魔法の値によって認識されています。検索結果のプロパティは、列の<code>id</code>属性によって列と結び付けられています。例えば、列の<code>id</code>を"title"に設定すると、列中のどの行も{{ Interface("nsINavHistoryResultNode") }}のtitleプロパティを表示します。/p&gt;</p>
<p>下記の表は、列の<code>id</code>と値が、<code>nsINavHistoryResultNode</code>のプロパティのどれに関連付けられているかを示しています。</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</td>
      <td><code>uri</code></td>
    </tr>
    <tr>
      <td>date</td>
      <td><code>time</code></td>
    </tr>
    <tr>
      <td>visitCount</td>
      <td><code>accessCount</code></td>
    </tr>
    <tr>
      <td>keyword</td>
      <td>*</td>
    </tr>
    <tr>
      <td>description</td>
      <td>*</td>
    </tr>
    <tr>
      <td>dateAdded</td>
      <td><code>dateAdded</code></td>
    </tr>
    <tr>
      <td>lastModified</td>
      <td><code>lastModified</code></td>
    </tr>
    <tr>
      <td>tags</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 id=".E3.83.84.E3.83.AA.E3.83.BC.E3.83.93.E3.83.A5.E3.83.BC.E3.81.AE.E4.BD.BF.E3.81.84.E6.96.B9">ツリービューの使い方</h4>
<p>ビルトインツリービューの使用の準備ができました。どうやって表示されるデータを扱うのでしょうか?</p>
<p>はじめに{{ Interface("nsIPlacesView") }}を参照してください。全てのPlacesビューと同様に、ビルトインツリービューもこのインターフェイスを実装しており、ビューの{{Interface("nsINavHistoryResult")}}インスタンスを取得し、ビューの選択部を調べるための幅広い手段を提供しています。</p>
<p>次に、ツリーについて話す場合において、"view"とは多くの意味を持つ言葉であるということを知っておいてください。この文書ではPlacesビューについて述べています。PlacesビューはまさしくXUL要素であり、<a href="#Tree_view">上で述べたように</a>、ビルトインPlacesツリービューは、<code>type</code>属性に"places"が設定されたtree要素なのです。ですが、Placesビューであるかどうかに関わらず、全てのツリーは<code><a href="../../../../ja/nsITreeView" rel="internal">nsITreeView</a></code>を使用して、それぞれのデータを表示しているということを思い出してください。そのためビルトインPlacesツリービューは、viewの値に自分自身を持ちます。このビューは、最も一般的かつ最も具体的なものから順に、{{ Interface("nsINavHistoryResultTreeViewer") }}、{{ Interface("nsINavHistoryResultObserver") }} {{ gecko_minversion_inline("2.0") }}、そして{{ Interface("nsITreeView") }}といった3つのインターフェイスを実装したオブジェクトです。<code>nsINavHistoryResultTreeViewer</code>は、それぞれの行の索引と、それぞれの列中に含まれている{{ Interface("nsINavHistoryResultNode") }}を配置します。<code>nsINavHistoryResultObserver</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>によって提供されているインターフェイスは非常に一般的なものであるのですが、ビューに直接実装されたメソッドとプロパティは非常に特殊なものです。時々、相互作用する4つの手段のうち、主に使用している手段とは別の手段の使用が必要となることがあります。</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 id=".E4.BE.BF.E5.88.A9.E3.81.AA.E3.83.A1.E3.82.BD.E3.83.83.E3.83.89">便利なメソッド</h4>
<p>ビルトインツリービューは幅広く使用されるものの複雑であるので、よく使われる処理を簡単に記述するために、いくつかの便利なメソッドがツリービューに直接実装されています。</p>
<div class="warning">
  <strong>警告:</strong> {{ Bug(476952) }} が修正されるまでは、 <code>place</code>属性や<code>place</code>プロパティと併用して、これらのメソッドを使用することによって問題が発生するかもしれません。</div>
<h5 id="applyFilter()">applyFilter()</h5>
<p>特定の検索条件とフォルダに合致した新規クエリを読み込みます。</p>
<pre>
void applyFilter(
  string filterString,
  array folderRestrict
);
</pre>
<h6 id=".E3.83.91.E3.83.A9.E3.83.A1.E3.83.BC.E3.82.BF">パラメータ</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 id="load()">load()</h5>
<p>ビューの表示のクエリを設定します。このメソッドは上で述べられているツリーの<code>place</code>プロパティを設定するための代わりの手段としても使われます。</p>
<pre>
void load(
  array queries,
  nsINavHistoryQueryOptions options
);
</pre>
<h6 id=".E3.83.91.E3.83.A9.E3.83.A1.E3.83.BC.E3.82.BF">パラメータ</h6>
<dl>
  <dt>
    <code>queries</code></dt>
  <dd>
    {{ Interface("nsINavHistoryQuery") }} オブジェクトの配列。</dd>
  <dt>
    <code>options</code></dt>
  <dd>
    {{ Interface("nsINavHistoryQueryOptions") }} オブジェクト。</dd>
</dl>
<h5 id="selectItems()">selectItems()</h5>
<p>与えられたアイテムIDのそれぞれに合致した、ツリー中の最初のノードを選択します。選択されたアイテムを表示する必要があるため、選択されたアイテムの親ノードを展開します。</p>
<pre>
void selectItems(
  array aIDs,
  array aOpenContainers
);
</pre>
<h6 id=".E3.83.91.E3.83.A9.E3.83.A1.E3.83.BC.E3.82.BF">パラメータ</h6>
<dl>
  <dt>
    <code>aIDs</code></dt>
  <dd>
    アイテムIDの配列。</dd>
  <dt>
    <code>aOpenContainers</code></dt>
  <dd>
    真または未定義の場合、閉じられたフォルダも同様に検索されます。そうでない場合、閉じられたフォルダは検索されません。省略可。</dd>
</dl>
<h5 id="selectNode()">selectNode()</h5>
<p>ツリー中で選択された特定のノードの祖先である全てのコンテナが展開され、選択されたノードが見えるようになります。</p>
<pre>
void selectNode(
  nsINavHistoryNode node
);
</pre>
<h6 id=".E3.83.91.E3.83.A9.E3.83.A1.E3.83.BC.E3.82.BF">パラメータ</h6>
<dl>
  <dt>
    <code>node</code></dt>
  <dd>
    選択された{{ Interface("nsINavHistoryResultNode") }}。</dd>
</dl>
<h5 id="selectPlaceURI()">selectPlaceURI()</h5>
<p>ツリー中で、特定のplaceURIに一致するノードが選択され、そのノードの祖先である全てのコンテナが展開されることにより、選択されたノードが見えるようになります。</p>
<pre>
void selectPlaceURI(
  string placeURI
);
</pre>
<h6 id=".E3.83.91.E3.83.A9.E3.83.A1.E3.83.BC.E3.82.BF">パラメータ</h6>
<dl>
  <dt>
    <code>placeURI</code></dt>
  <dd>
    選択する{{ Interface("nsINavHistoryResultNode") }}のURI(文字列型)。</dd>
</dl>
<h4 id=".E4.BE.BF.E5.88.A9.E3.81.AA.E3.83.97.E3.83.AD.E3.83.91.E3.83.86.E3.82.A3">便利なプロパティ</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>trueであれば、コンテナの内部を表示しません。 <code>onOpenFlatContainer</code>プロパティによってコンテナの開閉が設定されている際に機能します。 少なくとも<code>flatList</code>及び<code>showRoot</code>の一方はfalseである必要があります。</td>
    </tr>
    <tr>
      <td><code>onOpenFlatContainer</code></td>
      <td><code>string</code></td>
      <td>コンテナが開閉された際に呼び出されます。 <code>flatList</code> プロパティがtrueである場合のみ適用されます。 <code>aContainer</code>という名前の引数として{{ Interface("nsINavHistoryResultNode") }} を渡します。 <code>aContainer</code> に{{ Interface("nsINavHistoryContainerResultNode") }}をQueryInterface<code>します。</code></td>
    </tr>
    <tr>
      <td><code>showRoot</code></td>
      <td><code>boolean</code></td>
      <td>trueであれば、ルートの{{ Interface("nsINavHistoryContainerResultNode") }}をツリー最初の列に表示します。 少なくとも <code>showRoot</code> 及び <code>flatList</code> の一方はfalseである必要があります。</td>
    </tr>
  </tbody>
</table>
<h4 id=".E4.BD.BF.E7.94.A8.E4.BE.8B">使用例</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 id="PlacesTreeView">PlacesTreeView</h4>
<div class="note">
  <strong>註:</strong> この節では、PlacesTreeViewの実装の方法について述べています。</div>
<p>ビルトインツリービューの実態は<code>PlacesTreeView</code>のインスタンスであり、プロトタイプは{{ Source("browser/components/places/content/treeView.js") }}で定義されています。<code>PlacesTreeView</code>の挙動はビルトインツリービューにおいて、{{ Interface("nsITreeView") }}、及びPlacesビューに必要な機能の多くを実装するという2つの機能をなします。後者においては具体的には{{ Interface("nsINavHistoryResultViewer") }}を継承した{{ Interface("nsINavHistoryResultObserver") }} {{ gecko_minversion_inline("2.0") }}が実装されています。</p>
<p>以下のように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.addObserver(view.QueryInterface(Components.interfaces.nsINavHistoryResultObserver));
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=".E3.83.A1.E3.83.8B.E3.83.A5.E3.83.BC.E3.83.93.E3.83.A5.E3.83.BC">メニュービュー</h3>
<p>ポップアップメニューにおける Places ビューについての情報が記述されています。</p>
<p>{{ h3_gecko_minversion("Firefox 3.6 以前", "1.9.2") }}</p>
<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>{{ h3_gecko_minversion("Firefox 4", "2.0") }}</p>
<p>以下のようにすることで、ポップアップのように Places の情報を追加することができます:</p>
<pre class="brush: xml">
&lt;menu id="bookmarksMenu"&gt;
&nbsp; &lt;menupopup placespopup="true"&gt;
&nbsp;&nbsp;&nbsp; onpopupshowing="if (!document.getElementById('bookmarksMenu')._placesView)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
&nbsp; &lt;/menupopup&gt;
&lt;/menu&gt; 
</pre>
<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=".E3.83.84.E3.83.BC.E3.83.AB.E3.83.90.E3.83.BC.E3.83.93.E3.83.A5.E3.83.BC">ツールバービュー</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 id=".E3.83.93.E3.83.A5.E3.83.BC.E3.81.AE.E4.BD.BF.E3.81.84.E6.96.B9">ビューの使い方</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 id="Creating_custom_views" 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("nsINavHistoryResultObserver") }}のインスタンスとして保持してください。あなたのviewと{{ Interface("nsINavHistoryResult") }}オブジェクトを接続するため、結果の<code>addObserver()</code>メソッドを呼び出し、<code>nsINavHistoryResultObserver</code>のインスタンスである<code>viewer</code>オブジェクトを渡してください。もし、あなたのviewが<code>nsINavHistoryResultObserver</code>を実装しているのであれば、<code>viewer</code>オブジェクトを渡す事ができます。もし、あなたのviewが<code>nsINavHistoryResultObserver</code>のインスタンスを内部に含んでいるならば、代わりにそれを渡すことができます。(3種類の組み込みビューもこのアプローチを採用しています) resultオブジェクトはこのインスタンスを通じてあなたのviewと連絡を取り、基底データの変更の通知を受けた場合に表示を更新するのです。</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);

// このmyViewとはあなたのviewです。そしてmyView.viewerはnsINavHistoryResultObserverを実装したオブジェクトです。
result.addObserver(myView.viewer);
</pre>
<p>より本質的な意味において、上述したコードは、あなたのviewのメソッドへと送信されます。呼び出し元は検索結果または検索クエリを渡し、あなたは検索クエリを実行し、<code>addObserver()</code>を使用して観察対象のクライアントとしてあなたのviewを追加します。(ビルトインツリービューの<a href="#load()" title="#load()">loadメソッド</a>での処理手法です)</p>
<p>あなたのviewが結果を観察した時、resultは与えられた<code>nsINavHistoryResultObserver</code>の<code>result</code>プロパティに設定されます。<em>あなたは<code>result</code>プロパティを明確に設定するべきではありません。</em>resultとビューの接続を解除するには、 あなたの結果から<code>removeObserver(view)</code>を呼び出してください。</p>
<p>循環参照に注意してください。ビューとresultは、両方とも互いへの参照を持ちます。JavaScriptのガベージコレクションによってこれらのオブジェクトが解放されるためには、<code>result.removeObserver(view)</code>を呼び出すことによって、この循環を消去しなければなりません。(例えば、ビルトインツリービューでは自動的にこの作業を行っています。ツリーが破棄された、または別の{{ Interface("nsITreeView") }}とツリーが関連付けられた場合、ツリーは古い方の<code>nsITreeView</code>の<code>tree</code>プロパティをnullに設定します。<code>nsITreeView</code>を実装したオブジェクトは<code>nsINavHistoryResultObserver</code>も実装しているため、ビューは<code>removeObserver()</code>を呼び出し、resultから自分自身への接続を解除します。)</p>
<div class="note">
  <code>nsINavHistoryResultObserver</code>が使用されている場合でも正確な内容でしょうか?</div>
<h3 id=".E3.82.AB.E3.82.B9.E3.82.BF.E3.83.A0.E3.83.84.E3.83.AA.E3.83.BC.E3.83.93.E3.83.A5.E3.83.BC.E3.81.AE.E4.BD.9C.E6.88.90">カスタムツリービューの作成</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("nsINavHistoryResultObserver") }}、{{ 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;
  }
   // そうでない場合、オリジナルの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.addObserver(view);
treeView.view = view;
</pre>
<p>下記のXULでは、JavaScript中から参照される<code>myTreeView</code>要素を定義しています。</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>このページ下部の<a href="#page-files">ファイル</a>の項目に、コードの全文が挙げられています。</p>
<p>上記のツリー要素は、ビルトインビューの際の特殊な <code>type</code> 属性を持たないことを注記しておきます。I上記のツリーはあなたが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 id=".E9.96.A2.E9.80.A3.E8.A8.98.E4.BA.8B">関連記事</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>
Revert to this revision