IntelliJ IdeaのプラグインUIを「mavenのように」する

背景



タスクは、開発者とQAが共通のリポジトリにある約20のサーバーアプリケーション(アプリケーションのすべての部分に共通のXML構成と共通のブートストラップクラス)を起動する便利な方法を作成することでした。







Borland Delphi 6.0でGUIを最後にペイントした人にとって便利なものを作成するにはどうすればよいですか? 将来のユーザーはIntelliJ Ideaで作業するため、Maven統合プラグインのように見えて動作するプラグインを構築するために、アイデアが思いついたので、ニーズに合わせて既製のものとテーラーメイドのものを取ります。







画像







katomクラスとこれを支援する実用的なメソッドの下。







ドキュメントに関するいくつかの言葉



Ideaのプラグインに関するドキュメントは、 ここまたはHabrに関する一連の記事にあります。







このドキュメントの唯一の問題は、UIについてほとんど何も存在しないことです。幸い、 コードがあり、どのドキュメントよりも優れています。 (特にシャベルで最初の排出がある場合)







もちろん、 プラグイン/ mavenフォルダーに興味があります。







ヒントとコツ



ツールウィンドウ



ツールウィンドウを追加するために、ドキュメントで plugin.xmlの使用を提案しています。 ただし、たとえばウィンドウの初期化時間を制御する必要がある場合は、これをすべて手動で行う必要があります。







private void initToolWindow() { final ToolWindowManagerEx manager = ToolWindowManagerEx.getInstanceEx(myProject); ToolWindowEx myToolWindow = (ToolWindowEx) manager.registerToolWindow(HolyProjectPanel.ID, false, ToolWindowAnchor.RIGHT, myProject, true); myToolWindow.setIcon(IconLoader.findIcon("/icons/jesterhat.png")); final ContentFactory contentFactory = ServiceManager.getService(ContentFactory.class); final Content content = contentFactory.createContent(panel, "", false); ContentManager contentManager = myToolWindow.getContentManager(); contentManager.addContent(content); }
      
      





Ideaがプロジェクトを完全に初期化するまで待つ方法は?



サンプルコードを見つければ複雑なことはありません。







  public static void runWhenInitialized(final Project project, final Runnable r) { if (project.isDisposed()) return; if (!project.isInitialized()) { StartupManager.getInstance(project).registerPostStartupActivity(DisposeAwareRunnable.create(r, project)); return; } runDumbAware(project, r); } public static void runDumbAware(final Project project, final Runnable r) { if (DumbService.isDumbAware(r)) { r.run(); } else { DumbService.getInstance(project).runWhenSmart(DisposeAwareRunnable.create(r, project)); } }
      
      





木を育てる方法



木を成長させる前に、どこでそれを行うかを理解する必要があります。 答えは明らかです:JPanel(上記のHolyProjectPanelは、JPanelを継承するSimpleToolWindowPanelのサブクラスです (卵のアヒル、ウサギのアヒル、ショックのウサギ)

JTreeオブジェクトを作成し、コンテンツとして保存します。







UI Maven plugin'aはSimpleTreeクラスに基づいており、その使用法はJTreeと変わりませんが、オンザフライ検索などの便利な機能が追加されます。







画像







木を埋める方法



塗りつぶしはSimpleTreeBuilderを使用して行うことが提案されています。







  SimpleTreeBuilder myTreeBuilder = new SimpleTreeBuilder(tree, (DefaultTreeModel) tree.getModel(), this, null) Disposer.register(project, myTreeBuilder); myTreeBuilder.initRoot(); myTreeBuilder.expand(myRoot, null);
      
      





特に、ノードを並べ替えることができ、コンストラクターの最後の引数としてComparatorを渡すだけです。

また、次のノードから開始して、すべてのノードを更新すると便利な場合がよくあります。







 myTreeBuilder.addSubtreeToUpdate(node)
      
      





木を埋める方法



SimpleTreeおよびSimpleTreeBuilderとの類推により、SimpleNodeを使用します。 このクラスは3ペニーと同じくらい簡単です。 実装する必要のあるgetChildrenメソッドは1つだけで、ノードを描画する必要があるたびに(ウィンドウ全体を開くとき、またはサブツリーを展開するときに)呼び出されます。







この見かけの単純さは、詳細に目を向け始めると終了します。







異なる色でノード名を書く方法



画像







SimpleNodeクラスは、PresentationDataクラスのオブジェクトを使用してレンダリングされます。 使用する必要があります:







  private void updatePresentation() { PresentationData presentation = getPresentation(); presentation.clear(); presentation.addText(myName, SimpleTextAttributes.REGULAR_ATTRIBUTES); presentation.addText(" Red", new SimpleTextAttributes(Font.PLAIN, Color.RED)); presentation.addText(" Level2Node", SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES); }
      
      





特に、ノードを再描画するには同じオブジェクトを使用する必要があります。







  @Override public void handleDoubleClickOrEnter(SimpleTree tree, InputEvent inputEvent) { if(Color.RED.equals(myColor)){ myColor = Color.BLUE; } else { myColor = Color.RED; } updatePresentation(); } private void updatePresentation() { PresentationData presentation = getPresentation(); presentation.clear(); presentation.addText(myName, SimpleTextAttributes.REGULAR_ATTRIBUTES); presentation.addText(" Red", new SimpleTextAttributes(Font.PLAIN, myColor)); presentation.addText(" Level2Node", SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES); }
      
      





画像







パネルを閉じて開くたびにツリーが折り畳まれるのはなぜですか?



これは、ルートを除くすべてのノードが実際に再作成されるためです。 これを回避するには、SimpleNodeの代わりにCachingSimpleNodeクラスを使用します(実装する必要がある単一のメソッドbuildChildren()もあります)。

CachingSimpleNodeを手動で再描画するには、その上でupdate()またはupdate(PresentationData)メソッドを呼び出す必要があります。







ツリーの上にボタンを追加する方法



画像







ボタンを追加する方法は、私にはあまり明らかではありませんでした(コード内でToolsWindow自体を作成する場合-さらにその場合)。 これらは、Actionsセクションのplugin.xmlファイルに追加され、名前、アイコン、ツールチップ、その他すべてがそこで構成されます。







 <actions> <action id="HolyProject.ExpandAll" class="ui.ProcessesTreeAction$ExpandAll" text="Expand All" icon="AllIcons.Actions.Expandall"/> <action id="HolyProject.CollapseAll" class="ui.ProcessesTreeAction$CollapseAll" text="Collapse All" icon="AllIcons.Actions.Collapseall"/> <action class="actions.MyToggleAction" id="HolyProject.RefreshProcesses" icon="AllIcons.Nodes.Cvs_roots" text="Refresh HolyProjectProcesses status" description="Refresh HolyProjectProcesses status"/> <action class="actions.CommonAction" id="HolyProject.RecreateProcesses" icon="AllIcons.ToolbarDecorator.Import" text="Recreate Processes List" description="Recreate Processes List"/> <group id="HolyProject.ProcessesToolbar"> <reference id="HolyProject.RefreshProcesses"/> <reference id="HolyProject.RecreateProcesses"/> <separator/> <reference id="HolyProject.ExpandAll"/> <reference id="HolyProject.CollapseAll"/> </group> </actions>
      
      





「Toggle 'Skip Tests' Mode」のような有効/無効ボタンを追加するには、AnActionの代わりにToggleActionを使用する必要があります







UIスレッドのアクションを別のスレッドから呼び出す方法



これはパネルの開発に直接関係するものではありませんが、UIスレッドで実行する必要があるアクションを他の場所から呼び出す必要が非常に頻繁にあります。 これには方法があります:







 AppUIUtil.invokeOnEdt(() -> {/*do smth useful*/});
      
      





共有したいのはこれだけです。githubにプラグインの例があります。







頑張って








All Articles