Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed Multiple-Nag Bug by Refactoring in-app New Campaign Handling #5357

Merged
merged 2 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MekHQ/resources/mekhq/resources/CampaignGUI.properties
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ menuHelp.text=Help
menuAbout.text=About...
#End Menu Resources

# In-App New Campaign
savePrompt.title=Save First?
savePrompt.text=Do you want to save the game before starting a new campaign?

## Unsorted Resources
btnAdvanceDay.text=Advance Day
btnAdvanceDay.toolTipText=Advance forward one day.
Expand Down
19 changes: 11 additions & 8 deletions MekHQ/src/mekhq/MekHQ.java
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,17 @@ private static void setUserPreferences() {
}
}

public void exit() {
int savePrompt = JOptionPane.showConfirmDialog(null, "Do you want to save the game before quitting MekHQ?",
"Save First?", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if ((savePrompt == JOptionPane.CANCEL_OPTION) || (savePrompt == JOptionPane.CLOSED_OPTION)) {
return;
} else if ((savePrompt == JOptionPane.YES_OPTION) && !getCampaigngui().saveCampaign(null)) {
// When the user did not actually save the game, don't close MHQ
return;
public void exit(boolean includeSavePrompt) {
if (includeSavePrompt) {
int savePrompt = JOptionPane.showConfirmDialog(null,
"Do you want to save the game before quitting MekHQ?",
"Save First?", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if ((savePrompt == JOptionPane.CANCEL_OPTION) || (savePrompt == JOptionPane.CLOSED_OPTION)) {
return;
} else if ((savePrompt == JOptionPane.YES_OPTION) && !getCampaigngui().saveCampaign(null)) {
// When the user did not actually save the game, don't close MHQ
return;
}
}

// Actually close MHQ
Expand Down
80 changes: 57 additions & 23 deletions MekHQ/src/mekhq/gui/CampaignGUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ private void initComponents() {
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent evt) {
getApplication().exit();
getApplication().exit(true);
}
});

Expand Down Expand Up @@ -362,12 +362,7 @@ private void initMenu() {
JMenuItem menuNew = new JMenuItem(resourceMap.getString("menuNew.text"));
menuNew.setMnemonic(KeyEvent.VK_N);
menuNew.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.ALT_DOWN_MASK));
menuNew.addActionListener(evt -> {
int decision = new NewCampaignConfirmationDialog().YesNoOption();
if (decision == JOptionPane.YES_OPTION) {
new DataLoadingDialog(frame, app, null).setVisible(true);
}
});
menuNew.addActionListener(evt -> handleInAppNewCampaign());
menuFile.add(menuNew);

// region menuImport
Expand Down Expand Up @@ -696,7 +691,7 @@ private void initMenu() {
JMenuItem menuExitItem = new JMenuItem(resourceMap.getString("menuExit.text"));
menuExitItem.setMnemonic(KeyEvent.VK_E);
menuExitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.ALT_DOWN_MASK));
menuExitItem.addActionListener(evt -> getApplication().exit());
menuExitItem.addActionListener(evt -> getApplication().exit(true));
menuFile.add(menuExitItem);

menuBar.add(menuFile);
Expand Down Expand Up @@ -1051,6 +1046,58 @@ private void initMenu() {
// endregion Help Menu
}

/**
* Handles a new campaign event triggered from within an existing campaign.
* <p>
* This method performs the following actions in sequence:
* <ul>
* <li>Prompts the user to save any current progress through a confirmation dialog.</li>
* <li>If the user chooses to cancel or closes the dialog, the operation is aborted.</li>
* <li>If the user agrees to save and the save operation fails, the operation is aborted.</li>
* <li>Unregisters all event handlers associated with the current campaign, including those
* in the CampaignGUI and tabs.</li>
* <li>Starts a new campaign by displaying a data loading dialog.</li>
* </ul>
* </p>
*/
private void handleInAppNewCampaign() {
int decision = new NewCampaignConfirmationDialog().YesNoOption();
if (decision != JOptionPane.YES_OPTION) {
return;
}

// Prompt the user to save
int savePrompt = JOptionPane.showConfirmDialog(null,
resourceMap.getString("savePrompt.text"),
resourceMap.getString("savePrompt.title"),
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);

// Abort if the user cancels, closes the dialog, or fails to save
if (savePrompt == JOptionPane.CANCEL_OPTION || savePrompt == JOptionPane.CLOSED_OPTION ||
(savePrompt == JOptionPane.YES_OPTION && !app.getCampaigngui().saveCampaign(null))) {
return;
}

// Unregister handlers for campaign tabs
for (int i = 0; i < tabMain.getTabCount(); i++) {
Component tab = tabMain.getComponentAt(i);
if (tab instanceof CampaignGuiTab) {
((CampaignGuiTab) tab).disposeTab();
}
}

// Unregister other handlers
MekHQ.unregisterHandler(this);

if (getCampaign().getStoryArc() != null) {
MekHQ.unregisterHandler(getCampaign().getStoryArc());
}

// Start a new campaign
new DataLoadingDialog(frame, app, null, null, true).setVisible(true);
}

private void initStatusBar() {
statusPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 20, 4));
statusPanel.getAccessibleContext().setAccessibleName("Status Bar");
Expand Down Expand Up @@ -1623,21 +1670,8 @@ public void refitUnit(Refit r, boolean selectModelName) {
if (getCampaign().isWorkingOnRefit(tech) || tech.isEngineer()) {
continue;
}
StringBuilder nameBuilder = new StringBuilder(128);
nameBuilder.append("<html>")
.append(tech.getFullName())
.append(", <b>")
.append(SkillType.getColoredExperienceLevelName(tech.getSkillLevel(getCampaign(), false)))
.append("</b> ")
.append(tech.getPrimaryRoleDesc())
.append(" (")
.append(getCampaign().getTargetFor(r, tech).getValueAsString())
.append("+), ")
.append(tech.getMinutesLeft())
.append('/')
.append(tech.getDailyAvailableTechTime())
.append(" minutes</html>");
name = nameBuilder.toString();
String nameBuilder = "<html>" + tech.getFullName() + ", <b>" + SkillType.getColoredExperienceLevelName(tech.getSkillLevel(getCampaign(), false)) + "</b> " + tech.getPrimaryRoleDesc() + " (" + getCampaign().getTargetFor(r, tech).getValueAsString() + "+), " + tech.getMinutesLeft() + '/' + tech.getDailyAvailableTechTime() + " minutes</html>";
name = nameBuilder;
techHash.put(name, tech);
if (tech.isRightTechTypeFor(r)) {
techList.add(lastRightTech++, name);
Expand Down
15 changes: 12 additions & 3 deletions MekHQ/src/mekhq/gui/dialog/CampaignOptionsDialog.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2022 - The MegaMek Team. All Rights Reserved.
* Copyright (c) 2009-2024 - The MegaMek Team. All Rights Reserved.
*
* This file is part of MekHQ.
*
Expand Down Expand Up @@ -45,6 +45,7 @@ public class CampaignOptionsDialog extends AbstractMHQValidationButtonDialog {
//region Variable Declarations
private final Campaign campaign;
private final boolean startup;
private final MekHQ application;
private CampaignOptionsPane campaignOptionsPane;
//endregion Variable Declarations

Expand All @@ -55,18 +56,21 @@ public CampaignOptionsDialog(final JFrame frame, final Campaign campaign, final
"CampaignOptionsDialog", "CampaignOptionsDialog.title");
this.campaign = campaign;
this.startup = startup;
this.application = null;
initialize();
}

/**
* Allows dialog to be constructed with an owner being another dialog
*/
public CampaignOptionsDialog(final JDialog owner, final JFrame frame, final Campaign campaign, final boolean startup) {
public CampaignOptionsDialog(final JDialog owner, final JFrame frame, final Campaign campaign,
final boolean startup, @Nullable final MekHQ application) {
super(owner, frame, true, ResourceBundle.getBundle("mekhq.resources.CampaignOptionsDialog",
MekHQ.getMHQOptions().getLocale()),
"CampaignOptionsDialog", "CampaignOptionsDialog.title");
this.campaign = campaign;
this.startup = startup;
this.application = application;
initialize();
}
//endregion Constructors
Expand Down Expand Up @@ -116,7 +120,12 @@ protected JPanel createButtonPanel() {
}));

panel.add(new MMButton("btnCancel", resources, "Cancel.text", "Cancel.toolTipText",
this::cancelActionPerformed));
evt -> {
if (application != null) {
application.exit(false);
} else {
cancelActionPerformed(evt);
}}));

return panel;
}
Expand Down
14 changes: 10 additions & 4 deletions MekHQ/src/mekhq/gui/dialog/DataLoadingDialog.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2022 - The MegaMek Team. All Rights Reserved.
* Copyright (c) 2009-2024 - The MegaMek Team. All Rights Reserved.
*
* This file is part of MekHQ.
*
Expand Down Expand Up @@ -75,21 +75,23 @@ public class DataLoadingDialog extends AbstractMHQDialog implements PropertyChan
private JLabel splash;
private JProgressBar progressBar;
private StoryArcStub storyArcStub;
private boolean isInAppNewCampaign;

// endregion Variable Declarations

// region Constructors
public DataLoadingDialog(final JFrame frame, final MekHQ application,
final @Nullable File campaignFile) {
this(frame, application, campaignFile, null);
this(frame, application, campaignFile, null, false);
}

public DataLoadingDialog(final JFrame frame, final MekHQ application,
final @Nullable File campaignFile, StoryArcStub stub) {
final @Nullable File campaignFile, StoryArcStub stub, final boolean isInAppNewCampaign) {
super(frame, "DataLoadingDialog", "DataLoadingDialog.title");
this.application = application;
this.campaignFile = campaignFile;
this.storyArcStub = stub;
this.isInAppNewCampaign = isInAppNewCampaign;
this.task = new Task(this);
getTask().addPropertyChangeListener(this);
initialize();
Expand Down Expand Up @@ -295,6 +297,9 @@ public Campaign doInBackground() throws Exception {

switch (presetSelectionDialog.getReturnState()) {
case PRESET_SELECTION_CANCELLED -> {
if (isInAppNewCampaign) {
application.exit(false);
}
return null;
}
case PRESET_SELECTION_SELECT -> {
Expand Down Expand Up @@ -338,7 +343,8 @@ public Campaign doInBackground() throws Exception {
campaign.getGameOptions().getOption(OptionsConstants.ALLOWED_YEAR).setValue(campaign.getGameYear());
campaign.setStartingSystem((preset == null) ? null : preset.getPlanet());

CampaignOptionsDialog optionsDialog = new CampaignOptionsDialog(dialog, getFrame(), campaign, true);
CampaignOptionsDialog optionsDialog =
new CampaignOptionsDialog(dialog, getFrame(), campaign, true, application);
optionsDialog.setLocationRelativeTo(getFrame());
optionsDialog.applyPreset(preset);
if (optionsDialog.showDialog().isCancelled()) {
Expand Down
11 changes: 6 additions & 5 deletions MekHQ/src/mekhq/gui/dialog/NewCampaignConfirmationDialog.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 - The MegaMek Team. All Rights Reserved.
* Copyright (c) 2021-2024 - The MegaMek Team. All Rights Reserved.
*
* This file is part of MekHQ.
*
Expand All @@ -18,12 +18,13 @@
*/
package mekhq.gui.dialog;

import javax.swing.JOptionPane;
import javax.swing.*;

public class NewCampaignConfirmationDialog {
public int YesNoOption() {
return JOptionPane.showConfirmDialog(null, "Are you sure you want to start a new campaign?\n" +
"Do not save your current campaign if you cancel after this point!", "Start New Campaign?",
return JOptionPane.showConfirmDialog(null,
"Are you sure you want to start a new campaign?",
"Start New Campaign?",
JOptionPane.YES_NO_OPTION);
}
}
}
35 changes: 12 additions & 23 deletions MekHQ/src/mekhq/gui/panels/StartupScreenPanel.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 - The MegaMek Team. All Rights Reserved.
* Copyright (c) 2022-2024 - The MegaMek Team. All Rights Reserved.
*
* This file is part of MekHQ.
*
Expand All @@ -18,25 +18,6 @@
*/
package mekhq.gui.panels;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;

import megamek.client.ui.swing.util.UIUtil;
import megamek.client.ui.swing.widget.MegaMekButton;
import megamek.client.ui.swing.widget.SkinSpecification;
Expand All @@ -57,6 +38,15 @@
import mekhq.gui.dialog.DataLoadingDialog;
import mekhq.gui.dialog.StoryArcSelectionDialog;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.util.List;

public class StartupScreenPanel extends AbstractMHQPanel {
private static final MMLogger logger = MMLogger.create(StartupScreenPanel.class);

Expand All @@ -71,8 +61,7 @@ public class StartupScreenPanel extends AbstractMHQPanel {
public boolean accept(File dir, String name) {
// Allow any .xml, .cpnx, and .cpnx.gz file that is not in the list of excluded
// files
List<String> toReject = Arrays.asList(
PreferenceManager.DEFAULT_CFG_FILE_NAME.toLowerCase());
List<String> toReject = List.of(PreferenceManager.DEFAULT_CFG_FILE_NAME.toLowerCase());
return (((name.toLowerCase().endsWith(".cpnx") || name.toLowerCase().endsWith(".xml"))
|| name.toLowerCase().endsWith(".cpnx.gz")) && !toReject.contains(name.toLowerCase()));
}
Expand Down Expand Up @@ -240,7 +229,7 @@ private void startCampaign(final @Nullable File file) {
}

private void startCampaign(final @Nullable File file, @Nullable StoryArcStub storyArcStub) {
new DataLoadingDialog(getFrame(), app, file, storyArcStub).setVisible(true);
new DataLoadingDialog(getFrame(), app, file, storyArcStub, false).setVisible(true);
}

private @Nullable File selectCampaignFile() {
Expand Down
Loading