From 9bd2a47e025e3e0d2f58f99d0b7a2c84d3f79b81 Mon Sep 17 00:00:00 2001 From: Pavel Braginskiy Date: Tue, 29 Oct 2024 15:38:09 -0700 Subject: [PATCH] Allow drag-dropping unit and MUL files onto MML --- .../megameklab/resources/Dialogs.properties | 2 + .../megameklab/resources/Menu.properties | 3 + .../src/megameklab/ui/MegaMekLabMainUI.java | 13 +++- megameklab/src/megameklab/ui/MenuBar.java | 4 ++ .../src/megameklab/ui/MenuBarOwner.java | 2 + .../src/megameklab/ui/MulDndBehaviour.java | 33 +++++++++ megameklab/src/megameklab/ui/StartupGUI.java | 7 ++ .../ui/dialog/settings/MiscSettingsPanel.java | 35 +++++++--- megameklab/src/megameklab/util/CConfig.java | 1 + .../megameklab/util/MMLFileDropTarget.java | 70 +++++++++++++++++++ .../src/megameklab/util/UnitPrintManager.java | 8 ++- 11 files changed, 162 insertions(+), 16 deletions(-) create mode 100644 megameklab/src/megameklab/ui/MulDndBehaviour.java create mode 100644 megameklab/src/megameklab/util/MMLFileDropTarget.java diff --git a/megameklab/resources/megameklab/resources/Dialogs.properties b/megameklab/resources/megameklab/resources/Dialogs.properties index b516eee11..6937df920 100644 --- a/megameklab/resources/megameklab/resources/Dialogs.properties +++ b/megameklab/resources/megameklab/resources/Dialogs.properties @@ -66,6 +66,8 @@ ConfigurationDialog.startup.text=MML Startup: ConfigurationDialog.startup.tooltip=Depending on the startup type selected, MML will start in the main menu or, alternatively, directly load the most recent unit or start with a new unit instead of the main menu. ConfigurationDialog.mekChassis.text=Mek Chassis Arrangement: ConfigurationDialog.mekChassis.tooltip=Meks with a Clan and an IS chassis name will print their chassis in the selected arrangement. Meks with no clan chassis name will always just print their chassis. +ConfigurationDialog.cbMulDndBehaviour.text=MUL file drag and drop behaviour: +ConfigurationDialog.cbMulDndBehaviour.tooltip=What should be done when a MUL file is dragged onto the MML window? RecordSheetTask.printing=Printing RecordSheetTask.exporting=Exporting diff --git a/megameklab/resources/megameklab/resources/Menu.properties b/megameklab/resources/megameklab/resources/Menu.properties index b69fc38d7..5b8a40a5e 100644 --- a/megameklab/resources/megameklab/resources/Menu.properties +++ b/megameklab/resources/megameklab/resources/Menu.properties @@ -117,6 +117,9 @@ MMLStartUp.NEW_JUMPSHIP=New Advanced Aerospace MMLStartUp.NEW_SUPPORTVEE=New Support Vehicle MMLStartUp.NEW_PROTOMEK=New ProtoMek +MulDndBehaviour.PRINT=Print +MulDndBehaviour.EXPORT=Export to PDF + # The following values are used programatically by ClanISMekNameOrdering ClanISMekNameOrdering.CLAN_IS=Clan Name (IS Name) ClanISMekNameOrdering.IS_CLAN=IS Name (Clan Name) diff --git a/megameklab/src/megameklab/ui/MegaMekLabMainUI.java b/megameklab/src/megameklab/ui/MegaMekLabMainUI.java index f4466140e..1b1e61877 100644 --- a/megameklab/src/megameklab/ui/MegaMekLabMainUI.java +++ b/megameklab/src/megameklab/ui/MegaMekLabMainUI.java @@ -24,6 +24,7 @@ import megameklab.ui.util.ExitOnWindowClosingListener; import megameklab.ui.util.RefreshListener; import megameklab.util.CConfig; +import megameklab.util.MMLFileDropTarget; import javax.swing.*; import java.awt.*; @@ -34,7 +35,7 @@ public abstract class MegaMekLabMainUI extends JFrame implements RefreshListener protected MenuBar mmlMenuBar; protected boolean refreshRequired = false; private String originalName = ""; - + public MegaMekLabMainUI() { setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); addWindowListener(new ExitOnWindowClosingListener(this)); @@ -46,8 +47,9 @@ protected void finishSetup() { setJMenuBar(mmlMenuBar); reloadTabs(); refreshAll(); + this.setDropTarget(new MMLFileDropTarget(this)); } - + protected void setSizeAndLocation() { pack(); restrictToScrenSize(); @@ -196,4 +198,9 @@ public void refreshMenuBar() { public boolean hasEntityNameChanged() { return !MenuBar.createUnitFilename(entity).equals(originalName); } -} \ No newline at end of file + + @Override + public MenuBar getMMLMenuBar() { + return mmlMenuBar; + } +} diff --git a/megameklab/src/megameklab/ui/MenuBar.java b/megameklab/src/megameklab/ui/MenuBar.java index b82ab09eb..12462e116 100644 --- a/megameklab/src/megameklab/ui/MenuBar.java +++ b/megameklab/src/megameklab/ui/MenuBar.java @@ -1202,6 +1202,10 @@ private void loadUnitFromFile(int fileNumber) { } } + loadFile(unitFile); + } + + public void loadFile(File unitFile) { try { Entity loadedUnit = new MekFileParser(unitFile).getEntity(); diff --git a/megameklab/src/megameklab/ui/MenuBarOwner.java b/megameklab/src/megameklab/ui/MenuBarOwner.java index 04a1feae9..7f6699984 100644 --- a/megameklab/src/megameklab/ui/MenuBarOwner.java +++ b/megameklab/src/megameklab/ui/MenuBarOwner.java @@ -133,4 +133,6 @@ default void changeTheme(String lookAndFeelInfo) { } }); } + + MenuBar getMMLMenuBar(); } diff --git a/megameklab/src/megameklab/ui/MulDndBehaviour.java b/megameklab/src/megameklab/ui/MulDndBehaviour.java new file mode 100644 index 000000000..80da7cd2e --- /dev/null +++ b/megameklab/src/megameklab/ui/MulDndBehaviour.java @@ -0,0 +1,33 @@ +/* + * 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.ui; + +import java.util.ResourceBundle; + +public enum MulDndBehaviour { + PRINT, + EXPORT; + + private final ResourceBundle resources = ResourceBundle.getBundle("megameklab.resources.Menu"); + + /** @return A display name for this MMLStartUp taken from the resources (possibly localised). */ + public String getDisplayName() { + return resources.getString("MulDndBehaviour." + name()); + } +} diff --git a/megameklab/src/megameklab/ui/StartupGUI.java b/megameklab/src/megameklab/ui/StartupGUI.java index de277199c..d1b80ed78 100644 --- a/megameklab/src/megameklab/ui/StartupGUI.java +++ b/megameklab/src/megameklab/ui/StartupGUI.java @@ -29,6 +29,7 @@ import megameklab.ui.dialog.UiLoader; import megameklab.ui.util.ExitOnWindowClosingListener; import megameklab.util.CConfig; +import megameklab.util.MMLFileDropTarget; import megameklab.util.UnitUtil; import javax.swing.*; @@ -236,6 +237,7 @@ private void initComponents() { frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); + this.setDropTarget(new MMLFileDropTarget(this)); } /** @@ -314,4 +316,9 @@ public boolean hasEntityNameChanged() { public void refreshMenuBar() { mmlMenuBar.refreshMenuBar(); } + + @Override + public MenuBar getMMLMenuBar() { + return mmlMenuBar; + } } diff --git a/megameklab/src/megameklab/ui/dialog/settings/MiscSettingsPanel.java b/megameklab/src/megameklab/ui/dialog/settings/MiscSettingsPanel.java index 5c1df2036..93ee203f1 100644 --- a/megameklab/src/megameklab/ui/dialog/settings/MiscSettingsPanel.java +++ b/megameklab/src/megameklab/ui/dialog/settings/MiscSettingsPanel.java @@ -39,16 +39,10 @@ import megamek.common.preference.PreferenceManager; import megamek.logging.MMLogger; import megameklab.ui.MMLStartUp; +import megameklab.ui.MulDndBehaviour; import megameklab.ui.util.SpringUtilities; import megameklab.util.CConfig; -import org.apache.logging.log4j.LogManager; -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; import java.util.*; /** @@ -64,9 +58,10 @@ public class MiscSettingsPanel extends JPanel { private final JCheckBox chkSkipSavePrompts = new JCheckBox(); private final JTextField txtUserDir = new JTextField(20); private final JSlider guiScale = new JSlider(); + private final MMComboBox cbMulDndBehaviour = new MMComboBox<>("MUL Drag and Drop behaviour", MulDndBehaviour.values()); MiscSettingsPanel(JFrame parent) { - startUpMMComboBox.setRenderer(startUpRenderer); + startUpMMComboBox.setRenderer(miscComboBoxRenderer); startUpMMComboBox.setSelectedItem(CConfig.getStartUpType()); startUpMMComboBox.setToolTipText(resources.getString("ConfigurationDialog.startup.tooltip")); JLabel startUpLabel = new JLabel(resources.getString("ConfigurationDialog.startup.text")); @@ -78,6 +73,17 @@ public class MiscSettingsPanel extends JPanel { startUpLine.add(Box.createHorizontalStrut(5)); startUpLine.add(startUpMMComboBox); + cbMulDndBehaviour.setRenderer(miscComboBoxRenderer); + cbMulDndBehaviour.setToolTipText(resources.getString("ConfigurationDialog.cbMulDndBehaviour.tooltip")); + cbMulDndBehaviour.setSelectedItem(CConfig.getBooleanParam(CConfig.MISC_MUL_DND_BEHAVIOUR) ? MulDndBehaviour.EXPORT : MulDndBehaviour.PRINT); + JLabel mulDndLabel = new JLabel(resources.getString("ConfigurationDialog.cbMulDndBehaviour.text")); + mulDndLabel.setToolTipText(resources.getString("ConfigurationDialog.cbMulDndBehaviour.tooltip")); + + JPanel mulDndLine = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); + mulDndLine.add(mulDndLabel); + mulDndLine.add(Box.createHorizontalStrut(5)); + mulDndLine.add(cbMulDndBehaviour); + chkSummaryFormatTRO.setText(resources.getString("ConfigurationDialog.chkSummaryFormatTRO.text")); chkSummaryFormatTRO.setToolTipText(resources.getString("ConfigurationDialog.chkSummaryFormatTRO.tooltip")); @@ -136,11 +142,12 @@ public class MiscSettingsPanel extends JPanel { JPanel gridPanel = new JPanel(new SpringLayout()); gridPanel.add(startUpLine); gridPanel.add(userDirLine); + gridPanel.add(mulDndLine); gridPanel.add(chkSummaryFormatTRO); gridPanel.add(chkSkipSavePrompts); gridPanel.add(scaleLine); - SpringUtilities.makeCompactGrid(gridPanel, 5, 1, 0, 0, 15, 10); + SpringUtilities.makeCompactGrid(gridPanel, 6, 1, 0, 0, 15, 10); gridPanel.setBorder(new EmptyBorder(20, 30, 20, 30)); setLayout(new FlowLayout(FlowLayout.LEFT)); add(gridPanel); @@ -154,6 +161,7 @@ Map getMiscSettings() { ? MMLStartUp.SPLASH_SCREEN : startUpMMComboBox.getSelectedItem(); miscSettings.put(CConfig.MISC_STARTUP, startUp.name()); + miscSettings.put(CConfig.MISC_MUL_DND_BEHAVIOUR, String.valueOf(cbMulDndBehaviour.getSelectedItem() == MulDndBehaviour.EXPORT)); // User directory and gui scale are stored in MM's client settings, not in CConfig, therefore not added here return miscSettings; } @@ -166,7 +174,7 @@ float guiScale() { return 0.1f * guiScale.getValue(); } - DefaultListCellRenderer startUpRenderer = new DefaultListCellRenderer() { + DefaultListCellRenderer miscComboBoxRenderer = new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { @@ -175,6 +183,11 @@ public Component getListCellRendererComponent(JList list, Object value, int i }; private String displayName(Object value) { - return (value instanceof MMLStartUp) ? ((MMLStartUp) value).getDisplayName() : ""; + if (value instanceof MMLStartUp su) { + return su.getDisplayName(); + } else if (value instanceof MulDndBehaviour mdb) { + return mdb.getDisplayName(); + } + return ""; } } diff --git a/megameklab/src/megameklab/util/CConfig.java b/megameklab/src/megameklab/util/CConfig.java index 290857a42..90137fc2b 100644 --- a/megameklab/src/megameklab/util/CConfig.java +++ b/megameklab/src/megameklab/util/CConfig.java @@ -62,6 +62,7 @@ public final class CConfig { public static final String MISC_STARTUP = "StartupGui"; public static final String MISC_SUMMARY_FORMAT_TRO = "useTROFormat"; public static final String MISC_SKIP_SAFETY_PROMPTS = "skipSafetyPrompts"; + public static final String MISC_MUL_DND_BEHAVIOUR = "mulDndBehaviour"; public static final String GUI_PLAF = "lookAndFeel"; public static final String GUI_COLOR_WEAPONS = "Weapons"; diff --git a/megameklab/src/megameklab/util/MMLFileDropTarget.java b/megameklab/src/megameklab/util/MMLFileDropTarget.java new file mode 100644 index 000000000..f4a3e0a02 --- /dev/null +++ b/megameklab/src/megameklab/util/MMLFileDropTarget.java @@ -0,0 +1,70 @@ +/* + * 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.logging.MMLogger; +import megameklab.ui.MenuBarOwner; + +import java.awt.datatransfer.DataFlavor; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetDropEvent; +import java.io.File; +import java.util.List; + +public class MMLFileDropTarget extends DropTarget { + private static final MMLogger logger = MMLogger.create(MMLFileDropTarget.class); + + private final MenuBarOwner owner; + + public MMLFileDropTarget(MenuBarOwner owner) { + this.owner = owner; + } + + @Override + public synchronized void drop(DropTargetDropEvent event) { + try { + event.acceptDrop(DnDConstants.ACTION_COPY); + var files = (List) event.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); + if (files.size() != 1) { + event.dropComplete(false); + return; + } + + var file = files.get(0); + var name = file.getName(); + + if (name.endsWith(".mtf") || name.endsWith(".blk")) { + owner.getMMLMenuBar().loadFile(file); + event.dropComplete(true); + } else if (name.endsWith(".mul")) { + UnitPrintManager.printMUL(owner.getFrame(), CConfig.getBooleanParam(CConfig.MISC_MUL_DND_BEHAVIOUR), file); + event.dropComplete(true); + } else { + event.dropComplete(false); + } + + + } catch (Exception e) { + event.dropComplete(false); + logger.warn(e); + } + } +} diff --git a/megameklab/src/megameklab/util/UnitPrintManager.java b/megameklab/src/megameklab/util/UnitPrintManager.java index 945750468..0cfc729dd 100644 --- a/megameklab/src/megameklab/util/UnitPrintManager.java +++ b/megameklab/src/megameklab/util/UnitPrintManager.java @@ -77,20 +77,24 @@ public static void printMUL(JFrame parent, boolean printToPdf) { // I want a file, y'know! return; } + printMUL(parent, printToPdf, f.getSelectedFile()); + } + + public static void printMUL(JFrame parent, boolean printToPdf, File file) { Vector loadedUnits; try { var options = new GameOptions(); options.initialize(); options.getOption(RPG_MANEI_DOMINI).setValue(true); options.getOption(RPG_PILOT_ADVANTAGES).setValue(true); - loadedUnits = new MULParser(f.getSelectedFile(), options).getEntities(); + loadedUnits = new MULParser(file, options).getEntities(); loadedUnits.trimToSize(); } catch (Exception ex) { logger.error("", ex); return; } - new PrintQueueDialog(parent, printToPdf, loadedUnits, true, f.getSelectedFile().getName()).setVisible(true); + new PrintQueueDialog(parent, printToPdf, loadedUnits, true, file.getName()).setVisible(true); } public static File getExportFile(Frame parent) {