forked from spbu-coding-2022/trees-3
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add RBTree visualization with ability to interact with Neo4j DB
- Loading branch information
Showing
4 changed files
with
216 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,101 @@ | ||
package app.controller | ||
|
||
class RBTController { | ||
import bst.RedBlackTree | ||
import bst.nodes.RBTNode | ||
import bst.db.controllers.JsonController | ||
import bst.db.controllers.Neo4jController | ||
import javafx.collections.FXCollections | ||
import javafx.collections.ObservableList | ||
import javafx.scene.control.Label | ||
import javafx.scene.layout.Pane | ||
import javafx.scene.paint.Color | ||
import javafx.scene.shape.Circle | ||
import javafx.scene.shape.Line | ||
import tornadofx.Controller | ||
|
||
class RBTController: Controller() { | ||
fun isNumeric(s: String): Boolean { | ||
return try { | ||
s.toInt() | ||
true | ||
} catch (e: NumberFormatException) { | ||
false | ||
} | ||
} | ||
|
||
fun insertNode(tree: RedBlackTree<Int, String>, treePane: Pane, key: Int, value: String) { | ||
tree.insert(key, value) | ||
drawTree(tree, treePane) | ||
} | ||
|
||
fun clearTree(tree: RedBlackTree<Int, String>, treePane: Pane) { | ||
tree.clear() | ||
treePane.children.clear() | ||
} | ||
|
||
//make here not null check | ||
fun drawTree(tree: RedBlackTree<Int, String>, treePane: Pane) { | ||
treePane.children.clear() | ||
val root = tree.getRoot() | ||
if (root != null) { | ||
drawNode(root, treePane, treePane.width / 2.0, 50.0, treePane.width / 4.0) | ||
} | ||
} | ||
|
||
private fun drawNode(node: RBTNode<Int, String>, treePane: Pane, x: Double, y: Double, offsetX: Double) { | ||
val circleRadius = 20.0 | ||
val circle = Circle(circleRadius) | ||
circle.centerX = x | ||
circle.centerY = y | ||
circle.fill = if (node.color == RBTNode.Color.RED) Color.RED else Color.BLACK | ||
circle.stroke = Color.BLACK | ||
val nodeLabel = Label(node.key.toString()) | ||
nodeLabel.layoutX = circle.centerX - (circle.radius / 3) | ||
nodeLabel.layoutY = circle.centerY - (circle.radius / 3) | ||
treePane.children.addAll(circle, nodeLabel) | ||
|
||
if (node.left != null) { | ||
val leftX = x - offsetX | ||
val leftY = y + 50 | ||
val leftLine = Line(x, y + circleRadius, leftX, leftY - circleRadius) | ||
treePane.children.add(leftLine) | ||
drawNode(node.left!!, treePane, leftX, leftY, offsetX / 2.0) | ||
} | ||
|
||
if (node.right != null) { | ||
val rightX = x + offsetX | ||
val rightY = y + 50 | ||
val rightLine = Line(x, y + circleRadius, rightX, rightY - circleRadius) | ||
treePane.children.add(rightLine) | ||
drawNode(node.right!!, treePane, rightX, rightY, offsetX / 2.0) | ||
} | ||
} | ||
|
||
fun getTreesList(): ObservableList<String>? { | ||
val controller = Neo4jController() | ||
val treeNames = controller.getNames() | ||
val values = FXCollections.observableArrayList<String>() | ||
treeNames.forEach { | ||
values.add(it) | ||
} | ||
return values | ||
} | ||
fun getTreeFromNeo4j(name: String): RedBlackTree<Int, String>? { | ||
val controller = Neo4jController() | ||
return controller.getTree(name) | ||
} | ||
|
||
fun deleteTreeFromDB(name: String) { | ||
Neo4jController().run { | ||
removeTree(name) | ||
} | ||
} | ||
fun saveTree(tree: RedBlackTree<Int, String>, treeName: String) { | ||
val controller = Neo4jController() | ||
controller.saveTree(tree, treeName) | ||
} | ||
fun deleteNode(value: Int, tree: RedBlackTree<Int, String>, treePane: Pane){ | ||
tree.remove(value) | ||
drawTree(tree, treePane) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 115 additions & 6 deletions
121
app/src/main/kotlin/app/view/treeView/RedBlackTreeView.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,131 @@ | ||
package app.view.treeView | ||
import app.view.treeView.AVLTreeView | ||
import app.view.treeView.BinarySearchTreeView | ||
|
||
import app.controller.RBTController | ||
import tornadofx.* | ||
import bst.RedBlackTree | ||
import bst.db.controllers.Neo4jController | ||
import javafx.beans.property.SimpleStringProperty | ||
import javafx.scene.layout.Pane | ||
import javafx.scene.control.Alert | ||
|
||
|
||
class RedBlackTreeView : View() { | ||
private val controller: RBTController by inject() | ||
private var tree = RedBlackTree<Int, String>() | ||
private val treePane = Pane() | ||
private val key = SimpleStringProperty() | ||
private val value = SimpleStringProperty() | ||
private var trees = controller.getTreesList() | ||
private var selectedItem: String? = "" | ||
private val treeName = SimpleStringProperty() | ||
private val valueFotDeletion = SimpleStringProperty() | ||
|
||
class RedBlackTreeView: View() { | ||
override val root = vbox { | ||
hbox { | ||
val availableTrees = combobox<String> { | ||
this@RedBlackTreeView.trees?.let { items.addAll(it) } | ||
selectionModel.selectedItemProperty().addListener { _, _, newValue -> | ||
this@RedBlackTreeView.selectedItem = newValue | ||
} | ||
} | ||
|
||
button("Select") { | ||
action { | ||
println("Selected item: $selectedItem") | ||
val loadedTree = selectedItem?.let { controller.getTreeFromNeo4j(it) } | ||
if (loadedTree != null) { | ||
tree = loadedTree | ||
controller.drawTree(tree, treePane) | ||
} | ||
} | ||
} | ||
button("Delete") { | ||
action { | ||
selectedItem?.let { | ||
controller.clearTree(tree, treePane) | ||
controller.deleteTreeFromDB(it) | ||
} | ||
availableTrees.items.remove(selectedItem) | ||
|
||
println("Item deleted: $selectedItem") | ||
} | ||
} | ||
|
||
button("Clear") { | ||
action { | ||
controller.clearTree(tree, treePane) | ||
} | ||
} | ||
form { | ||
fieldset { | ||
field("Key input") { | ||
textfield(key) | ||
} | ||
field("Value input") { | ||
textfield(value) | ||
} | ||
|
||
button("Add Node") { | ||
action { | ||
if (key.value != null && value.value != null && controller.isNumeric(key.value)) { | ||
controller.insertNode(tree, treePane, key.value.toInt(), value.value) | ||
} else { | ||
alert(type = Alert.AlertType.ERROR, header = "Insertion Error") | ||
} | ||
key.value = "" | ||
value.value = "" | ||
} | ||
} | ||
field("Value input"){ | ||
textfield(valueFotDeletion) | ||
} | ||
button("Delete node"){ | ||
action { | ||
if (controller.isNumeric(valueFotDeletion.value)){ | ||
controller.deleteNode(valueFotDeletion.value.toInt(), tree, treePane) | ||
} | ||
else{ | ||
alert(type = Alert.AlertType.ERROR, header = "Deletion Error") | ||
} | ||
} | ||
} | ||
|
||
field("Input tree name") { | ||
textfield(treeName) | ||
} | ||
button("Save tree") { | ||
action { | ||
if (tree.getRoot() != null) { | ||
// tree.treeName = treeName.value | ||
controller.saveTree(tree, treeName.value) | ||
if (!availableTrees.items.contains(treeName.value)) { | ||
availableTrees.items.add(treeName.value) | ||
} | ||
} | ||
else{ | ||
alert(type = Alert.AlertType.ERROR, header = "Can not save tree with empty root") | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
button("AVL Tree") { | ||
action { | ||
replaceWith(AVLTreeView::class, ViewTransition.Slide(0.3.seconds, ViewTransition.Direction.LEFT)) | ||
|
||
} | ||
} | ||
|
||
button("Binary Search Tree") { | ||
action { | ||
replaceWith(BinarySearchTreeView::class, ViewTransition.Slide(0.3.seconds, ViewTransition.Direction.LEFT)) | ||
|
||
} | ||
} | ||
this += treePane | ||
treePane.apply { | ||
minWidth = 600.0 | ||
minHeight = 400.0 | ||
style = "-fx-border-color: black;" | ||
} | ||
} | ||
} | ||
} |