diff --git a/megameklab/src/megameklab/ui/MegaMekLabMainUI.java b/megameklab/src/megameklab/ui/MegaMekLabMainUI.java
index b2fd32fbf..237cc1e14 100644
--- a/megameklab/src/megameklab/ui/MegaMekLabMainUI.java
+++ b/megameklab/src/megameklab/ui/MegaMekLabMainUI.java
@@ -20,6 +20,7 @@
import megamek.common.Entity;
import megamek.common.Mounted;
import megamek.common.preference.PreferenceManager;
+import megameklab.util.EntityChangedUtil;
import megameklab.MMLConstants;
import megameklab.MegaMekLab;
import megameklab.ui.util.ExitOnWindowClosingListener;
@@ -83,7 +84,7 @@ public void setVisible(boolean b) {
@Override
public boolean safetyPrompt() {
- if (CConfig.getBooleanParam(CConfig.MISC_SKIP_SAFETY_PROMPTS)) {
+ if (CConfig.getBooleanParam(CConfig.MISC_SKIP_SAFETY_PROMPTS) || !EntityChangedUtil.hasEntityChanged(this)) {
return true;
} else {
int savePrompt = JOptionPane.showConfirmDialog(this,
diff --git a/megameklab/src/megameklab/ui/MegaMekLabTabbedUI.java b/megameklab/src/megameklab/ui/MegaMekLabTabbedUI.java
index b18f2a09b..c20f44d09 100644
--- a/megameklab/src/megameklab/ui/MegaMekLabTabbedUI.java
+++ b/megameklab/src/megameklab/ui/MegaMekLabTabbedUI.java
@@ -23,12 +23,13 @@
import megamek.client.ui.swing.util.UIUtil;
import megamek.common.Entity;
import megamek.common.preference.PreferenceManager;
-import megameklab.EntityChangedUtil;
+import megameklab.util.EntityChangedUtil;
import megameklab.MMLConstants;
import megameklab.MegaMekLab;
import megameklab.ui.dialog.UiLoader;
import megameklab.ui.mek.BMMainUI;
import megameklab.ui.util.ExitOnWindowClosingListener;
+import megameklab.ui.util.MegaMekLabFileSaver;
import megameklab.ui.util.TabStateUtil;
import megameklab.util.CConfig;
import megameklab.util.MMLFileDropTransferHandler;
@@ -235,9 +236,36 @@ public void addUnit(Entity entity, String filename) {
tabs.setTabComponentAt(tabs.getSelectedIndex(), new EditorTab(entity.getDisplayName(), currentEditor()));
}
+ private boolean exitPrompt() {
+ if (CConfig.getBooleanParam(CConfig.MISC_SKIP_SAFETY_PROMPTS)) {
+ return true;
+ }
+ if (editors.stream().limit(editors.size() - 1).noneMatch(EntityChangedUtil::hasEntityChanged)) {
+ return true;
+ }
+ int savePrompt = JOptionPane.showConfirmDialog(this,
+ "All unsaved changes to open units will be discarded. Save the units first?",
+ "Save Units Before Proceeding?",
+ JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.WARNING_MESSAGE);
+ if (savePrompt == JOptionPane.NO_OPTION) {
+ return true;
+ }
+ if (savePrompt == JOptionPane.YES_OPTION) {
+ return editors.stream().limit(editors.size() - 1)
+ .filter(EntityChangedUtil::hasEntityChanged)
+ .noneMatch(editor -> {
+ tabs.setSelectedComponent(editor.getContentPane());
+ tabs.paintImmediately(tabs.getBounds());
+ return !editor.getMMLMenuBar().saveUnit();
+ });
+ }
+ return false;
+ }
+
@Override
public boolean exit() {
- if (!currentEditor().safetyPrompt()) {
+ if (!exitPrompt()) {
return false;
}
@@ -348,6 +376,11 @@ public MenuBar getMMLMenuBar() {
return menuBar;
}
+ @Override
+ public boolean safetyPrompt() {
+ return currentEditor().safetyPrompt();
+ }
+
@Override
public void stateChanged(ChangeEvent e) {
if (e.getSource() == tabs) {
diff --git a/megameklab/src/megameklab/ui/MenuBar.java b/megameklab/src/megameklab/ui/MenuBar.java
index e399d5b74..f3c76b187 100644
--- a/megameklab/src/megameklab/ui/MenuBar.java
+++ b/megameklab/src/megameklab/ui/MenuBar.java
@@ -44,7 +44,6 @@
import megamek.common.annotations.Nullable;
import megamek.common.templates.TROView;
import megamek.logging.MMLogger;
-import megameklab.EntityChangedUtil;
import megameklab.MMLConstants;
import megameklab.ui.dialog.MMLFileChooser;
import megameklab.ui.dialog.MegaMekLabUnitSelectorDialog;
@@ -1171,7 +1170,8 @@ public void loadFile(File unitFile) {
throw new Exception();
}
- if (!owner.safetyPrompt()) {
+ // TabbedUi loads a unit into a new tab, no safety prompt needed.
+ if (!(owner instanceof MegaMekLabTabbedUI) || !owner.safetyPrompt()) {
return;
}
diff --git a/megameklab/src/megameklab/ui/util/MegaMekLabFileSaver.java b/megameklab/src/megameklab/ui/util/MegaMekLabFileSaver.java
index 1cc522747..2f25cbe3b 100644
--- a/megameklab/src/megameklab/ui/util/MegaMekLabFileSaver.java
+++ b/megameklab/src/megameklab/ui/util/MegaMekLabFileSaver.java
@@ -19,9 +19,11 @@
import megamek.common.loaders.BLKFile;
import megamek.logging.MMLogger;
import megameklab.ui.FileNameManager;
+import megameklab.ui.MegaMekLabMainUI;
import megameklab.ui.PopupMessages;
import megameklab.ui.dialog.MMLFileChooser;
import megameklab.util.CConfig;
+import megameklab.util.EntityChangedUtil;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
@@ -119,6 +121,12 @@ private String saveUnitTo(JFrame ownerFrame, File file, Entity entity) {
} else {
BLKFile.encode(file.getPath(), entity);
}
+
+ if (ownerFrame instanceof MegaMekLabMainUI mui) {
+ // Since we've saved the entity, update the entity being compared against to determine if the user has unsaved work.
+ EntityChangedUtil.editorSaved(mui);
+ }
+
PopupMessages.showUnitSavedMessage(ownerFrame, entity, file);
return file.toString();
} catch (Exception ex) {
diff --git a/megameklab/src/megameklab/EntityChangedUtil.java b/megameklab/src/megameklab/util/EntityChangedUtil.java
similarity index 54%
rename from megameklab/src/megameklab/EntityChangedUtil.java
rename to megameklab/src/megameklab/util/EntityChangedUtil.java
index 4d8d9fed4..066bbceaf 100644
--- a/megameklab/src/megameklab/EntityChangedUtil.java
+++ b/megameklab/src/megameklab/util/EntityChangedUtil.java
@@ -1,21 +1,42 @@
-package megameklab;
+/*
+ * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved.
+ *
+ * This file is part of MegaMekLab.
+ *
+ * MegaMek 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * MegaMek 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MegaMek. If not, see .
+ */
+
+package megameklab.util;
import megamek.common.Entity;
import megamek.common.Mek;
import megamek.common.MekFileParser;
import megamek.common.loaders.BLKFile;
+import megamek.common.loaders.EntityLoadingException;
import megamek.common.loaders.EntitySavingException;
import megamek.logging.MMLogger;
import megameklab.ui.MegaMekLabMainUI;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class EntityChangedUtil {
- private static MMLogger logger = MMLogger.create(EntityChangedUtil.class);
+ private static final MMLogger logger = MMLogger.create(EntityChangedUtil.class);
- private static Map cache = new ConcurrentHashMap<>();
+ private static final Map cache = new ConcurrentHashMap<>();
public static boolean hasEntityChanged(MegaMekLabMainUI editor) {
var filename = editor.getFileName();
@@ -32,14 +53,15 @@ public static boolean hasEntityChanged(MegaMekLabMainUI editor) {
try {
var e = new MekFileParser(f).getEntity();
- cache.put(filename, encode(e));
+ cache.put(filename, e);
} catch (Exception ex) {
logger.error("Entity loading failure:", ex);
+ cache.put(filename, null);
}
}
try {
- var o = cache.get(filename);
+ var o = encode(cache.get(filename));
var n = encode(editor.getEntity());
return !o.equals(n);
} catch (EntitySavingException e) {
@@ -55,13 +77,19 @@ public static void editorSaved(MegaMekLabMainUI editor) {
}
try {
- cache.put(editor.getFileName(), encode(editor.getEntity()));
- } catch (EntitySavingException e) {
+ var bis = new ByteArrayInputStream(encode(editor.getEntity()).getBytes());
+ cache.put(editor.getFileName(), new MekFileParser(bis, editor.getFileName()).getEntity());
+ } catch (EntitySavingException | EntityLoadingException e) {
+ cache.remove(filename);
logger.error("Entity encoding failure:", e);
}
}
private static String encode(Entity e) throws EntitySavingException {
+ if (e == null) {
+ return "";
+ }
+
if (e instanceof Mek m) {
return m.getMtf();
} else {