From dac2f5343ac6ff05bfd0718a921266c7ed345657 Mon Sep 17 00:00:00 2001 From: Joacim Breiler Date: Thu, 19 Jan 2023 19:23:08 +0100 Subject: [PATCH 1/2] Grouped all create actions to make room for more actions in the toolbar. Hidden action will now toggle the icon based on the hidden/visible state. Attempt to fix jog controller not being enabled on certain platforms --- .../processors/CommandProcessorList.java | 4 +- .../nbp/designer/actions/ToggleHidden.java | 31 ++++- .../actions/ToolDrawCircleAction.java | 6 +- .../designer/actions/ToolImportAction.java | 6 +- .../designer/actions/ToolSelectAction.java | 2 +- .../ugs/nbp/designer/gui/ToolBox.java | 117 ++++++++++-------- .../gui/clipart/InsertClipartDialog.java | 2 +- .../com/willwinder/ugs/nbp/jog/JogPanel.java | 3 +- .../ugs/nbp/jog/JogTopComponent.java | 7 +- 9 files changed, 106 insertions(+), 72 deletions(-) diff --git a/ugs-core/src/com/willwinder/universalgcodesender/gcode/processors/CommandProcessorList.java b/ugs-core/src/com/willwinder/universalgcodesender/gcode/processors/CommandProcessorList.java index 064b50505..7fa3915b3 100644 --- a/ugs-core/src/com/willwinder/universalgcodesender/gcode/processors/CommandProcessorList.java +++ b/ugs-core/src/com/willwinder/universalgcodesender/gcode/processors/CommandProcessorList.java @@ -10,11 +10,13 @@ import java.util.Iterator; import java.util.List; import java.util.Spliterator; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.LinkedBlockingDeque; import java.util.function.Consumer; public class CommandProcessorList implements CommandProcessor, Iterable { - private List commandProcessors = new ArrayList<>(); + private final BlockingDeque commandProcessors = new LinkedBlockingDeque<>(); /** * Applies all command processors to a given command and returns the diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToggleHidden.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToggleHidden.java index 6043f92a8..125d1810c 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToggleHidden.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToggleHidden.java @@ -18,6 +18,7 @@ This file is part of Universal Gcode Sender (UGS). */ package com.willwinder.ugs.nbp.designer.actions; +import com.willwinder.ugs.nbp.designer.entities.Entity; import com.willwinder.ugs.nbp.designer.entities.cuttable.Cuttable; import com.willwinder.ugs.nbp.designer.entities.selection.SelectionEvent; import com.willwinder.ugs.nbp.designer.entities.selection.SelectionListener; @@ -46,15 +47,19 @@ This file is part of Universal Gcode Sender (UGS). public class ToggleHidden extends AbstractDesignAction implements SelectionListener { public static final String SMALL_ICON_PATH = "img/eye.svg"; public static final String LARGE_ICON_PATH = "img/eye24.svg"; + public static final String SMALL_ICON_HIDDEN_PATH = "img/eyeoff.svg"; + public static final String LARGE_ICON_HIDDEN_PATH = "img/eyeoff24.svg"; + public static final String PROPERTY_MENU_TEXT = "menuText"; public ToggleHidden() { - putValue("menuText", "Toggle hidden"); + putValue(PROPERTY_MENU_TEXT, "Toggle hidden"); putValue(NAME, "Toggle hidden"); putValue("iconBase", SMALL_ICON_PATH); putValue(SMALL_ICON, ImageUtilities.loadImageIcon(SMALL_ICON_PATH, false)); putValue(LARGE_ICON_KEY, ImageUtilities.loadImageIcon(LARGE_ICON_PATH, false)); ControllerFactory.getSelectionManager().addSelectionListener(this); + ControllerFactory.getController().addListener(e -> onSelectionEvent(null)); } @Override @@ -63,7 +68,7 @@ public void actionPerformed(ActionEvent e) { .findFirst() .map(Cuttable::isHidden) .orElse(true); - + UndoableShowHideAction action = new UndoableShowHideAction(getCuttableStream().collect(Collectors.toList()), !isHidden); action.redo(); ControllerFactory.getUndoManager().addAction(action); @@ -78,6 +83,19 @@ private Stream getCuttableStream() { public void onSelectionEvent(SelectionEvent selectionEvent) { SelectionManager selectionManager = ControllerFactory.getSelectionManager(); setEnabled(!selectionManager.getSelection().isEmpty()); + + boolean allIsHidden = getCuttableStream().allMatch(Cuttable::isHidden); + if (allIsHidden) { + putValue(SMALL_ICON, ImageUtilities.loadImageIcon(SMALL_ICON_PATH, false)); + putValue(LARGE_ICON_KEY, ImageUtilities.loadImageIcon(LARGE_ICON_PATH, false)); + putValue(PROPERTY_MENU_TEXT, "Show"); + putValue(NAME, "Show"); + } else { + putValue(SMALL_ICON, ImageUtilities.loadImageIcon(SMALL_ICON_HIDDEN_PATH, false)); + putValue(LARGE_ICON_KEY, ImageUtilities.loadImageIcon(LARGE_ICON_HIDDEN_PATH, false)); + putValue(PROPERTY_MENU_TEXT, "Hide"); + putValue(NAME, "Hide"); + } } private static class UndoableShowHideAction implements UndoableAction { @@ -92,11 +110,20 @@ public UndoableShowHideAction(List entities, boolean setAsHidden) { @Override public void redo() { entities.forEach(entity -> entity.setHidden(setAsHidden)); + triggerSelectionEvent(); } @Override public void undo() { entities.forEach(entity -> entity.setHidden(!setAsHidden)); + triggerSelectionEvent(); + } + + private void triggerSelectionEvent() { + SelectionManager selectionManager = ControllerFactory.getSelectionManager(); + List selection = selectionManager.getSelection(); + selectionManager.clearSelection(); + selectionManager.setSelection(selection); } @Override diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolDrawCircleAction.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolDrawCircleAction.java index 4efb3f9e4..79275f1fe 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolDrawCircleAction.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolDrawCircleAction.java @@ -36,7 +36,7 @@ This file is part of Universal Gcode Sender (UGS). id = "ToolDrawCircleAction") @ActionRegistration( iconBase = ToolDrawCircleAction.ICON_SMALL_PATH, - displayName = "Draw circle", + displayName = "Draw ellipse", lazy = false) public class ToolDrawCircleAction extends AbstractDesignAction { public static final String ICON_SMALL_PATH = "img/circle.svg"; @@ -46,8 +46,8 @@ public ToolDrawCircleAction() { putValue("iconBase", ICON_SMALL_PATH); putValue(SMALL_ICON, ImageUtilities.loadImageIcon(ICON_SMALL_PATH, false)); putValue(LARGE_ICON_KEY, ImageUtilities.loadImageIcon(ICON_LARGE_PATH, false)); - putValue("menuText", "Draw circle"); - putValue(NAME, "Draw circle"); + putValue("menuText", "Draw ellipse"); + putValue(NAME, "Draw ellipse"); } @Override diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolImportAction.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolImportAction.java index 945e4fe5a..4109cf27d 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolImportAction.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolImportAction.java @@ -48,7 +48,7 @@ This file is part of Universal Gcode Sender (UGS). id = "ToolImportAction") @ActionRegistration( iconBase = ToolImportAction.SMALL_ICON_PATH, - displayName = "Import", + displayName = "Import file", lazy = false) public final class ToolImportAction extends AbstractDesignAction { @@ -60,8 +60,8 @@ public ToolImportAction() { putValue("iconBase", SMALL_ICON_PATH); putValue(SMALL_ICON, ImageUtilities.loadImageIcon(SMALL_ICON_PATH, false)); putValue(LARGE_ICON_KEY, ImageUtilities.loadImageIcon(LARGE_ICON_PATH, false)); - putValue("menuText", "Import"); - putValue(NAME, "Import"); + putValue("menuText", "Import file"); + putValue(NAME, "Import file"); this.controller = ControllerFactory.getController(); } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolSelectAction.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolSelectAction.java index 59cd014a4..489ec1691 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolSelectAction.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/actions/ToolSelectAction.java @@ -40,7 +40,7 @@ This file is part of Universal Gcode Sender (UGS). lazy = false) public class ToolSelectAction extends AbstractDesignAction { public static final String SMALL_ICON_PATH = "img/pointer.svg"; - private static final String LARGE_ICON_PATH = "img/pointer24.svg"; + public static final String LARGE_ICON_PATH = "img/pointer24.svg"; private final transient Controller controller; public ToolSelectAction() { diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/ToolBox.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/ToolBox.java index f5f57ba8f..50cf398cd 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/ToolBox.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/ToolBox.java @@ -23,8 +23,10 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.actions.FlipHorizontallyAction; import com.willwinder.ugs.nbp.designer.actions.FlipVerticallyAction; import com.willwinder.ugs.nbp.designer.actions.IntersectionAction; +import com.willwinder.ugs.nbp.designer.actions.JogMachineToCenterAction; import com.willwinder.ugs.nbp.designer.actions.MultiplyAction; import com.willwinder.ugs.nbp.designer.actions.SubtractAction; +import com.willwinder.ugs.nbp.designer.actions.ToggleHidden; import com.willwinder.ugs.nbp.designer.actions.ToolClipartAction; import com.willwinder.ugs.nbp.designer.actions.ToolDrawCircleAction; import com.willwinder.ugs.nbp.designer.actions.ToolDrawPointAction; @@ -37,16 +39,25 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugs.nbp.designer.actions.UnionAction; import com.willwinder.ugs.nbp.designer.logic.Controller; import com.willwinder.ugs.nbp.designer.logic.ControllerEventType; +import org.openide.awt.DropDownButtonFactory; +import org.openide.util.ImageUtilities; +import javax.swing.Action; import javax.swing.ButtonGroup; +import javax.swing.Icon; import javax.swing.JButton; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; import javax.swing.JToggleButton; +import java.awt.event.ActionListener; /** * @author Joacim Breiler */ public class ToolBox extends ToolBar { + private JToggleButton toolDropDownButton = null; + public ToolBox(Controller controller) { setFloatable(false); @@ -56,46 +67,7 @@ public ToolBox(Controller controller) { select.setToolTipText("Select and move shapes"); add(select); - JToggleButton point = new JToggleButton(new ToolDrawPointAction()); - point.setText(""); - point.setToolTipText("Draw points"); - add(point); - - JToggleButton rectangle = new JToggleButton(new ToolDrawRectangleAction()); - rectangle.setText(""); - rectangle.setToolTipText("Draw squares and rectangles"); - add(rectangle); - - JToggleButton circle = new JToggleButton(new ToolDrawCircleAction()); - circle.setText(""); - circle.setToolTipText("Draw circles and ellipses"); - add(circle); - - JToggleButton text = new JToggleButton(new ToolDrawTextAction()); - text.setText(""); - text.setToolTipText("Write text"); - add(text); - - JButton importButton = new JButton(new ToolImportAction()); - importButton.setText(""); - importButton.setToolTipText("Imports a drawing"); - importButton.setContentAreaFilled(false); - importButton.setBorderPainted(false); - add(importButton); - - JButton insertButton = new JButton(new ToolClipartAction()); - insertButton.setText(""); - insertButton.setToolTipText("Inserts a clipart"); - insertButton.setContentAreaFilled(false); - insertButton.setBorderPainted(false); - add(insertButton); - - insertButton = new JButton(new TraceImageAction()); - insertButton.setText(""); - insertButton.setToolTipText("Traces a bitmap image"); - insertButton.setContentAreaFilled(false); - insertButton.setBorderPainted(false); - add(insertButton); + add(createToolDropDownButton()); addSeparator(); @@ -139,12 +111,24 @@ public ToolBox(Controller controller) { addSeparator(); + JButton visible = new JButton(new ToggleHidden()); + visible.setToolTipText("Toggles if the object should be hidden"); + visible.setBorderPainted(false); + visible.setHideActionText(true); + add(visible); + JButton multiply = new JButton(new MultiplyAction()); multiply.setText(""); multiply.setToolTipText("Multiplies the selection"); multiply.setBorderPainted(false); add(multiply); + JButton jogTo = new JButton(new JogMachineToCenterAction()); + jogTo.setText(""); + jogTo.setToolTipText("Jog machine to center"); + jogTo.setBorderPainted(false); + add(jogTo); + addSeparator(); JToggleButton zoom = new JToggleButton(new ToolZoomAction()); @@ -155,10 +139,7 @@ public ToolBox(Controller controller) { ButtonGroup buttons = new ButtonGroup(); buttons.add(select); - buttons.add(circle); - buttons.add(rectangle); - buttons.add(text); - buttons.add(importButton); + buttons.add(toolDropDownButton); buttons.add(zoom); controller.addListener(event -> { @@ -170,27 +151,55 @@ public ToolBox(Controller controller) { select.setSelected(true); break; case POINT: - point.setSelected(true); - break; case RECTANGLE: - rectangle.setSelected(true); - break; case CIRCLE: - circle.setSelected(true); - break; case TEXT: - text.setSelected(true); - break; - case INSERT: - importButton.setSelected(true); + toolDropDownButton.setSelected(true); break; case ZOOM: zoom.setSelected(true); break; default: + toolDropDownButton.setSelected(false); } repaint(); } }); } + + private JToggleButton createToolDropDownButton() { + // An action listener that listens to the popup menu items and changes the current action + ActionListener toolMenuListener = e -> { + if (toolDropDownButton == null) { + return; + } + + JMenuItem source = (JMenuItem) e.getSource(); + toolDropDownButton.setIcon((Icon) source.getAction().getValue(Action.LARGE_ICON_KEY)); + toolDropDownButton.setSelected(true); + toolDropDownButton.setAction(source.getAction()); + }; + + ToolDrawRectangleAction toolDrawRectangleAction = new ToolDrawRectangleAction(); + JPopupMenu popupMenu = new JPopupMenu(); + addDropDownAction(popupMenu, toolDrawRectangleAction, toolMenuListener); + addDropDownAction(popupMenu, new ToolDrawCircleAction(), toolMenuListener); + addDropDownAction(popupMenu, new ToolDrawPointAction(), toolMenuListener); + addDropDownAction(popupMenu, new ToolDrawTextAction(), toolMenuListener); + popupMenu.addSeparator(); + addDropDownAction(popupMenu, new ToolImportAction(), null); + addDropDownAction(popupMenu, new ToolClipartAction(), null); + addDropDownAction(popupMenu, new TraceImageAction(), null); + toolDropDownButton = DropDownButtonFactory.createDropDownToggleButton(ImageUtilities.loadImageIcon(ToolDrawRectangleAction.LARGE_ICON_PATH, false), popupMenu); + toolDropDownButton.setAction(toolDrawRectangleAction); + return toolDropDownButton; + } + + private void addDropDownAction(JPopupMenu popupMenu, Action action, ActionListener actionListener) { + JMenuItem menuItem = new JMenuItem(action); + if (actionListener != null) { + menuItem.addActionListener(actionListener); + } + popupMenu.add(menuItem); + } } diff --git a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/clipart/InsertClipartDialog.java b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/clipart/InsertClipartDialog.java index dda8e8b86..f12a66e5e 100644 --- a/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/clipart/InsertClipartDialog.java +++ b/ugs-platform/ugs-platform-plugin-designer/src/main/java/com/willwinder/ugs/nbp/designer/gui/clipart/InsertClipartDialog.java @@ -44,7 +44,7 @@ public class InsertClipartDialog extends JDialog implements ListSelectionListene public InsertClipartDialog() { super((JFrame) null, true); - setTitle("Insert shape"); + setTitle("Insert clipart"); setPreferredSize(new Dimension(700, 480)); setLayout(new MigLayout("fill, insets 5", "[][grow, fill]", "")); diff --git a/ugs-platform/ugs-platform-plugin-jog/src/main/java/com/willwinder/ugs/nbp/jog/JogPanel.java b/ugs-platform/ugs-platform-plugin-jog/src/main/java/com/willwinder/ugs/nbp/jog/JogPanel.java index bfb980871..3e0db906e 100644 --- a/ugs-platform/ugs-platform-plugin-jog/src/main/java/com/willwinder/ugs/nbp/jog/JogPanel.java +++ b/ugs-platform/ugs-platform-plugin-jog/src/main/java/com/willwinder/ugs/nbp/jog/JogPanel.java @@ -1,5 +1,5 @@ /* - Copyright 2018-2021 Will Winder + Copyright 2018-2023 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -34,7 +34,6 @@ This file is part of Universal Gcode Sender (UGS). import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.JSeparator; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; diff --git a/ugs-platform/ugs-platform-plugin-jog/src/main/java/com/willwinder/ugs/nbp/jog/JogTopComponent.java b/ugs-platform/ugs-platform-plugin-jog/src/main/java/com/willwinder/ugs/nbp/jog/JogTopComponent.java index af315a2d6..ab1a609e1 100644 --- a/ugs-platform/ugs-platform-plugin-jog/src/main/java/com/willwinder/ugs/nbp/jog/JogTopComponent.java +++ b/ugs-platform/ugs-platform-plugin-jog/src/main/java/com/willwinder/ugs/nbp/jog/JogTopComponent.java @@ -1,5 +1,5 @@ /* - Copyright 2018-2021 Will Winder + Copyright 2018-2023 Will Winder This file is part of Universal Gcode Sender (UGS). @@ -149,10 +149,7 @@ private void checkAxisEnabled(Axis axis) { } private void updateControls() { - boolean canJog = jogService.canJog(); - if (canJog != jogPanel.isEnabled()) { - jogPanel.setEnabled(canJog); - } + jogPanel.setEnabled(jogService.canJog()); } @Override From 64330a79989c38fd0f365e0347710b5b2610ce65 Mon Sep 17 00:00:00 2001 From: Joacim Breiler Date: Thu, 19 Jan 2023 20:36:31 +0100 Subject: [PATCH 2/2] Add menu for opening recent files --- .../resources/MessagesBundle_en_US.properties | 1 + .../ugs/nbp/CloudStorageOpenAction.java | 2 +- .../ugs/nbp/core/actions/OpenAction.java | 38 ++++----- .../ugs/nbp/core/actions/OpenFileAction.java | 66 +++++++++++++++ .../nbp/core/actions/OpenRecentAction.java | 80 +++++++++++++++++++ .../nbp/lib/services/LocalizingService.java | 3 + .../willwinder/ugp/welcome/RecentWorkTab.java | 12 +-- 7 files changed, 170 insertions(+), 32 deletions(-) create mode 100644 ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenFileAction.java create mode 100644 ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenRecentAction.java diff --git a/ugs-core/src/resources/MessagesBundle_en_US.properties b/ugs-core/src/resources/MessagesBundle_en_US.properties index 3f3ea73b0..ef97a4583 100644 --- a/ugs-core/src/resources/MessagesBundle_en_US.properties +++ b/ugs-core/src/resources/MessagesBundle_en_US.properties @@ -403,6 +403,7 @@ toolbar.icon.small = Small Icons toolbar.icon.large = Large Icons sender.help.verbose.console = Show additional information in the controller console. platform.menu.open = Open... +platform.menu.open.recent = Open recent platform.menu.save = Save platform.menu.edit = Edit Gcode File... mainWindow.swing.reset = Reset diff --git a/ugs-platform/ugs-platform-plugin-cloud-storage/src/main/java/com/willwinder/ugs/nbp/CloudStorageOpenAction.java b/ugs-platform/ugs-platform-plugin-cloud-storage/src/main/java/com/willwinder/ugs/nbp/CloudStorageOpenAction.java index cdb8a34f5..3a6a2327a 100644 --- a/ugs-platform/ugs-platform-plugin-cloud-storage/src/main/java/com/willwinder/ugs/nbp/CloudStorageOpenAction.java +++ b/ugs-platform/ugs-platform-plugin-cloud-storage/src/main/java/com/willwinder/ugs/nbp/CloudStorageOpenAction.java @@ -53,7 +53,7 @@ This file is part of Universal Gcode Sender (UGS). @ActionReferences({ @ActionReference( path = LocalizingService.OpenWindowPath, - position = 11) + position = 12) }) public final class CloudStorageOpenAction implements ActionListener { diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenAction.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenAction.java index 1eba19016..2e1220a90 100644 --- a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenAction.java +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenAction.java @@ -23,6 +23,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.utils.GUIHelpers; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; @@ -61,8 +62,8 @@ This file is part of Universal Gcode Sender (UGS). public final class OpenAction extends AbstractAction { public static final String ICON_BASE = "resources/icons/open.svg"; - private transient final FileFilterService fileFilterService; - private transient final BackendAPI backend; + private final transient FileFilterService fileFilterService; + private final transient BackendAPI backend; private final JFileChooser fileChooser; public OpenAction() { @@ -93,31 +94,24 @@ public void actionPerformed(ActionEvent e) { int returnVal = fileChooser.showOpenDialog(new JFrame()); if (returnVal == JFileChooser.APPROVE_OPTION) { - try { - File selectedFile = fileChooser.getSelectedFile(); - openFile(selectedFile); - } catch (DataObjectNotFoundException ex) { - ex.printStackTrace(); - } + File selectedFile = fileChooser.getSelectedFile(); + openFile(selectedFile); } } - public void openFile(File selectedFile) throws DataObjectNotFoundException { - if (EditorUtils.closeOpenEditors()) { - backend.getSettings().setLastOpenedFilename(selectedFile.getAbsolutePath()); - OpenCookie c = DataObject.find(FileUtil.toFileObject(selectedFile)) - .getLookup() - .lookup(OpenCookie.class); - if (c != null) c.open(); - } + public void openFile(File selectedFile) { + OpenFileAction action = new OpenFileAction(selectedFile); + action.actionPerformed(null); } private JFileChooser createFileChooser(String directory) { - JFileChooser fileChooser = new JFileChooser(directory); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - fileChooser.setFileHidingEnabled(true); - fileChooser.setDialogType(JFileChooser.OPEN_DIALOG); - fileChooser.setAcceptAllFileFilterUsed(true); - return fileChooser; + JFileChooser chooser = new JFileChooser(directory); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + chooser.setFileHidingEnabled(true); + chooser.setDialogType(JFileChooser.OPEN_DIALOG); + chooser.setAcceptAllFileFilterUsed(true); + return chooser; } + + } diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenFileAction.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenFileAction.java new file mode 100644 index 000000000..677d48061 --- /dev/null +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenFileAction.java @@ -0,0 +1,66 @@ +/* + Copyright 2023 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.actions; + +import com.willwinder.ugs.nbp.lib.EditorUtils; +import com.willwinder.ugs.nbp.lib.lookup.CentralLookup; +import com.willwinder.universalgcodesender.model.BackendAPI; +import com.willwinder.universalgcodesender.utils.GUIHelpers; +import org.openide.cookies.OpenCookie; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import java.awt.event.ActionEvent; +import java.io.File; + +/** + * A generic action for opening a file + * + * @author Joacim Breiler + */ +public class OpenFileAction extends AbstractAction { + private final File selectedFile; + + public OpenFileAction(File selectedFile) { + this.selectedFile = selectedFile; + putValue(NAME, selectedFile.getName()); + putValue(Action.SHORT_DESCRIPTION, selectedFile.getAbsolutePath()); + } + + @Override + public void actionPerformed(ActionEvent event) { + if (!EditorUtils.closeOpenEditors()) { + return; + } + + try { + BackendAPI backend = CentralLookup.getDefault().lookup(BackendAPI.class); + backend.getSettings().setLastOpenedFilename(selectedFile.getAbsolutePath()); + OpenCookie c = DataObject.find(FileUtil.toFileObject(selectedFile)) + .getLookup() + .lookup(OpenCookie.class); + if (c != null) c.open(); + } catch (DataObjectNotFoundException e) { + GUIHelpers.displayErrorDialog("Could not open file " + selectedFile.getAbsolutePath()); + } + } +} diff --git a/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenRecentAction.java b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenRecentAction.java new file mode 100644 index 000000000..29837e853 --- /dev/null +++ b/ugs-platform/ugs-platform-ugscore/src/main/java/com/willwinder/ugs/nbp/core/actions/OpenRecentAction.java @@ -0,0 +1,80 @@ +/* + Copyright 2023 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.actions; + +import com.willwinder.ugs.nbp.lib.lookup.CentralLookup; +import com.willwinder.ugs.nbp.lib.services.LocalizingService; +import com.willwinder.universalgcodesender.model.BackendAPI; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.awt.ActionRegistration; +import org.openide.awt.DynamicMenuContent; + +import javax.swing.AbstractAction; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import java.awt.event.ActionEvent; +import java.io.File; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +@ActionID( + id = "com.willwinder.ugs.nbp.core.actions.OpenRecentAction", + category = LocalizingService.OpenCategory) +@ActionRegistration( + iconBase = OpenAction.ICON_BASE, + lazy = false, + displayName = "Open recent...") +@ActionReferences({ + @ActionReference( + path = LocalizingService.MENU_FILE, + position = 11), +}) +public class OpenRecentAction extends AbstractAction implements DynamicMenuContent { + + @Override + public void actionPerformed(ActionEvent e) { + // does nothing, this is a popup menu + } + + @Override + public JComponent[] getMenuPresenters() { + JMenu submenu = new JMenu(LocalizingService.OpenRecentTitle); + createMenu().forEach(submenu::add); + return new JComponent[]{submenu}; + } + + @Override + public JComponent[] synchMenuPresenters(JComponent[] items) { + return getMenuPresenters(); + } + + private List createMenu() { + BackendAPI backend = CentralLookup.getDefault().lookup(BackendAPI.class); + return backend.getSettings().getRecentFiles().stream() + .map(file -> Paths.get(file).toFile()) + .filter(File::exists) + .filter(File::isFile) + .map(file -> new JMenuItem(new OpenFileAction(file))) + .collect(Collectors.toList()); + } +} 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 40dffc868..8522d7045 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 @@ -117,6 +117,9 @@ public class LocalizingService { public final static String OpenActionId = "com.willwinder.ugs.nbp.core.actions.OpenAction"; public final static String OpenCategory = CATEGORY_FILE; + public final static String OpenRecentTitleKey = "platform.menu.open.recent"; + public final static String OpenRecentTitle = Localization.getString(OpenRecentTitleKey, lang); + public final static String SaveTitleKey = "platform.menu.save"; public final static String SaveTitle = Localization.getString(SaveTitleKey, lang); public final static String SaveWindowPath = MENU_FILE; diff --git a/ugs-platform/ugs-platform-welcome-page/src/main/java/com/willwinder/ugp/welcome/RecentWorkTab.java b/ugs-platform/ugs-platform-welcome-page/src/main/java/com/willwinder/ugp/welcome/RecentWorkTab.java index c844a6832..114ff0f30 100644 --- a/ugs-platform/ugs-platform-welcome-page/src/main/java/com/willwinder/ugp/welcome/RecentWorkTab.java +++ b/ugs-platform/ugs-platform-welcome-page/src/main/java/com/willwinder/ugp/welcome/RecentWorkTab.java @@ -21,11 +21,11 @@ This file is part of Universal Gcode Sender (UGS). import com.willwinder.ugp.welcome.content.AbstractTab; import com.willwinder.ugp.welcome.content.JLinkButton; import com.willwinder.ugs.nbp.core.actions.OpenAction; +import com.willwinder.ugs.nbp.core.actions.OpenFileAction; import com.willwinder.ugs.nbp.lib.lookup.CentralLookup; import com.willwinder.universalgcodesender.model.BackendAPI; import com.willwinder.universalgcodesender.uielements.helpers.ThemeColors; import net.miginfocom.swing.MigLayout; -import org.openide.loaders.DataObjectNotFoundException; import javax.swing.BorderFactory; import javax.swing.JComponent; @@ -44,7 +44,7 @@ This file is part of Universal Gcode Sender (UGS). */ public class RecentWorkTab extends AbstractTab { private static final Logger LOGGER = Logger.getLogger(RecentWorkTab.class.getName()); - private final BackendAPI backend; + private final transient BackendAPI backend; public RecentWorkTab() { super("Recent Work"); @@ -120,13 +120,7 @@ private JLinkButton createFileButton(Path p) { button.setLinkColor(ThemeColors.LIGHT_BLUE_GREY); } - button.addActionListener(l -> { - try { - new OpenAction().openFile(p.toFile()); - } catch (DataObjectNotFoundException e) { - LOGGER.log(Level.SEVERE, "Could not open file " + p, e); - } - }); + button.addActionListener(l -> new OpenFileAction(p.toFile()).actionPerformed(null)); return button; } }