There was a task to create for developers and QA a convenient way to start about 20 server applications that live in a common repository (Spring with XML configuration and a bootstrap class common to all parts of an application).
How to make something convenient to the person who last GUI painted in Borland Delphi 6.0? Take something already ready and adapt to their needs, well, since the future users are working in IntelliJ Idea, the idea to build a plugin that looks and behaves the way the Maven Integration Plugin does.
Under the cut classes and some utilitarian methods that will help to do this.
Documentation for plugins for Idea can be found here or in a series of articles on habre .
The only problem with this documentation is that there is almost nothing about UI, fortunately, there is code , and this is better than any documentation! (especially if you have the first rank on a shovel)
We are, of course, interested in the plugins / maven folder.
To add your Tool Window documentation offers to use plugin.xml. But if you need, for example, to control the window initialization time, you will have to do all this manually:
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); }
Nothing complicated if you find sample code:
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)); } }
Before you grow a tree, you need to understand where to do it. The answer is obvious: JPanel (the HolyProjectPanel mentioned above is a subclass of SimpleToolWindowPanel, which inherits from JPanel (egg in duck, duck in hare, hare in shock) .
Create a JTree object and save it as content.
The UI Maven plugin is built on the SimpleTree class, using it is no different from JTree, but it adds useful features, for example, search on the fly:
Filling is proposed to do using SimpleTreeBuilder:
SimpleTreeBuilder myTreeBuilder = new SimpleTreeBuilder(tree, (DefaultTreeModel) tree.getModel(), this, null) Disposer.register(project, myTreeBuilder); myTreeBuilder.initRoot(); myTreeBuilder.expand(myRoot, null);
Among other things, it allows you to sort the nodes, simply pass the Comparator as the last argument to the constructor.
Also, it is often useful to update all nodes starting from this:
myTreeBuilder.addSubtreeToUpdate(node)
By analogy with SimpleTree and SimpleTreeBuilder, we will use SimpleNode. This class is simple, like a penny. There is only one getChildren method that needs to be implemented and which is called every time you need to draw a node (when opening the entire window or when expanding a subtree), and several available fields with obvious names that are easy to find by auto-completion (myName, myClosedIcon, etc.).
This seeming simplicity ends when you begin to look into the details.
The SimpleNode class is drawn using the objects of the PresentationData class. it should be used:
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); }
Among other things, the same object must be used to redraw the node:
@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); }
This is because all nodes, except the root, are actually re-created. To avoid this, use the CachingSimpleNode class instead of SimpleNode (It also has the only method you need to implement: buildChildren ()).
To manually redraw CachingSimpleNode, you must call the update () or update (PresentationData) method on it.
The method of adding buttons seemed not quite obvious to me (if you create ToolsWindow itself in code, all the more). They are added in the plugin.xml file in the Actions section, names, icons, tooltips, and everything else are configured there.
<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>
To add an Enabled / Disabled button like "Toggle 'Skip Tests' Mode" you need to use ToggleAction instead of AnAction
This is not directly related to the design of the panel, but too often there is a need to trigger an action that must be performed in the UI stream, from somewhere else. There is a method for this:
AppUIUtil.invokeOnEdt(() -> {/*do smth useful*/});
That's all I wanted to share, I have an example of a plugin on the githaba .
Good luck!
Source: https://habr.com/ru/post/281851/
All Articles