diff --git a/README.md b/README.md index 7d87d79..2752d47 100644 --- a/README.md +++ b/README.md @@ -20,39 +20,47 @@ A comprehensive user guide is available in Russian in the [Wiki of this reposito ## Features * Automata types - - DFA, NFA, epsilon-NFA - - PDA, n-PDA, DPDA, n-DPDA - - Register automaton - - Mealy machine, Moore machine - - Turing Machine (TM), multi-tape TM, multi-track TM, TM with registers - - Support building blocks + - DFA, NFA, epsilon-NFA + - PDA, n-PDA, DPDA, n-DPDA + - Register automaton + - Mealy machine, Moore machine + - Turing Machine (TM), multi-tape TM, multi-track TM, TM with registers + - Support building blocks * Automaton graph editing and visualization - - State and transition addition, editing, and deletion - - State moving - - Automatically laying out automaton graph - - Group selection - - Graph pane zooming and scrolling - - Undoing and redoing performed operations + - State and transition addition, editing, and deletion + - State moving + - Automatically laying out automaton graph + - Group selection + - Graph pane zooming and scrolling + - Undoing and redoing performed operations +* State-transition table and adjacency matrix representations + - State and transition addition, editing, and deletion + - Group selection + - Undoing and redoing performed operations * Simulation - - Instant simulation - - Step-by-state simulation - - Step-by-closure simulation - - Execution tree - - Advancing and restarting execution for individual execution states - - Freezing executions states - - Viewing execution states associated with a given state -* Transformations - - Determinization of finite automata - - Minimization of finite automata - - Conversion of regular expression to finite automata - - Elimination of epsilon-transitions - - Conversion of Mealy machine to Moore machine - - Conversion of Moore machine to Mealy machine + - Instant simulation + - Step-by-state simulation + - Step-by-closure simulation + - Execution tree + - Advancing and restarting execution for individual execution states + - Freezing executions states + - Viewing execution states associated with a given state +* Algorithms + - Determinization of finite automata + - Minimization of finite automata + - Conversion of regular expression to finite automata + - Elimination of epsilon-transitions + - Conversion of Mealy machine to Moore machine + - Conversion of Moore machine to Mealy machine + - Conversion of PDA to context-free grammar + - Hellings algorithm * Other features - - Non determinism detection - - Epsilon-transition detection - - Problem detection - - Serialization + - Non determinism detection + - Epsilon-transition detection + - Problem detection + - Serialization + - Test panel to run the automaton on multiple inputs + - Library of automaton examples ## Architecture @@ -77,7 +85,7 @@ This project uses Gradle build system. Here are commands for some of its most im | `./gradlew tasks` | Displays all runnable tasks | When running Gradle task you can specify target platform classifier with `-Pplatform={classifier}` option, -the following classifiers are supported: `win`, `linux`, `mac`, `win-x86`, `linux-aarch64`, `mac-aarch64`. +the following classifiers are supported: `win`, `linux`, `mac`, `win-x86`, `linux-aarch64`, `mac-aarch64`. ## Technologies @@ -87,10 +95,8 @@ the following classifiers are supported: `win`, `linux`, `mac`, `win-x86`, `linu **Build system:** Gradle -**Tests:** JUnit5, MockK +**Tests:** JUnit5, MockK, TestFX ## License The Automata Constructor is licensed under the Apache-2.0 license, as detailed in the [LICENSE](LICENSE) file. - - diff --git a/build.gradle.kts b/build.gradle.kts index e7dcb04..c89ecaf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -129,7 +129,7 @@ tasks { vendor = "spbu-se" application = appName appIdentifier = "automaton.constructor" - version = "1.2.1.0" + version = "1.3.0-SNAPSHOT" licenseFile("LICENSE") icons = icoFile bundleJre = System.getenv("JAVA_HOME") diff --git a/src/main/kotlin/automaton/constructor/controller/AutomatonGraphController.kt b/src/main/kotlin/automaton/constructor/controller/AutomatonGraphController.kt index 604bfbb..71ae11a 100644 --- a/src/main/kotlin/automaton/constructor/controller/AutomatonGraphController.kt +++ b/src/main/kotlin/automaton/constructor/controller/AutomatonGraphController.kt @@ -7,9 +7,10 @@ import automaton.constructor.model.element.* import automaton.constructor.utils.* import automaton.constructor.view.* import automaton.constructor.view.automaton.AutomatonGraphView +import automaton.constructor.view.elements.vertex.AutomatonVertexView +import automaton.constructor.view.elements.transition.TransitionView import javafx.geometry.Point2D import javafx.scene.control.ContextMenu -import javafx.scene.input.KeyCode import javafx.scene.input.MouseButton import javafx.scene.shape.Line import tornadofx.* @@ -89,27 +90,7 @@ class AutomatonGraphController(automaton: Automaton, automatonViewContext: Autom newTransitionSource = null } graphView.focusedProperty().onChange { if (!it) newTransitionSource = null } - graphView.setOnKeyPressed { event -> - event.consume() - if (event.code == KeyCode.DELETE && automaton.allowsModificationsByUser) { - automaton.undoRedoManager.group { - selectedElementsViews.forEach { - when (it.automatonElement) { - is AutomatonVertex -> automaton.removeVertex(it.automatonElement) - is Transition -> automaton.removeTransition(it.automatonElement) - } - } - } - clearSelection() - } else if (event.code == KeyCode.A && event.isControlDown) { - clearSelection() - selectedElementsViews.addAll( - graphView.edgeViews.values.flatMap { it.transitionViews } - .onEach { it.selected = true }) - selectedElementsViews.addAll( - graphView.vertexToViewMap.values.onEach { it.selected = true }) - } - } + enableShortcuts(graphView) } fun registerVertexView(automatonVertexView: AutomatonVertexView) { diff --git a/src/main/kotlin/automaton/constructor/controller/AutomatonRepresentationController.kt b/src/main/kotlin/automaton/constructor/controller/AutomatonRepresentationController.kt index e7c6f6a..2690809 100644 --- a/src/main/kotlin/automaton/constructor/controller/AutomatonRepresentationController.kt +++ b/src/main/kotlin/automaton/constructor/controller/AutomatonRepresentationController.kt @@ -4,14 +4,13 @@ import automaton.constructor.model.action.Action import automaton.constructor.model.action.ActionAvailability import automaton.constructor.model.action.ActionFailedException import automaton.constructor.model.automaton.Automaton -import automaton.constructor.model.element.AutomatonElement -import automaton.constructor.model.element.BuildingBlock -import automaton.constructor.model.element.State -import automaton.constructor.model.element.Transition +import automaton.constructor.model.element.* import automaton.constructor.utils.I18N import automaton.constructor.view.AutomatonElementView import automaton.constructor.view.AutomatonViewContext +import automaton.constructor.view.automaton.AutomatonRepresentationView import javafx.scene.control.ContextMenu +import javafx.scene.input.KeyCode import javafx.scene.input.MouseButton import tornadofx.* @@ -118,4 +117,24 @@ open class AutomatonRepresentationController( selectedElementsViews.onEach { it.selected = false }.clear() lastSelectedElement = null } -} \ No newline at end of file + + fun enableShortcuts(automatonView: AutomatonRepresentationView) { + automatonView.setOnKeyPressed { event -> + event.consume() + if (event.code == KeyCode.DELETE && automaton.allowsModificationsByUser) { + automaton.undoRedoManager.group { + selectedElementsViews.forEach { + when (it.automatonElement) { + is AutomatonVertex -> automaton.removeVertex(it.automatonElement) + is Transition -> automaton.removeTransition(it.automatonElement) + } + } + } + clearSelection() + } else if (event.code == KeyCode.A && event.isControlDown) { + clearSelection() + selectedElementsViews.addAll(automatonView.getAllElementsViews().onEach { it.selected = true }) + } + } + } +} diff --git a/src/main/kotlin/automaton/constructor/controller/algorithms/HellingsAlgoController.kt b/src/main/kotlin/automaton/constructor/controller/algorithms/HellingsAlgoController.kt index c2f5b2f..c405358 100644 --- a/src/main/kotlin/automaton/constructor/controller/algorithms/HellingsAlgoController.kt +++ b/src/main/kotlin/automaton/constructor/controller/algorithms/HellingsAlgoController.kt @@ -43,7 +43,8 @@ class HellingsAlgoController( it.rightSide.size == 1 && it.rightSide[0] is Terminal && it.rightSide[0].getSymbol() == transition.propetiesText } productions.forEach { - val newHellingsTransition = HellingsTransition(it.leftSide, transition.source, + val newHellingsTransition = HellingsTransition( + it.leftSide, transition.source, transition.target, SimpleBooleanProperty(false) ) currentTransitions.add(newHellingsTransition) @@ -52,7 +53,8 @@ class HellingsAlgoController( } if (grammar.productions.any { it.leftSide == grammar.initialNonterminal && it.rightSide.isEmpty() }) { openedAutomaton.vertices.forEach { - val newHellingsTransition = HellingsTransition(grammar.initialNonterminal, it, it, + val newHellingsTransition = HellingsTransition( + grammar.initialNonterminal, it, it, SimpleBooleanProperty(false) ) currentTransitions.add(newHellingsTransition) @@ -66,10 +68,12 @@ class HellingsAlgoController( val allTransitions = observableListOf() prepareForExecution(currentTransitions, allTransitions) - val hellingsAlgoExecutionWindow = find(mapOf( - HellingsAlgoExecutionView::currentTransitions to currentTransitions, - HellingsAlgoExecutionView::allTransitions to allTransitions - )).apply { title = I18N.messages.getString("HellingsAlgorithm.Execution.Title") } + val hellingsAlgoExecutionWindow = find( + mapOf( + HellingsAlgoExecutionView::currentTransitions to currentTransitions, + HellingsAlgoExecutionView::allTransitions to allTransitions + ) + ).apply { title = I18N.messages.getString("HellingsAlgorithm.Execution.Title") } hellingsAlgoExecutionWindow.openWindow() find(mapOf(CFGView::grammar to grammar)).apply { title = I18N.messages.getString("CFGView.Title") diff --git a/src/main/kotlin/automaton/constructor/model/element/AutomatonVertex.kt b/src/main/kotlin/automaton/constructor/model/element/AutomatonVertex.kt index 512495c..33c5914 100644 --- a/src/main/kotlin/automaton/constructor/model/element/AutomatonVertex.kt +++ b/src/main/kotlin/automaton/constructor/model/element/AutomatonVertex.kt @@ -58,6 +58,8 @@ sealed class AutomatonVertex( get() = super.undoRedoProperties + listOf(nameProperty, lastReleasePositionProperty, isInitialProperty, isFinalProperty, requiresLayoutProperty) + override fun toString() = name + companion object { const val RADIUS = 50.0 } diff --git a/src/main/kotlin/automaton/constructor/view/AutomatonEdgeView.kt b/src/main/kotlin/automaton/constructor/view/AutomatonEdgeView.kt index 6e7812c..294831f 100644 --- a/src/main/kotlin/automaton/constructor/view/AutomatonEdgeView.kt +++ b/src/main/kotlin/automaton/constructor/view/AutomatonEdgeView.kt @@ -4,9 +4,11 @@ import automaton.constructor.model.element.AutomatonEdge import automaton.constructor.model.element.AutomatonVertex.Companion.RADIUS import automaton.constructor.model.element.Transition import automaton.constructor.utils.* -import automaton.constructor.view.AutomatonVertexView.ShapeType -import automaton.constructor.view.AutomatonVertexView.ShapeType.CIRCLE -import automaton.constructor.view.AutomatonVertexView.ShapeType.SQUARE +import automaton.constructor.view.elements.vertex.AutomatonVertexView +import automaton.constructor.view.elements.vertex.AutomatonVertexView.ShapeType +import automaton.constructor.view.elements.vertex.AutomatonVertexView.ShapeType.CIRCLE +import automaton.constructor.view.elements.vertex.AutomatonVertexView.ShapeType.SQUARE +import automaton.constructor.view.elements.transition.TransitionView import javafx.beans.binding.Bindings.isNotNull import javafx.beans.value.ObservableBooleanValue import javafx.beans.value.ObservableDoubleValue diff --git a/src/main/kotlin/automaton/constructor/view/AutomatonView.kt b/src/main/kotlin/automaton/constructor/view/AutomatonView.kt index 0363262..54023f1 100644 --- a/src/main/kotlin/automaton/constructor/view/AutomatonView.kt +++ b/src/main/kotlin/automaton/constructor/view/AutomatonView.kt @@ -83,6 +83,7 @@ class AutomatonView(val automaton: Automaton, automatonViewContext: AutomatonVie }) automatonTransitionTableView.controller.lastSelectedElementProperty.addListener(ChangeListener { _, _, newValue -> settingsProperty.set(newValue?.getSettings()) + }) automatonAdjacencyMatrixView.controller.lastSelectedElementProperty.addListener(ChangeListener { _, _, newValue -> settingsProperty.set(newValue?.getSettings()) @@ -95,14 +96,18 @@ class AutomatonView(val automaton: Automaton, automatonViewContext: AutomatonVie label { isWrapText = true layoutXProperty().bind(this@AutomatonView.widthProperty() - widthProperty() - 10.0) - maxWidthProperty().bind(this@AutomatonView.widthProperty() - settingsEditor.widthProperty() - 20.0) + val tabWidth = 700.0 + maxWidthProperty().bind(this@AutomatonView.widthProperty() - tabWidth - 20.0) + maxHeight = 30.0 font = Font.font(16.0) textProperty().bind(automaton.descriptionBinding) visibleWhen(automaton.isOutputOfTransformationProperty.booleanBinding { it == null }) } label { layoutXProperty().bind(this@AutomatonView.widthProperty() - widthProperty() - 10.0) - layoutYProperty().bind(this@AutomatonView.heightProperty() - heightProperty()) + layoutYProperty().bind(this@AutomatonView.heightProperty() - heightProperty() - 45.0) + val buttonsWidth = 700.0 + maxWidthProperty().bind(this@AutomatonView.widthProperty() - buttonsWidth - 20.0) font = Font.font(16.0) textFill = Color.DARKRED textAlignment = TextAlignment.RIGHT diff --git a/src/main/kotlin/automaton/constructor/view/automaton/AutomatonAdjacencyMatrixView.kt b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonAdjacencyMatrixView.kt index ce1bdcb..4a6cdae 100644 --- a/src/main/kotlin/automaton/constructor/view/automaton/AutomatonAdjacencyMatrixView.kt +++ b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonAdjacencyMatrixView.kt @@ -4,7 +4,7 @@ import automaton.constructor.model.automaton.Automaton import automaton.constructor.model.element.AutomatonVertex import automaton.constructor.model.element.Transition import automaton.constructor.utils.I18N -import automaton.constructor.view.AdjacencyMatrixTransitionView +import automaton.constructor.view.elements.transition.AdjacencyMatrixTransitionView import automaton.constructor.view.AutomatonViewContext import javafx.beans.property.ReadOnlyDoubleProperty import javafx.beans.property.SimpleObjectProperty @@ -66,6 +66,7 @@ class AutomatonAdjacencyMatrixView( transitionsByVertices.removeAll { it.source == vertex } unregisterColumn( transitionsColumns.columns.find { it.text == vertex.name } as TableColumn>) + super.unregisterVertex(vertex) } override fun registerTransition(transition: Transition) { @@ -83,7 +84,7 @@ class AutomatonAdjacencyMatrixView( val list = this!!.transitions[transition.target]!!.value this.transitions[transition.target]!!.set(list - transition) } - transitionToViewMap.remove(transition) + super.unregisterTransition(transition) } private fun registerColumn(addedColumn: TableColumn>) { diff --git a/src/main/kotlin/automaton/constructor/view/automaton/AutomatonGraphView.kt b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonGraphView.kt index 6464d90..528c55c 100644 --- a/src/main/kotlin/automaton/constructor/view/automaton/AutomatonGraphView.kt +++ b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonGraphView.kt @@ -10,7 +10,7 @@ import automaton.constructor.model.element.State import automaton.constructor.utils.hoverableTooltip import automaton.constructor.utils.subPane import automaton.constructor.view.AutomatonEdgeView -import automaton.constructor.view.AutomatonVertexView +import automaton.constructor.view.elements.vertex.AutomatonVertexView import automaton.constructor.view.AutomatonViewContext import automaton.constructor.view.module.executor.executionStatesTooltip import javafx.collections.MapChangeListener @@ -20,11 +20,11 @@ import tornadofx.add import tornadofx.fitToParentSize import kotlin.collections.set -class AutomatonGraphView(val automaton: Automaton, private val automatonViewContext: AutomatonViewContext) : Pane() { +class AutomatonGraphView(val automaton: Automaton, private val automatonViewContext: AutomatonViewContext) : AutomatonRepresentationView() { private val edgePane = subPane() val edgeViews = mutableMapOf, AutomatonEdgeView>() val vertexToViewMap = mutableMapOf() - val controller: AutomatonGraphController = AutomatonGraphController(automaton, automatonViewContext) + override val controller: AutomatonGraphController = AutomatonGraphController(automaton, automatonViewContext) init { minWidth = GRAPH_PANE_INIT_SIZE.x @@ -43,6 +43,8 @@ class AutomatonGraphView(val automaton: Automaton, private val automatonViewCont controller.clearSelection() } + override fun getAllElementsViews() = edgeViews.values.flatMap { it.transitionViews } + vertexToViewMap.values + private fun registerVertex(vertex: AutomatonVertex) { val automatonVertexView = AutomatonVertexView(vertex) controller.registerVertexView(automatonVertexView) diff --git a/src/main/kotlin/automaton/constructor/view/automaton/AutomatonRepresentationView.kt b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonRepresentationView.kt new file mode 100644 index 0000000..d1e0da0 --- /dev/null +++ b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonRepresentationView.kt @@ -0,0 +1,10 @@ +package automaton.constructor.view.automaton + +import automaton.constructor.controller.AutomatonRepresentationController +import automaton.constructor.view.AutomatonElementView +import javafx.scene.layout.Pane + +abstract class AutomatonRepresentationView: Pane() { + abstract val controller: AutomatonRepresentationController + abstract fun getAllElementsViews(): List +} diff --git a/src/main/kotlin/automaton/constructor/view/automaton/AutomatonTableView.kt b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonTableView.kt index 477d8fb..7f79e09 100644 --- a/src/main/kotlin/automaton/constructor/view/automaton/AutomatonTableView.kt +++ b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonTableView.kt @@ -7,26 +7,27 @@ import automaton.constructor.model.data.addContent import automaton.constructor.model.element.AutomatonVertex import automaton.constructor.model.element.BuildingBlock import automaton.constructor.model.element.Transition +import automaton.constructor.model.module.hasProblems +import automaton.constructor.model.module.hasProblemsBinding import automaton.constructor.utils.I18N import automaton.constructor.utils.addOnSuccess import automaton.constructor.utils.hoverableTooltip -import automaton.constructor.view.AutomatonTableVertexView +import automaton.constructor.view.AutomatonElementView +import automaton.constructor.view.elements.vertex.AutomatonTableVertexView import automaton.constructor.view.AutomatonViewContext -import automaton.constructor.view.TableTransitionView +import automaton.constructor.view.elements.transition.TableTransitionView import javafx.beans.property.ReadOnlyDoubleProperty import javafx.beans.property.SimpleObjectProperty -import javafx.beans.property.SimpleStringProperty import javafx.collections.SetChangeListener import javafx.geometry.Insets -import javafx.scene.control.ListCell import javafx.scene.control.TableCell import javafx.scene.control.TableColumn import javafx.scene.control.TableView import javafx.scene.control.cell.PropertyValueFactory +import javafx.scene.input.KeyCode import javafx.scene.input.MouseButton import javafx.scene.layout.Pane import javafx.scene.layout.VBox -import javafx.scene.paint.Color import tornadofx.* import kotlin.random.Random @@ -35,9 +36,6 @@ interface TransitionMap class VertexCell( private val table: AutomatonTableView ): TableCell() { - private val colourProperty = SimpleStringProperty("") - private var colour by colourProperty - private fun registerVertex(vertex: AutomatonVertex): AutomatonTableVertexView { val vertexView = AutomatonTableVertexView(vertex) table.controller.registerAutomatonElementView(vertexView) @@ -54,18 +52,27 @@ class VertexCell( } } } + table.vertexToViewMap[vertex] = vertexView return vertexView } override fun updateItem(item: AutomatonVertex?, empty: Boolean) { super.updateItem(item, empty) + this.style = "-fx-background-color: none;" if (item != null) { val vertexView = registerVertex(item) - colourProperty.bind(vertexView.colourProperty) - this.style = "-fx-background-color: ${colour};" - colourProperty.addListener(ChangeListener { _, _, newValue -> - this.style = "-fx-background-color: ${newValue};" - }) + if (item is BuildingBlock) { + if (item.subAutomaton.hasProblems) { + this.style = "-fx-background-color: red;" + } + item.subAutomaton.hasProblemsBinding.addListener { _, _, newValue -> + if (newValue) { + this.style = "-fx-background-color: red;" + } else { + this.style = "-fx-background-color: none;" + } + } + } graphic = vertexView } else { this.style = "-fx-background-color: none;" @@ -99,29 +106,13 @@ class NewTransitionPopup: Fragment() { override val root = vbox(5.0) { label(I18N.messages.getString("NewTransitionPopup.Question")) borderpane { - class VertexCell: ListCell() { - override fun updateItem(item: AutomatonVertex?, empty: Boolean) { - super.updateItem(item, empty) - graphic = if (item != null) { - label(item.name) { - textFill = Color.BLACK - } - } else { - null - } - } - } left = hbox(5.0) { label(I18N.messages.getString("NewTransitionPopup.Source")) - val sourceBox = combobox(source, automaton.vertices.toList()) - sourceBox.setCellFactory { VertexCell() } - sourceBox.buttonCell = VertexCell() + choicebox(source, automaton.vertices.toList()) } right = hbox(2.0) { label(I18N.messages.getString("NewTransitionPopup.Target")) - val targetBox = combobox(target, automaton.vertices.toList()) - targetBox.setCellFactory { VertexCell() } - targetBox.buttonCell = VertexCell() + choicebox(target, automaton.vertices.toList()) } } button(I18N.messages.getString("NewTransitionPopup.Add")) { @@ -139,12 +130,13 @@ abstract class AutomatonTableView( val automatonViewContext: AutomatonViewContext, private val tablePrefWidth: ReadOnlyDoubleProperty, private val tablePrefHeight: ReadOnlyDoubleProperty -): Pane() { +): AutomatonRepresentationView() { val transitionsByVertices = observableListOf() val table = TableView(transitionsByVertices) val sourceColumn = TableColumn() - val controller = AutomatonRepresentationController(automaton, automatonViewContext) + final override val controller = AutomatonRepresentationController(automaton, automatonViewContext) val transitionToViewMap = mutableMapOf() + val vertexToViewMap = mutableMapOf() init { automaton.vertices.addListener(SetChangeListener { if (it.wasRemoved()) { @@ -226,17 +218,31 @@ abstract class AutomatonTableView( table.setOnMouseClicked { if (it.button == MouseButton.PRIMARY) controller.clearSelection() } + table.selectionModel = null + table.setOnKeyPressed { event -> + if (event.code == KeyCode.A && event.isControlDown) { // AutomatonTableView can't consume this event for some reason + controller.clearSelection() + controller.selectedElementsViews.addAll(getAllElementsViews().onEach { it.selected = true }) + } + } + controller.enableShortcuts(this) table.style { fontSize = 16.0.px } } - abstract fun unregisterVertex(vertex: AutomatonVertex) + override fun getAllElementsViews(): List = vertexToViewMap.values + transitionToViewMap.values + + open fun unregisterVertex(vertex: AutomatonVertex) { + vertexToViewMap.remove(vertex) + } abstract fun registerTransition(transition: Transition) - abstract fun unregisterTransition(transition: Transition) + open fun unregisterTransition(transition: Transition) { + transitionToViewMap.remove(transition) + } fun enableProperResizing() { table.prefWidthProperty().bind(tablePrefWidth) diff --git a/src/main/kotlin/automaton/constructor/view/automaton/AutomatonTransitionTableView.kt b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonTransitionTableView.kt index 93777c1..7f2ecd5 100644 --- a/src/main/kotlin/automaton/constructor/view/automaton/AutomatonTransitionTableView.kt +++ b/src/main/kotlin/automaton/constructor/view/automaton/AutomatonTransitionTableView.kt @@ -5,7 +5,7 @@ import automaton.constructor.model.element.AutomatonVertex import automaton.constructor.model.element.Transition import automaton.constructor.utils.I18N import automaton.constructor.view.AutomatonViewContext -import automaton.constructor.view.TransitionTableTransitionView +import automaton.constructor.view.elements.transition.TransitionTableTransitionView import javafx.beans.property.ReadOnlyDoubleProperty import javafx.beans.property.SimpleObjectProperty import javafx.scene.control.* @@ -45,6 +45,7 @@ class AutomatonTransitionTableView( override fun unregisterVertex(vertex: AutomatonVertex) { transitionsByVertices.removeAll { it.source == vertex } + super.unregisterVertex(vertex) } override fun registerTransition(transition: Transition) { @@ -56,7 +57,7 @@ class AutomatonTransitionTableView( override fun unregisterTransition(transition: Transition) { deleteTransitionFromTable(transition) - transitionToViewMap.remove(transition) + super.unregisterTransition(transition) } private fun addTransitionToTable(transition: Transition) { diff --git a/src/main/kotlin/automaton/constructor/view/AdjacencyMatrixTransitionView.kt b/src/main/kotlin/automaton/constructor/view/elements/transition/AdjacencyMatrixTransitionView.kt similarity index 63% rename from src/main/kotlin/automaton/constructor/view/AdjacencyMatrixTransitionView.kt rename to src/main/kotlin/automaton/constructor/view/elements/transition/AdjacencyMatrixTransitionView.kt index 4a30baf..eb75004 100644 --- a/src/main/kotlin/automaton/constructor/view/AdjacencyMatrixTransitionView.kt +++ b/src/main/kotlin/automaton/constructor/view/elements/transition/AdjacencyMatrixTransitionView.kt @@ -1,6 +1,7 @@ -package automaton.constructor.view +package automaton.constructor.view.elements.transition import automaton.constructor.model.element.Transition +import automaton.constructor.view.elements.transition.TableTransitionView import javafx.scene.paint.Color import tornadofx.label @@ -8,7 +9,7 @@ class AdjacencyMatrixTransitionView(transition: Transition): TableTransitionView init { label { textProperty().bind(transition.propertiesTextBinding) - textFill = Color.BLACK + textFillProperty().bind(colorProperty) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/automaton/constructor/view/TableTransitionView.kt b/src/main/kotlin/automaton/constructor/view/elements/transition/BasicTransitionView.kt similarity index 83% rename from src/main/kotlin/automaton/constructor/view/TableTransitionView.kt rename to src/main/kotlin/automaton/constructor/view/elements/transition/BasicTransitionView.kt index 7fd1c07..80b0e70 100644 --- a/src/main/kotlin/automaton/constructor/view/TableTransitionView.kt +++ b/src/main/kotlin/automaton/constructor/view/elements/transition/BasicTransitionView.kt @@ -1,13 +1,14 @@ -package automaton.constructor.view +package automaton.constructor.view.elements.transition import automaton.constructor.model.element.Transition import automaton.constructor.utils.I18N import automaton.constructor.utils.Setting import automaton.constructor.utils.SettingGroup import automaton.constructor.utils.createUnmodifiableSettingControl +import automaton.constructor.view.AutomatonElementView import tornadofx.toProperty -open class TableTransitionView(val transition: Transition): AutomatonElementView(transition) { +open class BasicTransitionView(val transition: Transition): AutomatonElementView(transition) { override fun getSettings() = listOf( SettingGroup( I18N.messages.getString("TransitionView.Transition").toProperty(), listOf( @@ -22,4 +23,4 @@ open class TableTransitionView(val transition: Transition): AutomatonElementView ) ) ) + super.getSettings() -} \ No newline at end of file +} diff --git a/src/main/kotlin/automaton/constructor/view/elements/transition/TableTransitionView.kt b/src/main/kotlin/automaton/constructor/view/elements/transition/TableTransitionView.kt new file mode 100644 index 0000000..48d9f6e --- /dev/null +++ b/src/main/kotlin/automaton/constructor/view/elements/transition/TableTransitionView.kt @@ -0,0 +1,12 @@ +package automaton.constructor.view.elements.transition + +import automaton.constructor.model.element.Transition +import automaton.constructor.utils.* +import javafx.beans.binding.Binding +import javafx.scene.paint.Color + +open class TableTransitionView(transition: Transition): BasicTransitionView(transition) { + val colorProperty: Binding = selectedProperty.nonNullObjectBinding { + if (selected) Color.AQUA else Color.BLACK + } +} diff --git a/src/main/kotlin/automaton/constructor/view/TransitionTableTransitionView.kt b/src/main/kotlin/automaton/constructor/view/elements/transition/TransitionTableTransitionView.kt similarity index 71% rename from src/main/kotlin/automaton/constructor/view/TransitionTableTransitionView.kt rename to src/main/kotlin/automaton/constructor/view/elements/transition/TransitionTableTransitionView.kt index 199eb47..759533b 100644 --- a/src/main/kotlin/automaton/constructor/view/TransitionTableTransitionView.kt +++ b/src/main/kotlin/automaton/constructor/view/elements/transition/TransitionTableTransitionView.kt @@ -1,4 +1,4 @@ -package automaton.constructor.view +package automaton.constructor.view.elements.transition import automaton.constructor.model.element.Transition import javafx.scene.paint.Color @@ -9,17 +9,17 @@ class TransitionTableTransitionView(transition: Transition): TableTransitionView hbox { label { textProperty().bind(transition.filtersTextBinding) - textFill = Color.BLACK + textFillProperty().bind(colorProperty) } if (transition.sideEffectsText.isNotEmpty()) { label("→") { - textFill = Color.BLACK + textFillProperty().bind(colorProperty) } label { textProperty().bind(transition.sideEffectsTextBinding) - textFill = Color.BLACK + textFillProperty().bind(colorProperty) } } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/automaton/constructor/view/TransitionView.kt b/src/main/kotlin/automaton/constructor/view/elements/transition/TransitionView.kt similarity index 55% rename from src/main/kotlin/automaton/constructor/view/TransitionView.kt rename to src/main/kotlin/automaton/constructor/view/elements/transition/TransitionView.kt index 7b1e162..76db5fe 100644 --- a/src/main/kotlin/automaton/constructor/view/TransitionView.kt +++ b/src/main/kotlin/automaton/constructor/view/elements/transition/TransitionView.kt @@ -1,7 +1,8 @@ -package automaton.constructor.view +package automaton.constructor.view.elements.transition import automaton.constructor.model.element.Transition import automaton.constructor.utils.* +import automaton.constructor.view.elements.transition.BasicTransitionView import javafx.beans.binding.Binding import javafx.beans.property.DoubleProperty import javafx.scene.paint.Color @@ -9,9 +10,9 @@ import javafx.scene.text.Font import tornadofx.* class TransitionView( - val transition: Transition, + transition: Transition, index: Int -) : AutomatonElementView(transition) { +) : BasicTransitionView(transition) { val indexProperty = index.toProperty() var index by indexProperty val xProperty: DoubleProperty @@ -21,21 +22,6 @@ class TransitionView( if (selected) Color.BLUE else Color.BLACK } - override fun getSettings() = listOf( - SettingGroup( - I18N.messages.getString("TransitionView.Transition").toProperty(), listOf( - Setting( - I18N.messages.getString("TransitionView.Source"), - createUnmodifiableSettingControl(transition.source.nameProperty) - ), - Setting( - I18N.messages.getString("TransitionView.Target"), - createUnmodifiableSettingControl(transition.target.nameProperty) - ) - ) - ) - ) + super.getSettings() - init { val text = text { fillProperty().bind(colorProperty) diff --git a/src/main/kotlin/automaton/constructor/view/AutomatonBasicVertexView.kt b/src/main/kotlin/automaton/constructor/view/elements/vertex/AutomatonBasicVertexView.kt similarity index 78% rename from src/main/kotlin/automaton/constructor/view/AutomatonBasicVertexView.kt rename to src/main/kotlin/automaton/constructor/view/elements/vertex/AutomatonBasicVertexView.kt index 31deb62..cafaf00 100644 --- a/src/main/kotlin/automaton/constructor/view/AutomatonBasicVertexView.kt +++ b/src/main/kotlin/automaton/constructor/view/elements/vertex/AutomatonBasicVertexView.kt @@ -1,17 +1,12 @@ -package automaton.constructor.view +package automaton.constructor.view.elements.vertex import automaton.constructor.model.element.AutomatonVertex -import automaton.constructor.model.element.BuildingBlock -import automaton.constructor.model.module.hasProblems -import automaton.constructor.model.module.hasProblemsBinding import automaton.constructor.utils.I18N import automaton.constructor.utils.Setting import automaton.constructor.utils.SettingGroup -import javafx.beans.property.SimpleIntegerProperty -import javafx.beans.property.SimpleStringProperty +import automaton.constructor.view.AutomatonElementView import javafx.scene.control.CheckBox import javafx.scene.control.TextField -import javafx.scene.paint.Color import tornadofx.* open class AutomatonBasicVertexView(val vertex: AutomatonVertex) : AutomatonElementView(vertex) { diff --git a/src/main/kotlin/automaton/constructor/view/AutomatonTableVertexView.kt b/src/main/kotlin/automaton/constructor/view/elements/vertex/AutomatonTableVertexView.kt similarity index 82% rename from src/main/kotlin/automaton/constructor/view/AutomatonTableVertexView.kt rename to src/main/kotlin/automaton/constructor/view/elements/vertex/AutomatonTableVertexView.kt index 4d3df1c..8efa47b 100644 --- a/src/main/kotlin/automaton/constructor/view/AutomatonTableVertexView.kt +++ b/src/main/kotlin/automaton/constructor/view/elements/vertex/AutomatonTableVertexView.kt @@ -1,22 +1,25 @@ -package automaton.constructor.view +package automaton.constructor.view.elements.vertex import automaton.constructor.model.element.AutomatonVertex import automaton.constructor.model.element.BuildingBlock import automaton.constructor.model.module.hasProblems import automaton.constructor.model.module.hasProblemsBinding +import automaton.constructor.utils.nonNullObjectBinding +import javafx.beans.binding.Binding import javafx.beans.property.SimpleIntegerProperty import javafx.beans.property.SimpleStringProperty import javafx.scene.paint.Color import tornadofx.* class AutomatonTableVertexView(vertex: AutomatonVertex): AutomatonBasicVertexView(vertex) { - val colourProperty = SimpleStringProperty("none") - private var colour by colourProperty + private val colorBinding: Binding = selectedProperty.nonNullObjectBinding { + if (selected) Color.AQUA else Color.BLACK + } init { hbox { label { textProperty().bind(vertex.nameProperty) - textFill = Color.BLACK + textFillProperty().bind(colorBinding) } val startFinalCount = SimpleIntegerProperty(0) if (vertex.isInitial) { @@ -41,7 +44,7 @@ class AutomatonTableVertexView(vertex: AutomatonVertex): AutomatonBasicVertexVie if (startFinalCount.value == 2) { text = " (start, final)" } - textFill = Color.BLACK + textFillProperty().bind(colorBinding) isVisible = vertex.isInitial || vertex.isFinal } vertex.isInitialProperty.addListener { _, _, newValue -> @@ -76,17 +79,5 @@ class AutomatonTableVertexView(vertex: AutomatonVertex): AutomatonBasicVertexVie } } } - if (vertex is BuildingBlock) { - if (vertex.subAutomaton.hasProblems) { - colour = "red" - } - vertex.subAutomaton.hasProblemsBinding.addListener(ChangeListener { _, _, newValue -> - colour = if (newValue) { - "red" - } else { - "none" - } - }) - } } } diff --git a/src/main/kotlin/automaton/constructor/view/AutomatonVertexView.kt b/src/main/kotlin/automaton/constructor/view/elements/vertex/AutomatonVertexView.kt similarity index 93% rename from src/main/kotlin/automaton/constructor/view/AutomatonVertexView.kt rename to src/main/kotlin/automaton/constructor/view/elements/vertex/AutomatonVertexView.kt index 55cfd79..a21d31a 100644 --- a/src/main/kotlin/automaton/constructor/view/AutomatonVertexView.kt +++ b/src/main/kotlin/automaton/constructor/view/elements/vertex/AutomatonVertexView.kt @@ -1,4 +1,4 @@ -package automaton.constructor.view +package automaton.constructor.view.elements.vertex import automaton.constructor.model.element.AutomatonVertex import automaton.constructor.model.element.AutomatonVertex.Companion.RADIUS @@ -6,9 +6,11 @@ import automaton.constructor.model.element.BuildingBlock import automaton.constructor.model.element.State import automaton.constructor.model.module.hasProblems import automaton.constructor.model.module.hasProblemsBinding -import automaton.constructor.utils.* -import automaton.constructor.view.AutomatonVertexView.ShapeType.CIRCLE -import automaton.constructor.view.AutomatonVertexView.ShapeType.SQUARE +import automaton.constructor.utils.nonNullObjectBinding +import automaton.constructor.utils.x +import automaton.constructor.utils.y +import automaton.constructor.view.elements.vertex.AutomatonVertexView.ShapeType.CIRCLE +import automaton.constructor.view.elements.vertex.AutomatonVertexView.ShapeType.SQUARE import javafx.beans.property.Property import javafx.geometry.Point2D import javafx.geometry.VPos diff --git a/src/main/kotlin/automaton/constructor/view/module/executor/tree/ExecutionNodeView.kt b/src/main/kotlin/automaton/constructor/view/module/executor/tree/ExecutionNodeView.kt index 21bfc20..364f6e2 100644 --- a/src/main/kotlin/automaton/constructor/view/module/executor/tree/ExecutionNodeView.kt +++ b/src/main/kotlin/automaton/constructor/view/module/executor/tree/ExecutionNodeView.kt @@ -6,7 +6,7 @@ import automaton.constructor.model.module.executor.SimpleExecutionState import automaton.constructor.model.module.executor.SuperExecutionState import automaton.constructor.utils.* import automaton.constructor.view.AutomatonEdgeView -import automaton.constructor.view.AutomatonVertexView +import automaton.constructor.view.elements.vertex.AutomatonVertexView import automaton.constructor.view.TransitionLabelPosition import automaton.constructor.view.module.executor.color import automaton.constructor.view.module.executor.simpleTooltipContent diff --git a/wiki/examples.gif b/wiki/examples.gif index 3e7fb8e..483c610 100644 Binary files a/wiki/examples.gif and b/wiki/examples.gif differ diff --git a/wiki/matrix.png b/wiki/matrix.png new file mode 100644 index 0000000..8c7f872 Binary files /dev/null and b/wiki/matrix.png differ diff --git a/wiki/table.png b/wiki/table.png new file mode 100644 index 0000000..626bd63 Binary files /dev/null and b/wiki/table.png differ diff --git a/wiki/testing_panel.gif b/wiki/testing_panel.gif index 9a95696..07afd26 100644 Binary files a/wiki/testing_panel.gif and b/wiki/testing_panel.gif differ