在idea中可以通过扩展Configurable来设计project和application级别的设置。再结合 Persistence Model就可实现插件设置的保存。设置可以保存到单独的文件中也可和系统设置保存在一起。

一、plugin.xml配置说明

1、<applicationConfigurable>

        可参考示例:ConsoleConfigurable

<extensions defaultExtensionNs="com.intellij">
  <applicationConfigurable
      parentId="tools"
      instance="com.example.ApplicationSettingsConfigurable"
      id="com.example.ApplicationSettingsConfigurable"
      displayName="My Application Settings"/>
</extensions>

2、<projectConfigurable>

        可参考示例:AutoImportOptionsConfigurable

<extensions defaultExtensionNs="com.intellij">
  <projectConfigurable
      parentId="tools"
      instance="com.example.ProjectSettingsConfigurable"
      id="com.example.ProjectSettingsConfigurable"
      displayName="My Project Settings"
      nonDefaultProject="true"/>
</extensions>

3、配置属性说明

属性

提供者

说明

instance

Configurable

自定义实现类,提供了一个带有 Swing 形式的命名可配置组件,可参考示例SearchableConfigurable

provider

ConfigurableProvider

自定义实现类,可以有条件的显示或隐藏此配置组件Swing

nonDefaultProject

Configurable

适用于projectConfigurable,

true= 显示除默认项目之外的所有项目的设置。

false= 显示所有项目的设置。

displayName

Configurable

ConfigurableProvider

显示文案,如里需要国际化可用key来代替

keybundle

Configurable

ConfigurableProvider

国际化相关

id

Configurable

ConfigurableProvider

此实现的唯一 FQN 标识符

parentId

Configurable

ConfigurableProvider

创建设置的层次结构

groupWeight

Configurable

ConfigurableProvider

指定该组件在父可配置组件组中的权重(堆叠顺序)。默认权重为 0,表示顺序最低

dynamic

Configurable.Composite

该组件的子组件是通过调用该getConfigurables()方法动态计算的,但不是太推荐因为会影响性能

childrenEPName

Configurable

指定将用于计算此组件的子项的扩展点的 FQN 名称

 【注意】:上述属性中:1、displayName和key二选一;2、parentId和groupId二选一,且可以都不填写;

parentId属性

  • 默认:当parentId和groupId都不设置时默认会放置在other组中;
  • 可选:appearance、build、build.tools、editor、language、tools

二、EextendsPoint

1、Configurable

com.intellij.openapi.options.Configurable

      几个重要的方法:

  • 打开配置窗口时,会先调用Configurable.reset(),然后立即调用createComponent()方法,要加载显示的信息可查看ShowSettingsUtil类的实现;
  • 初始化时,使用applicationConfigurable声明的应用程序设置实现必须具有不带参数的默认构造函数,使用projectConfigurableEP声明的项目设置实现必须声明一个构造函数,该构造函数具有一个类型的参数
  • 点击设置对话框的取消或确定按钮会清空一次资源,系统会调用disposeUIResources()方法,结束当前生命周期。

        全局设置标记:

Configurable.NoScroll

  • - 通知设置对话框不要向表单添加滚动条。 

Configurable.NoMargin

  • - 通知设置对话框不要向表单添加空边框。

Configurable.Beta

  •  (2022.3) -在设置树中的设置页面标题旁边添加Beta标签。

com.intellij.openapi.options.ConfigurableEP

        专门用于特定类型设置的类,比如向Settings | Editor | General | Appearance 中添加一个额外的设置就可以使用扩展com.intellij.editorSmartKeysConfigurable,实现类可通过继承EditorSmartKeysConfigurableEP类来实现

2、ConfigurableProvider

    ConfigurableIntelliJ 调用ConfigurableProvider.canCreateConfigurable(),它评估运行时条件以确定设置更改在当前上下文中是否有意义。如果显示设置有意义,can方法则返回true。然后平台才会调用ConfigurableProvider.createConfigurable()返回Configurable设置实现的对象。

        可参考示例RunToolbarSettingsConfigurableProvider

三、自定义设置组

        虽然我们可以指定parentId,但如果插件比较复杂就可能需要实现层级式的设置页了。

单独的EP的父子设置

        注意第二个配置的parentId值它设置的是第一个配置的id值。


<extensions defaultExtensionNs="com.intellij">
  <projectConfigurable
      parentId="tools"
      id="com.intellij.sdk.tasks"
      displayName="Tasks"
      nonDefaultProject="true"
      instance="com.intellij.sdk.TaskConfigurable"/>

  <projectConfigurable
      parentId="com.intellij.sdk.tasks"
      id="com.intellij.sdk.tasks.servers"
      displayName="Servers"
      nonDefaultProject="true"
      instance="com.intellij.sdk.TaskRepositoriesConfigurable"/>
</extensions>


嵌套 EP 的父子设置

        这种设置是基于id值的,比如下例中com.intellij.sdk.tasks和com.intellij.sdk.tasks.servers。这里的子必须前缀为com.intellij.sdk.tasks,然后再加.children。


<extensions defaultExtensionNs="com.intellij">
  <projectConfigurable
        parentId="tools"
        id="com.intellij.sdk.tasks"
        displayName="Tasks"
        nonDefaultProject="true"
        instance="com.intellij.sdk.TaskConfigurable"/>
    <configurable
        id="com.intellij.sdk.tasks.servers"
        displayName="Servers"
        nonDefaultProject="true"
        instance="com.intellij.sdk.TaskRepositoriesConfigurable"/>
  </projectConfigurable>
</extensions>


四、示例程序

IDEA Presistence在哪 Hibernete idea preferences_intellij-idea


1、定义State

定义AppSettingsState类

@State(
        name = "org.intellij.sdk.settings.AppSettingsState",
        storages = @Storage("SdkSettingsPlugin.xml")
)
public class AppSettingsState implements PersistentStateComponent<AppSettingsState> {

  public String userId = "John Q. Public";
  public boolean ideaStatus = false;

  public static AppSettingsState getInstance() {
    return ApplicationManager.getApplication().getService(AppSettingsState.class);
  }

  @Nullable
  @Override
  public AppSettingsState getState() {
    return this;
  }

  @Override
  public void loadState(@NotNull AppSettingsState state) {
    XmlSerializerUtil.copyBean(state, this);
  }

}
  • name: 指定的是实现类的全路径;
  • storages:默认路径为~/Library/Application Support/JetBrains/IntelliJIdea2023.1/plugins;测试时此文件位于code_samples /settings /build /idea-sandbox /config /options/中;
  • AppSettingsState:中定义的属性默认为持久化的;如果不需要持久化可用@com.intellij.util.xmlb.annotations.Transient来标注不再持久化;

 这个配置不建议使用,因为idea要废弃对component的使用,在java类中通过注解的方式来实现


<application>
  <component name="org.intellij.sdk.settings.AppSettingsState">
    <option name="ideaStatus" value="true" />
  </component>
</application>


2、定义UI

public class AppSettingsComponent {

  private final JPanel myMainPanel;
  private final JBTextField myUserNameText = new JBTextField();
  private final JBCheckBox myIdeaUserStatus = new JBCheckBox("Do you use IntelliJ IDEA? ");

  public AppSettingsComponent() {
    myMainPanel = FormBuilder.createFormBuilder()
            .addLabeledComponent(new JBLabel("Enter user name: "), myUserNameText, 1, false)
            .addComponent(myIdeaUserStatus, 1)
            .addComponentFillVertically(new JPanel(), 0)
            .getPanel();
  }

  public JPanel getPanel() {
    return myMainPanel;
  }

  public JComponent getPreferredFocusedComponent() {
    return myUserNameText;
  }

  @NotNull
  public String getUserNameText() {
    return myUserNameText.getText();
  }

  public void setUserNameText(@NotNull String newText) {
    myUserNameText.setText(newText);
  }

  public boolean getIdeaUserStatus() {
    return myIdeaUserStatus.isSelected();
  }

  public void setIdeaUserStatus(boolean newStatus) {
    myIdeaUserStatus.setSelected(newStatus);
  }

}

3、定义AppSettingsConfigurable类

public class AppSettingsConfigurable implements Configurable {

  private AppSettingsComponent mySettingsComponent;

  // A default constructor with no arguments is required because this implementation
  // is registered as an applicationConfigurable EP

  @Nls(capitalization = Nls.Capitalization.Title)
  @Override
  public String getDisplayName() {
    return "SDK: Application Settings Example";
  }

  @Override
  public JComponent getPreferredFocusedComponent() {
    return mySettingsComponent.getPreferredFocusedComponent();
  }

  @Nullable
  @Override
  public JComponent createComponent() {
    mySettingsComponent = new AppSettingsComponent();
    return mySettingsComponent.getPanel();
  }

  @Override
  public boolean isModified() {
    AppSettingsState settings = AppSettingsState.getInstance();
    boolean modified = !mySettingsComponent.getUserNameText().equals(settings.userId);
    modified |= mySettingsComponent.getIdeaUserStatus() != settings.ideaStatus;
    return modified;
  }

  @Override
  public void apply() {
    AppSettingsState settings = AppSettingsState.getInstance();
    settings.userId = mySettingsComponent.getUserNameText();
    settings.ideaStatus = mySettingsComponent.getIdeaUserStatus();
  }

  @Override
  public void reset() {
    AppSettingsState settings = AppSettingsState.getInstance();
    mySettingsComponent.setUserNameText(settings.userId);
    mySettingsComponent.setIdeaUserStatus(settings.ideaStatus);
  }

  @Override
  public void disposeUIResources() {
    mySettingsComponent = null;
  }

}

配置

<extensions defaultExtensionNs="com.intellij">
    <applicationConfigurable parentId="tools" instance="org.intellij.sdk.settings.AppSettingsConfigurable"
                             id="org.intellij.sdk.settings.AppSettingsConfigurable"
                             displayName="SDK: Application Settings Example"/>
    <applicationService serviceImplementation="org.intellij.sdk.settings.AppSettingsState"/>
  </extensions>

4、测试 runIde

         SdkSettingsPlugin.xml存储位置:code_samples /settings /build /idea-sandbox /config /options/中