From 3120b2d96890565b1fa6dbd2630717aaeb73a2cd Mon Sep 17 00:00:00 2001 From: SiboVG Date: Sat, 22 Jul 2023 01:46:07 +0200 Subject: [PATCH] Include simulation headers in clipboard copy + add to context menu --- core/resources/l10n/messages.properties | 4 +- .../openrocket/gui/main/SimulationPanel.java | 188 ++++++++++++------ 2 files changed, 125 insertions(+), 67 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index ac42cc483..4d6cbbf11 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -581,12 +581,13 @@ simpanel.but.ttip.editsim = Edit the selected simulation simpanel.but.ttip.runsimu = Re-run the selected simulations simpanel.but.ttip.deletesim = Delete the selected simulations simpanel.pop.edit = Edit +simpanel.pop.copyValues = Copy values simpanel.pop.plot = Plot / Export simpanel.pop.run = Run simpanel.pop.delete = Delete simpanel.pop.duplicate = Duplicate simpanel.pop.exportSimTableToCSV = Export simulation table as CSV file -simpanel.pop.exportSelectedSimsToCSV = Export simulations as CSV file +simpanel.pop.exportSelectedSimsToCSV = Export simulation(s) as CSV file simpanel.pop.exportToCSV.save.dialog.title = Save as CSV file simpanel.dlg.no.simulation.table.rows = Simulation table has no entries\u2026 Please run a simulation first. simpanel.checkbox.donotask = Do not ask me again @@ -594,6 +595,7 @@ simpanel.lbl.defpref = You can change the default operation in the preferences. simpanel.dlg.lbl.DeleteSim1 = Delete the selected simulations? simpanel.dlg.lbl.DeleteSim2 = This operation cannot be undone. simpanel.dlg.lbl.DeleteSim3 = Delete simulations +simpanel.col.Status = Status simpanel.col.Name = Name simpanel.col.Motors = Motors simpanel.col.Configuration = Configuration diff --git a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java index 7f5aed9e0..c5be48302 100644 --- a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -110,6 +110,7 @@ public class SimulationPanel extends JPanel { private final JPopupMenu pm; private final SimulationAction editSimulationAction; + private final SimulationAction copyValuesSimulationAction; private final SimulationAction runSimulationAction; private final SimulationAction plotSimulationAction; private final SimulationAction duplicateSimulationAction; @@ -129,6 +130,7 @@ public class SimulationPanel extends JPanel { // Simulation actions SimulationAction newSimulationAction = new NewSimulationAction(); editSimulationAction = new EditSimulationAction(); + copyValuesSimulationAction = new CopyValuesSimulationAction(); runSimulationAction = new RunSimulationAction(); plotSimulationAction = new PlotSimulationAction(); duplicateSimulationAction = new DuplicateSimulationAction(); @@ -155,7 +157,7 @@ public class SimulationPanel extends JPanel { RocketActions.tieActionToButton(runButton, runSimulationAction, trans.get("simpanel.but.runsimulations")); runButton.setToolTipText(trans.get("simpanel.but.ttip.runsimu")); this.add(runButton, "gapright para"); - + //// Delete simulations button deleteButton = new IconButton(); RocketActions.tieActionToButton(deleteButton, deleteSimulationAction, trans.get("simpanel.but.deletesimulations")); @@ -184,10 +186,12 @@ public class SimulationPanel extends JPanel { simulationTable.setDefaultRenderer(Object.class, new JLabelRenderer()); simulationTableModel.setColumnWidths(simulationTable.getColumnModel()); simulationTable.setFillsViewportHeight(true); + simulationTable.registerKeyboardAction(copyValuesSimulationAction, "Copy", RocketActions.COPY_KEY_STROKE, JComponent.WHEN_FOCUSED); // Context menu pm = new JPopupMenu(); pm.add(editSimulationAction); + pm.add(copyValuesSimulationAction); pm.add(duplicateSimulationAction); pm.add(deleteSimulationAction); pm.addSeparator(); @@ -480,36 +484,40 @@ public class SimulationPanel extends JPanel { } - private void copySimulationAction() { - int numCols=simulationTable.getColumnCount(); - int numRows=simulationTable.getSelectedRowCount(); - int[] rowsSelected=simulationTable.getSelectedRows(); - - if (numRows!=rowsSelected[rowsSelected.length-1]-rowsSelected[0]+1 || numRows!=rowsSelected.length) { + private void copySimulationValuesAction() { + int numCols = simulationTable.getColumnCount(); + int numRows = simulationTable.getSelectedRowCount(); + int[] rowsSelected = simulationTable.getSelectedRows(); + if (numRows != (rowsSelected[rowsSelected.length-1] - rowsSelected[0] + 1) || numRows != rowsSelected.length) { JOptionPane.showMessageDialog(null, "Invalid Copy Selection", "Invalid Copy Selection", JOptionPane.ERROR_MESSAGE); return; } - StringBuilder excelStr =new StringBuilder(); - for (int k = 1; k < numCols; k++) { - excelStr.append(simulationTable.getColumnName(k)); - if (k < numCols-1) { - excelStr.append("\t"); + StringBuilder valuesStr = new StringBuilder(); + + // Copy the column names + valuesStr.append(trans.get("simpanel.col.Status")).append("\t"); + for (int i = 1; i < numCols; i++) { + valuesStr.append(simulationTable.getColumnName(i)); + if (i < numCols-1) { + valuesStr.append("\t"); } } - excelStr.append("\n"); + valuesStr.append("\n"); + + // Copy the values for (int i = 0; i < numRows; i++) { - for (int j = 1; j < numCols; j++) { - excelStr.append(simulationTable.getValueAt(rowsSelected[i], j)); + for (int j = 0; j < numCols; j++) { + valuesStr.append(simulationTable.getValueAt(rowsSelected[i], j).toString()); if (j < numCols-1) { - excelStr.append("\t"); + valuesStr.append("\t"); } } - excelStr.append("\n"); + valuesStr.append("\n"); } - StringSelection sel = new StringSelection(excelStr.toString()); + StringSelection sel = new StringSelection(valuesStr.toString()); Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); cb.setContents(sel, sel); @@ -545,6 +553,7 @@ public class SimulationPanel extends JPanel { private void updateButtonStates() { editSimulationAction.updateEnabledState(); + copyValuesSimulationAction.updateEnabledState(); deleteSimulationAction.updateEnabledState(); runSimulationAction.updateEnabledState(); plotSimulationAction.updateEnabledState(); @@ -595,6 +604,61 @@ public class SimulationPanel extends JPanel { return simulationTable.getSelectionModel(); } + private String getSimulationToolTip(Simulation sim, boolean includeSimName) { + String tip; + FlightData data = sim.getSimulatedData(); + + tip = ""; + if (includeSimName) { + tip += "" + sim.getName() + "
"; + } + switch (sim.getStatus()) { + case CANT_RUN: + tip += trans.get("simpanel.ttip.noData")+"
"; + break; + case LOADED: + tip += trans.get("simpanel.ttip.loaded") + "
"; + break; + case UPTODATE: + tip += trans.get("simpanel.ttip.uptodate") + "
"; + break; + + case OUTDATED: + tip += trans.get("simpanel.ttip.outdated") + "
"; + break; + + case EXTERNAL: + tip += trans.get("simpanel.ttip.external") + "
"; + return tip; + + case NOT_SIMULATED: + tip += trans.get("simpanel.ttip.notSimulated"); + return tip; + } + + if (data == null) { + tip += trans.get("simpanel.ttip.noData"); + return tip; + } + WarningSet warnings = data.getWarningSet(); + + if (warnings.isEmpty()) { + tip += trans.get("simpanel.ttip.noWarnings"); + return tip; + } + + tip += trans.get("simpanel.ttip.warnings"); + for (Warning w : warnings) { + tip += "
" + w.toString(); + } + + return tip; + } + + private String getSimulationToolTip(Simulation sim) { + return getSimulationToolTip(sim, true); + } + private void openDialog(boolean plotMode, boolean isNewSimulation, final Simulation... sims) { SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, isNewSimulation, sims); if (plotMode) { @@ -670,6 +734,25 @@ public class SimulationPanel extends JPanel { } } + class CopyValuesSimulationAction extends SimulationAction { + public CopyValuesSimulationAction() { + putValue(NAME, trans.get("simpanel.pop.copyValues")); + this.putValue(MNEMONIC_KEY, KeyEvent.VK_C); + this.putValue(ACCELERATOR_KEY, RocketActions.COPY_KEY_STROKE); + this.putValue(SMALL_ICON, Icons.EDIT_COPY); + } + + @Override + public void actionPerformed(ActionEvent e) { + copySimulationValuesAction(); + } + + @Override + public void updateEnabledState() { + setEnabled(simulationTable.getSelectedRowCount() > 0); + } + } + class RunSimulationAction extends SimulationAction { public RunSimulationAction() { putValue(NAME, trans.get("simpanel.pop.run")); @@ -852,53 +935,24 @@ public class SimulationPanel extends JPanel { } return component; } + } - private String getSimulationToolTip(Simulation sim) { - String tip; - FlightData data = sim.getSimulatedData(); + private class StatusLabel extends StyledLabel { + private Simulation simulation; - tip = "" + sim.getName() + "
"; - switch (sim.getStatus()) { - case CANT_RUN: - tip += trans.get("simpanel.ttip.noData")+"
"; - break; - case LOADED: - tip += trans.get("simpanel.ttip.loaded") + "
"; - break; - case UPTODATE: - tip += trans.get("simpanel.ttip.uptodate") + "
"; - break; + public StatusLabel(Simulation simulation, float size) { + super(size); + this.simulation = simulation; + } - case OUTDATED: - tip += trans.get("simpanel.ttip.outdated") + "
"; - break; + public void replaceSimulation(Simulation simulation) { + this.simulation = simulation; + } - case EXTERNAL: - tip += trans.get("simpanel.ttip.external") + "
"; - return tip; - - case NOT_SIMULATED: - tip += trans.get("simpanel.ttip.notSimulated"); - return tip; - } - - if (data == null) { - tip += trans.get("simpanel.ttip.noData"); - return tip; - } - WarningSet warnings = data.getWarningSet(); - - if (warnings.isEmpty()) { - tip += trans.get("simpanel.ttip.noWarnings"); - return tip; - } - - tip += trans.get("simpanel.ttip.warnings"); - for (Warning w : warnings) { - tip += "
" + w.toString(); - } - - return tip; + @Override + public String toString() { + String text = getSimulationToolTip(simulation, false); + return text.replace("
", "-").replaceAll("<[^>]*>",""); } } @@ -909,31 +963,33 @@ public class SimulationPanel extends JPanel { super( //// Status and warning column new Column("") { - private JLabel label = null; + private StatusLabel label = null; @Override public Object getValueAt(int row) { if (row < 0 || row >= document.getSimulationCount()) return null; + Simulation simulation = document.getSimulation(row); + // Initialize the label if (label == null) { - label = new StyledLabel(2f); + label = new StatusLabel(simulation, 2f); label.setIconTextGap(1); // label.setFont(label.getFont().deriveFont(Font.BOLD)); + } else { + label.replaceSimulation(simulation); } // Set simulation status icon - Simulation.Status status = document.getSimulation(row).getStatus(); + Simulation.Status status = simulation.getStatus(); label.setIcon(Icons.SIMULATION_STATUS_ICON_MAP.get(status)); // Set warning marker if (status == Simulation.Status.NOT_SIMULATED || status == Simulation.Status.EXTERNAL) { - label.setText(""); - } else { WarningSet w = document.getSimulation(row).getSimulatedWarnings();