📜 ⬆️ ⬇️

Development of IntelliJ IDEA plugin. Part 7

In this part: user interface components. The previous part is here .


IntelliJ IDEA includes a large number of custom Swing components. Using these components in your plugins ensures that they look and work consistent with the rest of the IDE user interface and often reduces the size of the code, compared to using standard Swing components.

Menus and toolbars


Menus and toolbars (toolbars) are built using the action system (as already described in the second part).

Tool windows


Tool windows are panels that are displayed to the left, bottom, and right of the main IntelliJ IDEA window. On each side there are two groups of instrument windows - primary and secondary, and at the same time only one group can be active.
')
Each tool window can contain several tabs (called “contents” in the API). For example, the toolwindow “Run” displays a tab for each active launch configuration, and “Changes” displays a fixed set of tabs depending on the version control system used in the project.

There are two main scenarios for using toolboxes in plugins. In the first scenario (used, for example, in Ant and Commander plugins), the tool window button is always displayed, hence the user can activate and interact with the functionality of the plugin at any time. In the second scenario (used by the “Analyze Dependencies” action) a tool window is created in order to show the results of a specific operation and can be closed by the user immediately after the operation is completed.

In the first scenario, the window is registered in the plugin.xml file using the extension point
<<toolWindow>> 
settings. The extension point attributes contain data that is used to display the toolwindow button:

In addition to this, you should specify a factory class (in the “factoryClass” attribute) that implements the ToolWindowFactory interface. When the user clicks the tool window button, the createToolWindowContent () method is called and initializes the user interface. This procedure ensures that unused tool windows do not cause any overhead in memory usage or startup time: if the user does not interact with your plug-in's toolwindow, no code will be loaded or executed.

If the tool window is not required for all types of projects, you can specify an optional conditionClass attribute that contains the fully qualified class name that implements the Condition interface (it can be the same class that implements the factory). If the value () method returns “false”, the tool window will not be displayed. Please note that the condition is calculated only once when loading the project. If you want to show and hide tool windows dynamically, while working with a project, you need to use the second tool window registration script.

Configuration example
 <extensions defaultExtensionNs="com.intellij"> <toolWindow id="My Sample Tool Window" icon="/myPackage/icon.png" anchor="right" factoryClass="myPackage.MyToolWindowFactory" /> </extensions> 

The second script is a normal call to the ToolWindowManager .registerToolWindow () method from the plugin code. This method has several overloads that can be used depending on your tasks. If you use an overload that accepts a Swing component, then it becomes the first tab displayed in the tool window.

Displaying the contents of many toolwindows requires access to indexes. Because of this, the windows are turned off when building indexes, but it will remain active if you pass “true” as the value of the canWorkInDumbMode parameter to the registerToolWindow () function.

As mentioned earlier, tool windows can contain several tabs. To manage the contents of a window, you can call ToolWindow .getContentManager (). To add a tab (“content”), you must first create it by calling ContentManager .getFactory (). CreateContent (), and then add it to the toolbox using ContentManager.addContent ().

You can determine whether the user is allowed to close tabs, either globally or individually. The latter is done by defining the canCloseContents parameter of the registerToolWindow () function, or by specifying
 <canCloseContents="true"> 
in the plugin.xml file. Even if tab closing is enabled globally, it can be disabled for a particular tab by calling
 <Content.setCloseable(false)> 
.

Dialogues


DialogWrapper is the base class for all modal (and some non-modal) dialog boxes used in the IntelliJ IDEA plugin. It provides the following features:

When using the DialogWrapper class for a custom dialog box, you must perform the following steps:

The DialogWrapper class is often used in conjunction with the UI Designer forms. To bind the form and your class that extends DialogWrapper, bind the root form panel to the field and return it from the createCenterPanel () method.

To display a dialog box, call the show () method and then use the getExitCode () method to check how the dialog box was closed.

You can override the createActions () or createLeftActions () methods to customize the buttons displayed in the dialog box (ie, replacing the standard set of OK / Cancel / Help buttons). Both of these methods return an array of Swing Action objects. If the button you add closes the dialog box, you can use DialogWrapperExitAction as the base class for the action.

To check the data entered in the dialog box, you can override the doValidate () method. The method will be called automatically by timer. If currently entered data is valid, you need to return null. Otherwise, return a ValidationInfo object that encapsulates the error message and, optionally, a component associated with incorrect data. If you specify a component, an error icon will be displayed next to it and it will receive focus when the user tries to click the OK button.

Popup windows


The IntelliJ IDEA user interface makes extensive use of pop-up windows — semi-modal windows that do not have an explicit close button and automatically disappear when the focus is lost. Using these controls in your plugin provides a single user interface between the plugin and the rest of the IDE.

Pop-up windows can have a title, can be moved if necessary and allow resizing (remembering is supported), they can be nested (it is allowed to show additional pop-up windows when an element is selected).

The JBPopupFactory interface allows you to create pop-up windows that display different types of Swing components, depending on your specific needs. The most commonly used methods are:

Action group popups support various ways to select an action using the keyboard, in addition to the usual arrow keys. By transferring the value of one of the constants to the ActionSelectionAid enumeration, you can choose whether it will be possible to select an action by pressing the numeric key corresponding to its ordinal number, entering a part of its text (accelerated search) or pressing the mnemonic symbol. For pop-up windows with a fixed set of elements, it is recommended to choose the method of ordinal numbering; for pop-ups with variable and potentially large numbers of items, an accelerated search usually works best.

If you need to create a popup popup dialog, but the usual JList does not suit you - for example, it is undesirable to collect actions into a group, you can work directly with the ListPopupStep interface and the JBPopupFactory.createListPopup () method. Usually it is not necessary to implement the entire interface; instead, you can inherit from the BaseListPopupStep class. The basic methods for overriding this are: getTextFor () (the text that is displayed for the element is returned) and onChosen () (called when the element is selected). By returning a new PopupStep from the onChosen () method, you can implement hierarchical (nested) pop-up windows.

After you have created a window, you need to display it by calling one of the show () methods. You can let IntelliJ IDEA automatically select a context-based position by calling showInBestPositionFor (), or explicitly specify a position using methods such as showUnderneathOf () and showInCenterOf (). Note that the show () methods return control immediately, rather than waiting for the pop-up window to close. If you need to perform some actions when closing a window, you can bind a listener to it using the addListener () method; or override a method similar to PopupStep.onChosen (); or attach an event handler to the corresponding component inside the popup.

Notifications


One of the leading design principles in recent versions of IntelliJ IDEA is to prevent modal windows from being used to notify users of errors and other situations that may require their attention. As a replacement, IntelliJ IDEA provides a choice of several modeless notification types.

Dialogues

When working with a modal dialog box, instead of checking the entered data when you click on the OK button and notify the user about invalid data in another modal window, it is recommended to use the DialogBuilder.doValidate () method that was described earlier.

Editor Tips

For actions called from the editor (for example, refactoring, navigation, and the like), the best way to notify the user about the impossibility of taking actions is to use the HintManager class. Its showErrorHint () method displays a window floating above the editor that disappears automatically when the user starts another action in the editor. The remaining methods of HintManager can be used to display other types of modeless notifications in the form of hints above the editor.

High Level Notifications

The most common way to display modeless notifications is to use the Notifications class. It has two main advantages:

The main method used to display the notification is Notifications.Bus.notify (). Notification text may contain HTML tags. You can allow the user to interact with the notification by including hyperlinks and passing the instance of NotificationListener into the constructor of the Notification class.

The GroupDisplayId parameter of the Notication constructor indicates the type of notification; the user can select the type of display corresponding to the type of each notification in the Settings | Notifications To specify a preferred type, you must call Notifications.Bus.register () before displaying a notification.

Select classes and files


File selection

To allow the user to select a file, directory, or several files, use the FileChooser method .chooseFiles (). This method has several overloads, one of which returns void and gets a callback function that takes a list of selected files as a parameter. This is the only overload that will display the native dialog box on Mac OS X.

The FileChooserDescriptor class allows you to control which files can be selected. The constructor parameters determine whether files and / or directories can be selected, whether multiple elements can be selected. For more precise control, you can overload the isFileSelectable () method. You can also customize the display of files by overloading the getIcon (), getName () and getComment () methods of the FileChooserDescriptor class. Note that the native Mac OS X file selection dialog does not support most of the settings, so if you rely on them, you must use the chooseFiles () method overload, which displays the standard IntelliJ IDEA dialog box.

A very common way to select a file is to use a text field to enter a path with an ellipsis ("...") to display the file selection dialog. To create such a control, use the TextFieldWithBrowseButton component and call its addBrowseFolderListener () method to configure the file picker. As an added bonus, this will allow the completion of the file name when you enter the path in the text box manually.

An alternate UI for selecting files, which is ideal when you need to search for a file by name, is available through the TreeFileChooserFactory class. The dialog box used by this API has two tabs: one shows the structure of the project, the other - a list of files similar to that used in “Goto File”. To display a dialog box, call showDialog () on the object returned from createFileChooser () and then call getSelectedFile () to get a custom selection.

Choosing a class and package

If you want to offer the user the choice of a Java class, you can use the TreeClassChooserFactory class. Its various methods allow you to specify a search scope in order to limit the selection to descendants of a particular class or interface implementations, as well as include or exclude internal classes from the list.

To select a Java package, you can use the PackageChooserDialog class.

Editor components


Compared to Swing JTextArea, the IntelliJ IDEA editor component has a lot of advantages - syntax highlighting, code completion, code folding, and much more. The editors in IntelliJ IDEA are usually displayed as editor tabs, but they can be embedded in dialog boxes or tool windows. This allows the EditorTextField component.

When creating an EditorTextField, you can specify the following attributes:

One common use case for EditorTextField is to edit the name of a Java class or package. This can be achieved using the following steps:

Lists and trees


JBList and Tree

Whenever you plan to use the standard Swing component of the JList, consider using its alternative JBList, which supports the following additional features:

Similar to JBList, there is a class com.intellij.ui.treeStructure.Tree providing a replacement for the standard JTree class. In addition to JBList features, it supports Mac-style rendering and auto-scrolling for drag & drop.

ColoredListCellRenderer and ColoredTreeCellRenderer

When you need to customize the presentation of items in a combo box or tree, it is recommended to use the classes ColoredListCellRenderer or ColoredTreeCellRenderer as a means of visualizing cells. These classes allow you to assemble views from several pieces of text with different attributes (by calling append ()) and use an additional icon for an element (by calling setIcon ()). The visualization system automatically assumes the setting of the correct text color for the selected elements and many other platform-specific rendering details.

ListSpeedSearch and TreeSpeedSearch

To facilitate the selection of items using the keyboard in the list or tree, you can apply a quick search handler to them. This can be done by a simple call.
 <new ListSpeedSeach(list)> 
or
 <new TreeSpeedSearch(tree)> 
. If you need to customize the text that is used to search for an item, you can override the getElementText () method. In addition, you can pass a function to convert elements to strings (as elementTextDelegate in the ListSpeedSearch constructor or as the toString () method in the TreeSpeedSearch constructor).

ToolbarDecorator

A very common task when developing a plugin is to display a list or tree where the user could add, delete, edit or reorder items. This task is greatly facilitated by the ToolbarDecorator class. This class contains a toolbar with actions attached to elements and automatically allows drag & drop reordering of elements in lists if it supports the underlying list model. The position of the toolbar (above or below the list) depends on the platform on which IntelliJ IDEA is running.

To use the toolbar decorator:

Swing-


Messages

Messages , ( ) ( ). . Mac OS X .

showCheckboxMessageDialog() «Do not show this again».

, , . .

JBSplitter

JBSplitter JSplitPane. , JetBrains Swing- , .. API. , , JBSplitter JSplitPane.
, setFirstComponent() setSecondComponent().

JBSplitter . , , setSplitterProportionKey() , .

JBTabs

JBTabs JetBrains, . look & feel, Swing Mac OS X, , .

...

: 1 , 2 , 3 , 4 , 5 , 6 , 7 .

Source: https://habr.com/ru/post/188060/


All Articles