将表单元素绑定到 IntelliJ 插件中的持久存储

Binding form elements to persistent storage in IntelliJ plugin

我刚开始尝试制作自己的 IntelliJ 插件,但不知道如何正确保存绑定表单组件的持久信息。

我在表单上单击鼠标右键,选择数据绑定向导,并正确匹配列出的所有内容。然后我修改了生成的方法来处理无法绑定的对象(或者在这种情况下,一个对象)(一个 JSpinner)。

当我的表单上的组件状态发生变化时,我应该如何让持久存储自动save/update?

这是我的 PersistentStateComponent class:

import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.util.xmlb.XmlSerializerUtil;

@State(
        name = "Hastebin Configuration",
        reloadable = true,
        storages = {
                @Storage(id = "other", file = StoragePathMacros.APP_CONFIG + "/hastebin.xml")
        }
)
public class HastebinService implements PersistentStateComponent<HastebinService> {

    private String host = "hastebin.com";
    private String msgSuccess = "Share with Hastebin successful.<br>Link is waiting in your clipboard.";
    private String msgFailure = "Something went wrong.<br><br>Problem description: {error}<br><br>Please try again and it problem persists, contact the author.";
    private boolean logPastes = false;
    private int port = 80;
    private boolean useFileAssoc = true;
    private boolean useSSL = false;

    public String getHost() {
        return this.host;
    }

    public boolean getLogPastes() {
        return this.logPastes;
    }

    public String getMsgFailure() {
        return this.msgFailure;
    }

    public String getMsgSuccess() {
        return this.msgSuccess;
    }

    public int getPort() {
        return this.port;
    }

    @Override
    public HastebinService getState() {
        return this;
    }

    public boolean getUseFileAssoc() {
        return this.useFileAssoc;
    }

    public boolean getUseSSL() {
        return this.useSSL;
    }

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

    public void setHost(String host) {
        this.host = host;
        System.out.println("testing");
    }

    public void setLogPastes(boolean logPastes) {
        this.logPastes = logPastes;
    }

    public void setMsgFailure(String msgFailure) {
        this.msgFailure = msgFailure;
    }

    public void setMsgSuccess(String msgSuccess) {
        this.msgSuccess = msgSuccess;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setUseFileAssoc(boolean useFileAssoc) {
        this.useFileAssoc = useFileAssoc;
    }

    public void setUseSSL(boolean useSSL) {
        this.useSSL = useSSL;
    }

}

这是我的表格class:

import com.intellij.ui.components.JBScrollPane;

import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.SpinnerNumberModel;
import java.awt.Color;
import java.awt.event.ActionListener;

public class SettingsPanel {
    private JTabbedPane hasteTabConfig;
    private JCheckBox chkUseSsl;
    private JCheckBox chkFileAssoc;
    private JCheckBox chkLogHistory;
    private JTextField txtSuccess;
    private JTextField txtFailure;
    private JTextField txtDomain;
    private JLabel lblProtocol;
    private JSpinner spinPort;
    private JPanel rootPanel;
    private JScrollPane scrollPane;
    private JPanel scrollPanel;
    private JTable tblHistory;

    public SettingsPanel() {
        this.scrollPanel.setOpaque(false);

        this.chkUseSsl.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent e) {
                updateProtocol();
            }
        });
    }

    private void createUIComponents() {
        // Scroll Pane
        this.scrollPane = new JBScrollPane();
        this.scrollPane.setBackground(new Color(230, 230, 230));
        this.scrollPane.setViewport(new CustomViewPort(this.scrollPanel));
        this.scrollPane.setOpaque(false);
        this.scrollPane.getVerticalScrollBar().setBlockIncrement(20);
        this.scrollPane.getVerticalScrollBar().setUnitIncrement(16);

        // Port Number
        this.spinPort = new JSpinner(new SpinnerNumberModel(80, 1, 65535, 1));
        JFormattedTextField textField = ((JSpinner.DefaultEditor)this.spinPort.getEditor()).getTextField();
        textField.setColumns(1);
    }

    public void getData(HastebinService data) {
        this.getUnboundData(data);
        data.setHost(this.txtDomain.getText());
        data.setUseSSL(this.chkUseSsl.isSelected());
        data.setUseFileAssoc(this.chkFileAssoc.isSelected());
        data.setLogPastes(this.chkLogHistory.isSelected());
        data.setMsgSuccess(this.txtSuccess.getText());
        data.setMsgFailure(this.txtFailure.getText());
    }

    private void getUnboundData(HastebinService data) {
        data.setPort((int)this.spinPort.getValue());
    }

    public JPanel getRootPanel() {
        return this.rootPanel;
    }

    public boolean isModified(HastebinService data) {
        if (this.isUnboundModified(data)) return true;
        if (this.txtDomain.getText() != null ? !this.txtDomain.getText().equals(data.getHost()) : data.getHost() != null)
            return true;
        if (this.chkUseSsl.isSelected() != data.getUseSSL()) return true;
        if (this.chkFileAssoc.isSelected() != data.getUseFileAssoc()) return true;
        if (this.chkLogHistory.isSelected() != data.getLogPastes()) return true;
        if (this.txtSuccess.getText() != null ? !this.txtSuccess.getText().equals(data.getMsgSuccess()) : data.getMsgSuccess() != null)
            return true;
        if (this.txtFailure.getText() != null ? !this.txtFailure.getText().equals(data.getMsgFailure()) : data.getMsgFailure() != null)
            return true;
        return false;
    }

    private boolean isUnboundModified(HastebinService data) {
        if ((int)this.spinPort.getValue() != data.getPort()) return true;
        return false;
    }

    public void setData(HastebinService data) {
        this.setUnboundData(data);
        this.txtDomain.setText(data.getHost());
        this.chkUseSsl.setSelected(data.getUseSSL());
        this.chkFileAssoc.setSelected(data.getUseFileAssoc());
        this.chkLogHistory.setSelected(data.getLogPastes());
        this.txtSuccess.setText(data.getMsgSuccess());
        this.txtFailure.setText(data.getMsgFailure());
        this.updateProtocol();
    }

    public void setUnboundData(HastebinService data) {
        this.spinPort.setValue(data.getPort());
    }

    private void updateProtocol() {
        this.lblProtocol.setText("http" + (this.chkUseSsl.isSelected() ? "s" : "") + "://");
    }

    private class CustomViewPort extends JViewport {

        public CustomViewPort(JComponent component) {
            this.setView(component);
            this.setOpaque(false);
        }
    }
}

IntelliJ IDEA 代码库不包含任何用于在表单更改时自动更新持久组件的标准数据绑定解决方案。 JetBrains 自己的代码只是手动将字段从表单复制到组件。

考虑到yole的回答,我想出了一个解决方案,对于轻插件,可以"ok enough"方式自动保存数据。

new Timer(2000, new ActionListener() { // Create 2 Second Timer
    @Override
    public void actionPerformed(ActionEvent event) {
        if (isModified()) // Any Changes?
            getData(); // Save Data
    }
}).start();