From 1d299da0fec00a96b032d4270ab8175016323500 Mon Sep 17 00:00:00 2001 From: IllianiCBT Date: Fri, 4 Oct 2024 01:04:24 -0500 Subject: [PATCH] Implemented Campaign Options IIC Preset Picker Replaced the existing preset picker class with `SelectPresetDialog` - the preset picker that was developed for the Campaign Options IIC project. I figured compartmentalizing would make reviewing easier. Especially as CO IIC is going to be a hefty merge. --- .../resources/mekhq/resources/GUI.properties | 3 - .../NEWCampaignOptionsDialog.properties | 11 + MekHQ/src/mekhq/campaign/CampaignPreset.java | 49 ++--- MekHQ/src/mekhq/gui/CampaignGUI.java | 13 +- .../gui/dialog/CampaignOptionsDialog.java | 8 +- .../dialog/CampaignPresetSelectionDialog.java | 79 ------- .../mekhq/gui/dialog/DataLoadingDialog.java | 67 +++--- .../mekhq/gui/panes/CampaignPresetPane.java | 104 --------- .../campaignOptions/SelectPresetDialog.java | 199 ++++++++++++++++++ 9 files changed, 284 insertions(+), 249 deletions(-) create mode 100644 MekHQ/resources/mekhq/resources/NEWCampaignOptionsDialog.properties delete mode 100644 MekHQ/src/mekhq/gui/dialog/CampaignPresetSelectionDialog.java delete mode 100644 MekHQ/src/mekhq/gui/panes/CampaignPresetPane.java create mode 100644 MekHQ/src/mekhq/gui/panes/campaignOptions/SelectPresetDialog.java diff --git a/MekHQ/resources/mekhq/resources/GUI.properties b/MekHQ/resources/mekhq/resources/GUI.properties index 11eb2a4ca0..e3dae29a9d 100644 --- a/MekHQ/resources/mekhq/resources/GUI.properties +++ b/MekHQ/resources/mekhq/resources/GUI.properties @@ -433,9 +433,6 @@ btnNewYear.toolTipText=Advance to the first day of the next year (e.g., 01-JAN-3 btnNewQuinquennial.text=New Quinquennial btnNewQuinquennial.toolTipText=Advance to the first day of the next quinquennial (e.g., 01-JAN-3025, 01-JAN-3030).
WARNING: This will take a large amount of RAM to run, and may cause MekHQ to crash if there is not enough allocated. -### CampaignPresetSelectionDialog Class -CampaignPresetSelectionDialog.title=Select Campaign Preset - ### StoryArcSelectionDialog Class StoryArcSelectionDialog.title=Select a Story Arc diff --git a/MekHQ/resources/mekhq/resources/NEWCampaignOptionsDialog.properties b/MekHQ/resources/mekhq/resources/NEWCampaignOptionsDialog.properties new file mode 100644 index 0000000000..837d87a1db --- /dev/null +++ b/MekHQ/resources/mekhq/resources/NEWCampaignOptionsDialog.properties @@ -0,0 +1,11 @@ +## SelectPresetDialog Class +# SelectPresetDialog +presetDialog.title=Select a Campaign Preset +presetDialog.description=Choose a preset to tailor your experience. Each option provides a\ + \ well-balanced challenge, suitable for both newcomers and seasoned players. +presetDialogSelect.name=Confirm +presetDialogSelect.tooltip=Confirm the currently selected preset. +presetDialogCustomize.name=Customize +presetDialogCustomize.tooltip=Select a preset, then open the campaign options menu. +presetDialogCancel.name=Cancel +presetDialogCancel.tooltip=Return to the prior screen. \ No newline at end of file diff --git a/MekHQ/src/mekhq/campaign/CampaignPreset.java b/MekHQ/src/mekhq/campaign/CampaignPreset.java index 4b996ad4e3..cf58104fc4 100644 --- a/MekHQ/src/mekhq/campaign/CampaignPreset.java +++ b/MekHQ/src/mekhq/campaign/CampaignPreset.java @@ -18,33 +18,6 @@ */ package mekhq.campaign; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.ResourceBundle; -import java.util.stream.Collectors; - -import javax.swing.JFrame; -import javax.swing.JOptionPane; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - import megamek.Version; import megamek.common.annotations.Nullable; import megamek.common.options.GameOptions; @@ -64,15 +37,26 @@ import mekhq.campaign.universe.Systems; import mekhq.campaign.universe.companyGeneration.CompanyGenerationOptions; import mekhq.utilities.MHQXMLUtility; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.swing.*; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.util.*; +import java.util.stream.Collectors; /** * This is an object which holds a set of objects that collectively define the * initial options setup for a campaign. - * + *

* It includes both startup values, which are only used on initial startup (the * date, starting planet, and rank system), and continuous options, which can be * applied at any time (campaign options, skills, SPAs). - * + *

* It also includes a short title and description that allows one to create and * save different presets. The goal is to allow users to create and load various * different presets. @@ -162,6 +146,13 @@ public boolean isUserData() { return userData; } + /** + * @return the title of the {@link CampaignPreset} + */ + public String getTitle() { + return title; + } + public void setTitle(final String title) { this.title = title; } diff --git a/MekHQ/src/mekhq/gui/CampaignGUI.java b/MekHQ/src/mekhq/gui/CampaignGUI.java index 645e8ad867..a86193246f 100644 --- a/MekHQ/src/mekhq/gui/CampaignGUI.java +++ b/MekHQ/src/mekhq/gui/CampaignGUI.java @@ -74,6 +74,7 @@ import mekhq.gui.dialog.reportDialogs.*; import mekhq.gui.enums.MHQTabType; import mekhq.gui.model.PartsTableModel; +import mekhq.gui.panes.campaignOptions.SelectPresetDialog; import mekhq.io.FileType; import mekhq.utilities.MHQXMLUtility; import org.w3c.dom.Document; @@ -95,6 +96,8 @@ import java.util.stream.IntStream; import java.util.zip.GZIPOutputStream; +import static mekhq.gui.panes.campaignOptions.SelectPresetDialog.PRESET_SELECTION_CANCELLED; + /** * The application's main frame. */ @@ -307,7 +310,7 @@ private void setUserPreferences() { * as they are both accessed through the same GUI page. * The following mnemonic keys are being used as of 30-MAR-2020: * A, B, C, E, F, H, I, L, M, N, O, P, R, S, T, V, W, / - * + *

* Note 1: the slash is used for the help, as it is normally the same key as the * ? * Note 2: the A mnemonic is used for the Advance Day button @@ -376,9 +379,9 @@ private void initMenu() { miImportCampaignPreset.setMnemonic(KeyEvent.VK_C); miImportCampaignPreset.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_DOWN_MASK)); miImportCampaignPreset.addActionListener(evt -> { - final CampaignPresetSelectionDialog campaignPresetSelectionDialog = new CampaignPresetSelectionDialog( - getFrame()); - if (!campaignPresetSelectionDialog.showDialog().isConfirmed()) { + final SelectPresetDialog campaignPresetSelectionDialog = + new SelectPresetDialog(getFrame(), true, false); + if (campaignPresetSelectionDialog.getReturnState() == PRESET_SELECTION_CANCELLED) { return; } final CampaignPreset preset = campaignPresetSelectionDialog.getSelectedPreset(); @@ -1545,7 +1548,7 @@ private void menuOptionsActionPerformed(final ActionEvent evt) { getCampaign().getUnitMarket().setOffers(unitMarket.getOffers()); miUnitMarket.setVisible(!getCampaign().getUnitMarket().getMethod().isNone()); } - + AbstractContractMarket contractMarket = getCampaign().getContractMarket(); if (contractMarket.getMethod() != newOptions.getContractMarketMethod()) { getCampaign().setContractMarket(newOptions.getContractMarketMethod().getContractMarket()); diff --git a/MekHQ/src/mekhq/gui/dialog/CampaignOptionsDialog.java b/MekHQ/src/mekhq/gui/dialog/CampaignOptionsDialog.java index 5ecc984881..899912d1f0 100644 --- a/MekHQ/src/mekhq/gui/dialog/CampaignOptionsDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/CampaignOptionsDialog.java @@ -28,12 +28,15 @@ import mekhq.gui.FileDialogs; import mekhq.gui.baseComponents.AbstractMHQValidationButtonDialog; import mekhq.gui.panes.CampaignOptionsPane; +import mekhq.gui.panes.campaignOptions.SelectPresetDialog; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.util.ResourceBundle; +import static mekhq.gui.panes.campaignOptions.SelectPresetDialog.PRESET_SELECTION_CANCELLED; + /** * @author Jay Lawson (jaylawson39 at yahoo.com) (Original Version, now largely CampaignOptionsPane) * @author Justin 'Windchild' Bowen (Current Version) @@ -105,8 +108,9 @@ protected JPanel createButtonPanel() { panel.add(new MMButton("btnLoadPreset", resources, "btnLoadPreset.text", "btnLoadPreset.toolTipText", evt -> { - final CampaignPresetSelectionDialog presetSelectionDialog = new CampaignPresetSelectionDialog(getFrame()); - if (presetSelectionDialog.showDialog().isConfirmed()) { + final SelectPresetDialog presetSelectionDialog = + new SelectPresetDialog(getFrame(), true, false); + if (presetSelectionDialog.getReturnState() != PRESET_SELECTION_CANCELLED) { applyPreset(presetSelectionDialog.getSelectedPreset()); } })); diff --git a/MekHQ/src/mekhq/gui/dialog/CampaignPresetSelectionDialog.java b/MekHQ/src/mekhq/gui/dialog/CampaignPresetSelectionDialog.java deleted file mode 100644 index 848be08b22..0000000000 --- a/MekHQ/src/mekhq/gui/dialog/CampaignPresetSelectionDialog.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. - * - * This file is part of MekHQ. - * - * MekHQ 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. - * - * MekHQ 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 MekHQ. If not, see . - */ -package mekhq.gui.dialog; - -import megamek.common.annotations.Nullable; -import mekhq.campaign.CampaignPreset; -import mekhq.gui.baseComponents.AbstractMHQButtonDialog; -import mekhq.gui.panes.CampaignPresetPane; - -import javax.swing.*; -import java.awt.*; - -public class CampaignPresetSelectionDialog extends AbstractMHQButtonDialog { - //region Variable Declarations - private CampaignPresetPane presetSelectionPanel; - //endregion Variable Declarations - - //region Constructors - public CampaignPresetSelectionDialog(final JFrame parentFrame) { - super(parentFrame, "CampaignPresetSelectionDialog", "CampaignPresetSelectionDialog.title"); - initialize(); - } - - /** - * Allows dialog to be constructed using a dialog as owner - */ - public CampaignPresetSelectionDialog(final JDialog parentDialog, final JFrame parentFrame) { - super(parentDialog, parentFrame, "CampaignPresetSelectionDialog", "CampaignPresetSelectionDialog.title"); - initialize(); - } - //endregion Constructors - - //region Getters/Setters - public CampaignPresetPane getPresetSelectionPanel() { - return presetSelectionPanel; - } - - public void setPresetSelectionPanel(final CampaignPresetPane presetSelectionPanel) { - this.presetSelectionPanel = presetSelectionPanel; - } - - /** - * @return the selected preset, or null if the dialog was cancelled or no preset was selected - */ - public @Nullable CampaignPreset getSelectedPreset() { - return getResult().isConfirmed() ? getPresetSelectionPanel().getSelectedPreset() : null; - } - //endregion Getters/Setters - - //region Initialization - @Override - protected Container createCenterPane() { - setPresetSelectionPanel(new CampaignPresetPane(getFrame())); - return getPresetSelectionPanel(); - } - //endregion Initialization - - @Override - public void setVisible(final boolean visible) { - // Only show if there are presets to select from - super.setVisible(visible && (getPresetSelectionPanel().getPresets().getModel().getSize() > 0)); - } -} diff --git a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java index 090f7a0702..db6a62606b 100644 --- a/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java +++ b/MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java @@ -18,23 +18,6 @@ */ package mekhq.gui.dialog; -import java.awt.BorderLayout; -import java.awt.Container; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; -import java.io.FileInputStream; -import java.time.LocalDate; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; - -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JProgressBar; -import javax.swing.SwingWorker; - import megamek.client.generator.RandomCallsignGenerator; import megamek.client.generator.RandomNameGenerator; import megamek.client.ui.swing.util.UIUtil; @@ -66,6 +49,21 @@ import mekhq.campaign.universe.Systems; import mekhq.campaign.universe.eras.Eras; import mekhq.gui.baseComponents.AbstractMHQDialog; +import mekhq.gui.panes.campaignOptions.SelectPresetDialog; + +import javax.swing.*; +import java.awt.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.FileInputStream; +import java.time.LocalDate; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; + +import static mekhq.gui.panes.campaignOptions.SelectPresetDialog.PRESET_SELECTION_CANCELLED; +import static mekhq.gui.panes.campaignOptions.SelectPresetDialog.PRESET_SELECTION_CUSTOMIZE; +import static mekhq.gui.panes.campaignOptions.SelectPresetDialog.PRESET_SELECTION_SELECT; public class DataLoadingDialog extends AbstractMHQDialog implements PropertyChangeListener { private static final MMLogger logger = MMLogger.create(DataLoadingDialog.class); @@ -290,12 +288,23 @@ public Campaign doInBackground() throws Exception { campaign = new Campaign(); // Campaign Preset - final CampaignPresetSelectionDialog presetSelectionDialog = new CampaignPresetSelectionDialog(dialog, - getFrame()); - if (presetSelectionDialog.showDialog().isCancelled()) { - return null; + final SelectPresetDialog presetSelectionDialog = + new SelectPresetDialog(getFrame(), true, true); + CampaignPreset preset; + boolean isSelect = false; + + switch (presetSelectionDialog.getReturnState()) { + case PRESET_SELECTION_CANCELLED -> { + return null; + } + case PRESET_SELECTION_SELECT -> { + preset = presetSelectionDialog.getSelectedPreset(); + isSelect = true; + } + case PRESET_SELECTION_CUSTOMIZE -> preset = presetSelectionDialog.getSelectedPreset(); + default -> throw new IllegalStateException("Unexpected value in mekhq/gui/dialog/DataLoadingDialog.java/Step 6: " + + presetSelectionDialog.getReturnState()); } - final CampaignPreset preset = presetSelectionDialog.getSelectedPreset(); // Date final LocalDate date = ((preset == null) || (preset.getDate() == null)) @@ -319,11 +328,15 @@ public Campaign doInBackground() throws Exception { setVisible(false); // Campaign Options - CampaignOptionsDialog optionsDialog = new CampaignOptionsDialog(dialog, getFrame(), campaign, true); - optionsDialog.setLocationRelativeTo(getFrame()); - optionsDialog.applyPreset(preset); - if (optionsDialog.showDialog().isCancelled()) { - return null; + if (isSelect && preset != null) { + preset.applyContinuousToCampaign(campaign); + } else { + CampaignOptionsDialog optionsDialog = new CampaignOptionsDialog(dialog, getFrame(), campaign, true); + optionsDialog.setLocationRelativeTo(getFrame()); + optionsDialog.applyPreset(preset); + if (optionsDialog.showDialog().isCancelled()) { + return null; + } } // initialize reputation diff --git a/MekHQ/src/mekhq/gui/panes/CampaignPresetPane.java b/MekHQ/src/mekhq/gui/panes/CampaignPresetPane.java deleted file mode 100644 index 864bf8f89f..0000000000 --- a/MekHQ/src/mekhq/gui/panes/CampaignPresetPane.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2021 - The MegaMek Team. All Rights Reserved. - * - * This file is part of MekHQ. - * - * MekHQ 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. - * - * MekHQ 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 MekHQ. If not, see . - */ -package mekhq.gui.panes; - -import java.awt.Dimension; -import java.awt.GridLayout; - -import javax.swing.DefaultListModel; -import javax.swing.JFrame; -import javax.swing.JList; -import javax.swing.JScrollPane; -import javax.swing.ListSelectionModel; - -import megamek.client.ui.preferences.JListPreference; -import megamek.client.ui.preferences.PreferencesNode; -import megamek.common.annotations.Nullable; -import megamek.logging.MMLogger; -import mekhq.campaign.CampaignPreset; -import mekhq.gui.baseComponents.AbstractMHQScrollPane; -import mekhq.gui.baseComponents.AbstractMHQScrollablePanel; -import mekhq.gui.baseComponents.DefaultMHQScrollablePanel; -import mekhq.gui.renderers.CampaignPresetRenderer; - -public class CampaignPresetPane extends AbstractMHQScrollPane { - private static final MMLogger logger = MMLogger.create(CampaignPresetPane.class); - - // region Variable Declarations - private JList presets; - // endregion Variable Declarations - - // region Constructors - public CampaignPresetPane(final JFrame frame) { - super(frame, "CampaignPresetPane", JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, - JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - initialize(); - } - // endregion Constructors - - // region Getters/Setters - public JList getPresets() { - return presets; - } - - public void setPresets(final JList presets) { - this.presets = presets; - } - - public @Nullable CampaignPreset getSelectedPreset() { - return getPresets().getSelectedValue(); - } - // endregion Getters/Setters - - // region Initialization - @Override - protected void initialize() { - final DefaultListModel listModel = new DefaultListModel<>(); - listModel.addAll(CampaignPreset.getCampaignPresets()); - setPresets(new JList<>(listModel)); - getPresets().setName("campaignPresetList"); - getPresets().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - getPresets().setSelectedIndex(0); - getPresets().setLayoutOrientation(JList.VERTICAL); - getPresets().setCellRenderer(new CampaignPresetRenderer(getFrame())); - - final AbstractMHQScrollablePanel panel = new DefaultMHQScrollablePanel(getFrame(), - "campaignPresetPanel", new GridLayout(1, 1)); - panel.add(getPresets()); - - setViewportView(panel); - setMinimumSize(new Dimension(350, 150)); - setPreferredSize(new Dimension(500, 400)); - - try { - setPreferences(); - } catch (Exception ex) { - logger.error( - "Error setting the Campaign Preset Pane's preferences. Keeping the created pane, but this is likely to cause some oddities.", - ex); - } - } - - @Override - protected void setCustomPreferences(final PreferencesNode preferences) throws Exception { - super.setCustomPreferences(preferences); - preferences.manage(new JListPreference(getPresets())); - } - // endregion Initialization -} diff --git a/MekHQ/src/mekhq/gui/panes/campaignOptions/SelectPresetDialog.java b/MekHQ/src/mekhq/gui/panes/campaignOptions/SelectPresetDialog.java new file mode 100644 index 0000000000..342da2a033 --- /dev/null +++ b/MekHQ/src/mekhq/gui/panes/campaignOptions/SelectPresetDialog.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2024 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MekHQ. + * + * MekHQ 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. + * + * MekHQ 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 MekHQ. If not, see . + */ +package mekhq.gui.panes.campaignOptions; + +import megamek.logging.MMLogger; +import mekhq.MekHQ; +import mekhq.campaign.CampaignPreset; + +import javax.swing.*; +import javax.swing.GroupLayout.Alignment; +import java.awt.*; +import java.util.ResourceBundle; + +import static megamek.client.ui.WrapLayout.wordWrap; + +/** + * A dialog for selecting campaign presets. Extends {@link JDialog}. + * Keeps track of the selected preset and return state. + * Provides options to select a preset, customize a preset, or cancel the operation. + */ +public class SelectPresetDialog extends JDialog { + private static String RESOURCE_PACKAGE = "mekhq/resources/NEWCampaignOptionsDialog"; + private static final ResourceBundle resources = ResourceBundle.getBundle(RESOURCE_PACKAGE, + MekHQ.getMHQOptions().getLocale()); + + final static String OPTION_SELECT_PRESET = resources.getString("presetDialogSelect.name"); + final static String OPTION_CUSTOMIZE_PRESET = resources.getString("presetDialogCustomize.name"); + final static String OPTION_CANCEL = resources.getString("presetDialogCancel.name"); + + private static final MMLogger logger = MMLogger.create(SelectPresetDialog.class); + + private int returnState; + public static final int PRESET_SELECTION_CANCELLED = 0; + public static final int PRESET_SELECTION_SELECT = 1; + public static final int PRESET_SELECTION_CUSTOMIZE = 2; + private CampaignPreset selectedPreset; + + /** + * Returns the current return state of the dialog. + *

{@code PRESET_SELECTION_CANCELLED} = 0 + *

{@code PRESET_SELECTION_SELECT} = 1 + *

{@code PRESET_SELECTION_CUSTOMIZE} = 2 + * + * @return An integer representing the return state of the dialog. + */ + public int getReturnState() { + return returnState; + } + + /** + * @return The {@link CampaignPreset} that was selected. + */ + public CampaignPreset getSelectedPreset() { + return selectedPreset; + } + + /** + * Constructs a dialog window for selecting a campaign preset. + * + * @param frame the parent {@link JFrame} for the dialog + * @param includePresetSelectOption whether to include the option to select a preset + * @param includeCustomizePresetOption whether to include the option to customize a preset + */ + public SelectPresetDialog(JFrame frame, boolean includePresetSelectOption, boolean includeCustomizePresetOption) { + super(frame, resources.getString("presetDialog.title"), true); + returnState = PRESET_SELECTION_CANCELLED; + + setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + + ImageIcon image = new ImageIcon("data/images/misc/megamek-splash.png"); + JLabel imageLabel = new JLabel(image); + add(imageLabel, BorderLayout.NORTH); + + JPanel centerPanel = new JPanel(); + final GroupLayout layout = new GroupLayout(centerPanel); + layout.setAutoCreateGaps(true); + layout.setAutoCreateContainerGaps(true); + centerPanel.setLayout(layout); + + JLabel descriptionLabel = new JLabel(String.format( + "

%s
", + resources.getString("presetDialog.description"))); + + final DefaultListModel campaignPresets = new DefaultListModel<>(); + campaignPresets.addAll(CampaignPreset.getCampaignPresets()); + + if (campaignPresets.isEmpty()) { + logger.error("No campaign presets found", "Error"); + } + + JComboBox comboBox = new JComboBox<>(); + comboBox.setModel(convertPresetListModelToComboBoxModel(campaignPresets)); + + DefaultListCellRenderer listRenderer = new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, + boolean cellHasFocus) { + if (value instanceof CampaignPreset preset) { + setText(preset.getTitle()); + setToolTipText(wordWrap(preset.getDescription())); + } + + setHorizontalAlignment(JLabel.CENTER); + + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + return this; + } + }; + comboBox.setRenderer(listRenderer); + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addComponent(descriptionLabel) + .addComponent(comboBox) + ); + + layout.setHorizontalGroup( + layout.createParallelGroup(Alignment.LEADING) + .addComponent(descriptionLabel) + .addComponent(comboBox) + ); + + add(centerPanel, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(); + + JButton buttonSelect = new JButton(OPTION_SELECT_PRESET); + buttonSelect.setToolTipText(resources.getString("presetDialogSelect.tooltip")); + buttonSelect.addActionListener(e -> { + selectedPreset = (CampaignPreset) comboBox.getSelectedItem(); + returnState = PRESET_SELECTION_SELECT; + dispose(); + }); + buttonSelect.setEnabled(includePresetSelectOption); + buttonPanel.add(buttonSelect); + + JButton buttonCustomize = new JButton(OPTION_CUSTOMIZE_PRESET); + buttonCustomize.setToolTipText(resources.getString("presetDialogCustomize.tooltip")); + buttonCustomize.addActionListener(e -> { + selectedPreset = (CampaignPreset) comboBox.getSelectedItem(); + returnState = PRESET_SELECTION_CUSTOMIZE; + dispose(); + }); + buttonCustomize.setEnabled(includeCustomizePresetOption); + buttonPanel.add(buttonCustomize); + + JButton buttonCancel = new JButton(OPTION_CANCEL); + buttonCancel.setToolTipText(resources.getString("presetDialogCancel.tooltip")); + buttonCancel.addActionListener(e -> { + returnState = PRESET_SELECTION_CANCELLED; + dispose(); + }); + buttonPanel.add(buttonCancel); + + add(buttonPanel, BorderLayout.PAGE_END); + + pack(); + setAlwaysOnTop(true); + setResizable(false); + setLocationRelativeTo(null); + setVisible(true); + } + + /** + * Converts a {@link DefaultListModel} of {@link CampaignPreset} objects to a {@link DefaultComboBoxModel}. + * + * @param listModel The {@link DefaultListModel} to convert. + * @return The converted {@link DefaultComboBoxModel}. + */ + private DefaultComboBoxModel convertPresetListModelToComboBoxModel( + DefaultListModel listModel) { + + // Create a new DefaultComboBoxModel + DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel<>(); + + // Populate the DefaultComboBoxModel with the elements from the DefaultListModel + for (int i = 0; i < listModel.size(); i++) { + comboBoxModel.addElement(listModel.get(i)); + } + + return comboBoxModel; + } +}