fix after review IDEA-CR-50366
[idea/community.git] / platform / platform-api / src / com / intellij / openapi / options / Configurable.java
1 // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.options;
3
4 import com.intellij.ide.ui.UINumericRange;
5 import com.intellij.openapi.extensions.ExtensionPointName;
6 import com.intellij.openapi.ui.ComboBox;
7 import com.intellij.openapi.util.Comparing;
8 import com.intellij.openapi.util.text.StringUtil;
9 import org.jetbrains.annotations.Nls;
10 import org.jetbrains.annotations.NonNls;
11 import org.jetbrains.annotations.NotNull;
12 import org.jetbrains.annotations.Nullable;
13
14 import javax.swing.*;
15 import java.awt.*;
16
17 /**
18  * This interface represents a named configurable component that provides a Swing form
19  * to configure some settings via the Settings dialog.
20  * <p/>
21  * To register a custom implementation of this interface use the following extension points:
22  * {@code com.intellij.applicationConfigurable} for settings, which are global for IDE,
23  * and {@code com.intellij.projectConfigurable} for project settings, which are applied
24  * to the current project only.  They differ only in the constructor implementation.
25  * Classes for IDE settings must have a default constructor with no arguments,
26  * while classes for project settings must declare a constructor with a single argument
27  * of the {@link com.intellij.openapi.project.Project Project} type.
28  * <p/>
29  * The following attributes are available for both extension points mentioned above:
30  * <dl>
31  *   <dt>{@link ConfigurableEP#instanceClass instance}</dt>
32  *   <dd>This attribute specifies a qualified name of a custom implementation of this interface.
33  *   The constructor will be determined automatically from the tag name:
34  *   <br>{@code <extensions defaultExtensionNs="com.intellij">}
35  *   <br>{@code &nbsp;&nbsp;&nbsp;&nbsp;<projectConfigurable instance="fully.qualified.class.name"/>}
36  *   <br>{@code </extensions>}</dd>
37  *   <dt>{@link ConfigurableEP#providerClass provider}</dt>
38  *   <dd>This attribute can be used instead of the {@code instance} attribute.
39  *   It specifies a qualified name of a custom implementation of the {@link ConfigurableProvider} interface,
40  *   which provides another way to create a configurable component:
41  *   <br>{@code <extensions defaultExtensionNs="com.intellij">}
42  *   <br>{@code &nbsp;&nbsp;&nbsp;&nbsp;<projectConfigurable provider="fully.qualified.class.name"/>}
43  *   <br>{@code </extensions>}</dd>
44  *   <dt><strike>{@link ConfigurableEP#implementationClass implementation}</strike></dt>
45  *   <dd>This attribute is deprecated and replaced with two attributes above.
46  *   In fact, it works as the {@code instance} attribute.</dd>
47  *   <dt>{@link ConfigurableEP#nonDefaultProject nonDefaultProject}</dt>
48  *   <dd>This attribute is applicable to the {@code projectConfigurable} extension only.
49  *   If it is set to {@code true}, the corresponding project settings will be shown for a real project only,
50  *   not for the {@link com.intellij.openapi.project.ProjectManager#getDefaultProject() template project},
51  *   which provides default settings for all the new projects.</dd>
52  *   <dt>{@link ConfigurableEP#displayName displayName}</dt>
53  *   <dd>This attribute specifies the setting name visible to users.
54  *   If the display name is not set, a configurable component will be instantiated to retrieve its name dynamically.
55  *   This causes a loading of plugin classes and increases the delay before showing the settings dialog.
56  *   It is highly recommended specifying the display name in XML to improve UI responsiveness.</dd>
57  *   <dt>{@link ConfigurableEP#key key} and {@link ConfigurableEP#bundle bundle}</dt>
58  *   <dd>These attributes specify the display name too, if the specified key is declared in the specified resource bundle.</dd>
59  *   <dt>{@link ConfigurableEP#id id}</dt>
60  *   <dd>This attribute specifies the {@link SearchableConfigurable#getId() unique identifier}
61  *   for the configurable component.  It is also recommended specifying the identifier in XML.</dd>
62  *   <dt>{@link ConfigurableEP#parentId parentId}</dt>
63  *   <dd>This attribute is used to create a hierarchy of settings.
64  *   If it is set, the configurable component will be a child of the specified parent component.</dd>
65  *   <dt>{@link ConfigurableEP#groupId groupId}</dt>
66  *   <dd>This attribute specifies a top-level group, which the configurable component belongs to.
67  *   If this attribute is not set, the configurable component will be added to the Other Settings group.
68  *   The following groups are supported:
69  *   <dl>
70  *     <dt>ROOT {@code groupId="root"}</dt>
71  *     <dd>This is the invisible root group that contains all other groups.
72  *     Usually, you should not place your settings here.</dd>
73  *     <dt>Appearance & Behavior {@code groupId="appearance"}</dt>
74  *     <dd>This group contains settings to personalize IDE appearance and behavior:
75  *     change themes and font size, tune the keymap, and configure plugins and system settings,
76  *     such as password policies, HTTP proxy, updates and more.</dd>
77  *     <dt>Editor {@code groupId="editor"}</dt>
78  *     <dd>This group contains settings to personalize source code appearance by changing fonts,
79  *     highlighting styles, indents, etc.  Here you can customize the editor from line numbers,
80  *     caret placement and tabs to source code inspections, setting up templates and file encodings.</dd>
81  *     <dt>Default Project / Project Settings {@code groupId="project"}</dt>
82  *     <dd>This group is intended to store some project-related settings, but now it is rarely used.</dd>
83  *     <dt>Build, Execution, Deployment {@code groupId="build"}</dt>
84  *     <dd>This group contains settings to configure you project integration with the different build tools,
85  *     modify the default compiler settings, manage server access configurations, customize the debugger behavior, etc.</dd>
86  *     <dt>Build Tools {@code groupId="build.tools"}</dt>
87  *     <dd>This is subgroup of the group above. Here you can configure your project integration
88  *     with the different build tools, such as Maven, Gradle, or Gant.</dd>
89  *     <dt>Languages & Frameworks {@code groupId="language"}</dt>
90  *     <dd>This group is intended to configure the settings related to specific frameworks and technologies used in your project.</dd>
91  *     <dt>Tools {@code groupId="tools"}</dt>
92  *     <dd>This group contains settings to configure integration with third-party applications,
93  *     specify the SSH Terminal connection settings, manage server certificates and tasks, configure diagrams layout, etc.</dd>
94  *     <dt>Other Settings {@code groupId="other"}</dt>
95  *     <dd>This group contains settings that are related to non-bundled custom plugins and are not assigned to any other category.</dd>
96  *   </dl>
97  *   The {@code parentId} and the {@code groupId} attributes should not be used together and the {@code parentId} has precedence.
98  *   Currently, it is possible to specify a group identifier in the {@code parentId} attribute.</dd>
99  *   <dt>{@link ConfigurableEP#groupWeight groupWeight}</dt>
100  *   <dd>This attribute specifies the weight of a configurable component within a group or a parent configurable component.
101  *   The default weight is {@code 0}. If one child in a group or a parent configurable component has non-zero weight,
102  *   all children will be sorted descending by their weight. And if the weights are equal,
103  *   the components will be sorted ascending by their display name.</dd>
104  *   <dt>{@link ConfigurableEP#dynamic dynamic}</dt>
105  *   <dd>This attribute states that a custom configurable component implements the {@link Composite} interface
106  *   and its children are dynamically calculated by calling the {@code getConfigurables} method.
107  *   It is needed to improve performance, because we do not want to load any additional classes during the building a setting tree.</dd>
108  *   <dt>{@link ConfigurableEP#childrenEPName childrenEPName}</dt>
109  *   <dd>This attribute specifies a name of the extension point that will be used to calculate children.</dd>
110  *   <dt>{@link ConfigurableEP#children configurable}</dt>
111  *   <dd>This is not an attribute, this is an inner tag. It specifies children directly in the main tag body. For example,
112  *   <br>{@code <projectConfigurable id="tasks" nonDefaultProject="true" instance="com.intellij.tasks.config.TaskConfigurable">}
113  *   <br>{@code &nbsp;&nbsp;&nbsp;&nbsp;<configurable id="tasks.servers" instance="com.intellij.tasks.config.TaskRepositoriesConfigurable"/>}
114  *   <br>{@code </projectConfigurable>}
115  *   <br>is similar to the following declarations
116  *   <br>{@code <projectConfigurable id="tasks" nonDefaultProject="true" instance="com.intellij.tasks.config.TaskConfigurable"/>}
117  *   <br>{@code <projectConfigurable parentId="tasks" id="tasks.servers" nonDefaultProject="true" instance="com.intellij.tasks.config.TaskRepositoriesConfigurable"/>}</dd>
118  * </dl>
119  *
120  * @see ConfigurableEP
121  * @see SearchableConfigurable
122  * @see ShowSettingsUtil
123  */
124 public interface Configurable extends UnnamedConfigurable {
125   ExtensionPointName<ConfigurableEP<Configurable>> APPLICATION_CONFIGURABLE = ExtensionPointName.create("com.intellij.applicationConfigurable");
126   ExtensionPointName<ConfigurableEP<Configurable>> PROJECT_CONFIGURABLE = ExtensionPointName.create("com.intellij.projectConfigurable");
127
128   /**
129    * Returns the visible name of the configurable component.
130    * Note, that this method must return the display name
131    * that is equal to the display name declared in XML
132    * to avoid unexpected errors.
133    *
134    * @return the visible name of the configurable component
135    */
136   @Nls(capitalization = Nls.Capitalization.Title)
137   String getDisplayName();
138
139   /**
140    * Returns the topic in the help file which is shown when help for the configurable is requested.
141    *
142    * @return the help topic, or {@code null} if no help is available
143    */
144   @Nullable
145   @NonNls
146   default String getHelpTopic() {
147     return null;
148   }
149
150   /**
151    * This interface represents a configurable component that has child components.
152    * It is not recommended to use this approach to specify children of a configurable component,
153    * because it causes loading additional classes during the building a setting tree.
154    * Use XML attributes instead if possible.
155    */
156   @FunctionalInterface
157   interface Composite {
158     @NotNull
159     Configurable[] getConfigurables();
160   }
161
162   /**
163    * This marker interface notifies the Settings dialog to not add scroll bars to the Swing form.
164    * Required when the Swing form contains its own scrollable components.
165    */
166   interface NoScroll {
167     // see ConfigurableCardPanel#create(Configurable)
168   }
169
170   /**
171    * This marker interface notifies the Settings dialog to not add an empty border to the Swing form.
172    * Required when the Swing form is a tabbed pane.
173    */
174   interface NoMargin {
175     // see ConfigurableCardPanel#create(Configurable)
176   }
177
178   /**
179    * Allows to dynamically define if current configurable settings apply to current project or to the IDE and update "For current project"
180    * indicator accordingly.
181    */
182   interface VariableProjectAppLevel {
183     /**
184      * @return True if current settings apply to the current project (enable "For current project" indicator), false for application-level
185      *         (IDE) settings.
186      */
187     boolean isProjectLevel();
188   }
189
190   default boolean isModified(@NotNull JTextField textField, @NotNull String value) {
191     return !StringUtil.equals(textField.getText().trim(), value);
192   }
193
194   default boolean isModified(@NotNull JTextField textField, int value, @NotNull UINumericRange range) {
195     try {
196       int currentValue = Integer.parseInt(textField.getText().trim());
197       return range.fit(currentValue) == currentValue && currentValue != value;
198     }
199     catch (NumberFormatException e) {
200       return false;
201     }
202   }
203
204   default boolean isModified(@NotNull JToggleButton toggleButton, boolean value) {
205     return toggleButton.isSelected() != value;
206   }
207
208   default <T> boolean isModified(@NotNull ComboBox<T> comboBox, T value) {
209     return !Comparing.equal(comboBox.getSelectedItem(), value);
210   }
211
212   /**
213    * @return component which should be focused when the dialog appears
214    *         on the screen.
215    */
216   default JComponent getPreferredFocusedComponent() {
217     return null;
218   }
219
220   interface TopComponentController {
221     void setLeftComponent(@Nullable Component component);
222
223     void showProgress(boolean start);
224   }
225
226   interface TopComponentProvider {
227     default boolean isAvailable() {
228       return true;
229     }
230
231     @NotNull
232     Component getCenterComponent(@NotNull TopComponentController controller);
233   }
234 }