From 739eac67f424eac02a717b1fd58713b339d0e14a Mon Sep 17 00:00:00 2001 From: Mara Date: Sat, 3 Aug 2024 11:00:26 +0800 Subject: [PATCH] a6.8.2 --- .../controller/BaseDataTreeController.java | 163 +--- .../BaseDataTreeNodeController.java | 379 +++++++++ .../controller/ControlDataTreeManage.java | 767 ++++++++++++++++++ .../ControlDataTreeNodeAttributes.java | 185 +++++ .../controller/ControlDataTreeNodeTags.java | 310 +++++++ .../controller/ControlDataTreeTable.java | 516 ++++++++++++ .../mybox/controller/ControlDataTreeView.java | 100 +-- .../controller/DataTreeManageController.java | 364 +++++++++ .../mybox/controller/DataTreeNodeEditor.java | 316 ++++++++ .../DataTreeNodeParentController.java | 55 ++ .../mara/mybox/controller/NoteEditor.java | 3 +- .../java/mara/mybox/db/data/TreeNode.java | 52 +- .../java/mara/mybox/db/table/TableTree.java | 223 ++--- .../resources/fxml/ControlDataTreeManage.fxml | 71 ++ .../fxml/ControlDataTreeNodeAttributes.fxml | 53 ++ .../fxml/ControlDataTreeNodeTags.fxml | 56 ++ .../resources/fxml/ControlDataTreeView.fxml | 72 ++ .../src/main/resources/fxml/NoteEditor.fxml | 16 +- .../src/main/resources/fxml/NotesQuery.fxml | 215 +++++ .../src/main/resources/fxml/NotesTree.fxml | 116 +++ 20 files changed, 3615 insertions(+), 417 deletions(-) create mode 100644 alpha/MyBox/src/main/java/mara/mybox/controller/BaseDataTreeNodeController.java create mode 100644 alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeManage.java create mode 100644 alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeNodeAttributes.java create mode 100644 alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeNodeTags.java create mode 100644 alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeTable.java create mode 100644 alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeManageController.java create mode 100644 alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeNodeEditor.java create mode 100644 alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeNodeParentController.java create mode 100644 alpha/MyBox/src/main/resources/fxml/ControlDataTreeManage.fxml create mode 100644 alpha/MyBox/src/main/resources/fxml/ControlDataTreeNodeAttributes.fxml create mode 100644 alpha/MyBox/src/main/resources/fxml/ControlDataTreeNodeTags.fxml create mode 100644 alpha/MyBox/src/main/resources/fxml/ControlDataTreeView.fxml create mode 100644 alpha/MyBox/src/main/resources/fxml/NotesQuery.fxml create mode 100644 alpha/MyBox/src/main/resources/fxml/NotesTree.fxml diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/BaseDataTreeController.java b/alpha/MyBox/src/main/java/mara/mybox/controller/BaseDataTreeController.java index da5e7f8ec..a49df4d66 100644 --- a/alpha/MyBox/src/main/java/mara/mybox/controller/BaseDataTreeController.java +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/BaseDataTreeController.java @@ -1,16 +1,6 @@ package mara.mybox.controller; -import javafx.event.Event; -import javafx.event.EventHandler; -import javafx.fxml.FXML; -import javafx.scene.control.Button; -import javafx.scene.control.RadioButton; -import javafx.scene.control.SplitPane; -import javafx.scene.control.TextField; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.FlowPane; -import javafx.scene.layout.VBox; -import mara.mybox.db.data.InfoNode; +import mara.mybox.db.data.TreeNode; import mara.mybox.db.data.VisitHistory; import mara.mybox.db.table.BaseTable; import mara.mybox.db.table.TableTag; @@ -18,8 +8,6 @@ import mara.mybox.db.table.TableTreeTag; import mara.mybox.dev.MyBoxLog; import mara.mybox.fxml.FxSingletonTask; -import mara.mybox.fxml.PopTools; -import mara.mybox.value.UserConfig; /** * @Author Mara @@ -28,51 +16,17 @@ */ public abstract class BaseDataTreeController extends BaseController { - protected ControlDataTreeView infoTree; + protected ControlDataTreeView treeView; protected BaseTable dataTable; protected TableTree tableTree; protected TableTag tableTag; protected TableTreeTag tableTreeTag; - @FXML - protected ControlDataTreeView listController; - @FXML - protected ControlInfoTreeTable tableController; - @FXML - protected VBox timesBox; - @FXML - protected RadioButton findNameRadio, findValueRadio; - @FXML - protected FlowPane tagsPane; - @FXML - protected Button refreshTimesButton, queryTimesButton; - @FXML - protected InfoTreeTagsController tagsController; - @FXML - protected ControlTimesTree timesController; - @FXML - protected TextField findInput; - @FXML - protected SplitPane managePane; - @FXML - protected VBox nodesListBox; - @Override public void setFileType() { setFileType(VisitHistory.FileType.Text); } - @Override - public void initValues() { - try { - super.initValues(); - - infoTree = listController; - } catch (Exception e) { - MyBoxLog.error(e); - } - } - public void loadData() { if (dataTable == null) { return; @@ -82,45 +36,14 @@ public void loadData() { tableTag = new TableTag(); tableTreeTag = new TableTreeTag(tableTree); - infoTree.setParameters(this); - tableController.setParameters(this); - tagsController.setParameters(this); - tagsController.loadTableData(); - - initTimes(); - initFind(); + treeView.setParameters(this); } catch (Exception e) { MyBoxLog.error(e); } } - public void showNodesList(boolean show) { - if (isSettingValues || infoTree.nodesListCheck == null) { - return; - } - infoTree.isSettingValues = true; - infoTree.nodesListCheck.setSelected(show); - infoTree.isSettingValues = false; - - isSettingValues = true; - if (show) { - if (!managePane.getItems().contains(nodesListBox)) { - managePane.getItems().add(1, nodesListBox); - } - } else { - if (managePane.getItems().contains(nodesListBox)) { - managePane.getItems().remove(nodesListBox); - } - } - isSettingValues = false; - - if (show && leftPaneCheck != null) { - leftPaneCheck.setSelected(true); - } - } - - public void popNode(InfoNode item) { + public void popNode(TreeNode item) { if (item == null) { return; } @@ -133,7 +56,7 @@ public void popNode(InfoNode item) { @Override protected boolean handle() { try { - html = InfoNode.nodeHtml(this, myController, item, null); + html = item.html(); return html != null && !html.isBlank(); } catch (Exception e) { error = e.toString(); @@ -150,80 +73,4 @@ protected void whenSucceeded() { start(task); } - /* - Times - */ - public void initTimes() { - try { - timesController.setParent(this, " category='" + category + "' ", "Tree_Node", "update_time"); - - timesController.queryNodesButton.setOnMouseClicked(new EventHandler() { - @Override - public void handle(MouseEvent event) { - queryTimes(); - } - }); - timesController.refreshNodesButton.setOnMouseClicked(new EventHandler() { - @Override - public void handle(MouseEvent event) { - refreshTimes(); - } - }); - - refreshTimes(); - } catch (Exception e) { - MyBoxLog.error(e); - } - } - - @FXML - protected void refreshTimes() { - timesController.loadTree(); - } - - @FXML - protected void queryTimes() { - tableController.queryTimes(timesController.check(), timesController.getFinalTitle()); - } - - /* - Tags - */ - protected void refreshTags() { - tagsController.refreshAction(); - } - - public void tagsChanged() { - } - - /* - find - */ - public void initFind() { - try { - findNameRadio.setText(nameMsg); - findValueRadio.setText(valueMsg); - } catch (Exception e) { - MyBoxLog.error(e); - } - } - - @FXML - protected void find() { - tableController.find(findInput.getText(), findNameRadio.isSelected()); - - } - - @FXML - protected void showFindHistories(Event event) { - PopTools.popStringValues(this, findInput, event, baseName + category + "Histories", false); - } - - @FXML - public void popFindHistories(Event event) { - if (UserConfig.getBoolean(baseName + category + "HistoriesPopWhenMouseHovering", false)) { - showFindHistories(event); - } - } - } diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/BaseDataTreeNodeController.java b/alpha/MyBox/src/main/java/mara/mybox/controller/BaseDataTreeNodeController.java new file mode 100644 index 000000000..ee234a1fc --- /dev/null +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/BaseDataTreeNodeController.java @@ -0,0 +1,379 @@ +package mara.mybox.controller; + +import java.io.File; +import java.nio.charset.Charset; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.event.Event; +import javafx.fxml.FXML; +import javafx.scene.control.Tab; +import mara.mybox.db.data.TreeNode; +import static mara.mybox.db.data.TreeNode.TitleSeparater; +import mara.mybox.db.data.VisitHistory; +import mara.mybox.dev.MyBoxLog; +import mara.mybox.fxml.FxSingletonTask; +import mara.mybox.fxml.FxTask; +import mara.mybox.fxml.PopTools; +import mara.mybox.tools.DateTools; +import mara.mybox.tools.TextFileTools; +import static mara.mybox.value.Languages.message; +import mara.mybox.value.UserConfig; + +/** + * @Author Mara + * @CreateDate 2024-8-3 + * @License Apache License Version 2.0 + */ +public class BaseDataTreeNodeController extends BaseController { + + protected DataTreeManageController manager; + protected String defaultExt; + protected final SimpleBooleanProperty nodeChanged; + protected BaseController valuesEditor; + + @FXML + protected Tab attributesTab, valueTab, tagsTab; + @FXML + protected ControlDataTreeNodeAttributes attributesController; + @FXML + protected ControlDataTreeNodeTags tagsController; + + public BaseDataTreeNodeController() { + defaultExt = "txt"; + nodeChanged = new SimpleBooleanProperty(false); + } + + @Override + public void setFileType() { + setFileType(VisitHistory.FileType.Text); + } + + public void setManager(DataTreeManageController treeController) { + try { + this.manager = treeController; + attributesController.setParameters(manager); + tagsController.setParameters(manager); + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + protected boolean editNode(TreeNode node) { + updateEditorTitle(node); + attributesController.editNode(node); + editValue(node); + showEditorPane(); + nodeChanged(false); + return true; + } + + protected void updateEditorTitle(TreeNode node) { + if (node != null) { + manager.setTitle(manager.baseTitle + ": " + + node.getNodeid() + " - " + node.getTitle()); + } else { + manager.setTitle(manager.baseTitle); + } + } + + protected void editValue(TreeNode node) { + if (valueInput == null) { + return; + } + isSettingValues = true; + if (node != null) { + valueInput.setText(node.getInfo()); + } else { + valueInput.setText(""); + } + isSettingValues = false; + } + + public TreeNode pickNodeData() { + String title = nodeTitle(); + if (title == null || title.isBlank()) { + return null; + } + TreeNode node = TreeNode.create() + .setDataTable(manager.dataTable) + .setTitle(title); + return pickValue(node); + } + + public void saveNode() { +// TreeNode node = editor.pickNodeData(); +// if (node == null) { +// return; +// } +// if (parentNode == null) { +// selectParent(); +// return; +// } +// if (task != null) { +// task.cancel(); +// } +// task = new FxSingletonTask(this) { +// private boolean newData = false; +// +// @Override +// protected boolean handle() { +// try (Connection conn = DerbyBase.getConnection()) { +// node.setUpdateTime(new Date()); +// if (currentNode != null) { +// currentNode = tableTree.readData(conn, currentNode); +// if (currentNode == null) { +// conn.close(); +// return true; +// } +// if (currentNode.getParentid() >= 0) { +// parentNode = tableTree.find(conn, currentNode.getParentid()); +// } else { +// parentNode = tableTree.readData(conn, parentNode); +// } +// if (parentNode == null) { +// currentNode = null; +// conn.close(); +// return true; +// } else { +// node.setNodeid(currentNode.getNodeid()); +// node.setParentid(parentNode.getNodeid()); +// currentNode = tableTree.updateData(conn, node); +// newData = false; +// } +// } else { +// node.setParentid(parentNode.getNodeid()); +// currentNode = tableTree.insertData(conn, node); +// newData = true; +// } +// if (currentNode == null) { +// conn.close(); +// return false; +// } +// long nodeid = currentNode.getNodeid(); +// List nodeTags = tableTreeTag.nodeTagNames(conn, nodeid); +// List selected = selectedItems(); +// if (selected == null || selected.isEmpty()) { +// tableTreeNodeTag.removeTags(conn, nodeid); +// } else { +// List selectedNames = new ArrayList<>(); +// for (Tag tag : selected) { +// selectedNames.add(tag.getTag()); +// } +// List items = new ArrayList<>(); +// for (String tagName : selectedNames) { +// if (!nodeTags.contains(tagName)) { +// items.add(tagName); +// } +// } +// tableTreeNodeTag.addTags(conn, nodeid, category, items); +// items.clear(); +// for (String tagName : nodeTags) { +// if (!selectedNames.contains(tagName)) { +// items.add(tagName); +// } +// } +// tableTreeNodeTag.removeTags(conn, nodeid, category, items); +// } +// conn.commit(); +// } catch (Exception e) { +// error = e.toString(); +// MyBoxLog.error(e); +// return false; +// } +// return currentNode != null; +// } +// +// @Override +// protected void whenSucceeded() { +// if (parentNode == null) { +// selectParent(); +// } +// if (currentNode == null) { +// copyNode(); +// popError(message("NotExist")); +// } else { +// editor.editNode(currentNode); +// if (newData) { +// manager.newNodeSaved(); +// } else { +// manager.nodeSaved(); +// } +// popSaved(); +// } +// } +// +// }; +// start(task); + } + + protected TreeNode pickValue(TreeNode node) { + if (node == null) { + return null; + } + String info = null; + if (valueInput != null) { + info = valueInput.getText(); + } + return node.setInfo(info); + } + + protected String nodeTitle() { + String title = attributesController.nameInput.getText(); + if (title == null || title.isBlank()) { + popError(message("InvalidParameters") + ": " + manager.nameMsg); + if (tabPane != null && attributesTab != null) { + tabPane.getSelectionModel().select(attributesTab); + } + return null; + } + if (title.contains(TitleSeparater)) { + popError(message("NameShouldNotInclude") + " \"" + TitleSeparater + "\""); + return null; + } + return title; + } + + protected void showEditorPane() { + manager.showRightPane(); + } + + public void valueChanged(boolean changed) { + if (isSettingValues) { + return; + } + if (valueTab != null) { + valueTab.setText(manager.valueMsg + (changed ? "*" : "")); + } + if (changed) { + nodeChanged(changed); + } + } + + public void nodeChanged(boolean changed) { + if (isSettingValues) { + return; + } + nodeChanged.set(changed); + if (!changed) { + if (valueTab != null) { + valueTab.setText(manager.valueMsg); + } + if (attributesTab != null) { + attributesTab.setText(message("Attributes")); + } + } + } + + public void newNodeCreated() { + popInformation(message("InputNewNode")); + if (tabPane != null && attributesTab != null) { + tabPane.getSelectionModel().select(attributesTab); + } + } + + public boolean isNewNode() { + return attributesController.currentNode == null; + } + + @FXML + @Override + public void saveAsAction() { + if (valueInput == null) { + return; + } + String codes = valueInput.getText(); + if (codes == null || codes.isBlank()) { + popError(message("NoData")); + return; + } + File file = chooseSaveFile(message(manager.category) + "-" + DateTools.nowFileString() + "." + defaultExt); + if (file == null) { + return; + } + FxTask saveAsTask = new FxTask(this) { + + @Override + protected boolean handle() { + File tfile = TextFileTools.writeFile(file, codes, Charset.forName("UTF-8")); + return tfile != null && tfile.exists(); + } + + @Override + protected void whenSucceeded() { + popInformation(message("Saved")); + recordFileWritten(file); + } + + }; + start(saveAsTask, false); + } + + @FXML + public void clearValue() { + if (valueInput != null) { + valueInput.clear(); + } + } + + @Override + public void sourceFileChanged(File file) { + if (valueInput == null + || file == null || !file.exists() + || !manager.checkBeforeNextAction()) { + return; + } + editNode(null); + if (task != null) { + task.cancel(); + } + valueInput.clear(); + task = new FxSingletonTask(this) { + + String codes; + + @Override + protected boolean handle() { + codes = TextFileTools.readTexts(this, file); + return codes != null; + } + + @Override + protected void whenSucceeded() { + valueInput.setText(codes); + recordFileOpened(file); + } + + }; + start(task, thisPane); + } + + public void pasteNode(TreeNode node) { + if (valueInput == null || node == null) { + return; + } + String v = TreeNode.majorInfo(node); + if (v == null || v.isBlank()) { + return; + } + valueInput.replaceText(valueInput.getSelection(), v); + valueInput.requestFocus(); + tabPane.getSelectionModel().select(valueTab); + } + + protected String editorName() { + return manager.category; + } + + @FXML + protected void popHistories(Event event) { + if (UserConfig.getBoolean(editorName() + "HistoriesPopWhenMouseHovering", false)) { + showHistories(event); + } + } + + @FXML + protected void showHistories(Event event) { + PopTools.popStringValues(this, valueInput, event, editorName() + "Histories", false); + } + +} diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeManage.java b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeManage.java new file mode 100644 index 000000000..f7e737d7b --- /dev/null +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeManage.java @@ -0,0 +1,767 @@ +package mara.mybox.controller; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.nio.charset.Charset; +import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; +import javafx.event.ActionEvent; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.control.CheckMenuItem; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.control.RadioMenuItem; +import javafx.scene.control.SeparatorMenuItem; +import javafx.scene.control.ToggleGroup; +import javafx.scene.control.TreeItem; +import javafx.scene.input.MouseEvent; +import javafx.scene.paint.Color; +import mara.mybox.db.DerbyBase; +import mara.mybox.db.data.TreeNode; +import static mara.mybox.db.data.TreeNode.TitleSeparater; +import mara.mybox.db.data.TreeNodeTag; +import mara.mybox.dev.MyBoxLog; +import mara.mybox.fximage.FxColorTools; +import mara.mybox.fxml.FxSingletonTask; +import mara.mybox.fxml.FxTask; +import mara.mybox.fxml.PopTools; +import mara.mybox.fxml.style.HtmlStyles; +import mara.mybox.fxml.style.StyleTools; +import mara.mybox.tools.FileTmpTools; +import mara.mybox.tools.HtmlWriteTools; +import mara.mybox.tools.StringTools; +import mara.mybox.value.Fxmls; +import static mara.mybox.value.Languages.message; +import mara.mybox.value.UserConfig; + +/** + * @Author Mara + * @CreateDate 2022-8-3 + * @License Apache License Version 2.0 + */ +public class ControlDataTreeManage extends ControlDataTreeView { + + protected DataTreeManageController manager; + protected boolean nodeExecutable; + + public void setManager(DataTreeManageController parent) { + manager = parent; + nodeExecutable = manager != null + && (manager.startButton != null || manager.goButton != null + || (manager.editor != null + && (manager.editor.startButton != null + || manager.editor.goButton != null))); + } + + @Override + public void loadTree() { + try (Connection conn = DerbyBase.getConnection()) { +// if (tableTree.categoryEmpty(conn)) { +// File file = TreeNode.exampleFile(category); +// if (file != null) { +// if (AppVariables.isTesting +// || PopTools.askSure(getTitle(), message("ImportExamples") + ": " + message(category))) { +// importExamples(); +// return; +// } +// } +// } + loadTree(null); + } catch (Exception e) { + MyBoxLog.debug(e); + } + } + + public String chainName(Connection conn, TreeNode node) { + if (node == null) { + return null; + } + String chainName = ""; + List ancestor = ancestor(conn, node); + if (ancestor != null) { + for (TreeNode a : ancestor) { + chainName += a.getTitle() + TitleSeparater; + } + } + chainName += node.getTitle(); + return chainName; + } + + @Override + public void itemClicked(MouseEvent event, TreeItem item) { + clicked(UserConfig.getString(baseName + "WhenLeftClickNode", "Edit"), item); + } + + @Override + public void doubleClicked(MouseEvent event, TreeItem item) { + clicked(UserConfig.getString(baseName + "WhenDoubleClickNode", "PopNode"), item); + } + + @Override + public void rightClicked(MouseEvent event, TreeItem item) { + clicked(UserConfig.getString(baseName + "WhenRightClickNode", "PopMenu"), item); + } + + public void clicked(String clickAction, TreeItem item) { + if (item == null || clickAction == null) { + return; + } + switch (clickAction) { + case "PopMenu": + showPopMenu(item); + break; + case "Edit": + editNode(item); + break; + case "Paste": + pasteNode(item); + break; + case "PopNode": + popNode(item); + break; + case "Execute": + executeNode(item); + break; +// case "LoadChildren": +// listChildren(item); +// break; +// case "LoadDescendants": +// listDescentants(item); +// break; + default: + break; + } + } + + @Override + public List operationsMenuItems(TreeItem treeItem) { + List items = new ArrayList<>(); + + items.addAll(updateMenuItems(treeItem)); + + items.add(new SeparatorMenuItem()); + + items.add(leftClickMenu(treeItem)); + items.add(doubleClickMenu(treeItem)); + items.add(rightClickMenu(treeItem)); + + return items; + } + + public List updateMenuItems(TreeItem treeItem) { + boolean isRoot = treeItem == null || isRoot(treeItem.getValue()); + + List items = new ArrayList<>(); + + MenuItem menu = new MenuItem(message("AddNode"), StyleTools.getIconImageView("iconAdd.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + addChild(treeItem); + }); + items.add(menu); + + menu = new MenuItem(message("DeleteNode"), StyleTools.getIconImageView("iconDelete.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + deleteNode(treeItem); + }); + items.add(menu); + + menu = new MenuItem(message("RenameNode"), StyleTools.getIconImageView("iconInput.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + renameNode(treeItem); + }); + menu.setDisable(isRoot); + items.add(menu); + + menu = new MenuItem(message("CopyNodes"), StyleTools.getIconImageView("iconCopy.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + copyNode(treeItem); + }); + menu.setDisable(isRoot); + items.add(menu); + + menu = new MenuItem(message("MoveNodes"), StyleTools.getIconImageView("iconMove.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + moveNode(treeItem); + }); + menu.setDisable(isRoot); + menu.setDisable(treeItem == null); + items.add(menu); + + if (nodeExecutable) { + menu = new MenuItem(message("Execute"), StyleTools.getIconImageView("iconGo.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + executeNode(treeItem); + }); + menu.setDisable(treeItem == null); + items.add(menu); + } + + menu = new MenuItem(message("EditNode"), StyleTools.getIconImageView("iconEdit.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + editNode(treeItem); + }); + menu.setDisable(treeItem == null); + items.add(menu); + + menu = new MenuItem(message("PasteNodeValueToCurrentEdit"), StyleTools.getIconImageView("iconPaste.png")); + menu.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + pasteNode(treeItem); + } + }); + items.add(menu); + + return items; + } + + @FXML + public void popDataMenu(Event event) { + if (UserConfig.getBoolean(baseName + "TreeDataPopWhenMouseHovering", true)) { + showDataMenu(event); + } + } + + @FXML + public void showDataMenu(Event event) { + TreeItem item = selected(); + if (item == null) { + return; + } + List items = new ArrayList<>(); + + MenuItem menu = new MenuItem(StringTools.menuPrefix(label(item))); + menu.setStyle("-fx-text-fill: #2e598a;"); + items.add(menu); + items.add(new SeparatorMenuItem()); + + items.addAll(dataMenuItems(item)); + + items.add(new SeparatorMenuItem()); + + CheckMenuItem popItem = new CheckMenuItem(message("PopMenuWhenMouseHovering"), StyleTools.getIconImageView("iconPop.png")); + popItem.setSelected(UserConfig.getBoolean(baseName + "TreeDataPopWhenMouseHovering", true)); + popItem.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + UserConfig.setBoolean(baseName + "TreeDataPopWhenMouseHovering", popItem.isSelected()); + } + }); + items.add(popItem); + + if (event == null) { + popNodeMenu(treeView, items); + } else { + popEventMenu(event, items); + } + } + + public List dataMenuItems(TreeItem item) { + if (item == null) { + return null; + } + List items = new ArrayList<>(); + + MenuItem menu = new MenuItem(message("TreeView"), StyleTools.getIconImageView("iconHtml.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + infoTree(); + }); + items.add(menu); + + menu = new MenuItem(message("Examples"), StyleTools.getIconImageView("iconExamples.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + importExamples(); + }); + items.add(menu); + + menu = new MenuItem(message("Export"), StyleTools.getIconImageView("iconExport.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + exportNode(item); + }); + items.add(menu); + + menu = new MenuItem(message("Import"), StyleTools.getIconImageView("iconImport.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + importAction(); + }); + items.add(menu); + + return items; + } + + public Menu leftClickMenu(TreeItem treeItem) { + Menu clickMenu = new Menu(message("WhenLeftClickNode"), StyleTools.getIconImageView("iconSelect.png")); + clickMenu(treeItem, clickMenu, "WhenLeftClickNode", "Edit"); + return clickMenu; + } + + public Menu doubleClickMenu(TreeItem treeItem) { + Menu clickMenu = new Menu(message("WhenDoubleClickNode"), StyleTools.getIconImageView("iconSelectAll.png")); + clickMenu(treeItem, clickMenu, "WhenDoubleClickNode", "PopNode"); + return clickMenu; + } + + public Menu rightClickMenu(TreeItem treeItem) { + Menu clickMenu = new Menu(message("WhenRightClickNode"), StyleTools.getIconImageView("iconSelectNone.png")); + clickMenu(treeItem, clickMenu, "WhenRightClickNode", "PopMenu"); + return clickMenu; + } + + public Menu clickMenu(TreeItem treeItem, Menu menu, String key, String defaultAction) { + ToggleGroup clickGroup = new ToggleGroup(); + String currentClick = UserConfig.getString(baseName + key, defaultAction); + + RadioMenuItem editNodeMenu = new RadioMenuItem(message("EditNode"), StyleTools.getIconImageView("iconEdit.png")); + editNodeMenu.setSelected("Edit".equals(currentClick)); + editNodeMenu.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + UserConfig.setString(baseName + key, "Edit"); + } + }); + editNodeMenu.setToggleGroup(clickGroup); + + RadioMenuItem popNodeMenu = new RadioMenuItem(message("PopNode"), StyleTools.getIconImageView("iconPop.png")); + popNodeMenu.setSelected("PopNode".equals(currentClick)); + popNodeMenu.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + UserConfig.setString(baseName + key, "PopNode"); + } + }); + popNodeMenu.setToggleGroup(clickGroup); + + RadioMenuItem pasteNodeMenu = new RadioMenuItem(message("PasteNodeValueToCurrentEdit"), StyleTools.getIconImageView("iconPaste.png")); + pasteNodeMenu.setSelected("Paste".equals(currentClick)); + pasteNodeMenu.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + UserConfig.setString(baseName + key, "Paste"); + } + }); + pasteNodeMenu.setToggleGroup(clickGroup); + + menu.getItems().addAll(editNodeMenu, pasteNodeMenu, popNodeMenu); + + if (nodeExecutable) { + RadioMenuItem executeNodeMenu = new RadioMenuItem(message("Execute"), StyleTools.getIconImageView("iconGo.png")); + executeNodeMenu.setSelected("Execute".equals(currentClick)); + executeNodeMenu.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + UserConfig.setString(baseName + key, "Execute"); + } + }); + executeNodeMenu.setToggleGroup(clickGroup); + menu.getItems().add(executeNodeMenu); + } + + RadioMenuItem loadChildrenMenu = new RadioMenuItem(message("LoadChildren"), StyleTools.getIconImageView("iconList.png")); + loadChildrenMenu.setSelected("LoadChildren".equals(currentClick)); + loadChildrenMenu.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + UserConfig.setString(baseName + key, "LoadChildren"); + } + }); + loadChildrenMenu.setToggleGroup(clickGroup); + + RadioMenuItem loadDescendantsMenu = new RadioMenuItem(message("LoadDescendants"), StyleTools.getIconImageView("iconList.png")); + loadDescendantsMenu.setSelected("LoadDescendants".equals(currentClick)); + loadDescendantsMenu.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + UserConfig.setString(baseName + key, "LoadDescendants"); + } + }); + loadDescendantsMenu.setToggleGroup(clickGroup); + + RadioMenuItem nothingMenu = new RadioMenuItem(message("DoNothing")); + nothingMenu.setSelected(currentClick == null || "DoNothing".equals(currentClick)); + nothingMenu.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + UserConfig.setString(baseName + key, "DoNothing"); + } + }); + nothingMenu.setToggleGroup(clickGroup); + + RadioMenuItem clickPopMenu = new RadioMenuItem(message("ContextMenu"), StyleTools.getIconImageView("iconMenu.png")); + clickPopMenu.setSelected("PopMenu".equals(currentClick)); + clickPopMenu.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + UserConfig.setString(baseName + key, "PopMenu"); + } + }); + clickPopMenu.setToggleGroup(clickGroup); + + menu.getItems().addAll(loadChildrenMenu, loadDescendantsMenu, clickPopMenu, nothingMenu); + + return menu; + } + + @FXML + public void showPopMenu(TreeItem item) { + if (item == null) { + return; + } + List items = new ArrayList<>(); + + MenuItem menu = new MenuItem(StringTools.menuPrefix(label(item))); + menu.setStyle("-fx-text-fill: #2e598a;"); + items.add(menu); + items.add(new SeparatorMenuItem()); + + Menu dataMenu = new Menu(message("Data"), StyleTools.getIconImageView("iconData.png")); + dataMenu.getItems().addAll(dataMenuItems(item)); + items.add(dataMenu); + + Menu treeMenu = new Menu(message("View"), StyleTools.getIconImageView("iconView.png")); + treeMenu.getItems().addAll(viewMenuItems(item)); + items.add(treeMenu); + + items.add(new SeparatorMenuItem()); + + items.addAll(operationsMenuItems(item)); + + popNodeMenu(treeView, items); + } + + @Override + public void nodeAdded(TreeNode parent, TreeNode newNode) { + manager.nodeAdded(parent, newNode); + } + + @Override + protected void viewNode(TreeItem item) { + popNode(item); + } + + protected void deleteNode(TreeItem targetItem) { + if (targetItem == null) { + popError(message("SelectToHandle")); + return; + } + TreeNode node = targetItem.getValue(); + if (node == null) { + popError(message("SelectToHandle")); + return; + } + boolean isRoot = isRoot(node); + if (isRoot) { + if (!PopTools.askSure(getTitle(), message("Delete"), message("SureDeleteAll"))) { + return; + } + } else { + String chainName = chainName(targetItem); + if (!PopTools.askSure(getTitle(), chainName, message("Delete"))) { + return; + } + } + if (task != null) { + task.cancel(); + } + task = new FxSingletonTask(this) { + + private TreeItem rootItem; + + @Override + protected boolean handle() { + try (Connection conn = DerbyBase.getConnection()) { + if (isRoot) { + tableTree.deleteChildren(conn, node.getNodeid()); + TreeNode rootNode = root(conn); + rootItem = new TreeItem(rootNode); + } else { + tableTree.deleteData(conn, node); + } + } catch (Exception e) { + error = e.toString(); + return false; + } + return true; + } + + @Override + protected void whenSucceeded() { + if (isRoot) { + setRoot(rootItem); + } else { + targetItem.getChildren().clear(); + if (targetItem.getParent() != null) { + targetItem.getParent().getChildren().remove(targetItem); + } + } + popSuccessful(); + manager.nodeDeleted(node); + } + + }; + start(task, treeView); + } + + protected void renameNode(TreeItem item) { + if (item == null) { + popError(message("SelectToHandle")); + return; + } + TreeNode nodeValue = item.getValue(); + if (nodeValue == null || isRoot(nodeValue)) { + popError(message("SelectToHandle")); + return; + } + String chainName = chainName(item); + String name = PopTools.askValue(getBaseTitle(), chainName, message("RenameNode"), nodeValue.getTitle() + "m"); + if (name == null || name.isBlank()) { + return; + } + if (name.contains(TitleSeparater)) { + popError(message("NameShouldNotInclude") + " \"" + TitleSeparater + "\""); + return; + } + if (task != null) { + task.cancel(); + } + task = new FxSingletonTask(this) { + private TreeNode updatedNode; + + @Override + protected boolean handle() { + nodeValue.setTitle(name); + updatedNode = tableTree.updateData(nodeValue); + return updatedNode != null; + } + + @Override + protected void whenSucceeded() { + item.setValue(updatedNode); + treeView.refresh(); + manager.nodeRenamed(updatedNode); + popSuccessful(); + } + }; + start(task, treeView); + } + + protected void copyNode(TreeItem item) { + if (item == null || isRoot(item.getValue())) { + return; + } + String chainName = chainName(item); + InfoTreeNodeCopyController controller + = (InfoTreeNodeCopyController) childStage(Fxmls.InfoTreeNodeCopyFxml); + controller.setParameters(manager, item.getValue(), chainName); + } + + protected void moveNode(TreeItem item) { + if (item == null || isRoot(item.getValue())) { + return; + } + String chainName = chainName(item); + InfoTreeNodeMoveController controller = (InfoTreeNodeMoveController) childStage(Fxmls.InfoTreeNodeMoveFxml); + controller.setParameters(manager, item.getValue(), chainName); + } + + protected void nodeMoved(TreeNode parent, TreeNode node) { + manager.nodeMoved(parent, node); + } + + protected void editNode(TreeItem item) { + if (item == null) { + return; + } + manager.editNode(item.getValue()); + } + + protected void pasteNode(TreeItem item) { + if (item == null) { + return; + } + manager.pasteNode(item.getValue()); + } + + protected void executeNode(TreeItem item) { + if (item == null) { + return; + } + manager.executeNode(item.getValue()); + } + + protected void exportNode(TreeItem item) { + InfoTreeNodeExportController exportController + = (InfoTreeNodeExportController) childStage(Fxmls.InfoTreeNodeExportFxml); + exportController.setParamters(infoController, item); + } + + @FXML + protected void importAction() { + InfoTreeNodeImportController controller + = (InfoTreeNodeImportController) childStage(Fxmls.InfoTreeNodeImportFxml); + controller.setCaller(manager); + } + + @FXML + protected void importExamples() { + InfoTreeNodeImportController controller + = (InfoTreeNodeImportController) childStage(Fxmls.InfoTreeNodeImportFxml); + controller.setCaller(infoController); + controller.importExamples(); + } + + @FXML + public void infoTree() { + infoTree(selected()); + } + + public void infoTree(TreeItem node) { + if (node == null) { + return; + } + TreeNode nodeValue = node.getValue(); + if (nodeValue == null) { + return; + } + FxTask infoTask = new FxTask(this) { + private File file; + + @Override + protected boolean handle() { + file = FileTmpTools.generateFile(message(category), "htm"); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file, Charset.forName("utf-8"), false))) { + writer.write(HtmlWriteTools.htmlPrefix(chainName(node), "utf-8", HtmlStyles.TableStyle)); + // https://www.jb51.net/article/116957.htm + writer.write("\n"); + writer.write(" \n\n"); + writer.write("
\n
\n" + + " " + + message("Unfold") + "\n" + + " " + + message("HierarchyNumber") + "\n" + + " " + + message("Tags") + "\n" + + " " + + message("Values") + "\n" + + "
\n
\n"); + try (Connection conn = DerbyBase.getConnection()) { + treeView(this, writer, conn, nodeValue, 4, ""); + } catch (Exception e) { + error = e.toString(); + return false; + } +// writer.write("\n
\n* " +// + message("HtmlEditableComments") + "

\n"); + writer.write("\n\n"); + writer.flush(); + return true; + } catch (Exception e) { + error = e.toString(); + return false; + } + } + + @Override + protected void whenSucceeded() { + WebBrowserController.openFile(file); + } + }; + start(infoTask, false); + } + + protected void treeView(FxTask infoTask, BufferedWriter writer, Connection conn, + TreeNode node, int indent, String serialNumber) { + try { + if (conn == null || node == null) { + return; + } + List children = tableTree.children(conn, node.getNodeid()); + String indentNode = " ".repeat(indent); + String spaceNode = " ".repeat(indent); + String nodePageid = "item" + node.getNodeid(); + String nodeName = node.getTitle(); + String displayName = "" + serialNumber + "  " + nodeName; + if (children != null && !children.isEmpty()) { + displayName = "" + displayName + ""; + } + writer.write(indentNode + "
" + spaceNode + + displayName + "\n"); + List tags = tableTreeTag.nodeTags(conn, node.getNodeid()); + if (tags != null && !tags.isEmpty()) { + String indentTag = " ".repeat(indent + 8); + String spaceTag = " ".repeat(2); + writer.write(indentTag + "\n"); + for (TreeNodeTag nodeTag : tags) { + if (infoTask != null && !infoTask.isWorking()) { + return; + } + Color color = nodeTag.getTag().getColor(); + if (color == null) { + color = FxColorTools.randomColor(); + } + writer.write(indentTag + spaceTag + + "" + nodeTag.getTag().getTag() + "\n"); + } + writer.write(indentTag + "\n"); + } + writer.write(indentNode + "
\n"); + String infoDisplay = TreeNode.infoHtml(infoTask, myController, category, node.getInfo(), true, true); + if (infoDisplay != null && !infoDisplay.isBlank()) { + writer.write(indentNode + "
" + + "
" + + "
\n"); + writer.write(indentNode + infoDisplay + "\n"); + writer.write(indentNode + "
\n"); + } + if (children != null && !children.isEmpty()) { + writer.write(indentNode + "
\n"); + for (int i = 0; i < children.size(); i++) { + if (infoTask != null && !infoTask.isWorking()) { + return; + } + TreeNode child = children.get(i); + String ps = serialNumber == null || serialNumber.isBlank() ? "" : serialNumber + "."; + treeView(infoTask, writer, conn, child, indent + 4, ps + (i + 1)); + } + writer.write(indentNode + "
\n"); + } + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + @FXML + @Override + public void cancelAction() { + + } + +} diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeNodeAttributes.java b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeNodeAttributes.java new file mode 100644 index 000000000..32cebc053 --- /dev/null +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeNodeAttributes.java @@ -0,0 +1,185 @@ +package mara.mybox.controller; + +import java.sql.Connection; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import mara.mybox.db.DerbyBase; +import mara.mybox.db.data.TreeNode; +import mara.mybox.db.table.BaseTable; +import mara.mybox.db.table.TableTree; +import mara.mybox.dev.MyBoxLog; +import mara.mybox.fxml.FxTask; +import mara.mybox.tools.DateTools; +import static mara.mybox.value.Languages.message; + +/** + * @Author Mara + * @CreateDate 2022-3-11 + * @License Apache License Version 2.0 + */ +public class ControlDataTreeNodeAttributes extends BaseController { + + protected DataTreeManageController manager; + protected BaseDataTreeNodeController editor; + protected TableTree tableTree; + protected FxTask tagsTask; + protected BaseTable dataTable; + protected TreeNode parentNode, currentNode; + + @FXML + protected TextField idInput, titleInput, timeInput; + @FXML + protected Label chainLabel; + + public ControlDataTreeNodeAttributes() { + } + + @Override + public void initControls() { + try { + super.initControls(); + + titleInput.textProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue v, String ov, String nv) { + attributesChanged(); + } + }); + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + public void setParameters(DataTreeManageController manager) { + try { + this.manager = manager; + this.editor = manager.editor; + tableTree = manager.tableTree; + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + /* + attributes + */ + public void attributesChanged() { + if (isSettingValues || editor == null) { + return; + } + if (editor.attributesTab != null) { + editor.attributesTab.setText(message("Attributes") + "*"); + } + editor.nodeChanged(true); + } + + protected void editNode(TreeNode node) { + currentNode = node; + isSettingValues = true; + if (node != null) { + idInput.setText(node.getNodeid() + ""); + titleInput.setText(node.getTitle()); + timeInput.setText(DateTools.datetimeToString(node.getUpdateTime())); + selectButton.setVisible(node.getNodeid() < 0 || node.getParentid() < 0); + } else { + idInput.setText(message("NewData")); + titleInput.setText(""); + timeInput.setText(""); + selectButton.setVisible(true); + } + isSettingValues = false; + refreshParentNode(); + refreshAction(); + } + + protected void copyNode() { + isSettingValues = true; + parentController.setTitle(parentController.baseTitle + ": " + message("NewData")); + idInput.setText(message("NewData")); + titleInput.appendText(" " + message("Copy")); + currentNode = null; + selectButton.setVisible(true); + isSettingValues = false; + attributesChanged(); + } + + public void renamed(String newName) { + if (titleInput == null) { + return; + } + isSettingValues = true; + titleInput.setText(newName); + isSettingValues = false; + } + + /* + parent + */ + @FXML + public void selectParent() { +// InfoTreeNodeParentController.open(this); + } + + protected void checkParentNode(TreeNode node) { + if (parentNode == null || node.getNodeid() != parentNode.getNodeid()) { + return; + } + refreshParentNode(); + } + + protected void setParentNode(TreeNode node) { + parentNode = node; + refreshParentNode(); + } + + protected void refreshParentNode() { + FxTask updateTask = new FxTask(this) { + private String chainName; + + @Override + protected boolean handle() { + try (Connection conn = DerbyBase.getConnection()) { + if (currentNode != null) { + if (currentNode.getParentid() >= 0) { + parentNode = tableTree.find(conn, currentNode.getParentid()); + } else { + parentNode = tableTree.readData(conn, parentNode); + } + } + if (parentNode == null) { + chainName = ""; + } else { + chainName = manager.treeController.chainName(conn, parentNode); + } + } catch (Exception e) { + error = e.toString(); + return false; + } + return true; + } + + @Override + protected void whenSucceeded() { + chainLabel.setText(chainName); + } + }; + start(updateTask, false); + } + + @Override + public void cleanPane() { + try { + if (tagsTask != null) { + tagsTask.cancel(); + } + } catch (Exception e) { + } + super.cleanPane(); + } + +} diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeNodeTags.java b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeNodeTags.java new file mode 100644 index 000000000..af5b00bb7 --- /dev/null +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeNodeTags.java @@ -0,0 +1,310 @@ +package mara.mybox.controller; + +import java.sql.Connection; +import java.util.Date; +import java.util.List; +import java.util.Random; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.paint.Color; +import javafx.util.Callback; +import javafx.util.converter.DefaultStringConverter; +import mara.mybox.db.DerbyBase; +import mara.mybox.db.data.Tag; +import mara.mybox.db.data.TreeNode; +import mara.mybox.db.table.BaseTable; +import mara.mybox.db.table.TableColor; +import mara.mybox.db.table.TableTag; +import mara.mybox.db.table.TableTree; +import mara.mybox.db.table.TableTreeTag; +import mara.mybox.dev.MyBoxLog; +import mara.mybox.fximage.FxColorTools; +import mara.mybox.fxml.FxTask; +import mara.mybox.fxml.PopTools; +import mara.mybox.fxml.cell.TableAutoCommitCell; +import mara.mybox.fxml.cell.TableColorEditCell; +import static mara.mybox.value.Languages.message; + +/** + * @Author Mara + * @CreateDate 2021-9-23 + * @License Apache License Version 2.0 + */ +public class ControlDataTreeNodeTags extends BaseSysTableController { + + protected BaseDataTreeController dataController; + protected TableTree tableTree; + protected TableTag tableTag; + protected TableTreeTag tableTreeTag; + protected BaseTable dataTable; + protected TreeNode currentNode; + + @FXML + protected TableColumn tagColumn; + @FXML + protected TableColumn colorColumn; + @FXML + protected Button queryTagsButton, deleteTagsButton; + + public ControlDataTreeNodeTags() { + loadInBackground = true; + } + + @Override + public void initColumns() { + try { + super.initColumns(); + + tableView.setEditable(true); + + tagColumn.setEditable(true); + tagColumn.setCellValueFactory(new PropertyValueFactory<>("tag")); + tagColumn.setCellFactory(TableAutoCommitCell.forStringColumn()); + tagColumn.setCellFactory(new Callback, TableCell>() { + @Override + public TableCell call(TableColumn param) { + try { + TableAutoCommitCell cell = new TableAutoCommitCell(new DefaultStringConverter()) { + + @Override + public boolean setCellValue(String value) { + try { + if (value == null || value.isBlank() || !isEditingRow()) { + return false; + } + for (int i = 0; i < tableData.size(); i++) { + String tagName = tableData.get(i).getTag(); + if (value.equals(tagName)) { + cancelEdit(); + return false; + } + } + Tag row = tableData.get(editingRow); + if (row == null) { + cancelEdit(); + return false; + } + row.setTag(value); + saveTag(row); + return super.setCellValue(value); + } catch (Exception e) { + MyBoxLog.debug(e); + return false; + } + } + + }; + return cell; + } catch (Exception e) { + return null; + } + } + }); + tagColumn.getStyleClass().add("editable-column"); + + colorColumn.setEditable(true); + TableColor tableColor = new TableColor(); + colorColumn.setCellValueFactory(new PropertyValueFactory<>("color")); + colorColumn.setCellFactory(new Callback, TableCell>() { + @Override + public TableCell call(TableColumn param) { + TableColorEditCell cell = new TableColorEditCell(myController, tableColor) { + @Override + public void colorChanged(int index, Color color) { + if (isSettingValues || color == null + || index < 0 || index >= tableData.size()) { + return; + } + if (color.equals(tableData.get(index).getColor())) { + return; + } + tableData.get(index).setColor(color); + saveTag(tableData.get(index)); + } + }; + return cell; + } + }); + colorColumn.getStyleClass().add("editable-column"); + + checkButtons(); + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + public void setParameters(BaseDataTreeController controller) { + try { + this.dataController = controller; + this.parentController = dataController; + this.baseName = dataController.baseName; + dataTable = dataController.dataTable; + tableTree = dataController.tableTree; + tableTag = dataController.tableTag; + tableTreeTag = dataController.tableTreeTag; + setTableDefinition(tableTag); + + currentPage = 0; + pageSize = Integer.MAX_VALUE; + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + @Override + public void checkButtons() { + super.checkButtons(); + boolean none = isNoneSelected(); + if (deleteTagsButton != null) { + deleteTagsButton.setDisable(none); + } + if (queryTagsButton != null) { + queryTagsButton.setDisable(tableData == null || tableData.isEmpty()); + } + } + + public String askName() { + String name = PopTools.askValue(getBaseTitle(), + message("Add"), message("Tag"), message("Tag") + new Date().getTime()); + if (name == null || name.isBlank()) { + return null; + } + for (Tag tag : tableData) { + if (name.equals(tag.getTag())) { + popError(message("AlreadyExisted")); + return null; + } + } + return name; + } + + @FXML + public void addTag() { + String name = askName(); + if (name == null || name.isBlank()) { + return; + } + FxTask tagTask = new FxTask(this) { + private Tag tag = null; + + @Override + protected boolean handle() { + try (Connection conn = DerbyBase.getConnection()) { + tag = tableTag.insertData(conn, new Tag(tableTree.getTableName(), name)); + } catch (Exception e) { + error = e.toString(); + return false; + } + return tag != null; + } + + @Override + protected void whenSucceeded() { + tableData.add(0, tag); + popSuccessful(); + tagsChanged(); + } + + }; + start(tagTask, thisPane); + } + + public void saveTag(Tag tag) { + if (isSettingValues) { + return; + } + FxTask saveTask = new FxTask(this) { + + @Override + protected boolean handle() { + return tableTag.writeData(tag) != null; + } + + @Override + protected void whenSucceeded() { + tagsChanged(); + } + + }; + start(saveTask, false); + } + + @FXML + public void queryTags() { + List selected = selectedItems(); + if (selected == null || selected.isEmpty()) { + selected = tableData; + } + if (selected == null || selected.isEmpty()) { + popError(message("SelectToHandle")); + return; + } +// dataController.tableController.queryTags(selected); + } + + @FXML + public void randomColors() { + try { + isSettingValues = true; + Random r = new Random(); + for (int i = 0; i < tableData.size(); i++) { + tableData.get(i).setColor(FxColorTools.randomColor(r)); + } + tableView.refresh(); + isSettingValues = false; + saveAction(); + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + @FXML + @Override + public void saveAction() { + if (isSettingValues) { + return; + } + FxTask saveTask = new FxTask(this) { + + @Override + protected boolean handle() { + return tableTag.updateList(tableData) >= 0; + } + + @Override + protected void whenSucceeded() { + tagsChanged(); + } + + }; + start(saveTask, false); + } + + @Override + public void notifyLoaded() { + super.notifyLoaded(); + tagsChanged(); + } + + @Override + public void tableChanged(boolean changed) { + super.tableChanged(changed); + if (!changed || isSettingValues || isSettingTable) { + return; + } + tagsChanged(); + } + + public void tagsChanged() { + if (isSettingValues) { + return; + } +// dataController.tagsChanged(); + } + +} diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeTable.java b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeTable.java new file mode 100644 index 000000000..6bd8f9b10 --- /dev/null +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeTable.java @@ -0,0 +1,516 @@ +package mara.mybox.controller; + +import java.sql.Connection; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.ActionEvent; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Hyperlink; +import javafx.scene.control.Label; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.control.RadioButton; +import javafx.scene.control.SelectionMode; +import javafx.scene.control.SeparatorMenuItem; +import javafx.scene.control.TableColumn; +import javafx.scene.control.Toggle; +import javafx.scene.control.ToggleGroup; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import mara.mybox.db.DerbyBase; +import mara.mybox.db.data.Tag; +import mara.mybox.db.data.TreeNode; +import mara.mybox.db.table.TableStringValues; +import mara.mybox.db.table.TableTree; +import mara.mybox.dev.MyBoxLog; +import mara.mybox.fxml.FxTask; +import mara.mybox.fxml.cell.TableTextTrimCell; +import mara.mybox.fxml.style.StyleTools; +import mara.mybox.tools.StringTools; +import static mara.mybox.value.Languages.message; +import mara.mybox.value.UserConfig; + +/** + * @Author Mara + * @CreateDate 2022-3-9 + * @License Apache License Version 2.0 + */ +public class ControlDataTreeTable extends BaseSysTableController { + + protected BaseDataTreeController dataController; + protected InfoTreeManageController manager; + protected TableTree tableTree; + protected String queryLabel; + protected TreeNode loadedParent; + + @FXML + protected TableColumn nodeidColumn; + @FXML + protected TableColumn nameColumn, valueColumn; + @FXML + protected TableColumn timeColumn; + @FXML + protected VBox conditionBox; + @FXML + protected ToggleGroup nodesGroup; + @FXML + protected RadioButton childrenRadio, descendantsRadio; + @FXML + protected FlowPane namesPane, nodeGroupPane; + @FXML + protected Label conditionLabel; + @FXML + protected Button operationsButton; + + @Override + public void setTableDefinition() { + + } + + public void setParameters(BaseDataTreeController controller) { + try { + dataController = controller; + baseName = dataController.baseName; + tableTree = dataController.tableTree; + tableDefinition = dataController.tableTree; + + if (dataController instanceof DataTreeManageController) { + manager = (DataTreeManageController) dataController; + } + if (manager == null) { + tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + operationsButton.setVisible(false); + } + + nodeidColumn.setCellValueFactory(new PropertyValueFactory<>("nodeid")); + nameColumn.setText(dataController.nameMsg); + nameColumn.setCellValueFactory(new PropertyValueFactory<>("title")); + valueColumn.setText(dataController.valueMsg); + if (TreeNode.WebFavorite.equals(dataController.category)) { + valueColumn.setCellValueFactory(new PropertyValueFactory<>("icon")); + } else { + valueColumn.setCellValueFactory(new PropertyValueFactory<>("value")); + } + valueColumn.setCellFactory(new TableTextTrimCell()); + timeColumn.setText(dataController.timeMsg); + timeColumn.setCellValueFactory(new PropertyValueFactory<>("updateTime")); + + if (UserConfig.getBoolean(baseName + "AllDescendants", false)) { + descendantsRadio.setSelected(true); + } + nodesGroup.selectedToggleProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue ov, Toggle oldTab, Toggle newTab) { + UserConfig.setBoolean(baseName + "AllDescendants", descendantsRadio.isSelected()); + if (loadedParent != null) { + loadTableData(); + } + } + }); + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + public void clearQuery() { + loadedParent = null; + queryConditions = null; + queryLabel = null; + tableData.clear(); + conditionBox.getChildren().clear(); + namesPane.getChildren().clear(); + startRowOfCurrentPage = 0; + } + + public void loadNodes(TreeNode parentNode) { + clearQuery(); + loadedParent = parentNode; + if (loadedParent != null) { + queryConditions = " category='" + dataController.category + "' AND " + + "parentid=" + loadedParent.getNodeid() + " AND nodeid<>parentid"; + loadTableData(); + } + dataController.showNodesList(true); + } + + public void loadChildren(TreeNode parentNode) { + childrenRadio.setSelected(true); + loadNodes(parentNode); + } + + public void loadDescendants(TreeNode parentNode) { + descendantsRadio.setSelected(true); + loadNodes(parentNode); + } + + @Override + public void postLoadedTableData() { + super.postLoadedTableData(); + if (loadedParent != null) { + tableData.add(0, loadedParent); + } + makeConditionPane(); + } + + public void makeConditionPane() { + conditionBox.getChildren().clear(); + if (loadedParent == null) { + if (queryConditionsString != null) { + conditionLabel.setText(queryConditionsString.length() > 300 + ? queryConditionsString.substring(0, 300) : queryConditionsString); + conditionBox.getChildren().add(conditionLabel); + } + conditionBox.applyCss(); + return; + } + FxTask loadTask = new FxTask(this) { + private List ancestor; + + @Override + protected boolean handle() { + ancestor = tableTree.ancestor(loadedParent.getNodeid()); + return true; + } + + @Override + protected void whenSucceeded() { + List nodes = new ArrayList<>(); + if (ancestor != null) { + for (TreeNode node : ancestor) { + Hyperlink link = new Hyperlink(node.getTitle()); + link.setWrapText(true); + link.setMinHeight(Region.USE_PREF_SIZE); + link.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + loadNodes(node); + } + }); + nodes.add(link); + nodes.add(new Label(">")); + } + } + Label label = new Label(loadedParent.getTitle()); + label.setWrapText(true); + label.setMinHeight(Region.USE_PREF_SIZE); + nodes.add(label); + namesPane.getChildren().setAll(nodes); + conditionBox.getChildren().setAll(namesPane, nodeGroupPane); + conditionBox.applyCss(); + } + }; + start(loadTask, false); + } + + @Override + public long readDataSize(FxTask currentTask, Connection conn) { + if (loadedParent != null) { + if (descendantsRadio.isSelected()) { + return tableTree.decentantsSize(conn, loadedParent.getNodeid()) + 1; + } else { + return tableTree.conditionSize(conn, queryConditions) + 1; + } + + } else if (queryConditions != null) { + return tableTree.conditionSize(conn, queryConditions); + + } else { + return 0; + } + + } + + @Override + public List readPageData(FxTask currentTask, Connection conn) { + if (loadedParent != null && descendantsRadio.isSelected()) { + return tableTree.decentants(conn, loadedParent.getNodeid(), startRowOfCurrentPage, pageSize); + + } else if (queryConditions != null) { + return tableTree.queryConditions(conn, queryConditions, orderColumns, startRowOfCurrentPage, pageSize); + + } else { + return null; + } + } + + @Override + public void itemClicked() { + if (manager == null) { + viewAction(); + } + } + + @Override + public void itemDoubleClicked() { + if (manager != null) { + editAction(); + } + } + + @FXML + @Override + public void viewAction() { + TreeNode item = selectedItem(); + if (item == null) { + popError(message("SelectToHanlde")); + return; + } + if (dataController instanceof ControlInfoTreeHandler) { + ((ControlInfoTreeHandler) dataController).viewNode(item); + } else { + dataController.popNode(item); + } + + } + + @Override + protected long clearData(FxTask currentTask) { + if (queryConditions != null) { + return tableTree.deleteCondition(queryConditions); + + } else { + return -1; + } + } + + @Override + protected void afterDeletion() { + super.afterDeletion(); + if (manager != null) { + manager.nodesDeleted(); + } + } + + @Override + protected void afterClear() { + super.afterClear(); + if (manager != null) { + manager.nodesDeleted(); + } + } + + @Override + public List viewMenuItems(Event fevent) { + try { + List items = new ArrayList<>(); + MenuItem menu; + boolean selected = !isNoneSelected(); + + if (selected) { + menu = new MenuItem(message("View"), StyleTools.getIconImageView("iconView.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + viewAction(); + }); + items.add(menu); + } + + menu = new MenuItem(message("Refresh"), StyleTools.getIconImageView("iconRefresh.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + refreshAction(); + }); + items.add(menu); + + items.addAll(super.makeTableContextMenu()); + + return items; + + } catch (Exception e) { + MyBoxLog.error(e); + return null; + } + } + + @Override + public List operationsMenuItems(Event fevent) { + try { + if (manager == null) { + return null; + } + List items = new ArrayList<>(); + MenuItem menu; + boolean selected = !isNoneSelected(); + + menu = new MenuItem(message("Add"), StyleTools.getIconImageView("iconAdd.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + addAction(); + }); + items.add(menu); + + if (selected) { + menu = new MenuItem(message("Edit"), StyleTools.getIconImageView("iconEdit.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + editAction(); + }); + items.add(menu); + + menu = new MenuItem(message("Paste"), StyleTools.getIconImageView("iconPaste.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + manager.pasteAction(); + }); + items.add(menu); + + menu = new MenuItem(message("Move"), StyleTools.getIconImageView("iconMove.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + manager.moveAction(); + }); + items.add(menu); + + menu = new MenuItem(message("Copy"), StyleTools.getIconImageView("iconCopy.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + manager.copyAction(); + }); + items.add(menu); + + menu = new MenuItem(message("Delete"), StyleTools.getIconImageView("iconDelete.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + deleteAction(); + }); + items.add(menu); + } + + menu = new MenuItem(message("Clear"), StyleTools.getIconImageView("iconClear.png")); + menu.setOnAction((ActionEvent menuItemEvent) -> { + clearAction(); + }); + items.add(menu); + + return items; + + } catch (Exception e) { + MyBoxLog.error(e); + return null; + } + } + + @Override + protected List makeTableContextMenu() { + List items = viewMenuItems(null); + List opItems = operationsMenuItems(null); + if (opItems != null && !opItems.isEmpty()) { + Menu m = new Menu(message("View"), StyleTools.getIconImageView("iconView.png")); + m.getItems().addAll(items); + items.clear(); + items.addAll(opItems); + items.add(new SeparatorMenuItem()); + items.add(m); + } + return items; + } + + @FXML + @Override + public void addAction() { + if (manager == null) { + return; + } + if (!manager.checkBeforeNextAction()) { + return; + } + if (loadedParent != null) { + manager.editor.attributesController.parentNode = loadedParent; + } + manager.addNode(); + } + + @FXML + @Override + public void editAction() { + if (manager == null) { + return; + } + manager.editNode(selectedItem()); + } + + @FXML + @Override + public void pasteAction() { + if (manager == null) { + return; + } + manager.pasteNode(selectedItem()); + } + + public void queryTimes(String value, String title) { + if (value == null) { + popError(message("MissTime")); + return; + } + clearQuery(); + queryConditions = " category='" + dataController.category + "' " + (value.isBlank() ? "" : (" AND " + value)); + queryConditionsString = title; + loadTableData(); + + dataController.showNodesList(true); + } + + public void queryTags(List tags) { + if (tags == null || tags.isEmpty()) { + popError(message("SelectToHandle")); + return; + } + clearQuery(); + queryConditions = " category='" + dataController.category + "' AND " + + tableTree.tagsCondition(tags); + queryConditionsString = message("Tag") + ": "; + for (Tag tag : tags) { + queryConditionsString += " " + tag.getTag(); + } + loadTableData(); + dataController.showNodesList(true); + } + + public void find(String s, boolean isName) { + if (s == null || s.isBlank()) { + popError(message("InvalidParameters") + ": " + message("Find")); + return; + } + String[] values = StringTools.splitBySpace(s); + if (values == null || values.length == 0) { + popError(message("InvalidParameters") + ": " + message("Find")); + return; + } + TableStringValues.add(baseName + dataController.category + "Histories", s); + clearQuery(); + if (isName) { + queryConditions = null; + queryConditionsString = message("Title") + ":"; + for (String v : values) { + if (queryConditions != null) { + queryConditions += " OR "; + } else { + queryConditions = " "; + } + queryConditions += " ( title like '%" + DerbyBase.stringValue(v) + "%' ) "; + queryConditionsString += " " + v; + } + + } else { + queryConditions = null; + queryConditionsString = message("Contents") + ":"; + for (String v : values) { + if (queryConditions != null) { + queryConditions += " OR "; + } else { + queryConditions = " "; + } + queryConditions += " ( info like '%" + DerbyBase.stringValue(v) + "%' ) "; + queryConditionsString += " " + v; + } + } + queryConditions = " category='" + dataController.category + "' AND " + queryConditions; + loadTableData(); + + dataController.showNodesList(true); + } + +} diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeView.java b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeView.java index 9540aa6f8..1d4714adb 100644 --- a/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeView.java +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/ControlDataTreeView.java @@ -4,13 +4,10 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; -import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; -import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.control.Button; -import javafx.scene.control.CheckBox; import javafx.scene.control.Label; import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; @@ -21,6 +18,7 @@ import javafx.scene.input.MouseEvent; import mara.mybox.db.DerbyBase; import mara.mybox.db.data.TreeNode; +import static mara.mybox.db.data.TreeNode.TitleSeparater; import mara.mybox.db.table.BaseTable; import mara.mybox.db.table.TableTree; import mara.mybox.db.table.TableTreeTag; @@ -55,8 +53,6 @@ public class ControlDataTreeView extends BaseTreeTableViewController { @FXML protected Label titleLabel; @FXML - protected CheckBox nodesListCheck; - @FXML protected Button helpButton; @@ -111,23 +107,10 @@ public void setParameters(BaseDataTreeController parent) { dataController = parent; tableTree = parent.tableTree; tableTreeTag = parent.tableTreeTag; - category = infoController.category; + dataTable = dataController.dataTable; parentController = parent; - baseName = parent.baseName + "_" + category; - baseTitle = category; - - infoController.showNodesList(false); - if (nodesListCheck != null) { - nodesListCheck.selectedProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue ov, Boolean oldValue, Boolean newValue) { - if (isSettingValues) { - return; - } - infoController.showNodesList(nodesListCheck.isSelected()); - } - }); - } + baseName = dataTable.getTableName(); + baseTitle = baseName; loadTree(); } @@ -157,7 +140,7 @@ protected boolean handle() { } rootItem = new TreeItem(rootNode); rootItem.setExpanded(true); - int size = tableTree.categorySize(conn, category); + int size = tableTree.size(conn); if (size < 1) { return true; } @@ -247,9 +230,8 @@ public boolean copyDescendants(Connection conn, TreeNode sourceNode, TreeNode ta for (TreeNode child : children) { TreeNode newNode = TreeNode.create() .setParentid(targetid) - .setCategory(category) - .setTitle(child.getTitle()) - .setInfo(child.getInfo()); + .setDataTable(child.getDataTable()) + .setTitle(child.getTitle()); tableTree.insertData(conn, newNode); copyDescendants(conn, child, newNode); } @@ -274,7 +256,7 @@ public String title(TreeNode node) { @Override public String value(TreeNode node) { - return node == null ? null : node.getInfo(); + return node == null ? null : node.texts(); } @Override @@ -292,11 +274,14 @@ public boolean equalItem(TreeItem item1, TreeItem item2) { @Override public boolean equalNode(TreeNode node1, TreeNode node2) { - return TreeNode.equal(node1, node2); + if (node1 == null || node2 == null) { + return false; + } + return node1.getNodeid() == node2.getNodeid(); } public TreeNode root(Connection conn) { - return tableTree.findAndCreateRoot(conn, category); + return tableTree.findAndCreateRoot(conn); } public boolean isRoot(TreeNode node) { @@ -379,27 +364,26 @@ public List viewMenuItems(TreeItem item) { items.add(new SeparatorMenuItem()); - if (nodesListCheck != null) { - menu = new MenuItem(message("LoadChildren"), StyleTools.getIconImageView("iconList.png")); - menu.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent event) { - listChildren(item); - } - }); - items.add(menu); - - menu = new MenuItem(message("LoadDescendants"), StyleTools.getIconImageView("iconList.png")); - menu.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent event) { - listDescentants(item); - } - }); - items.add(menu); - - } - +// if (nodesListCheck != null) { +// menu = new MenuItem(message("LoadChildren"), StyleTools.getIconImageView("iconList.png")); +// menu.setOnAction(new EventHandler() { +// @Override +// public void handle(ActionEvent event) { +// listChildren(item); +// } +// }); +// items.add(menu); +// +// menu = new MenuItem(message("LoadDescendants"), StyleTools.getIconImageView("iconList.png")); +// menu.setOnAction(new EventHandler() { +// @Override +// public void handle(ActionEvent event) { +// listDescentants(item); +// } +// }); +// items.add(menu); +// +// } menu = new MenuItem(message("Refresh"), StyleTools.getIconImageView("iconRefresh.png")); menu.setOnAction((ActionEvent menuItemEvent) -> { refreshAction(); @@ -473,10 +457,10 @@ protected void whenSucceeded() { } protected void popNode(TreeItem item) { - if (item == null || infoController == null) { + if (item == null || dataController == null) { return; } - infoController.popNode(item.getValue()); + dataController.popNode(item.getValue()); } @Override @@ -563,20 +547,6 @@ public void unfold(Connection conn, TreeItem item, boolean descendants } } - protected void listChildren(TreeItem item) { - if (item == null || infoController == null) { - return; - } - infoController.tableController.loadChildren(item.getValue()); - } - - protected void listDescentants(TreeItem item) { - if (item == null || infoController == null) { - return; - } - infoController.tableController.loadDescendants(item.getValue()); - } - @FXML @Override public void refreshAction() { diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeManageController.java b/alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeManageController.java new file mode 100644 index 000000000..d223eaf5a --- /dev/null +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeManageController.java @@ -0,0 +1,364 @@ +package mara.mybox.controller; + +import java.io.File; +import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.Region; +import javafx.stage.Stage; +import javafx.stage.Window; +import mara.mybox.db.DerbyBase; +import mara.mybox.db.data.InfoNode; +import mara.mybox.dev.MyBoxLog; +import mara.mybox.fxml.FxSingletonTask; +import mara.mybox.fxml.WindowTools; +import mara.mybox.value.Fxmls; +import static mara.mybox.value.Languages.message; + +/** + * @Author Mara + * @CreateDate 2022-3-9 + * @License Apache License Version 2.0 + */ +public class DataTreeManageController extends BaseDataTreeController { + + protected BaseDataTreeNodeController editor; + + @FXML + protected ControlDataTreeManage treeController; + + @Override + public void initValues() { + try { + super.initValues(); + treeView = treeController; + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + @Override + public void initControls() { + try { + super.initControls(); + + treeController.setManager(this); + editor.setManager(this); + + loadData(); + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + @Override + public boolean keyEventsFilter(KeyEvent event) { + if (editor != null) { + if (editor.thisPane.isFocused() || editor.thisPane.isFocusWithin()) { + if (editor.keyEventsFilter(event)) { + return true; + } + } + } + if (super.keyEventsFilter(event)) { + return true; + } + if (editor == null) { + return false; + } + return editor.keyEventsFilter(event); // pass event to editor + } + + /* + synchronize + */ + public void nodeAdded(InfoNode parent, InfoNode newNode) { + if (parent == null || newNode == null) { + return; + } + + } + + public void nodeRenamed(InfoNode node) { + if (node == null) { + return; + } + long id = node.getNodeid(); + + if (editor.attributesController.parentNode != null + && id == editor.attributesController.parentNode.getNodeid()) { + editor.attributesController.setParentNode(node); + } + if (editor.attributesController.currentNode != null + && id == editor.attributesController.currentNode.getNodeid()) { + editor.attributesController.renamed(node.getTitle()); + } + } + + public void nodeDeleted(InfoNode node) { + if (node == null) { + return; + } + long id = node.getNodeid(); + + editor.editNode(null); + } + + public void nodeMoved(InfoNode parent, InfoNode node) { + if (parent == null || node == null) { + return; + } + long id = node.getNodeid(); + + if (editor.attributesController.currentNode != null + && id == editor.attributesController.currentNode.getNodeid()) { + editor.attributesController.setParentNode(parent); + } + if (editor.attributesController.parentNode != null + && id == editor.attributesController.parentNode.getNodeid()) { + editor.attributesController.setParentNode(node); + } + } + + public void nodesMoved(InfoNode parent, List nodes) { + if (parent == null || nodes == null || nodes.isEmpty()) { + return; + } + treeController.loadTree(parent); + } + + public void nodesCopied(InfoNode parent) { + treeController.loadTree(parent); + } + + public void nodesDeleted() { + task = new FxSingletonTask(this) { + + @Override + protected boolean handle() { + try (Connection conn = DerbyBase.getConnection()) { + tableController.loadedParent = tableTreeNode.readData(conn, tableController.loadedParent); + editor.attributesController.currentNode + = tableTreeNode.readData(conn, editor.attributesController.currentNode); + editor.attributesController.parentNode + = tableTreeNode.readData(conn, editor.attributesController.parentNode); + } catch (Exception e) { + error = e.toString(); + return false; + } + return true; + } + + @Override + protected void whenSucceeded() { + editor.editNode(editor.attributesController.currentNode); + treeController.loadTree(tableController.loadedParent); + } + }; + start(task); + } + + public void nodeSaved() { + if (editor.attributesController.currentNode == null) { + return; + } + long id = editor.attributesController.currentNode.getNodeid(); + if (tableController.loadedParent != null && id == tableController.loadedParent.getNodeid()) { + tableController.loadedParent = editor.attributesController.currentNode; + tableController.makeConditionPane(); + } + for (int i = 0; i < tableController.tableData.size(); i++) { + InfoNode tnode = tableController.tableData.get(i); + if (tnode.getNodeid() == id) { + tableController.tableData.set(i, editor.attributesController.currentNode); + break; + } + } + treeController.updateNode(editor.attributesController.currentNode); + editor.nodeChanged(false); + } + + public void newNodeSaved() { + if (editor.attributesController.currentNode == null) { + return; + } + treeController.addNewNode(treeController.find(editor.attributesController.parentNode), + editor.attributesController.currentNode, false); + if (tableController.loadedParent != null + && editor.attributesController.parentNode.getNodeid() == tableController.loadedParent.getNodeid()) { + tableController.loadNodes(editor.attributesController.currentNode); + } + editor.nodeChanged(false); + } + + public void nodeChanged() { + if (isSettingValues) { + return; + } + String currentTitle = getTitle(); + if (editor.nodeChanged.get()) { + if (!currentTitle.endsWith(" *")) { + setTitle(currentTitle + " *"); + } + } else { + if (currentTitle.endsWith(" *")) { + setTitle(currentTitle.substring(0, currentTitle.length() - 2)); + } + } + } + + + /* + tree + */ + public boolean editNode(InfoNode node) { + if (!checkBeforeNextAction()) { + return false; + } + return editor.editNode(node); + } + + @FXML + @Override + public void copyAction() { + InfoTreeNodesCopyController.oneOpen(this); + } + + @FXML + protected void moveAction() { + InfoTreeNodesMoveController.oneOpen(this); + } + + public void pasteNode(InfoNode node) { + editor.pasteNode(node); + } + + public void executeNode(InfoNode node) { + if (node == null) { + return; + } + editNode(node); + if (editor.startButton != null) { + editor.startAction(); + } else if (editor.goButton != null) { + editor.goAction(); + } else if (startButton != null) { + startAction(); + } else if (goButton != null) { + goAction(); + } + } + + + /* + node + */ + @FXML + protected void addNode() { + if (editNode(null)) { + editor.newNodeCreated(); + } + } + + @FXML + protected void copyNode() { + if (!checkBeforeNextAction()) { + return; + } + editor.attributesController.copyNode(); + editor.newNodeCreated(); + } + + @FXML + protected void recoverNode() { + editor.editNode(editor.attributesController.currentNode); + } + + @FXML + @Override + public void saveAction() { + editor.attributesController.saveNode(); + } + + @Override + public void sourceFileChanged(File file) { + editor.sourceFileChanged(file); + } + + public boolean isNodeChanged() { + return editor.nodeChanged.get(); + } + + @Override + public boolean checkBeforeNextAction() { + if (!isNodeChanged()) { + return true; + } else { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setTitle(getMyStage().getTitle()); + alert.setContentText(message("DataChanged")); + alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE); + ButtonType buttonSave = new ButtonType(message("Save")); + ButtonType buttonNotSave = new ButtonType(message("NotSave")); + ButtonType buttonCancel = new ButtonType(message("Cancel")); + alert.getButtonTypes().setAll(buttonSave, buttonNotSave, buttonCancel); + Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + stage.setAlwaysOnTop(true); + stage.toFront(); + + Optional result = alert.showAndWait(); + if (result == null || !result.isPresent()) { + return false; + } + if (result.get() == buttonSave) { + saveAction(); + return false; + } else if (result.get() == buttonNotSave) { + editor.nodeChanged.set(false); + return true; + } else { + return false; + } + } + } + + /* + Tags + */ + @Override + public void tagsChanged() { + editor.attributesController.synchronizeTags(); + } + + /* + static methods + */ + public static DataTreeManageController oneOpen() { + DataTreeManageController controller = null; + List windows = new ArrayList<>(); + windows.addAll(Window.getWindows()); + for (Window window : windows) { + Object object = window.getUserData(); + if (object != null && object instanceof DataTreeManageController) { + try { + controller = (WebFavoritesController) object; + break; + } catch (Exception e) { + } + } + } + if (controller == null) { + controller = (DataTreeManageController) WindowTools.openStage(Fxmls.InfoTreeManageFxml); + } + controller.requestMouse(); + return controller; + } + +} diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeNodeEditor.java b/alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeNodeEditor.java new file mode 100644 index 000000000..c6be4b084 --- /dev/null +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeNodeEditor.java @@ -0,0 +1,316 @@ +package mara.mybox.controller; + +import java.io.File; +import java.nio.charset.Charset; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.event.Event; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; +import javafx.scene.control.Tab; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextInputControl; +import mara.mybox.db.data.InfoNode; +import static mara.mybox.db.data.InfoNode.TitleSeparater; +import mara.mybox.db.data.VisitHistory; +import mara.mybox.dev.MyBoxLog; +import mara.mybox.fxml.FxSingletonTask; +import mara.mybox.fxml.FxTask; +import mara.mybox.fxml.PopTools; +import mara.mybox.tools.DateTools; +import mara.mybox.tools.TextFileTools; +import static mara.mybox.value.Languages.message; +import mara.mybox.value.UserConfig; + +/** + * @Author Mara + * @CreateDate 2022-3-11 + * @License Apache License Version 2.0 + */ +public class DataTreeNodeEditor extends BaseController { + + protected DataTreeManageController manager; + protected String defaultExt; + protected final SimpleBooleanProperty nodeChanged; + + @FXML + protected Tab attributesTab, valueTab; + @FXML + protected ControlInfoNodeAttributes attributesController; + @FXML + protected TextInputControl valueInput, moreInput; + @FXML + protected Label valueLabel; + @FXML + protected CheckBox wrapCheck; + + public DataTreeNodeEditor() { + defaultExt = "txt"; + nodeChanged = new SimpleBooleanProperty(false); + } + + @Override + public void setFileType() { + setFileType(VisitHistory.FileType.Text); + } + + @Override + public void initControls() { + try { + super.initControls(); + + if (valueInput != null) { + valueInput.textProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue v, String ov, String nv) { + valueChanged(true); + } + }); + } + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + public void setManager(InfoTreeManageController treeController) { + try { + this.manager = treeController; + attributesController.setParameters(manager); + + if (valueLabel != null) { + valueLabel.setText(manager.valueMsg); + } + + if (wrapCheck != null && (valueInput instanceof TextArea)) { + wrapCheck.setSelected(UserConfig.getBoolean(manager.category + "ValueWrap", false)); + wrapCheck.selectedProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue ov, Boolean oldValue, Boolean newValue) { + UserConfig.setBoolean(treeController.category + "ValueWrap", newValue); + ((TextArea) valueInput).setWrapText(newValue); + } + }); + ((TextArea) valueInput).setWrapText(wrapCheck.isSelected()); + } + + } catch (Exception e) { + MyBoxLog.error(e); + } + } + + protected boolean editNode(InfoNode node) { + updateEditorTitle(node); + attributesController.editNode(node); + editValue(node); + showEditorPane(); + nodeChanged(false); + return true; + } + + protected void updateEditorTitle(InfoNode node) { + if (node != null) { + manager.setTitle(manager.baseTitle + ": " + + node.getNodeid() + " - " + node.getTitle()); + } else { + manager.setTitle(manager.baseTitle); + } + } + + protected void editValue(InfoNode node) { + if (valueInput == null) { + return; + } + isSettingValues = true; + if (node != null) { + valueInput.setText(node.getInfo()); + } else { + valueInput.setText(""); + } + isSettingValues = false; + } + + public InfoNode pickNodeData() { + String title = nodeTitle(); + if (title == null || title.isBlank()) { + return null; + } + InfoNode node = InfoNode.create() + .setCategory(manager.category) + .setTitle(title); + return pickValue(node); + } + + protected InfoNode pickValue(InfoNode node) { + if (node == null) { + return null; + } + String info = null; + if (valueInput != null) { + info = valueInput.getText(); + } + return node.setInfo(info); + } + + protected String nodeTitle() { + String title = attributesController.nameInput.getText(); + if (title == null || title.isBlank()) { + popError(message("InvalidParameters") + ": " + manager.nameMsg); + if (tabPane != null && attributesTab != null) { + tabPane.getSelectionModel().select(attributesTab); + } + return null; + } + if (title.contains(TitleSeparater)) { + popError(message("NameShouldNotInclude") + " \"" + TitleSeparater + "\""); + return null; + } + return title; + } + + protected void showEditorPane() { + manager.showRightPane(); + } + + public void valueChanged(boolean changed) { + if (isSettingValues) { + return; + } + if (valueTab != null) { + valueTab.setText(manager.valueMsg + (changed ? "*" : "")); + } + if (changed) { + nodeChanged(changed); + } + } + + public void nodeChanged(boolean changed) { + if (isSettingValues) { + return; + } + nodeChanged.set(changed); + if (!changed) { + if (valueTab != null) { + valueTab.setText(manager.valueMsg); + } + if (attributesTab != null) { + attributesTab.setText(message("Attributes")); + } + } + } + + public void newNodeCreated() { + popInformation(message("InputNewNode")); + if (tabPane != null && attributesTab != null) { + tabPane.getSelectionModel().select(attributesTab); + } + } + + public boolean isNewNode() { + return attributesController.currentNode == null; + } + + @FXML + @Override + public void saveAsAction() { + if (valueInput == null) { + return; + } + String codes = valueInput.getText(); + if (codes == null || codes.isBlank()) { + popError(message("NoData")); + return; + } + File file = chooseSaveFile(message(manager.category) + "-" + DateTools.nowFileString() + "." + defaultExt); + if (file == null) { + return; + } + FxTask saveAsTask = new FxTask(this) { + + @Override + protected boolean handle() { + File tfile = TextFileTools.writeFile(file, codes, Charset.forName("UTF-8")); + return tfile != null && tfile.exists(); + } + + @Override + protected void whenSucceeded() { + popInformation(message("Saved")); + recordFileWritten(file); + } + + }; + start(saveAsTask, false); + } + + @FXML + public void clearValue() { + if (valueInput != null) { + valueInput.clear(); + } + } + + @Override + public void sourceFileChanged(File file) { + if (valueInput == null + || file == null || !file.exists() + || !manager.checkBeforeNextAction()) { + return; + } + editNode(null); + if (task != null) { + task.cancel(); + } + valueInput.clear(); + task = new FxSingletonTask(this) { + + String codes; + + @Override + protected boolean handle() { + codes = TextFileTools.readTexts(this, file); + return codes != null; + } + + @Override + protected void whenSucceeded() { + valueInput.setText(codes); + recordFileOpened(file); + } + + }; + start(task, thisPane); + } + + public void pasteNode(InfoNode node) { + if (valueInput == null || node == null) { + return; + } + String v = InfoNode.majorInfo(node); + if (v == null || v.isBlank()) { + return; + } + valueInput.replaceText(valueInput.getSelection(), v); + valueInput.requestFocus(); + tabPane.getSelectionModel().select(valueTab); + } + + protected String editorName() { + return manager.category; + } + + @FXML + protected void popHistories(Event event) { + if (UserConfig.getBoolean(editorName() + "HistoriesPopWhenMouseHovering", false)) { + showHistories(event); + } + } + + @FXML + protected void showHistories(Event event) { + PopTools.popStringValues(this, valueInput, event, editorName() + "Histories", false); + } + +} diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeNodeParentController.java b/alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeNodeParentController.java new file mode 100644 index 000000000..990788da5 --- /dev/null +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/DataTreeNodeParentController.java @@ -0,0 +1,55 @@ +package mara.mybox.controller; + +import javafx.fxml.FXML; +import mara.mybox.db.data.InfoNode; +import mara.mybox.fxml.WindowTools; +import mara.mybox.value.Fxmls; +import static mara.mybox.value.Languages.message; + +/** + * @Author Mara + * @CreateDate 2022-3-14 + * @License Apache License Version 2.0 + */ +public class DataTreeNodeParentController extends BaseInfoTreeHandleController { + + protected ControlInfoNodeAttributes attributesController; + + public DataTreeNodeParentController() { + baseTitle = message("SelectNodeAsParent"); + } + + public void setParameters(ControlInfoNodeAttributes nodeController) { + attributesController = nodeController; + manager = nodeController.manager; + setParameters(manager); + } + + @FXML + @Override + public void okAction() { + if (manager == null || !manager.getMyStage().isShowing()) { + close(); + return; + } + InfoNode targetNode = handlerController.selectedNode; + if (targetNode == null) { + popError(message("SelectNodeMoveInto")); + return; + } + attributesController.setParentNode(targetNode); + close(); + } + + /* + static methods + */ + public static DataTreeNodeParentController open(ControlInfoNodeAttributes nodeController) { + DataTreeNodeParentController controller = (DataTreeNodeParentController) WindowTools.childStage( + nodeController, Fxmls.InfoTreeNodeParentFxml); + controller.setParameters(nodeController); + controller.requestMouse(); + return controller; + } + +} diff --git a/alpha/MyBox/src/main/java/mara/mybox/controller/NoteEditor.java b/alpha/MyBox/src/main/java/mara/mybox/controller/NoteEditor.java index 583e7149a..213a09407 100644 --- a/alpha/MyBox/src/main/java/mara/mybox/controller/NoteEditor.java +++ b/alpha/MyBox/src/main/java/mara/mybox/controller/NoteEditor.java @@ -10,7 +10,7 @@ * @CreateDate 2021-8-11 * @License Apache License Version 2.0 */ -public class NoteEditor extends InfoTreeNodeEditor { +public class NoteEditor extends BaseDataTreeNodeController { @FXML protected ControlNoteEditor valueController; @@ -21,6 +21,7 @@ public void initControls() { super.initControls(); valueController.setParameters(this); + valuesEditor = valueController; } catch (Exception e) { MyBoxLog.error(e); } diff --git a/alpha/MyBox/src/main/java/mara/mybox/db/data/TreeNode.java b/alpha/MyBox/src/main/java/mara/mybox/db/data/TreeNode.java index 4ef314838..1be84dad4 100644 --- a/alpha/MyBox/src/main/java/mara/mybox/db/data/TreeNode.java +++ b/alpha/MyBox/src/main/java/mara/mybox/db/data/TreeNode.java @@ -1,6 +1,7 @@ package mara.mybox.db.data; import java.util.Date; +import mara.mybox.db.table.BaseTable; import mara.mybox.dev.MyBoxLog; /** @@ -20,14 +21,15 @@ public class TreeNode extends BaseData { public static final String MoreSeparater = "MyBoxTreeNodeMore:"; public static final String Root = "Root"; + protected BaseTable dataTable; protected long nodeid, parentid; - protected String category, title; + protected String title; protected Date updateTime; private void init() { + dataTable = null; nodeid = -1; parentid = -2; - category = null; title = null; updateTime = new Date(); } @@ -39,14 +41,14 @@ public TreeNode() { public TreeNode(TreeNode parent, String title) { init(); this.parentid = parent.getNodeid(); - this.category = parent.getCategory(); + this.dataTable = parent.getDataTable(); this.title = title; } public TreeNode copyIn(TreeNode parent) { TreeNode node = new TreeNode(); node.setParentid(parent.getNodeid()); - node.setCategory(parent.getCategory()); + node.setDataTable(parent.getDataTable()); node.setTitle(title); return node; } @@ -64,14 +66,11 @@ public boolean setNodeValue(String column, Object value) { case "nodeid": nodeid = value == null ? -1 : (long) value; return true; - case "parentid": - parentid = value == null ? -1 : (long) value; - return true; case "title": title = value == null ? null : (String) value; return true; - case "category": - category = value == null ? null : (String) value; + case "parentid": + parentid = value == null ? -1 : (long) value; return true; case "update_time": updateTime = value == null ? null : (Date) value; @@ -90,12 +89,10 @@ public Object getNodeValue(String column) { switch (column) { case "nodeid": return nodeid; - case "parentid": - return parentid; case "title": return title; - case "category": - return category; + case "parentid": + return parentid; case "update_time": return updateTime; } @@ -104,11 +101,18 @@ public Object getNodeValue(String column) { @Override public boolean valid() { - return category != null - && title != null && !title.isBlank() + return title != null && !title.isBlank() && !title.contains(TitleSeparater); } + public String texts() { + return title; + } + + public String html() { + return title; + } + /* Static methods */ @@ -119,6 +123,15 @@ public static TreeNode create() { /* get/set */ + public BaseTable getDataTable() { + return dataTable; + } + + public TreeNode setDataTable(BaseTable dataTable) { + this.dataTable = dataTable; + return this; + } + public long getNodeid() { return nodeid; } @@ -146,15 +159,6 @@ public TreeNode setTitle(String title) { return this; } - public String getCategory() { - return category; - } - - public TreeNode setCategory(String category) { - this.category = category; - return this; - } - public Date getUpdateTime() { return updateTime; } diff --git a/alpha/MyBox/src/main/java/mara/mybox/db/table/TableTree.java b/alpha/MyBox/src/main/java/mara/mybox/db/table/TableTree.java index ecbb13829..95d967d52 100644 --- a/alpha/MyBox/src/main/java/mara/mybox/db/table/TableTree.java +++ b/alpha/MyBox/src/main/java/mara/mybox/db/table/TableTree.java @@ -36,9 +36,7 @@ public TableTree(BaseTable data) { public final TableTree defineColumns() { addColumn(new ColumnDefinition("nodeid", ColumnType.Long, true, true).setAuto(true)); - addColumn(new ColumnDefinition("category", ColumnType.String, true).setLength(StringMaxLength)); addColumn(new ColumnDefinition("title", ColumnType.String, true).setLength(StringMaxLength)); - addColumn(new ColumnDefinition("info", ColumnType.Clob)); addColumn(new ColumnDefinition("update_time", ColumnType.Datetime)); addColumn(new ColumnDefinition("parentid", ColumnType.Long) .setReferName("Tree_Node_parent_fk").setReferTable("Tree_Node").setReferColumn("nodeid") @@ -47,47 +45,8 @@ public final TableTree defineColumns() { return this; } - public static final String Create_Parent_Index - = "CREATE INDEX Tree_Node_parent_index on Tree_Node ( parentid )"; - - public static final String Create_Title_Index - = "CREATE INDEX Tree_Node_title_index on Tree_Node ( parentid, title )"; - - public static final String QueryID - = "SELECT * FROM Tree_Node WHERE nodeid=?"; - - public static final String QueryRoot - = "SELECT * FROM Tree_Node WHERE category=? AND nodeid=parentid ORDER BY nodeid ASC"; - - public static final String QueryChildren - = "SELECT * FROM Tree_Node WHERE parentid=? AND nodeid<>parentid ORDER BY nodeid ASC"; - - public static final String QueryLastChild - = "SELECT * FROM Tree_Node WHERE parentid=? AND title=? AND nodeid<>parentid ORDER BY nodeid DESC FETCH FIRST ROW ONLY"; - - public static final String DeleteID - = "DELETE FROM Tree_Node WHERE nodeid=?"; - - public static final String ChildrenCount - = "SELECT count(nodeid) FROM Tree_Node WHERE parentid=? AND nodeid<>parentid"; - - public static final String ChildrenEmpty - = "SELECT nodeid FROM Tree_Node WHERE parentid=? AND nodeid<>parentid FETCH FIRST ROW ONLY"; - - public static final String CategoryCount - = "SELECT count(nodeid) FROM Tree_Node WHERE category=? AND nodeid<>parentid"; - - public static final String CategoryEmpty - = "SELECT nodeid FROM Tree_Node WHERE category=? AND nodeid<>parentid FETCH FIRST ROW ONLY"; - - public static final String DeleteParent - = "DELETE FROM Tree_Node WHERE parentid=?"; - - public static final String DeleteChildren - = "DELETE FROM Tree_Node WHERE parentid=? AND nodeid<>parentid"; - public boolean createTable(Connection conn, boolean dropExisted) { - if (conn == null) { + if (conn == null || tableName == null) { return false; } try { @@ -99,6 +58,7 @@ public boolean createTable(Connection conn, boolean dropExisted) { conn.commit(); } createTable(conn); + createIndices(conn); return true; } catch (Exception e) { MyBoxLog.debug(e); @@ -106,6 +66,27 @@ public boolean createTable(Connection conn, boolean dropExisted) { } } + public boolean createIndices(Connection conn) { + if (conn == null || tableName == null) { + return false; + } + String sql = "CREATE INDEX " + tableName + "_parent_index on " + tableName + " ( parentid )"; + try (PreparedStatement statement = conn.prepareStatement(sql)) { + statement.executeUpdate(); + } catch (Exception e) { + MyBoxLog.debug(e); + return false; + } + sql = "CREATE INDEX " + tableName + "_title_index on " + tableName + " ( parentid, title )"; + try (PreparedStatement statement = conn.prepareStatement(sql)) { + statement.executeUpdate(); + } catch (Exception e) { + MyBoxLog.debug(e); + return false; + } + return true; + } + public TreeNode find(long id) { if (id < 0) { return null; @@ -122,7 +103,8 @@ public TreeNode find(Connection conn, long id) { if (conn == null || id < 0) { return null; } - try (PreparedStatement statement = conn.prepareStatement(QueryID)) { + String sql = "SELECT * FROM " + tableName + " WHERE nodeid=?"; + try (PreparedStatement statement = conn.prepareStatement(sql)) { statement.setLong(1, id); return query(conn, statement); } catch (Exception e) { @@ -131,21 +113,21 @@ public TreeNode find(Connection conn, long id) { } } - public List findRoots(String category) { + public List findRoots() { try (Connection conn = DerbyBase.getConnection()) { - return findRoots(conn, category); + return findRoots(conn); } catch (Exception e) { MyBoxLog.debug(e); return null; } } - public List findRoots(Connection conn, String category) { - if (conn == null || category == null) { + public List findRoots(Connection conn) { + if (conn == null) { return null; } - try (PreparedStatement statement = conn.prepareStatement(QueryRoot)) { - statement.setString(1, category); + String sql = "SELECT * FROM " + tableName + " WHERE nodeid=parentid ORDER BY nodeid ASC"; + try (PreparedStatement statement = conn.prepareStatement(sql)) { return query(statement); } catch (Exception e) { MyBoxLog.debug(e); @@ -169,7 +151,8 @@ public List children(Connection conn, long parent) { if (conn == null || parent < 0) { return null; } - try (PreparedStatement statement = conn.prepareStatement(QueryChildren)) { + String sql = "SELECT * FROM " + tableName + " WHERE parentid=? AND nodeid<>parentid ORDER BY nodeid ASC"; + try (PreparedStatement statement = conn.prepareStatement(sql)) { statement.setLong(1, parent); return query(statement); } catch (Exception e) { @@ -227,7 +210,9 @@ public TreeNode find(Connection conn, long parent, String title) { if (conn == null || title == null || title.isBlank()) { return null; } - try (PreparedStatement statement = conn.prepareStatement(QueryLastChild)) { + String sql = "SELECT * FROM " + tableName + " WHERE parentid=? AND title=? AND nodeid<>parentid " + + "ORDER BY nodeid DESC FETCH FIRST ROW ONLY"; + try (PreparedStatement statement = conn.prepareStatement(sql)) { statement.setLong(1, parent); statement.setString(2, title); return query(conn, statement); @@ -268,14 +253,14 @@ public TreeNode findAndCreate(Connection conn, long parent, String title) { } } - public TreeNode checkBase(Connection conn) { + public TreeNode findAndCreateRoot(Connection conn) { TreeNode base = find(conn, 1); if (base == null) { try { - String sql = "INSERT INTO Tree_Node (nodeid,title,parentid,category) VALUES(1,'base',1, 'Root')"; + String sql = "INSERT INTO " + tableName + " (nodeid,title,parentid) VALUES(1,'Root',1)"; update(conn, sql); conn.commit(); - sql = "ALTER TABLE Tree_Node ALTER COLUMN nodeid RESTART WITH 2"; + sql = "ALTER TABLE " + tableName + " ALTER COLUMN nodeid RESTART WITH 2"; update(conn, sql); conn.commit(); base = find(conn, 1); @@ -286,69 +271,17 @@ public TreeNode checkBase(Connection conn) { return base; } - public TreeNode findAndCreateRoot(String category) { - try (Connection conn = DerbyBase.getConnection()) { - return findAndCreateRoot(conn, category); - } catch (Exception e) { - MyBoxLog.debug(e); - return null; - } - } - - public TreeNode findAndCreateRoot(Connection conn, String category) { - List roots = findAndCreateRoots(conn, category); - if (roots != null && !roots.isEmpty()) { - TreeNode root = roots.get(0); - root.setTitle(message(category)); - return root; - } else { - return null; - } - } - - public List findAndCreateRoots(Connection conn, String category) { - if (conn == null) { - return null; - } - List roots = findRoots(conn, category); - if (roots == null || roots.isEmpty()) { - try { - conn.setAutoCommit(true); - TreeNode base = checkBase(conn); - if (base == null) { - return null; - } - TreeNode root = TreeNode.create().setCategory(category) - .setTitle(message(category)).setParentid(base.getNodeid()); - root = insertData(conn, root); - if (root == null) { - return null; - } - root.setParentid(root.getNodeid()); - root = updateData(conn, root); - if (root == null) { - return null; - } - roots = new ArrayList<>(); - roots.add(root); - } catch (Exception e) { -// MyBoxLog.debug(e); - } - } - return roots; - } - - public TreeNode findAndCreateChain(Connection conn, TreeNode categoryRoot, String ownerChain) { - if (conn == null || categoryRoot == null || ownerChain == null || ownerChain.isBlank()) { + public TreeNode findAndCreateChain(Connection conn, TreeNode root, String ownerChain) { + if (conn == null || root == null || ownerChain == null || ownerChain.isBlank()) { return null; } try { - long parentid = categoryRoot.getNodeid(); + long parentid = root.getNodeid(); String chain = ownerChain; - if (chain.startsWith(categoryRoot.getTitle() + TitleSeparater)) { - chain = chain.substring((categoryRoot.getTitle() + TitleSeparater).length()); - } else if (chain.startsWith(message(categoryRoot.getTitle()) + TitleSeparater)) { - chain = chain.substring((message(categoryRoot.getTitle()) + TitleSeparater).length()); + if (chain.startsWith(root.getTitle() + TitleSeparater)) { + chain = chain.substring((root.getTitle() + TitleSeparater).length()); + } else if (chain.startsWith(message(root.getTitle()) + TitleSeparater)) { + chain = chain.substring((message(root.getTitle()) + TitleSeparater).length()); } String[] nodes = chain.split(TitleSeparater); TreeNode owner = null; @@ -383,7 +316,8 @@ public List decentants(Connection conn, long parentid) { public List decentants(Connection conn, long parentid, long start, long size) { List children = new ArrayList<>(); - try (PreparedStatement query = conn.prepareStatement(QueryChildren)) { + String sql = "SELECT * FROM " + tableName + " WHERE parentid=? AND nodeid<>parentid ORDER BY nodeid ASC"; + try (PreparedStatement query = conn.prepareStatement(sql)) { decentants(conn, query, parentid, start, size, children, 0); } catch (Exception e) { MyBoxLog.debug(e); @@ -443,7 +377,8 @@ public int decentantsSize(Connection conn, long parentid) { return 0; } int count = 0; - try (PreparedStatement sizeQuery = conn.prepareStatement(ChildrenCount)) { + String sql = "SELECT count(nodeid) FROM " + tableName + " WHERE parentid=? AND nodeid<>parentid"; + try (PreparedStatement sizeQuery = conn.prepareStatement(sql)) { count = decentantsSize(conn, sizeQuery, parentid); } catch (Exception e) { MyBoxLog.debug(e); @@ -508,7 +443,8 @@ public int childrenSize(Connection conn, long parent) { return 0; } int size = 0; - try (PreparedStatement sizeQuery = conn.prepareStatement(ChildrenCount)) { + String sql = "SELECT count(nodeid) FROM " + tableName + " WHERE parentid=? AND nodeid<>parentid"; + try (PreparedStatement sizeQuery = conn.prepareStatement(sql)) { size = childrenSize(sizeQuery, parent); } catch (Exception e) { MyBoxLog.debug(e); @@ -518,7 +454,8 @@ public int childrenSize(Connection conn, long parent) { public boolean childrenEmpty(Connection conn, long parent) { boolean isEmpty = true; - try (PreparedStatement statement = conn.prepareStatement(ChildrenEmpty)) { + String sql = "SELECT nodeid FROM " + tableName + " WHERE parentid=? AND nodeid<>parentid FETCH FIRST ROW ONLY"; + try (PreparedStatement statement = conn.prepareStatement(sql)) { statement.setLong(1, parent); conn.setAutoCommit(true); try (ResultSet results = statement.executeQuery()) { @@ -556,55 +493,6 @@ public TreeNode parent(Connection conn, TreeNode node) { return find(conn, node.getParentid()); } - public int categorySize(String category) { - try (Connection conn = DerbyBase.getConnection()) { - return categorySize(conn, category); - } catch (Exception e) { - MyBoxLog.debug(e); - return -1; - } - } - - public int categorySize(Connection conn, String category) { - if (conn == null) { - return 0; - } - int size = 0; - try (PreparedStatement statement = conn.prepareStatement(CategoryCount)) { - statement.setString(1, category); - conn.setAutoCommit(true); - try (ResultSet results = statement.executeQuery()) { - if (results != null && results.next()) { - size = results.getInt(1); - } - } catch (Exception e) { - MyBoxLog.debug(e); - } - } catch (Exception e) { - MyBoxLog.debug(e); - } - return size; - } - - public boolean categoryEmpty(Connection conn, String category) { - if (conn == null) { - return true; - } - boolean isEmpty = true; - try (PreparedStatement statement = conn.prepareStatement(CategoryEmpty)) { - statement.setString(1, category); - conn.setAutoCommit(true); - try (ResultSet results = statement.executeQuery()) { - isEmpty = results == null || !results.next(); - } catch (Exception e) { - MyBoxLog.debug(e); - } - } catch (Exception e) { - MyBoxLog.debug(e); - } - return isEmpty; - } - public int deleteChildren(long parent) { try (Connection conn = DerbyBase.getConnection()) { return deleteChildren(conn, parent); @@ -615,7 +503,8 @@ public int deleteChildren(long parent) { } public int deleteChildren(Connection conn, long parent) { - try (PreparedStatement statement = conn.prepareStatement(DeleteChildren)) { + String sql = "DELETE FROM " + tableName + " WHERE parentid=? AND nodeid<>parentid"; + try (PreparedStatement statement = conn.prepareStatement(sql)) { statement.setLong(1, parent); return statement.executeUpdate(); } catch (Exception e) { diff --git a/alpha/MyBox/src/main/resources/fxml/ControlDataTreeManage.fxml b/alpha/MyBox/src/main/resources/fxml/ControlDataTreeManage.fxml new file mode 100644 index 000000000..7e7e8306f --- /dev/null +++ b/alpha/MyBox/src/main/resources/fxml/ControlDataTreeManage.fxml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/alpha/MyBox/src/main/resources/fxml/ControlDataTreeNodeAttributes.fxml b/alpha/MyBox/src/main/resources/fxml/ControlDataTreeNodeAttributes.fxml new file mode 100644 index 000000000..11ed7dff7 --- /dev/null +++ b/alpha/MyBox/src/main/resources/fxml/ControlDataTreeNodeAttributes.fxml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/alpha/MyBox/src/main/resources/fxml/ControlDataTreeNodeTags.fxml b/alpha/MyBox/src/main/resources/fxml/ControlDataTreeNodeTags.fxml new file mode 100644 index 000000000..15f447544 --- /dev/null +++ b/alpha/MyBox/src/main/resources/fxml/ControlDataTreeNodeTags.fxml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/alpha/MyBox/src/main/resources/fxml/ControlDataTreeView.fxml b/alpha/MyBox/src/main/resources/fxml/ControlDataTreeView.fxml new file mode 100644 index 000000000..4c264c8c1 --- /dev/null +++ b/alpha/MyBox/src/main/resources/fxml/ControlDataTreeView.fxml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/alpha/MyBox/src/main/resources/fxml/NoteEditor.fxml b/alpha/MyBox/src/main/resources/fxml/NoteEditor.fxml index 3ce27e620..769b57afd 100644 --- a/alpha/MyBox/src/main/resources/fxml/NoteEditor.fxml +++ b/alpha/MyBox/src/main/resources/fxml/NoteEditor.fxml @@ -11,7 +11,7 @@ License: Apache License Version 2.0 - + @@ -34,11 +34,23 @@ License: Apache License Version 2.0 - + + + + + + + + + + + + + diff --git a/alpha/MyBox/src/main/resources/fxml/NotesQuery.fxml b/alpha/MyBox/src/main/resources/fxml/NotesQuery.fxml new file mode 100644 index 000000000..af0eb8eb0 --- /dev/null +++ b/alpha/MyBox/src/main/resources/fxml/NotesQuery.fxml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
diff --git a/alpha/MyBox/src/main/resources/fxml/NotesTree.fxml b/alpha/MyBox/src/main/resources/fxml/NotesTree.fxml new file mode 100644 index 000000000..8dd5c4719 --- /dev/null +++ b/alpha/MyBox/src/main/resources/fxml/NotesTree.fxml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +