Skip to content

Commit a8b4c4d

Browse files
committed
Separate Scheme into State and Scheme
...once again. This time to allow TemplateList to be a State but not a Scheme.
1 parent 99b338e commit a8b4c4d

31 files changed

+518
-477
lines changed

build.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ dependencies {
3333
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
3434
api("org.jetbrains.kotlin:kotlin-reflect")
3535

36-
testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:${properties("mockitoKotlinVersion")}")
3736
testImplementation("org.assertj:assertj-core:${properties("assertjVersion")}")
3837
testImplementation("org.assertj:assertj-swing-junit:${properties("assertjSwingVersion")}")
39-
testImplementation("org.junit.platform:junit-platform-runner:${properties("junitRunnerVersion")}")
38+
testRuntimeOnly("org.junit.platform:junit-platform-runner:${properties("junitRunnerVersion")}")
4039
testImplementation("org.junit.jupiter:junit-jupiter-api:${properties("junitVersion")}")
4140
testImplementation("org.junit.jupiter:junit-jupiter-engine:${properties("junitVersion")}")
4241
testImplementation("org.junit.vintage:junit-vintage-engine:${properties("junitVersion")}")

gradle.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ emojiVersion = 5.1.1
2727
jacocoVersion = 0.8.7
2828
junitVersion = 5.7.2
2929
junitRunnerVersion = 1.7.2
30-
mockitoKotlinVersion = 2.2.0
3130
spekVersion = 2.0.15
3231
uuidGeneratorVersion = 3.3.0
3332

src/main/kotlin/com/fwdekker/randomness/Scheme.kt

Lines changed: 5 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,26 @@
11
package com.fwdekker.randomness
22

33
import com.fwdekker.randomness.array.ArraySchemeDecorator
4-
import com.intellij.util.xmlb.XmlSerializerUtil
54
import com.intellij.util.xmlb.annotations.Transient
6-
import icons.RandomnessIcons
75
import javax.swing.Icon
86
import kotlin.random.Random
97

108

119
/**
12-
* A scheme is a configurable random number generator.
10+
* A scheme is a [State] that is also a configurable random number generator.
1311
*
1412
* Schemes can additionally be given [SchemeDecorator]s that extend their functionality.
1513
*/
16-
abstract class Scheme {
14+
abstract class Scheme : State() {
1715
/**
1816
* Settings that determine whether the output should be an array of values.
1917
*/
2018
abstract val decorator: ArraySchemeDecorator?
2119

2220
/**
23-
* The name of the scheme as shown to the user.
21+
* The icon for this scheme; depends on whether its array decorator is enabled.
2422
*/
25-
abstract val name: String
26-
27-
/**
28-
* The icons that represent schemes of this type.
29-
*/
30-
@Transient
31-
open val icons: RandomnessIcons? = null
32-
33-
/**
34-
* The icon that represents this scheme instance.
35-
*/
36-
@get:Transient
37-
open val icon: Icon?
23+
override val icon: Icon?
3824
get() =
3925
if (decorator?.enabled == true) icons?.Array
4026
else icons?.Base
@@ -78,42 +64,7 @@ abstract class Scheme {
7864
abstract fun generateUndecoratedStrings(count: Int = 1): List<String>
7965

8066

81-
/**
82-
* Validates the scheme, and indicates whether and why it is invalid.
83-
*
84-
* @return `null` if the scheme is valid, or a string explaining why the scheme is invalid
85-
*/
86-
open fun doValidate(): String? = null
87-
88-
/**
89-
* Copies the given scheme into this scheme.
90-
*
91-
* Works by copying all references in a [deepCopy] of [scheme] into `this`. Note that fields marked with [Transient]
92-
* will be shallow-copied.
93-
*
94-
* @param scheme the scheme to copy into this scheme; should be a subclass of this scheme
95-
*/
96-
fun copyFrom(scheme: Scheme) = XmlSerializerUtil.copyBean(scheme.deepCopy(), this)
97-
98-
/**
99-
* Returns a deep copy of this scheme.
100-
*
101-
* Fields marked with [Transient] will be shallow-copied.
102-
*
103-
* @return a deep copy of this scheme
104-
*/
105-
abstract fun deepCopy(): Scheme
106-
107-
108-
/**
109-
* Holds constants.
110-
*/
111-
companion object {
112-
/**
113-
* The default value of the [name] field.
114-
*/
115-
const val DEFAULT_NAME: String = "Unnamed scheme"
116-
}
67+
abstract override fun deepCopy(): Scheme
11768
}
11869

11970
/**

src/main/kotlin/com/fwdekker/randomness/SchemeEditor.kt

Lines changed: 0 additions & 77 deletions
This file was deleted.

src/main/kotlin/com/fwdekker/randomness/SettingsConfigurable.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import javax.swing.JComponent
66

77

88
/**
9-
* Tells IntelliJ how to use a [SchemeEditor] in the settings dialog.
9+
* Tells IntelliJ how to use a [StateEditor] in the settings dialog.
1010
*/
1111
@Suppress("LateinitUsage") // `createComponent` is invoked before any of the other methods
1212
abstract class SettingsConfigurable : Configurable {
1313
/**
1414
* The user interface for changing the settings, displayed in IntelliJ's settings window.
1515
*/
16-
lateinit var editor: SchemeEditor<*> private set
16+
lateinit var editor: StateEditor<*> private set
1717

1818

1919
/**
@@ -34,7 +34,7 @@ abstract class SettingsConfigurable : Configurable {
3434
if (validationInfo != null)
3535
throw ConfigurationException(validationInfo, "Failed to save settings")
3636

37-
editor.applyScheme()
37+
editor.applyState()
3838
}
3939

4040
/**
@@ -59,5 +59,5 @@ abstract class SettingsConfigurable : Configurable {
5959
*
6060
* @return a new editor
6161
*/
62-
abstract fun createEditor(): SchemeEditor<*>
62+
abstract fun createEditor(): StateEditor<*>
6363
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.fwdekker.randomness
2+
3+
import com.intellij.util.xmlb.XmlSerializerUtil
4+
import com.intellij.util.xmlb.annotations.Transient
5+
import icons.RandomnessIcons
6+
import javax.swing.Icon
7+
8+
9+
/**
10+
* A state holds variables that can be configured.
11+
*/
12+
abstract class State {
13+
/**
14+
* The name of the scheme as shown to the user.
15+
*/
16+
abstract val name: String
17+
18+
/**
19+
* The icons that represent schemes of this type.
20+
*/
21+
@Transient
22+
open val icons: RandomnessIcons? = null
23+
24+
/**
25+
* The icon that represents this scheme instance.
26+
*/
27+
@get:Transient
28+
open val icon: Icon?
29+
get() = icons?.Base
30+
31+
32+
/**
33+
* Validates the scheme, and indicates whether and why it is invalid.
34+
*
35+
* @return `null` if the scheme is valid, or a string explaining why the scheme is invalid
36+
*/
37+
open fun doValidate(): String? = null
38+
39+
/**
40+
* Copies the given scheme into this scheme.
41+
*
42+
* Works by copying all references in a [deepCopy] of [scheme] into `this`. Note that fields marked with [Transient]
43+
* will be shallow-copied.
44+
*
45+
* @param scheme the scheme to copy into this scheme; should be a subclass of this scheme
46+
*/
47+
fun copyFrom(scheme: State) = XmlSerializerUtil.copyBean(scheme.deepCopy(), this)
48+
49+
/**
50+
* Returns a deep copy of this scheme.
51+
*
52+
* Fields marked with [Transient] will be shallow-copied.
53+
*
54+
* @return a deep copy of this scheme
55+
*/
56+
abstract fun deepCopy(): State
57+
58+
59+
/**
60+
* Holds constants.
61+
*/
62+
companion object {
63+
/**
64+
* The default value of the [name] field.
65+
*/
66+
const val DEFAULT_NAME: String = "Unnamed scheme"
67+
}
68+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.fwdekker.randomness
2+
3+
import javax.swing.JPanel
4+
5+
6+
/**
7+
* A component that can be used to edit a [State].
8+
*
9+
* The editor's state is initially read from [originalState]. Changes in the editor are written into [originalState]
10+
* when they are applied using [applyState].
11+
*
12+
* @param S the type of state that is edited; should be a self-reference
13+
* @property originalState the state object to write changes into
14+
*/
15+
abstract class StateEditor<S : State>(val originalState: S) {
16+
/**
17+
* The root component of the editor.
18+
*/
19+
abstract val rootComponent: JPanel
20+
21+
22+
/**
23+
* Loads the given state into the editor and into [originalState].
24+
*
25+
* @param state the state to load
26+
*/
27+
open fun loadState(state: S = originalState) {
28+
originalState.copyFrom(state)
29+
}
30+
31+
/**
32+
* Returns the editor's current state, including potentially unsaved changes.
33+
*
34+
* @return the editor's current state, including potentially unsaved changes
35+
*/
36+
abstract fun readState(): S
37+
38+
/**
39+
* Saves the editor's state into [originalState].
40+
*
41+
* Does nothing if and only if [isModified] returns false.
42+
*/
43+
fun applyState() = originalState.copyFrom(readState())
44+
45+
46+
/**
47+
* Returns true if and only if the editor contains modifications relative to the last saved state.
48+
*
49+
* Override this method if the default equals method of [S] is not sufficient to detect changes.
50+
*/
51+
open fun isModified() = originalState != readState()
52+
53+
/**
54+
* Resets the editor's state to the last saved state.
55+
*
56+
* Does nothing if and only if [isModified] return false.
57+
*/
58+
open fun reset() = loadState(originalState)
59+
60+
/**
61+
* Validates the state of the editor, i.e. of [readState], and indicates whether and why it is invalid.
62+
*
63+
* @return `null` if the state is valid, or a string explaining why the state is invalid
64+
*/
65+
open fun doValidate(): String? = readState().doValidate()
66+
67+
68+
/**
69+
* Adds a listener that is invoked whenever the editor's state is modified.
70+
*
71+
* The editor's state is defined by [readState], such that this method is triggered when a change occurs such that
72+
* [readState] returns a value that is non-equal to the value before the change was made.
73+
*
74+
* @param listener the listener that is invoked
75+
*/
76+
abstract fun addChangeListener(listener: () -> Unit)
77+
}

0 commit comments

Comments
 (0)