From c542b72b33e1ff9e9c8563e84d36a876c6d65e30 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 22 Jun 2022 02:00:20 +0200 Subject: [PATCH] [#1054] Custom double click listener for design view --- .../gui/scalefigure/RocketPanel.java | 47 ++++++++++++------- .../utils/CustomClickCountListener.java | 46 ++++++++++++++++++ 2 files changed, 76 insertions(+), 17 deletions(-) create mode 100644 swing/src/net/sf/openrocket/utils/CustomClickCountListener.java diff --git a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java index 652a2a9b5..ac3a9d2c6 100644 --- a/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java +++ b/swing/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java @@ -5,6 +5,7 @@ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Font; import java.awt.Point; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; @@ -15,6 +16,7 @@ import java.util.EventListener; import java.util.EventObject; import java.util.List; import java.util.LinkedList; +import java.util.TimerTask; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -74,6 +76,7 @@ import net.sf.openrocket.util.Chars; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.StateChangeListener; +import net.sf.openrocket.utils.CustomClickCountListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -200,10 +203,12 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change scrollPane = new ScaleScrollPane(figure) { private static final long serialVersionUID = 1L; + final CustomClickCountListener clickCountListener = new CustomClickCountListener(); @Override public void mouseClicked(MouseEvent event) { - handleMouseClick(event); + clickCountListener.click(); + handleMouseClick(event, clickCountListener.getClickCount()); } }; scrollPane.getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE); @@ -237,9 +242,12 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change }); figure3d.addComponentSelectionListener(new RocketFigure3d.ComponentSelectionListener() { + final CustomClickCountListener clickCountListener = new CustomClickCountListener(); + @Override - public void componentClicked(RocketComponent clicked[], MouseEvent event) { - handleComponentClick(clicked, event); + public void componentClicked(RocketComponent[] clicked, MouseEvent event) { + clickCountListener.click(); + handleComponentClick(clicked, event, clickCountListener.getClickCount()); } }); } @@ -551,7 +559,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change */ public static final int CYCLE_SELECTION_MODIFIER = InputEvent.SHIFT_DOWN_MASK; - private void handleMouseClick(MouseEvent event) { + private void handleMouseClick(MouseEvent event, int clickCount) { // Get the component that is clicked on Point p0 = event.getPoint(); Point p1 = scrollPane.getViewport().getViewPosition(); @@ -567,7 +575,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change } if (event.getButton() == MouseEvent.BUTTON1) { - handleComponentClick(clicked, event); + handleComponentClick(clicked, event, clickCount); } else if (event.getButton() == MouseEvent.BUTTON3) { List selectedComponents = Arrays.stream(selectionModel.getSelectionPaths()) .map(c -> (RocketComponent) c.getLastPathComponent()).collect(Collectors.toList()); @@ -593,14 +601,29 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change } } - private void handleComponentClick(RocketComponent[] clicked, MouseEvent event) { + private void handleComponentClick(RocketComponent[] clicked, MouseEvent event, int clickCount) { List selectedComponents = Arrays.stream(selectionModel.getSelectionPaths()) .map(c -> (RocketComponent) c.getLastPathComponent()).collect(Collectors.toList()); if (clicked == null || clicked.length == 0) return; + // Check for double-click. If the component was not already selected, ignore the double click and treat it as a single click + if (clickCount == 2) { + if (!selectedComponents.contains(clicked[0])) { + clickCount = 1; + } else { + TreePath path = ComponentTreeModel.makeTreePath(clicked[0]); + selectionModel.setSelectionPath(path); // Revert to single selection + RocketComponent component = (RocketComponent) path.getLastPathComponent(); + + ComponentConfigDialog.showDialog(SwingUtilities.getWindowAncestor(this), + document, component); + return; + } + } + // If the shift-button is held, add a newly clicked component to the selection path - if ((event.isShiftDown() || event.isMetaDown()) && event.getClickCount() == 1) { + if (clickCount == 1 && (event.isShiftDown() || event.isMetaDown())) { List paths = new ArrayList<>(Arrays.asList(selectionModel.getSelectionPaths())); for (int i = 0; i < clicked.length; i++) { if (!selectedComponents.contains(clicked[i])) { @@ -622,16 +645,6 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change selectionModel.setSelectionPath(path); } } - - // Check for double-click - if (event.getClickCount() == 2) { - TreePath path = ComponentTreeModel.makeTreePath(clicked[0]); - selectionModel.setSelectionPath(path); // Revert to single selection - RocketComponent component = (RocketComponent) path.getLastPathComponent(); - - ComponentConfigDialog.showDialog(SwingUtilities.getWindowAncestor(this), - document, component); - } } /** diff --git a/swing/src/net/sf/openrocket/utils/CustomClickCountListener.java b/swing/src/net/sf/openrocket/utils/CustomClickCountListener.java new file mode 100644 index 000000000..5ff085274 --- /dev/null +++ b/swing/src/net/sf/openrocket/utils/CustomClickCountListener.java @@ -0,0 +1,46 @@ +package net.sf.openrocket.utils; + +import java.util.TimerTask; + +/** + * This class is a custom implementation of the mouse click count listener, where you can choose the maximum + * interval between two clicks for them to still be registered as a double click. + * + * @author Sibo Van Gool + */ +public class CustomClickCountListener { + private final int CLICK_INTERVAL; // Maximum interval between two clicks for them to still be registered as a double click (in ms) + private int clickCnt = 0; + private final java.util.Timer timer = new java.util.Timer("doubleClickTimer", false); + + public CustomClickCountListener() { + this.CLICK_INTERVAL = 600; // ms + } + + public CustomClickCountListener(int clickInterval) { + this.CLICK_INTERVAL = clickInterval; + } + + /** + * Call this method when the mouseClicked event is activated. + */ + public void click() { + clickCnt++; + if (clickCnt == 1) { + timer.schedule(new TimerTask() { + @Override + public void run() { + clickCnt = 0; + } + }, CLICK_INTERVAL); + } + } + + /** + * Return the current click count. + * @return the current click count + */ + public int getClickCount() { + return clickCnt; + } +}