From dc69b15d8563082565fa031979b377458ac5912d Mon Sep 17 00:00:00 2001 From: cliebhardt Date: Sun, 29 Mar 2026 22:41:36 +0200 Subject: [PATCH 1/2] feat: add kotlin views for tree --- .../samples/views/tree/TreeIconsKotlinView.kt | 103 ++++++++++++++++++ .../samples/views/tree/TreeKotlinView.kt | 83 ++++++++++++++ .../views/tree/TreeLazyLoadKotlinView.kt | 53 +++++++++ .../views/tree/TreeModifyKotlinView.kt | 78 +++++++++++++ .../views/tree/TreeSelectionKotlinView.kt | 77 +++++++++++++ 5 files changed, 394 insertions(+) create mode 100644 src/main/kotlin/com/webforj/samples/views/tree/TreeIconsKotlinView.kt create mode 100644 src/main/kotlin/com/webforj/samples/views/tree/TreeKotlinView.kt create mode 100644 src/main/kotlin/com/webforj/samples/views/tree/TreeLazyLoadKotlinView.kt create mode 100644 src/main/kotlin/com/webforj/samples/views/tree/TreeModifyKotlinView.kt create mode 100644 src/main/kotlin/com/webforj/samples/views/tree/TreeSelectionKotlinView.kt diff --git a/src/main/kotlin/com/webforj/samples/views/tree/TreeIconsKotlinView.kt b/src/main/kotlin/com/webforj/samples/views/tree/TreeIconsKotlinView.kt new file mode 100644 index 000000000..5cbd6fc71 --- /dev/null +++ b/src/main/kotlin/com/webforj/samples/views/tree/TreeIconsKotlinView.kt @@ -0,0 +1,103 @@ +package com.webforj.samples.views.tree + +import com.webforj.component.Composite +import com.webforj.component.icons.FeatherIcon +import com.webforj.component.layout.flexlayout.FlexDirection +import com.webforj.component.layout.flexlayout.FlexLayout +import com.webforj.kotlin.dsl.component.tree.tree +import com.webforj.kotlin.dsl.component.tree.treeNode +import com.webforj.kotlin.extension.set +import com.webforj.kotlin.extension.styles +import com.webforj.kotlin.extension.vh +import com.webforj.router.annotation.FrameTitle +import com.webforj.router.annotation.Route + +@Route +@FrameTitle("Tree Icons View") +class TreeIconsKotlinView: Composite() { + private val self = boundComponent + + init { + self.apply { + direction = FlexDirection.COLUMN + height = 100.vh + styles["overflow"] = "auto" + tree { + styles["margin"] = "var(--dwc-space-l)" + setCollapsedIcon(FeatherIcon.CHEVRON_RIGHT.create()) + setExpandedIcon(FeatherIcon.CHEVRON_DOWN.create()) + treeNode("Documents") { + tooltipText = "Work and personal documents" + treeNode("Reports") { + tooltipText = "Monthly and annual reports" + treeNode("2023") { + treeNode("January.pdf") { + tooltipText = "January report" + setIcon(FeatherIcon.FILE.create()) + setSelectedIcon(FeatherIcon.FILE_TEXT.create()) + } + treeNode("February.pdf") { + tooltipText = "February report" + setIcon(FeatherIcon.FILE.create()) + setSelectedIcon(FeatherIcon.FILE_TEXT.create()) + } + } + treeNode("2022") { + treeNode("Q4.pdf") { + tooltipText = "Quarter 4 report" + setIcon(FeatherIcon.FILE.create()) + setSelectedIcon(FeatherIcon.FILE_TEXT.create()) + } + treeNode("Q3.pdf") { + tooltipText = "Quarter 3 report" + setIcon(FeatherIcon.FILE.create()) + setSelectedIcon(FeatherIcon.FILE_TEXT.create()) + } + } + } + treeNode("Invoices") { + tooltipText = "Invoices and billing" + treeNode("ClientA.pdf") { + tooltipText = "Invoice for Client A" + setIcon(FeatherIcon.FILE.create()) + setSelectedIcon(FeatherIcon.FILE_TEXT.create()) + } + treeNode("ClientB.pdf") { + tooltipText = "Invoice for Client B" + setIcon(FeatherIcon.FILE.create()) + setSelectedIcon(FeatherIcon.FILE_TEXT.create()) + } + } + } + treeNode("Pictures") { + tooltipText = "Photos and images" + treeNode("Vacations") { + treeNode("Beach.png") { + tooltipText = "Beach photo" + setIcon(FeatherIcon.IMAGE.create()) + setSelectedIcon(FeatherIcon.IMAGE.create()) + } + treeNode("Mountains") { + treeNode("Mountains.png") { + tooltipText = "Mountain photo" + setIcon(FeatherIcon.IMAGE.create()) + setSelectedIcon(FeatherIcon.IMAGE.create()) + } + } + } + treeNode("Events") { + treeNode("Birthday.jpg") { + tooltipText = "Birthday party" + setIcon(FeatherIcon.IMAGE.create()) + setSelectedIcon(FeatherIcon.IMAGE.create()) + } + } + } + expand("Documents") + expand("Pictures") + expand("Vacations") + selectKey("Mountains.png") + } + } + } +} diff --git a/src/main/kotlin/com/webforj/samples/views/tree/TreeKotlinView.kt b/src/main/kotlin/com/webforj/samples/views/tree/TreeKotlinView.kt new file mode 100644 index 000000000..1672f0e97 --- /dev/null +++ b/src/main/kotlin/com/webforj/samples/views/tree/TreeKotlinView.kt @@ -0,0 +1,83 @@ +package com.webforj.samples.views.tree + +import com.webforj.component.Composite +import com.webforj.component.layout.flexlayout.FlexDirection +import com.webforj.component.layout.flexlayout.FlexLayout +import com.webforj.kotlin.dsl.component.tree.tree +import com.webforj.kotlin.dsl.component.tree.treeNode +import com.webforj.kotlin.extension.set +import com.webforj.kotlin.extension.size +import com.webforj.kotlin.extension.styles +import com.webforj.kotlin.extension.vh +import com.webforj.router.annotation.FrameTitle +import com.webforj.router.annotation.Route + +@Route +@FrameTitle("Tree View") +class TreeKotlinView: Composite() { + private val self = boundComponent + + init { + self.apply { + direction = FlexDirection.COLUMN + size = "min-content" to 100.vh + styles["overflow"] = "auto" + tree { + styles["margin"] = "var(--dwc-space-l)" + treeNode("Documents") { + tooltipText = "Work and personal documents" + treeNode("Reports") { + tooltipText = "Monthly and annual reports" + treeNode("2023") { + treeNode("January.pdf") { + tooltipText = "January report" + } + treeNode("February.pdf") { + tooltipText = "February report" + } + } + treeNode("2022") { + treeNode("Q4.pdf") { + tooltipText = "Quarter 4 report" + } + treeNode("Q3.pdf") { + tooltipText = "Quarter 3 report" + } + } + } + treeNode("Invoices") { + tooltipText = "Invoices and billing" + treeNode("ClientA.pdf") { + tooltipText = "Invoice for Client A" + } + treeNode("ClientB.pdf") { + tooltipText = "Invoice for Client B" + } + } + } + treeNode("Pictures") { + tooltipText = "Photos and images" + treeNode("Vacations") { + treeNode("Beach.png") { + tooltipText = "Beach photo" + } + treeNode("Mountains") { + treeNode("Mountains.png") { + tooltipText = "Mountain photo" + } + } + } + treeNode("Events") { + treeNode("Birthday.jpg") { + tooltipText = "Birthday party" + } + } + } + expand("Documents") + expand("Pictures") + expand("Vacations") + selectKey("Mountains.png") + } + } + } +} diff --git a/src/main/kotlin/com/webforj/samples/views/tree/TreeLazyLoadKotlinView.kt b/src/main/kotlin/com/webforj/samples/views/tree/TreeLazyLoadKotlinView.kt new file mode 100644 index 000000000..761a7e11c --- /dev/null +++ b/src/main/kotlin/com/webforj/samples/views/tree/TreeLazyLoadKotlinView.kt @@ -0,0 +1,53 @@ +package com.webforj.samples.views.tree + +import com.webforj.Interval +import com.webforj.component.Composite +import com.webforj.component.layout.flexlayout.FlexDirection +import com.webforj.component.layout.flexlayout.FlexLayout +import com.webforj.component.tree.Tree +import com.webforj.kotlin.dsl.component.tree.tree +import com.webforj.kotlin.dsl.component.tree.treeNode +import com.webforj.kotlin.extension.set +import com.webforj.kotlin.extension.styles +import com.webforj.kotlin.extension.vh +import com.webforj.router.annotation.FrameTitle +import com.webforj.router.annotation.Route + +@Route +@FrameTitle("Lazy Load Tree View") +class TreeLazyLoadKotlinView: Composite() { + private val self = boundComponent + + init { + self.apply { + direction = FlexDirection.COLUMN + height = 100.vh + styles["overflow"] = "auto" + tree { + styles["margin"] = "var(--dwc-space-l)" + for (i in 1..4) { + treeNode("Node $i") { + treeNode(" + val node = event.node + if (node.children.size == 1) { + val child = node.children.first() + if (child.getUserData("spinner") == true) { + Interval(1f) { + it.interval.stop() + node.remove(child) + for (i in 1..3) { + node.treeNode("${node.text} - Child $i") + } + }.start() + } + } + } + } + } + } +} diff --git a/src/main/kotlin/com/webforj/samples/views/tree/TreeModifyKotlinView.kt b/src/main/kotlin/com/webforj/samples/views/tree/TreeModifyKotlinView.kt new file mode 100644 index 000000000..62c7b9fc3 --- /dev/null +++ b/src/main/kotlin/com/webforj/samples/views/tree/TreeModifyKotlinView.kt @@ -0,0 +1,78 @@ +package com.webforj.samples.views.tree + +import com.webforj.annotation.InlineStyleSheet +import com.webforj.component.Composite +import com.webforj.component.button.ButtonTheme +import com.webforj.component.layout.flexlayout.FlexDirection +import com.webforj.component.layout.flexlayout.FlexLayout +import com.webforj.component.optiondialog.InputDialog +import com.webforj.kotlin.dsl.component.tree.tree +import com.webforj.kotlin.dsl.component.tree.treeNode +import com.webforj.kotlin.extension.set +import com.webforj.kotlin.extension.styles +import com.webforj.kotlin.extension.vh +import com.webforj.router.annotation.FrameTitle +import com.webforj.router.annotation.Route + +@Route +@FrameTitle("Tree Modify View") +@InlineStyleSheet( + """ + :root { + --dwc-tree-icon-fill: var(--dwc-color-primary); + } + + """ +) +class TreeModifyKotlinView : Composite() { + private val self = boundComponent + + init { + self.apply { + direction = FlexDirection.COLUMN + height = 100.vh + styles["overflow"] = "auto" + tree { + styles["margin"] = "var(--dwc-space-l)" + treeNode("Projects") { + treeNode("Alpha") { + treeNode("Planning") + treeNode("Execution") + treeNode("Review") + } + treeNode("Beta") { + treeNode("Design") + treeNode("Development") + treeNode("Testing") + } + } + treeNode("Departments") { + treeNode("Engineering") { + treeNode("Software") + treeNode("Hardware") + } + treeNode("Marketing") + treeNode("Human Resources") + } + expand("Departments") + onDoubleClick { event -> + event.node?.let { node -> + val result = InputDialog( + "Enter a new name for the node: ${node.text}", + "Modify Node" + ).apply { + defaultValue = node.text + firstButtonText = "Modify" + secondButtonText = "Cancel" + setFirstButtonTheme(ButtonTheme.PRIMARY) + }.run { show() } + result?.takeIf { it.isNotEmpty() }?.let { + node.text = it + node.tooltipText = "Modified: $it" + } + } + } + } + } + } +} diff --git a/src/main/kotlin/com/webforj/samples/views/tree/TreeSelectionKotlinView.kt b/src/main/kotlin/com/webforj/samples/views/tree/TreeSelectionKotlinView.kt new file mode 100644 index 000000000..b14a285b2 --- /dev/null +++ b/src/main/kotlin/com/webforj/samples/views/tree/TreeSelectionKotlinView.kt @@ -0,0 +1,77 @@ +package com.webforj.samples.views.tree + +import com.webforj.component.Composite +import com.webforj.component.layout.flexlayout.FlexDirection +import com.webforj.component.layout.flexlayout.FlexLayout +import com.webforj.component.optiondialog.OptionDialog.showMessageDialog +import com.webforj.component.tree.Tree +import com.webforj.component.tree.TreeNode +import com.webforj.kotlin.dsl.component.button.button +import com.webforj.kotlin.dsl.component.optioninput.switch +import com.webforj.kotlin.dsl.component.tree.tree +import com.webforj.kotlin.dsl.component.tree.treeNode +import com.webforj.kotlin.extension.px +import com.webforj.kotlin.extension.set +import com.webforj.kotlin.extension.styles +import com.webforj.router.annotation.FrameTitle +import com.webforj.router.annotation.Route + +@Route +@FrameTitle("Tree Selection Example") +class TreeSelectionKotlinView: Composite() { + private val self = boundComponent + + init { + self.apply { + direction = FlexDirection.COLUMN + maxWidth = 400.px + styles["margin"] = "0 auto" + styles["padding"] = "var(--dwc-space-l)" + styles["overflow"] = "auto" + styles["height"] = "calc(100vh - 2 * var(--dwc-space-l)" + val multiSelectToggle = switch("Enable Multi-selection", true) + val tree = tree { + selectionMode = Tree.SelectionMode.MULTIPLE + treeNode("Colors") { + treeNode("Red") + treeNode("Green") + treeNode("Blue") + }.also { + expand(it) + selectChildren(it) + } + treeNode("Shapes") { + treeNode("Circle") + treeNode("Square") + treeNode("Triangle") + } + treeNode("Animals") { + treeNode("Dog") + treeNode("Cat") + treeNode("Bird") + } + multiSelectToggle.onToggle { + if (it.isToggled) { + selectionMode = Tree.SelectionMode.MULTIPLE + } else { + selectionMode = Tree.SelectionMode.SINGLE + } + } + } + button("Show Selected Nodes") { + onClick { + val msg = tree.selectedItems.takeIf { it.isNotEmpty() }?.let { selectedNodes -> + val nodes = selectedNodes.map(TreeNode::getText) + .joinToString("", "
    ", "
") { "
  • $it
  • " } + """ + You have selected the following nodes + $nodes + + """.trimIndent() + } ?: "There are no node selected" + showMessageDialog(msg, "Node Selection") + } + } + } + } +} From 32b44e96a46e88e5e108a9928e2a3843843b5210 Mon Sep 17 00:00:00 2001 From: cliebhardt Date: Wed, 1 Apr 2026 12:17:52 +0200 Subject: [PATCH 2/2] fix: fix typo and structure --- .../webforj/samples/views/tree/TreeIconsKotlinView.kt | 10 ++++------ .../com/webforj/samples/views/tree/TreeKotlinView.kt | 6 ++---- .../samples/views/tree/TreeLazyLoadKotlinView.kt | 2 +- .../samples/views/tree/TreeSelectionKotlinView.kt | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/com/webforj/samples/views/tree/TreeIconsKotlinView.kt b/src/main/kotlin/com/webforj/samples/views/tree/TreeIconsKotlinView.kt index 5cbd6fc71..6a173a9e8 100644 --- a/src/main/kotlin/com/webforj/samples/views/tree/TreeIconsKotlinView.kt +++ b/src/main/kotlin/com/webforj/samples/views/tree/TreeIconsKotlinView.kt @@ -77,12 +77,10 @@ class TreeIconsKotlinView: Composite() { setIcon(FeatherIcon.IMAGE.create()) setSelectedIcon(FeatherIcon.IMAGE.create()) } - treeNode("Mountains") { - treeNode("Mountains.png") { - tooltipText = "Mountain photo" - setIcon(FeatherIcon.IMAGE.create()) - setSelectedIcon(FeatherIcon.IMAGE.create()) - } + treeNode("Mountains.png") { + tooltipText = "Mountain photo" + setIcon(FeatherIcon.IMAGE.create()) + setSelectedIcon(FeatherIcon.IMAGE.create()) } } treeNode("Events") { diff --git a/src/main/kotlin/com/webforj/samples/views/tree/TreeKotlinView.kt b/src/main/kotlin/com/webforj/samples/views/tree/TreeKotlinView.kt index 1672f0e97..d43592744 100644 --- a/src/main/kotlin/com/webforj/samples/views/tree/TreeKotlinView.kt +++ b/src/main/kotlin/com/webforj/samples/views/tree/TreeKotlinView.kt @@ -61,10 +61,8 @@ class TreeKotlinView: Composite() { treeNode("Beach.png") { tooltipText = "Beach photo" } - treeNode("Mountains") { - treeNode("Mountains.png") { - tooltipText = "Mountain photo" - } + treeNode("Mountains.png") { + tooltipText = "Mountain photo" } } treeNode("Events") { diff --git a/src/main/kotlin/com/webforj/samples/views/tree/TreeLazyLoadKotlinView.kt b/src/main/kotlin/com/webforj/samples/views/tree/TreeLazyLoadKotlinView.kt index 761a7e11c..b7d0bc0ea 100644 --- a/src/main/kotlin/com/webforj/samples/views/tree/TreeLazyLoadKotlinView.kt +++ b/src/main/kotlin/com/webforj/samples/views/tree/TreeLazyLoadKotlinView.kt @@ -27,7 +27,7 @@ class TreeLazyLoadKotlinView: Composite() { styles["margin"] = "var(--dwc-space-l)" for (i in 1..4) { treeNode("Node $i") { - treeNode("") { setUserData("spinner", true) } } diff --git a/src/main/kotlin/com/webforj/samples/views/tree/TreeSelectionKotlinView.kt b/src/main/kotlin/com/webforj/samples/views/tree/TreeSelectionKotlinView.kt index b14a285b2..4cb8966f7 100644 --- a/src/main/kotlin/com/webforj/samples/views/tree/TreeSelectionKotlinView.kt +++ b/src/main/kotlin/com/webforj/samples/views/tree/TreeSelectionKotlinView.kt @@ -28,7 +28,7 @@ class TreeSelectionKotlinView: Composite() { styles["margin"] = "0 auto" styles["padding"] = "var(--dwc-space-l)" styles["overflow"] = "auto" - styles["height"] = "calc(100vh - 2 * var(--dwc-space-l)" + styles["height"] = "calc(100vh - 2 * var(--dwc-space-l))" val multiSelectToggle = switch("Enable Multi-selection", true) val tree = tree { selectionMode = Tree.SelectionMode.MULTIPLE