From 2633c89aded94a330bbe4fc8a13e061c3a5c770e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Wed, 24 Feb 2021 10:55:42 +0100 Subject: [PATCH] [Editor] Enable base script management --- .../CodeStructureItemStringConverter.kt | 12 +-- .../component/CodeStructureItemTreeCell.kt | 81 ++++++++++++++----- .../base/editor/code/model/FileSystemNode.kt | 47 +++++++++++ .../editor/code/view/CodeStructureView.kt | 34 ++++---- 4 files changed, 126 insertions(+), 48 deletions(-) create mode 100644 editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/model/FileSystemNode.kt diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemStringConverter.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemStringConverter.kt index f1bce895..6f506fa0 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemStringConverter.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemStringConverter.kt @@ -1,15 +1,15 @@ package com.bartlomiejpluta.base.editor.code.component +import com.bartlomiejpluta.base.editor.code.model.FileSystemNode import javafx.scene.control.TreeCell import javafx.util.StringConverter -import java.io.File class CodeStructureItemStringConverter( - private val cell: TreeCell, - private val onUpdate: (item: File, name: String) -> File -) : StringConverter() { - override fun toString(item: File?): String = when (item) { - is File -> item.name + private val cell: TreeCell, + private val onUpdate: (item: FileSystemNode, name: String) -> FileSystemNode +) : StringConverter() { + override fun toString(item: FileSystemNode?): String = when (item) { + is FileSystemNode -> item.file.name else -> "" } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemTreeCell.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemTreeCell.kt index 5525f107..1955cd04 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemTreeCell.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/component/CodeStructureItemTreeCell.kt @@ -1,58 +1,95 @@ package com.bartlomiejpluta.base.editor.code.component +import com.bartlomiejpluta.base.editor.code.model.FileSystemNode import javafx.scene.control.ContextMenu -import javafx.scene.control.MenuItem import javafx.scene.control.cell.TextFieldTreeCell import org.kordamp.ikonli.javafx.FontIcon import tornadofx.action -import java.io.File +import tornadofx.enableWhen +import tornadofx.item +import tornadofx.toProperty -class CodeStructureItemTreeCell(renameFile: (file: File, name: String) -> File, deleteFile: (file: File) -> Unit) : - TextFieldTreeCell() { - private val fileMenu = ContextMenu() +class CodeStructureItemTreeCell : TextFieldTreeCell() { + private val isRoot = true.toProperty() + private val isNotRoot = isRoot.not() + + private val fileMenu = ContextMenu().apply { + item("Rename") { + enableWhen(isNotRoot) - init { - converter = CodeStructureItemStringConverter(this, renameFile) - MenuItem("Rename").apply { action { treeView.isEditable = true startEdit() treeView.isEditable = false } - - fileMenu.items.add(this) } - MenuItem("Delete").apply { - action { - deleteFile(item as File) - } - - fileMenu.items.add(this) + item("Delete") { + enableWhen(isNotRoot) + action { item.delete() } } } - override fun updateItem(item: File?, empty: Boolean) { + private val directoryMenu = ContextMenu().apply { + item("Refresh") { + action { item.refresh() } + } + + item("Rename") { + enableWhen(isNotRoot) + + action { + treeView.isEditable = true + startEdit() + treeView.isEditable = false + } + } + + item("Delete") { + enableWhen(isNotRoot) + action { item.delete() } + } + } + + init { + converter = CodeStructureItemStringConverter(this, this::renameFile) + } + + private fun renameFile(file: FileSystemNode, name: String) = file.apply { + file.rename(name) + } + + override fun updateItem(item: FileSystemNode?, empty: Boolean) { super.updateItem(item, empty) if (empty || item == null) { text = null graphic = null + contextMenu = null + isRoot.value = true return } - contextMenu = if (isEditing) null else fileMenu - text = item.name - graphic = FontIcon(getFileIcon(item)) + text = item.file.name + graphic = FontIcon(getFileSystemNodeIcon(item)) + + contextMenu = when { + isEditing -> null + item.isFile -> fileMenu + item.isDirectory -> directoryMenu + else -> null + } + + isRoot.value = (item.parent == null) } companion object { - private fun getFileIcon(file: File): String { + private fun getFileSystemNodeIcon(file: FileSystemNode): String { if (file.isDirectory) { return "fa-folder" } - return when (file.extension.toLowerCase()) { + return when (file.file.extension.toLowerCase()) { "java" -> "fa-code" else -> "fa-file" } diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/model/FileSystemNode.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/model/FileSystemNode.kt new file mode 100644 index 00000000..d3efeb72 --- /dev/null +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/model/FileSystemNode.kt @@ -0,0 +1,47 @@ +package com.bartlomiejpluta.base.editor.code.model + +import tornadofx.observableListOf +import java.io.File + +class FileSystemNode(file: File, val parent: FileSystemNode? = null) { + var file = file + private set + + val isFile = file.isFile + val isDirectory = file.isDirectory + + val children = observableListOf() + + init { + refreshChildren() + } + + private fun refreshChildren() { + if (isDirectory) { + children.clear() + file.listFiles()?.map { FileSystemNode(it, this) }?.let { children.addAll(it) } + } + } + + fun rename(name: String) { + val newFile = File(file.parent, name) + file.renameTo(newFile) + file = newFile + } + + fun delete() { + val deleted = when { + isFile -> file.delete() + isDirectory -> file.deleteRecursively() + else -> false + } + + if (deleted) { + parent?.children?.remove(this) + } + } + + fun refresh() { + refreshChildren() + } +} \ No newline at end of file diff --git a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/CodeStructureView.kt b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/CodeStructureView.kt index c512a6a2..79972159 100644 --- a/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/CodeStructureView.kt +++ b/editor/src/main/kotlin/com/bartlomiejpluta/base/editor/code/view/CodeStructureView.kt @@ -1,12 +1,16 @@ package com.bartlomiejpluta.base.editor.code.view import com.bartlomiejpluta.base.editor.code.component.CodeStructureItemTreeCell +import com.bartlomiejpluta.base.editor.code.model.FileSystemNode import com.bartlomiejpluta.base.editor.main.controller.MainController import com.bartlomiejpluta.base.editor.project.context.ProjectContext import javafx.scene.control.TreeItem import javafx.scene.control.TreeView -import tornadofx.* -import java.io.File +import javafx.scene.input.MouseButton +import tornadofx.View +import tornadofx.expandAll +import tornadofx.populate +import tornadofx.treeview class CodeStructureView : View() { private val projectContext: ProjectContext by di() @@ -15,36 +19,26 @@ class CodeStructureView : View() { init { projectContext.projectProperty.addListener { _, _, project -> project?.let { - treeView.root = TreeItem(it.codeDirectory) - treeView.populate { item -> item.value?.listFiles()?.toList() } + treeView.root = TreeItem(FileSystemNode(it.codeDirectory)) + treeView.populate { item -> item.value?.children } root.root.expandAll() } } } - private val treeView: TreeView = treeview { - setCellFactory { - CodeStructureItemTreeCell(this@CodeStructureView::renameFile, this@CodeStructureView::deleteFile) - } + private val treeView: TreeView = treeview { + setCellFactory { CodeStructureItemTreeCell() } setOnMouseClicked { event -> - if (event.clickCount == 2) { + if (event.button == MouseButton.PRIMARY && event.clickCount == 2) { selectionModel?.selectedItem?.value .takeIf { it?.isFile ?: false } - ?.let { mainController.openScript(it) } - } + ?.let { mainController.openScript(it.file) } - event.consume() + event.consume() + } } } override val root = treeView - - private fun renameFile(file: File, name: String) = file.apply { - // TODO - } - - private fun deleteFile(file: File) { - // TODO - } } \ No newline at end of file