1 // Copyright 2000-2021 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;
4 import com.intellij.ide.ui.UINumericRange;
5 import com.intellij.openapi.extensions.BaseExtensionPointName;
6 import com.intellij.openapi.extensions.ExtensionPointName;
7 import com.intellij.openapi.extensions.ProjectExtensionPointName;
8 import com.intellij.openapi.ui.ComboBox;
9 import com.intellij.openapi.util.Comparing;
10 import com.intellij.openapi.util.NlsContexts;
11 import com.intellij.openapi.util.text.StringUtil;
12 import org.jetbrains.annotations.Contract;
13 import org.jetbrains.annotations.NonNls;
14 import org.jetbrains.annotations.NotNull;
15 import org.jetbrains.annotations.Nullable;
19 import java.util.Collection;
22 * This interface represents a named configurable component that provides a Swing form
23 * to configure some settings via the Settings dialog.
25 * To register a custom implementation of this interface use the following extension points:
26 * {@code com.intellij.applicationConfigurable} for settings, which are global for IDE,
27 * and {@code com.intellij.projectConfigurable} for project settings, which are applied
28 * to the current project only. They differ only in the constructor implementation.
29 * Classes for IDE settings must have a default constructor with no arguments,
30 * while classes for project settings must declare a constructor with a single argument
31 * of the {@link com.intellij.openapi.project.Project Project} type.
33 * The following attributes are available for both extension points mentioned above:
35 * <dt>{@link ConfigurableEP#instanceClass instance}</dt>
36 * <dd>This attribute specifies a qualified name of a custom implementation of this interface.
37 * The constructor will be determined automatically from the tag name:
38 * <br>{@code <extensions defaultExtensionNs="com.intellij">}
39 * <br>{@code <projectConfigurable instance="fully.qualified.class.name"/>}
40 * <br>{@code </extensions>}</dd>
41 * <dt>{@link ConfigurableEP#providerClass provider}</dt>
42 * <dd>This attribute can be used instead of the {@code instance} attribute.
43 * It specifies a qualified name of a custom implementation of the {@link ConfigurableProvider} interface,
44 * which provides another way to create a configurable component:
45 * <br>{@code <extensions defaultExtensionNs="com.intellij">}
46 * <br>{@code <projectConfigurable provider="fully.qualified.class.name"/>}
47 * <br>{@code </extensions>}</dd>
48 * <dt><strike>{@link ConfigurableEP#implementationClass implementation}</strike></dt>
49 * <dd>This attribute is deprecated and replaced with two attributes above.
50 * In fact, it works as the {@code instance} attribute.</dd>
51 * <dt>{@link ConfigurableEP#nonDefaultProject nonDefaultProject}</dt>
52 * <dd>This attribute is applicable to the {@code projectConfigurable} extension only.
53 * If it is set to {@code true}, the corresponding project settings will be shown for a real project only,
54 * not for the {@link com.intellij.openapi.project.ProjectManager#getDefaultProject() template project},
55 * which provides default settings for all the new projects.</dd>
56 * <dt>{@link ConfigurableEP#displayName displayName}</dt>
57 * <dd>This attribute specifies the setting name visible to users.
58 * If the display name is not set, a configurable component will be instantiated to retrieve its name dynamically.
59 * This causes a loading of plugin classes and increases the delay before showing the settings dialog.
60 * It is highly recommended specifying the display name in XML to improve UI responsiveness.</dd>
61 * <dt>{@link ConfigurableEP#key key} and {@link ConfigurableEP#bundle bundle}</dt>
62 * <dd>These attributes specify the display name too, if the specified key is declared in the specified resource bundle.</dd>
63 * <dt>{@link ConfigurableEP#id id}</dt>
64 * <dd>This attribute specifies the {@link SearchableConfigurable#getId() unique identifier}
65 * for the configurable component. It is also recommended specifying the identifier in XML.</dd>
66 * <dt>{@link ConfigurableEP#parentId parentId}</dt>
67 * <dd>This attribute is used to create a hierarchy of settings.
68 * If it is set, the configurable component will be a child of the specified parent component.</dd>
69 * <dt>{@link ConfigurableEP#groupId groupId}</dt>
70 * <dd>This attribute specifies a top-level group, which the configurable component belongs to.
71 * If this attribute is not set, the configurable component will be added to the Other Settings group.
72 * The following groups are supported:
74 * <dt>ROOT {@code groupId="root"}</dt>
75 * <dd>This is the invisible root group that contains all other groups.
76 * Usually, you should not place your settings here.</dd>
77 * <dt>Appearance & Behavior {@code groupId="appearance"}</dt>
78 * <dd>This group contains settings to personalize IDE appearance and behavior:
79 * change themes and font size, tune the keymap, and configure plugins and system settings,
80 * such as password policies, HTTP proxy, updates and more.</dd>
81 * <dt>Editor {@code groupId="editor"}</dt>
82 * <dd>This group contains settings to personalize source code appearance by changing fonts,
83 * highlighting styles, indents, etc. Here you can customize the editor from line numbers,
84 * caret placement and tabs to source code inspections, setting up templates and file encodings.</dd>
85 * <dt>Default Project / Project Settings {@code groupId="project"}</dt>
86 * <dd>This group is intended to store some project-related settings, but now it is rarely used.</dd>
87 * <dt>Build, Execution, Deployment {@code groupId="build"}</dt>
88 * <dd>This group contains settings to configure you project integration with the different build tools,
89 * modify the default compiler settings, manage server access configurations, customize the debugger behavior, etc.</dd>
90 * <dt>Build Tools {@code groupId="build.tools"}</dt>
91 * <dd>This is subgroup of the group above. Here you can configure your project integration
92 * with the different build tools, such as Maven, Gradle, or Gant.</dd>
93 * <dt>Languages & Frameworks {@code groupId="language"}</dt>
94 * <dd>This group is intended to configure the settings related to specific frameworks and technologies used in your project.</dd>
95 * <dt>Tools {@code groupId="tools"}</dt>
96 * <dd>This group contains settings to configure integration with third-party applications,
97 * specify the SSH Terminal connection settings, manage server certificates and tasks, configure diagrams layout, etc.</dd>
98 * <dt>Other Settings {@code groupId="other"}</dt>
99 * <dd>This group contains settings that are related to non-bundled custom plugins and are not assigned to any other category.</dd>
101 * The {@code parentId} and the {@code groupId} attributes should not be used together and the {@code parentId} has precedence.
102 * Currently, it is possible to specify a group identifier in the {@code parentId} attribute.</dd>
103 * <dt>{@link ConfigurableEP#groupWeight groupWeight}</dt>
104 * <dd>This attribute specifies the weight of a configurable component within a group or a parent configurable component.
105 * The default weight is {@code 0}. If one child in a group or a parent configurable component has non-zero weight,
106 * all children will be sorted descending by their weight. And if the weights are equal,
107 * the components will be sorted ascending by their display name.</dd>
108 * <dt>{@link ConfigurableEP#dynamic dynamic}</dt>
109 * <dd>This attribute states that a custom configurable component implements the {@link Composite} interface
110 * and its children are dynamically calculated by calling the {@code getConfigurables} method.
111 * It is needed to improve performance, because we do not want to load any additional classes during the building a setting tree.</dd>
112 * <dt>{@link ConfigurableEP#childrenEPName childrenEPName}</dt>
113 * <dd>This attribute specifies a name of the extension point that will be used to calculate children.</dd>
114 * <dt>{@link ConfigurableEP#children configurable}</dt>
115 * <dd>This is not an attribute, this is an inner tag. It specifies children directly in the main tag body. For example,
116 * <br>{@code <projectConfigurable id="tasks" nonDefaultProject="true" instance="com.intellij.tasks.config.TaskConfigurable">}
117 * <br>{@code <configurable id="tasks.servers" instance="com.intellij.tasks.config.TaskRepositoriesConfigurable"/>}
118 * <br>{@code </projectConfigurable>}
119 * <br>is similar to the following declarations
120 * <br>{@code <projectConfigurable id="tasks" nonDefaultProject="true" instance="com.intellij.tasks.config.TaskConfigurable"/>}
121 * <br>{@code <projectConfigurable parentId="tasks" id="tasks.servers" nonDefaultProject="true" instance="com.intellij.tasks.config.TaskRepositoriesConfigurable"/>}</dd>
124 * @see ConfigurableEP
125 * @see SearchableConfigurable
126 * @see ShowSettingsUtil
128 public interface Configurable extends UnnamedConfigurable {
129 ExtensionPointName<ConfigurableEP<Configurable>> APPLICATION_CONFIGURABLE = new ExtensionPointName<>("com.intellij.applicationConfigurable");
130 ProjectExtensionPointName<ConfigurableEP<Configurable>> PROJECT_CONFIGURABLE = new ProjectExtensionPointName<>("com.intellij.projectConfigurable");
133 * Returns the visible name of the configurable component.
134 * Note, that this method must return the display name
135 * that is equal to the display name declared in XML
136 * to avoid unexpected errors.
138 * @return the visible name of the configurable component
140 @NlsContexts.ConfigurableName
141 @Contract(pure = true)
142 String getDisplayName();
145 * Returns the topic in the help file which is shown when help for the configurable is requested.
147 * @return the help topic, or {@code null} if no help is available
151 @Contract(pure = true)
152 default String getHelpTopic() {
157 * This interface represents a configurable component that has child components.
158 * It is not recommended to use this approach to specify children of a configurable component,
159 * because it causes loading additional classes during the building a setting tree.
160 * Use XML attributes instead if possible.
163 interface Composite {
164 Configurable @NotNull [] getConfigurables();
168 * This marker interface notifies the Settings dialog to not add scroll bars to the Swing form.
169 * Required when the Swing form contains its own scrollable components.
172 // see ConfigurableCardPanel#create(Configurable)
176 * This marker interface notifies the Settings dialog to not add an empty border to the Swing form.
177 * Required when the Swing form is a tabbed pane.
180 // see ConfigurableCardPanel#create(Configurable)
184 * Allows to dynamically define if current configurable settings apply to current project or to the IDE and update "For current project"
185 * indicator accordingly.
187 interface VariableProjectAppLevel {
189 * @return True if current settings apply to the current project (enable "For current project" indicator), false for application-level
192 boolean isProjectLevel();
196 * The interface is used for configurable that depends on some dynamic extension points.
197 * If a configurable implements the interface by default the configurable will re-created after adding / removing extensions for the EP.
199 * Examples: postfix template configurable. If we have added a plugin with new postfix templates we have to re-create the configurable
200 * (but only if the content of the configurable was loaded)
202 * @apiNote if the configurable is not marked as dynamic=true it must not initialize EP-depend resources in the constructor.
203 * This interface also can be used with {@link ConfigurableProvider}.
206 interface WithEpDependencies {
208 * @return EPName-s that affect the configurable or configurable provider
210 @NotNull Collection<BaseExtensionPointName<?>> getDependencies();
213 default boolean isModified(@NotNull JTextField textField, @NotNull String value) {
214 return !StringUtil.equals(textField.getText().trim(), value);
217 default boolean isModified(@NotNull JTextField textField, int value, @NotNull UINumericRange range) {
219 int currentValue = Integer.parseInt(textField.getText().trim());
220 return range.fit(currentValue) == currentValue && currentValue != value;
222 catch (NumberFormatException e) {
227 default boolean isModified(@NotNull JToggleButton toggleButton, boolean value) {
228 return toggleButton.isSelected() != value;
231 default <T> boolean isModified(@NotNull ComboBox<T> comboBox, T value) {
232 return !Comparing.equal(comboBox.getSelectedItem(), value);
235 interface TopComponentController {
236 TopComponentController EMPTY = new TopComponentController() {
238 public void setLeftComponent(@Nullable Component component) {}
241 public void showProgress(boolean start) {}
244 public void showProject(boolean hasProject) {}
247 void setLeftComponent(@Nullable Component component);
249 void showProgress(boolean start);
251 void showProject(boolean hasProject);
254 interface TopComponentProvider {
255 default boolean isAvailable() {
259 @NotNull Component getCenterComponent(@NotNull TopComponentController controller);