From aaa907479e1a44a26f44d795ad07a6649b15a6b3 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 01:08:19 -0500 Subject: [PATCH 01/20] created FileBrowser Panel and TopComponent --- .../uielements/panels/FileBrowserPanel.java | 230 ++++++++++++++++++ .../core/control/FileBrowserTopComponent.java | 76 ++++++ 2 files changed, 306 insertions(+) create mode 100644 ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java create mode 100644 ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java new file mode 100644 index 0000000000..914023dd08 --- /dev/null +++ b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java @@ -0,0 +1,230 @@ +/* + Copyright 2016-2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UGS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UGS. If not, see . + */ +package com.willwinder.universalgcodesender.uielements.panels; + +import com.willwinder.universalgcodesender.listeners.UGSEventListener; +import com.willwinder.universalgcodesender.model.BackendAPI; +import com.willwinder.universalgcodesender.model.UGSEvent; +import com.willwinder.universalgcodesender.utils.GUIHelpers; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeWillExpandListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; +import java.awt.BorderLayout; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; + +/** + * Displays a list of files and directories in a given directory. + * + * @author andrewmurraydavid + */ +public final class FileBrowserPanel extends JPanel implements UGSEventListener { + private final transient BackendAPI backend; + private JTree fileTree; + private DefaultTreeModel treeModel; + private File currentFile; + + private JTextField currentPathField; + private JButton goButton; + private JCheckBox showHiddenCheckBox; + + public FileBrowserPanel(BackendAPI backend) { + this.backend = backend; + setLayout(new BorderLayout()); + + JPanel northPanel = new JPanel(new BorderLayout()); + currentPathField = new JTextField(); + northPanel.add(currentPathField, BorderLayout.CENTER); + + goButton = new JButton("Go"); + northPanel.add(goButton, BorderLayout.EAST); + + showHiddenCheckBox = new JCheckBox("Show Hidden", false); + northPanel.add(showHiddenCheckBox, BorderLayout.SOUTH); + + add(northPanel, BorderLayout.NORTH); + + File initialDirectory = new File(System.getProperty("user.home")); + + DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(new FileNode(initialDirectory)); + treeModel = new DefaultTreeModel(rootNode); + fileTree = new JTree(treeModel); + + fileTree.setRootVisible(true); + fileTree.setShowsRootHandles(true); + JScrollPane treeScroll = new JScrollPane(fileTree); + add(treeScroll, BorderLayout.CENTER); + + setDirectory(backend != null ? + new File(backend.getSettings().getLastWorkingDirectory()) : + initialDirectory + ); + + fileTree.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + TreePath path = fileTree.getPathForLocation(e.getX(), e.getY()); + if (path != null) { + DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent(); + FileNode fileNode = (FileNode) selectedNode.getUserObject(); + if (fileNode.displayName.equals("..")) { + DefaultMutableTreeNode upperNode = (DefaultMutableTreeNode) selectedNode.getParent(); + File upperPath = ((FileNode) upperNode.getUserObject()).getFile(); + File parentFile = upperPath.getParentFile(); + setDirectory(parentFile); + } else if (fileNode.getFile().isDirectory()) { + setDirectory(fileNode.getFile()); + } else { + File gcodeFile = fileNode.getFile(); + GUIHelpers.openGcodeFile(gcodeFile, backend); + } + } + } + } + }); + + fileTree.addTreeWillExpandListener(new TreeWillExpandListener() { + @Override + public void treeWillExpand(TreeExpansionEvent event) { + TreePath path = event.getPath(); + DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent(); + FileNode fileNode = (FileNode) node.getUserObject(); + + if (fileNode.isDirectory()) { + node.removeAllChildren(); + createChildren(node, fileNode.getFile(), showHiddenCheckBox.isSelected()); + ((DefaultTreeModel) fileTree.getModel()).nodeStructureChanged(node); + } + } + + @Override + public void treeWillCollapse(TreeExpansionEvent event) { + // No need to handle collapse events in this context + } + }); + + ActionListener goActionListener = e -> changeDirectory(currentPathField.getText()); + goButton.addActionListener(goActionListener); + currentPathField.addActionListener(goActionListener); + + showHiddenCheckBox.addItemListener(e -> { + boolean showHidden = e.getStateChange() == ItemEvent.SELECTED; + refreshFileList(showHidden); + }); + } + + public void setDirectory(File directory) { + currentFile = directory; + currentPathField.setText(directory.getAbsolutePath()); + refreshFileList(showHiddenCheckBox.isSelected()); + backend.getSettings().setLastWorkingDirectory(directory.getAbsolutePath()); + } + + private void refreshFileList(boolean showHidden) { + DefaultMutableTreeNode newRootNode = new DefaultMutableTreeNode(new FileNode(currentFile)); + if (currentFile.getParentFile() != null) { + newRootNode.add(new DefaultMutableTreeNode(new FileNode(null, ".."))); + } + createChildren(newRootNode, currentFile, showHidden); + + DefaultTreeModel model = (DefaultTreeModel) fileTree.getModel(); + model.setRoot(newRootNode); + model.reload(); + + currentPathField.setText(currentFile.getAbsolutePath()); + } + + + private void changeDirectory(String path) { + File newDirectory = new File(path); + if (newDirectory.exists() && newDirectory.isDirectory()) { + setDirectory(newDirectory); + } else { + JOptionPane.showMessageDialog(this, "Directory does not exist: " + path, "Error", JOptionPane.ERROR_MESSAGE); + } + } + + private void createChildren(DefaultMutableTreeNode node, File file, boolean showHidden) { + if (file == null) { + return; + } + + File[] files = file.listFiles(); + if (files != null) { + for (File child : files) { + if (!showHidden && (child.isHidden() || child.getName().startsWith(".") || child.getName().startsWith("$"))) { + continue; + } + DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(new FileNode(child)); + node.add(childNode); + if (child.isDirectory()) { + childNode.add(new DefaultMutableTreeNode(new FileNode(null, "Loading..."))); + } + } + } + } + + + @Override + public void UGSEvent(UGSEvent evt) { + // React to events as needed + } + + private static class FileNode { + private final File file; + private final String displayName; + + public FileNode(File file) { + this.file = file; + this.displayName = file.getName().isEmpty() ? file.getPath() : file.getName(); + } + + public FileNode(File file, String displayName) { + this.file = file; + this.displayName = displayName; + } + + public boolean isDirectory() { + return file.isDirectory(); + } + + public File getFile() { + return file; + } + + @Override + public String toString() { + return displayName; + } + } +} diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java new file mode 100644 index 0000000000..5b6d2a974c --- /dev/null +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java @@ -0,0 +1,76 @@ +/* + Copyright 2016-2024 Will Winder + + This file is part of Universal Gcode Sender (UGS). + + UGS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + UGS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with UGS. If not, see . + */ +package com.willwinder.ugs.nbp.core.control; + +import com.willwinder.ugs.nbp.lib.Mode; +import com.willwinder.ugs.nbp.lib.lookup.CentralLookup; +import com.willwinder.ugs.nbp.lib.services.LocalizingService; +import com.willwinder.universalgcodesender.model.BackendAPI; +import com.willwinder.universalgcodesender.uielements.panels.FileBrowserPanel; + +import java.awt.BorderLayout; + +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.windows.TopComponent; + + +/** + * Top component which displays something. + */ +@TopComponent.Description( + preferredID = "FileBrowserTopComponent", + //iconBase="SET/PATH/TO/ICON/HERE", + persistenceType = TopComponent.PERSISTENCE_ALWAYS +) +@TopComponent.Registration(mode = Mode.LEFT_TOP, openAtStartup = true) +@ActionID(category = LocalizingService.FileBrowserPanelCategory, id = LocalizingService.FileBrowserPanelActionId) +@ActionReference(path = LocalizingService.FileBrowserPanelWindowPath) +@TopComponent.OpenActionRegistration( + displayName = "", + preferredID = "FileBrowserTopComponent" +) +public final class FileBrowserTopComponent extends TopComponent { + + public FileBrowserTopComponent() { + this.setLayout(new BorderLayout()); + BackendAPI backend = CentralLookup.getDefault().lookup(BackendAPI.class); + this.add(new FileBrowserPanel(backend), BorderLayout.CENTER); + } + + @Override + public void componentOpened() { + setName(LocalizingService.FileBrowserPanelTitle); + setToolTipText(LocalizingService.FileBrowserPanelTooltip); + } + + @Override + public void componentClosed() { + // TODO add custom code on component closing + } + + public void writeProperties(java.util.Properties p) { + // better to version settings since initial version as advocated at + // http://wiki.apidesign.org/wiki/PropertyFiles + p.setProperty("version", "1.0"); + } + + public void readProperties(java.util.Properties p) { + } +} From ec686eae8a9d1a3f7e7a97610e1b6e7bf9e002e3 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 01:09:02 -0500 Subject: [PATCH 02/20] added localization strings for FileBrowserPanel --- ugs-core/src/resources/MessagesBundle_en_US.properties | 2 ++ .../ugs/nbp/lib/services/LocalizingService.java | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ugs-core/src/resources/MessagesBundle_en_US.properties b/ugs-core/src/resources/MessagesBundle_en_US.properties index e56f274826..75924e014a 100644 --- a/ugs-core/src/resources/MessagesBundle_en_US.properties +++ b/ugs-core/src/resources/MessagesBundle_en_US.properties @@ -315,6 +315,8 @@ platform.window.serialconsole = Console platform.window.serialconsole.tooltip = Console displaying messages to and from the controller. platform.window.visualizer = Visualizer platform.window.visualizer.tooltip = 3D view of the current operation. +platform.window.fileBrowser = File Browser +platform.window.fileBrowser.tooltip = Load a folder to view and work with files. platform.visualizer.edit.options.title = Visualizer options platform.visualizer.color.background = Background Color platform.visualizer.tool = Show tool location diff --git a/ugs-platform/ugs-platform-ugslib/src/main/java/com/willwinder/ugs/nbp/lib/services/LocalizingService.java b/ugs-platform/ugs-platform-ugslib/src/main/java/com/willwinder/ugs/nbp/lib/services/LocalizingService.java index 34927fef89..c5d991cbd4 100644 --- a/ugs-platform/ugs-platform-ugslib/src/main/java/com/willwinder/ugs/nbp/lib/services/LocalizingService.java +++ b/ugs-platform/ugs-platform-ugslib/src/main/java/com/willwinder/ugs/nbp/lib/services/LocalizingService.java @@ -1,5 +1,5 @@ /* - Copyright 2016-2021 Will Winder + Copyright 2016-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -298,6 +298,12 @@ public class LocalizingService { public final static String DiagnosticsActionId = "com.willwinder.ugs.nbp.core.windows.DiagnosticsTopComponent"; public final static String DiagnosticsCategory = CATEGORY_WINDOW; + public final static String FileBrowserPanelTitle = Localization.getString("platform.window.fileBrowser", lang); + public final static String FileBrowserPanelTooltip = Localization.getString("platform.window.fileBrowser.tooltip", lang); + public final static String FileBrowserPanelActionId = "com.willwinder.ugs.nbp.core.windows.FileBrowserTopComponent"; + public final static String FileBrowserPanelWindowPath = MENU_WINDOW; + public final static String FileBrowserPanelCategory = CATEGORY_WINDOW; + public final static String RunFromTitleKey = "platform.menu.runFrom"; public final static String RunFromTitle = Localization.getString(RunFromTitleKey, lang); public final static String RunFromWindowPath = MENU_PROGRAM; From 58e0183c64e0abf82097fd2ed9aaf7b107950f4a Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 01:09:55 -0500 Subject: [PATCH 03/20] added user setting for last working directory --- .../universalgcodesender/utils/Settings.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java b/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java index d0c4c41c41..1c5710fe21 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/utils/Settings.java @@ -1,5 +1,5 @@ /* - Copyright 2014-2023 Will Winder + Copyright 2014-2024 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -29,8 +29,20 @@ This file is part of Universal Gcode Sender (UGS). import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; import java.util.logging.Logger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.List; + + public class Settings { private static final Logger logger = Logger.getLogger(Settings.class.getName()); @@ -120,6 +132,11 @@ public class Settings { */ private boolean showTranslationsWarning = true; + /** + * The last working directory used by the file browser + */ + private String lastWorkingDirectory = System.getProperty("user.home"); + /** * The GSON deserialization doesn't do anything beyond initialize what's in the json document. Call finalizeInitialization() before using the Settings. */ @@ -556,6 +573,14 @@ public void setShowTranslationsWarning(boolean showTranslationsWarning) { this.showTranslationsWarning = showTranslationsWarning; } + public String getLastWorkingDirectory() { + return lastWorkingDirectory; + } + + public void setLastWorkingDirectory(String lastWorkingDirectory) { + this.lastWorkingDirectory = lastWorkingDirectory; + } + public static class FileStats { public Position minCoordinate; public Position maxCoordinate; From b0655b182322e71ea72b897afc054d6e9d72b38f Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 01:10:31 -0500 Subject: [PATCH 04/20] added FileBrowserPanel to WidgetPreviewer --- .../universalgcodesender/uielements/WidgetPreviewer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/WidgetPreviewer.java b/ugs-core/src/com/willwinder/universalgcodesender/uielements/WidgetPreviewer.java index 070be04e22..faf31bd436 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/uielements/WidgetPreviewer.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/uielements/WidgetPreviewer.java @@ -18,6 +18,7 @@ This file is part of Universal Gcode Sender (UGS). */ package com.willwinder.universalgcodesender.uielements; +import com.willwinder.universalgcodesender.uielements.panels.FileBrowserPanel; import com.willwinder.universalgcodesender.uielements.panels.SendStatusPanel; import com.willwinder.universalgcodesender.uielements.toolbars.*; import com.willwinder.universalgcodesender.uielements.panels.OverridesPanel; @@ -81,6 +82,7 @@ public static void main(String[] args) throws Exception { panel.add(frameLauncherButton("MacroActionPanel", new MacroActionPanel(backend))); panel.add(frameLauncherButton("MacroSettingsPanel", new MacroSettingsPanel(backend))); panel.add(frameLauncherButton("OverridesPanel", new OverridesPanel(backend))); + panel.add(frameLauncherButton("FileBrowser", new FileBrowserPanel(backend))); panel.add(frameLauncherButton("SendStatusLine", new SendStatusLine(backend))); panel.add(frameLauncherButton("SendStatusPanel", new SendStatusPanel(backend))); panel.add(frameLauncherButton("ActionButtonPanel", new ActionButtonPanel(backend))); From 5a8587e23043599453fb21221f030a0e381a782a Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 01:13:03 -0500 Subject: [PATCH 05/20] a bit of cleanup in FileBrowserPanel --- .../uielements/panels/FileBrowserPanel.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java index 914023dd08..8235ed1955 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java @@ -49,13 +49,10 @@ This file is part of Universal Gcode Sender (UGS). */ public final class FileBrowserPanel extends JPanel implements UGSEventListener { private final transient BackendAPI backend; - private JTree fileTree; - private DefaultTreeModel treeModel; + private final JTree fileTree; private File currentFile; - - private JTextField currentPathField; - private JButton goButton; - private JCheckBox showHiddenCheckBox; + private final JTextField currentPathField; + private final JCheckBox showHiddenCheckBox; public FileBrowserPanel(BackendAPI backend) { this.backend = backend; @@ -65,7 +62,7 @@ public FileBrowserPanel(BackendAPI backend) { currentPathField = new JTextField(); northPanel.add(currentPathField, BorderLayout.CENTER); - goButton = new JButton("Go"); + JButton goButton = new JButton("Go"); northPanel.add(goButton, BorderLayout.EAST); showHiddenCheckBox = new JCheckBox("Show Hidden", false); @@ -76,7 +73,7 @@ public FileBrowserPanel(BackendAPI backend) { File initialDirectory = new File(System.getProperty("user.home")); DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(new FileNode(initialDirectory)); - treeModel = new DefaultTreeModel(rootNode); + DefaultTreeModel treeModel = new DefaultTreeModel(rootNode); fileTree = new JTree(treeModel); fileTree.setRootVisible(true); From ada88736d455149548c932ea6c36f9f7ab05c319 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 02:34:27 -0500 Subject: [PATCH 06/20] add key listeners to FileBrowserPanel tree --- .../uielements/panels/FileBrowserPanel.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java index 8235ed1955..06edf04bb7 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java @@ -110,6 +110,37 @@ public void mouseClicked(MouseEvent e) { } }); + fileTree.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + TreePath path = fileTree.getSelectionPath(); // Get the selected path + if (path != null) { + DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent(); + if (selectedNode.getUserObject() instanceof FileNode fileNode) { + if (fileNode.displayName.startsWith("..")) { + DefaultMutableTreeNode upperNode = (DefaultMutableTreeNode) selectedNode.getParent(); + File upperPath = ((FileNode) upperNode.getUserObject()).getFile(); + File parentFile = upperPath.getParentFile(); + setDirectory(parentFile); + } else if (fileNode.getFile().isDirectory()) { + setDirectory(fileNode.getFile()); + } else { + File gcodeFile = fileNode.getFile(); + GUIHelpers.openGcodeFile(gcodeFile, backend); + } + } + } + } else if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { + // Navigate up when backspace is pressed + File parentFile = currentFile.getParentFile(); + if (parentFile != null) { + setDirectory(parentFile); + } + } + } + }); + fileTree.addTreeWillExpandListener(new TreeWillExpandListener() { @Override public void treeWillExpand(TreeExpansionEvent event) { From 35295500c1d01e01b49236fe9744985058f604bf Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 02:35:47 -0500 Subject: [PATCH 07/20] nicer icons --- ugs-core/pom.xml | 6 ++ .../uielements/panels/FileBrowserPanel.java | 70 ++++++++++++++----- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/ugs-core/pom.xml b/ugs-core/pom.xml index bcf77eed90..603d0a8a70 100644 --- a/ugs-core/pom.xml +++ b/ugs-core/pom.xml @@ -17,6 +17,7 @@ release_files + RELEASE180 @@ -119,6 +120,11 @@ nashorn-core ${ugs.nashorn-core.version} + + org.netbeans.api + org-openide-util-ui + ${netbeans.version} + diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java index 06edf04bb7..5938040f2a 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java @@ -23,6 +23,18 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.universalgcodesender.model.UGSEvent; import com.willwinder.universalgcodesender.utils.GUIHelpers; +import java.awt.Component; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.BorderLayout; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import java.io.File; +import org.openide.util.ImageUtilities; + import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JOptionPane; @@ -30,17 +42,15 @@ This file is part of Universal Gcode Sender (UGS). import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTree; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeWillExpandListener; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; -import java.awt.BorderLayout; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.File; + /** * Displays a list of files and directories in a given directory. @@ -70,21 +80,19 @@ public FileBrowserPanel(BackendAPI backend) { add(northPanel, BorderLayout.NORTH); - File initialDirectory = new File(System.getProperty("user.home")); + File initialDirectory = backend != null ? + new File(backend.getSettings().getLastWorkingDirectory()) : + new File(System.getProperty("user.home")); DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(new FileNode(initialDirectory)); DefaultTreeModel treeModel = new DefaultTreeModel(rootNode); fileTree = new JTree(treeModel); - - fileTree.setRootVisible(true); - fileTree.setShowsRootHandles(true); + fileTree.setCellRenderer(new FileTreeCellRenderer()); + fileTree.setRootVisible(false); JScrollPane treeScroll = new JScrollPane(fileTree); add(treeScroll, BorderLayout.CENTER); - setDirectory(backend != null ? - new File(backend.getSettings().getLastWorkingDirectory()) : - initialDirectory - ); + setDirectory(initialDirectory); fileTree.addMouseListener(new MouseAdapter() { @Override @@ -94,7 +102,7 @@ public void mouseClicked(MouseEvent e) { if (path != null) { DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent(); FileNode fileNode = (FileNode) selectedNode.getUserObject(); - if (fileNode.displayName.equals("..")) { + if (fileNode.displayName.startsWith("..")) { DefaultMutableTreeNode upperNode = (DefaultMutableTreeNode) selectedNode.getParent(); File upperPath = ((FileNode) upperNode.getUserObject()).getFile(); File parentFile = upperPath.getParentFile(); @@ -181,7 +189,8 @@ public void setDirectory(File directory) { private void refreshFileList(boolean showHidden) { DefaultMutableTreeNode newRootNode = new DefaultMutableTreeNode(new FileNode(currentFile)); if (currentFile.getParentFile() != null) { - newRootNode.add(new DefaultMutableTreeNode(new FileNode(null, ".."))); + newRootNode.add(new DefaultMutableTreeNode(new FileNode(null, ". (" + currentFile.getName() + ")"))); + newRootNode.add(new DefaultMutableTreeNode(new FileNode(null, ".. (" + currentFile.getParentFile().getName() + ")"))); } createChildren(newRootNode, currentFile, showHidden); @@ -222,7 +231,6 @@ private void createChildren(DefaultMutableTreeNode node, File file, boolean show } } - @Override public void UGSEvent(UGSEvent evt) { // React to events as needed @@ -255,4 +263,32 @@ public String toString() { return displayName; } } + + public static class FileTreeCellRenderer extends DefaultTreeCellRenderer { + + public static final String SMALL_GCODE_ICON = "icons/new.svg"; + public static final String SMALL_FOLDER_ICON = "resources/icons/open.svg"; + public static final String SMALL_PARENT_ICON = "resources/icons/reload.svg"; + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; + if (node.getUserObject() instanceof FileNode fileNode) { + if (fileNode.getFile() == null) { + setIcon(ImageUtilities.loadImageIcon(SMALL_PARENT_ICON, false)); + } else if (fileNode.getFile().isFile()) { + String fileName = fileNode.getFile().getName(); + if (fileName.matches(".*\\.(gcode|GCODE|cnc|CNC|nc|NC|ngc|NGC|tap|TAP|txt|TXT|gc|GC)")) { + setIcon(ImageUtilities.loadImageIcon(SMALL_GCODE_ICON, false)); + } + } else if (fileNode.getFile().isDirectory() && !fileNode.displayName.startsWith("..")) { + setIcon(ImageUtilities.loadImageIcon(SMALL_FOLDER_ICON, false)); + } + } + + return this; + } + } } From c2c7aa770588d988b9223547745cddbc6cb69ed9 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 02:37:12 -0500 Subject: [PATCH 08/20] added ancestor listener to focus tree when panel is visible --- .../uielements/panels/FileBrowserPanel.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java index 5938040f2a..7a3cbac661 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java @@ -177,6 +177,24 @@ public void treeWillCollapse(TreeExpansionEvent event) { boolean showHidden = e.getStateChange() == ItemEvent.SELECTED; refreshFileList(showHidden); }); + + addAncestorListener(new AncestorListener() { + @Override + public void ancestorAdded(AncestorEvent event) { + // Request focus for the JTree when the panel is shown + fileTree.requestFocusInWindow(); + } + + @Override + public void ancestorRemoved(AncestorEvent event) { + } + + @Override + public void ancestorMoved(AncestorEvent event) { + // Handle case when the panel or its ancestor is moved, if necessary + fileTree.requestFocusInWindow(); + } + }); } public void setDirectory(File directory) { From 09c6244167a4149d69ffa1ac813b8888b4342188 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 17:00:35 -0500 Subject: [PATCH 09/20] show root handles --- .../universalgcodesender/uielements/panels/FileBrowserPanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java index 7a3cbac661..ef765f12a7 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java @@ -89,6 +89,7 @@ public FileBrowserPanel(BackendAPI backend) { fileTree = new JTree(treeModel); fileTree.setCellRenderer(new FileTreeCellRenderer()); fileTree.setRootVisible(false); + fileTree.setShowsRootHandles(true); JScrollPane treeScroll = new JScrollPane(fileTree); add(treeScroll, BorderLayout.CENTER); From e9e7ad327b2ff42d141292597b713f6f52e9fac6 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 17:22:23 -0500 Subject: [PATCH 10/20] moved FileBrowserPanel to `ugs-platform-ugscore` --- .../universalgcodesender/uielements/WidgetPreviewer.java | 2 -- .../ugs/nbp/core/control/FileBrowserTopComponent.java | 2 +- .../com/willwinder/ugs/nbp/core}/panels/FileBrowserPanel.java | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) rename {ugs-core/src/com/willwinder/universalgcodesender/uielements => ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core}/panels/FileBrowserPanel.java (99%) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/WidgetPreviewer.java b/ugs-core/src/com/willwinder/universalgcodesender/uielements/WidgetPreviewer.java index faf31bd436..070be04e22 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/uielements/WidgetPreviewer.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/uielements/WidgetPreviewer.java @@ -18,7 +18,6 @@ This file is part of Universal Gcode Sender (UGS). */ package com.willwinder.universalgcodesender.uielements; -import com.willwinder.universalgcodesender.uielements.panels.FileBrowserPanel; import com.willwinder.universalgcodesender.uielements.panels.SendStatusPanel; import com.willwinder.universalgcodesender.uielements.toolbars.*; import com.willwinder.universalgcodesender.uielements.panels.OverridesPanel; @@ -82,7 +81,6 @@ public static void main(String[] args) throws Exception { panel.add(frameLauncherButton("MacroActionPanel", new MacroActionPanel(backend))); panel.add(frameLauncherButton("MacroSettingsPanel", new MacroSettingsPanel(backend))); panel.add(frameLauncherButton("OverridesPanel", new OverridesPanel(backend))); - panel.add(frameLauncherButton("FileBrowser", new FileBrowserPanel(backend))); panel.add(frameLauncherButton("SendStatusLine", new SendStatusLine(backend))); panel.add(frameLauncherButton("SendStatusPanel", new SendStatusPanel(backend))); panel.add(frameLauncherButton("ActionButtonPanel", new ActionButtonPanel(backend))); diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java index 5b6d2a974c..f82f1ad420 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java @@ -22,7 +22,7 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.lib.lookup.CentralLookup; import com.willwinder.ugs.nbp.lib.services.LocalizingService; import com.willwinder.universalgcodesender.model.BackendAPI; -import com.willwinder.universalgcodesender.uielements.panels.FileBrowserPanel; +import com.willwinder.ugs.nbp.core.panels.FileBrowserPanel; import java.awt.BorderLayout; diff --git a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java similarity index 99% rename from ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java rename to ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java index ef765f12a7..85b15a86f1 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/uielements/panels/FileBrowserPanel.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java @@ -16,7 +16,7 @@ This file is part of Universal Gcode Sender (UGS). You should have received a copy of the GNU General Public License along with UGS. If not, see . */ -package com.willwinder.universalgcodesender.uielements.panels; +package com.willwinder.ugs.nbp.core.panels; import com.willwinder.universalgcodesender.listeners.UGSEventListener; import com.willwinder.universalgcodesender.model.BackendAPI; From 4cbe349093714d8b96fe593dd13a7ca8f679e7a9 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 17:26:31 -0500 Subject: [PATCH 11/20] fixed localization issue on FileBrowserTopComponent --- .../core/control/FileBrowserTopComponent.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java index f82f1ad420..9fe921aad8 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java @@ -20,14 +20,21 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.lib.Mode; import com.willwinder.ugs.nbp.lib.lookup.CentralLookup; -import com.willwinder.ugs.nbp.lib.services.LocalizingService; +import com.willwinder.ugs.nbp.lib.services.TopComponentLocalizer; import com.willwinder.universalgcodesender.model.BackendAPI; import com.willwinder.ugs.nbp.core.panels.FileBrowserPanel; +import static com.willwinder.ugs.nbp.lib.services.LocalizingService.FileBrowserPanelCategory; +import static com.willwinder.ugs.nbp.lib.services.LocalizingService.FileBrowserPanelActionId; +import static com.willwinder.ugs.nbp.lib.services.LocalizingService.FileBrowserPanelWindowPath; +import static com.willwinder.ugs.nbp.lib.services.LocalizingService.FileBrowserPanelTitle; +import static com.willwinder.ugs.nbp.lib.services.LocalizingService.FileBrowserPanelTooltip; + import java.awt.BorderLayout; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; +import org.openide.modules.OnStart; import org.openide.windows.TopComponent; @@ -40,8 +47,8 @@ This file is part of Universal Gcode Sender (UGS). persistenceType = TopComponent.PERSISTENCE_ALWAYS ) @TopComponent.Registration(mode = Mode.LEFT_TOP, openAtStartup = true) -@ActionID(category = LocalizingService.FileBrowserPanelCategory, id = LocalizingService.FileBrowserPanelActionId) -@ActionReference(path = LocalizingService.FileBrowserPanelWindowPath) +@ActionID(category = FileBrowserPanelCategory, id = FileBrowserPanelActionId) +@ActionReference(path = FileBrowserPanelWindowPath) @TopComponent.OpenActionRegistration( displayName = "", preferredID = "FileBrowserTopComponent" @@ -56,8 +63,8 @@ public FileBrowserTopComponent() { @Override public void componentOpened() { - setName(LocalizingService.FileBrowserPanelTitle); - setToolTipText(LocalizingService.FileBrowserPanelTooltip); + setName(FileBrowserPanelTitle); + setToolTipText(FileBrowserPanelTooltip); } @Override @@ -73,4 +80,11 @@ public void writeProperties(java.util.Properties p) { public void readProperties(java.util.Properties p) { } + + @OnStart + public static class Localizer extends TopComponentLocalizer { + public Localizer() { + super(FileBrowserPanelCategory, FileBrowserPanelActionId, FileBrowserPanelTitle); + } + } } From ff2588b25acb0b5a6f66ae67c5484825b53cf503 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 17:26:55 -0500 Subject: [PATCH 12/20] fixed file open action on FileBrowserPanel --- .../com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java index 85b15a86f1..e0616bcb92 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java @@ -18,6 +18,7 @@ This file is part of Universal Gcode Sender (UGS). */ package com.willwinder.ugs.nbp.core.panels; +import com.willwinder.ugs.nbp.core.actions.OpenFileAction; import com.willwinder.universalgcodesender.listeners.UGSEventListener; import com.willwinder.universalgcodesender.model.BackendAPI; import com.willwinder.universalgcodesender.model.UGSEvent; @@ -112,7 +113,7 @@ public void mouseClicked(MouseEvent e) { setDirectory(fileNode.getFile()); } else { File gcodeFile = fileNode.getFile(); - GUIHelpers.openGcodeFile(gcodeFile, backend); + new OpenFileAction(gcodeFile).actionPerformed(null); } } } From 12597cda6de8a3ecff7abae48ae5b160b454a1e7 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 21:39:27 -0500 Subject: [PATCH 13/20] fixed icons defaulting to system icons when disabled --- .../ugs/nbp/core/panels/FileBrowserPanel.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java index e0616bcb92..01a21acef0 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java @@ -287,8 +287,11 @@ public String toString() { public static class FileTreeCellRenderer extends DefaultTreeCellRenderer { public static final String SMALL_GCODE_ICON = "icons/new.svg"; + public static final String SMALL_GCODE_DISABLED_ICON = "icons/new_dark.svg"; public static final String SMALL_FOLDER_ICON = "resources/icons/open.svg"; + public static final String SMALL_FOLDER_DISABLED_ICON = "resources/icons/open_dark.svg"; public static final String SMALL_PARENT_ICON = "resources/icons/reload.svg"; + public static final String SMALL_PARENT_DISABLED_ICON = "resources/icons/reload_dark.svg"; @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { @@ -296,18 +299,22 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; if (node.getUserObject() instanceof FileNode fileNode) { - if (fileNode.getFile() == null) { - setIcon(ImageUtilities.loadImageIcon(SMALL_PARENT_ICON, false)); - } else if (fileNode.getFile().isFile()) { + if (fileNode.displayName.startsWith("..")) { + setIcon(ImageUtilities.loadImageIcon(tree.isEnabled() ? SMALL_PARENT_ICON : SMALL_PARENT_DISABLED_ICON, false)); + } else if (fileNode.getFile() != null && fileNode.getFile().isFile()) { String fileName = fileNode.getFile().getName(); if (fileName.matches(".*\\.(gcode|GCODE|cnc|CNC|nc|NC|ngc|NGC|tap|TAP|txt|TXT|gc|GC)")) { - setIcon(ImageUtilities.loadImageIcon(SMALL_GCODE_ICON, false)); + setIcon(ImageUtilities.loadImageIcon(tree.isEnabled() ? SMALL_GCODE_ICON : SMALL_GCODE_DISABLED_ICON, false)); } - } else if (fileNode.getFile().isDirectory() && !fileNode.displayName.startsWith("..")) { - setIcon(ImageUtilities.loadImageIcon(SMALL_FOLDER_ICON, false)); + } else if ((fileNode.getFile() == null || fileNode.getFile().isDirectory()) && !fileNode.displayName.startsWith("..")) { + setIcon(ImageUtilities.loadImageIcon(tree.isEnabled() ? SMALL_FOLDER_ICON : SMALL_FOLDER_DISABLED_ICON, false)); } } + if (!tree.isEnabled()) { + setDisabledIcon(getIcon()); + } + return this; } } From 8adb2fab054f8f314ac5c4ac2919b33667a55bef Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 21:40:15 -0500 Subject: [PATCH 14/20] small cleanup --- .../ugs/nbp/core/panels/FileBrowserPanel.java | 60 +++++++++---------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java index 01a21acef0..8a81158611 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java @@ -64,6 +64,7 @@ public final class FileBrowserPanel extends JPanel implements UGSEventListener { private File currentFile; private final JTextField currentPathField; private final JCheckBox showHiddenCheckBox; + private final JButton goButton; public FileBrowserPanel(BackendAPI backend) { this.backend = backend; @@ -73,7 +74,7 @@ public FileBrowserPanel(BackendAPI backend) { currentPathField = new JTextField(); northPanel.add(currentPathField, BorderLayout.CENTER); - JButton goButton = new JButton("Go"); + goButton = new JButton("Go"); northPanel.add(goButton, BorderLayout.EAST); showHiddenCheckBox = new JCheckBox("Show Hidden", false); @@ -81,9 +82,7 @@ public FileBrowserPanel(BackendAPI backend) { add(northPanel, BorderLayout.NORTH); - File initialDirectory = backend != null ? - new File(backend.getSettings().getLastWorkingDirectory()) : - new File(System.getProperty("user.home")); + File initialDirectory = new File(backend.getSettings().getLastWorkingDirectory()); DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(new FileNode(initialDirectory)); DefaultTreeModel treeModel = new DefaultTreeModel(rootNode); @@ -101,21 +100,7 @@ public FileBrowserPanel(BackendAPI backend) { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { TreePath path = fileTree.getPathForLocation(e.getX(), e.getY()); - if (path != null) { - DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent(); - FileNode fileNode = (FileNode) selectedNode.getUserObject(); - if (fileNode.displayName.startsWith("..")) { - DefaultMutableTreeNode upperNode = (DefaultMutableTreeNode) selectedNode.getParent(); - File upperPath = ((FileNode) upperNode.getUserObject()).getFile(); - File parentFile = upperPath.getParentFile(); - setDirectory(parentFile); - } else if (fileNode.getFile().isDirectory()) { - setDirectory(fileNode.getFile()); - } else { - File gcodeFile = fileNode.getFile(); - new OpenFileAction(gcodeFile).actionPerformed(null); - } - } + openFileFromFileNode(path); } } }); @@ -126,20 +111,7 @@ public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { TreePath path = fileTree.getSelectionPath(); // Get the selected path if (path != null) { - DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent(); - if (selectedNode.getUserObject() instanceof FileNode fileNode) { - if (fileNode.displayName.startsWith("..")) { - DefaultMutableTreeNode upperNode = (DefaultMutableTreeNode) selectedNode.getParent(); - File upperPath = ((FileNode) upperNode.getUserObject()).getFile(); - File parentFile = upperPath.getParentFile(); - setDirectory(parentFile); - } else if (fileNode.getFile().isDirectory()) { - setDirectory(fileNode.getFile()); - } else { - File gcodeFile = fileNode.getFile(); - GUIHelpers.openGcodeFile(gcodeFile, backend); - } - } + openFileFromFileNode(path); } } else if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { // Navigate up when backspace is pressed @@ -199,6 +171,28 @@ public void ancestorMoved(AncestorEvent event) { }); } + private void openFileFromFileNode(TreePath path) { + if (!this.isEnabled()) { + return; + } + + if (path != null) { + DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent(); + FileNode fileNode = (FileNode) selectedNode.getUserObject(); + if (fileNode.displayName.startsWith("..")) { + DefaultMutableTreeNode upperNode = (DefaultMutableTreeNode) selectedNode.getParent(); + File upperPath = ((FileNode) upperNode.getUserObject()).getFile(); + File parentFile = upperPath.getParentFile(); + setDirectory(parentFile); + } else if (fileNode.getFile().isDirectory()) { + setDirectory(fileNode.getFile()); + } else { + File gcodeFile = fileNode.getFile(); + new OpenFileAction(gcodeFile).actionPerformed(null); + } + } + } + public void setDirectory(File directory) { currentFile = directory; currentPathField.setText(directory.getAbsolutePath()); From 1205f8c99132b2060ccb28dbd8a97fd58a52e305 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 21:42:15 -0500 Subject: [PATCH 15/20] disable/enable file tree on certain UGSEvents --- .../core/control/FileBrowserTopComponent.java | 8 ++--- .../ugs/nbp/core/panels/FileBrowserPanel.java | 31 +++++++++++++++++-- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java index 9fe921aad8..0ec3bae205 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java @@ -37,14 +37,11 @@ This file is part of Universal Gcode Sender (UGS). import org.openide.modules.OnStart; import org.openide.windows.TopComponent; - /** * Top component which displays something. */ @TopComponent.Description( - preferredID = "FileBrowserTopComponent", - //iconBase="SET/PATH/TO/ICON/HERE", - persistenceType = TopComponent.PERSISTENCE_ALWAYS + preferredID = "FileBrowserTopComponent" ) @TopComponent.Registration(mode = Mode.LEFT_TOP, openAtStartup = true) @ActionID(category = FileBrowserPanelCategory, id = FileBrowserPanelActionId) @@ -58,7 +55,8 @@ public final class FileBrowserTopComponent extends TopComponent { public FileBrowserTopComponent() { this.setLayout(new BorderLayout()); BackendAPI backend = CentralLookup.getDefault().lookup(BackendAPI.class); - this.add(new FileBrowserPanel(backend), BorderLayout.CENTER); + FileBrowserPanel panel = new FileBrowserPanel(backend); + this.add(panel, BorderLayout.CENTER); } @Override diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java index 8a81158611..b8a52479e5 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java @@ -19,10 +19,12 @@ This file is part of Universal Gcode Sender (UGS). package com.willwinder.ugs.nbp.core.panels; import com.willwinder.ugs.nbp.core.actions.OpenFileAction; +import com.willwinder.universalgcodesender.listeners.ControllerState; import com.willwinder.universalgcodesender.listeners.UGSEventListener; import com.willwinder.universalgcodesender.model.BackendAPI; import com.willwinder.universalgcodesender.model.UGSEvent; -import com.willwinder.universalgcodesender.utils.GUIHelpers; +import com.willwinder.universalgcodesender.model.events.ControllerStateEvent; +import com.willwinder.universalgcodesender.model.events.ControllerStatusEvent; import java.awt.Component; import java.awt.event.KeyAdapter; @@ -34,6 +36,7 @@ This file is part of Universal Gcode Sender (UGS). import java.awt.event.MouseEvent; import java.io.File; + import org.openide.util.ImageUtilities; import javax.swing.JButton; @@ -68,6 +71,7 @@ public final class FileBrowserPanel extends JPanel implements UGSEventListener { public FileBrowserPanel(BackendAPI backend) { this.backend = backend; + backend.addUGSEventListener(this); setLayout(new BorderLayout()); JPanel northPanel = new JPanel(new BorderLayout()); @@ -245,9 +249,32 @@ private void createChildren(DefaultMutableTreeNode node, File file, boolean show } } + private void setPanelEnabled(boolean enabled) { + this.setEnabled(enabled); + goButton.setEnabled(enabled); + fileTree.setEnabled(enabled); + currentPathField.setEnabled(enabled); + showHiddenCheckBox.setEnabled(enabled); + } + + private void setEnabledFromStatus(ControllerState controllerStateEvent) { + switch (controllerStateEvent) { + case DISCONNECTED, IDLE, UNKNOWN: + setPanelEnabled(true); + break; + default: + setPanelEnabled(false); + break; + } + } + @Override public void UGSEvent(UGSEvent evt) { - // React to events as needed + if (evt instanceof ControllerStateEvent controllerStateEvent) { + setEnabledFromStatus(controllerStateEvent.getState()); + } else if (evt instanceof ControllerStatusEvent controllerStatusEvent) { + setEnabledFromStatus(controllerStatusEvent.getStatus().getState()); + } } private static class FileNode { From 98b5ad598a738fdcc9b31917ff6d5f4dfd2a0dfb Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Thu, 8 Feb 2024 21:48:06 -0500 Subject: [PATCH 16/20] removed netbeans dependency from `ugs-core` --- ugs-core/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ugs-core/pom.xml b/ugs-core/pom.xml index 603d0a8a70..bcf77eed90 100644 --- a/ugs-core/pom.xml +++ b/ugs-core/pom.xml @@ -17,7 +17,6 @@ release_files - RELEASE180 @@ -120,11 +119,6 @@ nashorn-core ${ugs.nashorn-core.version} - - org.netbeans.api - org-openide-util-ui - ${netbeans.version} - From 2123874a33efbd5c7483aa584dadb0837b29b1dd Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Mon, 12 Feb 2024 14:40:49 -0500 Subject: [PATCH 17/20] give MachineStatusTopComponent lower position --- .../com/willwinder/ugs/nbp/dro/MachineStatusTopComponent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ugs-platform/ugs-platform-plugin-dro/src/main/java/com/willwinder/ugs/nbp/dro/MachineStatusTopComponent.java b/ugs-platform/ugs-platform-plugin-dro/src/main/java/com/willwinder/ugs/nbp/dro/MachineStatusTopComponent.java index d3290be121..607c37378c 100644 --- a/ugs-platform/ugs-platform-plugin-dro/src/main/java/com/willwinder/ugs/nbp/dro/MachineStatusTopComponent.java +++ b/ugs-platform/ugs-platform-plugin-dro/src/main/java/com/willwinder/ugs/nbp/dro/MachineStatusTopComponent.java @@ -43,7 +43,8 @@ This file is part of Universal Gcode Sender (UGS). ) @TopComponent.Registration( mode = Mode.LEFT_TOP, - openAtStartup = true + openAtStartup = true, + position = 100 ) @ActionID( category = LocalizingService.LocationStatusCategory, From 1a31abeecc0dab2744f52512cdcc391ecf003c9e Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Mon, 12 Feb 2024 14:41:39 -0500 Subject: [PATCH 18/20] FileBrowserTopComponent high position and disable openAtStartup --- .../ugs/nbp/core/control/FileBrowserTopComponent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java index 0ec3bae205..1abda52d4f 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/control/FileBrowserTopComponent.java @@ -43,7 +43,7 @@ This file is part of Universal Gcode Sender (UGS). @TopComponent.Description( preferredID = "FileBrowserTopComponent" ) -@TopComponent.Registration(mode = Mode.LEFT_TOP, openAtStartup = true) +@TopComponent.Registration(mode = Mode.LEFT_TOP, openAtStartup = false, position = 2200) @ActionID(category = FileBrowserPanelCategory, id = FileBrowserPanelActionId) @ActionReference(path = FileBrowserPanelWindowPath) @TopComponent.OpenActionRegistration( From 3e0ccf9e9c161134b2d52898022f700881e086b9 Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Mon, 12 Feb 2024 15:14:35 -0500 Subject: [PATCH 19/20] cleanup FileTreeCellRenderer --- .../ugs/nbp/core/panels/FileBrowserPanel.java | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java index b8a52479e5..5794e5f5d0 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java @@ -306,34 +306,26 @@ public String toString() { } public static class FileTreeCellRenderer extends DefaultTreeCellRenderer { - public static final String SMALL_GCODE_ICON = "icons/new.svg"; - public static final String SMALL_GCODE_DISABLED_ICON = "icons/new_dark.svg"; - public static final String SMALL_FOLDER_ICON = "resources/icons/open.svg"; - public static final String SMALL_FOLDER_DISABLED_ICON = "resources/icons/open_dark.svg"; - public static final String SMALL_PARENT_ICON = "resources/icons/reload.svg"; - public static final String SMALL_PARENT_DISABLED_ICON = "resources/icons/reload_dark.svg"; @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; - if (node.getUserObject() instanceof FileNode fileNode) { - if (fileNode.displayName.startsWith("..")) { - setIcon(ImageUtilities.loadImageIcon(tree.isEnabled() ? SMALL_PARENT_ICON : SMALL_PARENT_DISABLED_ICON, false)); - } else if (fileNode.getFile() != null && fileNode.getFile().isFile()) { - String fileName = fileNode.getFile().getName(); - if (fileName.matches(".*\\.(gcode|GCODE|cnc|CNC|nc|NC|ngc|NGC|tap|TAP|txt|TXT|gc|GC)")) { - setIcon(ImageUtilities.loadImageIcon(tree.isEnabled() ? SMALL_GCODE_ICON : SMALL_GCODE_DISABLED_ICON, false)); - } - } else if ((fileNode.getFile() == null || fileNode.getFile().isDirectory()) && !fileNode.displayName.startsWith("..")) { - setIcon(ImageUtilities.loadImageIcon(tree.isEnabled() ? SMALL_FOLDER_ICON : SMALL_FOLDER_DISABLED_ICON, false)); - } + if (!(node.getUserObject() instanceof FileNode fileNode)) { + return this; } - if (!tree.isEnabled()) { - setDisabledIcon(getIcon()); + if (fileNode.getFile() == null) { + setIcon(getDefaultOpenIcon()); + setDisabledIcon(getDefaultOpenIcon()); + } else if (fileNode.getFile().isFile()) { + String fileName = fileNode.getFile().getName(); + if (fileName.matches(".*\\.(gcode|GCODE|cnc|CNC|nc|NC|ngc|NGC|tap|TAP|txt|TXT|gc|GC)")) { + setIcon(ImageUtilities.loadImageIcon(SMALL_GCODE_ICON, false)); + setDisabledIcon(ImageUtilities.loadImageIcon(SMALL_GCODE_ICON, false)); + } } return this; From c19521ab317b5e37546ca979814fca61ed2971ed Mon Sep 17 00:00:00 2001 From: "Andrew D. Murray" Date: Mon, 12 Feb 2024 15:16:48 -0500 Subject: [PATCH 20/20] fix issue with trying to open the `.` folder as a file --- .../com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java index 5794e5f5d0..651c67fef2 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/panels/FileBrowserPanel.java @@ -190,7 +190,7 @@ private void openFileFromFileNode(TreePath path) { setDirectory(parentFile); } else if (fileNode.getFile().isDirectory()) { setDirectory(fileNode.getFile()); - } else { + } else if (!fileNode.displayName.startsWith(".")) { File gcodeFile = fileNode.getFile(); new OpenFileAction(gcodeFile).actionPerformed(null); }