言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

Swing におけるテキストの表現

Swing のテキストエディタは、テキストを表現する為のデータ構造を複数提供しているらしいので調べてみた。前回使ったコード http://d.hatena.ne.jp/propella/20080315/p1 で、JTextArea を基点に色々調べていくと、

  • this: JTextArea テキストを表示する部品
    • model: PlainDocument テキストの編集機能を持つ
      • data: GapContent テキストのデータと位置情報を持つ
    • ui: BasicTextAreaUI
      • rootView: BasicTextUI$RootView
        • view: PlainView 行情報をもつらしい
    • caret: BasicTextUI$BasicCaret カーソル

という感じになっている。VisualWorks との対比で言うと、

  • JTextArea : TextEditorView
  • PlainDocument : ComposedText (ただし座標情報は含まない)
  • PlainView : ComposedText (座標情報)
  • GapContent : GapString

なのかな?結構複雑。

次に、エディタを実現するためにはモデルにどんな機能が必要なのかを調べてみる。例えば、「行末へ移動」を実現するためには改行の位置を調べる機能や、キャレットを動かす機能などが必要だけど、どんなインタフェースを採用するかで効率が変わってくるので結構難しい。

JTextArea では右カーソルキーが押されると次の事が起こる。

  • JTextArea(JComponent) にイベントがやって来る。
  • DefaultEditorKit$NextVisualPositionAction.actionPerformed が呼ばれる
    • このオブジェクトがどうやって参照されているのか謎
    • キー操作ごとに、それぞれ TextAction のサブクラスが定義されていて、このように TextAction.actionPerformed でキーに応じたコマンドが実行される。
  • BasicTextAreaUI(BasicTextUI).getNextVisualPositionFrom が呼ばれる
  • PlainView(View).getNextVisualPositionFrom が呼ばれる
    • ここで新しいカーソル位置が求まる。
  • BasicTextUI$BasicCaret(DefaultCaret).setDot caret が更新される。

これで、カーソル位置はビューによって決まるという事が分かる。左右の事だけ考えればビューは関係無さそうだが、上下移動には文書幅が必要だからだろう。例えば行頭コマンドは次のように実行される。

  • DefaultEditorKit$BeginLineAction.actionPerformed
  • Utilities.getRowStart 行頭位置を求める
    • ここで、何度か JTextComponent.modelToView を呼び出して表示座標を比較しながら行頭を求めて行く。
      • modelToView は PlainView.modelToView に委譲

PlainView.modelToView は Element を使って文字位置から表示座標を求めて行く。Element の構造については、ちょっと難しいので次回調べようと思う。ちなみに Caret の用法では dot をカーソル位置 mark を選択開始と言う。

参考