モジュール java.desktop
パッケージ javax.swing.text

インタフェースDocument

既知のすべてのサブインタフェース:
StyledDocument
既知のすべての実装クラス:
AbstractDocument, DefaultStyledDocument, HTMLDocument, PlainDocument

public interface Document

Documentはswingテキスト・コンポーネントのモデルとなるテキストのコンテナです。 このインタフェースのめざすところはプレーン・テキストのテキスト・フィールドのように非常にシンプルなものからHTMLまたはXMLのように複雑なものにまで対応できるようにスケーリングすることです。

Content

もっともシンプルなレベルでは、テキストは線状に伸びる一連の文字として形成されます。 国際化に備えてSwingテキスト・モデルはunicode文字を使用します。 通常、テキスト・コンポーネントに表示される文字シーケンスはコンポーネントのコンテンツと呼ばれます。

シーケンス内の場所を参照するために2文字間の位置座標を使用します。 下の図に示すように、テキスト・ドキュメント内の場所は位置として、またはオフセットとして示すことができます。 この位置はゼロから始まります。

次の文は、この図について説明しています。

たとえば、前の図のようにドキュメントのコンテンツが「The quick brown fox」というシーケンスの場合、「The」の前の場所は0で、「The」の後とそれに続く空白の間の場所は3となります。 「The」というシーケンスの全文字シーケンスを範囲と呼びます。

次のメソッドでコンテンツを構成する文字データへアクセスできます。

構造

テキストが単調なコンテンツとして表されることはほとんどありません。 むしろ、通常、テキストはコンテンツと関連した構造になっています。 正確にどの構造がモデルになっているかは特定のDocument実装により異なります。 単純なテキスト・フィールドのように構造がないようなシンプルなものもあれば、下の図のようなものもあります。

図は、Book、Chapter、Paragraphの順に示しています。

構造単位、すなわちツリーのノードはElementインタフェースで表せます。 各Elementは属性のセットによりタグを付けることができます。 こういう名前と値のペアの属性はAttributeSetインタフェースで定義されます。

次のメソッドでドキュメント構造へアクセスできます。

Mutations

すべてのドキュメントは簡単なテキストの追加および削除ができる必要があります。 通常、テキストはキーボードまたはマウスのジェスチャで挿入、削除ができます。 挿入、削除をした結果ドキュメント構造にどういう影響があるかはすべてドキュメントの実装によります。

次のメソッドはドキュメント・コンテンツの変化に関係付けられています。

Notification

Documentに変更が生じた場合は関係者に通知する必要があります。 変更通知はJavaBeansに指定されているイベント・モデルのガイドラインに準じます。 JavaBeansイベント・モデルの規定では、いったんイベント通知を送信したら、イベント・ソースをさらに変更する前にすべてのリスナーに通知する必要があります。 また、配信の順序は保証されません。

通知は、2つの別個のイベント、DocumentEventUndoableEditEventとして提供されます。 APIを介してDocumentが変更された場合、登録されているすべてのDocumentListenersDocumentEventが送信されます。 Documentの実装が元に戻す機能や再実行機能をサポートしている場合、登録されているすべてのUndoableEditListenerUndoableEditEventが送信されます。 取消し可能な編集が取り消された場合、DocumentからDocumentEventをトリガーして再度変更されたことが示されます。 しかしこの場合、その編集はAPIを介して行われたDocumentの変更というよりむしろソースの変更であるため、UndoableEditEventは生成されません。

前の文は、この図について説明しています。

上記の図に関して、左に示されているコンポーネントが青い矩形で表されているドキュメント・オブジェクトを変更したと仮定します。 ドキュメントは両コンポーネントのビューにDocumentEventを送信して応答し、履歴バッファを保持しているリスニング・ロジックにUndoableEditEventを送ります。

上記の図に関して、右に示されているコンポーネントが青い矩形で表されているドキュメント・オブジェクトを変更したと仮定します。 ドキュメントは両コンポーネントのビューにDocumentEventを送信して応答し、履歴バッファを保持しているリスニング・ロジックにUndoableEditEventを送ります。

その後、履歴バッファがロールバックされる(つまり、最後のUndoableEditが実行されない)と、DocumentEventが両ビューに送られ、両ビューは実行されなかったドキュメントの変更を反映させます(つまり、右のコンポーネントの変更を削除します)。 履歴バッファが再度別の変更をロールバックすると、さらに別のDocumentEventが両ビューに送られ、実行されなかったドキュメントの変更を反映させます。つまり、左のコンポーネントの変更を削除します。

ドキュメントの変化に関係するメソッドは次のとおりです。

プロパティ

通常、Documentの実装には実行時に関連したプロパティ・セットがあります。 よく知られた2つのプロパティは、Documentがどこから出されたものかを記述するときに使用するStreamDescriptionPropertyDocumentに名前を付けるときに使用するTitlePropertyです。 プロパティに関係するメソッドは次のとおりです。

概要とプログラミングのヒント

Elementは、Documentの構築に使用される重要なインタフェースです。 段落、テキスト行、リスト内の(HTMLドキュメント内)アイテムなど、ドキュメントの様々な構造部分を記述する機能があります。 概念上、ElementインタフェースはSGMLドキュメントのスピリットの一部を取得します。 したがって、SGMLがわかっている場合は、Swing Elementインタフェースについて理解していることがあります。

SwingテキストAPIドキュメント・モデルでは、インタフェース要素は、段落、テキスト行、HTMLドキュメントのリスト・アイテムなど、ドキュメントの構造部分を定義します。

すべての要素は、「ブランチ」または「リーフ」のいずれかです。 要素がブランチの場合、isLeaf()メソッドはfalseを返します。 要素がリーフの場合、isLeaf()はtrueを返します。

ブランチには任意の数の子を含めることができます。 リーフには子がありません。 ブランチに含まれる子の数を確認するには、getElementCount()をコールします。 要素の親を決定するには、getParentElement()をコールします。 ルート要素には親がないため、ルートでgetParentElement()をコールするとnullが返されます。

要素は、startOffsetで始まり、endOffsetの直前に終了するドキュメント内の特定のリージョンを表します。 ブランチ要素の開始オフセットは、通常、最初の子の開始オフセットです。 同様に、ブランチ要素の終了オフセットは通常、最後の子の終了オフセットです。

すべての要素は、getAttributes()をコールしてアクセスできるAttributeSetに関連付けられています。 要素およびAttributeSetは、基本的にキーと値のペアのセットです。 これらのペアは通常、マークアップに使用されます -- (要素のフォアグラウンド・カラー、フォント・サイズなどの決定など)。 ただし、AttributeSetに格納される内容は、モデルおよび開発者によって決まります。

Documentのルート要素(または要素)を取得するには、Documentインタフェースで定義されているgetDefaultRootElement()およびgetRootElements()メソッドをコールします。

Documentインタフェースは、文字の線形ビューをElement操作に変換します。 要素の構造を定義するのは、各文書の実装によって異なります。

PlainDocumentクラス

PlainDocumentクラスは、ルート・ノードがモデル内のテキスト行ごとに子ノードを持つ要素構造を定義します。 「図1」では、PlainDocumentによって2行のテキストがどのようにモデル化されるかが示されます。

前の文は、この図について説明しています。

「図2」では、これらの同じ2行のテキストが実際のコンテンツにどのようにマップされるかを示します:

前の文は、この図について説明しています。

PlainDocumentへのテキストの挿入

前述のように、PlainDocumentにはルート要素が含まれ、ルート要素にはテキストの各行の要素が含まれます。 テキストがPlainDocumentに挿入されると、各改行に要素が存在するために必要な要素が作成されます。 説明するために、前述の「図2」のオフセット2に改行を挿入するとします。 この目的を達成するには、次の構文を使用してDocumentメソッドinsertString()を使用します:

document.insertString(2, "\n", null);

insertString()メソッドを起動すると、Element構造は「図3」に示すようになります。

前の文は、この図について説明しています。

別の例として、「図2」で前述したように、オフセット2にパターン"新規テキスト"を挿入するとします。 この操作の結果は、「図4」に表示されます。

前の文は、この図について説明しています。

前述の図では、行番号と一致するように挿入後に行要素の名前が変更されています。 ただし、これを行うと、AttributeSetsは同じままになります。 たとえば、「図2」では、明細2のAttributeSetは「図4」の明細4のAttributeSetのAttributeSetと一致します。

PlainDocumentからのテキストの削除

テキストを削除すると、削除が複数の行にまたがる場合に構造が変更されます。 「図3」で前述したオフセット1から始まる7文字を削除することを検討してください。 この場合、2行目を表す要素は、削除されたリージョンに含まれているため、完全に削除されます。 行1と行3を表す要素は、削除されたリージョンに部分的に含まれているため結合されます。 したがって、結果は次のようになります:

前の文は、この図について説明しています。

デフォルトのStyledDocumentクラス

スタイル設定されたテキストに使用されるDefaultStyledDocumentクラスには、別のレベルの要素が含まれます。 この追加レベルは、各段落に異なるスタイルのテキストを含めることができるようにするために必要です。 「図6」に示されている2つの段落では、最初の段落に2つのスタイルが含まれ、2つ目の段落に3つのスタイルが含まれています。

前の文は、この図について説明しています。

「図7」には、これらの同じ要素がコンテンツにどのようにマップされるかが表示されます。

前の文は、この図について説明しています。

DefaultStyledDocumentへのテキストの挿入

前述のように、DefaultStyledDocumentでは、ルート要素に各段落の子要素が含まれるようにElement構造が保持されます。 次に、これらの各段落要素には、段落内のテキストの各スタイルの要素が含まれます。 たとえば、「図8」に示すように、ある段落を含むドキュメントがあり、この段落に2つのスタイルが含まれているとします。

前の文は、この図について説明しています。

オフセット2に改行を挿入する場合は、次のようにinsertString()メソッドを再度使用します:

 styledDocument.insertString(2, "\n",
                styledDocument.getCharacterElement(0).getAttributes());

この操作の結果は、「図9」に表示されます。

前の文は、この図について説明しています。

insertString()に渡されるAttributeSetは、Style 1の属性のAttributeSetと一致することに注意してください。 insertString()に渡されたAttributeSetが一致しなかった場合、結果は「図10」に示されている状況になります。

前の文は、この図について説明しています。

DefaultStyledDocumentからのテキストの削除

DefaultStyledDocumentからのテキストの削除は、PlainDocumentからのテキストの削除と似ています。 唯一の違いは、要素の追加レベルです。 上の図10のオフセット1で2つの文字を削除した場合はどうなるかを考慮してください。 段落1の2番目の要素は削除されたリージョンに完全に含まれているため、削除されます。 段落1の最初の子の属性がParagraph2の最初の子の属性と一致した場合、結果は「図11」に表示されるものになります。

前の文は、この図について説明しています。

属性が一致しなかった場合は、「図12」に表示される結果が得られます。

前の文は、この図について説明しています。

StyledDocumentクラス

StyledDocumentクラスには、特定の範囲の文字要素に属性を設定できるsetCharacterAttributes()という名前のメソッドが用意されています:

 public void setCharacterAttributes
          (int offset, int length, AttributeSet s, boolean replace);

前のセクションで示した図では、図面に表示されているすべてのリーフ要素も文字要素であることを思い出してください。 つまり、setCharacterAttributes()メソッドを使用して属性を設定できます。

setCharacterAttributes()メソッドは4つの引数を取ります。 最初の引数と2番目の引数は、変更するドキュメント内のリージョンを識別します。 3番目の引数は新しい属性(AttributeSetとして)を指定し、4番目の引数は新しい属性を既存の属性(falseの値)に追加するかどうか、または文字要素が既存の属性を新しい属性(trueの値)に置き換えるかどうかを決定します。

たとえば、前述の「図9」の最初の3文字の属性を変更するとします。 setCharacterAttributes()に渡される最初の2つの引数は0および3です。 3番目の引数は、新しい属性を含むAttributeSetです。 この例では、4番目の引数が何であるかは考慮していません。

変更されたリージョン(0および3)の開始オフセットと終了オフセットが文字要素境界に該当するため、構造の変更は必要ありません。 つまり、文字要素スタイル1の属性のみが変更されます。

次に、構造の変更が必要な例を見てみましょう。 「図9」に表示されている最初の3文字を変更するかわりに、最初の2文字を変更します。 終了変更オフセット(2)は文字要素境界に該当しないため、オフセット2の要素は、オフセット2が2つの要素の境界になるように分割する必要があります。 開始オフセットが0で長さが2のsetCharacterAttributes()を起動すると、前述の結果が「図10」に表示されます。

StyledDocumentの段落属性の変更

StyledDocumentクラスには、段落要素の属性を変更するために使用できるsetParagraphAttributes()というメソッドが用意されています:

 public void setParagraphAttributes
         (int offset, int length, AttributeSet s, boolean replace);

このメソッドはsetCharacterAttributes()に似ていますが、段落要素の属性を変更できます。 StyledDocumentの実装によって、どの要素が段落であるかが定義されます。 DefaultStyledDocumentは、段落要素をcharacter要素の親要素として解釈します。 このメソッドを呼び出しても、構造は変更されません。段落要素の属性のみが変更されます。

EditorKitおよびViewを参照することをお薦めします。 ビューは特定の要素のレンダリングを担当し、EditorKitは要素に基づいて作成するビューを決定できるViewFactoryを担当します。

関連項目: