diff --git a/doc/features.md b/doc/features.md index 244f7eee..cf67e169 100644 --- a/doc/features.md +++ b/doc/features.md @@ -144,6 +144,14 @@ A new `Ember Serve` run configuration can be created through To configure advanced settings like the server host, proxy or ssl, expand the `Advanced settings` panel. +### Running ember tests + +This plugin also adds a `Ember Test` run configuration that will run your projects tests. +A new `Ember Test` run configuration can be created through +`Run → Edit Configurations...`. + +To configure advanced settings like the server host, test filter or config file, expand the +`Advanced settings` panel. Live Templates ------------------------------------------------------------------------------- diff --git a/src/main/kotlin/com/emberjs/configuration/BooleanOptionsField.kt b/src/main/kotlin/com/emberjs/configuration/BooleanOptionsField.kt index 2ce78fd8..5eb1c191 100644 --- a/src/main/kotlin/com/emberjs/configuration/BooleanOptionsField.kt +++ b/src/main/kotlin/com/emberjs/configuration/BooleanOptionsField.kt @@ -3,7 +3,6 @@ package com.emberjs.configuration import com.emberjs.configuration.utils.ElementUtils import org.jdom.Element import javax.swing.JCheckBox -import javax.swing.JComponent class BooleanOptionsField( default: Boolean, @@ -12,23 +11,17 @@ class BooleanOptionsField( ) : OptionsField(default, field, cmdlineOptionName) { override var value: Boolean = default - override fun writeToElement(element: Element) { - ElementUtils.writeBool(element, this.field, this.value) - } - - override fun readFromElement(element: Element) { - this.value = ElementUtils.readBool(element, this.field) ?: this.default - } - - override fun writeToComponent(component: JComponent) { + override fun writeTo(component: Any) { when (component) { is JCheckBox -> component.isSelected = value + is Element -> ElementUtils.writeBool(component, this.field, this.value) } } - override fun readFromComponent(component: JComponent) { + override fun readFrom(component: Any) { when (component) { is JCheckBox -> value = component.isSelected + is Element -> this.value = ElementUtils.readBool(component, this.field) ?: this.default } } } \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/EmberCommandLineState.kt b/src/main/kotlin/com/emberjs/configuration/EmberCommandLineState.kt index 2b56f7ba..3e8cfd6b 100644 --- a/src/main/kotlin/com/emberjs/configuration/EmberCommandLineState.kt +++ b/src/main/kotlin/com/emberjs/configuration/EmberCommandLineState.kt @@ -7,7 +7,7 @@ import com.intellij.execution.process.ProcessHandler import com.intellij.execution.process.ProcessTerminatedListener import com.intellij.execution.runners.ExecutionEnvironment -class EmberCommandLineState(environment: ExecutionEnvironment) : CommandLineState(environment) { +open class EmberCommandLineState(environment: ExecutionEnvironment) : CommandLineState(environment) { override fun startProcess(): ProcessHandler { val configuration = (environment.runProfile as EmberConfiguration) val argList = configuration.options.toCommandLineOptions() diff --git a/src/main/kotlin/com/emberjs/configuration/OptionsField.kt b/src/main/kotlin/com/emberjs/configuration/OptionsField.kt index e09a58ab..538179e8 100644 --- a/src/main/kotlin/com/emberjs/configuration/OptionsField.kt +++ b/src/main/kotlin/com/emberjs/configuration/OptionsField.kt @@ -9,9 +9,7 @@ abstract class OptionsField( val cmdlineOptionName: String ) { abstract var value : T - abstract fun writeToElement(element: Element) - abstract fun readFromElement(element: Element) - abstract fun writeToComponent(component: JComponent) - abstract fun readFromComponent(component: JComponent) + abstract fun writeTo(component: Any) + abstract fun readFrom(component: Any) } \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/StringOptionsField.kt b/src/main/kotlin/com/emberjs/configuration/StringOptionsField.kt index 57d951c6..c05c01f0 100644 --- a/src/main/kotlin/com/emberjs/configuration/StringOptionsField.kt +++ b/src/main/kotlin/com/emberjs/configuration/StringOptionsField.kt @@ -1,10 +1,11 @@ package com.emberjs.configuration import com.emberjs.configuration.utils.ElementUtils +import com.emberjs.configuration.utils.PublicStringAddEditDeleteListPanel import com.intellij.ui.EditorTextField import org.jdom.Element +import javax.swing.ButtonGroup import javax.swing.JComboBox -import javax.swing.JComponent class StringOptionsField( default: String, @@ -14,28 +15,33 @@ class StringOptionsField( override var value: String = "" - override fun writeToElement(element: Element) { - ElementUtils.writeString(element, this.field, this.value) - } - - override fun readFromElement(element: Element) { - this.value = ElementUtils.readString(element, this.field) ?: this.default - } - - override fun writeToComponent(component: JComponent) { + override fun writeTo(component: Any) { when (component) { - is EditorTextField -> { - component.text = value - component.setPlaceholder(default) + is Element -> ElementUtils.writeString(component, this.field, this.value) + is EditorTextField -> component.apply { + text = value + setPlaceholder(default) } is JComboBox<*> -> component.selectedItem = if (value.isEmpty()) default else value + is PublicStringAddEditDeleteListPanel -> component.replaceItems(value.split(",").filter { it.isNotEmpty() }) + is ButtonGroup -> { + component.elements.toList() + .find { it.actionCommand == value } + ?.let { + it.isSelected = true + component.setSelected(it.model, true) + } + } } } - override fun readFromComponent(component: JComponent) { + override fun readFrom(component: Any) { when (component) { + is Element -> value = ElementUtils.readString(component, this.field) ?: this.default is EditorTextField -> value = component.text is JComboBox<*> -> value = component.selectedItem.toString() + is PublicStringAddEditDeleteListPanel -> value = component.listItems.joinToString(",") + is ButtonGroup -> component.selection?.let { value = it.actionCommand } } } } \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/serve/EmberServeConfiguration.kt b/src/main/kotlin/com/emberjs/configuration/serve/EmberServeConfiguration.kt index 7360b5a2..d00a6cba 100644 --- a/src/main/kotlin/com/emberjs/configuration/serve/EmberServeConfiguration.kt +++ b/src/main/kotlin/com/emberjs/configuration/serve/EmberServeConfiguration.kt @@ -36,14 +36,14 @@ class EmberServeConfiguration(project: Project, factory: ConfigurationFactory, n override fun writeExternal(element: Element?) { super.writeExternal(element) element?.let { - options.fields().forEach { optionsField -> optionsField.writeToElement(element)} + options.fields().forEach { optionsField -> optionsField.writeTo(element)} } } override fun readExternal(element: Element?) { super.readExternal(element) element?.let { - options.fields().forEach { optionsField -> optionsField.readFromElement(element) } + options.fields().forEach { optionsField -> optionsField.readFrom(element) } } } } \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/serve/ui/EmberServeSettingsEditor.kt b/src/main/kotlin/com/emberjs/configuration/serve/ui/EmberServeSettingsEditor.kt index e232636c..b0d1000c 100644 --- a/src/main/kotlin/com/emberjs/configuration/serve/ui/EmberServeSettingsEditor.kt +++ b/src/main/kotlin/com/emberjs/configuration/serve/ui/EmberServeSettingsEditor.kt @@ -59,14 +59,14 @@ class EmberServeSettingsEditor : SettingsEditor() { override fun resetEditorFrom(serveConfiguration: EmberServeConfiguration) { mappings.forEach { (first, second) -> - second.get(serveConfiguration.options).writeToComponent(first as JComponent) + first?.let { second.get(serveConfiguration.options).writeTo(it) } } } @Throws(ConfigurationException::class) override fun applyEditorTo(serveConfiguration: EmberServeConfiguration) { mappings.forEach { (first, second) -> - second.get(serveConfiguration.options).readFromComponent(first as JComponent) + first?.let { second.get(serveConfiguration.options).readFrom(it) } } } diff --git a/src/main/kotlin/com/emberjs/configuration/test/EmberTestCommandLineState.kt b/src/main/kotlin/com/emberjs/configuration/test/EmberTestCommandLineState.kt new file mode 100644 index 00000000..c1ed944f --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/EmberTestCommandLineState.kt @@ -0,0 +1,36 @@ +package com.emberjs.configuration.test + +import com.emberjs.configuration.EmberCommandLineState +import com.emberjs.configuration.EmberConfiguration +import com.intellij.execution.DefaultExecutionResult +import com.intellij.execution.ExecutionResult +import com.intellij.execution.Executor +import com.intellij.execution.configurations.RunConfiguration +import com.intellij.execution.process.ProcessHandler +import com.intellij.execution.runners.ExecutionEnvironment +import com.intellij.execution.runners.ProgramRunner +import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil +import com.intellij.execution.testframework.autotest.ToggleAutoTestAction +import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil.createAndAttachConsole + +class EmberTestCommandLineState(environment: ExecutionEnvironment) : EmberCommandLineState(environment) { + private val TEST_FRAMEWORK_NAME = "ember-qunit" + + override fun execute(executor: Executor, runner: ProgramRunner<*>): ExecutionResult { + val configuration = (environment.runProfile as EmberConfiguration) + + // enforce teamcity reporter because converter requires it + (configuration.options as EmberTestOptions).reporter.value = "teamcity" + + val processHandler: ProcessHandler = startProcess() + + val properties = EmberTestConsoleProperties(configuration as RunConfiguration, TEST_FRAMEWORK_NAME, executor) + val console = createAndAttachConsole(TEST_FRAMEWORK_NAME, processHandler, properties) + + SMTestRunnerConnectionUtil.createAndAttachConsole(TEST_FRAMEWORK_NAME, processHandler, properties) + + val executionResult = DefaultExecutionResult(console, processHandler, *createActions(console, processHandler)) + executionResult.setRestartActions(ToggleAutoTestAction()) + return executionResult + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/test/EmberTestConfiguration.kt b/src/main/kotlin/com/emberjs/configuration/test/EmberTestConfiguration.kt new file mode 100644 index 00000000..6c3f8efd --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/EmberTestConfiguration.kt @@ -0,0 +1,48 @@ +package com.emberjs.configuration.test + +import com.emberjs.configuration.EmberConfiguration +import com.emberjs.configuration.test.ui.EmberTestSettingsEditor +import com.intellij.execution.ExecutionException +import com.intellij.execution.Executor +import com.intellij.execution.configurations.* +import com.intellij.execution.runners.ExecutionEnvironment +import com.intellij.openapi.options.SettingsEditor +import com.intellij.openapi.project.Project +import org.jdom.Element +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable + +class EmberTestConfiguration(project: Project, factory: ConfigurationFactory, name: String) : RunConfigurationBase(project, factory, name), EmberConfiguration { + override val options = EmberTestOptions() + override val command: String = "test" + + @NotNull + override fun getConfigurationEditor(): SettingsEditor { + return EmberTestSettingsEditor() + } + + @Throws(RuntimeConfigurationException::class) + override fun checkConfiguration() { + + } + + @Nullable + @Throws(ExecutionException::class) + override fun getState(@NotNull executor: Executor, @NotNull executionEnvironment: ExecutionEnvironment): RunProfileState? { + return EmberTestCommandLineState(executionEnvironment) + } + + override fun writeExternal(element: Element?) { + super.writeExternal(element) + element?.let { + options.fields().forEach { optionsField -> optionsField.writeTo(element)} + } + } + + override fun readExternal(element: Element?) { + super.readExternal(element) + element?.let { + options.fields().forEach { optionsField -> optionsField.readFrom(element) } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/test/EmberTestConfigurationFactory.kt b/src/main/kotlin/com/emberjs/configuration/test/EmberTestConfigurationFactory.kt new file mode 100644 index 00000000..326fede4 --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/EmberTestConfigurationFactory.kt @@ -0,0 +1,21 @@ +package com.emberjs.configuration.test + +import com.intellij.execution.configurations.ConfigurationFactory +import com.intellij.execution.configurations.ConfigurationType +import com.intellij.execution.configurations.RunConfiguration +import com.intellij.openapi.project.Project + +class EmberTestConfigurationFactory(type: ConfigurationType) : ConfigurationFactory(type) { + + override fun createTemplateConfiguration(project: Project): RunConfiguration { + return EmberTestConfiguration(project, this, "Ember test") + } + + override fun getName(): String { + return FACTORY_NAME; + } + + companion object { + private val FACTORY_NAME = "Ember test configuration factory" + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/test/EmberTestConfigurationType.kt b/src/main/kotlin/com/emberjs/configuration/test/EmberTestConfigurationType.kt new file mode 100644 index 00000000..03afbc43 --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/EmberTestConfigurationType.kt @@ -0,0 +1,16 @@ +package com.emberjs.configuration.test + +import com.emberjs.icons.EmberIcons +import com.intellij.execution.configurations.ConfigurationFactory +import com.intellij.execution.configurations.ConfigurationTypeBase + +class EmberTestConfigurationType : ConfigurationTypeBase( + "EMBER_TEST_CONFIGURATION", + "Ember Test", + "Ember Test Configuration", + EmberIcons.ICON_16 +) { + override fun getConfigurationFactories(): Array { + return arrayOf(EmberTestConfigurationFactory(this)) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/test/EmberTestConsoleProperties.kt b/src/main/kotlin/com/emberjs/configuration/test/EmberTestConsoleProperties.kt new file mode 100644 index 00000000..05d77dbe --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/EmberTestConsoleProperties.kt @@ -0,0 +1,21 @@ +package com.emberjs.configuration.test + +import com.intellij.execution.Executor +import com.intellij.execution.configurations.RunConfiguration +import com.intellij.execution.testframework.TestConsoleProperties +import com.intellij.execution.testframework.sm.SMCustomMessagesParsing +import com.intellij.execution.testframework.sm.runner.OutputToGeneralTestEventsConverter +import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties + +class EmberTestConsoleProperties( + configuration: RunConfiguration, + TEST_FRAMEWORK_NAME: String, + executor: Executor) : SMTRunnerConsoleProperties( + configuration, + TEST_FRAMEWORK_NAME, + executor +), SMCustomMessagesParsing { + override fun createTestEventsConverter(testFrameworkName: String, consoleProperties: TestConsoleProperties): OutputToGeneralTestEventsConverter { + return EmberTestOutputToGeneralTestEventsConverter(testFrameworkName, consoleProperties); + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/test/EmberTestOptions.kt b/src/main/kotlin/com/emberjs/configuration/test/EmberTestOptions.kt new file mode 100644 index 00000000..cc92ed8a --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/EmberTestOptions.kt @@ -0,0 +1,87 @@ +package com.emberjs.configuration.test + +import com.emberjs.configuration.EmberOptions +import com.emberjs.configuration.OptionsField +import com.emberjs.configuration.StringOptionsField + +enum class LaunchType(val value: String) { + DEFAULT("DEFAULT"), + CUSTOM("CUSTOM"), + NONE("NONE") +} + +enum class FilterType(val value: String) { + ALL("ALL"), + MODULE("MODULE"), + FILTER("FILTER") +} + +class EmberTestOptions : EmberOptions { + val environment = StringOptionsField("test", "ENVIRONMENT", "environment") + val configFile = StringOptionsField("", "CONFIG_FILE", "config-file") + val host = StringOptionsField("", "HOST", "host") + val testPort = StringOptionsField("7357", "TEST_PORT", "test-port") + + val filterOption = StringOptionsField(FilterType.ALL.value, "FILTER_OPTION", "") + val filter = StringOptionsField("", "FILTER", "filter") + val module = StringOptionsField("", "MODULE", "module") + + val watcher = StringOptionsField("events", "WATCHER", "watcher") + val testemDebug = StringOptionsField("", "TESTEM_DEBUG", "testem-debug") + val testPage = StringOptionsField("", "TEST_PAGE", "test-page") + val path = StringOptionsField("", "PATH", "path") + val query = StringOptionsField("", "QUERY", "query") + val reporter = StringOptionsField("tap", "REPORTER", "reporter") + + val launchOption = StringOptionsField(LaunchType.DEFAULT.value, "LAUNCH_OPTION", "") + val launch = StringOptionsField("", "LAUNCH", "launch") + + override fun fields(): Array> { + return arrayOf( + environment, + configFile, + host, + testPort, + filter, + filterOption, + module, + watcher, + testemDebug, + testPage, + path, + query, + reporter, + launch, + launchOption + ) + } + + override fun toCommandLineOptions(): Array { + val options = fields() + .filter { + // allow any fields that aren't LAUNCH, FILTER, MODULE + !arrayOf("LAUNCH", "FILTER", "MODULE").contains(it.field) || + // allow any LAUNCH if LAUNCH_OPTION is CUSTOM or NONE + it.field == "LAUNCH" && arrayOf(LaunchType.CUSTOM.value, LaunchType.NONE.value).contains(launchOption.value) || + // allow any FILTER if FILTER_OPTION is FILTER + it.field =="FILTER" && filterOption.value == FilterType.FILTER.value || + // allow any MODULE if FILTER_OPTION is MODULE + it.field =="MODULE" && filterOption.value == FilterType.MODULE.value + } + .filter { optionsField -> + optionsField.cmdlineOptionName.isNotEmpty() && + optionsField.value != optionsField.default && + optionsField.value.toString().isNotEmpty() + } + .map { + if (it.field == "LAUNCH" && launchOption.value == LaunchType.NONE.value) { + "--${it.cmdlineOptionName}=false" + } else { + "--${it.cmdlineOptionName}=${it.value}" + } + } + .toTypedArray() + + return options + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/test/EmberTestOutputToGeneralTestEventsConverter.kt b/src/main/kotlin/com/emberjs/configuration/test/EmberTestOutputToGeneralTestEventsConverter.kt new file mode 100644 index 00000000..8a5bbbf5 --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/EmberTestOutputToGeneralTestEventsConverter.kt @@ -0,0 +1,32 @@ +package com.emberjs.configuration.test + +import com.intellij.execution.process.ProcessOutputTypes +import com.intellij.execution.testframework.TestConsoleProperties +import com.intellij.execution.testframework.sm.runner.OutputLineSplitter +import com.intellij.execution.testframework.sm.runner.OutputToGeneralTestEventsConverter +import com.intellij.openapi.util.Key + +class EmberTestOutputToGeneralTestEventsConverter(testFrameworkName: String, consoleProperties: TestConsoleProperties) : + OutputToGeneralTestEventsConverter(testFrameworkName, consoleProperties) { + var splitter: OutputLineSplitter; + + private val REGEX_TEAMCITY_LINE = """^##teamcity.*""".toRegex(RegexOption.DOT_MATCHES_ALL) + + init { + splitter = object : OutputLineSplitter(true) { + override fun onLineAvailable(text: String, outputType: Key<*>, tcLikeFakeOutput: Boolean) { + subProcessConsistentText(text, outputType, tcLikeFakeOutput); + } + } + } + + fun subProcessConsistentText(text: String, outputType: Key<*>, tcLikeFakeOutput: Boolean) { + if (REGEX_TEAMCITY_LINE.matches(text)) { + super.processConsistentText(text, ProcessOutputTypes.STDOUT, false) + } + } + + override fun process(text: String?, outputType: Key<*>?) { + splitter.process(text, outputType); + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/test/EmberTestProgramRunner.kt b/src/main/kotlin/com/emberjs/configuration/test/EmberTestProgramRunner.kt new file mode 100644 index 00000000..02eb8f83 --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/EmberTestProgramRunner.kt @@ -0,0 +1,12 @@ +package com.emberjs.configuration.test + +import com.intellij.execution.configurations.RunProfile +import com.intellij.execution.executors.DefaultRunExecutor +import com.intellij.execution.runners.DefaultProgramRunner + +class EmberTestProgramRunner : DefaultProgramRunner() { + override fun getRunnerId(): String = "EmberTestRunner" + + override fun canRun(executorId: String, profile: RunProfile): Boolean = + executorId == DefaultRunExecutor.EXECUTOR_ID && profile is EmberTestConfiguration +} \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/test/ui/EmberTestSettingsEditor.form b/src/main/kotlin/com/emberjs/configuration/test/ui/EmberTestSettingsEditor.form new file mode 100644 index 00000000..35d45e46 --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/ui/EmberTestSettingsEditor.form @@ -0,0 +1,350 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/kotlin/com/emberjs/configuration/test/ui/EmberTestSettingsEditor.kt b/src/main/kotlin/com/emberjs/configuration/test/ui/EmberTestSettingsEditor.kt new file mode 100644 index 00000000..73c8e1b1 --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/test/ui/EmberTestSettingsEditor.kt @@ -0,0 +1,205 @@ +package com.emberjs.configuration.test.ui + +import com.emberjs.configuration.test.EmberTestConfiguration +import com.emberjs.configuration.test.EmberTestOptions +import com.emberjs.configuration.test.FilterType +import com.emberjs.configuration.test.LaunchType +import com.emberjs.configuration.utils.PublicStringAddEditDeleteListPanel +import com.intellij.openapi.options.ConfigurationException +import com.intellij.openapi.options.SettingsEditor +import com.intellij.openapi.ui.Messages +import com.intellij.ui.CollectionComboBoxModel +import com.intellij.ui.EditorTextField +import com.intellij.ui.HideableDecorator +import org.jetbrains.annotations.NotNull +import java.util.* +import javax.swing.* + +class EmberTestSettingsEditor : SettingsEditor() { + private var myPanel: JPanel? = null + private var advancedSettings: JPanel? = null + private var advancedSettingsWrapper: JPanel? = null + private var launcherPanel: JPanel? = null + + private var testPortTextField: EditorTextField? = null + private var environmentComboBox: JComboBox? = null + + private var hostTextField: EditorTextField? = null + private var configFileTextField: EditorTextField? = null + private var filterTextField: EditorTextField? = null + private var moduleTextField: EditorTextField? = null + private var watcherTextField: EditorTextField? = null + private var testemDebugTextField: EditorTextField? = null + private var testPageTextField: EditorTextField? = null + private var pathTextField: EditorTextField? = null + private var queryTextField: EditorTextField? = null + + private var launcherDefaultRadioButton: JRadioButton? = null + private var launcherCustomRadioButton: JRadioButton? = null + private var launcherNoneRadioButton: JRadioButton? = null + + private var filterAllRadioButton: JRadioButton? = null + private var filterModuleRadioButton: JRadioButton? = null + private var filterFilterRadioButton: JRadioButton? = null + + private var launchAddEditDeleteListPanel: PublicStringAddEditDeleteListPanel? = null + + private var filterModulePanel: JPanel? = null + private var filterFilterPanel: JPanel? = null + + private var launcherButtonGroup: ButtonGroup? = null + private var filterButtonGroup: ButtonGroup? = null + + val bundle: ResourceBundle = ResourceBundle.getBundle("com.emberjs.locale.EmberTestConfigurationEditor") + val launchers = mutableListOf("Chrome") + + private val mappings = mutableListOf( + testPortTextField to EmberTestOptions::testPort, + environmentComboBox to EmberTestOptions::environment, + hostTextField to EmberTestOptions::host, + configFileTextField to EmberTestOptions::configFile, + filterTextField to EmberTestOptions::filter, + moduleTextField to EmberTestOptions::module, + watcherTextField to EmberTestOptions::watcher, + testemDebugTextField to EmberTestOptions::testemDebug, + pathTextField to EmberTestOptions::path, + queryTextField to EmberTestOptions::query, + testPageTextField to EmberTestOptions::testPage + ) + + private val launchTypToRadioButton = mutableListOf( + LaunchType.DEFAULT to launcherDefaultRadioButton, + LaunchType.CUSTOM to launcherCustomRadioButton, + LaunchType.NONE to launcherNoneRadioButton + ) + + private val filterTypeToRadioButton = mutableListOf( + FilterType.ALL to filterAllRadioButton, + FilterType.FILTER to filterFilterRadioButton, + FilterType.MODULE to filterModuleRadioButton + ) + + override fun resetEditorFrom(configuration: EmberTestConfiguration) { + handleLaunchRadio(try { + LaunchType.valueOf(configuration.options.launchOption.value) + } catch (_: Exception) { + LaunchType.DEFAULT + }) + + handleFilterRadio(try { + FilterType.valueOf(configuration.options.filterOption.value) + } catch (_: Exception) { + FilterType.ALL + }) + + mappings + .filter { it.first != null } + .forEach { (first, second) -> first?.let { second.get(configuration.options).writeTo(it) } } + } + + @Throws(ConfigurationException::class) + override fun applyEditorTo(configuration: EmberTestConfiguration) { + mappings + .filter { it.first != null } + .forEach { (first, second) -> first?.let { second.get(configuration.options).readFrom(it) } } + } + + @NotNull + override fun createEditor(): JComponent { + // Create the collapsible component for advances settings + HideableDecorator(advancedSettingsWrapper, bundle.getString("advanced"), false).apply { + setContentComponent(advancedSettings as JComponent) + setOn(false) + } + + // somehow the ButtonGroup aren't bound :( + launcherButtonGroup = ButtonGroup().apply { + add(launcherCustomRadioButton) + add(launcherDefaultRadioButton) + add(launcherNoneRadioButton) + } + + filterButtonGroup = ButtonGroup().apply { + add(filterAllRadioButton) + add(filterModuleRadioButton) + add(filterFilterRadioButton) + } + + mappings.add(filterButtonGroup to EmberTestOptions::filterOption) + mappings.add(launcherButtonGroup to EmberTestOptions::launchOption) + + environmentComboBox?.model = CollectionComboBoxModel().apply { + add("test") + add("development") + add("production") + } + + launchAddEditDeleteListPanel = object : PublicStringAddEditDeleteListPanel("", launchers) { + override fun editSelectedItem(item: String?): String? { + val message = Messages.showInputDialog(this, + bundle.getString("launchers.edit.message"), + bundle.getString("launchers.edit.title"), + Messages.getQuestionIcon(), + item, null) + + return if (message === null || message.isEmpty()) { + null + } else { + message + } + } + + override fun findItemToAdd(): String? { + val message = Messages.showInputDialog(this, + bundle.getString("launchers.create.message"), + bundle.getString("launchers.create.title"), + Messages.getQuestionIcon(), + "", null) + + return if (message === null || message.isEmpty()) { + null + } else { + message + } + } + } + + launchTypToRadioButton.forEach({ (first, second) -> + second!!.actionCommand = first.value + second.addActionListener { handleLaunchRadio(first) } + }) + filterTypeToRadioButton.forEach({ (first, second) -> + second!!.actionCommand = first.value + second.addActionListener { handleFilterRadio(first) } + }) + + launcherPanel!!.add(launchAddEditDeleteListPanel) + mappings.add(launchAddEditDeleteListPanel to EmberTestOptions::launch) + + return myPanel as JComponent + } + + fun handleLaunchRadio(type: LaunchType) { + when (type) { + LaunchType.CUSTOM -> launcherPanel!!.isVisible = true + LaunchType.NONE, LaunchType.DEFAULT -> launcherPanel!!.isVisible = false + } + } + + fun handleFilterRadio(type: FilterType) { + when (type) { + FilterType.MODULE -> { + filterModulePanel!!.isVisible = true + filterFilterPanel!!.isVisible = false + } + FilterType.FILTER -> { + filterModulePanel!!.isVisible = false + filterFilterPanel!!.isVisible = true + } + else -> { + filterModulePanel!!.isVisible = false + filterFilterPanel!!.isVisible = false + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/emberjs/configuration/utils/PublicStringAddEditDeleteListPanel.kt b/src/main/kotlin/com/emberjs/configuration/utils/PublicStringAddEditDeleteListPanel.kt new file mode 100644 index 00000000..487247d3 --- /dev/null +++ b/src/main/kotlin/com/emberjs/configuration/utils/PublicStringAddEditDeleteListPanel.kt @@ -0,0 +1,19 @@ +package com.emberjs.configuration.utils + +import com.intellij.ui.AddEditDeleteListPanel + +abstract class PublicStringAddEditDeleteListPanel( + title: String, + initialList: List +) : AddEditDeleteListPanel(title, initialList) { + fun replaceItems(items: List) { + myListModel.clear() + + if (items.isNotEmpty()) { + + items.forEach { myListModel.addElement(it) } + + myList.setSelectedValue(items.last(), false) + } + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 804e557a..173687b3 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -68,6 +68,10 @@ + + + + diff --git a/src/main/resources/com/emberjs/locale/EmberTestConfigurationEditor.properties b/src/main/resources/com/emberjs/locale/EmberTestConfigurationEditor.properties new file mode 100644 index 00000000..ab6d5d22 --- /dev/null +++ b/src/main/resources/com/emberjs/locale/EmberTestConfigurationEditor.properties @@ -0,0 +1,21 @@ +testPort=Test port: +host=Host: +environment=Environment: +path=Path: +watcher=Watcher: +configFile=Config file: +filter=Filter: +module=Module: +testemDebug=Testem debug: +testPage=Test page: +query=Query: +launch=Launch: + +advanced=Advanced settings + +launchers=Launchers +launchers.edit.title=Edit launcher +launchers.edit.message=Input a testem launcher (i.e. Chrome) + +launchers.create.title=Create launcher +launchers.create.message=Create a testem launcher (i.e. Chrome) \ No newline at end of file