package net.sf.openrocket.gui.util; import net.sf.openrocket.l10n.L10N; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.Markers; import net.sf.openrocket.startup.Application; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.filechooser.FileFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Locale; /** * Helper methods related to user-initiated file manipulation. * <p> * These methods log the necessary information to the debug log. * * @author Sampo Niskanen <sampo.niskanen@iki.fi> */ public final class FileHelper { private static final Logger log = LoggerFactory.getLogger(FileHelper.class); private static final Translator trans = Application.getTranslator(); // TODO: HIGH: Rename translation keys /** File filter for any rocket designs (*.ork, *.rkt) */ public static final FileFilter ALL_DESIGNS_FILTER = new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter1"), ".ork", ".ork.gz", ".rkt", ".rkt.gz"); /** File filter for OpenRocket designs (*.ork) */ public static final FileFilter OPENROCKET_DESIGN_FILTER = new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter2"), ".ork", ".ork.gz"); /** File filter for RockSim designs (*.rkt) */ public static final FileFilter ROCKSIM_DESIGN_FILTER = new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter3"), ".rkt", ".rkt.gz"); /** File filter for OpenRocket components and presets (*.orc) */ public static final FileFilter OPEN_ROCKET_COMPONENT_FILTER = new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter4"), ".orc", ".orc.gz"); /** File filter for PDF files (*.pdf) */ public static final FileFilter PDF_FILTER = new SimpleFileFilter(trans.get("filetypes.pdf"), ".pdf"); /** File filter for CSV files (*.csv) */ public static final FileFilter CSV_FILE_FILTER = new SimpleFileFilter(trans.get("SimExpPan.desc"), ".csv"); private FileHelper() { // Prevent instantiation } public static FileFilter getImageFileFilter() { String[] extensions = ImageIO.getReaderFileSuffixes(); for (int i = 0; i < extensions.length; i++) { extensions[i] = extensions[i].toLowerCase(Locale.ENGLISH); } Arrays.sort(extensions); StringBuilder sb = new StringBuilder(); sb.append(trans.get("filetypes.images")); sb.append(" ("); for (int i = 0; i < extensions.length; i++) { sb.append("*.").append(extensions[i]); if (i < extensions.length - 1) { sb.append("; "); } } sb.append(")"); return new SimpleFileFilter(sb.toString(), extensions); } /** * Ensure that the provided file has a file extension. If the file does not have * any extension, append the provided extension to it. * * @param original the original file * @param extension the extension to append if none exists (without preceding dot) * @return the resulting file */ public static File ensureExtension(File original, String extension) { if (original.getName().indexOf('.') < 0) { log.debug("File name does not contain extension, adding '" + extension + "'"); String name = original.getAbsolutePath(); name = name + "." + extension; return new File(name); } return original; } /** * Ensure that the provided file has the given file extension. This differs from ensureExtension in that this * method guarantees that the file will have the extension, whereas ensureExtension only treats the extension * as a default. * * @param original the original file * @param extension the extension to guarantee (without preceding dot) * @return the resulting file */ public static File forceExtension(File original, String extension) { if ( original == null ) { return null; } if (!original.getName().toLowerCase(Locale.ENGLISH).endsWith(extension.toLowerCase(Locale.ENGLISH))) { log.debug("File name does not contain extension, adding '" + extension + "'"); String name = original.getAbsolutePath(); if (extension.startsWith(".")) { name = name + extension; } else { name = name + "." + extension; } return new File(name); } return original; } /** * Confirm that it is allowed to write to a file. If the file exists, * a confirmation dialog will be presented to the user to ensure overwriting is ok. * * @param file the file that is going to be written. * @param parent the parent component for the dialog. * @return <code>true</code> to write, <code>false</code> to abort. */ public static boolean confirmWrite(File file, Component parent) { if (file.exists()) { log.info(Markers.USER_MARKER, "File " + file + " exists, confirming overwrite from user"); int result = JOptionPane.showConfirmDialog(parent, L10N.replace(trans.get("error.fileExists.desc"), "{filename}", file.getName()), trans.get("error.fileExists.title"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (result != JOptionPane.YES_OPTION) { log.info(Markers.USER_MARKER, "User decided not to overwrite the file"); return false; } log.info(Markers.USER_MARKER, "User decided to overwrite the file"); } return true; } /** * Display an error message to the user that writing a file failed. * * @param e the I/O exception that caused the error. * @param parent the parent component for the dialog. */ public static void errorWriting(IOException e, Component parent) { log.warn("Error writing to file", e); JOptionPane.showMessageDialog(parent, new Object[] { trans.get("error.writing.desc"), e.getLocalizedMessage() }, trans.get("error.writing.title"), JOptionPane.ERROR_MESSAGE); } }