Skip to content

Commit

Permalink
Merge pull request #4 from Cullen-Shannon/uiUpdates
Browse files Browse the repository at this point in the history
Mostly-functional UI, still needs a few things.
  • Loading branch information
Cullen-Shannon authored Jul 8, 2024
2 parents 0dcaaa7 + 9e17701 commit d9e01b0
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import java.awt.Dimension
import javax.swing.JComponent
import javax.swing.JPanel
import javax.swing.tree.DefaultMutableTreeNode
import javax.swing.tree.DefaultTreeModel
import javax.swing.tree.TreeSelectionModel

class AppSettingsConfigurable : Configurable {

Expand All @@ -26,12 +28,6 @@ class AppSettingsConfigurable : Configurable {
// The tree representing the current `MyMenuItem` config, update this when adding/removing elements
private var currentTree: Tree? = null

// dummy item for dev purposes
private val dummyMenuItem = MyMenuItem(
text = "text",
description = "description"
)

// Keep track of the "Path" text field so that we can read the value
private var pathTextFieldCell: Cell<JBTextField>? = null

Expand Down Expand Up @@ -67,40 +63,84 @@ class AppSettingsConfigurable : Configurable {
}
}

private fun myTreeDecorated(): JPanel {
val menuItem = fileInputService.readConfigFileContents()
/*
More TODOs:
reorder list to move items up and down
Add as a sibling in the list instead of at the bottom of the parent
double click to enter edit menu
Add divider options
Consider slightly different format for collection vs individual record, if possible
*/

var rootNode: DefaultMutableTreeNode? = null
private fun myTreeDecorated(): JPanel {

// TODO: Error Handling
if (menuItem != null) {
// Update the plugin's model with the menu that was just read in
pluginSettingsService.state.currentMenuItemConfig = menuItem
rootNode = DefaultMutableTreeNode(menuItem.text)
if (menuItem.children != null) {
FileInputUtil.readInTreeChildren(rootNode = rootNode, children = menuItem.children!!)
}
}

// Update the plugin's model with the menu that was just read in
val model = fileInputService.readConfigFileContents()!!
pluginSettingsService.state.currentMenuItemConfig = model
val rootNode = DefaultMutableTreeNode(model)
FileInputUtil.readInTreeChildren(rootNode = rootNode, children = model.children!!)
currentTree = Tree(rootNode)
currentTree!!.isRootVisible = true
currentTree!!.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION

// this might work if we want to add a double click event; leaving for reference
// currentTree!!.addMouseListener(object : MouseListener {
// override fun mouseClicked(e: MouseEvent?) {
// if (e?.clickCount == 2 && !e.isConsumed) {
// e.consume();
// println(e)
// }
// }
// override fun mousePressed(p0: MouseEvent?) {}
// override fun mouseReleased(p0: MouseEvent?) {}
// override fun mouseEntered(p0: MouseEvent?) {}
// override fun mouseExited(p0: MouseEvent?) {}
// })

val decoratedTree = ToolbarDecorator.createDecorator(currentTree!!)
.setAddAction {
if (MyDialog(dummyMenuItem).showAndGet()) {
Log.e("TAGX", "Got it!")
.setAddAction {
val changed = MyDialog(MyMenuItem("", "")) {
val selection = currentTree!!.lastSelectedPathComponent as DefaultMutableTreeNode?
val _model = currentTree!!.model as DefaultTreeModel

Check notice on line 105 in src/main/java/org/jetbrains/plugins/template/AppSettingsConfigurable.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Local variable naming convention

Local variable name `_model` should start with a lowercase letter
if (selection == null) {
val root = _model.root as DefaultMutableTreeNode
root.add(DefaultMutableTreeNode(it))
_model.reload()
} else {
val selCasted = selection.userObject as MyMenuItem
val addToParent = selCasted.children == null
if (addToParent) {
(selection.parent as DefaultMutableTreeNode).add(DefaultMutableTreeNode(it))
_model.reload(selection.parent as DefaultMutableTreeNode)
} else {
selection.add(DefaultMutableTreeNode(it))
_model.reload(selection)
}
}
}
.setRemoveAction { Log.e("TAGX", "TODO remove") }
.setEditAction { Log.e("TAGX", "TODO edit") }
.setPreferredSize(Dimension(400, 300)) // TODO -- can't figure out a way around needing this
.createPanel()
}.showAndGet()
if (changed) isModified = true
}
.setRemoveAction {
val selection = currentTree!!.lastSelectedPathComponent as DefaultMutableTreeNode
val _model = currentTree!!.model as DefaultTreeModel

Check notice on line 126 in src/main/java/org/jetbrains/plugins/template/AppSettingsConfigurable.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Local variable naming convention

Local variable name `_model` should start with a lowercase letter
_model.removeNodeFromParent(selection)
isModified = true
}
.setEditAction {
val selection = currentTree!!.lastSelectedPathComponent as DefaultMutableTreeNode
val changed = MyDialog(selection.userObject as MyMenuItem) {
selection.userObject = it
(currentTree!!.model as DefaultTreeModel).reload()
}.showAndGet()
if (changed) isModified = true
}
.setPreferredSize(Dimension(600, 400)) // TODO -- can't figure out a way around needing this
.createPanel()
return decoratedTree
}

override fun isModified(): Boolean {
return isModified
}
override fun isModified() = isModified

override fun apply() {
// TODO: Error Handling
Expand Down Expand Up @@ -128,7 +168,7 @@ class AppSettingsConfigurable : Configurable {
}

override fun getPreferredFocusedComponent(): JComponent? {

Check warning on line 170 in src/main/java/org/jetbrains/plugins/template/AppSettingsConfigurable.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Redundant nullable return type

'getPreferredFocusedComponent' always returns non-null type
return super.getPreferredFocusedComponent()
return pathTextFieldCell!!.component
}

override fun disposeUIResources() {

Check notice on line 174 in src/main/java/org/jetbrains/plugins/template/AppSettingsConfigurable.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Redundant overriding method

Redundant overriding method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ import javax.swing.tree.DefaultMutableTreeNode
* Represents a group of menu items. menuItem will be null for the top level menu defined in plugin.xml.
* Otherwise we can pass in the child object recursively to allow for infinite nesting based on user configuration.
*/
class DynamicActionGroup(var menuItem: MyMenuItem? = null, ) : ActionGroup() {

private val project = ProjectManager.getInstance().openProjects.first()
private val fileInputService = FileInputService.getInstance(project)
private val pluginSettingsService = PluginSettingsService.getInstance(project)
class DynamicActionGroup(var menuItem: MyMenuItem? = null ) : ActionGroup() {

Check notice on line 25 in src/main/java/org/jetbrains/plugins/template/DynamicActionGroup.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Class member can have 'private' visibility

Property 'menuItem' could be private

override fun update(e: AnActionEvent) {

val project = ProjectManager.getInstance().openProjects.first()
val fileInputService = FileInputService.getInstance(project)
val pluginSettingsService = PluginSettingsService.getInstance(project)

// TODO: Error Handling
if (menuItem == null) {
// Read in top level menu item
Expand All @@ -55,13 +56,13 @@ class DynamicActionGroup(var menuItem: MyMenuItem? = null, ) : ActionGroup() {

val array = mutableListOf<AnAction>()
menuItem!!.children!!.forEach {
if (it.addSeparatorBefore == true) array.add(Separator.getInstance())
if (it.addSeparatorBefore) array.add(Separator.getInstance())
if (it.children.isNullOrEmpty()) {
array.add(MyAction(it))
} else {
array.add(DynamicActionGroup(it))
}
if (it.addSeparatorAfter == true) array.add(Separator.getInstance())
if (it.addSeparatorAfter) array.add(Separator.getInstance())
}
// Add a custom edit menu to launch our UI
if (menuItem!!.isTopLevel) {
Expand Down
65 changes: 45 additions & 20 deletions src/main/java/org/jetbrains/plugins/template/MyDialog.kt
Original file line number Diff line number Diff line change
@@ -1,39 +1,64 @@
package org.jetbrains.plugins.template

import com.intellij.openapi.ui.DialogWrapper
import com.intellij.openapi.ui.ValidationInfo
import com.intellij.ui.components.JBCheckBox
import com.intellij.ui.components.JBTextField
import com.intellij.ui.dsl.builder.*
import com.intellij.ui.layout.not
import org.jetbrains.plugins.template.domain.MyMenuItem
import javax.swing.JComponent

class MyDialog(private val myMenuItem: MyMenuItem): DialogWrapper(true) {
/**
* Maintenance dialog.
* currentTree needed to determine what, if anything is selected
*/
class MyDialog(val model: MyMenuItem, val onSubmit: (MyMenuItem) -> Unit): DialogWrapper(true) {

Check notice on line 16 in src/main/java/org/jetbrains/plugins/template/MyDialog.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Class member can have 'private' visibility

Property 'model' could be private

lateinit var checkBox: Cell<JBCheckBox>
private lateinit var _title: Cell<JBTextField>
private lateinit var _description: Cell<JBTextField>
private lateinit var _url: Cell<JBTextField>
private lateinit var _isCollection: Cell<JBCheckBox>

private val panel = panel {
row("Title: ") {
_title = textField().bindText(model::text)
}
row("Description: ") {
_description = textField().bindText(model::description)
}
row {
_isCollection = checkBox("Is Collection").selected(model.children != null)

Check warning on line 31 in src/main/java/org/jetbrains/plugins/template/MyDialog.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Incorrect string capitalization

String 'Is Collection' is not properly capitalized. It should have sentence capitalization
}
row("Url: ") {
_url = textField().text(if (model.url == null) "" else model.url!!)
}.enabledIf(_isCollection.selected.not())
}

override fun doValidate(): ValidationInfo? {
if (_title.component.text.isBlank()) return ValidationInfo("Title is required!")
if (_description.component.text.isBlank()) return ValidationInfo("Description is required!")
if (!_isCollection.component.isSelected && _url.component.text.isBlank()) return ValidationInfo("Url is required!")
return null
}

init {
title = "Maintain Entry"
init()
}

override fun createCenterPanel(): JComponent? {

return panel {
row("Title: ") {
textField().bindText(myMenuItem::text)
}
row("Description: ") {
textField().bindText(myMenuItem::description)
}
row {
checkBox = checkBox("Group?")
}
row("Url: ") {
textField()
}.enabledIf(checkBox.selected.not())
}
}
override fun createCenterPanel() = panel

// todo handle okay listener
override fun doOKAction() {
panel.apply() // needed to set
val isCollection = _isCollection.component.isSelected
model.url = if (isCollection) null else _url.component.text
model.children = if (isCollection) mutableListOf() else null
onSubmit(model)
super.doOKAction()
}

override fun getPreferredFocusedComponent(): JComponent? {

Check warning on line 61 in src/main/java/org/jetbrains/plugins/template/MyDialog.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Redundant nullable return type

'getPreferredFocusedComponent' always returns non-null type
return _title.component
}
}
18 changes: 10 additions & 8 deletions src/main/java/org/jetbrains/plugins/template/domain/MyMenuItem.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.jetbrains.plugins.template.domain

data class MyMenuItem(
var text: String,
var description: String,
var url: String? = null,
var children: List<MyMenuItem>? = null,
var addSeparatorBefore: Boolean = false,
var addSeparatorAfter: Boolean = false,
var isTopLevel: Boolean = false
)
var text: String,
var description: String,
var url: String? = null,
var children: MutableList<MyMenuItem>? = null,
var addSeparatorBefore: Boolean = false,
var addSeparatorAfter: Boolean = false,
var isTopLevel: Boolean = false
) {
override fun toString() = text
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class FileInputService {
if (configFile != null) {
val text = LoadTextUtil.loadText(configFile)
menuItem = Gson().fromJson(text.toString(), MyMenuItem::class.java)
menuItem.isTopLevel = true
}

return menuItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ object FileInputUtil {
*/
fun readInTreeChildren(rootNode: DefaultMutableTreeNode, children: List<MyMenuItem>) {
for (child in children) {
val childNode = DefaultMutableTreeNode(child.text)
val childNode = DefaultMutableTreeNode(child)
rootNode.add(childNode)

// Recursively read in the tree's children
Expand Down

0 comments on commit d9e01b0

Please sign in to comment.