[#2226] Add Ok/Cancel buttons in preference dialog

This commit is contained in:
SiboVG 2023-06-01 13:32:22 +02:00
parent 80558fbf43
commit 5af6827e92
5 changed files with 185 additions and 22 deletions

View File

@ -380,6 +380,8 @@ pref.dlg.DescriptionArea.Adddirectories = Add directories, RASP motor files (*.e
PreferencesDialog.lbl.language = Interface language:
PreferencesDialog.languages.default = System default
PreferencesDialog.lbl.languageEffect = The language will change the next time you start OpenRocket.
PreferencesDialog.CancelOperation.title = Discard Preference Changes
PreferencesDialog.CancelOperation.msg.discardChanges = <html>Are you sure you want to <b>discard the preference changes</b>?</html>
generalprefs.lbl.language = Interface language
generalprefs.languages.default = System default

View File

@ -79,6 +79,7 @@ public abstract class Preferences implements ChangeSource {
private static final String OPEN_LEFTMOST_DESIGN_TAB = "OpenLeftmostDesignTab";
private static final String SHOW_DISCARD_CONFIRMATION = "IgnoreDiscardEditingWarning";
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 = "MARKER_STYLE_ICON";
private static final String SHOW_MARKERS = "SHOW_MARKERS";
private static final String SHOW_RASAERO_FORMAT_WARNING = "SHOW_RASAERO_FORMAT_WARNING";
@ -582,6 +583,22 @@ public abstract class Preferences implements ChangeSource {
this.putBoolean(SHOW_DISCARD_SIMULATION_CONFIRMATION, enabled);
}
/**
* Answer if a confirmation dialog should be shown when canceling preferences changes.
*
* @return true if the confirmation dialog should be shown.
*/
public final boolean isShowDiscardPreferencesConfirmation() {
return this.getBoolean(SHOW_DISCARD_PREFERENCES_CONFIRMATION, true);
}
/**
* Enable/Disable showing a confirmation warning when canceling preferences changes.
*/
public final void setShowDiscardPreferencesConfirmation(boolean enabled) {
this.putBoolean(SHOW_DISCARD_PREFERENCES_CONFIRMATION, enabled);
}
/**
* Answer if the always open leftmost tab is enabled.
*

View File

@ -1,21 +1,31 @@
package net.sf.openrocket.gui.dialogs.preferences;
import java.awt.Dialog;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.prefs.BackingStoreException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.main.BasicFrame;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.PreferencesExporter;
import net.sf.openrocket.gui.util.PreferencesImporter;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
@ -35,6 +45,9 @@ public class PreferencesDialog extends JDialog {
private BasicFrame parentFrame;
private boolean storePreferences = true;
private File initPrefsFile = null;
private PreferencesDialog(BasicFrame parent) {
// // Preferences
super(parent, trans.get("pref.dlg.title.Preferences"),
@ -42,6 +55,9 @@ public class PreferencesDialog extends JDialog {
this.parentFrame = parent;
// First store the initial preferences
initPrefsFile = storeInitPreferences();
JPanel panel = new JPanel(new MigLayout("fill, gap unrel", "[grow]",
"[grow][]"));
@ -78,16 +94,42 @@ public class PreferencesDialog extends JDialog {
// tabbedPane.addTab(trans.get("pref.dlg.tab.Colors"),
// new DisplayPreferencesPanel());
// Close button
JButton close = new SelectColorButton(trans.get("dlg.but.close"));
close.addActionListener(new ActionListener() {
//// Cancel button
JButton cancelButton = new SelectColorButton(trans.get("dlg.but.cancel"));
cancelButton.setToolTipText(trans.get("SimulationEditDialog.btn.Cancel.ttip"));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
PreferencesDialog.this.setVisible(false);
PreferencesDialog.this.dispose();
public void actionPerformed(ActionEvent e) {
// Apply the cancel operation if set to auto discard in preferences
if (!preferences.isShowDiscardPreferencesConfirmation()) {
closeDialog(false);
return;
}
// Yes/No dialog: Are you sure you want to discard your changes?
JPanel msg = createCancelOperationContent();
int resultYesNo = JOptionPane.showConfirmDialog(PreferencesDialog.this, msg,
trans.get("PreferencesDialog.CancelOperation.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if (resultYesNo == JOptionPane.YES_OPTION) {
closeDialog(false);
}
}
});
panel.add(close, "span, right, tag close");
panel.add(cancelButton, "span, split 2, right, tag cancel");
//// Ok button
JButton okButton = new SelectColorButton(trans.get("dlg.but.ok"));
okButton.setToolTipText(trans.get("SimulationEditDialog.btn.OK.ttip"));
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
closeDialog(true);
}
});
panel.add(okButton, "tag ok");
this.setContentPane(panel);
pack();
@ -96,7 +138,25 @@ public class PreferencesDialog extends JDialog {
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
// We don't want to lose the preference for the confirmation dialog
boolean isShowDiscardConfirmation = preferences.isShowDiscardPreferencesConfirmation();
// Reload initial preferences
if (!storePreferences) {
loadInitPreferences();
}
// Store the preference for showing the confirmation dialog
preferences.setShowDiscardPreferencesConfirmation(isShowDiscardConfirmation);
// Delete the init prefs
if (initPrefsFile != null) {
initPrefsFile.delete();
}
// Ensure the units are properly stored
preferences.storeDefaultUnits();
// Make sure unit change applies to the rocket figure
if (parent != null) {
parent.getRocketPanel().updateExtras();
@ -106,13 +166,72 @@ public class PreferencesDialog extends JDialog {
}
});
GUIUtil.setDisposableDialogOptions(this, close);
GUIUtil.setDisposableDialogOptions(this, okButton);
}
public BasicFrame getParentFrame() {
return parentFrame;
}
private void closeDialog(boolean storeChanges) {
storePreferences = storeChanges;
PreferencesDialog.this.setVisible(false);
PreferencesDialog.this.dispose();
}
/**
* Store the intial preferences in a temporary file, and return that file.
* @return the file containing the initial preferences, or null if something went wrong
*/
private File storeInitPreferences() {
try {
File outputFile = Files.createTempFile("ORInitPrefs_" + System.currentTimeMillis(), ".xml").toFile();
try (FileOutputStream outputFos = new FileOutputStream(outputFile)) {
PreferencesExporter.exportPreferencesToFile(preferences.getPreferences(), outputFos, false);
log.debug("Initial preferences stored in temporary file: " + outputFile.getAbsolutePath());
} catch (BackingStoreException e) {
log.error("Could not store initial preferences", e);
return null;
}
return outputFile;
} catch (IOException e) {
log.error("Could not create temporary preferences file", e);
return null;
}
}
/**
* Loads the initial stored preferences back (restores preferences).
*/
private void loadInitPreferences() {
if (initPrefsFile == null) {
return;
}
PreferencesImporter.importPreferences(initPrefsFile);
}
private JPanel createCancelOperationContent() {
JPanel panel = new JPanel(new MigLayout());
String msg = trans.get("PreferencesDialog.CancelOperation.msg.discardChanges");
JLabel msgLabel = new JLabel(msg);
JCheckBox dontAskAgain = new JCheckBox(trans.get("SimulationEditDialog.CancelOperation.checkbox.dontAskAgain"));
dontAskAgain.setSelected(false);
dontAskAgain.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
preferences.setShowDiscardPreferencesConfirmation(false);
}
// Unselected state should be not be possible and thus not be handled
}
});
panel.add(msgLabel, "left, wrap");
panel.add(dontAskAgain, "left, gaptop para");
return panel;
}
// ////// Singleton implementation ////////
private static PreferencesDialog dialog = null;

View File

@ -121,25 +121,32 @@ public abstract class PreferencesExporter {
keysToIgnore.add(SwingPreferences.UPDATE_PLATFORM); // Don't export platform-specific settings
}
private static void exportFilteredPreferences(Preferences preferences, FileOutputStream fos) throws BackingStoreException, IOException {
public static void exportPreferencesToFile(Preferences preferences, FileOutputStream fos, boolean filterPreferences)
throws BackingStoreException, IOException {
// If no filtering is required, just export the preferences
if (!filterPreferences) {
preferences.exportSubtree(fos);
return;
}
// Filter out user directories
Preferences root = Preferences.userRoot();
String originalNodeName = ((SwingPreferences) prefs).getNodename();
String nodeName = originalNodeName + "-temp";
if (root.nodeExists(nodeName)) {
root.node(nodeName).removeNode();
String filteredPrefsNodeName = originalNodeName + "-filtered";
if (root.nodeExists(filteredPrefsNodeName)) {
root.node(filteredPrefsNodeName).removeNode();
}
Preferences tempPrefs = root.node(nodeName);
Preferences filteredPrefs = root.node(filteredPrefsNodeName);
// Fill in all parameters to the temporary preferences, except for user directories
copyFilteredPreferences(preferences, tempPrefs, nodesToIgnore, keysToIgnore, prefixKeysToIgnore);
copyFilteredPreferences(preferences, filteredPrefs, nodesToIgnore, keysToIgnore, prefixKeysToIgnore);
// Export the filtered preferences
try {
// Export the filtered preferences to a temporary file
Path tempFile = Files.createTempFile("ORprefs_" + System.currentTimeMillis(), ".xml");
Path tempFile = Files.createTempFile("ORPrefs_" + System.currentTimeMillis(), ".xml");
try (FileOutputStream tempFos = new FileOutputStream(tempFile.toFile())) {
tempPrefs.exportSubtree(tempFos);
filteredPrefs.exportSubtree(tempFos);
}
// Read and parse the temporary file
@ -149,11 +156,11 @@ public abstract class PreferencesExporter {
doc = factory.newDocumentBuilder().parse(tempFis);
}
// Find and rename the node
// Find and rename the filtered prefs node
NodeList nodeList = doc.getElementsByTagName("node");
for (int i = 0; i < nodeList.getLength(); i++) {
Element element = (Element) nodeList.item(i);
if (element.getAttribute("name").equals(nodeName)) {
if (element.getAttribute("name").equals(filteredPrefsNodeName)) {
element.setAttribute("name", ((SwingPreferences) prefs).getNodename());
break;
}
@ -176,10 +183,14 @@ public abstract class PreferencesExporter {
} catch (ParserConfigurationException | TransformerException | SAXException e) {
e.printStackTrace();
} finally {
root.node(nodeName).removeNode();
root.node(filteredPrefsNodeName).removeNode();
}
}
private static void exportFilteredPreferences(Preferences preferences, FileOutputStream fos) throws BackingStoreException, IOException {
exportPreferencesToFile(preferences, fos, true);
}
private static void copyFilteredPreferences(Preferences src, Preferences dest,
List<String> nodesToIgnore, List<String> keysToIgnore, List<String> prefixKeysToIgnore) throws BackingStoreException {
for (String key : src.keys()) {

View File

@ -17,6 +17,11 @@ public abstract class PreferencesImporter {
private static final Translator trans = Application.getTranslator();
private static final Logger log = LoggerFactory.getLogger(PreferencesImporter.class);
/**
* Import the preferences by first showing a file chooser dialog to locate the preferences file.
* @param parent The parent window for the file chooser dialog.
* @return true if the preferences were imported successfully, false otherwise.
*/
public static boolean importPreferences(Window parent) {
final JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle(trans.get("PreferencesImporter.chooser.title"));
@ -33,13 +38,22 @@ public abstract class PreferencesImporter {
((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory());
File importFile = chooser.getSelectedFile();
return importPreferences(importFile);
}
/**
* Import preferences from an XML file.
* @param importFile The XML file to import preferences from.
* @return true if the preferences were imported successfully, false otherwise.
*/
public static boolean importPreferences(File importFile) {
try (FileInputStream fis = new FileInputStream(importFile)) {
Preferences.importPreferences(fis);
log.info("Preferences imported successfully.");
return true;
} catch (IOException | InvalidPreferencesFormatException e) {
log.warn("Error while importing preferences: " + e.getMessage());
}
return true;
return false;
}
}