From 407fa8162c1ea47ff40d9cd1251e0cb289545e3a Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 11 Jul 2023 15:46:35 +0200 Subject: [PATCH] Open dialog to save design information when saving the file --- core/resources/l10n/messages.properties | 3 + .../sf/openrocket/startup/Preferences.java | 16 +++ .../configdialog/RocketComponentConfig.java | 35 +++--- .../gui/configdialog/SaveDesignInfoPanel.java | 104 ++++++++++++++++++ .../sf/openrocket/gui/main/BasicFrame.java | 23 ++++ 5 files changed, 166 insertions(+), 15 deletions(-) create mode 100644 swing/src/net/sf/openrocket/gui/configdialog/SaveDesignInfoPanel.java diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index d2ea4caed..f9abe5920 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -95,7 +95,10 @@ BasicFrame.WarningDialog.title = Warnings while opening file BasicFrame.WarningDialog.saving.title = Warnings while opening file BasicFrame.ErrorWarningDialog.txt1 = Please correct the errors. BasicFrame.ErrorWarningDialog.saving.title = Errors/Warnings while saving file +BasicFrame.lbl.SaveRocketInfo = Save Design Info +! SaveDesignInfoPanel +SaveDesignInfoPanel.lbl.FillInInfo = (Optional) Fill in the design information for this file ! General error messages used in multiple contexts error.fileExists.title = File exists diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java index 382bfc438..02d272f03 100644 --- a/core/src/net/sf/openrocket/startup/Preferences.java +++ b/core/src/net/sf/openrocket/startup/Preferences.java @@ -82,6 +82,7 @@ public abstract class Preferences implements ChangeSource { private static final String AUTO_OPEN_LAST_DESIGN = "AutoOpenLastDesign"; private static final String OPEN_LEFTMOST_DESIGN_TAB = "OpenLeftmostDesignTab"; private static final String SHOW_DISCARD_CONFIRMATION = "IgnoreDiscardEditingWarning"; + private static final String SHOW_SAVE_ROCKET_INFO = "ShowSaveRocketInfo"; private static final String SHOW_DISCARD_SIMULATION_CONFIRMATION = "IgnoreDiscardSimulationEditingWarning"; private static final String SHOW_DISCARD_PREFERENCES_CONFIRMATION = "IgnoreDiscardPreferencesWarning"; public static final String MARKER_STYLE_ICON = "MarkerStyleIcon"; @@ -592,6 +593,21 @@ public abstract class Preferences implements ChangeSource { this.putBoolean(SHOW_DISCARD_CONFIRMATION, enabled); } + /** + * Returns whether a 'save rocket information' dialog should be shown after saving a new design file. + * @return true if the 'save rocket information' dialog should be shown. + */ + public final boolean isShowSaveRocketInfo() { + return this.getBoolean(SHOW_SAVE_ROCKET_INFO, true); + } + + /** + * Enable/Disable showing a 'save rocket information' dialog after saving a new design file. + * @return true if the 'save rocket information' dialog should be shown. + */ + public final void setShowSaveRocketInfo(boolean enabled) { + this.putBoolean(SHOW_SAVE_ROCKET_INFO, enabled); + } /** * Answer if a confirmation dialog should be shown when canceling a simulation config operation. * diff --git a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java index 045e88be7..fb9dc9a95 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java @@ -39,7 +39,6 @@ import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.gui.SpinnerEditor; import net.sf.openrocket.gui.adaptors.BooleanModel; import net.sf.openrocket.gui.adaptors.DoubleModel; -import net.sf.openrocket.gui.adaptors.IntegerModel; import net.sf.openrocket.gui.adaptors.PresetModel; import net.sf.openrocket.gui.adaptors.TextComponentSelectionKeyListener; import net.sf.openrocket.gui.components.BasicSlider; @@ -70,7 +69,7 @@ public class RocketComponentConfig extends JPanel { protected final OpenRocketDocument document; protected final RocketComponent component; protected final JTabbedPane tabbedPane; - protected final ComponentConfigDialog parent; + protected final JDialog parent; protected boolean isNewComponent = false; // Checks whether this config dialog is editing an existing component, or a new one private final List invalidatables = new ArrayList(); @@ -87,7 +86,7 @@ public class RocketComponentConfig extends JPanel { private DescriptionArea componentInfo; private IconToggleButton infoBtn; - private JPanel buttonPanel; + protected JPanel buttonPanel; protected JButton okButton; protected JButton cancelButton; private AppearancePanel appearancePanel = null; @@ -103,11 +102,7 @@ public class RocketComponentConfig extends JPanel { this.document = document; this.component = component; - if (parent instanceof ComponentConfigDialog) { - this.parent = (ComponentConfigDialog) parent; - } else { - this.parent = null; - } + this.parent = parent; // Check the listeners for the same type and massive status allSameType = true; @@ -195,7 +190,7 @@ public class RocketComponentConfig extends JPanel { /** * Add a section to the component configuration dialog that displays information about the component. */ - private void addComponentInfo(JPanel buttonPanel) { + protected void addComponentInfo(JPanel buttonPanel) { // Don't add the info panel if this is a multi-comp edit List listeners = component.getConfigListeners(); if (listeners != null && listeners.size() > 0) { @@ -274,14 +269,14 @@ public class RocketComponentConfig extends JPanel { @Override public void actionPerformed(ActionEvent arg0) { // Don't do anything on cancel if you are editing an existing component, and it is not modified - if (!isNewComponent && parent != null && !parent.isModified()) { - ComponentConfigDialog.disposeDialog(); + if (!isNewComponent && parent != null && (parent instanceof ComponentConfigDialog && !((ComponentConfigDialog) parent).isModified())) { + disposeDialog(); return; } // Apply the cancel operation if set to auto discard in preferences if (!preferences.isShowDiscardConfirmation()) { ComponentConfigDialog.clearConfigListeners = false; // Undo action => config listeners of new component will be cleared - ComponentConfigDialog.disposeDialog(); + disposeDialog(); document.undo(); return; } @@ -292,7 +287,7 @@ public class RocketComponentConfig extends JPanel { trans.get("RocketCompCfg.CancelOperation.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (resultYesNo == JOptionPane.YES_OPTION) { ComponentConfigDialog.clearConfigListeners = false; // Undo action => config listeners of new component will be cleared - ComponentConfigDialog.disposeDialog(); + disposeDialog(); document.undo(); } } @@ -305,7 +300,7 @@ public class RocketComponentConfig extends JPanel { okButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { - ComponentConfigDialog.disposeDialog(); + disposeDialog(); } }); buttonPanel.add(okButton); @@ -315,7 +310,17 @@ public class RocketComponentConfig extends JPanel { this.add(buttonPanel, "newline, spanx, growx"); } - private JPanel createCancelOperationContent() { + protected void disposeDialog() { + if (parent != null) { + if (parent instanceof ComponentConfigDialog) { + ComponentConfigDialog.disposeDialog(); + } else { + parent.dispose(); + } + } + } + + protected JPanel createCancelOperationContent() { JPanel panel = new JPanel(new MigLayout()); String msg = isNewComponent ? trans.get("RocketCompCfg.CancelOperation.msg.undoAdd") : trans.get("RocketCompCfg.CancelOperation.msg.discardChanges"); diff --git a/swing/src/net/sf/openrocket/gui/configdialog/SaveDesignInfoPanel.java b/swing/src/net/sf/openrocket/gui/configdialog/SaveDesignInfoPanel.java new file mode 100644 index 000000000..ec53c60bf --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/configdialog/SaveDesignInfoPanel.java @@ -0,0 +1,104 @@ +package net.sf.openrocket.gui.configdialog; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.gui.components.StyledLabel; +import net.sf.openrocket.gui.widgets.SelectColorButton; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.startup.Preferences; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * This class is used to create a panel that is shown when a new design file is saved. It is used to fill in the design + * information for the file. + */ +public class SaveDesignInfoPanel extends RocketConfig { + private static final Translator trans = Application.getTranslator(); + private static final Preferences preferences = Application.getPreferences(); + + public SaveDesignInfoPanel(OpenRocketDocument d, RocketComponent c, JDialog parent) { + super(d, c, parent); + + // (Optional) Fill in the design information for this file + StyledLabel label = new StyledLabel(trans.get("SaveDesignInfoPanel.lbl.FillInInfo"), StyledLabel.Style.BOLD); + this.add(label, "spanx, wrap para", 0); + } + + @Override + protected void addButtons(JButton... buttons) { + if (buttonPanel != null) { + this.remove(buttonPanel); + } + + buttonPanel = new JPanel(new MigLayout("fill, ins 5, hidemode 3")); + + //// Don't show this dialog again + JCheckBox dontShowAgain = new JCheckBox(trans.get("welcome.dlg.checkbox.dontShowAgain")); + dontShowAgain.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + preferences.setShowSaveRocketInfo(!((JCheckBox) e.getSource()).isSelected()); + } + }); + buttonPanel.add(dontShowAgain, "gapright 10, growx"); + + //// Cancel button + this.cancelButton = new SelectColorButton(trans.get("dlg.but.cancel")); + this.cancelButton.setToolTipText(trans.get("RocketCompCfg.btn.Cancel.ttip")); + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + // Don't do anything on cancel if you are editing an existing component, and it is not modified + if (!isNewComponent && parent != null && (parent instanceof ComponentConfigDialog && !((ComponentConfigDialog) parent).isModified())) { + disposeDialog(); + return; + } + // Apply the cancel operation if set to auto discard in preferences + if (!preferences.isShowDiscardConfirmation()) { + ComponentConfigDialog.clearConfigListeners = false; // Undo action => config listeners of new component will be cleared + disposeDialog(); + document.undo(); + return; + } + + // Yes/No dialog: Are you sure you want to discard your changes? + JPanel msg = createCancelOperationContent(); + int resultYesNo = JOptionPane.showConfirmDialog(SaveDesignInfoPanel.this, msg, + trans.get("RocketCompCfg.CancelOperation.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (resultYesNo == JOptionPane.YES_OPTION) { + ComponentConfigDialog.clearConfigListeners = false; // Undo action => config listeners of new component will be cleared + disposeDialog(); + document.undo(); + } + } + }); + buttonPanel.add(cancelButton, "split 2, right, gapleft 30lp"); + + //// Ok button + this.okButton = new SelectColorButton(trans.get("dlg.but.ok")); + this.okButton.setToolTipText(trans.get("RocketCompCfg.btn.OK.ttip")); + okButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + disposeDialog(); + } + }); + buttonPanel.add(okButton); + + this.add(buttonPanel, "newline, spanx, growx"); + } + + @Override + public void updateFields() { + // Do nothing + } +} diff --git a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java index d114b64f8..06e449c80 100644 --- a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java @@ -49,6 +49,7 @@ import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.gui.configdialog.SaveDesignInfoPanel; import net.sf.openrocket.gui.dialogs.ErrorWarningDialog; import net.sf.openrocket.logging.ErrorSet; import net.sf.openrocket.logging.WarningSet; @@ -1596,6 +1597,9 @@ public class BasicFrame extends JFrame { * @return true if the file was saved, false otherwise */ private boolean saveAsAction() { + // Open dialog for saving rocket info + showSaveRocketInfoDialog(); + File file = openFileSaveAsDialog(FileType.OPENROCKET); if (file == null) { return false; @@ -1610,6 +1614,25 @@ public class BasicFrame extends JFrame { return result; } + private void showSaveRocketInfoDialog() { + if (!prefs.isShowSaveRocketInfo()) { + return; + } + + // Select the rocket in the component tree to indicate to users that they can edit the rocket info by editing the rocket + setSelectedComponent(rocket); + + // Open the save rocket info + JDialog dialog = new JDialog(); + SaveDesignInfoPanel panel = new SaveDesignInfoPanel(document, rocket, dialog); + dialog.setContentPane(panel); + dialog.pack(); + dialog.setTitle(trans.get("BasicFrame.lbl.SaveRocketInfo")); + dialog.setModal(true); + dialog.setLocationRelativeTo(null); + dialog.setVisible(true); + } + /** * Perform the writing of the design to the given file in OpenRocket format.