diff --git a/megameklab/src/megameklab/ui/FileNameManager.java b/megameklab/src/megameklab/ui/FileNameManager.java new file mode 100644 index 000000000..66c7edbd5 --- /dev/null +++ b/megameklab/src/megameklab/ui/FileNameManager.java @@ -0,0 +1,20 @@ +/* + * MegaMek - Copyright (C) 2024 - The MegaMek Team + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +package megameklab.ui; + +public interface FileNameManager { + String getFileName(); + boolean hasEntityNameChanged(); + void setFileName(String fileName); +} diff --git a/megameklab/src/megameklab/ui/MegaMekLabMainUI.java b/megameklab/src/megameklab/ui/MegaMekLabMainUI.java index a39cf3bb8..6cc7c3195 100644 --- a/megameklab/src/megameklab/ui/MegaMekLabMainUI.java +++ b/megameklab/src/megameklab/ui/MegaMekLabMainUI.java @@ -22,6 +22,7 @@ import megameklab.MMLConstants; import megameklab.MegaMekLab; import megameklab.ui.util.ExitOnWindowClosingListener; +import megameklab.ui.util.MegaMekLabFileSaver; import megameklab.ui.util.RefreshListener; import megameklab.util.CConfig; import megameklab.util.MMLFileDropTransferHandler; @@ -29,7 +30,7 @@ import javax.swing.*; import java.awt.*; -public abstract class MegaMekLabMainUI extends JFrame implements RefreshListener, EntitySource, MenuBarOwner { +public abstract class MegaMekLabMainUI extends JFrame implements RefreshListener, EntitySource, MenuBarOwner, FileNameManager { private Entity entity = null; private String fileName = ""; protected MenuBar mmlMenuBar; @@ -158,7 +159,7 @@ public Entity getEntity() { public void setEntity(Entity entity, String currentEntityFilename) { this.entity = entity; - originalName = MenuBar.createUnitFilename(entity); + originalName = MegaMekLabFileSaver.createUnitFilename(entity); setFileName(currentEntityFilename); } @@ -187,10 +188,11 @@ public String getFileName() { return fileName; } + @Override public void setFileName(String fileName) { this.fileName = fileName; // If the filename is reloaded, restart tracking of the unit name changing. - this.originalName = MenuBar.createUnitFilename(entity); + this.originalName = MegaMekLabFileSaver.createUnitFilename(entity); refreshHeader(); } @@ -201,7 +203,7 @@ public void refreshMenuBar() { @Override public boolean hasEntityNameChanged() { - return !MenuBar.createUnitFilename(entity).equals(originalName); + return !MegaMekLabFileSaver.createUnitFilename(entity).equals(originalName); } @Override diff --git a/megameklab/src/megameklab/ui/MenuBar.java b/megameklab/src/megameklab/ui/MenuBar.java index 4ff5dd196..6f44191b5 100644 --- a/megameklab/src/megameklab/ui/MenuBar.java +++ b/megameklab/src/megameklab/ui/MenuBar.java @@ -42,7 +42,6 @@ import megamek.client.ui.swing.util.UIUtil; import megamek.common.*; import megamek.common.annotations.Nullable; -import megamek.common.loaders.BLKFile; import megamek.common.templates.TROView; import megamek.logging.MMLogger; import megameklab.MMLConstants; @@ -51,6 +50,7 @@ import megameklab.ui.dialog.PrintQueueDialog; import megameklab.ui.dialog.UiLoader; import megameklab.ui.dialog.settings.SettingsDialog; +import megameklab.ui.util.MegaMekLabFileSaver; import megameklab.util.CConfig; import megameklab.util.UnitPrintManager; import megameklab.util.UnitUtil; @@ -66,10 +66,11 @@ public class MenuBar extends JMenuBar implements ClipboardOwner { private final MenuBarOwner owner; private final ResourceBundle resources = ResourceBundle.getBundle("megameklab.resources.Menu"); private final MMLFileChooser loadUnitFileChooser = new MMLFileChooser(); - private final MMLFileChooser saveUnitFileChooser = new MMLFileChooser(); public final MMLFileChooser loadImageFileChooser = new MMLFileChooser(); private final JMenu fileMenu = new JMenu(resources.getString("fileMenu.text")); + private MegaMekLabFileSaver fileSaver; + public MenuBar(MenuBarOwner owner) { this.owner = owner; initialize(); @@ -118,7 +119,6 @@ private void initialize() { loadImageFileChooser.setDialogTitle(resources.getString("dialog.chooseUnit.title")); loadImageFileChooser.setFileFilter(new FileNameExtensionFilter("Image files (.png, .jpg, .gif)", "png", "jpg", "jpeg", "gif")); - saveUnitFileChooser.setDialogTitle(resources.getString("dialog.saveAs.title")); } private JMenu createFileMenu() { @@ -351,6 +351,7 @@ private JMenu createLoadMenu() { * @return the created Save menu */ private JMenu createSaveMenu() { + fileSaver = new MegaMekLabFileSaver(logger, resources.getString("dialog.saveAs.title")); final JMenu saveMenu = new JMenu(resources.getString("Save.text")); saveMenu.setName("saveMenu"); saveMenu.setMnemonic(KeyEvent.VK_S); @@ -374,6 +375,37 @@ private JMenu createSaveMenu() { return saveMenu; } + public boolean saveUnitAs() { + warnOnInvalid(); + Entity entity = getUnitMainUi().getEntity(); + UnitUtil.compactCriticals(entity); + getUnitMainUi().refreshAll(); // The crits may have moved + String file = fileSaver.saveUnitAs(getUnitMainUi(), entity); + if (file == null) { + return false; + } + getUnitMainUi().setFileName(file); + return true; + } + + public boolean saveUnit() { + Entity entity = getUnitMainUi().getEntity(); + if (entity == null) { + logger.error("Tried to save null entity."); + return false; + } else { + warnOnInvalid(); + } + UnitUtil.compactCriticals(entity); + getUnitMainUi().refreshAll(); // The crits may have moved + String file = fileSaver.saveUnit(getUnitMainUi().getFrame(), getUnitMainUi(), entity); + if (file == null) { + return false; + } + getUnitMainUi().setFileName(file); + return true; + } + /** * @return the created Export menu */ @@ -1080,110 +1112,6 @@ private void jMenuResetEntity_actionPerformed(ActionEvent event) { getUnitMainUi().repaint(); } - /** - * Constructs a file name for the current Entity using the chassis and model - * name and the - * correct extension for the unit type. Any character that is not legal for a - * Windows filename - * is replaced by an underscore. - * - * @param entity The Entity - * @return A default filename for the Entity - */ - public static String createUnitFilename(Entity entity) { - String fileName = (entity.getChassis() + ' ' + entity.getModel()).trim(); - fileName = fileName.replaceAll("[/\\\\<>:\"|?*]", "_"); - return fileName + ((entity instanceof Mek) ? ".mtf" : ".blk"); - } - - /** - * Tries to save the unit directly to its file, if it has a filename already. If - * it hasn't, it performs a Save As... Returns true when it successfully saves - * the - * unit, false if not. - * - * @return True when the unit was actually saved, false otherwise - */ - public boolean saveUnit() { - Entity entity = owner.getEntity(); - if (entity == null) { - logger.error("Tried to save null entity."); - return false; - } else { - warnOnInvalid(); - } - - UnitUtil.compactCriticals(entity); - owner.refreshAll(); // The crits may have moved - - String filePathName = owner.getFileName(); - // For safety, save automatically only to .mtf or .blk files, otherwise ask - if (!(filePathName.endsWith(".mtf") || filePathName.endsWith(".blk")) - || !new File(filePathName).exists() - || owner.hasEntityNameChanged()) { - File selectedFile = chooseSaveFile(); - if (selectedFile == null) { - return false; - } - - filePathName = selectedFile.getPath(); - } - - CConfig.setMostRecentFile(filePathName); - return saveUnitTo(new File(filePathName)); - } - - private void saveUnitAs() { - warnOnInvalid(); - - UnitUtil.compactCriticals(owner.getEntity()); - owner.refreshAll(); // The crits may have moved - - File saveFile = chooseSaveFile(); - if (saveFile != null) { - CConfig.setMostRecentFile(saveFile.toString()); - saveUnitTo(saveFile); - } - } - - private @Nullable File chooseSaveFile() { - if (getUnitMainUi().getEntity() instanceof Mek) { - saveUnitFileChooser.setFileFilter(new FileNameExtensionFilter("Mek files", "mtf")); - } else { - saveUnitFileChooser.setFileFilter(new FileNameExtensionFilter("Unit files", "blk")); - } - saveUnitFileChooser.setSelectedFile(new File(createUnitFilename(getUnitMainUi().getEntity()))); - int result = saveUnitFileChooser.showSaveDialog(owner.getFrame()); - if ((result != JFileChooser.APPROVE_OPTION) || (saveUnitFileChooser.getSelectedFile() == null)) { - return null; - } else { - return saveUnitFileChooser.getSelectedFile(); - } - } - - private boolean saveUnitTo(File file) { - if (getUnitMainUi().getEntity() == null) { - return false; - } - try { - if (getUnitMainUi().getEntity() instanceof Mek) { - try (FileOutputStream fos = new FileOutputStream(file); - PrintStream ps = new PrintStream(fos)) { - ps.println(((Mek) owner.getEntity()).getMtf()); - } - } else { - BLKFile.encode(file.getPath(), getUnitMainUi().getEntity()); - } - PopupMessages.showUnitSavedMessage(owner.getFrame(), getUnitMainUi().getEntity(), file); - getUnitMainUi().setFileName(file.toString()); - return true; - } catch (Exception ex) { - PopupMessages.showFileWriteError(owner.getFrame(), ex.getMessage()); - logger.error("", ex); - return false; - } - } - private String entitySummaryText(ViewFormatting formatting) { if (CConfig.getBooleanParam(CConfig.MISC_SUMMARY_FORMAT_TRO) && formatting != ViewFormatting.DISCORD) { TROView view = TROView.createView(owner.getEntity(), formatting); diff --git a/megameklab/src/megameklab/ui/StartupGUI.java b/megameklab/src/megameklab/ui/StartupGUI.java index 88b0b5f13..f502b9c0d 100644 --- a/megameklab/src/megameklab/ui/StartupGUI.java +++ b/megameklab/src/megameklab/ui/StartupGUI.java @@ -28,6 +28,7 @@ import megameklab.ui.dialog.MegaMekLabUnitSelectorDialog; import megameklab.ui.dialog.UiLoader; import megameklab.ui.util.ExitOnWindowClosingListener; +import megameklab.ui.util.MegaMekLabFileSaver; import megameklab.util.CConfig; import megameklab.util.MMLFileDropTransferHandler; import megameklab.util.UnitUtil; @@ -264,7 +265,7 @@ public static void selectAndLoadUnitFromCache(MenuBarOwner previousFrame) { if (fileName.toLowerCase().endsWith(".zip")) { fileName = viewer.getSelectedMekSummary().getSourceFile().getAbsolutePath(); fileName = fileName.substring(0, fileName.lastIndexOf(File.separatorChar) + 1); - fileName = fileName + MenuBar.createUnitFilename(newUnit); + fileName = fileName + MegaMekLabFileSaver.createUnitFilename(newUnit); } if (!previousFrame.safetyPrompt()) { diff --git a/megameklab/src/megameklab/ui/util/MegaMekLabFileSaver.java b/megameklab/src/megameklab/ui/util/MegaMekLabFileSaver.java new file mode 100644 index 000000000..1cc522747 --- /dev/null +++ b/megameklab/src/megameklab/ui/util/MegaMekLabFileSaver.java @@ -0,0 +1,130 @@ +/* + * MegaMek - Copyright (C) 2024 - The MegaMek Team + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +package megameklab.ui.util; + +import megamek.common.Entity; +import megamek.common.Mek; +import megamek.common.annotations.Nullable; +import megamek.common.loaders.BLKFile; +import megamek.logging.MMLogger; +import megameklab.ui.FileNameManager; +import megameklab.ui.PopupMessages; +import megameklab.ui.dialog.MMLFileChooser; +import megameklab.util.CConfig; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; + +public class MegaMekLabFileSaver { + + private final MMLFileChooser saveUnitFileChooser = new MMLFileChooser(); + private final MMLogger logger; + + public MegaMekLabFileSaver(MMLogger mainLogger, String dialogTitle) { + logger = mainLogger; + saveUnitFileChooser.setDialogTitle(dialogTitle); + } + + /** + * Constructs a file name for the current Entity using the chassis and model + * name and the + * correct extension for the unit type. Any character that is not legal for a + * Windows filename + * is replaced by an underscore. + * + * @param entity The Entity + * @return A default filename for the Entity + */ + public static String createUnitFilename(Entity entity) { + String fileName = (entity.getChassis() + ' ' + entity.getModel()).trim(); + fileName = fileName.replaceAll("[/\\\\<>:\"|?*]", "_"); + return fileName + ((entity instanceof Mek) ? ".mtf" : ".blk"); + } + + /** + * Tries to save the unit directly to its file, if it has a filename already. If + * it hasn't, it performs a Save As... Returns true when it successfully saves + * the + * unit, false if not. + * + * @return True when the unit was actually saved, false otherwise + */ + public String saveUnit(JFrame ownerFrame, FileNameManager fileNameManager, Entity entity) { + String filePathName = fileNameManager.getFileName(); + // For safety, save automatically only to .mtf or .blk files, otherwise ask + if (!(filePathName.endsWith(".mtf") || filePathName.endsWith(".blk")) + || !new File(filePathName).exists() + || fileNameManager.hasEntityNameChanged()) { + File selectedFile = chooseSaveFile(ownerFrame, entity); + if (selectedFile == null) { + return null; + } + filePathName = selectedFile.getPath(); + } + + CConfig.setMostRecentFile(filePathName); + return saveUnitTo(ownerFrame, new File(filePathName), entity); + } + + public String saveUnitAs(JFrame ownerFrame, Entity entity) { + + File saveFile = chooseSaveFile(ownerFrame, entity); + if (saveFile != null) { + CConfig.setMostRecentFile(saveFile.toString()); + return saveUnitTo(ownerFrame, saveFile, entity); + } + return null; + } + + // Replace owner class with EntitySource... somehow. + private @Nullable File chooseSaveFile(JFrame ownerFrame, Entity entity) { + if (entity instanceof Mek) { + saveUnitFileChooser.setFileFilter(new FileNameExtensionFilter("Mek files", "mtf")); + } else { + saveUnitFileChooser.setFileFilter(new FileNameExtensionFilter("Unit files", "blk")); + } + saveUnitFileChooser.setSelectedFile(new File(createUnitFilename(entity))); + int result = saveUnitFileChooser.showSaveDialog(ownerFrame); + if ((result != JFileChooser.APPROVE_OPTION) || (saveUnitFileChooser.getSelectedFile() == null)) { + return null; + } else { + return saveUnitFileChooser.getSelectedFile(); + } + } + + private String saveUnitTo(JFrame ownerFrame, File file, Entity entity) { + if (entity == null) { + return null; + } + try { + if (entity instanceof Mek) { + try (FileOutputStream fos = new FileOutputStream(file); + PrintStream ps = new PrintStream(fos)) { + ps.println(((Mek) entity).getMtf()); + } + } else { + BLKFile.encode(file.getPath(), entity); + } + PopupMessages.showUnitSavedMessage(ownerFrame, entity, file); + return file.toString(); + } catch (Exception ex) { + PopupMessages.showFileWriteError(ownerFrame, ex.getMessage()); + logger.error("", ex); + return null; + } + } +}