Eclipse プラグイン開発のベスト・プラクティス

マーカー、アノテーション、デコレーターを利用する

このチュートリアルでは、マーカーを使用してリソースに対して情報をマーキングする際のベスト・プラクティスに焦点を当て、ワークベンチ内でマーカーを強調表示するために使用するアノテーションおよびデコレーターについて紹介します。拡張ポイントを継承することにより、Eclipse の組み込み関数を再利用したり、適応させたりすること、そしてテキストを編集するときにテキスト・マーカーを移動させるといった高度なリソース・マーキングを実行することが可能になります。このチュートリアルで説明するのは、プラグイン・モデルを利用した手法です。この手法によって、効率性とパフォーマンスに優れ、統合されたルック・アンド・フィールのプラグインを実現することができます。

Andy Flatt, Software Developer, IBM

Photo of Andy FlattAndy Flatt は、英国 Hursley の IBM UK Software Development Laboratory に勤める開発者です。彼の経歴には、Java、Java パフォーマンス、OSGi、結合テストが含まれます。ソフトウェア開発に携わる前は、University of Hertfordshire に在学しており、コンピューター・サイエンスで優等学士号を取得しました。


developerWorks 貢献著者レベル

Mickael Maison, Software Developer, IBM

Photo of Mickael MaisonMickael は、2009年半ばに IBM に入社して以来、IBM Java Technology Center の Runtime Deliveries 部門に勤務しています。IBM Java SDK の L3 サポート・チームの一員として働いた後、開発を担当するようになりました。余暇は音楽と旅行を楽しんでいます。



2011年 9月 30日

はじめに

IDE Eclipse 環境のプラグインを開発するときには、設計に関して考慮すべき事項がいくつかあり、それらを考慮することによって、以下のことが確実になります。

  • ユーザー・インターフェース・スレッドがロックされないこと
  • パフォーマンスに影響を与えることなく UI を修飾できること
  • データがバックグラウンドで処理されること

このチュートリアルで取り上げるのは、Eclipse プラグインを設計する際の考慮事項を踏まえて、ワークスペースに保管されたリソース関連のデータを処理し、表示する方法です。具体的には、リソースに関する情報を保管および処理するために Eclipse が提供しているマーカー・インターフェースについて詳しく見て行きます。

リソースに対するデータ・マーカーを処理する際のベスト・プラクティスを説明するために、まず、データをマーキングする方法を示します。それに続き、ユーザー・インターフェース上でマーカーを表現する方法、そしてリソースの変更に応じてマーカーを更新する方法を説明します。このコンテキストで言うリソースとは、IResource インターフェースを実装するプロジェクト、ファイル、フォルダー、Java オブジェクト (パッケージ、クラス、ソースを含む) などの Eclipse オブジェクトです。

このチュートリアルの対象読者は、基本的なプラグインを作成することはできるものの、Eclipse リソースを扱う際のベスト・プラクティスは知らないため、それを学びたいという開発者です。

個々の拡張ポイントとインターフェースについては、Eclipse.org にドキュメントが揃っています。このチュートリアルは、これらの拡張ポイントとインターフェースを組み合わせて使用する際のベスト・プラクティスを選択する上で参考となります。このチュートリアルを読んで、既存の Eclipse 関数を利用して新しい機能を提供する方法を学んでください。


パート 1: 独自のマーカーを作成する

マーカーとは何か?

マーカーを使用する目的は、リソースを変更することなく、リソースに情報をリンクさせることです。マーカーが付けられた情報の一般的な例としては、ブレークポイント、ブックマーク、コンパイル・エラーが挙げられます。コンパイル・エラーを例にとると、コンパイル・ジョブが実行されるたびに、ソースがひと通り調べられ、エラーを強調表示するための新しいマーカーが作成されます。

マーカーを拡張する

このチュートリアルの最初のパートでは、独自のマーカーを作成します。その方法は、マーカー拡張ポイントを利用して、たった 1 行のコードを作成するだけのことです。

独自のマーカーは、IMarker 拡張ポイント org.eclipse.core.resources.markers を継承することによって作成することができます。まずは、リスト 1 のコードを plugin.xml ファイルに追加してください。このコードは、これから com.ibm.mymarkers.mymarker という id を持つ My Marker という名前のマーカーを作成することを意味します。このマーカーのスーパータイプは、org.eclipse.core.resources.marker です。これは最も基本的なマーカー・タイプですが、これよりも多少具体的な関数を提供する他のスーパータイプを継承することもできます。他のスーパータイプとしては、以下のものを使用することができます。

  • org.eclipse.core.resources.problemmarker
  • org.eclipse.core.resources.textmarker

注: これらのスーパータイプは、必要に応じていくつでも使用することができます。

リスト 1. マーカーの拡張を定義するコード (plugin.xml より抜粋)
<extension point="org.eclipse.core.resources.markers" id="com.ibm.mymarkers.mymarker"
  name="My Marker">
	<super type="org.eclipse.core.resources.marker"/>
<persistent value="false"/><attribute name="description"/>
</extension>

リスト 1 では persistent 要素と attribute 要素に注目してください。この 2 つが、mymarker マーカーに対して指定するプロパティーです。persistent 要素は、マーカーをワークスペース内に保管するかどうかを指定します。もう一方の要素では、mymarkerdescription という新しい属性を持たせています。

新しいマーカーを使用する

マーカーを新規に作成する場合には、対象とするリソースで createMarker メソッドを呼び出します。その際、新規マーカーの属性を設定することもできます。

マーカーを作成するには、リスト 2 に記載するメソッドを使用することもできます。このメソッドに唯一必要な入力は、マーカーにリンクする IResource だけです。マーカーを作成した後、マーカーの属性を設定することができます。

リスト 2. 新規マーカー・タイプを作成する Java コード
public static IMarker createMarker(IResource res)
throws CoreException {
       IMarker marker = null;
//note: you use the id that is defined in your plugin.xml
       marker = res.createMarker("com.ibm.mymarkers.mymarker");
       marker.setAttribute("description," "this is one of my markers");
//note: you can also use attributes from your supertype
       marker.setAttribute(IMarker.MESSAGE, "My Marker");
       return marker;
}

マーカーを検索する

IResource に関連付けられたマーカーを検索するには、リソースに対して問い合わせを行い、特定の id を持つすべてのマーカーを取得することと、関連するリソースを検索するかどうかを指定することができます。マーカーを検索するためには、特定のリソースで findMarkers メソッドを呼び出します。メソッド呼び出しには、マーカー・タイプや検索の深さなどの引数を指定する必要があります。

リスト 3 のコードは、IResource.DEPTH_ZERO 引数を使って、該当するリソースと直接リンクするマーカーを検索します。

リスト 3. 新規マーカー・タイプを検索する Java コード
public static final String MARKER = "com.ibm.mymarkers.mymarker";

public static List<IMarker> findMarkers(IResource resource) {
        try {
               return Arrays.asList(resource.findMarkers(MARKER, true, 
	IResource.DEPTH_ZERO));
        } catch (CoreException e) {
               return new ArrayList<IMarker>();
        }
    }

リソースの深さを IResource.DEPTH_INFINITE に変更すると、そのリソースまたはその任意のサブリソースに関連するすべてのマーカーが返されます。例えば、パッケージを渡して、そのパッケージからリソースにリンクされたすべてのマーカーを取得することもできます。


パート 2: アノテーションを使用してマーカーを表示および更新する

アノテーションとは何か?

アノテーションは、エディター内で特定のテキスト領域にマークを付けるために使用します。Eclipse では、エラー、警告、ビルド問題、タスク、ブレークポイントといった情報を表示するために、アノテーションが幅広く使用されます。アノテーションは、エディターのルーラー上とテキスト上に表示されます。図 1 に一例として、構文エラーを表示するアノテーションを示します。

図 1. アノテーションの例
Java コードの左側にあるアノテーション・バーに、緑色の三角形と、白いバツが付いた赤い円が示されている編集ウィンドウのスクリーン・ショット

アノテーションの一般的な実装は、ファイルを構文解析しながら、エラーや「ToDo」タグなどを見つけ出すとマークを生成します。この処理は、ビルド時に行われるのが通常です。他のアノテーション実装は、ブレークポイントなどの永続マーカーにリンクされます。ここでは、永続マーカーを使った例を取り上げます。

ユーザーはアノテーションの表示方法を、「General (一般)」 > 「Editors (エディター)」 > 「Text Editors (テキスト・エディター)」 > 「Annotations (アノテーション)」の順に選択すると表示される設定パネルでカスタマイズすることができます。つまり、ユーザーがアノテーションをカスタマイズできるようにするために追加で行わなければならない作業はありません。

図 2. アノテーション設定パネルのスクリーン・ショット
記号とその意味の一覧を表示するアノテーション設定パネルのスクリーン・ショット

クリックして大きなイメージを見る

図 2. アノテーション設定パネルのスクリーン・ショット

記号とその意味のリストを表示するアノテーション設定パネルのスクリーン・ショット

マーカー拡張ポイントのプロパティー

このチュートリアルのパート 1 で取り上げたマーカーは、単純にデフォルトのマーカー・タイプを継承しただけです。パート 2 では、テキスト・マーカー・タイプを継承して、テキストの位置をマーキングできるようにします。このタイプのマーカーは、charStartcharEnd という 2 つの重要な属性を定義します。また、このマーカーの場合には、セッションが終わっても次のセッションで維持されるように、persistent 要素の value 属性を “true” に変更します。以上の内容を設定するには、マーカーをリスト 4 に定義されているように更新してください。

リスト 4. マーカーの拡張定義 (plugin.xml より抜粋)
<extension point="org.eclipse.core.resources.markers" id="com.ibm.mymarkers.mymarker"
  name="My Marker">
<super type="org.eclipse.core.resources.textmarker"/>
	<super type="org.eclipse.core.resources.marker"/>
<persistent value="true"/>
</extension>

アノテーション仕様の拡張を定義する

独自のアノテーションを作成するには、拡張ポイント org.eclipse.ui.editors.markerAnnotationSpecification を使用します (リスト 5 を参照)。以下のリストは、アノテーションのプロパティーとそのデフォルトの表示オプションを定義するコードです。

リスト 5. アノテーション拡張を定義するコード (plugin.xml より抜粋)
<extension point="org.eclipse.ui.editors.markerAnnotationSpecification"
id="myannotationspecification" name="MyAnnotation">
	<specification annotationType="com.ibm.example.myannotation"
			label="MyAnnotation"
			icon="icons/sample.gif"
			overviewRulerPreferenceKey="clruler"
			overviewRulerPreferenceValue="true"
			colorPreferenceKey="clcolor"
			colorPreferenceValue="255,255,0"
			textPreferenceKey="cltext"
			textPreferenceValue="true"
			verticalRulerPreferenceKey="clvertical"
			verticalRulerPreferenceValue="true"
			textStylePreferenceKey="clstyle"
			textStylePreferenceValue="BOX">
	</specification>
</extension>

この XML のなかで、仕様にリンクするために使用するのは id 属性および annotationType 属性です。カスタマイズに使用できるその他の属性については、Eclipse.org にドキュメントが用意されています (「参考文献」を参照)。

次のステップは、拡張ポイント org.eclipse.ui.editors.annotationTypes を使用して、既存のマーカーを新しいアノテーション仕様に関連付けることです。仕様に関連付けるには、仕様のアノテーション・タイプとマーカー定義の id を使用します。

リスト 6. アノテーション・タイプを定義するコード (plugin.xml より抜粋)
<extension point="org.eclipse.ui.editors.annotationTypes">
                <type markerSeverity="0"
                                        super="org.eclipse.ui.workbench.texteditor.info"
name="com.ibm.example.myannotation"markerType="com.ibm.mymarkers.mymarker"/>
</extension>

この拡張ポイントについてのさらに詳しい情報を Eclipse.org から探すには「参考文献」を参照してください。

アノテーションを作成してエディターに追加する

アノテーションを作成してエディターに追加するには、リスト 7 のコードを使用します。

リスト 7. エディターへの新規アノテーションの追加
public static void addAnnotation(IMarker marker, ITextSelection selection, 
							ITextEditor editor) {
      //The DocumentProvider enables to get the document currently loaded in the editor
      IDocumentProvider idp = editor.getDocumentProvider();

      //This is the document we want to connect to. This is taken from 
      //the current editor input.
      IDocument document = idp.getDocument(editor.getEditorInput());

      //The IannotationModel enables to add/remove/change annotation to a Document 
      //loaded in an Editor
      IAnnotationModel iamf = idp.getAnnotationModel(editor.getEditorInput());

      //Note: The annotation type id specify that you want to create one of your 
      //annotations
      SimpleMarkerAnnotation ma = new SimpleMarkerAnnotation(
				“com.ibm.example.myannotation”,marker);

      //Finally add the new annotation to the model
      iamf.connect(document);
      iamf.addAnnotation(ma,newPosition(selection.getOffset(),selection.getLength()));
      iamf.disconnect(document);
}

マーカーとアノテーションを同期させる

アノテーション・モデルは、文書の編集時にアノテーションを移動させますが、アノテーションの移動に伴ってマーカーの属性を更新することはしません。アノテーションが移動した場合には、マーカーの charStart 属性と charEnd 属性を更新しなければなりません。最後に紹介する拡張ポイントは、マーカー・アップデーターです。マーカー・アップデーターは、アノテーションの移動に伴ってマーカーを更新するために使用するクラスを定義します。

リスト 8. マーカー・アップデーターを定義するコード (plugin.xml より抜粋)
<extension point="org.eclipse.ui.editors.markerUpdaters"> 
               <updater
                       id="com.ibm.example.MarkerUpdater"
                       class="com.ibm.example.mymarker.MarkerUpdater"
                       markerType="com.ibm.mymarkers.mymarker">
               </updater>
</extension>:

アノテーションが移動されたときに実行するコードを提供するには、IMarkerUpdater インターフェースを使用します。リスト 9 に記載するクラスが、マーカー・アップデーターです。マーカー・アップデーターのコードで興味深いのは updateMarker メソッドで、上記では、このメソッドを使ってマーカーの charStart および charEnd 属性を更新しています。

リスト 9. マーカー・アップデーターのコード
public class MarkerUpdater implements IMarkerUpdater {
       /*
       *Returns the attributes for which this updater is responsible.
       *If the result is null, the updater assumes responsibility for any attributes.
       */
       @Override
       public String[] getAttribute() {
            return null;
       }

       @Override
       public String getMarkerType() {
             //returns the marker type that we are interested in updating
            return "com.ibm.mymarkers.mymarker";
       }

       @Override
       public boolean updateMarker(IMarker marker, IDocument doc, Position position) {
             try {
                 int start = position.getOffset();
                   int end = position.getOffset() + position.getLength();
                   marker.setAttribute(IMarker.CHAR_START, start);
                   marker.setAttribute(IMarker.CHAR_END, end);
                   return true;
             } catch (CoreException e) {
                   return false;
             }
       }
}

パート 3: マーキングした IResources をデコレーターによって識別する

デコレーターとは何か

Eclipse 内でワークベンチのオブジェクトに可視の情報を追加するには、デコレーターを使用します。一般にデコレーターが表示するのは、オブジェクト・タイプと、そのオブジェクトに現在関連付けられている重要なあらゆるプロパティーです。図 3 に、パッケージ・エクスプローラーでデコレーターがユーザーに対してどのように表示されるのかを示します。デコレーターは、それぞれの項目が Java ソース・ファイルなのかパッケージなのかを示すとともに、警告またはエラーが含まれるソースおよびパッケージを表すマーカー・アイコンを表示します。パッケージ・エクスプローラーでは、例えばファイルがリポジトリーと同期しているかどうかなどの、チームの詳細を追加するためにも、デコレーターが使用されます。

図 3. 記号のアイコンで修飾されたパッケージおよびソース
ファイル・アイコンに追加された黄色の円や青色の矢印などの小さな記号を示すスクリーン・ショット

独自のデコレーターを定義する

独自のデコレーターを追加する場合の最初のステップは、org.eclipse.ui.decorators 拡張ポイントを継承することです。これによって、新しいデコレーターを定義できるようにして、修飾するオブジェクトの種類を選択します。

デコレーターを定義する際には、以下のフィールドが重要です。

  • classILightweightLabelDecorator (lightweight が “true” に設定されているため) を実装するクラスの完全修飾名を指定する必要があります。
  • enablement — デコレーターを適用する Eclipse オブジェクトのリストを含めます。
リスト 10. デコレーターを定義するコード (plugin.xml より抜粋)
<extension point="org.eclipse.ui.decorators">  
	<decorator   id="com.ibm.example.filedecorator"   
			label="MyMarker Decorator"   
			state="true"   
			class= "com.ibm.example.mymarker.FileDecorator"   
			adaptable="true"   
			lightweight="true">   
		<enablement>
			<objectClass name="org.eclipse.core.resources.IResource"/>   
		</enablement>  
	</decorator>
</extension>

Eclipse.org の、拡張ポイントに関する詳細なドキュメントについては、「参考文献」を参照してください。

注: lightweight と非 lightweight の違いに注意してください。API によると、非 lightweight デコレーターは今後の Eclipse では使用が廃止されることになっています。

独自のファイル・デコレーター・クラス

独自のデコレーターの振る舞いを決定するには、FileDecorator クラスを実装する必要があります。そしてこのクラスが、ILightweightLabelDecorator を実装しなければなりません。このクラスに LabelProvider を継承させるのは賢明な方法です。そうすれば、対象とするメソッド、すなわち decorate() だけをオーバーライドすることができます。

リスト 11 に、decorate() の基本的な実装を記載します。

リスト 11. decorate() の基本実装
public void decorate(Object resource, IDecoration decoration)  {
	decoration.addOverlay(ImageDescriptor.createFromFile(FileDecorator.class, 
					"/icons/sample.gif"), IDecoration.TOP_RIGHT);
	decoration.addPrefix("My Prefix ");
	decoration.addSuffix(" My Suffix");
}

IDecoration オブジェクトを使用して、フォントや、テキストの色、背景色をカスタマイズすることもできます。

図 4. リスト 11 のIResources を修飾するコードによる結果を示すスクリーン・ショット
コードを実行した結果、修飾されたファイル・アイコンのスクリーン・ショット

decorate() の最初の引数は、修飾対象とするリソースをフィルタリングするために使用することができます。リスト 12 に一例として、特定のマーカーが含まれるリソースだけを修飾する場合に使用するコードを記載します。

リスト 12. 特定のマーカーを持つリソースの修飾
public void decorate(Object resource, IDecoration decoration) {
	if(resource instanceof IResource){
		List<IMarker> markers = MyMarkerFactory.findMarkers((IResource) resource);
		if (markers.size() > 0) {
			decoration.addSuffix("  Marker !!");
		}
	}
}

これで、チュートリアルは完了です。この後に考えられる改善には、どのようなものがあるでしょうか。

例えば、以下のような高度な改善を加えることができます。

  • マーカーに編集可能なプロパティーを追加する: これによって、ユーザーがマーカーの状態を変更できるようになります。
  • マーカーの作成および削除を自動化する: バックグラウンド処理のジョブを使用して、マーカーを自動的に作成、更新、削除します。
  • マーカー・ホバーをカスタマイズする: 高度なマーカー・ホバーを使用して、HTML やマルチメディア・コンテンツをサポートします。

このチュートリアルでは、Eclipse を使用して容易にマーカーを作成およびカスタマイズして、高度なリソース・マーキングを行いました。ぜひ、この単純ながらも強力なツールを使用して、皆さんが開発したプラグインを Eclipse IDE に完全に組み込んでください。ただし注意する点として、この機能を広範に実装しすぎると、ユーザーにとって目障りになる恐れがあります。また、「Eclipse User Interface Guidelines」(「参考文献」を参照) を考慮に入れて Eclipse のルック・アンド・フィールを維持するのは、開発者の責任です。

参考文献

学ぶために

製品や技術を入手するために

  • Eclipse Marketplace は、オープンソースと商用両方の Eclipse 関連のオファリングを見つけられる便利なポータルです。Indigo が含まれるパッケージをダウンロードして、Eclipse Marketplace クライアントにアクセスしてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Java technology
ArticleID=758662
ArticleTitle=Eclipse プラグイン開発のベスト・プラクティス
publish-date=09302011