美文网首页
(十八)IntelliJ 插件开发——Preference Se

(十八)IntelliJ 插件开发——Preference Se

作者: 秋水畏寒 | 来源:发表于2020-03-16 22:22 被阅读0次

Github

https://github.com/kungyutucheng/my_gradle_plugin

参考

Easy Code

运行环境

macOS 10.14.5
IntelliJ idea 2019.2.4

定义

官方文档未找到如何在Preference中添加自定义的设置,所以在网上搜索到Easy Code项目,通过观看其源码撸了以下的Demo代码。

效果

初始效果 修改内容之后 配置数据存储文件位置

Demo

1、新建数据储存Settings

package com.kungyu.setting;

import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.HashMap;
import java.util.Map;

/**
 * @author wengyongcheng
 * @since 2020/3/14 10:27 下午
 */
@State(name = "MainSetting", storages = @Storage("main-setting.xml"))
public class Settings implements PersistentStateComponent<Settings> {

    private Map<String, String> settingMap;

    public Map<String, String> getSettingMap() {
        return settingMap;
    }

    public void setSettingMap(Map<String, String> settingMap) {
        this.settingMap = settingMap;
    }

    public static Settings getInstance() {

        return ServiceManager.getService(Settings.class);
    }

    public Settings(){
        init();
    }

    private void init() {
        settingMap = new HashMap<>();
    }

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

    /**
     * 新的组件状态被加载时,调用该方法,如果IDE运行期间,保存数据的文件被从外部修改,则该方法会被再次调用
     * @param state
     */
    @Override
    public void loadState(@NotNull Settings state) {
        setSettingMap(state.getSettingMap());
    }
}

@State(name = "MainSetting", storages = @Storage("main-setting.xml"))

@State注解用来定义配置数据存放的具体路径,具体请戳(二十一)IntelliJ 插件开发——Persisting State of Components(组件的持久化状态)

Settings实现了PersistentStateComponent接口,该接口需要实现俩个方法:

  • getState:返回当前组件的state
/**
   * @return a component state. All properties, public and annotated fields are serialized. Only values, which differ
   * from the default (i.e., the value of newly instantiated class) are serialized. {@code null} value indicates
   * that the returned state won't be stored, as a result previously stored state will be used.
   * @see com.intellij.util.xmlb.XmlSerializer
   */
  @Nullable
  T getState();
  • loadState:新的组件状态被加载时,调用该方法,如果IDE运行期间,保存数据的文件被从外部修改,则该方法会被再次调用
 /**
   * This method is called when new component state is loaded. The method can and will be called several times, if
   * config files were externally changed while IDE was running.
   * <p>
   * State object should be used directly, defensive copying is not required.
   *
   * @param state loaded component state
   * @see com.intellij.util.xmlb.XmlSerializerUtil#copyBean(Object, Object)
   */
  void loadState(@NotNull T state);

2、创建GUI Form对象MainSetting,作为设置主入口

package com.kungyu.setting;

import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;

/**
 * @author wengyongcheng
 * @since 2020/3/14 10:16 下午
 */
public class MainSetting implements Configurable,Configurable.Composite {
    private JTextField textField;
    private JLabel label;
    private JPanel mainPanel;

    private Settings settings = Settings.getInstance();

    public MainSetting(){init();}

    private void init() {
        this.settings = Settings.getInstance();
        textField.setText(settings.getSettingMap().get("mainSetting"));
    }
    
    @Nls(capitalization = Nls.Capitalization.Title)
    @Override
    public String getDisplayName() {
        return "Main Setting";
    }

    /**
     * 通过方法返回定义的子设置组件
     * @return
     */
    @NotNull
    @Override
    public Configurable[] getConfigurables() {
        Configurable[] configurables = new Configurable[1];
        configurables[0] = new SubSetting();
        return configurables;
    }

    @Nullable
    @Override
    public JComponent createComponent() {
        return mainPanel;
    }

    /**
     * 设置apply按钮是否可用,数据修改时被调用
     * @return
     */
    @Override
    public boolean isModified() {
        String origSetting = settings.getSettingMap().get("mainSetting");
        String newSetting = textField.getText();
        return !StringUtils.equals(origSetting,newSetting);
    }

    /**
     * 点击apply按钮后被调用
     * @throws ConfigurationException
     */
    @Override
    public void apply() throws ConfigurationException {
        settings.getSettingMap().put("mainSetting", textField.getText());
    }

    /**
     * reset按钮被点击时触发
     */
    @Override
    public void reset() {
        init();
    }
}

GUI Form创建方法请戳(十六)IntelliJ 插件开发——Run Configuration(运行配置)

从代码中我们可以看到,MainSetting实现了俩个接口:ConfigurableConfigurable.Composite

  1. Configurable接口这里实现了以下几个方法:
  • getDisplayName:展示的名称
  • isModified:当数据修改时会触发该方法,返回值代表Apply按钮是否可用,该Demo中通过判断原先的配置origSetting与新的输入内容newSetting是否相同来控制Apply按钮是否可用
  • apply:点击Apply按钮后触发,可以用来保存数据
  • reset:重置,通过Reset按钮触发,无须多言
  1. Configurable.Composite里面只有一个方法:
  • getConfigurables:用来返回该组件下的子组件列表,这里我们返回了自定义的SubSetting

3、子组件SubSetting

package com.kungyu.setting;

import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;

/**
 * @author wengyongcheng
 * @since 2020/3/14 10:20 下午
 */
public class SubSetting implements Configurable {
    private JPanel mainPanel;
    private JTextField testField;
    private JLabel label;

    public SubSetting(){}

    @Nls(capitalization = Nls.Capitalization.Title)
    @Override
    public String getDisplayName() {
        return "Sub Setting";
    }

    @Nullable
    @Override
    public JComponent createComponent() {
        return mainPanel;
    }

    @Override
    public boolean isModified() {
        return false;
    }

    @Override
    public void apply() throws ConfigurationException {

    }
}

MainSetting一致,唯一的区别时没有实现Configurable.Composite

4、注册service和配置

    <extensions defaultExtensionNs="com.intellij">
        <applicationService serviceImplementation="com.kungyu.setting.Settings"/>
        <applicationConfigurable instance="com.kungyu.setting.MainSetting" dynamic="true"/>
    </extensions>

其中,dynamic属性表明这是一个继承了Configurable.Composite接口的配置组件,并且其配置子项需要通过调用Configurable.Composite#getConfigurables方法来动态实现,这种动态加载的好处是通过不加载额外的配置来避免性能消耗,原文如下:

  /**
   * This attribute states that a custom configurable component implements the {@link Configurable.Composite} interface
   * and its children are dynamically calculated by calling the {@link Configurable.Composite#getConfigurables()} method.
   * It is needed to improve performance, because we do not want to load any additional classes during the building a setting tree.
   */
  @Attribute("dynamic")
  public boolean dynamic;

相关文章

网友评论

      本文标题:(十八)IntelliJ 插件开发——Preference Se

      本文链接:https://www.haomeiwen.com/subject/vklvehtx.html