Eclipseのプラグイン開発のJDTでのハイパーリンクについて。
|
Javaエディターで独自のハイパーリンクを行いたい。
(Javaエディター上のハイパーリンクから自分が指定したファイルへジャンプさせたい)
しかし、以前もハイパーリンクを作ったが、この方式ではIHyperlinkDetectorのインスタンス生成をSourceViewerConfigurationで行っている為、独自テキストエディターを作る場合にしか使えない。
そこで、IHyperlinkDetectorの定義をextensionで行う。
依存プラグインは「org.eclipse.ui.workbench.texteditor」。
まず、ハイパーリンクを出すことが可能かどうかを判定するクラスを作成する。
JDTのハイパーリンクはorg.eclipse.jdt.internal.ui.javaeditor.JavaElementHyperlinkDetectorが使われているようだが、例によってこのクラスは非公開(Eclipseプラグインではたとえpublicであっても、明示的に“公開”が指定されているクラスでないと使用できない)なので直接使用することは出来ない。
でも非常に参考になる。
import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.texteditor.ITextEditor;
public class MyHyperlinkDetector extends AbstractHyperlinkDetector {
@Override public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { // ハイパーリンクを表示するエディターを取得 ITextEditor editor = (ITextEditor) getAdapter(ITextEditor.class); if (editor == null) { return null; } // IJavaElementを取得 IEditorInput input = editor.getEditorInput(); IJavaElement element = (IJavaElement) input.getAdapter(IJavaElement.class); // ドキュメントを取得 IDocument document = editor.getDocumentProvider().getDocument(input); // マウスカーソルの指している位置の単語を取得 int offset = region.getOffset(); IRegion word = findWord(document, offset); if (word == null || word.getLength() == 0) { return null; } // 単語の位置のコードを取得 IJavaElement[] codes; try { ITypeRoot root = (ITypeRoot) element.getAdapter(ITypeRoot.class); codes = root.codeSelect(word.getOffset(), word.getLength()); } catch (JavaModelException e) { return null; } for (IJavaElement code : codes) { // コードの種類毎に分岐 int elementType = code.getElementType(); switch (elementType) { case IJavaElement.TYPE: //クラス IHyperlink[] tr = detectClassHyperlinks((IType) code, word); if (tr != null) { return tr; } break; case IJavaElement.FIELD: //フィールド IHyperlink[] fr = detectFieldHyperlinks((IField) code, word); if (fr != null) { return fr; } break; case IJavaElement.METHOD: //メソッド IHyperlink[] mr = detectMethodHyperlinks((IMethod) code, word); if (mr != null) { return mr; } break; } } return null; }
// @see org.eclipse.jdt.internal.ui.text.JavaWordFinder#findWord() private static IRegion findWord(IDocument document, int offset) { int start = -2; int end = -1; try { int pos; for (pos = offset; pos >= 0; pos--) { char c = document.getChar(pos); if (!Character.isJavaIdentifierPart(c)) { break; } } start = pos; pos = offset; for (int length = document.getLength(); pos < length; pos++) { char c = document.getChar(pos); if (!Character.isJavaIdentifierPart(c)) { break; } } end = pos; } catch (BadLocationException e) { } if (start >= -1 && end > -1) { if (start == offset && end == offset) { return new Region(offset, 0); } if (start == offset) { return new Region(start, end - start); } else { return new Region(start + 1, end - start - 1); } } else { return null; } }
private IHyperlink[] detectClassHyperlinks(IType type, IRegion region) { String name = type.getElementName(); 〜 return new IHyperlink[] { new MyHyperlink(name, region) }; } private IHyperlink[] detectFieldHyperlinks(IField field, IRegion region) { String name = field.getElementName(); 〜 return new IHyperlink[] { new MyHyperlink(name, region) }; } private IHyperlink[] detectMethodHyperlinks(IMethod method, IRegion region) { String name = method.getElementName(); 〜 return new IHyperlink[] { new MyHyperlink(name, region) }; } }
※IJavaElementを使わず、直接ASTNodeを使えば、例えば文字列等でも判定することが出来る。
マニフェストファイルのextensionでハイパーリンクの指定を行う。
<extension point="org.eclipse.ui.workbench.texteditor.hyperlinkDetectors"> <hyperlinkDetector activate="true" class="jp.hishidama.eclipse_plugin.dmdl_editor.jdt.hyperlink.MyHyperlinkDetector" description="Open Declared DMDL" id="dmdl-editor-plugin.hyperlinkDetector.jdt.open-declaration" name="Open Declared DMDL" targetId="org.eclipse.jdt.ui.javaCode"> </hyperlinkDetector> </extension>
targetIdに「org.eclipse.jdt.ui.javaCode」を指定することで、Javaエディターの場合だけ呼ばれるようになる。
import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.hyperlink.IHyperlink;
public class MyHyperlink implements IHyperlink { private String name; private IRegion region;
public MyHyperlink(String name, IRegion region) { this.name = name; this.region = region; }
@Override public IRegion getHyperlinkRegion() { return region; }
@Override public String getTypeLabel() { return "Open Declared DMDL"; }
@Override public String getHyperlinkText() { return "Open Declared DMDL"; }
Javaエディターでクラス名やフィールド名・メソッド名のハイパーリンクをしようとすると、既存のハイパーリンクと被ってしまう。
その場合はポップアップメニューが出て、動作をユーザーが選択できる。
その際のメニュー名はgetHyperlinkText()で返した文字列になる。
@Override public void open() { 〜 } }