Merge pull request #2135 from SiboVG/issue-2131

[#2131] Throw warning message when save filename contains illegal characters
This commit is contained in:
Sibo Van Gool 2023-03-24 11:37:36 +01:00 committed by GitHub
commit a93a20611b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 259 additions and 149 deletions

View File

@ -1343,6 +1343,10 @@ saveAs.openrocket.title = Save as OpenRocket ork file
saveAs.rocksim.title = Export as RockSim rkt file
saveAs.rasaero.title = Export as RASAero CDX1 file
! SaveAsFileChooser
SaveAsFileChooser.illegalFilename.title = Illegal filename
SaveAsFileChooser.illegalFilename.message = The filename '%s' may not contain the character ' %c '. Please remove it.
! StorageOptionChooser
StorageOptChooser.lbl.Simdatatostore = Simulated data to store:
StorageOptChooser.rdbut.Allsimdata = All simulated data

View File

@ -27,6 +27,7 @@ import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -363,7 +364,7 @@ public class PrintDialog extends JDialog implements TreeSelectionListener {
*/
private boolean onSavePDF() {
JFileChooser chooser = new JFileChooser();
JFileChooser chooser = new SaveFileChooser();
chooser.setFileFilter(FileHelper.PDF_FILTER);
// Select initial directory

View File

@ -52,6 +52,7 @@ import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import net.sf.openrocket.arch.SystemInfo;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -1154,7 +1155,7 @@ public class GeneralOptimizationDialog extends JDialog {
trans.get("export.header"), trans.get("export.header.ttip"));
JFileChooser chooser = new JFileChooser();
JFileChooser chooser = new SaveFileChooser();
chooser.setFileFilter(FileHelper.CSV_FILTER);
chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
chooser.setAccessory(csvOptions);

View File

@ -42,6 +42,7 @@ import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.Icons;
import net.sf.openrocket.gui.util.SimpleFileFilter;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.LoggingSystemSetup;
import net.sf.openrocket.logging.Markers;
@ -201,7 +202,7 @@ public class PhotoFrame extends JFrame {
final FileFilter png = new SimpleFileFilter(trans.get("PhotoFrame.fileFilter.png"),
".png");
final JFileChooser chooser = new JFileChooser();
final JFileChooser chooser = new SaveFileChooser();
chooser.addChoosableFileFilter(png);
chooser.setFileFilter(png);

View File

@ -87,6 +87,7 @@ import net.sf.openrocket.gui.util.OpenFileWorker;
import net.sf.openrocket.gui.util.SaveFileWorker;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.gui.util.URLUtil;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.Markers;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
@ -1383,7 +1384,7 @@ public class BasicFrame extends JFrame {
public boolean exportRockSimAction() {
File file;
final SaveAsFileChooser chooser = SaveAsFileChooser.build(document, FileType.ROCKSIM);
final DesignFileSaveAsFileChooser chooser = DesignFileSaveAsFileChooser.build(document, FileType.ROCKSIM);
int option = chooser.showSaveDialog(BasicFrame.this);
@ -1480,7 +1481,7 @@ public class BasicFrame extends JFrame {
private boolean saveAsAction() {
File file = null;
final SaveAsFileChooser chooser = SaveAsFileChooser.build(document, FileType.OPENROCKET);
final DesignFileSaveAsFileChooser chooser = DesignFileSaveAsFileChooser.build(document, FileType.OPENROCKET);
int option = chooser.showSaveDialog(BasicFrame.this);

View File

@ -3,9 +3,6 @@ package net.sf.openrocket.gui.main;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JFileChooser;
@ -15,10 +12,11 @@ import net.sf.openrocket.document.StorageOptions.FileType;
import net.sf.openrocket.gui.util.FileHelper;
import net.sf.openrocket.gui.util.SimpleFileFilter;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
public class SaveAsFileChooser extends JFileChooser {
public class DesignFileSaveAsFileChooser extends SaveFileChooser {
private final FileType type;
private final OpenRocketDocument document;
@ -26,11 +24,11 @@ public class SaveAsFileChooser extends JFileChooser {
private static final Translator trans = Application.getTranslator();
public static SaveAsFileChooser build( OpenRocketDocument document, FileType type ) {
return new SaveAsFileChooser(document,type);
public static DesignFileSaveAsFileChooser build(OpenRocketDocument document, FileType type ) {
return new DesignFileSaveAsFileChooser(document,type);
}
private SaveAsFileChooser( OpenRocketDocument document, FileType type ) {
private DesignFileSaveAsFileChooser(OpenRocketDocument document, FileType type ) {
this.document = document;
this.type = type;

View File

@ -43,6 +43,7 @@ import net.sf.openrocket.arch.SystemInfo;
import net.sf.openrocket.gui.components.CsvOptionPanel;
import net.sf.openrocket.gui.util.FileHelper;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -403,25 +404,25 @@ public class SimulationPanel extends JPanel {
return;
}
JFileChooser fch = setUpSimExportCSVFileChooser();
int selectionStatus = fch.showSaveDialog(tableParent);
JFileChooser chooser = setUpSimExportCSVFileChooser();
int selectionStatus = chooser.showSaveDialog(tableParent);
if (selectionStatus != JFileChooser.APPROVE_OPTION) {
log.debug("User cancelled CSV export");
return;
}
// Fetch the info from the file chooser
File CSVFile = fch.getSelectedFile();
File CSVFile = chooser.getSelectedFile();
CSVFile = FileHelper.forceExtension(CSVFile, "csv");
if (!FileHelper.confirmWrite(CSVFile, SimulationPanel.this)) {
log.debug("User cancelled CSV export overwrite");
return;
}
String separator = ((CsvOptionPanel) fch.getAccessory()).getFieldSeparator();
int precision = ((CsvOptionPanel) fch.getAccessory()).getDecimalPlaces();
boolean isExponentialNotation = ((CsvOptionPanel) fch.getAccessory()).isExponentialNotation();
((CsvOptionPanel) fch.getAccessory()).storePreferences();
String separator = ((CsvOptionPanel) chooser.getAccessory()).getFieldSeparator();
int precision = ((CsvOptionPanel) chooser.getAccessory()).getDecimalPlaces();
boolean isExponentialNotation = ((CsvOptionPanel) chooser.getAccessory()).isExponentialNotation();
((CsvOptionPanel) chooser.getAccessory()).storePreferences();
// Handle some special separator options from CsvOptionPanel
if (separator.equals(trans.get("CsvOptionPanel.separator.space"))) {
@ -439,29 +440,29 @@ public class SimulationPanel extends JPanel {
* @return The file chooser.
*/
private JFileChooser setUpSimExportCSVFileChooser() {
JFileChooser fch = new JFileChooser();
fch.setDialogTitle(trans.get("simpanel.pop.exportToCSV.save.dialog.title"));
fch.setFileFilter(FileHelper.CSV_FILTER);
fch.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
fch.setAcceptAllFileFilterUsed(false);
JFileChooser chooser = new SaveFileChooser();
chooser.setDialogTitle(trans.get("simpanel.pop.exportToCSV.save.dialog.title"));
chooser.setFileFilter(FileHelper.CSV_FILTER);
chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
chooser.setAcceptAllFileFilterUsed(false);
// Default output CSV to same name as the document's rocket name.
String fileName = document.getRocket().getName() + ".csv";
fch.setSelectedFile(new File(fileName));
chooser.setSelectedFile(new File(fileName));
// Add CSV options to FileChooser
CsvOptionPanel CSVOptions = new CsvOptionPanel(SimulationTableCSVExport.class);
fch.setAccessory(CSVOptions);
chooser.setAccessory(CSVOptions);
// TODO: update this dynamically instead of hard-coded values
// The macOS file chooser has an issue where it does not update its size when the accessory is added.
if (SystemInfo.getPlatform() == SystemInfo.Platform.MAC_OS) {
Dimension currentSize = fch.getPreferredSize();
Dimension currentSize = chooser.getPreferredSize();
Dimension newSize = new Dimension((int) (1.5 * currentSize.width), (int) (1.3 * currentSize.height));
fch.setPreferredSize(newSize);
chooser.setPreferredSize(newSize);
}
return fch;
return chooser;
}
private Simulation[] getSelectedSimulations() {

View File

@ -26,6 +26,7 @@ import net.sf.openrocket.gui.util.FileHelper;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.Icons;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.Preferences;
@ -173,7 +174,7 @@ public class SimulationPlotDialog extends JDialog {
}
private boolean doPngExport(ChartPanel chartPanel, JFreeChart chart){
JFileChooser chooser = new JFileChooser();
JFileChooser chooser = new SaveFileChooser();
chooser.setAcceptAllFileFilterUsed(false);
chooser.setFileFilter(FileHelper.PNG_FILTER);
chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());

View File

@ -32,6 +32,7 @@ import net.sf.openrocket.gui.util.FileHelper;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.gui.util.SaveCSVWorker;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.simulation.FlightData;
import net.sf.openrocket.simulation.FlightDataBranch;
@ -219,7 +220,7 @@ public class SimulationExportPanel extends JPanel {
}
public boolean doExport() {
JFileChooser chooser = new JFileChooser();
JFileChooser chooser = new SaveFileChooser();
chooser.setFileFilter(FileHelper.CSV_FILTER);
chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());

View File

@ -0,0 +1,100 @@
package net.sf.openrocket.gui.widgets;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import java.io.File;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class SaveFileChooser extends JFileChooser {
private static final Translator trans = Application.getTranslator();
private static final char[] ILLEGAL_CHARS = new char[] { '/', '\\', ':', '*', '?', '"', '<', '>', '|' };
private File cwd = null;
private File currentFile = null;
private String fileName = null;
@Override
public void setSelectedFile(File file) {
currentFile = file;
if (file == null) {
super.setSelectedFile(null);
return;
}
if (file.getParentFile() != getCurrentDirectory()) {
cwd = getCurrentDirectory();
fileName = getFilenameInput(currentFile, cwd);
if (getIllegalChar(fileName) != null) {
return;
}
}
super.setSelectedFile(file);
fileName = file.getName();
cwd = getCurrentDirectory();
}
@Override
public void approveSelection() {
Character c = getIllegalChar(fileName);
if (c != null) {
// Illegal character found
JOptionPane.showMessageDialog(getParent(),
String.format(trans.get("SaveAsFileChooser.illegalFilename.message"), fileName, c),
trans.get("SaveAsFileChooser.illegalFilename.title"),
JOptionPane.WARNING_MESSAGE);
} else {
// Successful filename
super.setSelectedFile(currentFile);
setCurrentDirectory(cwd);
super.approveSelection();
}
}
/**
* Returns an illegal character if one is found in the filename, otherwise returns null.
* @param filename The filename to check
* @return The illegal character, or null if none is found
*/
private Character getIllegalChar(String filename) {
if (filename == null || filename.isEmpty()) {
return null;
}
for (char c : ILLEGAL_CHARS) {
if (filename.indexOf(c) >= 0) {
return c;
}
}
return null;
}
/**
* Returns the filename input by the user, or null if the filename is invalid.
* You can't simply use getSelectedFile().getName() because it won't work for malformed filenames.
* @param file The file to get the filename from
* @param cwd The current working directory
* @return The filename input by the user, or null if the filename is invalid
*/
private String getFilenameInput(File file, File cwd) {
if (file == null || cwd == null) {
return null;
}
String fullPath = file.getAbsolutePath();
String cwdPath = cwd.getAbsolutePath();
try {
String relativePath = fullPath.replaceFirst(Pattern.quote(cwdPath), "").trim();
relativePath = relativePath.replaceFirst(Pattern.quote(File.separator), "");
return relativePath;
} catch (PatternSyntaxException e) {
return null;
}
}
}

View File

@ -37,6 +37,7 @@ import net.sf.openrocket.gui.preset.PresetResultListener;
import net.sf.openrocket.gui.util.FileHelper;
import net.sf.openrocket.gui.util.Icons;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.gui.widgets.SaveFileChooser;
import net.sf.openrocket.logging.Markers;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
@ -404,7 +405,7 @@ public class ComponentPresetEditor extends JPanel implements PresetResultListene
private boolean saveAsORC() throws JAXBException, IOException {
File file = null;
final JFileChooser chooser = new JFileChooser();
final JFileChooser chooser = new SaveFileChooser();
chooser.addChoosableFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER);
chooser.setFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER);