16
062 JavaWorld 2004 March 独自プラグインの作成手順 本パートでは、HTMLエディタをEclipseプラグイ ンとして実現する方法を説明する。これを通して、 プラグインによる機能追加の方法を学んでいただき たい。 HTMLエディタは、Eclipseプラットフォーム・テキ スト・エディタ(標準テキスト・エディタ)を拡張して作 成することにする。以下のように機能を少しずつ追 加しながら、HTMLエディタを完成させていくことで、 各種の拡張方法を説明していく。 Step 1 :エディタの追加 Step 2 :ドキュメント・プロバイダの追加 Step 3 :色分け表示機能の追加 Step 4 :ファイル生成ウィザードの追加 Step 5 :表/イメージの挿入機能の追加 Step 6 :プレビュー機能の追加 Step 7 :入力支援機能の追加 その際、関連するクラスなどについて随時解説を 加えることにする。 表1に、このHTMLエディタのプラグインを構成す るクラスの一覧を示した。紙幅の都合上、これらの クラスすべてについては説明できないので、本稿 では主要なクラスの要点のみを説明することにす る。なおソース・コードの 完全版が 本誌付録CD- ROMに収録されているので、記事中で触れないク ラスについては、必要に応じてそちらを参照してい ただきたい。 それでは早速、Step 1から順に、各機能の追加 方法を説明していこう。 Eclipseにおいて、エディタは、ワークベンチ・ペー ジ内のビジュアル・コンポーネントとして提供される。 特定の入力オブジェクト(インタフェースorg.eclipse. ui.IEditorInputを実装したオブジェクト)に対して、1 つだけエディタを開くことができるが、異なる入力オ ブジェクトに対しては、同じエディタが複数開く可能 性がある。 Eclipseのワークベンチに新しいエディタを追加す るには、拡張ポイントorg.eclipse.ui.editorsを利用 する。これを使えば、内部エディタあるいは外部エ ディタをEclipseに追加することができる ※1 まず、Part 2で説明したのと同様の手順で、プラ グイン・プロジェクトを作成する。プロジェクト名とし て「com.samples.myhtmledit」を指定し、「プラグイ ン・コード生成プログラム」ページでは「デフォルト・ プラグイン構造」を選択してプラグイン・プロジェクト を作成していただきたい。 plugin.xmlでの指定は、 リスト1のとおりである。 ご 覧のように、拡張ポイントとして「org.eclipse. ui.editors」を設定し、要素extensionの子要素とし て要素editorを記述する。 ここで、まず 注目していただきたいのが、要素 editorの属性extensionsである。同属性には、エデ ィタによって認識されるファイル・タイプのリストとし 特集 Eclipse 実践! 開発 独自プラグインによる機能追加 HTMLエディタ の開発を通して知る、その手順とノウハウ Part 3 Eclipseでは、プラグインを開発することで、新規に独自の機能を追加することができる。この拡張性の高さこそが、 Eclipseの最大の魅力だ。本パートでは、「HTMLエディタ」の作成を例にとり、その開発手法を詳細に説明する。 Step1 エディタの追加 ※1 内部エディタとは、ワークベンチ内に組み込まれたかたちで表示されるエディ タである。一方、外部エディタとは、ワークベンチの外部に表示されるエディタの ことだ。 p062-077_特集part3 04.1.11 8:11 PM ページ 062

Eclipse Plugin Development Part 3

Embed Size (px)

DESCRIPTION

Eclipse Plugin Development田坂澄生, Eclipse プラグイン開発, JavaWORLD, 2004 3 月, pp.36-77

Citation preview

Page 1: Eclipse Plugin Development Part 3

062 JavaWorld 2004 March

独自プラグインの作成手順

本パートでは、HTMLエディタをEclipseプラグイ

ンとして実現する方法を説明する。これを通して、

プラグインによる機能追加の方法を学んでいただき

たい。

HTMLエディタは、Eclipseプラットフォーム・テキ

スト・エディタ(標準テキスト・エディタ)を拡張して作

成することにする。以下のように機能を少しずつ追

加しながら、HTMLエディタを完成させていくことで、

各種の拡張方法を説明していく。

Step 1:エディタの追加

Step 2:ドキュメント・プロバイダの追加

Step 3:色分け表示機能の追加

Step 4:ファイル生成ウィザードの追加

Step 5:表/イメージの挿入機能の追加

Step 6:プレビュー機能の追加

Step 7:入力支援機能の追加

その際、関連するクラスなどについて随時解説を

加えることにする。

表1に、このHTMLエディタのプラグインを構成す

るクラスの一覧を示した。紙幅の都合上、これらの

クラスすべてについては説明できないので、本稿

では主要なクラスの要点のみを説明することにす

る。なおソース・コードの完全版が本誌付録CD-

ROMに収録されているので、記事中で触れないク

ラスについては、必要に応じてそちらを参照してい

ただきたい。

それでは早速、Step 1から順に、各機能の追加

方法を説明していこう。

Eclipseにおいて、エディタは、ワークベンチ・ペー

ジ内のビジュアル・コンポーネントとして提供される。

特定の入力オブジェクト(インタフェースorg.eclipse.

ui.IEditorInputを実装したオブジェクト)に対して、1

つだけエディタを開くことができるが、異なる入力オ

ブジェクトに対しては、同じエディタが複数開く可能

性がある。

Eclipseのワークベンチに新しいエディタを追加す

るには、拡張ポイントorg.eclipse.ui.editorsを利用

する。これを使えば、内部エディタあるいは外部エ

ディタをEclipseに追加することができる※1。

まず、Part 2で説明したのと同様の手順で、プラ

グイン・プロジェクトを作成する。プロジェクト名とし

て「com.samples.myhtmledit」を指定し、「プラグイ

ン・コード生成プログラム」ページでは「デフォルト・

プラグイン構造」を選択してプラグイン・プロジェクト

を作成していただきたい。

plugin.xmlでの指定は、リスト1のとおりである。

ご覧のように、拡張ポイントとして「org.eclipse.

ui.editors」を設定し、要素extensionの子要素とし

て要素editorを記述する。

ここで、まず注目していただきたいのが、要素

editorの属性extensionsである。同属性には、エデ

ィタによって認識されるファイル・タイプのリストとし

特 集

Eclipse実践!

開発

独自プラグインによる機能追加「HTMLエディタ」の開発を通して知る、その手順とノウハウ

Part 3Eclipseでは、プラグインを開発することで、新規に独自の機能を追加することができる。この拡張性の高さこそが、

Eclipseの最大の魅力だ。本パートでは、「HTMLエディタ」の作成を例にとり、その開発手法を詳細に説明する。

Step1 エディタの追加

※1 内部エディタとは、ワークベンチ内に組み込まれたかたちで表示されるエディタである。一方、外部エディタとは、ワークベンチの外部に表示されるエディタのことだ。

p062-077_特集part3 04.1.11 8:11 PM ページ 062

Page 2: Eclipse Plugin Development Part 3

063JavaWorld2004 March

Tutorial for Eclipse Plugin Development

て「htm, html」が指定されている。これにより、これ

らの拡張子を持つファイルを「ナビゲーター」ビュー

などで選択すると、これから作成するHTMLエディ

タが開くことになる。

次に、要素editorの属性classにご注目いただき

たい。同属性にクラス名を指定すると、それが内部

エディタとして認識される。

属性classには、インタフェースorg.eclipse.ui.

IEditorPartをimplementsしたクラスか、同インタフ

ェースの実装クラスを継承したクラスを指定する必

要がある。ここでは、同インタフェースの実装クラス

org.eclipse.ui.editors.text.TextEditor(これがプラ

ットフォーム・テキスト・エディタの実体である)を継承

したクラスHtmlEditorを指定することにする。

なお、外部エディタを指定したい場合には、属性

classの代わりに、属性command、あるいはlaun

cherを指定する(これら3つの属性のうち、どれか1

つしか指定することはできない)。

属性classを記述した場合、属性contributor

Classも併せて記述しなければならない。同属性に

は、インタフェースorg.eclipse.ui.IEditorActionBar

Contributorをimplementsしたクラスを指定する必

要がある。ここでは、プラットフォーム・テキスト・エデ

ィタのアクションを管理するクラス(以下、コントリビ

ュータ・クラス)であるorg.eclipse.ui.editors.text.

TextEditorActionContributorを継承したクラス

HtmlEditorActionContributorを指定する。

Part 3独自プラグインによる機能追加

パッケージ名※

クラス名 

MyhtmleditPlugin

HtmlEditor

HtmlDocumentProvider

HtmlSourceViewerConfiguration

HtmlPartitionScanner

HtmlDefScanner

HtmlCommentScanner

HtmlTagScanner

HtmlTagRule

HtmlWhitespaceDetector

HtmlColorProvider

HtmlContentAssistProcessor

HtmlEditorMessage

HtmlEditorActionContributor

InsertImgAction

InsertImgDialog

InsertTableAction

InsertTableDialog

PreviewBrowserAction

ActionsMessage

HtmlEditorPreferencePage

PreviewPreferencePage

PreferenceMessages

NewHtmlFileWizard

NewHtmlFileCreationPage

WizardMessages

継承しているクラス/implementsしているインタフェース

クラスorg.eclipse.ui.plugin.AbstractUIPlugin

クラスorg.eclipse.ui.editors.text.TextEditor

クラスorg.eclipse.ui.editors.text.FileDocumentProvider

クラスorg.eclipse.jface.text.source.SourceViewerConfiguration

クラスorg.eclipse.jface.text.rules.RuleBasedPartitionScanner

クラスorg.eclipse.jface.text.rules.RuleBasedScanner

クラスorg.eclipse.jface.text.rules.RuleBasedScanner

クラスorg.eclipse.jface.text.rules.RuleBasedScanner

クラスorg.eclipse.jface.text.rules.MultiLineRule

インタフェースorg.eclipse.jface.text.rules.IWhitespaceDetector

インタフェースorg.eclipse.jface.text.contentassist.IContentAssistProcessor

クラスorg.eclipse.ui.editors.text.TextEditorActionContributor

クラスorg.eclipse.jface.action.Action

クラスorg.eclipse.jface.dialogs.Dialog

クラスorg.eclipse.jface.action.Action

クラスorg.eclipse.jface.dialogs.Dialog

クラスorg.eclipse.jface.action.Action

クラスorg.eclipse.jface.preference.FieldEditorPreferencePageインタフェースorg.eclipse.ui.IWorkbenchPreferencePage

クラスorg.eclipse.jface.preference.FieldEditorPreferencePageインタフェースorg.eclipse.ui.IWorkbenchPreferencePage

クラスorg.eclipse.jface.wizard.Wizardインタフェースorg.eclipse.ui.INewWizard

クラスorg.eclipse.ui.dialogs.WizardNewFileCreationPage

概要

プラグインのメインのクラス

プラットフォーム・テキスト・エディタを拡張したHTMLエディタ

HTMLファイルのドキュメント・プロバイダ

ソース・ビューワを構成するクラス

HTMLのルール・ベース・スキャナ

デフォルトのルール・ベース・スキャナ

HTMLコメント用のルール・ベース・スキャナ

HTMLタグ用のルール・ベース・スキャナ

HTMLタグのルール・クラス

HTMLでの空白を定義するクラス

色分け表示の色を管理するクラス

HTMLエディタ用の入力支援プロセッサ(コンテンツ・アシスト・プロセッサ)

リソース・バンドル・アクセッサ

HTMLエディタのコントリビュータ・クラス

「イメージ」アクション

「イメージ」ダイアログ

「表」アクション

「表」ダイアログ

「ブラウザでプレビュー」アクション

リソース・バンドル・アクセサ・クラス

HTMLエディタの「設定」ページ

「プレビュー」の設定ページ

リソース・バンドル・アクセッサ

HTMLファイル・ウィザード

HTMLファイル・ウィザードのメイン・ページ

リソース・バンドル・アクセッサ

表1:サンプル・プラグインを構成するクラス一覧

リスト1:エディタを追加するための設定

<extension point="org.eclipse.ui.editors"><editor

name="HTMLエディタ"icon="icons/myhtmledit.gif"extensions="htm, html"contributorClass

="com.samples.myhtmledit.htmleditor.actions.HtmlEditorActionContributor"class="com.samples.myhtmledit.htmleditor.HtmlEditor"id="com.samples.myhtmledit">

</editor></extension>

※ パッケージ名は、それぞれ①com.samples.myhtmledit、②com.samples.myhtmledit.htmleditor、③com.samples.myhtmledit.preference、④com.samples.myhtmledit.preference、⑤com.samples.myhtmledit.wizardである。

p062-077_特集part3 04.1.11 8:11 PM ページ 063

Page 3: Eclipse Plugin Development Part 3

064 JavaWorld 2004 March

属性contributorClassに指定されたクラスは、関

連するエディタがアクティブなときに、ワークベンチの

メニューおよびツール・バーに新しいエディタ・アク

ションを追加する。ワークベンチ内に、特定の種類

のエディタが複数開いている場合があるため、この

コントリビュータ・クラスはエディタ自体から分離され

ている。つまり、エディタの各インスタンスでアクショ

ン(のオブジェクト)を生成するのではなく、共用さ

れるようになっているわけだ。なお、各アクションを

アクティブなエディタに対して実行するために、メソ

ッドIEditorActionBarContributor.setActiveEditor

によって、アクティブなエディタをコントリビュータ・ク

ラスに渡すという仕組みになっている。

plugin.xmlの編集が完了したら、属性classに指

定したクラスHtmlEditorと、属性contributorClass

に指定したクラスHtmlEditorActionContributorを

作成する。「Java属性エディター」を使用して作成し

てもよいが、同エディタではスーパークラスの指定が

できないため、「新規Javaクラス」ウィザードを使用し

て作成する(この時点では、詳細に実装する必要

はない)。

以上で、Step 1は完了である。作成したプラグイ

ンを実行してみると、画面1のような結果となる。「リ

ソース」パースペクティブの「ナビゲーター」において、

HTMLファイルのアイコンが、追加したエディタのア

イコンに変更されていることがわかる。ここで、

HTMLファイルを選択してポップアップ・メニューの

「アプリケーションから開く」を選ぶか、あるいは

HTMLファイルのアイコンをダブルクリックすると、追

加したHTMLエディタが表示される。同エディタのタ

ブに、ファイル名とアイコンが表示されていることが

わかるはずだ。

プラットフォーム・テキスト・エディタを拡張して独自

エディタを作成する場合、「ドキュメント・プロバイダ」

を作成したり、「ソース・ビューワ」を構成したりする必

要がある。Step 2では、これらのうち、まずドキュメ

ント・プロバイダを作成する。

プラットフォーム・テキスト・エディタを拡張するため

には、同エディタの構造について知っておく必要が

ある。プラットフォーム・テキスト・エディタを構成する

クラスの関係を、MVC(Model-View-Controller)の

かたちで表現すると、図1のようになる。

ご覧のように、Modelは、クラスorg.eclipse.

jface.text.Document(インタフェースorg.eclipse.jfa

ce.text.IDocumentの実装クラス)として実装されて

おり、ControllerはクラスTextEditorおよびorg.

eclipse.jface.text.source.SourceViewerとして実装

されている。一方、Viewは、クラスorg.eclipse.swt.

custom.StyledTextを利用して実現されている。

ControllerとModelの間に位置するクラスorg.eclip

特 集

Eclipse実践!

開発

Controller View

Model

クラスTextEditor+

クラスSourceViewerクラスStyledText

クラスDocumentクラスFileDocumentProvider

画面1:「HTMLエディタ」を追加した結果

図1:プラットフォーム・テキスト・エディタを構成するクラス群

Step2 ドキュメント・プロバイダの追加

p062-077_特集part3 04.1.11 8:11 PM ページ 064

Page 4: Eclipse Plugin Development Part 3

065JavaWorld2004 March

Tutorial for Eclipse Plugin Development

se.ui.editors.text.FileDocumentProviderは、

Documentオブジェクトを表示モデルにマッピングす

る方法を管理する。

以下、上に挙げたクラスのうち、主要なものにつ

いて解説を加えよう。

クラスTextEditor

プラットフォーム・テキスト・エディタの中心となるの

が、クラスTextEditorだ。同クラスは、プラットフォー

ム・テキスト・エディタの実装そのものであり、

「org.eclipse.ui.DefaultTextEditor」というIDが割

り当てられている。

クラスTextEditorは、パッケージorg.eclipse.

ui.editors.textに含まれている。このパッケージで

は、標準のプラットフォーム・テキスト・エディタとファ

イル・ベースのドキュメント・プロバイダが提供されて

いる。

通常、Eclipseにエディタを追加する場合には、イ

ンタフェースIEditorPartの実装クラスを作成する必

要がある。テキスト・エディタに関しては、同インタフ

ェースをそれ専用に拡張したものとして、インタフェー

スorg.eclipse.ui.texteditor.ITextEditorが用意さ

れている。さらに、同インタフェースの実装クラス(抽

象クラス)として、org.eclipse.ui.texteditor.Abstract

TextEditorも提供されている。テキスト・ベースのエ

ディタを開発する場合には、同クラスのサブクラスを

作成するという方法をとることもできる。

なお、パッケージorg.eclipse.ui.texteditorでは、

テキスト・エディタ用のフレームワーク(「プラットフォー

ム・テキスト・フレームワーク」)が提供されている。プ

ラットフォーム・テキスト・エディタも、同フレームワーク

を利用して実現されている。

クラスSourceViewer

クラスSourceViewerは、テキスト・データ用のビュ

ーワである。ここで言うビューワとは、JFaceによって

提供されている共通のUIを実装したものであり、テ

キスト・ビューワ以外に、リスト、ツリー、テーブルなど

が用意されている。

クラスSourceViewerは、インタフェースorg.eclipse.

jface.text.source.ISourceViewerをimplementsし、

さらにクラスorg.eclipse.jface.text.TextViewerを継

承している。このクラスTextViewerは、インタフェー

スITextViewerの実装クラスであり、ビューポート

(viewport)などのリスナをサポートするとともに、ダ

ブルクリックに対応する機能や、自動インデント機

能、アンドゥの管理機能などを提供する。

クラスSourceViewerのオブジェクトは、クラスText

Editorによって生成されるため、クラスSource

Viewerのサブクラスを作成しておく必要はない。ク

ラスTextEditorによってSourceViewerオブジェクト

が生成される際に、その内容を構成するためのク

ラスorg.eclipse.jface.text.source.SourceViewer

Configurationが提供されているので、それを利用

すればよい。同クラスを使えば、「色分け表示機能」

や「入力支援機能」などのうち、どの機能をエディタ

に追加するかを指定することができる。これらの機

能を追加する場合には、同クラスのメソッドをオーバ

ーライドして、独自に実装を行うことになる。

クラスFileDocumentProvider

クラスFileDocumentProviderは、インタフェース

org.eclipse.ui.texteditor.IDocumentProviderの

実装クラスである。同クラスは、ファイル・リソースに

特化したクラスであり、ドキュメント・コンテンツを作

成/管理する。具体的には、Documentオブジェク

トに適用された変更に関する情報をエディタに通知

するという役割を担う。

FileDocumentProviderオブジェクトがTextEditor

オブジェクトに関連づけられると、エディタからの入力

を基にDocumentオブジェクトが生成される。さらに、

後述する「ドキュメント・パーティショナ」が作成されて、

Documentオブジェクトとドキュメント・パーティショナ

が関連づけられる。

ドキュメント・プロバイダの追加方法

それでは、Step 2の本題であるドキュメント・プロ

バイダの追加方法を説明しよう。

Part 3独自プラグインによる機能追加

p062-077_特集part3 04.1.11 8:11 PM ページ 065

Page 5: Eclipse Plugin Development Part 3

066 JavaWorld 2004 March

まず、Step 1で作成したクラスHtmlEditorのコン

ストラクタで、ドキュメント・プロバイダを作成/設定

する。コンストラクタの記述はリスト2のようになる。

本稿のサンプル・プラグインでは、ドキュメント・プ

ロバイダとして、クラスFileDocumentProviderのサ

ブクラスHtmlDocumentProviderを作成した(リス

ト3)。同クラスのメソッドcreateDocumentでは、ド

キュメント(のオブジェクト)およびドキュメント・パー

ティショナを生成する。ドキュメント・パーティショナと

は、パーティションと呼ばれる非オーバーラップ領域

にドキュメントを分割する機能を持つオブジェクトだ。

このサンプルでは、ドキュメント・パーティショナと

して、プラットフォーム・テキスト・フレームワークによっ

て提供されているクラスorg.eclipse.jface.text.rules.

DefaultPartitionerを使用する。クラスHtmlDocum

entProviderでは、メソッドconnectとメソッドsetDo

cumentPartitionerによって、ドキュメント(IDo

cumentオブジェクト)とドキュメント・パーティショナを

関連づけている。本稿の例の場合、ドキュメント・

パーティショナは、HTMLタグのパーティションと

HTMLコメントのパーティション、それ以外のパーテ

ィションに分割するという役割を果たす。

リスト3では、クラスHtmlPartitionScannerという

クラスも使用している。これは、ルール・ベース・スキ

ャナであるクラスorg.eclipse.jface.text.rules.Rule

BasedPartitionScannerのサブクラスとして作成した。

クラスRuleBasedPartitionScannerのサブクラスで

は、トークンとそれ以外を区別するためのルールを

設定する必要がある。クラスHtmlPartitionScanner

のコンストラクタでは、HTMLのコメント用のルールと

タグ用のルールを設定している(リスト4)。

以上で、Step 2は完了である。なお、ドキュメン

ト・プロバイダを追加しても、HTMLエディタの見た

目などに変わりはない。ドキュメント・プロパテイダは、

次の色分け表示機能に利用する。

Step 3では、色分け表示機能(Syntax Color

ing)を追加する。ここでは、HTMLのタグ部分、コ

メント部分、それ以外、という構文ごとに色分けし

て表示されるようにする。また、「ウィンドウ」メニュー

特 集

Eclipse実践!

開発

リスト3:クラスHtmlDocumentProvider

…略…

public class HtmlDocumentProvider extends FileDocumentProvider {private final static String[] TYPES = new String[] {

HtmlPartitionScanner.HTML_TAG,HtmlPartitionScanner.HTML_COMMENT

};

protected IDocument createDocument(Object element)throws CoreException {IDocument document = super.createDocument(element);

if (document != null) {HtmlPartitionScanner scanner = new HtmlPartitionScanner();IDocumentPartitioner partitioner

= new DefaultPartitioner(scanner, TYPES);partitioner.connect(document);document.setDocumentPartitioner(partitioner);

}return document;

}}

リスト4:クラスHtmlPartitionScannerのコンストラクタ

public HtmlPartitionScanner() {super();IToken htmlcomment = new Token(HTML_COMMENT);IToken htmltag = new Token(HTML_TAG);

List rules = new ArrayList();

rules.add(new MultiLineRule("<!--", "-->", htmlcomment));rules.add(new HtmlTagRule(htmltag));

IPredicateRule[] result = new IPredicateRule[rules.size()];rules.toArray(result);setPredicateRules(result);

}

画面2:色の設定ページ

Step3 色分け表示機能の追加

リスト2:クラスHtmlEditorのコンストラクタ

public HtmlEditor() {super();HtmlDocumentProvider documentProvider = new HtmlDocumentProvider();setDocumentProvider(documentProvider);

}

p062-077_特集part3 04.1.11 8:11 PM ページ 066

Page 6: Eclipse Plugin Development Part 3

067JavaWorld2004 March

Tutorial for Eclipse Plugin Development

で「設定」→「HTMLエディタ」を選ぶと、ユーザーが

色の設定もできるようにするために、画面2のような

「設定」ページを追加する。

色の設定ページの組み込み

色の設定ページをEclipseに組み込むには、拡張

ポイントorg.eclipse.ui.preferencePagesを利用す

る。plugin.xmlの指定はリスト5のようになる。

属性nameには、「設定」ページの左側のツリーに

表示されるページの名前を指定する。この例では、

属性categoryを指定していないので、ツリーのトッ

プ・レベルに「HTMLエディタ」と表示される。

属性classには、インタフェースorg.eclipse.ui.I

WorkbenchPreferencePageをimplementsしたク

ラスを指定する必要がある。このサンプルでは、そ

のクラスをHtmlEditorPreferencePageという名前

で作成した。「設定」ページは、クラスorg.eclipse.

jface.preference.PreferencePageのサブクラスで実

現することもできるのだが、ここではクラスorg.ecl

ipse.jface.preference.FieldEditorPreferencePage

のサブクラスとして実装することにする。

クラスFieldEditorPreferencePageのサブクラス

では、ページにSWTコントロールを配置する代わり

に、「フィールド・エディタ(キーと値の対を扱うエディ

タ)」を配置する。フィールド・エディタの配置は、リス

ト6のようにメソッドcreateFieldEditorsで行う。フィ

ールド・エディタは、パッケージorg.eclipse.jface.pre

ferenceで定義されており、クラスBooleanFieldEd

itor、ColorFieldEditor、FontFieldEditor、Radio

GroupFieldEditor、StringFieldEditorなどがある。

続いて、色の設定ページの各コントロールの初期

値を設定する。初期値の設定は、プラグインのメイ

ンのクラスMyhtmleditPluginのメソッドinitializeD

efaultPreferencesで行う(リスト7)。

ソース・ビューワの構成

テキスト・エディタに色分け表示機能を追加する

には、ソース・ビューワ(のオブジェクト)を構成する必

要がある。先述したように、Eclipseでは、ソース・ビ

ューワを構成するためにクラスSourceViewerConfig

urationが提供されているので、クラスHtmlEditor

のコンストラクタでメソッドsetSourceViewerConfi

gurationを呼び出せばよい(リスト8のコードをリス

ト2の「super( )」の後に追加する)。

ソース・ビューワを構成する際には、「表示リコンサ

イラ」を定義する必要がある。表示リコンサイラは、

文書に適用された変更ごとに、ビジュアルな表記の

うち、どの領域が無効になるか、またそれをどのよ

うに修復するかを決定するという役割を果たす。

プラットフォーム・テキスト・エディタでは、「損傷

Part 3独自プラグインによる機能追加

リスト5:「設定」ページを組み込むための設定

<extension point="org.eclipse.ui.preferencePages"><page

name="HTMLエディタ"class="com.samples.myhtmledit.preference.HtmlEditorPreferencePage"id="com.samples.myhtmledit.PreferencePage">

</page></extension>

リスト6:クラスHtmlEditorPreferencePageのメソッドcreateFieldEditors

public void createFieldEditors() {Composite parent = getFieldEditorParent();String labelText = "";

labelText = PreferenceMessages.getString("タグ色(&T):");ColorFieldEditor colorTag = new ColorFieldEditor(

MyhtmleditPlugin.PREFERENCE_TAGCOLOR, labelText, parent);addField(colorTag);

labelText = PreferenceMessages.getString("文字列(&S):");ColorFieldEditor colorString = new ColorFieldEditor(

MyhtmleditPlugin.PREFERENCE_STRINGCOLOR, labelText, parent);addField(colorString);

labelText = PreferenceMessages.getString("コメント(&C):");ColorFieldEditor colorComment = new ColorFieldEditor(

MyhtmleditPlugin.PREFERENCE_COMMENTCOLOR, labelText, parent);addField(colorComment);

}

リスト7:クラスMyhtmleditPluginのメソッドinitializeDefaultPreferences

protected void initializeDefaultPreferences(IPreferenceStore store) {super.initializeDefaultPreferences(store);

Color tagColor= Display.getDefault().getSystemColor(DEFAULT_TAGCOLOR);

store.setDefault(PREFERENCE_TAGCOLOR,StringConverter.asString(tagColor.getRGB()) );

Color stringColor= Display.getDefault().getSystemColor(DEFAULT_STRINGCOLOR);

store.setDefault(PREFERENCE_STRINGCOLOR,StringConverter.asString(stringColor.getRGB()));

Color commentColor= Display.getDefault().getSystemColor(DEFAULT_COMMENTCOLOR);

store.setDefault(PREFERENCE_COMMENTCOLOR,StringConverter.asString(commentColor.getRGB()));

}

リスト8:クラスHtmlEditorのコンストラクタに追加するコード

colorProvider= MyhtmleditPlugin.getDefault().getColorProvider();

setSourceViewerConfiguration(new HtmlSourceViewerConfiguration(colorProvider));

p062-077_特集part3 04.1.11 8:11 PM ページ 067

Page 7: Eclipse Plugin Development Part 3

068 JavaWorld 2004 March

(Damager:ダメージャ)」、「修復(Repairer:リペア

ラ)」、および「調整(Reconciler:リコンサイラ)」のモ

デルにより、色分け表示機能が提供されている。こ

れらのうち、ダメージャは文書の変更が行われたた

めに、再構築しなければならない領域を決定し、リ

ペアラは再構築の処理を行う。このモデルにおけ

る処理の概要は、以下のようになる。

①表示リコンサイラは、それと関連するビューワで、

テキストの変更をモニタする

②テキストの変更の影響を受けるコンテンツ・タイプ

を判別する

③そのコンテンツ・タイプのダメージャに通知する

④テキストの変更による損傷をダメージャが計算す

⑤リペアラが修復する

表示リコンサイラの定義は、クラスHtmlSource

ViewerConfigurationのメソッドgetPresentati

onReconcilerの中で行う(リスト9)。同メソッドで

は、クラスorg.eclipse.jface.text.presentation.

PresentationReconcilerのオブジェクト(表示リコン

サイラ)を生成して、ダメージャとリペアラを設定して

いる。この処理モデルでは、ドキュメントに定義され

ているコンテンツ・タイプごとに、ダメージャとリペア

ラのペアと併せて表示リコンサイラを提供する必要

がある。そのため、この例では3つのパーティション

に対してクラスorg.eclipse.jface.text.rules.Default

DamagerRepairerのオブジェクトを生成し、メソッド

setDamager、setRepairerによって表示リコンサイ

ラに登録している。

プレファレンス・ストアの更新

ここまでで、色分け表示機能は追加されたことに

なるのだが、色の設定ページで設定が更新された

場合にも対応できるようにしておく必要がある。

色の設定ページで色が変更された場合、メソッ

ドhandlePreferenceStoreChangedが呼び出され

る。同メソッドの実装は、クラスHtmlColorProvider

に実際の処理を記述し、クラスHtmlEditorにオー

バーライドするという構成とした。クラスHtmlColor

ProviderのメソッドhandlePreferenceStoreCha

ngedでは、リスト10のように、変更後の色の情報

をorg.eclipse.jface.text.rules.Tokenオブジェクト

に設定する。

さらに、変更されたプロパティが、エディタの表示

に影響があるかどうかを判定できるようにする必要

がある。そこで、上と同様に、その処理をクラス

HtmlColorProviderのメソッドaffectsTextPres

entationに実装し、それをクラスHtmlEditorにオー

バーライドした。クラスHtmlEditorのメソッドaffe

ctsTextPresentationでは、リスト11のように、Html

特 集

Eclipse実践!

開発

リスト9:クラスHtmlSourceViewerConfigurationのメソッドgetPresentationReconciler

public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {PresentationReconciler reconciler = new PresentationReconciler();DefaultDamagerRepairer dr;dr = new DefaultDamagerRepairer(getHtmlDefScanner());reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);dr = new DefaultDamagerRepairer(getHtmlTagScanner());reconciler.setDamager(dr, HtmlPartitionScanner.HTML_TAG);reconciler.setRepairer(dr, HtmlPartitionScanner.HTML_TAG);dr = new DefaultDamagerRepairer(getHtmlCommentScanner());reconciler.setDamager(dr, HtmlPartitionScanner.HTML_COMMENT);reconciler.setRepairer(dr, HtmlPartitionScanner.HTML_COMMENT);return reconciler;

}

リスト10:クラスHtmlColorProviderのメソッドhandlePreferenceStoreChanged

public void handlePreferenceStoreChanged(PropertyChangeEvent event) {String prefKey = event.getProperty();Token token = (Token)tokenTable.get(prefKey);if (token != null) {

String colorName = preferenceStore.getString(prefKey);RGB rgb = StringConverter.asRGB(colorName);token.setData(new TextAttribute(getColor(rgb)));

}}

リスト11:クラスHtmlEditorのメソッドaffectsTextPresentation

protected boolean affectsTextPresentation(PropertyChangeEvent event) {return super.affectsTextPresentation(event) ||

colorProvider.affectsTextPresentation(event);}

画面3:HTMLファイルが色分け表示される

p062-077_特集part3 04.1.11 8:11 PM ページ 068

Page 8: Eclipse Plugin Development Part 3

069JavaWorld2004 March

Tutorial for Eclipse Plugin Development

ColorProviderオブジェクト(変数colorProvider)を

使って確認を行い、影響がある場合にtrueを返す。

以上で、色分け表示機能の追加は完了である。

プラグインを実行すると、HTMLファイルのうち、タグ

部分と文字列部分、それ以外の部分が色分けされ

て表示される(画面3)。また、色の設定ページで設

定を変更すると、その結果が反映される。

Step 4では、HTMLファイルを生成するためのウ

ィザードを追加する。

ウィザードを追加するには、拡張ポイントorg.eclip

se.ui.newWizardsを利用する。plugin.xmlには、リ

スト12の記述を追加すればよい。ご覧のように、

属性 c a t e g o r yに「 o r g . e c l i p s e . u i . B a

sic」を指定しているので、「新規」ダイアログの「シン

プル」カテゴリーに「HTMLファイル」が追加される。

属性classに指定したクラスNewHtmlFileWizard

の前に、まずウィザード・ページのクラスを作成しよ

う。ウィザード・ページは、クラスWizardNewFileCrea

tionPageを継承するクラスNewHtmlFileCreat

ionPageとして作成する(リスト13)。ここでは、画面

4のように、生成するHTMLファイルのタイトル(タブ

TITLE)を入力するコントロールを追加する。また、

「ファイル名」入力フィールドにファイル名の初期値

(「newPage1.html」)が表示されるようにする。

Part 3独自プラグインによる機能追加

リスト13:クラスNewHtmlFileCreationPage

画面4:「HTMLファイル・ウィザード」のファイル名入力用のページ

…略…

public class NewHtmlFileCreationPage extends WizardNewFileCreationPage {

private IWorkbench workbench;private static int nameCounter = 1;private Text textTitle;

public NewHtmlFileCreationPage(IWorkbench workbench, IStructuredSelection selection) {…略…

}

public void createControl(Composite parent) {super.createControl(parent);Composite composite = (Composite)getControl();this.setFileName("newPage" + nameCounter + ".html");Composite titleGroup = new Composite(composite, SWT.NONE);GridLayout layout = new GridLayout();layout.numColumns = 2;layout.marginWidth = 0;titleGroup.setLayout(layout);titleGroup.setLayoutData(new GridData(

GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));Label labelTitle = new Label(titleGroup, SWT.NONE);labelTitle.setText("タイトル(&T):");textTitle = new Text(titleGroup, SWT.BORDER);GridData data = new GridData(

GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);textTitle.setLayoutData(data);setPageComplete(validatePage());

}

protected InputStream getInitialContents() {String title = textTitle.getText();StringBuffer strbuf = new StringBuffer();strbuf.append("<HTML>¥n"); strbuf.append("<HEAD>¥n");strbuf.append("<META http-equiv=¥"Content-Type¥" "

+ "content=¥"text/html; charset=shift_jis¥">¥n");strbuf.append("<TITLE>" + title + "</TITLE>¥n");strbuf.append("</HEAD>¥n"); strbuf.append("<BODY>¥n"); strbuf.append("</BODY>¥n"); strbuf.append("</HTML>¥n"); return new ByteArrayInputStream(strbuf.toString().getBytes());

}

public boolean finish() {IFile newFile = createNewFile();if (newFile == null) {

return false; }try {

IWorkbenchWindow workbenchWindow= workbench.getActiveWorkbenchWindow();

IWorkbenchPage pageActive = workbenchWindow.getActivePage();if (pageActive != null) {

pageActive.openEditor(newFile);}

} catch (PartInitException e) {e.printStackTrace();return false;

}nameCounter++;return true;

}}

Step4 ファイル生成ウィザードの追加

リスト12:ウィザードを追加するための設定

<extension point="org.eclipse.ui.newWizards"><wizard

name="HTMLファイル"icon="icons/myhtmledit.gif"category="org.eclipse.ui.Basic"class="com.samples.myhtmledit.wizard.NewHtmlFileWizard"id="com.samples.myhtmledit.htmlwizard"><description>

新規にHTMLファイルを作成します</description><selection

class="org.eclipse.core.resources.IResource"></selection>

</wizard></extension>

p062-077_特集part3 04.1.11 8:11 PM ページ 069

Page 9: Eclipse Plugin Development Part 3

070 JavaWorld 2004 March

コントロールを追加するには、クラスWizardNew

FileCreationPageのメソッドcreateControlをクラス

NewHtmlFileCreationPageにオーバーライドする

(リスト13-①)。同メソッドでは、メソッドsetFileName

でファイル名の初期値を設定し、それ以降でSWT

のLabelオブジェクトとTextオブジェクト(パッケージ

名はともにorg.eclipse.swt.widgets)を配置する。

次に、メソッドgetInitialContentsをオーバーライ

ドし、入力されたタイトルをタグTITLEに設定して

HTMLファイルを作成する。同メソッドの実装内容

はリスト13-②のとおりだ。

最後に、メソッドfinishを実装する(リスト13-③)。

一方、クラスNewHtmlFileWizardでは、メソッド

addPagesでNewHtmlFileCreationPageオブジェ

クトを生成/追加し、メソッドperformFinishで同オ

ブジェクトのメソッドfinishを呼び出す(ソース・コー

ドは省略するので、付録CD-ROMをご参照いただ

きたい)。

以上でStep 4は完了である。「新規」ダイアログで

「HTMLファイル」を選択してファイル名とタイトルを

入力すると、HTMLファイルが生成される。

このステップでは、メイン・メニューに「挿入」メニ

ューを追加し、そのメニューに「表の挿入」、「イメー

ジの挿入」を行う各アクションを追加する。それぞ

れのアクションを選択するとダイアログが表示され、

入力された値に従って、HTMLエディタ上の現在の

カーソル位置に、タグTABLEおよびタグIMGが挿

入されるように実装する。

「表の挿入」アクションの作成

最初に、表を表示するタグTABLEを挿入するア

クションを作成する。アクションは、クラスActionを継

承するクラスInsertTableActionとして実装する。同

クラスでは、後述する「挿入」メニューにアクションを

追加するだけなので、画像イメージは必要ない。そ

のため、コンストラクタでは、ラベルだけ指定してオ

ブジェクトを生成するようにする(以下参照)。

アクション(のオブジェクト)は、現在アクティブなエ

ディタがどれであるかを知る必要がある。これを実

現するために、メソッドsetActiveEditorを以下のよ

うに実装する。

アクティブなエディタは、拡張ポイントorg.eclipse.

ui.editorsの属性contributorClassに指定したコン

トリビュータ・クラスに通知される。そのため、後でこ

のアクションを組み込むときに、Step 1で説明したコ

ントリビュータ・クラスHtmlEditorActionContributor

のメソッドsetActiveEditorの中で、このアクションの

メソッドsetActiveEditorを呼び出すように実装する

必要がある。

また、アクションがメニューなどから選択されると、

そのアクション(のオブジェクト)のメソッドrunが呼び

出される。そのため、クラスInsertTableActionのメ

ソッドrunには、「表の挿入」ダイアログを呼び出す

処理とHTMLタグを挿入する処理を記述する(リス

ト14)。以下、このメソッドrunの処理について説明

を加えよう。

現在アクティブなエディタに文字列を挿入するに

private HtmlEditor activeEditor;

public void setActiveEditor(HtmlEditor editor) {activeEditor = editor;

}

public InsertTableAction() {super("表(&T)");

}

特 集

Eclipse実践!

開発

リスト14:クラスInsertTableActionのメソッドrun

①public void run() {

InsertTableDialog dialog = new InsertTableDialog(shell);if (dialog.open() == Dialog.OK) {

String insertText = dialog.getInsertText();IEditorSite editorsite = activeEditor.getEditorSite();ISelectionProvider selectProvider

= editorsite.getSelectionProvider();ITextSelection select

= (ITextSelection)selectProvider.getSelection();int nOffset = select.getOffset();IDocumentProvider providor = activeEditor.getDocumentProvider();IDocument document

= providor.getDocument(activeEditor.getEditorInput());try {

document.replace(nOffset, 0, insertText);} catch (BadLocationException e) {

e.printStackTrace();}

}}

Step5 表/イメージの挿入機能の追加

p062-077_特集part3 04.1.11 8:11 PM ページ 070

Page 10: Eclipse Plugin Development Part 3

071JavaWorld2004 March

Tutorial for Eclipse Plugin Development

は、そのエディタ上のIDocumentオブジェクトを取

得する必要がある。ただし、IDocumentオブジェク

トはTextEditorオブジェクトから直接取得すること

はできない。そこで、リスト14のとおり、まずHtml

EditorオブジェクトのメソッドgetEditorSiteで

org.eclipse.ui.IEditorSiteオブジェクトを取得する。

続いて、同オブジェクトのメソッドgetSelection

Providerでorg.eclipse.jface.viewers.ISelecti

onProviderオブジェクトを取得する。そのうえで、

HtmlEditorオブジェクトのメソッドgetDocumentPro

viderでIDocumentProviderオブジェクトを取得し、

さらに同オブジェクトのメソッドgetDocumentを呼

び出すことで、ようやくIDocumentオブジェクトが取

得できる。後は、同オブジェクトのメソッドreplaceを

呼び出せば、文字列を挿入することができる。

なお、現在のカーソルの位置は、org.eclipse.jfa

ce.text.ITextSelectionオブジェクトから取得可能

だ。

「表の挿入」ダイアログの作成

Eclipseでは、クラスorg.eclipse.jface.dialogs.D

ialogのサブクラスを作ることで、独自のダイアログを

作成することができる。クラスDialogは、ダイアログ

を作成するための基本機能をサポートしており、

「OK」および「キャンセル」ボタンを生成する機能や

ダイアログを起動する機能を備える。クラスInsert

TableActionのメソッドrunで、InsertTableDialog

オブジェクトを生成しているが(リスト14-①)、このク

ラスInsertTableDialogがクラスDialogのサブクラス

である(リスト15)。

クラスDialogのサブクラスでは、メソッドcreate

DialogAreaにより、共通のボタン以外のコントロー

ルを配置する必要がある。クラスInsertTableDialog

のメソッドcreateDialogAreaでは、リスト15-①のよ

うにして、「行」、「列」、「幅」のSWTのTextコントロー

ルを配置する。また、リスト15-②では、メソッド

configureShellによってダイアログのタイトルを設定

している。

ここまでの実装により、画面5のようにコントロー

ルが配置されて、タイトルが表示される。

クラスDialogのサブクラスでは、メソッドokButton

Pressedをオーバーライドすることにより、ユーザー

が「OK」ボタンを押したときの処理を記述すること

ができる。クラスInsertTableDialogでは、リスト15-

③のようにメソッドokButtonPressedを実装してい

る。ご覧のように、メソッドchkIntValueで「行」と

「列」に入力された文字が数字かどうかを調べて、

数字でなければメッセージ・ダイアログを表示する

という処理だ。このチェックの結果、入力された文

字が数字であった場合、メソッドmakeInsertText

によって、挿入するタグTABLEが作成される。

Part 3独自プラグインによる機能追加

リスト15:クラスInsertTableDialog

…略…

public class InsertTableDialog extends Dialog {private String insertText;private Text rowText;private Text columnText;private Text widthText;…略…

protected Control createDialogArea(Composite parent) {Composite composite = (Composite)super.createDialogArea(parent);rowText = createTextLabelArea(composite, "行(&R):", 2, 4);rowText.setText("3");

columnText = createTextLabelArea(composite, "列(&C):", 2, 4);columnText.setText("3");

widthText = createTextLabelArea(composite, "幅(&W):", 5, 7); widthText.setText("100%");

createSeparatorLine(composite);return composite;

}

protected void configureShell(Shell newShell) {super.configureShell(newShell);newShell.setText("表の挿入");

}

protected void okPressed() {if (chkIntValue(rowText) == false) return;if (chkIntValue(columnText) == false) return;makeInsertText();super.okPressed();

}

private boolean chkIntValue(Text text) {…略…}private void makeInsertText() {…略…}

}

画面5:「表の挿入」ダイアログ

p062-077_特集part3 04.1.11 8:11 PM ページ 071

Page 11: Eclipse Plugin Development Part 3

072 JavaWorld 2004 March

メソッドchkIntValueやmakeInsertTextなど、省

略した部分については、付録CD-ROMに収録され

たサンプル・ソースを参照していただきたい。

「イメージの挿入」アクションの作成

「イメージの挿入」アクションの作成方法は、「表の

挿入」アクションのそれとほとんど同じなので、ここ

では説明を割愛し、実行結果として表示される「イ

メージの挿入」ダイアログのみを示すことにする(画

面6)。

詳細については、付録CD-ROMのサンプル・ソ

ース(クラスInsertImgActionおよびクラスInsert

ImgDialog)を参照していただきたい。

「挿入」メニューの追加

エディタに対するメニューやツール・バーなどの追

加は、コントリビュータ・クラスHtmlEditorAction

Contributorで行う。同クラスでは、リスト16-①の

ようにコンストラクタでアクションを生成する。

クラスTextEditorActionContributorのサブクラ

スでメニューにアクションを追加するには、メソッド

contributeToMenuをオーバーライドする必要があ

る。クラスHtmlEditorActionContributorのメソッド

contributeToMenuでは、リスト16-②のようにして、

「挿入」メニューを「編集」メニューの後ろに挿入し、

同メニュー(のオブジェクト)にInsertTableActionオ

ブジェクトとInsertImgActionオブジェクトを追加す

る。

表を挿入するアクションの作成法のところでも説

明したとおり、クラスHtmlEditorActionContributor

のメソッドsetActiveEditorでは、各アクションにアク

ティブなエディタを通知する必要がある。そのため、

リスト16-③のように、メソッドsetActiveEditorで、

InsertTableAction/InsertImgActionオブジェクト

のメソッドsetActiveEditorを呼び出している。

以上で、「挿入」メニューの追加は完了である。同

メニューは、HTMLエディタがアクティブなときだけ

表示される。HTMLファイルを開くと、画面7のよう

に「挿入」メニューが追加されていることが確認で

きるはずだ。

「挿入」メニューで「表」または「イメージ」を選択

すると、それぞれ画面5または画面6のダイアログが

表示される。そこで、各タグの属性値を入力すると、

現在のカーソル位置にタグが挿入される。

タグTABLE、IMG以外にも、HTMLには多くの

タグが用意されている。それぞれに対して同様に

アクションを作成すれば、より便利なエディタを実現

することができる。

このステップでは、「プレビュー機能」を追加する。

特 集

Eclipse実践!

開発

画面6:「イメージの挿入」ダイアログ

リスト16:クラスHtmlEditorActionContributor

…略…

public class HtmlEditorActionContributorextends TextEditorActionContributor {private InsertTableAction insertTableAction;private InsertImgAction insertImgAction;…略…

public HtmlEditorActionContributor() {insertTableAction = new InsertTableAction();insertImgAction = new InsertImgAction();// 後ほどコードを追加する

}

public void contributeToMenu(IMenuManager menu) {super.contributeToMenu(menu);

MenuManager insertMenu = new MenuManager("挿入(&I)");menu.insertAfter(IWorkbenchActionConstants.M_EDIT, insertMenu); insertMenu.add(insertTableAction);insertMenu.add(insertImgAction);// 後ほどコードを追加する

}

public void setActiveEditor(IEditorPart part) {super.setActiveEditor(part);

HtmlEditor editor = (HtmlEditor)part; insertTableAction.setActiveEditor(editor);insertImgAction.setActiveEditor(editor);// 後ほどコードを追加する

}

// 後ほどメソッドcontributeToToolBarを追加する}

Step6 プレビュー機能の追加

p062-077_特集part3 04.1.11 8:11 PM ページ 072

Page 12: Eclipse Plugin Development Part 3

073JavaWorld2004 March

Tutorial for Eclipse Plugin Development

ここで言うプレビュー機能とは、編集中のHTMLフ

ァイルを、ユーザーが指定したHTMLブラウザで表

示する機能のことだ。そのためには、どのブラウザ

を呼び出せばよいのかユーザーに指定してもらう必

要がある。そこで、まずそのための「設定」ページを

追加して、その後、プレビューのアクションを作成す

ることにしよう。

「設定」ページの追加

「設定」ページを追加する方法は、すでにStep 3

で説明した。それと同様に、ここでも、拡張ポイント

org.eclipse.ui.preferencePagesを利用して追加を

行う。

plugin.xmlでは、リスト17のように要素pageに

属性categoryを指定して、設定ツリーの「HTMLエ

ディタ」の子ノードとして表示されるようにする。

属性classに指定したクラスPreviewPreference

Pageは、Step 3と同様に、クラスFieldEditorPrefer

encePageを継承して作成する。クラスPreview

PreferencePageのメソッドcreateFieldEditorsで

は、リスト18のようにクラスorg.eclipse.jface.prefer

ence.FileFieldEditorを使用している。同クラスは、

ファイル・パスを入力するためのフィールド・エディタ

である。ここに、ブラウザの実行ファイルを指定する

わけだ。同クラスを使用すれば、画面8のように「ブ

ラウズ」ボタンが表示され、それをクリックするとファ

イル選択ダイアログが表示される。

「プレビュー」アクションの作成

「プレビュー」アクションは、クラスActionを継承し

たクラスPreviewBrowserActionとして作成する(リ

スト19)。本稿のサンプルでは、同クラスをツール・

バーへのアクションの追加でも使用するので、コン

ストラクタでは、イメージとラベルを指定するように実

装する(リスト19-①)。

メソッドrunは、リスト19-②のとおりである。同メ

ソッドでは、HtmlEditorオブジェクトのメソッド

isDirtyによって現在編集中のHTMLファイルが保

存されているかどうか調べ、保存されていない場合

Part 3独自プラグインによる機能追加

画面7:「挿入」メニュー

リスト17:ページを追加するための設定

<pagename="プレビュー"category="com.samples.myhtmledit.PreferencePage"class="com.samples.myhtmledit.preference.PreviewPreferencePage"id="com.samples.myhtmledit.pagePreview">

</page>

リスト18:クラスPreviewPreferencePageのメソッドcreateFieldEditors

画面8:プレビューの「設定」ページ

protected void createFieldEditors() {Composite parent = getFieldEditorParent();String labelText = "";

labelText = "ブラウザの指定(&R):";FileFieldEditor filePreview = new FileFieldEditor(

MyhtmleditPlugin.PREFERENCE_PREVIEW, labelText, parent);String[] extensions = {"*.exe"}; filePreview.setFileExtensions(extensions);addField(filePreview);

}

p062-077_特集part3 04.1.11 8:11 PM ページ 073

Page 13: Eclipse Plugin Development Part 3

…略…

public class PreviewBrowserAction extends Action {private static final String PREVIEW_IMAGE = "icons/preview.gif";private HtmlEditor activeEditor;private Shell shell;

public PreviewBrowserAction() {super("ブラウザでプレビュー(&B)");ImageDescriptor image;URL url

= MyhtmleditPlugin.getDefault().find(new Path(PREVIEW_IMAGE));if (url != null) {

image = ImageDescriptor.createFromURL(url);setImageDescriptor(image);

}String toolTipText = "ブラウザでプレビュー";setToolTipText(toolTipText);

}

…略…

public void run() {String title = "ブラウザでプレビュー";if (activeEditor.isDirty() == true) {

String message= "変更されています。プレビューの前に保存しますか?";

if (MessageDialog.openQuestion(shell, title, message) == true) {activeEditor.doSave(null);

}}

IFileEditorInput fileEditorInput= (IFileEditorInput)activeEditor.getEditorInput();

IFile file = fileEditorInput.getFile();String filePath = file.getLocation().toString();

IPreferenceStore store= MyhtmleditPlugin.getDefault().getPreferenceStore();

String browser= store.getString(MyhtmleditPlugin.PREFERENCE_PREVIEW);

if (browser.length() == 0) {String messageErr = "プレビューするブラウザが指定されていません";MessageDialog.openError(shell, title, messageErr);return;

}

String command = browser + " " + filePath;try {

Runtime.getRuntime().exec(command);} catch (IOException e1) {

e1.printStackTrace();}

}}

074 JavaWorld 2004 March

にはメッセージ・ダイアログを表示する。一方、保存

されていれば、メソッドdoSaveでHtmlEditorオブ

ジェクトに保存する。

現在エディタで編集中のファイルのパスを取得す

るには、まずメソッドgetEditorInputによりorg.

eclipse.ui.IFileEditorInputオブジェクトを取得し、

さらにメソッドgetFileによってorg.eclipse.core.res

ources.IFileオブジェクトを取得する。これにより、

ファイル・パスを知ることができる。

また、メソッドrunでは、ユーザーが「設定」ページ

で指定したブラウザの情報を取得し、もし情報が空

であれば、メッセージを表示する。

最後に、現在エディタで編集中のファイルのパス

とブラウザの指定情報を基にコマンドを組み立て、

メソッドRuntime.getRuntime.execによってブラウ

ザを呼び出す。

メニューおよびツール・バーへの追加

作成した「プレビュー」アクションをメニューおよび

ツール・バーに追加するには、クラスHtmlEditorActi

onContributorに、先ほどの「挿入」メニューで行っ

たのと同様の処理を追加する。

まず、クラスHtmlEditorActionContributorのコ

ンストラクタ(リスト16-①)に、PreviewBrowserAction

オブジェクトを生成する以下のコードを追加する。

また、メソッドcontributeToMenu(リスト16-②)

に、リスト20のコードを追加して、「ファイル」メニュー

の「印刷」の後ろ(下)に「ブラウザでプレビュー」を

追加する。

さらに、メソッドsetActiveEditorでも、ここまでに

説明したアクションと同様に、クラスPreviewBro

wserActionのメソッドsetActiveEditorを呼び出す

必要がある。そこで、リスト16-③の部分に以下のコ

ードを追加する。

クラスPreviewBrowserActionで実現するアクシ

ョンをツール・バーに追加するには、クラスTextEd

itorActionContributorのメソッドcontributeTo

ToolBarをクラスHtmlEditorActionContributorに

オーバーライドする必要がある。そこで、リスト21の

コードを同クラスに追加する。

以上で、プレビュー機能の追加は完了である。プ

レビュー機能も、HTMLエディタがアクティブなときだ

previewBrowserAction.setActiveEditor(editor);

previewBrowserAction= new PreviewBrowserAction();

リスト20:メソッドcontributeToMenuに追加するコード

IMenuManager fileMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_FILE);

if (fileMenu != null) {fileMenu.insertAfter(

IWorkbenchActionConstants.PRINT, previewBrowserAction);fileMenu.insertAfter(

IWorkbenchActionConstants.PRINT, new Separator());}

リスト19:クラスPreviewBrowserAction

…略…

public class PreviewBrowserAction extends Action {private static final String PREVIEW_IMAGE = "icons/preview.gif";private HtmlEditor activeEditor;private Shell shell;

public PreviewBrowserAction() {super("ブラウザでプレビュー(&B)");ImageDescriptor image;URL url

= MyhtmleditPlugin.getDefault().find(new Path(PREVIEW_IMAGE));if (url != null) {

image = ImageDescriptor.createFromURL(url);setImageDescriptor(image);

}String toolTipText = "ブラウザでプレビュー";setToolTipText(toolTipText);

}

…略…

public void run() {String title = "ブラウザでプレビュー";if (activeEditor.isDirty() == true) {

String message= "変更されています。プレビューの前に保存しますか?";

if (MessageDialog.openQuestion(shell, title, message) == true) {activeEditor.doSave(null);

}}

IFileEditorInput fileEditorInput= (IFileEditorInput)activeEditor.getEditorInput();

IFile file = fileEditorInput.getFile();String filePath = file.getLocation().toString();

IPreferenceStore store= MyhtmleditPlugin.getDefault().getPreferenceStore();

String browser= store.getString(MyhtmleditPlugin.PREFERENCE_PREVIEW);

if (browser.length() == 0) {String messageErr = "プレビューするブラウザが指定されていません";MessageDialog.openError(shell, title, messageErr);return;

}

String command = browser + " " + filePath;try {

Runtime.getRuntime().exec(command);} catch (IOException e1) {

e1.printStackTrace();}

}}

p062-077_特集part3 04.1.11 8:11 PM ページ 074

Page 14: Eclipse Plugin Development Part 3

075JavaWorld2004 March

Tutorial for Eclipse Plugin Development

け有効になる。HTMLエディタをアクティブにすると、

画面9のように「ファイル」メニューの「印刷」の下に

「ブラウザでプレビュー」が追加される。また、ツー

ル・バーには「ブラウザでプレビュー」のボタンが追

加される。「ファイル」メニューのほうを選ぶか、ある

いはツール・バーのボタンをクリックすると、編集中

のHTMLファイルがブラウザで表示される。

このステップでは、HTMLエディタに入力支援機

能(Content Assist:コンテンツ・アシスト)を追加す

る。この機能は、HTMLエディタ上で「<」が入力さ

れたときに、入力候補としてHTMLのタグをリストと

して表示するというものだ。

画面10は、「<」に続いて「F」と入力したことによ

り、「FONT」、「FORM」、「FRAME」などが候補とし

てリスト表示された結果である。ユーザーが入力候

補のうち、いずれかを選択すると、そのタグがその

位置に挿入される。

さらに、「編集」メニューに「コンテンツ・アシスト」を

追加して、「Ctrl」+スペース・キーを押すと、入力候

補が表示されるようにする。

プロセッサの作成

入力支援機能を追加するには、それを実現する

独自の「コンテンツ・アシスト・プロセッサ(以下、単に

プロセッサと表記する)」を作成して、ソース・ビューワ

を構成する必要がある。

プロセッサは、インタフェースorg.eclipse.jface.

text.contentassist.IContentAssistProcessorを

implementsしたクラスHtmlContentAssistProc

essorとして定義する。同クラスでは、入力候補とし

て表示するリストをメソッドcomputeCompletion

Proposalsによって設定する。同メソッドでは、ICom

pletionProposal型の配列を返せばよいので、単純

にHTMLのタグをすべて表示することにしてもかま

わないのだが、ここでは、上述した「<」に続いて「F」

Part 3独自プラグインによる機能追加

リスト21:クラスPreviewBrowserActionに追加するメソッドcontributeToToolBar

public void contributeToToolBar(IToolBarManager toolBarManager) {super.contributeToToolBar(toolBarManager);toolBarManager.add(new Separator("HtmlEditor")); toolBarManager.add(previewBrowserAction);

}

画面9:「ブラウザでプレビュー」が追加された

画面10:入力支援機能が働いた様子

Step7 入力支援機能の追加

p062-077_特集part3 04.1.11 8:11 PM ページ 075

Page 15: Eclipse Plugin Development Part 3

076 JavaWorld 2004 March

と入力した例のように、入力候補が表示されている

間に文字が入力されると、候補が絞られていくよう

に実装する。このような機能は、デフォルトではサ

ポートされていないので、独自に実装する必要があ

る。

メソッドcomputeCompletionProposalsは、リスト

22のようになる。同メソッドでは、メソッドgetWord

によって、現在のカーソル位置に入力されている文

字列を取得する。

HTMLタグのリストは、クラスHtmlContentAssist

Processor内にString型の配列(名前はfgPro

posals)として定義してある。その各要素と入力され

た文字列がマッチするかどうか順に調べていき、マ

ッチすれば、その要素を入力候補として一時的に

Vectorオブジェクトに保存する。すべて調べ終わっ

たら、必要な計算を行ったうえで、CompletionPro

posalオブジェクトを生成する。

また、HTMLエディタ上で「<」が入力されたら、自

動的に入力候補が表示されるようにするために、メ

ソッドgetCompletionProposalAutoActivation

Charactersをオーバーライドする。同メソッドは、以

下のようにchar型の配列を返すようにするだけでよ

い。

ソース・ビューワの構成

入力支援機能を追加するには、クラスHtmlSou

rceViewerConfigurationに、クラスSourceViewer

ConfigurationのメソッドgetContentAssistantをオ

ーバーライドする(リスト23)。同メソッドでは、メソッ

ドsetContentAssistProcessorによって、org.ecli

pse.jface.text.contentassist.ContentAssistantオブ

ジェクトに対して、コンテンツ・タイプごとにプロセッ

サのオブジェクトを登録する。ここでは、HTMLタグ

とデフォルト・コンテンツに対して、先ほど作成した

クラスHtmlContentAssistProcessorのオブジェクト

を登録する。ただし、HTMLのコメントの場合には

登録を行わないので、コメントの中では入力候補は

表示されない。

なお、コンテンツ・タイプごとに、異なるプロセッサ

を登録することが可能である。したがって、スクリプ

トのコンテンツ・タイプを定義して、それに対してス

クリプト用の入力候補を表示するといったことも行

える。

以上のように実装することにより、ソース・ビューワ

を構成する処理が完了した時点で、HTMLエディ

タの編集中に「<」を入力すると、入力候補が表示

されるようになる。

メニューへの追加

入力支援機能のアクションは、再ターゲット化が

可能なアクション(メニューやツール・バーをビューま

たはエディタで共有するためのグローバル・アクショ

ン)としてテキスト・エディタで定義されている。その

ため、表の挿入などのアクションとは少し実装の方

public char[]getCompletionProposalAutoActivationCharacters() {return new char[] { '<' };

}

特 集

Eclipse実践!

開発

リスト22:クラスHtmlContentAssistProcessorのメソッドcomputeCompletionProposals

public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {String word = getWord(viewer, documentOffset);

Vector proposalList = new Vector();for (int i = 0; i < fgProposals.length; i++) {

if (fgProposals[i].startsWith(word.toUpperCase())) {proposalList.add(fgProposals[i]);

}}

ICompletionProposal[] result= new ICompletionProposal[proposalList.size()];

int replacementOffset = documentOffset - word.length();int replacementLength = word.length();int index = 0;for (Iterator j = proposalList.iterator(); j.hasNext();) {

String keyWord = (String)j.next();result[index] = new CompletionProposal(keyWord,

replacementOffset, replacementLength, keyWord.length());index++;

}proposalList.removeAllElements();return result;

}

リスト23:クラスHtmlSourceViewerConfigurationのメソッドgetContentAssistant

public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {ContentAssistant assistant = new ContentAssistant();IContentAssistProcessor processor = new HtmlContentAssistProcessor();assistant.setContentAssistProcessor(

processor, HtmlPartitionScanner.HTML_TAG);assistant.setContentAssistProcessor(

processor, IDocument.DEFAULT_CONTENT_TYPE);assistant.enableAutoActivation(true);assistant.enableAutoInsert(true);return assistant;

}

p062-077_特集part3 04.1.11 8:11 PM ページ 076

Page 16: Eclipse Plugin Development Part 3

077JavaWorld2004 March

Tutorial for Eclipse Plugin Development

法が異なる。具体的には、HTMLエディタのメイン

のクラスであるHtmlEditorに、クラスTextEditorの

メソッドcreateActionsをオーバーライドする。これに

より、入力支援機能のアクションを生成する。

メソッドcreateActionsの実装はリスト24のとおり

である。同メソッドでは、クラスActionのサブクラス

であるクラスorg.eclipse.ui.texteditor.TextOpera

tionActionを利用して入力支援機能のアクション(の

オブジェクト)を生成し、メソッドsetActionDefiniti

onIdにより、そのアクションのIDを設定している。

アクションをメニューに表示するには、クラスHtml

EditorActionContributorに実装を追加する必要

がある。その内容は、ここまでに説明したアクション

の場合と同様であるが、コンストラクタでアクションを

生成する際に、クラスorg . ec l i p se . u i . t ex t e

ditor.RetargetTextEditorActionを使用する。クラ

スHtmlEditorActionContributorのコンストラクタに

追加するコードはリスト25のとおりである。

次に、同クラスのメソッドcontributeToMenuに、

「編集」メニューに「コンテンツ・アシスト」を追加する

ためのコードを追加する(リスト26)。

さらに、ここまでの例と同様に、同クラスのメソッ

ドsetActiveEditorでは、アクティブなエディタをアク

ションに通知する必要がある。そのため、以下のよ

うにRetargetTextEditorActionオブジェクト(変数

contentAssistAction)に対してメソッドsetActionを

呼び出す。

以上で、メニューへの追加処理の実装は完了

だ。このプラグインを実行すると、「編集」メニューに

「コンテンツ・アシスト」が表示される。また、HTML

エディタで「Ctrl」+スペース・キーを押すと、入力候

補が表示されるはずである。これら2つの機能を確

認してみていただきたい。

* * *

以上、本パートでは、Eclipseプラグインとして

contentAssistAction.setAction(getAction(editor,"ContentAssistProposal"));

HTMLエディタを実装する方法を説明した。プラッ

トフォーム・テキスト・フレームワークを活用すれば、

テキスト・ベースのエディタについては、かなり容易

に拡張が行えることがご理解いただけたのではな

いだろうか。

また、Eclipseの拡張性は非常に高いため、この

例のようなフレームワークがサポートされていないケ

ースでも、比較的容易に独自の機能を追加するこ

とができる。

本特集を全体を通じて、Eclipseのプラグインの

開発に焦点を当てて解説してきた。しかし、紙数に

は限りがあるため、取り上げられなかったトピックが

数多くある。EclipseのWebサイトには、プラグイン開

発に関する解説記事も用意されているので、ぜひ

そちらにも目を通してみていただきたい(http://ww

w.eclipse.org/articles/)。

Eclipseプラグインの開発は、拡張ポイントと、

Eclipseで提供されているAPIに慣れさえすれば、

通常のJavaプログラム開発と何ら変わるところはな

い。つまり、ある程度のスキルを有している人であ

れば、さまざまなプラグインを開発することができる。

“優れたプラグイン”が開発できるかどうかは、アイデ

ア次第だ。

Part 3独自プラグインによる機能追加

リスト24:クラスHtmlEditorのメソッドcreateActions

protected void createActions() {super.createActions();ResourceBundle bundle = HtmlEditorMessage.getResourceBundle();if (bundle != null) {

IAction action = new TextOperationAction(bundle, "ContentAssistProposal.", this,

ISourceViewer.CONTENTASSIST_PROPOSALS);action.setActionDefinitionId(

ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);setAction("ContentAssistProposal", action);

}}

リスト25:クラスHtmlEditorActionContributorのコンストラクタに追加するコード

ResourceBundle bundle = ActionsMessage.getResourceBundle();contentAssistAction = new RetargetTextEditorAction(

bundle, "ContentAssistProposal.");contentAssistAction.setActionDefinitionId(

ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);

リスト26:クラスHtmlEditorActionContributorのメソッドcontributeToMenuに追加するコード

IMenuManager editMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT);

if (editMenu != null) {editMenu.add(new Separator());editMenu.add(contentAssistAction);

}

p062-077_特集part3 04.1.11 8:11 PM ページ 077