Run configuration editor without writeExternal

Answered

Hello!

I'm trying to create a Run configuration (specifically using AbstractPythonRunConfiguration) that relies on a Rest API of another system to get some data for the script execution. All is good and well until I get to the SettingsEditor implementation.

In the SettingsEditor, I want to let the users choose some values that it gets from the API in a comboBox. At this point, whenever the user selects a different item from the comboBox, the Apply button is still grayed out. After some debugging later I saw the apply button relies on the XML serialization of the run configuration in RunConfiguration#writeExternal(). This post sums it up.

Now, In my situation, I don't want to serialize the user choices. I want these settings to live as long as the IDE is open, and re-entered when the IDE is restarted. The reason is that the data I fetch is dynamic and can change between user sessions, and might contain sensitive data. Serializing it also means writing it to workspace.xml.
But if I don't save the configuration in writeExternal, the Apply button will never be enabled. If I select what I need and click OK, the settings are not saved.

The weird thing is when I use LazyRunConfigurationProducer to create a run configuration, It opens a configuration editor (because some parameters are mandatory in RunConfiguration#CheckConfiguration()), and the configuration I enter there is saved to the run configuration, Because the Apply button in this window is enabled by default, regardless of the state of the configuration. When I try to edit this configuration, again the apply button will never be enabled.

Any idea how I can save the config only to my run configuration instance, without serializing it?

Also, I'm using kotlin UI DSL in the SettingsEditor, maybe there's a way to use DialogPanel#onIsModified() or something else to achieve that?

Thanks!

 

0
2 comments

Hi,

Is there any chance to see the code to reproduce it? It will be much easier to see the possibilities.

0

Hey Karol,

Sure, Apologies for not putting it in the first place. Code is stripped down a bit

The run configuration currently needs a script path, and a "test case" I pull from the API. The sciprtPath is serialized in writeExternal, while the testCase isn't. In checkConfiguration I check that I have all the details to run the script.

class ProductRunConfiguration(project: Project,
                              factory: ConfigurationFactory
) : AbstractPythonRunConfiguration<ProductRunConfiguration>(project, factory) {
    var scriptPath: String? = null
    var testCase: TestCase? = null

    override fun writeExternal(element: Element) {
        super.writeExternal(element)
        JDOMExternalizerUtil.writeField(element, SCRIPT_PATH, scriptPath)
    }

    override fun checkConfiguration() {
        super.checkConfiguration()
        if (scriptPath == null || testCase == null) {
throw RuntimeConfigurationError("Missing test case")
} } }

And this is my editor:

class ProductRunConfigurationEditor(project: Project, configuration: ProductRunConfiguration) : SettingsEditor<ProductRunConfiguration>() {
    private lateinit var panel: DialogPanel
    private val scriptPathField = textFieldWithBrowseButton(
        project,
        "Choose Script",
        fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFileDescriptor(PythonFileType.INSTANCE)
    )
    private lateinit var testCaseCombo : ComboBox<TestCase>
    val testCasesComboBoxModel = MutableCollectionComboBoxModel<TestCase>()

    override fun resetEditorFrom(s: ProductRunConfiguration) {
        scriptPathField.text = s.scriptPath!!
        testCasesComboBoxModel.selectedItem = s.testCase
        panel.reset()
    }

    override fun applyEditorTo(s: ProductRunConfiguration) {
        panel.apply()
        s.scriptPath = scriptPathField.text
        s.testCase = testCasesComboBoxModel.selectedItem as? TestCase
    }

    override fun createEditor(): JComponent {
        getTestCases()
        panel = panel {
            row("Script Path") {
                cell(scriptPathField)
                    .align(AlignX.FILL)
            }
            row("Test Case") {
                testCaseCombo = comboBox(testCasesComboBoxModel, SimpleListCellRenderer.create {
                        label, case, _ -> case.let { label.text = "${case.caseId} - ${case.environment} - ${case.title}" }
                })
                    .align(AlignX.FILL)
                    .component
            }
        }
        return panel
    }

    private fun getTestCases() {
        // execute SwingWorker to fetch test cases from the API and populate testCaseComboBox
    }
}

The testCase object is being applied to the run configuration in applyEditorTo, but I don't serialize it in writeExternal, so the apply button state won't change when I change the testCase comboBox. Only when I change scriptPath.

Hope that clarifies my issue!

0

Please sign in to leave a comment.