コンテンツ・アシスタントの概念はJFaceテキスト・ビューアーの特別な実装であるクラス、org.eclipse.jface.text.source.SourceViewerに関連しています。各種のエディターを実装するために、このクラスのインスタンスはEclipseワークベンチ全体に使われています。ただしSourceViewersはEclipseワークベンチに限らず、SWTやJFace JARsの上にビルドするアプリケーションならばどれにでも使用できます。この記事ではコンテンツ・アシスタントの実装をエディター・プラグインの面から説明し、「裸の」SourceViewersでコンテンツ・アシスタントをどう使うかについてのヒントを説明します。
簡単なHTMLエディターを実装してみましょう。ここではコンテンツ・アシスタントが非常に役に立ちます。例えばコンテンツ・アシスタントで、表やリンクのようなHTMLの典型的な構造を生成したり、選択された文字列部分をスタイル・タグでまとめたりといったことができます。
時間を節約するために、このエディターの実装にNew Plug-in Projectウィザードの一つを使ってエディター・プラグインを生成します。生成されるこのエディターはXMLエディターであり、HTMLはXMLベースのマークアップ言語なので、ごくわずかな手直しだけでこのエディターをHTMLエディターに変換できます。では始めましょう。
Newウィザードを起動してPlug-in DevelopmentとPlug-in Projectを選択します。次の画面でプロジェクト名「Sample HTML Editor」を入力します。次の画面で適当なプラグインID(例えば「com.bdaum.SampleHTMLEditor」など)を決めます。下記の画面で適当なコード生成ウィザードを選択できます。図1に示すように、Plug-in with an editorを選択します。
図1. Plug-in with an editor
次の画面で、(必要あれば)挙げられているプラグイン名とプラグイン・クラス名を変更し、プロバイダー名を指定します。他はそのままにしておきます。
次の画面に進み、挙げられているEditor Class Nameを「HTMLEditor」に、Editor Nameを「Sample HTML Editor」に、File Extensionを「html, htm」に変更します(図2)。この変更で新しいエディターが、拡張子として.html または .htmを持つすべてのファイルに関連付けられます。
図2. エディターのオプション
Finishボタンをクリックして新しいエディターを生成します。ここでRun > Run as ... > Run-time workbenchで新しいワークベンチを起動します。.htm または .htmlの拡張子を持つファイルを作り(またはそういうファイルをインポートして)、新しいエディターで開きます。
間もなく分かると思いますが、このエディターにはコンテンツ・アシスタント機能がありません。Ctrlとスペースキーを押しても何も起こりません。デフォルトではSourceViewersにコンテンツ・アシスタントは無いのです。ですから、ここのHTMLエディターで使うSourceViewerを適当に設定しなければなりません。
HTMLエディターのSourceViewerの設定はSourceViewerConfigurationのサブクラスで、生成されたクラスであるXMLConfigurationで表現されます。(このクラスをHTMLConfigurationにリネームすることもできますが、本質的なことではありません。)コンテンツ・アシスタントをソース・ビューアーに追加するにはSourceViewerConfigurationメソッドgetContentAssistant()をオーバーライドする必要があります。これにはJavaエディターのコンテキスト機能Source > Override/Implement Methods...を使うのが一番で、この機能がこのメソッドのスタブを生成してくれます。ここでこのメソッドを実装し、適当なIContentAssistant型のインスタンスを返さなければなりません。
コンテンツ・アシスタントは一つ以上のコンテンツ・プロセッサーから成りますが、サポートしたいコンテンツ・タイプごとに一つのコンテンツ・プロセッサーが必要です。ソース・ビューアーが処理するドキュメントはコンテンツ・タイプごとにいくつかのパーティションに分割されます。分割はパーティション・スキャナーによって行われますが、実際、パッケージcom.bdaum.HTMLEditor.editorsにクラスXMLPartitionScannerがあります。このクラスはここでのドキュメント・タイプに3つの異なるコンテンツ・タイプを定義します。XML_DEFAULTとXML_COMMENT、それにXML_TAGです。ドキュメントによってはこれに加えてIDocument.DEFAULT_CONTENT_TYPE型のパーティションがある場合もあります。
新しいメソッドgetContentAssistant()では最初に、IContentAssistantのデフォルト実装の新しいインスタンスを作り、コンテンツ・タイプXML_DEFAULT、XML_TAG、IDocument.DEFAULT_CONTENT_TYPEに対して同じ一つのコンテンツ・アシスト・プロセッサーを実装します。HTMLコメント内でのアシストは用意しないので、コンテンツ・タイプXML_COMMENTに対するコンテンツ・アシスト・プロセッサーは生成しません。
リスト1. getContentAssistant
public IContentAssistant getContentAssistant(SourceViewer sourceViewer) {
// Create content assistant
ContentAssistant assistant = new ContentAssistant();
// Create content assistant processor
IContentAssistProcessor processor = new HtmlContentAssistProcessor();
// Set this processor for each supported content type
assistant.setContentAssistProcessor(processor, XMLPartitionScanner.XML_TAG);
assistant.setContentAssistProcessor(processor, XMLPartitionScanner.XML_DEFAULT);
assistant.setContentAssistProcessor(processor, IDocument.DEFAULT_CONTENT_TYPE);
// Return the content assistant return assistant;
}
|
HtmlContentAssistProcessorクラスはまだ存在しません。黄色い電球型のQuickFixをクリックして生成します。この新しいクラスではインターフェースIContentAssistProcessorから継承した、あらかじめ生成されたメソッドを完成させるだけです。今ここで一番興味を引くメソッドはcomputeCompletionProposals()です。このメソッドは提案すべき候補ごとに一つ、一連のCompletionProposal instancesを返します。例えば、選択候補としてHTMLの全タグを提案することもできなくはありませんが、もう少し高度なことをしたいと思います。エディターがテキスト範囲を選択した場合は、このテキストを囲めるようなスタイル・タグの一式を提案します。それ以外の場合には新しいHTML構造を生成できるようなタグを提案します。何をしたいかを図3と4に示します。
図3. structProposal
図4. styleProposal
そこでまず、エディターのSourceViewerインスタンスから現在の選択範囲を取り出します(リスト2)。
リスト2. computeCompletionProposals
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {
// Retrieve current document
IDocument doc = viewer.getDocument();
// Retrieve current selection range
Point selectedRange = viewer.getSelectedRange();
|
次に、生成されたICompletionProposalインスタンスを集めるためにArrayList instanceを生成します(リスト3)。
リスト3. computeCompletionProposals(続き)
List propList = new ArrayList();
|
テキスト範囲が選択された場合は、選択されたテキストを取り出し、スタイル・タグとして提案するものを計算します(リスト4)。
リスト4. computeCompletionProposals(続き)
if (selectedRange.y > 0) {
try {
// Retrieve selected text
String text = doc.get(selectedRange.x, selectedRange.y);
// Compute completion proposals
computeStyleProposals(text, selectedRange, propList);
} catch (BadLocationException e) {
}
} else {
|
それ以外の場合はリスト5に示すように、ドキュメントからクォリファイアーを取り出します。こうしたクォリファイアーは部分的に入力されたHTMLタグの文字すべてから成り、提案候補を制限するために使われます。
リスト5. computeCompletionProposals(続き)
// Retrieve qualifier
String qualifier = getQualifier(doc, documentOffset);
// Compute completion proposals
computeStructureProposals(qualifier, documentOffset, propList);
}
|
最後に、補完候補のリストを配列に変換し、この配列を結果として返します(リスト6)。
リスト6. computeCompletionProposals(続き)
// Create completion proposal array
ICompletionProposal[] proposals = new ICompletionProposal[propList.size()];
// and fill with list elements
propList.toArray(proposals);
// Return the proposals
return proposals;
}
|
ではどうやって現在のドキュメントからクォリファイアーを取り出すかを見てみましょう。リスト7に示すようにgetQualifier()メソッドを実装する必要があります。
リスト7. getQualifier
private String getQualifier(IDocument doc, int documentOffset) {
// Use string buffer to collect characters
StringBuffer buf = new StringBuffer();
while (true) {
try {
// Read character backwards
char c = doc.getChar(--documentOffset);
// This was not the start of a tag
if (c == '>' || Character.isWhitespace(c))
return "";
// Collect character
buf.append(c);
// Start of tag. Return qualifier
if (c == '<')
return buf.reverse().toString();
} catch (BadLocationException e) {
// Document start reached, no tag found
return "";
}
}
}
|
これは非常に簡単です。現在のドキュメント・オフセットから始め、ドキュメントの文字を後ろから読んだわけです。オープン・ブラケット(<記号)を検出したらタグの開始を見つけたことになり、集めた文字の順番を逆にしてから返します。タグの開始が見つからない他の場合には、空のストリングを返します。この場合、候補は制限されません。
では、補完候補をコンパイルしましょう。リスト8はこうした提案を構成するタグとして関係あるもの一式です。追加したければもっと追加することもできます。
リスト8. 提案の一式
// Proposal part before cursor
private final static String[] STRUCTTAGS1 =
new String[] { "<P>", "<A SRC=\"", "<TABLE>", "<TR>", "<TD>" };
// Proposal part after cursor
private final static String[] STRUCTTAGS2 =
new String[] { "", "\"></A>", "</TABLE>", "</TR>", "</TD>" }
|
ご覧の通り、各タグ提案を2つに分けました。予定したカーソル位置の前と後です。リスト9はこれらの提案をコンパイルするcomputeStructureProposals()メソッドを示します。
リスト9. computeStructureProposals
private void computeStructureProposals(String qualifier, int documentOffset, List propList) {
int qlen = qualifier.length();
// Loop through all proposals
for (int i = 0; i < STRUCTTAGS1.length; i++) {
String startTag = STRUCTTAGS1[i];
// Check if proposal matches qualifier
if (startTag.startsWith(qualifier)) {
// Yes -- compute whole proposal text
String text = startTag + STRUCTTAGS2[i];
// Derive cursor position
int cursor = startTag.length();
// Construct proposal
CompletionProposal proposal =
new CompletionProposal(text, documentOffset - qlen, qlen, cursor);
// and add to result list
propList.add(proposal);
}
}
}
|
タグ列をループして行き、指定したクォリファイアーで始まるすべてのタグを選択します。選択された各タグに対して新しいCompletionProposalインスタンスを作ります。パラメーターとして渡すのは、完全なタグ・テキスト、このテキストを挿入する場所、置き換えるべきドキュメント中でのテキストの長さ(つまりクォリファイアーの長さ)、それに挿入テキスト開始位置に対してのカーソルの予定位置です。
このメソッドはWYSIWYG ("what you see is what you get")なので、完了提案が目で分かります。コンテンツ・アシスタントのポップアップ・ウィンドウには、提案が選択されてドキュメントに挿入された状態とまったく同じ形式で、提案がリストアップされます。
先に示した方法は、これからまだ実装する必要のあるメソッドcomputeStyleProposals()には適当ではありません。このメソッドでは選択されたテキストを選択されたスタイル・タグで囲み、ドキュメント中の選択されたテキストを新しいテキストで置き換えます。置き換えるテキストの長さは任意なので、置き換えられたテキストをコンテンツ・アシスタントの提案選択ウィンドウに表示してもあまり意味はありません。それよりも、あるスタイル提案が選択されると同時に提案選択ウィンドウに、短くても意味のあるラベルを表示し、置き換えたテキストの完全な表示はプレビュー・ウィンドウで行う方が適切です。これはCompletionProposal()コンストラクターの拡張形を使うことで実現できます。
リスト10はサポートしたいスタイル・タグとそれに関連したラベルを示します。ここでも、これにさらに追加することもできます。
リスト10. スタイル・タグの一式
private final static String[] STYLETAGS = new String[] { "b", "i", "code", "strong"
};
private final static String[] STYLELABELS = new String[] { "bold", "italic", "code", "strong"
}; |
リスト11はメソッドcomputeStyleProposals()を示します。
リスト11. computeStyleProposals
private void computeStyleProposals(String selectedText, Point selectedRange, List propList) {
// Loop through all styles
for (int i = 0; i < STYLETAGS.length; i++) {
String tag = STYLETAGS[i];
// Compute replacement text
String replacement = "<" + tag + ">" + selectedText + "</" + tag + ">";
// Derive cursor position
int cursor = tag.length()+2;
// Compute a suitable context information
IContextInformation contextInfo = new ContextInformation(null, STYLELABELS[i]+" Style");
// Construct proposal
CompletionProposal proposal = new CompletionProposal
(replacement, selectedRange.x, selectedRange.y, cursor, null, STYLELABELS[i],
contextInfo, replacement);
// and add to result list
propList.add(proposal);
}
} |
サポートしているスタイル・タグそれぞれに対し代替文字列を構成し、新しい完了提案を生成します。もちろんこの方法はちょっと安易すぎるかもしれません。本来は代替文字列をもっと詳しく見るべきでしょう。この文字列にタグが含まれていた場合には、タグに従って文字列を適当なセグメントに分割し、各単一セグメントを別々に新しいスタイル・タグで囲みます。
CompletionProposal()コンストラクターの最初の4パラメーターはcomputeStructureProposals()メソッドと同じです(代替文字列、挿入点、置き換えたテキストの長さ、挿入点に対してのカーソル位置)。5番目のパラメーターはイメージ・インスタンスを受け取ります(この例ではnullが渡されます)。このイメージはポップアップ・ウィンドウで各エントリーの左側に表示されます。6番目のパラメーターは提案選択ウィンドウに表示される、表示ラベルを受け取ります。7番目のパラメーターはIContextInformationインスタンスに使われますが、これについてはこの後説明します。最後に8番目のパラメーターは、提案が選択されたときに追加情報ウィンドウに表示されるテキストを受け取ります。ただし、単にこのパラメーターに値を入れただけでは実際に情報ウィンドウを作るには十分ではなく、コンテンツ・アシスタントも合わせて設定する必要があります。これもまたXMLConfigurationで行われます。リスト12に示すように、メソッドgetContentAssistant()に一行を追加するだけです。
リスト12. getContentAssistantに追加する
assistant.setInformationControlCreator(getInformationControlCreator(sourceViewer));
|
これで何をしているのでしょうか?まず、現在のソース・ビューアー設定からIInformationControlCreator型のインスタンスを得ます。このインスタンスはクラスDefaultInformationControlのインスタンスを生成するファクトリーですが、情報ウィンドウを管理します。次にコンテンツ・アシスタントに対し、このファクトリーのことを知らせます。するとコンテンツ・アシスタントはこのファクトリーを使って、完了提案が選択されたときに情報コントロール・インスタンスを生成します。
この情報コントロール・インスタンスはデフォルトでは、追加的な情報をプレーン・テキストで表しますが、さらに何か適当なテキスト表記を追加することも可能です。例えばすべてのタグを太字で表示したいとすると、IInformationControlCreator に生成されるDefaultInformationControlインスタンスをそれに合わせて設定する必要があります。それには一つの方法しかなく、異なるIInformationControlCreatorを使い、XMLConfigurationメソッドgetInformationControlCreator()をオーバーライドします。
SourceViewerConfigurationクラスでの、このメソッドの標準的な実装をリスト13に示します。
リスト13. getInformationControlCreator
public IInformationControlCreator getInformationControlCreator
(ISourceViewer sourceViewer) {
return new IInformationControlCreator() {
public IInformationControl createInformationControl(Shell parent) {
return new DefaultInformationControl(parent);
}
};
}
|
DefaultInformationControl()コンストラクターにDefaultInformationControl.IInformationPresenter型のテキスト・プレゼンターを追加することでDefaultInformationControlインスタンスの生成を修正します(リスト14)。
リスト14. テキスト・プレゼンターを追加する
return new DefaultInformationControl(parent, presenter);
|
残っているのは、このテキスト・プレゼンターを実装することだけです(リスト15)。
リスト15. テキスト・プレゼンター
private static final DefaultInformationControl.IInformationPresenter
presenter = new DefaultInformationControl.IInformationPresenter() {
public String updatePresentation(Display display, String infoText,
TextPresentation presentation, int maxWidth, int maxHeight) {
int start = -1;
// Loop over all characters of information text
for (int i = 0; i < infoText.length(); i++) {
switch (infoText.charAt(i)) {
case '<' :
// Remember start of tag
start = i;
break;
case '>' :
if (start >= 0) {
// We have found a tag and create a new style range
StyleRange range = new StyleRange(start, i - start + 1, null, null, SWT.BOLD)
// Add this style range to the presentation
presentation.addStyleRange(range);
// Reset tag start indicator
start = -1;
}
break;
}
}
// Return the information text
return infoText;
}
};
|
この処理はメソッドupdatePresentation()で行われます。このメソッドは表示したいテキストと、デフォルトのTextPresentationインスタンスを受け取ります。ここでは単に情報テキストの文字をループし、テキスト中の各XMLタグに対するこのテキスト・プレゼンテーション・インスタンスに、新しいスタイル範囲を追加します。この新しいスタイル範囲では前景色も背景色も変えませんが、フォント・スタイルは太字にしています。
ではメソッドcomputeStyleProposals()で生成したContextInformationインスタンスを見てみましょう。このコンテキスト情報はドキュメントに提案が挿入された後の情報を示しています。これでユーザーに対し、完了提案が適用できたことを知らせることができますが、CompletionProposal()コンストラクターにContextInformationインスタンスを渡すだけでは不十分です。メソッドgetContextInformationValidator()を完了して、このコンテキスト情報に対するバリデーターも渡す必要があります。リスト16はこれをどう行うかを示します。
リスト16. getContextInformationValidator
public IContextInformationValidator getContextInformationValidator() {
return new ContextInformationValidator(this);
}
|
ここではデフォルト実装ContextInformationValidatorを使いました。このバリデーターはメソッドcomputeContextInformation()が返すコンテキスト情報アイテム一式の中に、表示すべきコンテンツ情報が含まれているかどうかをチェックします。もし含まれていない場合はその情報は表示されません。ですからリスト17に示すように、メソッドcomputeContextInformation()も完了する必要があります。
リスト17. computeContextInformation
public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset) {
// Retrieve selected range
Point selectedRange = viewer.getSelectedRange();
if (selectedRange.y > 0) {
// Text is selected. Create a context information array.
ContextInformation[] contextInfos = new ContextInformation[STYLELABELS.length];
// Create one context information item for each style
for (int i = 0; i < STYLELABELS.length; i++)
contextInfos[i] = new ContextInformation(null, STYLELABELS[i]+" Style");
return contextInfos;
}
return new ContextInformation[0];
} |
ここでは単に各スタイルタグに対してIcontextInformationアイテムを作ります。もちろんこの方法はちょっと単純すぎています。もっときちんとした実装では、選択したテキストにどのスタイルタグを適用するかを決めるに際して、選択したテキストの周囲も見るものです。
この方法では実装したくなければ、常に真(true)を返す、独自のIcontextInformationValidatorを実装するという選択肢もあります。
ここまでで新しいコンテンツ・アシスタントの中心となるロジックができました。ただ、プラグインをテストする段になり、Ctrlとスペースキーを押してもまだ何も起きません。起きなくて当然です。Ctrlとスペースキーが押したときに完了提案のリストが要求されているということが、ソース・ビューアーにはまだ分からないのです。
スタンド・アローンのSWT/JFaceアプリケーションではベリファイ・リスナーをソース・ビューアーに追加し(リスト18参照)、Ctrlとスペースキーの組み合わせをチェックします。Ctrlとスペースキーを押すことでコンテンツ・アシスト操作が起動し、ソース・ビューアーがそれ以上キー・イベントを処理しないようにキー・イベントを拒否します。
リスト18. VerifyKeyListener
sourceViewer.appendVerifyKeyListener(
new VerifyKeyListener() {
public void verifyKey(VerifyEvent event) {
// Check for Ctrl+Spacebar
if (event.stateMask == SWT.CTRL && event.character == ' ') {
// Check if source viewer is able to perform operation
if (sourceViewer.canDoOperation(SourceViewer.CONTENTASSIST_PROPOSALS))
// Perform operation
sourceViewer.doOperation(SourceViewer.CONTENTASSIST_PROPOSALS);
// Veto this key press to avoid further processing
event.doit = false;
}
}
});
|
ただ、ワークベンチ・エディター設定内では(HTMLエディターのプラグインの場合と同様に)、イベント処理の詳細に入り込む必要はありません。ここでは単にコンテンツ・アシスト操作を起動する適当なTextOperationAction(リスト19)を生成しますが、これはクラスHTMLEditorのメソッドcreateActions()を拡張することで行います。パッケージSampleHTMLEditor内のSampleHTMLEditorPluginResources.propertiesファイルを確実に生成して、プラグイン・リソース・バンドルの要求を満足させるだけです。
リスト19. TextOperationAction
private static final String CONTENTASSIST_PROPOSAL_ID = "com.bdaum.HTMLeditor.ContentAssistProposal";
protected void createActions() {
super.createActions();
// This action will fire a CONTENTASSIST_PROPOSALS operation
// when executed
IAction action = new TextOperationAction(SampleHTMLEditorPlugin.getDefault().getResourceBundle(),
"ContentAssistProposal", this, SourceViewer.CONTENTASSIST_PROPOSALS);
action.setActionDefinitionId(CONTENTASSIST_PROPOSAL_ID);
// Tell the editor about this new action
setAction(CONTENTASSIST_PROPOSAL_ID, action);
// Tell the editor to execute this action // when Ctrl+Spacebar is pressed
setActionActivationCode(CONTENTASSIST_PROPOSAL_ID,' ', -1, SWT.CTRL);
}
|
これで再度プラグインをテストできます。今度はCtrlとスペースキーを押すことでコンテンツ・アシスタントを起動できるはずです。テキストが選択されたかどうかによってコンテンツ・アシスタントの振る舞いがどう変わるかも試してみることができます。
もうちょっとコードを追加することもできます。例えば、「<」記号が押されたときにコンテンツ・アシスタントが自動起動するようにできます。それには自動起動用の文字・記号をコンテンツ・アシスタント・プロセッサーに指定します(ドキュメントの各コンテンツ・タイプはそれぞれ特定のプロセッサーを持てるので、各コンテンツ・タイプごとに自動起動用の文字・記号を使うこともできます)。クラスHtmlContentAssistProcessor内のメソッドgetCompletionProposalAutoActivationCharactersの定義を完成させることで、この指定ができます(リスト20)。
リスト20. getCompletionProposalAutoActivationCharacters
public char[] getCompletionProposalAutoActivationCharacters() {
return new char[] { '<' };
}
|
さらに、自動起動をイネーブルにし、自動起動の遅延を設定する必要があります。これはクラスXMLConfigurationで行えます。次の行をメソッドgetContentAssistant()に追加します(リスト21)。
リスト21. getContentAssistantに追加する
assistant.enableAutoActivation(true);
assistant.setAutoActivationDelay(500);
|
最後に、追加情報ウィンドウと区別するために、コンテンツ・アシスタントのポップアップ・ウィンドウの背景色を変えたいと思います。そのために、メソッドgetContentAssistant()にさらに2行を追加します(リスト22)。
リスト22. getContentAssistantに追加する
Color bgColor = colorManager.getColor(new RGB(230,255,230));
assistant.setProposalSelectorBackground(bgColor);
|
新しい色を作るのにXMLConfigurationインスタンスのカラー・マネージャーを使ったことに注意してください。カラー・マネージャーは後処理をしてくれるので、その色が必要なくなったときにも自分で処理をせずにすみます。
HTMLマネージャーにコンテンツ・アシスタントを実装したので、今度はテンプレート・ベースのコンテンツ・アシスタントがどう動作するか、どう実装すべきかを知りたいのではないかと思います。このコンテンツ・アシスタントは(Javaソース・エディターで知っている通り)一つ特別な機能があり、完了提案がパラメーター化できるのです。提案内の特定の名前をユーザーが指定すると、提案中にあるその名前がすべて同期して変更されるという方式で手直しができるのです。
困った点としてはこの機能がEclipse Java Development Toolkit (JDT)プラグインの一部なので、このプラグインが無いアプリケーションでは(スタンドアローンのSWT/JFaceベースのアプリケーションであれ、Eclipseプラットフォームとして最小限のものであれ)この機能が使えないということです。ただ良い点として、この機能のソースコードは入手可能で他の環境への応用はそれほど難しくはありません。特に、パッケージorg.eclipse.jdt.internal.ui.text.javaのクラスExperimentalProposalとパッケージorg.eclipse.jdt.internal.ui.text.linkの型IlinkedPositionListener、LinkedPositionUI、LinkedPositionManagerはこの機能を実装しています。
- この記事で紹介している sample HTML editor jar fileをダウンロードしてください。
- Eclipseに関するより詳しい情報についてはEclipse.orgを見てください。
- Berthold Daum著のEclipse 2 for Java Developers (2003年John Wiley & Sons刊)にはJavaでのEclipse開発について分かりやすく解説されています。supporting Web siteについてのダウンロード情報もこの本に出ています。
- 「Eclipseプラグインの開発」(developerWorks 2002年12月)では簡単な「Hello, World」プラグイン生成について順を追って説明しています。
- 「EclipseでのJava Development Toolsの拡張」(developerWorks 2003年7月)ではPDEを使ってEclipseプラグインを生成する過程を、順を追って説明しています。
- developerWorksOpen source projectsゾーンのarticles for Eclipse usersには他にも記事があります。alphaWorksの最新Eclipse technology downloadsも見てみてください。
Berthold DaumはドイツLuetzelbach在住のコンサルタント兼ライターです。彼のベストセラーEclipse 2 for Java Developers の英語版が最近John Wiley & Sonsから出版されました。さらに詳しくはBerthold's Web siteを見て下さい。