From e3a978655103a914763e314928fa31830b4e2ad9 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 26 Jul 2023 12:13:49 +0200 Subject: [PATCH 1/3] Allow for discontinuous row selection No idea why this was once implemented --- core/resources/l10n/messages.properties | 1 + swing/src/net/sf/openrocket/gui/main/SimulationPanel.java | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 4d6cbbf11..2a6e0831d 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -617,6 +617,7 @@ simpanel.ttip.notSimulated = Not simulated yet
Click Run simulat simpanel.ttip.noData = No simulation data available. simpanel.ttip.noWarnings = No warnings. simpanel.ttip.warnings = Warnings: +simpanel.msg.invalidCopySelection = Invalid copy selection ! SimulationRunDialog SimuRunDlg.title.RunSim = Running simulations\u2026 diff --git a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java index c5be48302..ff1fc55f7 100644 --- a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -489,8 +489,9 @@ public class SimulationPanel extends JPanel { 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); + if (numRows != rowsSelected.length) { + JOptionPane.showMessageDialog(this, trans.get("simpanel.msg.invalidCopySelection"), + trans.get("simpanel.msg.invalidCopySelection"), JOptionPane.ERROR_MESSAGE); return; } From bb3c72e2107a22711dcb59f4343af55fc57b66e6 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Wed, 26 Jul 2023 12:14:07 +0200 Subject: [PATCH 2/3] Also copy sim data to clipboard on rocket action --- swing/src/net/sf/openrocket/gui/main/RocketActions.java | 1 + swing/src/net/sf/openrocket/gui/main/SimulationPanel.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/swing/src/net/sf/openrocket/gui/main/RocketActions.java b/swing/src/net/sf/openrocket/gui/main/RocketActions.java index 2bfa6e9a6..1d705db7d 100644 --- a/swing/src/net/sf/openrocket/gui/main/RocketActions.java +++ b/swing/src/net/sf/openrocket/gui/main/RocketActions.java @@ -754,6 +754,7 @@ public class RocketActions { } OpenRocketClipboard.setClipboard(simsCopy); + simulationPanel.copySimulationValuesAction(); parentFrame.selectTab(BasicFrame.SIMULATION_TAB); } } diff --git a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java index ff1fc55f7..9d0381d20 100644 --- a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -484,7 +484,7 @@ public class SimulationPanel extends JPanel { } - private void copySimulationValuesAction() { + public void copySimulationValuesAction() { int numCols = simulationTable.getColumnCount(); int numRows = simulationTable.getSelectedRowCount(); int[] rowsSelected = simulationTable.getSelectedRows(); From af5bd3f7a1a7defab75430073d4df7f35d104b6c Mon Sep 17 00:00:00 2001 From: SiboVG Date: Fri, 28 Jul 2023 00:43:35 +0200 Subject: [PATCH 3/3] Big cleanup of simulation actions --- core/resources/l10n/messages.properties | 29 +- core/resources/l10n/messages_ar.properties | 5 - core/resources/l10n/messages_cs.properties | 5 - core/resources/l10n/messages_de.properties | 5 - core/resources/l10n/messages_es.properties | 6 - core/resources/l10n/messages_fr.properties | 6 - core/resources/l10n/messages_it.properties | 5 - core/resources/l10n/messages_ja.properties | 5 - core/resources/l10n/messages_nl.properties | 5 - core/resources/l10n/messages_pl.properties | 5 - core/resources/l10n/messages_pt.properties | 6 - core/resources/l10n/messages_ru.properties | 5 - core/resources/l10n/messages_tr.properties | 6 - core/resources/l10n/messages_uk_UA.properties | 5 - core/resources/l10n/messages_zh_CN.properties | 6 - .../document/OpenRocketDocument.java | 11 +- .../SimulationPreferencesPanel.java | 2 +- .../sf/openrocket/gui/main/BasicFrame.java | 8 +- .../sf/openrocket/gui/main/DesignPanel.java | 14 +- .../sf/openrocket/gui/main/RocketActions.java | 650 ++++++++---------- .../openrocket/gui/main/SimulationPanel.java | 424 ++++++++---- 21 files changed, 613 insertions(+), 600 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 2a6e0831d..c33541c20 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -16,23 +16,18 @@ debug.currentFile = messages.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = Do not ask me again -RocketActions.lbl.Youcanchangedefop = You can change the default operation in the preferences. -RocketActions.showConfirmDialog.lbl1 = Delete the selected simulations? -RocketActions.showConfirmDialog.lbl2 = This operation cannot be undone. -RocketActions.showConfirmDialog.title = Delete simulations RocketActions.DelCompAct.Delete = Delete -RocketActions.DelCompAct.ttip.Delete = Delete the selected component. +RocketActions.DelCompAct.ttip.Delete = Delete the selected components. RocketActions.DelSimuAct.Delete = Delete -RocketActions.DelSimuAct.ttip.Delete = Delete the selected simulation. +RocketActions.DelSimuAct.ttip.Delete = Delete the selected simulations. RocketActions.DelAct.Delete = Delete -RocketActions.DelAct.ttip.Delete = Delete the selected component or simulation. +RocketActions.DelAct.ttip.Delete = Delete the selected components or simulations. RocketActions.CutAction.Cut = Cut -RocketActions.CutAction.ttip.Cut = Cut this component or simulation to the clipboard and delete from this design +RocketActions.CutAction.ttip.Cut = Cut these components or simulations to the clipboard and delete from this design RocketActions.CopyAct.Copy = Copy -RocketActions.CopyAct.ttip.Copy = Copy this component (and subcomponents) to the clipboard. +RocketActions.CopyAct.ttip.Copy = Copy these components (and subcomponents) to the clipboard. RocketActions.PasteAct.Paste = Paste -RocketActions.PasteAct.ttip.Paste = Paste the component or simulation on the clipboard to the design. +RocketActions.PasteAct.ttip.Paste = Paste the components or simulations on the clipboard to the design. RocketActions.PasteAct.invalidPosition.msg = Invalid paste position for object '%s', ignoring pasting. RocketActions.PasteAct.invalidPosition.title = Could not paste RocketActions.DuplicateAct.Duplicate = Duplicate @@ -581,11 +576,21 @@ 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.edit.ttip= Edit the selected simulation(s) +simpanel.pop.cut= Cut +simpanel.pop.cut.ttip= Copy the selected simulation(s) to the clipboard and delete from this design +simpanel.pop.copy= Copy +simpanel.pop.copy.ttip= Copy the selected simulation(s) to the clipboard +simpanel.pop.paste= Paste +simpanel.pop.paste.ttip= Paste the simulation(s) on the clipboard to the design. simpanel.pop.plot = Plot / Export +simpanel.pop.plot.ttip= Plot or Export the selected simulation(s) simpanel.pop.run = Run +simpanel.pop.run.ttip= Run the selected simulation(s) simpanel.pop.delete = Delete +simpanel.pop.delete.ttip= Delete the selected simulation(s) simpanel.pop.duplicate = Duplicate +simpanel.pop.duplicate.ttip= Duplicate the selected simulation(s) simpanel.pop.exportSimTableToCSV = Export simulation table as CSV file simpanel.pop.exportSelectedSimsToCSV = Export simulation(s) as CSV file simpanel.pop.exportToCSV.save.dialog.title = Save as CSV file diff --git a/core/resources/l10n/messages_ar.properties b/core/resources/l10n/messages_ar.properties index 96b45e6ab..65d2651d3 100644 --- a/core/resources/l10n/messages_ar.properties +++ b/core/resources/l10n/messages_ar.properties @@ -16,11 +16,6 @@ debug.currentFile = messages_ar.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = لا تسألني مجددا -RocketActions.lbl.Youcanchangedefop = يمكنك تغيير العملية الافتراضية في التفضيلات. -RocketActions.showConfirmDialog.lbl1 = إحذف المحاكاة المختارة؟ -RocketActions.showConfirmDialog.lbl2 = لا يمكنك التراجع عن هذه العملية. -RocketActions.showConfirmDialog.title = إحذف كل المحاكاة RocketActions.DelCompAct.Delete = إحذف RocketActions.DelCompAct.ttip.Delete = إحذف القطعة المختارة RocketActions.DelSimuAct.Delete = إحذف diff --git a/core/resources/l10n/messages_cs.properties b/core/resources/l10n/messages_cs.properties index 08a09dffd..27d128273 100644 --- a/core/resources/l10n/messages_cs.properties +++ b/core/resources/l10n/messages_cs.properties @@ -16,11 +16,6 @@ debug.currentFile = messages_cs.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = Pr\u0161te se me neptejte -RocketActions.lbl.Youcanchangedefop = Mu\u017Eete zmenit vchoz operaci v nastaven. -RocketActions.showConfirmDialog.lbl1 = Chcete smazat oznacenou simulaci? -RocketActions.showConfirmDialog.lbl2 = Tuto operaci nelze vzt zpet. -RocketActions.showConfirmDialog.title = Sma\u017E simulace RocketActions.DelCompAct.Delete = Sma\u017E RocketActions.DelCompAct.ttip.Delete = Sma\u017E oznacenou komponentu. RocketActions.DelSimuAct.Delete = Sma\u017E diff --git a/core/resources/l10n/messages_de.properties b/core/resources/l10n/messages_de.properties index 0c68ebee2..908a48690 100644 --- a/core/resources/l10n/messages_de.properties +++ b/core/resources/l10n/messages_de.properties @@ -16,11 +16,6 @@ debug.currentFile = messages_de.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = Nicht wieder fragen -RocketActions.lbl.Youcanchangedefop = Die Standardaktion kann in den Einstellungen gendert werden. -RocketActions.showConfirmDialog.lbl1 = Simulationen lschen? -RocketActions.showConfirmDialog.lbl2 = Diese Aktion kann nicht rckgngig gemacht werden. -RocketActions.showConfirmDialog.title = Simulationen lschen RocketActions.DelCompAct.Delete = Lschen RocketActions.DelCompAct.ttip.Delete = Die ausgewhlte Komponente lschen. RocketActions.DelSimuAct.Delete = Lschen diff --git a/core/resources/l10n/messages_es.properties b/core/resources/l10n/messages_es.properties index 3d989be9b..30b830045 100644 --- a/core/resources/l10n/messages_es.properties +++ b/core/resources/l10n/messages_es.properties @@ -811,12 +811,6 @@ RocketActions.NewStageAct.Newstage = Nueva etapa RocketActions.NewStageAct.ttip.Newstage = A\u00f1adir una nueva etapa al dise\u00f1o del cohete RocketActions.PasteAct.Paste = Pegar RocketActions.PasteAct.ttip.Paste = Pegar al portapapeles -! RocketActions -RocketActions.checkbox.Donotaskmeagain = No volver a preguntarme -RocketActions.lbl.Youcanchangedefop = Puede modificar la operaci\u00f3n por defecto con sus preferencias -RocketActions.showConfirmDialog.lbl1 = \u00bfBorrar las simulaciones seleccionadas? -RocketActions.showConfirmDialog.lbl2 = Esta operaci\u00f3n no puede deshacerse. -RocketActions.showConfirmDialog.title = Borrar simulaciones RocketCfg.lbl.Comments = Comentarios: RocketCfg.lbl.Designer = Dise\u00f1ador: diff --git a/core/resources/l10n/messages_fr.properties b/core/resources/l10n/messages_fr.properties index 0eff3be76..2fd925ed2 100644 --- a/core/resources/l10n/messages_fr.properties +++ b/core/resources/l10n/messages_fr.properties @@ -802,12 +802,6 @@ RocketActions.NewStageAct.Newstage = Nouvel \u00E9tage RocketActions.NewStageAct.ttip.Newstage = Ajouter un nouvel \u00E9tage au projet. RocketActions.PasteAct.Paste = Coller RocketActions.PasteAct.ttip.Paste = Coller la pi\u00E8ce ou simulation pr\u00E9sente dans le presse papier dans le projet. -! RocketActions -RocketActions.checkbox.Donotaskmeagain = Ne plus me demander -RocketActions.lbl.Youcanchangedefop = Vous pouvez changer le mode op\u00E9ratoire par d\u00E9faut dans les pr\u00E9ferences. -RocketActions.showConfirmDialog.lbl1 = Supprimer les simulations s\u00E9lectionn\u00E9es? -RocketActions.showConfirmDialog.lbl2 = Cette op\u00E9ration n'est pas r\u00E9versible. -RocketActions.showConfirmDialog.title = Effacer les simulations RocketCfg.lbl.Comments = Commentaires: RocketCfg.lbl.Designer = Concepteur: diff --git a/core/resources/l10n/messages_it.properties b/core/resources/l10n/messages_it.properties index 55c33cc87..34980ad02 100644 --- a/core/resources/l10n/messages_it.properties +++ b/core/resources/l10n/messages_it.properties @@ -16,11 +16,6 @@ debug.currentFile = messages_it.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = Non chiedermelo piu' -RocketActions.lbl.Youcanchangedefop = Puoi cambiare le operazioni prestabilite in PREFERENZE. -RocketActions.showConfirmDialog.lbl1 = Cancello le simulazioni selezionate? -RocketActions.showConfirmDialog.lbl2 = Questa operazione non puo' essere annullata. -RocketActions.showConfirmDialog.title = Cancello Simulazioni RocketActions.DelCompAct.Delete = Cancella RocketActions.DelCompAct.ttip.Delete = Cancello il componente selezionato. RocketActions.DelSimuAct.Delete = Cancella diff --git a/core/resources/l10n/messages_ja.properties b/core/resources/l10n/messages_ja.properties index 947c2022a..45d5c4003 100644 --- a/core/resources/l10n/messages_ja.properties +++ b/core/resources/l10n/messages_ja.properties @@ -12,11 +12,6 @@ debug.currentFile = messages_ja.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = \u6B21\u56DE\u304B\u3089\u8868\u793A\u3057\u306A\u3044 -RocketActions.lbl.Youcanchangedefop = \u8A2D\u5B9A\u306E\u4E2D\u3067\u30C7\u30D5\u30A9\u30EB\u30C8\u306B\u5909\u66F4\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059 -RocketActions.showConfirmDialog.lbl1 = \u9078\u629E\u3057\u305F\u30B7\u30DF\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3\u3092\u6D88\u53BB\u3057\u307E\u3059\u304B\uFF1F -RocketActions.showConfirmDialog.lbl2 = \u6D88\u53BB\u3057\u305F\u3089\u5FA9\u5143\u3067\u304D\u307E\u305B\u3093 -RocketActions.showConfirmDialog.title = \u30B7\u30DF\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3\u306E\u524A\u9664 RocketActions.DelCompAct.Delete = \u524A\u9664 RocketActions.DelCompAct.ttip.Delete = \u9078\u629E\u3057\u305F\u90E8\u54C1\u306E\u524A\u9664 RocketActions.DelSimuAct.Delete = \u524A\u9664 diff --git a/core/resources/l10n/messages_nl.properties b/core/resources/l10n/messages_nl.properties index 8fb96b539..c44ec545e 100644 --- a/core/resources/l10n/messages_nl.properties +++ b/core/resources/l10n/messages_nl.properties @@ -18,11 +18,6 @@ debug.currentFile = messages_nl.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = Niet opnieuw vragen -RocketActions.lbl.Youcanchangedefop = U kan de standaardbewerking veranderen in de voorkeuren. -RocketActions.showConfirmDialog.lbl1 = Geselecteerde simulatie verwijderen? -RocketActions.showConfirmDialog.lbl2 = Deze bewerking kan niet ongedaan worden. -RocketActions.showConfirmDialog.title = Verwijder simulaties RocketActions.DelCompAct.Delete = Verwijder RocketActions.DelCompAct.ttip.Delete = Verwijder het geselecteerde onderdeel. RocketActions.DelSimuAct.Delete = Verwijder diff --git a/core/resources/l10n/messages_pl.properties b/core/resources/l10n/messages_pl.properties index 55577b105..cc4246b5f 100644 --- a/core/resources/l10n/messages_pl.properties +++ b/core/resources/l10n/messages_pl.properties @@ -16,11 +16,6 @@ debug.currentFile = messages_pl.properties ! RocketActions - RocketActions.checkbox.Donotaskmeagain = Nie pytaj ponownie - RocketActions.lbl.Youcanchangedefop = Domy\u015Bln\u0105 operacj\u0119 mo\u017Cna zmieni\u0107 w ustawieniach. - RocketActions.showConfirmDialog.lbl1 = Usun\u0105\u0107 zaznaczone symulacje? - RocketActions.showConfirmDialog.lbl2 = Tej operacji nie mo\u017Cna cofn\u0105\u0107. - RocketActions.showConfirmDialog.title = Usu\u0144 symulacje RocketActions.DelCompAct.Delete = Usu\u0144 RocketActions.DelCompAct.ttip.Delete = Usu\u0144 wybran\u0105 cz\u0119\u015B\u0107 RocketActions.DelSimuAct.Delete = Usu\u0144 diff --git a/core/resources/l10n/messages_pt.properties b/core/resources/l10n/messages_pt.properties index b9e7669c5..b5d9d3ee9 100644 --- a/core/resources/l10n/messages_pt.properties +++ b/core/resources/l10n/messages_pt.properties @@ -786,12 +786,6 @@ RocketActions.NewStageAct.Newstage = Novo est\u00e1gio RocketActions.NewStageAct.ttip.Newstage = Adicionar um novo est\u00e1gio ao projeto do foguete. RocketActions.PasteAct.Paste = Colar RocketActions.PasteAct.ttip.Paste = Cole o componente ou simula\u00e7\u00e3o na \u00e1rea da transfer\u00eancia para o projeto. -# RocketActions -RocketActions.checkbox.Donotaskmeagain = N\u00e3o me pergunte novamente -RocketActions.lbl.Youcanchangedefop = Voc\u00ea pode alterar a opera\u00e7\u00e3o padr\u00e3o em Prefer\u00eancias. -RocketActions.showConfirmDialog.lbl1 = Excluir as simula\u00e7\u00f5es selecionadas? -RocketActions.showConfirmDialog.lbl2 = Esta opera\u00e7\u00e3o n\u00e3o poder\u00e1 ser desfeita. -RocketActions.showConfirmDialog.title = Excluir simula\u00e7\u00f5es RocketCfg.lbl.Comments = Coment\u00e1rios: RocketCfg.lbl.Designer = Projetista: diff --git a/core/resources/l10n/messages_ru.properties b/core/resources/l10n/messages_ru.properties index 57de96180..f5622ac0c 100644 --- a/core/resources/l10n/messages_ru.properties +++ b/core/resources/l10n/messages_ru.properties @@ -16,11 +16,6 @@ debug.currentFile = messages_ru.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = \u0411\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C -RocketActions.lbl.Youcanchangedefop = \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445. -RocketActions.showConfirmDialog.lbl1 = \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044B? -RocketActions.showConfirmDialog.lbl2 = \u042D\u0442\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044E \u043D\u0435\u043B\u044C\u0437\u044F \u043E\u0442\u043C\u0435\u043D\u0438\u0442\u044C. -RocketActions.showConfirmDialog.title = \u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u043E\u0432 RocketActions.DelCompAct.Delete = \u0423\u0434\u0430\u043B\u0438\u0442\u044C RocketActions.DelCompAct.ttip.Delete = \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442. RocketActions.DelSimuAct.Delete = \u0423\u0434\u0430\u043B\u0438\u0442\u044C diff --git a/core/resources/l10n/messages_tr.properties b/core/resources/l10n/messages_tr.properties index 3c9c22979..f619a70c1 100644 --- a/core/resources/l10n/messages_tr.properties +++ b/core/resources/l10n/messages_tr.properties @@ -17,12 +17,6 @@ purposes) debug.currentFile = messages.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = Yeniden Tekrarlama -RocketActions.lbl.Youcanchangedefop = Hatal\u0131 \u00c7al\u0131\u015fmay\u0131 De\u011fi\u015ftirebilirsin -in the preferences. -RocketActions.showConfirmDialog.lbl1 = Se\u00e7ili sim\u00fclasyonlar\u0131 silmek ister misiniz? -RocketActions.showConfirmDialog.lbl2 = Bu \u00e7al\u0131\u015fma tamamlanmad\u0131. -RocketActions.showConfirmDialog.title = Sim\u00fclasyonlar\u0131 Sil RocketActions.DelCompAct.Delete = Sil RocketActions.DelCompAct.ttip.Delete = Se\u00e7ili par\u00e7ay\u0131 sil. RocketActions.DelSimuAct.Delete = Sil diff --git a/core/resources/l10n/messages_uk_UA.properties b/core/resources/l10n/messages_uk_UA.properties index 8a7e912d8..4fea26db2 100644 --- a/core/resources/l10n/messages_uk_UA.properties +++ b/core/resources/l10n/messages_uk_UA.properties @@ -18,11 +18,6 @@ debug.currentFile = messages.properties ! RocketActions -RocketActions.checkbox.Donotaskmeagain = \u0411\u0456\u043B\u044C\u0448\u0435 \u043D\u0435 \u043F\u0438\u0442\u0430\u0442\u0438 -RocketActions.lbl.Youcanchangedefop = \u0412\u0438 \u043C\u043E\u0436\u0435\u0442\u0435 \u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u0442\u0438\u043F\u043E\u0432\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044E \u0432 \u043E\u043F\u0446\u0438\u044F\u0445. -RocketActions.showConfirmDialog.lbl1 = \u0412\u0434\u0430\u043B\u0438\u0442\u0438 \u0432\u0438\u0431\u0440\u0430\u043D\u0443 \u0441\u0438\u043C\u0443\u043B\u044F\u0446\u0456\u044E? -RocketActions.showConfirmDialog.lbl2 = \u0426\u044F \u043E\u043F\u0435\u0440\u0430\u0446\u0456\u044F \u043D\u0435 \u043C\u043E\u0436\u0435 \u0431\u0443\u0442\u0438 \u0432\u0456\u0434\u043C\u0456\u043D\u0435\u043D\u0430. -RocketActions.showConfirmDialog.title = \u0412\u0434\u0430\u043B\u0438\u0442\u0438 \u0441\u0438\u043C\u0443\u043B\u044F\u0446\u0456\u044E RocketActions.DelCompAct.Delete = \u0412\u0434\u0430\u043B\u0438\u0442\u0438 RocketActions.DelCompAct.ttip.Delete = \u0412\u0434\u0430\u043B\u0438\u0442\u0438 \u0432\u0438\u0431\u0440\u0430\u043D\u0443 \u0447\u0430\u0441\u0442\u0438\u043D\u0443. RocketActions.DelSimuAct.Delete = \u0412\u0434\u0430\u043B\u0438\u0442\u0438 diff --git a/core/resources/l10n/messages_zh_CN.properties b/core/resources/l10n/messages_zh_CN.properties index b4bff94ed..05811ded0 100644 --- a/core/resources/l10n/messages_zh_CN.properties +++ b/core/resources/l10n/messages_zh_CN.properties @@ -875,12 +875,6 @@ RocketActions.NewStageAct.Newstage = \u65B0\u5EFA\u4E00\u7EA7 RocketActions.NewStageAct.ttip.Newstage = \u5728\u8BBE\u8BA1\u4E2D\u65B0\u5EFA\u4E00\u7EA7 RocketActions.PasteAct.Paste = \u7C98\u8D34 RocketActions.PasteAct.ttip.Paste = \u5C06\u526A\u8D34\u677F\u91CC\u7684\u90E8\u4EF6\u6216\u4EFF\u771F\u7C98\u8D34\u5230\u8BE5\u8BBE\u8BA1\u4E2D -! RocketActions -RocketActions.checkbox.Donotaskmeagain = \u4E0D\u518D\u63D0\u793A -RocketActions.lbl.Youcanchangedefop = \u4F60\u53EF\u4EE5\u4FEE\u6539\u7F3A\u7701\u8BBE\u7F6E -RocketActions.showConfirmDialog.lbl1 = \u5220\u9664\u9009\u5B9A\u4EFF\u771F? -RocketActions.showConfirmDialog.lbl2 = \u8BE5\u64CD\u4F5C\u65E0\u6CD5\u64A4\u9500 -RocketActions.showConfirmDialog.title = \u5220\u9664\u4EFF\u771F RocketCfg.lbl.Comments = \u6CE8\u91CA: RocketCfg.lbl.Designer = \u8BBE\u8BA1\u4EBA: diff --git a/core/src/net/sf/openrocket/document/OpenRocketDocument.java b/core/src/net/sf/openrocket/document/OpenRocketDocument.java index c1ea85f24..47160f751 100644 --- a/core/src/net/sf/openrocket/document/OpenRocketDocument.java +++ b/core/src/net/sf/openrocket/document/OpenRocketDocument.java @@ -383,12 +383,7 @@ public class OpenRocketDocument implements ComponentChangeListener, StateChangeL * @param simulation the simulation to be added */ public void addSimulation(Simulation simulation) { - simulations.add(simulation); - FlightConfigurationId simId = simulation.getId(); - if( !rocket.containsFlightConfigurationID( simId )){ - rocket.createFlightConfiguration(simId); - } - fireDocumentChangeEvent(new SimulationChangeEvent(simulation)); + addSimulation(simulation, simulations.size()); } /** @@ -399,6 +394,10 @@ public class OpenRocketDocument implements ComponentChangeListener, StateChangeL */ public void addSimulation(Simulation simulation, int n) { simulations.add(n, simulation); + FlightConfigurationId simId = simulation.getId(); + if( !rocket.containsFlightConfigurationID( simId )){ + rocket.createFlightConfiguration(simId); + } fireDocumentChangeEvent(new SimulationChangeEvent(simulation)); } diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/SimulationPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/SimulationPreferencesPanel.java index 92bb729b3..a45a68efc 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/SimulationPreferencesPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/SimulationPreferencesPanel.java @@ -41,7 +41,7 @@ public class SimulationPreferencesPanel extends PreferencesPanel { confirmDelete.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - preferences.setAutoRunSimulations(confirmDelete.isSelected()); + preferences.setConfirmSimDeletion(confirmDelete.isSelected()); } }); this.add(confirmDelete, "wrap, growx, sg combos "); diff --git a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java index 06e449c80..4c551e027 100644 --- a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java @@ -565,12 +565,12 @@ public class BasicFrame extends JFrame { editMenu.addSeparator(); - JMenu subMenu = new JMenu(trans.get("RocketActions.Select")); - editMenu.add(subMenu); + JMenu selectSubMenu = new JMenu(trans.get("RocketActions.Select")); + editMenu.add(selectSubMenu); item = new JMenuItem(actions.getSelectSameColorAction()); - subMenu.add(item); + selectSubMenu.add(item); item = new JMenuItem(actions.getDeselectAllAction()); - subMenu.add(item); + selectSubMenu.add(item); editMenu.addSeparator(); diff --git a/swing/src/net/sf/openrocket/gui/main/DesignPanel.java b/swing/src/net/sf/openrocket/gui/main/DesignPanel.java index b30a605ce..226c7f8c8 100644 --- a/swing/src/net/sf/openrocket/gui/main/DesignPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/DesignPanel.java @@ -61,13 +61,13 @@ public class DesignPanel extends JSplitPane { // Remove JTree key events that interfere with menu accelerators InputMap im = SwingUtilities.getUIInputMap(tree, JComponent.WHEN_FOCUSED); - im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, SHORTCUT_KEY), null); - im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, SHORTCUT_KEY), null); - im.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, SHORTCUT_KEY), null); - im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, SHORTCUT_KEY), null); - im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, SHORTCUT_KEY), null); - im.put(KeyStroke.getKeyStroke(KeyEvent.VK_O, SHORTCUT_KEY), null); - im.put(KeyStroke.getKeyStroke(KeyEvent.VK_N, SHORTCUT_KEY), null); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_O, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_N, SHORTCUT_KEY), "none"); // Highlight all child components of a stage/rocket/podset when it is selected tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { diff --git a/swing/src/net/sf/openrocket/gui/main/RocketActions.java b/swing/src/net/sf/openrocket/gui/main/RocketActions.java index 1d705db7d..aa90f9eaf 100644 --- a/swing/src/net/sf/openrocket/gui/main/RocketActions.java +++ b/swing/src/net/sf/openrocket/gui/main/RocketActions.java @@ -4,6 +4,7 @@ package net.sf.openrocket.gui.main; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; +import java.io.Serial; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -13,15 +14,13 @@ import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JButton; -import javax.swing.JCheckBox; import javax.swing.JOptionPane; -import javax.swing.JPanel; import javax.swing.KeyStroke; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; -import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; -import net.sf.openrocket.gui.components.StyledLabel; import net.sf.openrocket.gui.configdialog.ComponentConfigDialog; import net.sf.openrocket.gui.dialogs.ScaleDialog; import net.sf.openrocket.gui.util.Icons; @@ -34,7 +33,6 @@ import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.AxialStage; import net.sf.openrocket.startup.Application; -import net.sf.openrocket.startup.Preferences; import net.sf.openrocket.util.Color; import net.sf.openrocket.util.Pair; import org.slf4j.Logger; @@ -59,6 +57,7 @@ public class RocketActions { Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()); public static final KeyStroke EDIT_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_E, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()); + public static final KeyStroke DELETE_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0); private final OpenRocketDocument document; private final Rocket rocket; @@ -67,8 +66,6 @@ public class RocketActions { private final SimulationPanel simulationPanel; - private final RocketAction deleteComponentAction; - private final RocketAction deleteSimulationAction; private final RocketAction deleteAction; private final RocketAction cutAction; private final RocketAction copyAction; @@ -94,8 +91,6 @@ public class RocketActions { // Add action also to updateActions() this.deleteAction = new DeleteAction(); - this.deleteComponentAction = new DeleteComponentAction(); - this.deleteSimulationAction = new DeleteSimulationAction(); this.cutAction = new CutAction(); this.copyAction = new CopyAction(); this.pasteAction = new PasteAction(); @@ -107,10 +102,15 @@ public class RocketActions { this.moveUpAction = new MoveUpAction(); this.moveDownAction = new MoveDownAction(); - OpenRocketClipboard.addClipboardListener(this.pasteAction); + OpenRocketClipboard.addClipboardListener(new ClipboardListener() { + @Override + public void clipboardChanged() { + updateActions(); + } + }); updateActions(); - // Update all actions when tree selection or rocket changes + // Update all actions when tree selection, simulation selection or rocket changes selectionModel.addDocumentSelectionListener(new DocumentSelectionListener() { @Override @@ -118,6 +118,12 @@ public class RocketActions { updateActions(); } }); + simulationPanel.addSimulationTableListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + updateActions(); + } + }); document.getRocket().addComponentChangeListener(new ComponentChangeListener() { @Override public void componentChanged(ComponentChangeEvent e) { @@ -130,12 +136,13 @@ public class RocketActions { * Update the state of all of the actions. */ private void updateActions() { - deleteAction.clipboardChanged(); + simulationPanel.updateActions(); + editAction.clipboardChanged(); cutAction.clipboardChanged(); copyAction.clipboardChanged(); pasteAction.clipboardChanged(); + deleteAction.clipboardChanged(); duplicateAction.clipboardChanged(); - editAction.clipboardChanged(); selectSameColorAction.clipboardChanged(); deselectAllAction.clipboardChanged(); scaleAction.clipboardChanged(); @@ -143,16 +150,8 @@ public class RocketActions { moveDownAction.clipboardChanged(); } - - - public Action getDeleteComponentAction() { - return deleteAction; - } - public Action getDeleteSimulationAction() { - return deleteAction; - } public Action getDeleteAction() { return deleteAction; @@ -313,7 +312,7 @@ public class RocketActions { } private boolean isCopyable(List components) { - if (components == null || components.size() == 0) return false; + if (components == null || components.isEmpty()) return false; for (RocketComponent component : components) { if (!isCopyable(component)) return false; } @@ -409,43 +408,14 @@ public class RocketActions { private boolean isSimulationSelected() { Simulation[] selection = selectionModel.getSelectedSimulations(); - return (selection != null && selection.length > 0); - } - - - - private boolean verifyDeleteSimulation() { - boolean verify = Application.getPreferences().getBoolean(Preferences.CONFIRM_DELETE_SIMULATION, true); - if (verify) { - JPanel panel = new JPanel(new MigLayout()); - //// Do not ask me again - JCheckBox dontAsk = new JCheckBox(trans.get("RocketActions.checkbox.Donotaskmeagain")); - panel.add(dontAsk,"wrap"); - //// You can change the default operation in the preferences. - panel.add(new StyledLabel(trans.get("RocketActions.lbl.Youcanchangedefop"),-2)); - - int ret = JOptionPane.showConfirmDialog( - parentFrame, - new Object[] { - //// Delete the selected simulations? - trans.get("RocketActions.showConfirmDialog.lbl1"), - //// This operation cannot be undone. - trans.get("RocketActions.showConfirmDialog.lbl2"), - "", - panel }, - //// Delete simulations - trans.get("RocketActions.showConfirmDialog.title"), - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.WARNING_MESSAGE); - if (ret != JOptionPane.OK_OPTION) - return false; - - if (dontAsk.isSelected()) { - Application.getPreferences().putBoolean(Preferences.CONFIRM_DELETE_SIMULATION, false); + if (selection != null && selection.length > 0) { + List components = selectionModel.getSelectedComponents(); + if (components != null && !components.isEmpty()) { + throw new IllegalStateException("Both simulation and component selected"); } + return true; } - - return true; + return false; } @@ -517,130 +487,60 @@ public class RocketActions { public abstract void clipboardChanged(); } - /** - * Action that deletes the selected component. + * Action to edit the currently selected component. */ - private class DeleteComponentAction extends RocketAction { + private class EditAction extends RocketAction { + @Serial private static final long serialVersionUID = 1L; - public DeleteComponentAction() { - //// Delete - this.putValue(NAME, trans.get("RocketActions.DelCompAct.Delete")); - //// Delete the selected component. - this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.DelCompAct.ttip.Delete")); - this.putValue(MNEMONIC_KEY, KeyEvent.VK_D); -// this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)); - this.putValue(SMALL_ICON, Icons.EDIT_DELETE); - clipboardChanged(); - } - - @Override - public void actionPerformed(ActionEvent e) { - List components = new ArrayList<>(selectionModel.getSelectedComponents()); - if (components.size() == 0) return; - components.sort(Comparator.comparing(c -> c.getParent().getChildPosition(c))); - - if (components.size() == 1) { - document.addUndoPosition("Delete " + components.get(0).getComponentName()); - } else { - document.addUndoPosition("Delete components"); - } - - for (RocketComponent component : components) { - deleteComponent(component); - } - } - - private void deleteComponent(RocketComponent component) { - if (isDeletable(component)) { - ComponentConfigDialog.disposeDialog(); - - try { - component.getRocket().removeComponentChangeListener(ComponentConfigDialog.getDialog()); - - delete(component); - } catch (IllegalStateException ignored) { } - } - } - - @Override - public void clipboardChanged() { - this.setEnabled(isDeletable(selectionModel.getSelectedComponent())); - } - } - - - - /** - * Action that deletes the selected component. - */ - private class DeleteSimulationAction extends RocketAction { - private static final long serialVersionUID = 1L; - - public DeleteSimulationAction() { - //// Delete - this.putValue(NAME, trans.get("RocketActions.DelSimuAct.Delete")); - //// Delete the selected simulation. - this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.DelSimuAct.ttip.Delete")); - this.putValue(MNEMONIC_KEY, KeyEvent.VK_D); -// this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)); - this.putValue(SMALL_ICON, Icons.EDIT_DELETE); - clipboardChanged(); - } - - @Override - public void actionPerformed(ActionEvent e) { - Simulation[] sims = selectionModel.getSelectedSimulations(); - if (sims.length > 0) { - if (verifyDeleteSimulation()) { - for (Simulation s: sims) { - document.removeSimulation(s); - } - } - } - } - - @Override - public void clipboardChanged() { - this.setEnabled(isSimulationSelected()); - } - } - - - - /** - * Action that deletes the selected component. - */ - private class DeleteAction extends RocketAction { - private static final long serialVersionUID = 1L; - - public DeleteAction() { - //// Delete - this.putValue(NAME, trans.get("RocketActions.DelAct.Delete")); - //// Delete the selected component or simulation. - this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.DelAct.ttip.Delete")); - this.putValue(MNEMONIC_KEY, KeyEvent.VK_D); - this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)); - this.putValue(SMALL_ICON, Icons.EDIT_DELETE); + public EditAction() { + //// Edit + this.putValue(NAME, trans.get("RocketActions.EditAct.Edit")); + this.putValue(MNEMONIC_KEY, KeyEvent.VK_E); + this.putValue(ACCELERATOR_KEY, EDIT_KEY_STROKE); + this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.EditAct.ttip.Edit")); + this.putValue(SMALL_ICON, Icons.EDIT_EDIT); clipboardChanged(); } @Override public void actionPerformed(ActionEvent e) { if (isSimulationSelected()) { - deleteSimulationAction.actionPerformed(e); + simulationPanel.getEditSimulationAction().actionPerformed(e); parentFrame.selectTab(BasicFrame.SIMULATION_TAB); } else { - deleteComponentAction.actionPerformed(e); - parentFrame.selectTab(BasicFrame.DESIGN_TAB); + editComponents(); + // I wouldn't switch to the design tab here, because the user may be editing in the rocket view window } } + private void editComponents() { + List components = selectionModel.getSelectedComponents(); + + if (components == null || components.isEmpty()) { + return; + } + + if (ComponentConfigDialog.isDialogVisible()) + ComponentConfigDialog.disposeDialog(); + + RocketComponent component = components.get(0); + component.clearConfigListeners(); + if (components.size() > 1) { + for (int i = 1; i < components.size(); i++) { + RocketComponent listener = components.get(i); + listener.clearConfigListeners(); // Make sure all the listeners are cleared (should not be possible, but just in case) + component.addConfigListener(listener); + } + } + ComponentConfigDialog.showDialog(parentFrame, document, component); + } + @Override public void clipboardChanged() { - this.setEnabled(isDeletable(selectionModel.getSelectedComponent()) || - isSimulationSelected()); + List components = selectionModel.getSelectedComponents(); + this.setEnabled(!components.isEmpty() || simulationPanel.getEditSimulationAction().isEnabled()); } } @@ -650,14 +550,14 @@ public class RocketActions { * Action the cuts the selected component (copies to clipboard and deletes). */ private class CutAction extends RocketAction { + @Serial private static final long serialVersionUID = 1L; public CutAction() { //// Cut this.putValue(NAME, trans.get("RocketActions.CutAction.Cut")); - this.putValue(MNEMONIC_KEY, KeyEvent.VK_T); + this.putValue(MNEMONIC_KEY, KeyEvent.VK_T); // Use the 't' in Cut as mnemonic this.putValue(ACCELERATOR_KEY, CUT_KEY_STROKE); - //// Cut this component or simulation to the clipboard and remove from this design this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.CutAction.ttip.Cut")); this.putValue(SMALL_ICON, Icons.EDIT_CUT); clipboardChanged(); @@ -665,49 +565,49 @@ public class RocketActions { @Override public void actionPerformed(ActionEvent e) { + if (isSimulationSelected()) { + simulationPanel.getCutSimulationAction().actionPerformed(e); + parentFrame.selectTab(BasicFrame.SIMULATION_TAB); + } else { + cutComponents(); + } + } + + private void cutComponents() { List components = selectionModel.getSelectedComponents(); - if (components.size() > 0) { + if (!components.isEmpty()) { components = new ArrayList<>(components); fillInMissingSelections(components); components.sort(Comparator.comparing(c -> c.getParent() != null ? -c.getParent().getChildPosition(c) : 0)); } - Simulation[] sims = selectionModel.getSelectedSimulations(); - if (isDeletable(components) && isCopyable(components)) { - ComponentConfigDialog.disposeDialog(); - - if (components.size() == 1) { - document.addUndoPosition("Cut " + components.get(0).getComponentName()); - } else { - document.addUndoPosition("Cut components"); - } - - List copiedComponents = new LinkedList<>(copyComponentsMaintainParent(components)); - copiedComponents.sort(Comparator.comparing(c -> c.getParent() != null ? -c.getParent().getChildPosition(c) : 0)); - - OpenRocketClipboard.setClipboard(copiedComponents); - delete(components); - parentFrame.selectTab(BasicFrame.DESIGN_TAB); - } else if (isSimulationSelected()) { - - Simulation[] simsCopy = new Simulation[sims.length]; - for (int i=0; i < sims.length; i++) { - simsCopy[i] = sims[i].copy(); - } - OpenRocketClipboard.setClipboard(simsCopy); - - for (Simulation s: sims) { - document.removeSimulation(s); - } - parentFrame.selectTab(BasicFrame.SIMULATION_TAB); + if (!(isDeletable(components) && isCopyable(components))) { + return; } + + ComponentConfigDialog.disposeDialog(); + + if (components.size() == 1) { + document.addUndoPosition("Cut " + components.get(0).getComponentName()); + } else { + document.addUndoPosition("Cut components"); + } + + List copiedComponents = new LinkedList<>(copyComponentsMaintainParent(components)); + copiedComponents.sort(Comparator.comparing(c -> c.getParent() != null ? -c.getParent().getChildPosition(c) : 0)); + + OpenRocketClipboard.setClipboard(copiedComponents); + delete(components); + + parentFrame.selectTab(BasicFrame.DESIGN_TAB); } @Override public void clipboardChanged() { List components = selectionModel.getSelectedComponents(); - this.setEnabled((isDeletable(components) && isCopyable(components)) || isSimulationSelected()); + this.setEnabled((isDeletable(components) && isCopyable(components)) || + simulationPanel.getCutSimulationAction().isEnabled()); } } @@ -722,47 +622,47 @@ public class RocketActions { public CopyAction() { //// Copy this.putValue(NAME, trans.get("RocketActions.CopyAct.Copy")); + this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.CopyAct.ttip.Copy")); this.putValue(MNEMONIC_KEY, KeyEvent.VK_C); this.putValue(ACCELERATOR_KEY, COPY_KEY_STROKE); - //// Copy this component (and subcomponents) to the clipboard. - this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.CopyAct.ttip.Copy")); this.putValue(SMALL_ICON, Icons.EDIT_COPY); clipboardChanged(); } @Override public void actionPerformed(ActionEvent e) { + if (isSimulationSelected()) { + simulationPanel.getCopySimulationAction().actionPerformed(e); + parentFrame.selectTab(BasicFrame.SIMULATION_TAB); + } else { + copyComponents(); + } + } + + private void copyComponents() { List components = selectionModel.getSelectedComponents(); - if (components.size() > 0) { + if (!components.isEmpty()) { components = new ArrayList<>(components); fillInMissingSelections(components); components.sort(Comparator.comparing(c -> c.getParent() != null ? -c.getParent().getChildPosition(c) : 0)); } - Simulation[] sims = selectionModel.getSelectedSimulations(); - if (isCopyable(components)) { - List copiedComponents = new LinkedList<>(copyComponentsMaintainParent(components)); - copiedComponents.sort(Comparator.comparing(c -> c.getParent() != null ? -c.getParent().getChildPosition(c) : 0)); - - OpenRocketClipboard.setClipboard(copiedComponents); - parentFrame.selectTab(BasicFrame.DESIGN_TAB); - } else if (sims != null && sims.length > 0) { - Simulation[] simsCopy = new Simulation[sims.length]; - for (int i=0; i < sims.length; i++) { - simsCopy[i] = sims[i].copy(); - } - - OpenRocketClipboard.setClipboard(simsCopy); - simulationPanel.copySimulationValuesAction(); - parentFrame.selectTab(BasicFrame.SIMULATION_TAB); + if (!isCopyable(components)) { + return; } + + List copiedComponents = new LinkedList<>(copyComponentsMaintainParent(components)); + copiedComponents.sort(Comparator.comparing(c -> c.getParent() != null ? -c.getParent().getChildPosition(c) : 0)); + + OpenRocketClipboard.setClipboard(copiedComponents); + parentFrame.selectTab(BasicFrame.DESIGN_TAB); } @Override public void clipboardChanged() { this.setEnabled(isCopyable(selectionModel.getSelectedComponent()) || - isSimulationSelected()); + simulationPanel.getCopySimulationAction().isEnabled()); } } @@ -780,9 +680,8 @@ public class RocketActions { public PasteAction() { //// Paste this.putValue(NAME, trans.get("RocketActions.PasteAct.Paste")); - this.putValue(MNEMONIC_KEY, KeyEvent.VK_P); + this.putValue(MNEMONIC_KEY, KeyEvent.VK_V); this.putValue(ACCELERATOR_KEY, PASTE_KEY_STROKE); - //// Paste the component or simulation on the clipboard to the design. this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.PasteAct.ttip.Paste")); this.putValue(SMALL_ICON, Icons.EDIT_PASTE); clipboardChanged(); @@ -790,76 +689,67 @@ public class RocketActions { @Override public void actionPerformed(ActionEvent e) { - List components = new LinkedList<>(OpenRocketClipboard.getClipboardComponents()); - Simulation[] sims = OpenRocketClipboard.getClipboardSimulations(); - - if (components.size() > 0) { - ComponentConfigDialog.disposeDialog(); - - List pasted = new LinkedList<>(); - for (RocketComponent component : components) { - pasted.add(component.copy()); - } - - List> positions = getPastePositions(pasted); - - if (pasted.size() == 1) { - document.addUndoPosition("Paste " + pasted.get(0).getComponentName()); - } else { - document.addUndoPosition("Paste components"); - } - - List successfullyPasted = new LinkedList<>(); - for (int i = 0; i < pasted.size(); i++) { - if (positions.get(i) == null) { - JOptionPane.showMessageDialog(null, - String.format(trans.get("RocketActions.PasteAct.invalidPosition.msg"), - pasted.get(i).getComponentName()), - trans.get("RocketActions.PasteAct.invalidPosition.title"), JOptionPane.WARNING_MESSAGE); - } else { - RocketComponent parent = positions.get(i).getU(); - RocketComponent child = pasted.get(i); - if (parent != null && parent.isCompatible(child)) { - parent.addChild(child, positions.get(i).getV()); - successfullyPasted.add(pasted.get(i)); - } else { - log.warn("Pasted component {} is not compatible with {}", child, parent); - } - } - } - - selectionModel.setSelectedComponents(successfullyPasted); - - parentFrame.selectTab(BasicFrame.DESIGN_TAB); - - } else if (sims != null) { - - ArrayList copySims = new ArrayList(); - - for (Simulation s: sims) { - Simulation copy = s.duplicateSimulation(rocket); - String name = copy.getName(); - if (name.matches(OpenRocketDocument.SIMULATION_NAME_PREFIX + "[0-9]+ *")) { - copy.setName(document.getNextSimulationName()); - } - document.addSimulation(copy); - copySims.add(copy); - } - selectionModel.setSelectedSimulations(copySims.toArray(new Simulation[0])); - + if (isSimulationSelected()) { + simulationPanel.getPasteSimulationAction().actionPerformed(e); parentFrame.selectTab(BasicFrame.SIMULATION_TAB); + } else { + pasteComponents(); } } + private void pasteComponents() { + List components = new LinkedList<>(OpenRocketClipboard.getClipboardComponents()); + + if (components.isEmpty()) { + return; + } + ComponentConfigDialog.disposeDialog(); + + List pasted = new LinkedList<>(); + for (RocketComponent component : components) { + pasted.add(component.copy()); + } + + List> positions = getPastePositions(pasted); + + if (pasted.size() == 1) { + document.addUndoPosition("Paste " + pasted.get(0).getComponentName()); + } else { + document.addUndoPosition("Paste components"); + } + + List successfullyPasted = new LinkedList<>(); + for (int i = 0; i < pasted.size(); i++) { + if (positions.get(i) == null) { + JOptionPane.showMessageDialog(null, + String.format(trans.get("RocketActions.PasteAct.invalidPosition.msg"), + pasted.get(i).getComponentName()), + trans.get("RocketActions.PasteAct.invalidPosition.title"), JOptionPane.WARNING_MESSAGE); + } else { + RocketComponent parent = positions.get(i).getU(); + RocketComponent child = pasted.get(i); + if (parent != null && parent.isCompatible(child)) { + parent.addChild(child, positions.get(i).getV()); + successfullyPasted.add(pasted.get(i)); + } else { + log.warn("Pasted component {} is not compatible with {}", child, parent); + } + } + } + + selectionModel.setSelectedComponents(successfullyPasted); + parentFrame.selectTab(BasicFrame.DESIGN_TAB); + } + @Override public void clipboardChanged() { - this.setEnabled( - (getPastePositions(OpenRocketClipboard.getClipboardComponents()).size() > 0) || - (OpenRocketClipboard.getClipboardSimulations() != null)); + this.setEnabled(!getPastePositions(OpenRocketClipboard.getClipboardComponents()).isEmpty() || + simulationPanel.getPasteSimulationAction().isEnabled()); } } + /** * Action that duplicates the selected component. */ @@ -871,7 +761,6 @@ public class RocketActions { this.putValue(NAME, trans.get("RocketActions.DuplicateAct.Duplicate")); this.putValue(MNEMONIC_KEY, KeyEvent.VK_D); this.putValue(ACCELERATOR_KEY, DUPLICATE_KEY_STROKE); - //// Copy this component (and subcomponents) to the clipboard. this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.DuplicateAct.ttip.Duplicate")); this.putValue(SMALL_ICON, Icons.EDIT_DUPLICATE); clipboardChanged(); @@ -879,6 +768,15 @@ public class RocketActions { @Override public void actionPerformed(ActionEvent e) { + if (isSimulationSelected()) { + simulationPanel.getDuplicateSimulationAction().actionPerformed(e); + parentFrame.selectTab(BasicFrame.SIMULATION_TAB); + } else { + duplicateComponents(); + } + } + + private void duplicateComponents() { List components = selectionModel.getSelectedComponents(); List topComponents = new LinkedList<>(); // Components without a parent component in if (components.size() > 0) { @@ -893,136 +791,130 @@ public class RocketActions { topComponents.add(c); } } - Simulation[] sims = selectionModel.getSelectedSimulations(); - if (isCopyable(components)) { - if (ComponentConfigDialog.isDialogVisible()) - ComponentConfigDialog.disposeDialog(); - - List copiedComponents = copyComponentsMaintainParent(components); - OpenRocketClipboard.setClipboard(copiedComponents); - copiedComponents = new LinkedList<>(OpenRocketClipboard.getClipboardComponents()); - - List duplicateComponents = new LinkedList<>(); - for (RocketComponent component : copiedComponents) { - duplicateComponents.add(component.copy()); - } - - List> positions = new LinkedList<>(); - for (RocketComponent component : duplicateComponents) { - Pair pos; - if (RocketComponent.listContainsParent(duplicateComponents, component)) { - pos = getPastePosition(component, component.getParent()); - } else { - int compIdx = duplicateComponents.indexOf(component); - RocketComponent pasteParent = topComponents.get(compIdx).getParent(); - pos = getPastePosition(component, pasteParent); - } - positions.add(pos); - } - - if (duplicateComponents.size() == 1) { - document.addUndoPosition("Duplicate " + duplicateComponents.get(0).getComponentName()); - } else { - document.addUndoPosition("Duplicate components"); - } - - Collections.reverse(duplicateComponents); - Collections.reverse(positions); - - for (int i = 0; i < duplicateComponents.size(); i++) { - positions.get(i).getU().addChild(duplicateComponents.get(i), positions.get(i).getV()); - } - - selectionModel.setSelectedComponents(duplicateComponents); - - parentFrame.selectTab(BasicFrame.DESIGN_TAB); - } else if (sims != null && sims.length > 0) { - ArrayList copySims = new ArrayList(); - - // TODO: the undoing doesn't do anything... - if (sims.length == 1) { - document.addUndoPosition("Duplicate " + sims[0].getName()); - } else { - document.addUndoPosition("Duplicate simulations"); - } - - for (Simulation s: sims) { - Simulation copy = s.duplicateSimulation(rocket); - String name = copy.getName(); - if (name.matches(OpenRocketDocument.SIMULATION_NAME_PREFIX + "[0-9]+ *")) { - copy.setName(document.getNextSimulationName()); - } - document.addSimulation(copy); - copySims.add(copy); - } - - selectionModel.setSelectedSimulations(copySims.toArray(new Simulation[0])); - - parentFrame.selectTab(BasicFrame.SIMULATION_TAB); + if (!isCopyable(components)) { + return; } + + if (ComponentConfigDialog.isDialogVisible()) + ComponentConfigDialog.disposeDialog(); + + List copiedComponents = copyComponentsMaintainParent(components); + OpenRocketClipboard.setClipboard(copiedComponents); + copiedComponents = new LinkedList<>(OpenRocketClipboard.getClipboardComponents()); + + List duplicateComponents = new LinkedList<>(); + for (RocketComponent component : copiedComponents) { + duplicateComponents.add(component.copy()); + } + + List> positions = new LinkedList<>(); + for (RocketComponent component : duplicateComponents) { + Pair pos; + if (RocketComponent.listContainsParent(duplicateComponents, component)) { + pos = getPastePosition(component, component.getParent()); + } else { + int compIdx = duplicateComponents.indexOf(component); + RocketComponent pasteParent = topComponents.get(compIdx).getParent(); + pos = getPastePosition(component, pasteParent); + } + positions.add(pos); + } + + if (duplicateComponents.size() == 1) { + document.addUndoPosition("Duplicate " + duplicateComponents.get(0).getComponentName()); + } else { + document.addUndoPosition("Duplicate components"); + } + + Collections.reverse(duplicateComponents); + Collections.reverse(positions); + + for (int i = 0; i < duplicateComponents.size(); i++) { + positions.get(i).getU().addChild(duplicateComponents.get(i), positions.get(i).getV()); + } + + selectionModel.setSelectedComponents(duplicateComponents); + parentFrame.selectTab(BasicFrame.DESIGN_TAB); } @Override public void clipboardChanged() { this.setEnabled(isCopyable(selectionModel.getSelectedComponent()) || - isSimulationSelected()); + simulationPanel.getDuplicateSimulationAction().isEnabled()); } } - - + + /** - * Action to edit the currently selected component. + * Action that deletes the selected component. */ - private class EditAction extends RocketAction { + private class DeleteAction extends RocketAction { private static final long serialVersionUID = 1L; - public EditAction() { - //// Edit - this.putValue(NAME, trans.get("RocketActions.EditAct.Edit")); - this.putValue(MNEMONIC_KEY, KeyEvent.VK_E); - this.putValue(ACCELERATOR_KEY, EDIT_KEY_STROKE); - //// Edit the selected component. - this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.EditAct.ttip.Edit")); - this.putValue(SMALL_ICON, Icons.EDIT_EDIT); + public DeleteAction() { + //// Delete + this.putValue(NAME, trans.get("RocketActions.DelAct.Delete")); + //// Delete the selected component or simulation. + this.putValue(SHORT_DESCRIPTION, trans.get("RocketActions.DelAct.ttip.Delete")); + this.putValue(MNEMONIC_KEY, KeyEvent.VK_DELETE); + this.putValue(ACCELERATOR_KEY, DELETE_KEY_STROKE); + this.putValue(SMALL_ICON, Icons.EDIT_DELETE); clipboardChanged(); } @Override public void actionPerformed(ActionEvent e) { - List components = selectionModel.getSelectedComponents(); - Simulation[] sims = selectionModel.getSelectedSimulations(); + if (isSimulationSelected()) { + simulationPanel.getDeleteSimulationAction().actionPerformed(e); + parentFrame.selectTab(BasicFrame.SIMULATION_TAB); + } else { + deleteComponents(); + } + } - if (components.size() > 0) { - if (ComponentConfigDialog.isDialogVisible()) - ComponentConfigDialog.disposeDialog(); + private void deleteComponents() { + List components = new ArrayList<>(selectionModel.getSelectedComponents()); + if (components.size() == 0) return; + components.sort(Comparator.comparing(c -> c.getParent().getChildPosition(c))); - RocketComponent component = components.get(0); - component.clearConfigListeners(); - if (components.size() > 1) { - for (int i = 1; i < components.size(); i++) { - RocketComponent listener = components.get(i); - listener.clearConfigListeners(); // Make sure all the listeners are cleared (should not be possible, but just in case) - component.addConfigListener(listener); - } - } - ComponentConfigDialog.showDialog(parentFrame, document, component); - } else if (sims != null && sims.length > 0 && (simulationPanel != null)) { - simulationPanel.editSimulation(); + if (components.size() == 1) { + document.addUndoPosition("Delete " + components.get(0).getComponentName()); + } else { + document.addUndoPosition("Delete components"); + } + + for (RocketComponent component : components) { + deleteComponent(component); + } + + parentFrame.selectTab(BasicFrame.DESIGN_TAB); + } + + private void deleteComponent(RocketComponent component) { + if (isDeletable(component)) { + ComponentConfigDialog.disposeDialog(); + + try { + component.getRocket().removeComponentChangeListener(ComponentConfigDialog.getDialog()); + + delete(component); + } catch (IllegalStateException ignored) { } } } @Override public void clipboardChanged() { - List components = selectionModel.getSelectedComponents(); - - this.setEnabled(components.size() > 0 || isSimulationSelected()); + this.setEnabled(isDeletable(selectionModel.getSelectedComponent()) || + simulationPanel.getDeleteSimulationAction().isEnabled()); } } + + /** * Action to select all components with the same color as the currently selected component. */ @@ -1039,7 +931,7 @@ public class RocketActions { @Override public void actionPerformed(ActionEvent e) { List components = selectionModel.getSelectedComponents(); - if (components.size() == 0) { + if (components.isEmpty()) { return; } diff --git a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java index 9d0381d20..0bac65b69 100644 --- a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -17,10 +17,11 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; -import java.util.Arrays; +import java.io.Serial; import java.util.Comparator; import javax.swing.AbstractAction; +import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; @@ -81,6 +82,8 @@ import net.sf.openrocket.util.AlphanumComparator; import net.sf.openrocket.file.SimulationTableCSVExport; import net.sf.openrocket.utils.TableRowTraversalPolicy; +import static net.sf.openrocket.gui.main.BasicFrame.SHORTCUT_KEY; + @SuppressWarnings("serial") public class SimulationPanel extends JPanel { private static final Logger log = LoggerFactory.getLogger(SimulationPanel.class); @@ -110,7 +113,9 @@ public class SimulationPanel extends JPanel { private final JPopupMenu pm; private final SimulationAction editSimulationAction; - private final SimulationAction copyValuesSimulationAction; + private final SimulationAction cutSimulationAction; + private final SimulationAction copySimulationAction; + private final SimulationAction pasteSimulationAction; private final SimulationAction runSimulationAction; private final SimulationAction plotSimulationAction; private final SimulationAction duplicateSimulationAction; @@ -130,7 +135,9 @@ public class SimulationPanel extends JPanel { // Simulation actions SimulationAction newSimulationAction = new NewSimulationAction(); editSimulationAction = new EditSimulationAction(); - copyValuesSimulationAction = new CopyValuesSimulationAction(); + cutSimulationAction = new CutSimulationAction(); + copySimulationAction = new CopySimulationAction(); + pasteSimulationAction = new PasteSimulationAction(); runSimulationAction = new RunSimulationAction(); plotSimulationAction = new PlotSimulationAction(); duplicateSimulationAction = new DuplicateSimulationAction(); @@ -178,6 +185,7 @@ public class SimulationPanel extends JPanel { simulationTableModel = new SimulationTableModel(); simulationTable = new ColumnTable(simulationTableModel) { + @Serial private static final long serialVersionUID = -5799340181229735630L; }; ColumnTableRowSorter simulationTableSorter = new ColumnTableRowSorter(simulationTableModel); @@ -186,12 +194,22 @@ 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); + + // Unregister the default actions that would otherwise conflict with RocketActions and their acceleration keys + InputMap im = simulationTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_E, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, SHORTCUT_KEY), "none"); + im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, SHORTCUT_KEY), "none"); // Context menu pm = new JPopupMenu(); pm.add(editSimulationAction); - pm.add(copyValuesSimulationAction); + pm.add(cutSimulationAction); + pm.add(copySimulationAction); + pm.add(pasteSimulationAction); pm.add(duplicateSimulationAction); pm.add(deleteSimulationAction); pm.addSeparator(); @@ -252,7 +270,7 @@ public class SimulationPanel extends JPanel { public void valueChanged(ListSelectionEvent event) { if ((simulationTable.getSelectedRow() != previousSelectedRow) || (simulationTable.getSelectedRowCount() != previousSelectedRowCount)) { - updateButtonStates(); + updateActions(); previousSelectedRow = simulationTable.getSelectedRow(); previousSelectedRowCount = simulationTable.getSelectedRowCount(); } @@ -283,7 +301,55 @@ public class SimulationPanel extends JPanel { JScrollPane scrollpane = new JScrollPane(simulationTable); this.add(scrollpane, "spanx, grow, wrap rel"); - updateButtonStates(); + updateActions(); + } + + /** + * Returns the action used for editing selected simulations. + * @return the action used for editing selected simulations. + */ + public SimulationAction getEditSimulationAction() { + return editSimulationAction; + } + + /** + * Returns the action used for cutting selected simulations. + * @return the action used for cutting selected simulations. + */ + public SimulationAction getCutSimulationAction() { + return cutSimulationAction; + } + + /** + * Returns the action used for copying selected simulations. + * @return the action used for copying selected simulations. + */ + public SimulationAction getCopySimulationAction() { + return copySimulationAction; + } + + /** + * Returns the action used for pasting simulations. + * @return the action used for pasting simulations. + */ + public SimulationAction getPasteSimulationAction() { + return pasteSimulationAction; + } + + /** + * Returns the action used for duplicating selected simulations. + * @return the action used for duplicating selected simulations. + */ + public SimulationAction getDuplicateSimulationAction() { + return duplicateSimulationAction; + } + + /** + * Returns the action used for deleting selected simulations. + * @return the action used for deleting selected simulations. + */ + public SimulationAction getDeleteSimulationAction() { + return deleteSimulationAction; } public void updatePreviousSelection() { @@ -327,55 +393,62 @@ public class SimulationPanel extends JPanel { openDialog(true, sim); } - private void deleteSimulation() { - int[] selection = simulationTable.getSelectedRows(); - if (selection.length == 0) { + private void deleteSimulations(Simulation[] sims) { + if (sims == null || sims.length == 0) { return; } // Verify deletion - boolean verify = Application.getPreferences().getBoolean(Preferences.CONFIRM_DELETE_SIMULATION, true); - if (verify) { - - JPanel panel = new JPanel(new MigLayout()); - //// Do not ask me again - JCheckBox dontAsk = new JCheckBox(trans.get("simpanel.checkbox.donotask")); - panel.add(dontAsk, "wrap"); - //// You can change the default operation in the preferences. - panel.add(new StyledLabel(trans.get("simpanel.lbl.defpref"), -2)); - - int ret = JOptionPane.showConfirmDialog(SimulationPanel.this, - new Object[] { - //// Delete the selected simulations? - trans.get("simpanel.dlg.lbl.DeleteSim1"), - //// This operation cannot be undone. - trans.get("simpanel.dlg.lbl.DeleteSim2"), - "", - panel }, - //// Delete simulations - trans.get("simpanel.dlg.lbl.DeleteSim3"), - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.WARNING_MESSAGE); - if (ret != JOptionPane.OK_OPTION) - return; - - if (dontAsk.isSelected()) { - Application.getPreferences().putBoolean(Preferences.CONFIRM_DELETE_SIMULATION, false); - } + if (!verifyDeleteSimulation()) { + return; } // Delete simulations - for (int i = 0; i < selection.length; i++) { - selection[i] = simulationTable.convertRowIndexToModel(selection[i]); - } - Arrays.sort(selection); - for (int i = selection.length - 1; i >= 0; i--) { - document.removeSimulation(selection[i]); + for (Simulation sim : sims) { + document.removeSimulation(sim); } + simulationTableModel.fireTableDataChanged(); updatePreviousSelection(); takeTheSpotlight(); } + private void deleteSimulations() { + deleteSimulations(getSelectedSimulations()); + } + + private boolean verifyDeleteSimulation() { + boolean verify = Application.getPreferences().getConfirmSimDeletion(); + if (!verify) { + return true; + } + + JPanel panel = new JPanel(new MigLayout()); + //// Do not ask me again + JCheckBox dontAsk = new JCheckBox(trans.get("simpanel.checkbox.donotask")); + panel.add(dontAsk, "wrap"); + //// You can change the default operation in the preferences. + panel.add(new StyledLabel(trans.get("simpanel.lbl.defpref"), -2)); + + int ret = JOptionPane.showConfirmDialog(SimulationPanel.this, + new Object[] { + //// Delete the selected simulations? + trans.get("simpanel.dlg.lbl.DeleteSim1"), + //// This operation cannot be undone. + trans.get("simpanel.dlg.lbl.DeleteSim2"), + "", + panel }, + //// Delete simulations + trans.get("simpanel.dlg.lbl.DeleteSim3"), + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.WARNING_MESSAGE); + + if (dontAsk.isSelected()) { + Application.getPreferences().setConfirmSimDeletion(false); + } + + return ret == JOptionPane.OK_OPTION; + } + private void runSimulation() { Simulation[] sims = getSelectedSimulations(); if (sims == null) return; @@ -483,8 +556,28 @@ public class SimulationPanel extends JPanel { return sims; } + /** + * Full simulation copying + */ + public void copySimulationsAction() { + Simulation[] sims = getSelectedSimulations(); - public void copySimulationValuesAction() { + if (sims == null || sims.length == 0) + return; + + Simulation[] simsCopy = new Simulation[sims.length]; + for (int i=0; i < sims.length; i++) { + simsCopy[i] = sims[i].copy(); + } + + OpenRocketClipboard.setClipboard(simsCopy); + copySimulationValues(); + } + + /** + * Only copy the simulation table values to the clipboard. (not actual Simulation copying) + */ + public void copySimulationValues() { int numCols = simulationTable.getColumnCount(); int numRows = simulationTable.getSelectedRowCount(); int[] rowsSelected = simulationTable.getSelectedRows(); @@ -510,7 +603,8 @@ public class SimulationPanel extends JPanel { // Copy the values for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { - valuesStr.append(simulationTable.getValueAt(rowsSelected[i], j).toString()); + Object value = simulationTable.getValueAt(rowsSelected[i], j); + valuesStr.append(value == null ? "" : value.toString()); if (j < numCols-1) { valuesStr.append("\t"); } @@ -524,20 +618,51 @@ public class SimulationPanel extends JPanel { cb.setContents(sel, sel); } - private void duplicateSimulation() { - Simulation[] sims = getSelectedSimulations(); - if (sims == null) return; + private void pasteSimulationsAction() { + Simulation[] sims = OpenRocketClipboard.getClipboardSimulations(); + if (sims == null || sims.length == 0) { + return; + } + duplicateSimulation(sims, simulationTable.getSelectedRow() + 1); + } + + /** + * Duplicates the provided simulations at a certain index and selects them in the simulation table. + * @param sims The simulations to duplicate + * @param index The index to insert the simulations at (e.g. '1' to insert after the first simulation) + */ + public void duplicateSimulation(Simulation[] sims, int index) { + if (sims == null || sims.length == 0) return; + + // TODO: the undoing doesn't do anything... + if (sims.length == 1) { + document.addUndoPosition("Duplicate " + sims[0].getName()); + } else { + document.addUndoPosition("Duplicate simulations"); + } + + index = index >= 0 ? index : document.getSimulationCount(); + int newIndex = index; for (Simulation s: sims) { Simulation copy = s.duplicateSimulation(document.getRocket()); String name = copy.getName(); if (name.matches(OpenRocketDocument.SIMULATION_NAME_PREFIX + "[0-9]+ *")) { copy.setName(document.getNextSimulationName()); } - document.addSimulation(copy); + document.addSimulation(copy, newIndex); + newIndex++; // Ensure simulations are in the correct order } - simulationTable.getSelectionModel().setSelectionInterval(simulationTable.getRowCount()-sims.length,simulationTable.getRowCount()-1); + simulationTableModel.fireTableDataChanged(); + simulationTable.getSelectionModel().setSelectionInterval(index, newIndex-1); + } + /** + * Duplicates the provided simulations to the end and selects them in the simulation table. + * @param sims The simulations to duplicate. + */ + public void duplicateSimulation(Simulation[] sims) { + duplicateSimulation(sims, document.getSimulationCount()); } /** @@ -551,14 +676,24 @@ public class SimulationPanel extends JPanel { protected void doPopup(MouseEvent e) { pm.show(e.getComponent(), e.getX(), e.getY()); } + + /** + * Add a listener to the simulation table selection model. + * @param listener the listener to add. + */ + public void addSimulationTableListSelectionListener(ListSelectionListener listener) { + simulationTable.getSelectionModel().addListSelectionListener(listener); + } - private void updateButtonStates() { + public void updateActions() { editSimulationAction.updateEnabledState(); - copyValuesSimulationAction.updateEnabledState(); + cutSimulationAction.updateEnabledState(); + copySimulationAction.updateEnabledState(); + pasteSimulationAction.updateEnabledState(); + duplicateSimulationAction.updateEnabledState(); deleteSimulationAction.updateEnabledState(); runSimulationAction.updateEnabledState(); plotSimulationAction.updateEnabledState(); - duplicateSimulationAction.updateEnabledState(); simTableExportAction.updateEnabledState(); selectedSimsExportAction.updateEnabledState(); } @@ -692,7 +827,7 @@ public class SimulationPanel extends JPanel { } } - private abstract static class SimulationAction extends AbstractAction { + public abstract static class SimulationAction extends AbstractAction { private static final long serialVersionUID = 1L; public abstract void updateEnabledState(); @@ -718,7 +853,8 @@ public class SimulationPanel extends JPanel { class EditSimulationAction extends SimulationAction { public EditSimulationAction() { - putValue(NAME, trans.get("simpanel.pop.edit")); + this.putValue(NAME, trans.get("simpanel.pop.edit")); + this.putValue(SHORT_DESCRIPTION, trans.get("simpanel.pop.edit.ttip")); this.putValue(MNEMONIC_KEY, KeyEvent.VK_E); this.putValue(ACCELERATOR_KEY, RocketActions.EDIT_KEY_STROKE); this.putValue(SMALL_ICON, Icons.EDIT_EDIT); @@ -731,21 +867,28 @@ public class SimulationPanel extends JPanel { @Override public void updateEnabledState() { - setEnabled(simulationTable.getSelectedRowCount() > 0); + this.setEnabled(simulationTable.getSelectedRowCount() > 0); } } - 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); + class CutSimulationAction extends SimulationAction { + public CutSimulationAction() { + this.putValue(NAME, trans.get("simpanel.pop.cut")); + this.putValue(SHORT_DESCRIPTION, trans.get("simpanel.pop.cut.ttip")); + this.putValue(MNEMONIC_KEY, KeyEvent.VK_X); + this.putValue(ACCELERATOR_KEY, RocketActions.CUT_KEY_STROKE); + this.putValue(SMALL_ICON, Icons.EDIT_CUT); } @Override public void actionPerformed(ActionEvent e) { - copySimulationValuesAction(); + Simulation[] sims = getSelectedSimulations(); + + if (sims == null || sims.length == 0) + return; + + copySimulationsAction(); + deleteSimulations(sims); } @Override @@ -754,10 +897,93 @@ public class SimulationPanel extends JPanel { } } + class CopySimulationAction extends SimulationAction { + public CopySimulationAction() { + this.putValue(NAME, trans.get("simpanel.pop.copy")); + this.putValue(SHORT_DESCRIPTION, trans.get("simpanel.pop.copy.ttip")); + 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) { + copySimulationsAction(); + } + + @Override + public void updateEnabledState() { + this.setEnabled(simulationTable.getSelectedRowCount() > 0); + } + } + + class PasteSimulationAction extends SimulationAction { + public PasteSimulationAction() { + this.putValue(NAME, trans.get("simpanel.pop.paste")); + this.putValue(SHORT_DESCRIPTION, trans.get("simpanel.pop.paste.ttip")); + this.putValue(MNEMONIC_KEY, KeyEvent.VK_V); + this.putValue(ACCELERATOR_KEY, RocketActions.PASTE_KEY_STROKE); + this.putValue(SMALL_ICON, Icons.EDIT_PASTE); + } + + @Override + public void actionPerformed(ActionEvent e) { + pasteSimulationsAction(); + } + + @Override + public void updateEnabledState() { + this.setEnabled((simulationTable.getSelectedRowCount() > 0) && + (OpenRocketClipboard.getClipboardSimulations() != null) && (OpenRocketClipboard.getClipboardSimulations().length > 0)); + } + } + + class DuplicateSimulationAction extends SimulationAction { + public DuplicateSimulationAction() { + this.putValue(NAME, trans.get("simpanel.pop.duplicate")); + this.putValue(SHORT_DESCRIPTION, trans.get("simpanel.pop.duplicate.ttip")); + this.putValue(MNEMONIC_KEY, KeyEvent.VK_D); + this.putValue(ACCELERATOR_KEY, RocketActions.DUPLICATE_KEY_STROKE); + this.putValue(SMALL_ICON, Icons.EDIT_DUPLICATE); + } + + @Override + public void actionPerformed(ActionEvent e) { + duplicateSimulation(getSelectedSimulations()); + } + + @Override + public void updateEnabledState() { + this.setEnabled(simulationTable.getSelectedRowCount() > 0); + } + } + + class DeleteSimulationAction extends SimulationAction { + public DeleteSimulationAction() { + this.putValue(NAME, trans.get("simpanel.pop.delete")); + this.putValue(SHORT_DESCRIPTION, trans.get("simpanel.pop.delete.ttip")); + this.putValue(MNEMONIC_KEY, KeyEvent.VK_DELETE); + this.putValue(ACCELERATOR_KEY, RocketActions.DELETE_KEY_STROKE); + this.putValue(SMALL_ICON, Icons.EDIT_DELETE); + } + + @Override + public void actionPerformed(ActionEvent e) { + deleteSimulations(); + } + + @Override + public void updateEnabledState() { + this.setEnabled(simulationTable.getSelectedRowCount() > 0); + } + } + + class RunSimulationAction extends SimulationAction { public RunSimulationAction() { - putValue(NAME, trans.get("simpanel.pop.run")); - putValue(SMALL_ICON, Icons.SIM_RUN); + this.putValue(NAME, trans.get("simpanel.pop.run")); + this.putValue(SHORT_DESCRIPTION, trans.get("simpanel.pop.run.ttip")); + this.putValue(SMALL_ICON, Icons.SIM_RUN); } @Override @@ -767,26 +993,25 @@ public class SimulationPanel extends JPanel { @Override public void updateEnabledState() { - setEnabled(simulationTable.getSelectedRowCount() > 0); + this.setEnabled(simulationTable.getSelectedRowCount() > 0); } } - class DeleteSimulationAction extends SimulationAction { - public DeleteSimulationAction() { - putValue(NAME, trans.get("simpanel.pop.delete")); - putValue(MNEMONIC_KEY, KeyEvent.VK_D); - putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)); - putValue(SMALL_ICON, Icons.EDIT_DELETE); + class PlotSimulationAction extends SimulationAction { + public PlotSimulationAction() { + this.putValue(NAME, trans.get("simpanel.pop.plot")); + this.putValue(SHORT_DESCRIPTION, trans.get("simpanel.pop.plot.ttip")); + this.putValue(SMALL_ICON, Icons.SIM_PLOT); } @Override public void actionPerformed(ActionEvent e) { - deleteSimulation(); + plotSimulation(); } @Override public void updateEnabledState() { - setEnabled(simulationTable.getSelectedRowCount() > 0); + this.setEnabled(simulationTable.getSelectedRowCount() == 1); } } @@ -796,8 +1021,8 @@ public class SimulationPanel extends JPanel { class ExportSimulationTableAsCSVAction extends SimulationAction { public ExportSimulationTableAsCSVAction() { - putValue(NAME, trans.get("simpanel.pop.exportSimTableToCSV")); - putValue(SMALL_ICON, Icons.SIM_TABLE_EXPORT); + this.putValue(NAME, trans.get("simpanel.pop.exportSimTableToCSV")); + this.putValue(SMALL_ICON, Icons.SIM_TABLE_EXPORT); } @Override @@ -807,7 +1032,7 @@ public class SimulationPanel extends JPanel { @Override public void updateEnabledState() { - setEnabled(simulationTableModel != null && simulationTableModel.getRowCount() > 0); + this.setEnabled(simulationTableModel != null && simulationTableModel.getRowCount() > 0); } } @@ -818,8 +1043,8 @@ public class SimulationPanel extends JPanel { class ExportSelectedSimulationsAsCSVAction extends SimulationAction { public ExportSelectedSimulationsAsCSVAction() { - putValue(NAME, trans.get("simpanel.pop.exportSelectedSimsToCSV")); - putValue(SMALL_ICON, Icons.SIM_TABLE_EXPORT); + this.putValue(NAME, trans.get("simpanel.pop.exportSelectedSimsToCSV")); + this.putValue(SMALL_ICON, Icons.SIM_TABLE_EXPORT); } @Override @@ -829,47 +1054,13 @@ public class SimulationPanel extends JPanel { @Override public void updateEnabledState() { - setEnabled(simulationTableModel != null && simulationTableModel.getRowCount() > 0 && + this.setEnabled(simulationTableModel != null && simulationTableModel.getRowCount() > 0 && simulationTable.getSelectedRowCount() > 0); } } - class PlotSimulationAction extends SimulationAction { - public PlotSimulationAction() { - putValue(NAME, trans.get("simpanel.pop.plot")); - putValue(SMALL_ICON, Icons.SIM_PLOT); - } - @Override - public void actionPerformed(ActionEvent e) { - plotSimulation(); - } - - @Override - public void updateEnabledState() { - setEnabled(simulationTable.getSelectedRowCount() == 1); - } - } - - class DuplicateSimulationAction extends SimulationAction { - public DuplicateSimulationAction() { - putValue(NAME, trans.get("simpanel.pop.duplicate")); - putValue(MNEMONIC_KEY, KeyEvent.VK_D); - putValue(ACCELERATOR_KEY, RocketActions.DUPLICATE_KEY_STROKE); - putValue(SMALL_ICON, Icons.EDIT_DUPLICATE); - } - - @Override - public void actionPerformed(ActionEvent e) { - duplicateSimulation(); - } - - @Override - public void updateEnabledState() { - setEnabled(simulationTable.getSelectedRowCount() > 0); - } - } public static class CellTransferable implements Transferable { @@ -1217,7 +1408,7 @@ public class SimulationPanel extends JPanel { return; } if (previousSelection == null || previousSelection.length == 0) { - simulationTable.setRowSelectionInterval(0, 0); + simulationTable.getSelectionModel().setSelectionInterval(0, 0); } else { simulationTable.clearSelection(); for (int row : previousSelection) { @@ -1227,5 +1418,6 @@ public class SimulationPanel extends JPanel { simulationTable.addRowSelectionInterval(row, row); } } + updateActions(); } }