Skip to content

Commit 8403ca0

Browse files
committed
Add button for local/wsl scenario, use spinners for int fields
1 parent 6b3510f commit 8403ca0

File tree

6 files changed

+198
-151
lines changed

6 files changed

+198
-151
lines changed

clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotConfigurable.kt

Lines changed: 160 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,33 @@ import com.intellij.ui.dsl.builder.LabelPosition
1313
import com.intellij.ui.dsl.builder.Panel
1414
import com.intellij.ui.dsl.builder.Row
1515
import com.intellij.ui.dsl.builder.bindIntText
16+
import com.intellij.ui.dsl.builder.bindIntValue
1617
import com.intellij.ui.dsl.builder.bindSelected
1718
import com.intellij.ui.dsl.builder.bindText
1819
import com.intellij.ui.dsl.builder.columns
1920
import com.intellij.ui.dsl.builder.panel
21+
import com.intellij.ui.layout.ComponentPredicate
2022
import kotlin.reflect.KMutableProperty0
2123
import org.utbot.cpp.clion.plugin.UTBot
2224
import org.utbot.cpp.clion.plugin.listeners.UTBotSettingsChangedListener
25+
import org.utbot.cpp.clion.plugin.ui.ObservableValue
2326
import org.utbot.cpp.clion.plugin.ui.sourceFoldersView.UTBotProjectViewPaneForSettings
2427
import org.utbot.cpp.clion.plugin.utils.commandLineEditor
28+
import org.utbot.cpp.clion.plugin.utils.isWindows
29+
import org.utbot.cpp.clion.plugin.utils.toWslFormat
2530
import java.awt.Dimension
2631

2732
class UTBotConfigurable(private val myProject: Project) : BoundConfigurable(
28-
"Project Settings to generate tests"
33+
"Project Settings to Generate Tests"
2934
) {
3035
private val logger = Logger.getInstance("ProjectConfigurable")
3136
private val panel by lazy { createMainPanel() }
3237

3338
private val settings: UTBotProjectStoredSettings.State
3439
get() = myProject.settings.storedSettings
3540

41+
private val isLocalOrWsl = ObservableValue(settings.isLocalOrWslScenario)
42+
3643
init {
3744
myProject.messageBus.connect()
3845
.subscribe(UTBotSettingsChangedListener.TOPIC, UTBotSettingsChangedListener {
@@ -55,130 +62,169 @@ class UTBotConfigurable(private val myProject: Project) : BoundConfigurable(
5562
private fun createMainPanel(): DialogPanel {
5663
logger.trace("createPanel was called")
5764
return panel {
58-
group("Connection Settings") {
59-
row(UTBot.message("settings.project.port")) {
60-
intTextField().bindIntText(projectIndependentSettings::port).applyToComponent {
61-
maximumSize = TEXT_FIELD_MAX_SIZE
62-
}
63-
}.rowComment(UTBot.message("deployment.utbotPort.description"))
64-
row(UTBot.message("settings.project.serverName")) {
65-
textField().bindText(projectIndependentSettings::serverName)
66-
}.rowComment(UTBot.message("deployment.utbotHost.description"))
67-
row(UTBot.message("settings.project.remotePath")) {
68-
textField().bindText(settings::remotePath).columns(COLUMNS_LARGE)
69-
}.rowComment(UTBot.message("deployment.remotePath.description"))
70-
}
65+
group("Connection Settings") { this.createConnectionSettings() }
66+
group("Paths") { this.createPathsSettings() }
67+
group("CMake") { this.createCMakeSettings() }
68+
group("Generator Settings") { this.createGeneratorSettings() }
69+
}
70+
}
7171

72-
group("Paths") {
73-
row(UTBot.message("settings.project.projectPath")) {
74-
textFieldWithBrowseButton(
75-
UTBot.message("settings.project.projectPath.title"),
76-
myProject,
77-
FileChooserDescriptorFactory.createSingleFileDescriptor()
78-
).bindText(
79-
getter = { myProject.settings.projectPath },
80-
setter = { value -> myProject.settings.projectPath = value })
81-
.columns(COLUMNS_LARGE)
82-
}.rowComment(UTBot.message("settings.project.projectPath.info"))
83-
createPathChooser(
84-
settings::buildDirRelativePath,
85-
UTBot.message("settings.project.buildDir"),
86-
UTBot.message("settings.project.buildDir.browse.title")
87-
).rowComment(UTBot.message("paths.buildDirectory.description"))
88-
createPathChooser(
89-
settings::targetPath,
90-
UTBot.message("settings.project.target"),
91-
UTBot.message("settings.project.target.browse.title")
92-
).rowComment(UTBot.message("paths.target.description"))
93-
createPathChooser(
94-
settings::testDirPath,
95-
UTBot.message("settings.project.testsDir"),
96-
UTBot.message("settings.project.testsDir.browse.title")
97-
).rowComment(UTBot.message("paths.testsDirectory.description"))
98-
99-
row {
100-
val pane = UTBotProjectViewPaneForSettings(myProject)
101-
cell(pane.createComponent()).onApply {
102-
pane.apply()
103-
}.onReset {
104-
pane.reset()
105-
}.onIsModified {
106-
pane.isModified()
107-
}.label(UTBot.message("settings.project.sourcePaths"), LabelPosition.TOP)
108-
}.bottomGap(BottomGap.SMALL).rowComment(UTBot.message("paths.sourceDirectories.description"))
109-
110-
111-
row {
112-
label("Try to get paths from CMake model: ")
113-
button("Detect Paths") {
114-
myProject.settings.predictPaths()
115-
myProject.settings.fireUTBotSettingsChanged()
116-
}
117-
}.rowComment("Queries CMake configurations to get source paths and build path. Also predicts tests folder")
72+
private fun Panel.createConnectionSettings() {
73+
row(UTBot.message("settings.project.port")) {
74+
intTextField().bindIntText(projectIndependentSettings::port).applyToComponent {
75+
maximumSize = TEXT_FIELD_MAX_SIZE
11876
}
77+
}.rowComment(UTBot.message("deployment.utbotPort.description"))
78+
79+
row {
80+
checkBox("Local or WSL scenario")
81+
.bindSelected(settings::isLocalOrWslScenario)
82+
.applyToComponent {
83+
this.addActionListener {
84+
isLocalOrWsl.value = !isLocalOrWsl.value
85+
}
86+
}
87+
}
11988

120-
group("CMake") {
121-
row(UTBot.message("settings.project.cmakeOptions")) {
122-
commandLineEditor(
123-
{ settings.cmakeOptions },
124-
{ settings.cmakeOptions = it }
125-
)
126-
}.rowComment(UTBot.message("paths.cmakeOptions.description"))
127-
}
89+
val enabledIfNotLocalOrWslScenario = object : ComponentPredicate() {
90+
override fun invoke(): Boolean = !isLocalOrWsl.value
91+
override fun addListener(listener: (Boolean) -> Unit) =
92+
isLocalOrWsl.addOnChangeListener { value -> listener(!value) }
93+
}
12894

129-
data class CheckBoxInfo(
130-
val boolProperty: KMutableProperty0<Boolean>,
131-
val title: String,
132-
val description: String
133-
) {
134-
fun add(panel: Panel) {
135-
panel.row {
136-
checkBox(title).bindSelected(boolProperty)
137-
}.rowComment(description)
95+
row(UTBot.message("settings.project.serverName")) {
96+
textField().bindText(projectIndependentSettings::serverName).applyToComponent {
97+
isLocalOrWsl.addOnChangeListener { newValue ->
98+
if (newValue)
99+
this.text = "localhost"
138100
}
139-
}
101+
}.enabledIf(enabledIfNotLocalOrWslScenario)
102+
}.rowComment(UTBot.message("deployment.utbotHost.description"))
103+
104+
row(UTBot.message("settings.project.remotePath")) {
105+
textField().bindText(settings::remotePath).columns(COLUMNS_LARGE)
106+
.applyToComponent {
107+
isLocalOrWsl.addOnChangeListener { newValue ->
108+
if (newValue)
109+
this.text = if (isWindows) myProject.settings.projectPath.toWslFormat() else ""
110+
}
111+
}.enabledIf(enabledIfNotLocalOrWslScenario)
112+
}.rowComment(UTBot.message("deployment.remotePath.description"))
113+
}
140114

141-
group("Generator settings") {
142-
val checkBoxes = listOf(
143-
CheckBoxInfo(
144-
settings::useStubs,
145-
UTBot.message("stubs.useStubs.title"),
146-
UTBot.message("stubs.useStubs.description")
147-
),
148-
CheckBoxInfo(
149-
settings::verbose,
150-
UTBot.message("testsGeneration.verboseFormatting.title"),
151-
UTBot.message("testsGeneration.verboseFormatting.description")
152-
),
153-
CheckBoxInfo(
154-
settings::useDeterministicSearcher,
155-
UTBot.message("advanced.useDeterministicSearcher.title"),
156-
UTBot.message("advanced.useDeterministicSearcher.description")
157-
),
158-
CheckBoxInfo(
159-
settings::generateForStaticFunctions,
160-
UTBot.message("testsGeneration.generateForStaticFunctions.title"),
161-
UTBot.message("testsGeneration.generateForStaticFunctions.description")
162-
)
163-
)
164-
checkBoxes.forEach {
165-
it.add(this)
166-
}
115+
private fun Panel.createPathsSettings() {
116+
row(UTBot.message("settings.project.projectPath")) {
117+
textFieldWithBrowseButton(
118+
UTBot.message("settings.project.projectPath.title"),
119+
myProject,
120+
FileChooserDescriptorFactory.createSingleFileDescriptor()
121+
).bindText(
122+
getter = { myProject.settings.projectPath },
123+
setter = { value -> myProject.settings.projectPath = value })
124+
.columns(COLUMNS_LARGE)
125+
}.rowComment(UTBot.message("settings.project.projectPath.info"))
126+
createPathChooser(
127+
settings::buildDirRelativePath,
128+
UTBot.message("settings.project.buildDir"),
129+
UTBot.message("settings.project.buildDir.browse.title")
130+
).rowComment(UTBot.message("paths.buildDirectory.description"))
131+
createPathChooser(
132+
settings::targetPath,
133+
UTBot.message("settings.project.target"),
134+
UTBot.message("settings.project.target.browse.title")
135+
).rowComment(UTBot.message("paths.target.description"))
136+
createPathChooser(
137+
settings::testDirPath,
138+
UTBot.message("settings.project.testsDir"),
139+
UTBot.message("settings.project.testsDir.browse.title")
140+
).rowComment(UTBot.message("paths.testsDirectory.description"))
141+
142+
row {
143+
val pane = UTBotProjectViewPaneForSettings(myProject)
144+
cell(pane.createComponent()).onApply {
145+
pane.apply()
146+
}.onReset {
147+
pane.reset()
148+
}.onIsModified {
149+
pane.isModified()
150+
}.label(UTBot.message("settings.project.sourcePaths"), LabelPosition.TOP)
151+
}.bottomGap(BottomGap.SMALL).rowComment(UTBot.message("paths.sourceDirectories.description"))
152+
153+
154+
row {
155+
label("Try to get paths from CMake model: ")
156+
button("Detect Paths") {
157+
myProject.settings.predictPaths()
158+
myProject.settings.fireUTBotSettingsChanged()
159+
}
160+
}.rowComment("Queries CMake configurations to get source paths and build path. Also predicts tests folder")
161+
}
167162

168-
row(UTBot.message("advanced.timeoutPerFunction.title")) {
169-
intTextField().bindIntText(settings::timeoutPerFunction).applyToComponent {
170-
maximumSize = TEXT_FIELD_MAX_SIZE
171-
}
172-
}.rowComment(UTBot.message("advanced.timeoutPerFunction.description"))
163+
private fun Panel.createCMakeSettings() {
164+
row(UTBot.message("settings.project.cmakeOptions")) {
165+
commandLineEditor(
166+
{ settings.cmakeOptions },
167+
{ settings.cmakeOptions = it }
168+
)
169+
}.rowComment(UTBot.message("paths.cmakeOptions.description"))
170+
}
173171

174-
row(UTBot.message("advanced.timeoutPerTest.title")) {
175-
intTextField().bindIntText(settings::timeoutPerFunction).applyToComponent {
176-
maximumSize = TEXT_FIELD_MAX_SIZE
177-
}
178-
}.rowComment(UTBot.message("advanced.timeoutPerTest.description"))
172+
private fun Panel.createGeneratorSettings() {
173+
data class CheckBoxInfo(
174+
val boolProperty: KMutableProperty0<Boolean>,
175+
val title: String,
176+
val description: String
177+
) {
178+
fun add(panel: Panel) {
179+
panel.row {
180+
checkBox(title).bindSelected(boolProperty)
181+
}.rowComment(description)
179182
}
183+
}
180184

185+
val checkBoxes = listOf(
186+
CheckBoxInfo(
187+
settings::useStubs,
188+
UTBot.message("stubs.useStubs.title"),
189+
UTBot.message("stubs.useStubs.description")
190+
),
191+
CheckBoxInfo(
192+
settings::verbose,
193+
UTBot.message("testsGeneration.verboseFormatting.title"),
194+
UTBot.message("testsGeneration.verboseFormatting.description")
195+
),
196+
CheckBoxInfo(
197+
settings::useDeterministicSearcher,
198+
UTBot.message("advanced.useDeterministicSearcher.title"),
199+
UTBot.message("advanced.useDeterministicSearcher.description")
200+
),
201+
CheckBoxInfo(
202+
settings::generateForStaticFunctions,
203+
UTBot.message("testsGeneration.generateForStaticFunctions.title"),
204+
UTBot.message("testsGeneration.generateForStaticFunctions.description")
205+
)
206+
)
207+
checkBoxes.forEach {
208+
it.add(this)
181209
}
210+
211+
row(UTBot.message("advanced.timeoutPerFunction.title")) {
212+
spinner(
213+
UTBotProjectStoredSettings.TIMEOUT_PER_FUNCTION_MIN_VALUE..
214+
UTBotProjectStoredSettings.TIMEOUT_PER_FUNCTION_MAX_VALUE
215+
).bindIntValue(settings::timeoutPerFunction).applyToComponent {
216+
maximumSize = TEXT_FIELD_MAX_SIZE
217+
}
218+
}.rowComment(UTBot.message("advanced.timeoutPerFunction.description"))
219+
220+
row(UTBot.message("advanced.timeoutPerTest.title")) {
221+
spinner(
222+
UTBotProjectStoredSettings.TIMEOUT_PER_TEST_MIN_VALUE..
223+
UTBotProjectStoredSettings.TIMEOUT_PER_TEST_MAX_VALUE
224+
).bindIntValue(settings::timeoutPerFunction).applyToComponent {
225+
maximumSize = TEXT_FIELD_MAX_SIZE
226+
}
227+
}.rowComment(UTBot.message("advanced.timeoutPerTest.description"))
182228
}
183229

184230
override fun isModified(): Boolean {

clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotProjectStoredSettings.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class UTBotProjectStoredSettings(val project: Project) : PersistentStateComponen
3232
var generateForStaticFunctions: Boolean = true,
3333
var useStubs: Boolean = true,
3434
var useDeterministicSearcher: Boolean = true,
35+
var isLocalOrWslScenario: Boolean = false,
3536
var verbose: Boolean = false,
3637
var timeoutPerFunction: Int = 0,
3738
var timeoutPerTest: Int = 30
@@ -73,5 +74,9 @@ class UTBotProjectStoredSettings(val project: Project) : PersistentStateComponen
7374
const val REMOTE_PATH_VALUE_FOR_LOCAL_SCENARIO = ""
7475
const val DEFAULT_RELATIVE_PATH_TO_TEST_DIR = "utbot-tests"
7576
const val DEFAULT_RELATIVE_PATH_TO_BUILD_DIR = "utbot-build"
77+
const val TIMEOUT_PER_TEST_MAX_VALUE = 1000
78+
const val TIMEOUT_PER_TEST_MIN_VALUE = 0
79+
const val TIMEOUT_PER_FUNCTION_MAX_VALUE = 1000
80+
const val TIMEOUT_PER_FUNCTION_MIN_VALUE = 0
7681
}
7782
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.utbot.cpp.clion.plugin.ui
2+
3+
import kotlin.properties.Delegates
4+
5+
// allows attaching multiple listeners for value change
6+
class ObservableValue<T>(initialValue: T) {
7+
private val changeListeners: MutableList<(T) -> Unit> = mutableListOf()
8+
var value: T by Delegates.observable(initialValue) { _, _, newVal ->
9+
changeListeners.forEach {
10+
it(newVal)
11+
}
12+
}
13+
14+
fun addOnChangeListener(listener: (T) -> Unit) {
15+
changeListeners.add(listener)
16+
}
17+
}

clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/UTBotProjectViewPaneForSettings.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import com.intellij.ide.projectView.impl.ProjectViewTree
55
import com.intellij.openapi.project.Project
66
import org.utbot.cpp.clion.plugin.settings.UTBotProjectStoredSettings
77
import org.utbot.cpp.clion.plugin.settings.settings
8-
import org.utbot.cpp.clion.plugin.ui.wizard.steps.ObservableValue
98
import org.utbot.cpp.clion.plugin.utils.localPath
109
import javax.swing.tree.DefaultTreeModel
10+
import org.utbot.cpp.clion.plugin.ui.ObservableValue
1111

1212
open class UTBotProjectViewPaneForSettings(project: Project) : UTBotProjectViewPane(project) {
1313
private val sourceDirs: ObservableValue<Set<String>> = initObservableDirectories()

0 commit comments

Comments
 (0)