プラグイン作って覚えたことを淡々と記録するよ(アイコン編)
最近,WicketForgeが参考にしていたといわれるIntelliStripesがオープンソース化してくれたので,いろいろ知れて楽しい。
やっぱりIDEAはプラグイン作りやすいぞ。ヒマと熱意があればIntelliClickとか作れそうだ。
#って作んないけどさ。:-P
しかし,この人ら,どうやってIDEAの内部情報知り得てるんだろう?intellij.netのフォーラムだけで組めているとは到底思えない。
ファイルアイコン
IntelliStripesから発見。こんな具合に特定のクラスやファイルのみアイコンを変える。
#サンプルでは,Mapのサブクラスだけアイコンを変えてみた(TestMap.javaに注目)。
やり方は簡単。application-componentにIconProviderを実装するだけでOK。
なんで,application-componentじゃないとダメとか聞かないで。だってIntelliStripesがそうやってんだもん。:-)
public class IconPlugin implements ApplicationComponent, IconProvider { public IconPlugin() { } public void initComponent() { } public void disposeComponent() { } @NotNull public String getComponentName() { return "IconPlugin"; } @Nullable public Icon getIcon(@NotNull PsiElement element, int flags) { if (element instanceof PsiClass) { PsiClass clazz = (PsiClass) element; try { // PsiUtilsは自作ユーティリティで,OpenAPIとか関係無いです。 if (PsiUtils.isSubclass(clazz, "java.util.Map")) { return IconLoader.findIcon("/icon_small.png"); } } catch (Exception ignore) { } } return null; } }
ちなみに,IntelliStripesではgetIcon()の引数でもらうPsiElementを解析して,
のアイコンを変更しておりました。
ガーターアイコン
OpenAPIのAnnotatorってのとGutterIconRendererを組み合わせて実現するんだけど,こっちは,ちょっとアンドキュメンタブルな手順を踏む。そのアンドキュメンタブルな手順ってのが,このplugin.xmlのextensionsタグのこと。
<extensions defaultExtensionNs="com.intellij"> <annotator language="JAVA" annotatorClass="com.googlecode.intellimars.icon.IconAnnotator"/> </extensions>
一応,OpenAPIのJavadocのcom.intellij.ExtensionPoints
にextensionsタグに関する説明があるんだけど,どうも完全ではないみたいで,今回紹介したannotatorのほかにも,fileTemplateGroupやらfileEditorProviderやら,いろいろ宣言できるっぽい。
#DevkitにあるStrutsAssistantを見るといい。
ちょっと,そこまで極めたいとは思わないので,とりあえずannotatorだけ。Annotatorを実装したコードは,こんな感じ。見ての通り,そんな面倒なもんじゃない。
public class IconAnnotator implements Annotator { public void annotate(PsiElement psiElement, AnnotationHolder holder) { if( psiElement instanceof PsiClass) { PsiClass clazz = (PsiClass) psiElement; // PsiUtilsは自作ユーティリティで,OpenAPIとか関係無いです。 if( PsiUtils.isSubclass(clazz, "java.util.Map") ) { final Annotation annotation = holder.createInfoAnnotation(clazz.getNameIdentifier(), "My Annotator"); annotation.setGutterIconRenderer(new GotoMarkupGutter()); } } } }
AnnotationHolderってやつで,特定の場所のAnnotatorを作るんだけど,AnnotatorはInformation/Warning/Errorの3種類あるらしい。アノテートする場所とか種類とかは,AnnotationHolderのAPIみてくれ。
あとは,作ったAnnotatorに対して,setGutterIconRenderer()を呼びガーターアイコンを指定しておしまいとなる。
public class GotoMarkupGutter extends GutterIconRenderer { @NotNull public Icon getIcon() { return IconLoader.findIcon("/actions/clean.png"); } }
上記のコード例では何もしてないが,ガーターアイコンをクリックして,なんかしかのアクション(AnAction)を仕込むことも可っぽい。
うーん,こんだけ簡単だと,逆に拍子抜けするなぁ。
ps.
どうでもいいけど,PsiUtils.isSubclass()のソース。
public class PsiUtils { public static boolean isSubclass(PsiClass clazz, String superClass) { if (clazz == null) { return false; } try { if (clazz.getQualifiedName().equals(superClass)) { return true; } } catch (NullPointerException ignore) { } if (isSubclass(clazz.getSupers(), superClass)) { return true; } else if (isSubclass(clazz.getInterfaces(), superClass)) { return true; } return false; } protected static boolean isSubclass(PsiClass[] supers, String superClass) { for (PsiClass aSuper : supers) { if (isSubclass(aSuper, superClass)) { return true; } } return false; } }
アニメーションアイコン
これは,蛇足だったかも。アニGIF貼っ付けるんじゃなく,AnimatedIconのサブクラスを作るのがIDEA流らしい。とりあえず,(↓)こんなアイコンは,
AsyncProcessIconを作って,どっかに張るだけ(AnimatedIconはJComponentの子どもです)。それに,AsyncProcessIconは,Plugin SDKにソース付いているから,AnimatedIconを自作するときの参考にするとヨロシ。
これまた,どうでもいい話だけど,JetConnectプラグインのメールアイコンもAnimatedIconの子どもです(EnvelopeIcon)。