package tools.map.xml.creator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLEditorKit;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.xml.sax.SAXException;
import games.strategy.debug.ClientLogger;
import games.strategy.engine.ClientFileSystemHelper;
import games.strategy.engine.data.GameParser;
import games.strategy.engine.framework.lookandfeel.LookAndFeel;
import games.strategy.engine.framework.startup.mc.GameSelectorModel;
import games.strategy.ui.SwingAction;
import tools.image.FileSave;
/**
* A frame that will show the different steps creating a game XML.
*/
public class MapXmlCreator extends JFrame {
private static final String BUTTON_LABEL_SAVE_MAP_XML = "Save Map XML";
private static final String FILE_NAME_CENTERS_TXT = "centers.txt";
static final String FILE_NAME_ENDING_XML = ".xml";
private static final String FILE_NAME_ENDING_GIF = ".gif";
public static final String FILE_NAME_ENDING_PNG = ".png";
private static final long serialVersionUID = 3593102638082774498L;
public static final String TRIPLEA_MAP_FOLDER = "triplea.map.folder";
public static final String TRIPLEA_UNIT_ZOOM = "triplea.unit.zoom";
public static final String TRIPLEA_UNIT_WIDTH = "triplea.unit.width";
public static final String TRIPLEA_UNIT_HEIGHT = "triplea.unit.height";
private GameStep highestStep = GAME_STEP_FIRST;
static File mapImageFile = null;
static File mapCentersFile = null;
static File mapPolygonsFile = null;
static String waterFilterString = "";
static File mapFolderLocation = null;
final JPanel mainPanel;
final JPanel sidePanel;
final JPanel stepPanel = new JPanel();
private JPanel stepListPanel;
private final ArrayList<GameStepLabel> stepList = new ArrayList<>();
private final JPanel southPanel = new JPanel();
private JPanel southCenterPanel;
private JButton buttonHelp;
private JButton buttonBack;
private JButton autoFillButton;
private JButton nextButton;
private final JPanel stepActionPanel;
public JPanel getStepActionPanel() {
return stepActionPanel;
}
private final JLabel stepTitleLabel;
private final JPanel actionPanel;
private GameStep currentStep = GAME_STEP_FIRST;
public static final GameStep GAME_STEP_FIRST = GameStep.MAP_PROPERTIES;
public static final String MAP_XML_CREATOR_LOGGER_NAME = "Logger for Map XML Creation";
public static enum GameStep {
MAP_PROPERTIES,
TERRITORY_DEFINITIONS,
TERRITORY_CONNECTIONS,
PLAYERS_AND_ALLIANCES,
UNIT_DEFINITIONS,
GAMEPLAY_SEQUENCE,
PLAYER_SEQUENCE,
TECHNOLOGY_DEFINITIONS,
PRODUCTION_FRONTIERS,
UNIT_ATTACHMENTS,
TERRITORY_PRODUCTION,
CANAL_DEFINITIONS,
TERRITORY_OWNERSHIP,
UNIT_PLACEMENTS,
GAME_SETTINGS,
MAP_FINISHED
}
public static GameStep getMaxGameStep(final GameStep step1, final GameStep step2) {
return (step1.ordinal() >= step2.ordinal()) ? step1 : step2;
}
private static String getGameStepName(final GameStep step) {
switch (step) {
case MAP_PROPERTIES:
return "Map Properties";
case TERRITORY_DEFINITIONS:
return "Territory Definitions";
case TERRITORY_CONNECTIONS:
return "Territory Connections";
case PLAYERS_AND_ALLIANCES:
return "Players and Alliances";
case UNIT_DEFINITIONS:
return "Unit Definitions";
case GAMEPLAY_SEQUENCE:
return "Gameplay Sequence";
case PLAYER_SEQUENCE:
return "Player Sequence";
case TECHNOLOGY_DEFINITIONS:
return "Technology Definitions";
case PRODUCTION_FRONTIERS:
return "Production Frontiers";
case UNIT_ATTACHMENTS:
return "Unit Attachments";
case TERRITORY_PRODUCTION:
return "Territory Production";
case CANAL_DEFINITIONS:
return "Canal Definitions";
case TERRITORY_OWNERSHIP:
return "Territory Ownership";
case UNIT_PLACEMENTS:
return "Unit Placements";
case GAME_SETTINGS:
return "Game Settings";
case MAP_FINISHED:
return "Map finished!";
default:
throw new IllegalArgumentException(
"Provided value is not valid for " + GameStep.class);
}
}
private static GameStep getNextGameStepTo(final GameStep currentStep) {
switch (currentStep) {
case MAP_PROPERTIES:
return GameStep.TERRITORY_DEFINITIONS;
case TERRITORY_DEFINITIONS:
return GameStep.TERRITORY_CONNECTIONS;
case TERRITORY_CONNECTIONS:
return GameStep.PLAYERS_AND_ALLIANCES;
case PLAYERS_AND_ALLIANCES:
return GameStep.UNIT_DEFINITIONS;
case UNIT_DEFINITIONS:
return GameStep.GAMEPLAY_SEQUENCE;
case GAMEPLAY_SEQUENCE:
return GameStep.PLAYER_SEQUENCE;
case PLAYER_SEQUENCE:
return GameStep.TECHNOLOGY_DEFINITIONS;
case TECHNOLOGY_DEFINITIONS:
return GameStep.PRODUCTION_FRONTIERS;
case PRODUCTION_FRONTIERS:
return GameStep.UNIT_ATTACHMENTS;
case UNIT_ATTACHMENTS:
return GameStep.TERRITORY_PRODUCTION;
case TERRITORY_PRODUCTION:
return GameStep.CANAL_DEFINITIONS;
case CANAL_DEFINITIONS:
return GameStep.TERRITORY_OWNERSHIP;
case TERRITORY_OWNERSHIP:
return GameStep.UNIT_PLACEMENTS;
case UNIT_PLACEMENTS:
return GameStep.GAME_SETTINGS;
case GAME_SETTINGS:
return GameStep.MAP_FINISHED;
case MAP_FINISHED:
return GameStep.MAP_FINISHED;
default:
throw new IllegalArgumentException(
"'" + currentStep + "' is not a valid string for " + GameStep.class);
}
}
private static GameStep getPrevGameStepTo(final GameStep currentStep) {
switch (currentStep) {
case MAP_PROPERTIES:
return GameStep.MAP_PROPERTIES;
case TERRITORY_DEFINITIONS:
return GameStep.MAP_PROPERTIES;
case TERRITORY_CONNECTIONS:
return GameStep.TERRITORY_DEFINITIONS;
case PLAYERS_AND_ALLIANCES:
return GameStep.TERRITORY_CONNECTIONS;
case UNIT_DEFINITIONS:
return GameStep.PLAYERS_AND_ALLIANCES;
case GAMEPLAY_SEQUENCE:
return GameStep.UNIT_DEFINITIONS;
case PLAYER_SEQUENCE:
return GameStep.GAMEPLAY_SEQUENCE;
case TECHNOLOGY_DEFINITIONS:
return GameStep.PLAYER_SEQUENCE;
case PRODUCTION_FRONTIERS:
return GameStep.TECHNOLOGY_DEFINITIONS;
case UNIT_ATTACHMENTS:
return GameStep.PRODUCTION_FRONTIERS;
case TERRITORY_PRODUCTION:
return GameStep.UNIT_ATTACHMENTS;
case CANAL_DEFINITIONS:
return GameStep.TERRITORY_PRODUCTION;
case TERRITORY_OWNERSHIP:
return GameStep.CANAL_DEFINITIONS;
case UNIT_PLACEMENTS:
return GameStep.TERRITORY_OWNERSHIP;
case GAME_SETTINGS:
return GameStep.UNIT_PLACEMENTS;
case MAP_FINISHED:
return GameStep.GAME_SETTINGS;
default:
throw new IllegalArgumentException(
"'" + currentStep + "' is not a valid string for " + GameStep.class);
}
}
public static String[] getProperties() {
return new String[] {TRIPLEA_MAP_FOLDER, TRIPLEA_UNIT_ZOOM, TRIPLEA_UNIT_WIDTH, TRIPLEA_UNIT_HEIGHT};
}
private static final Logger logger = Logger.getLogger(MAP_XML_CREATOR_LOGGER_NAME);
public static Logger getLogger() {
return logger;
}
public static void main(final String[] args) {
MapXmlCreator.getLogger().setLevel(Level.OFF);
MapXmlCreator.log(Level.INFO, "Starting MapXMLCreator");
// handleCommandLineArgs(args);
LookAndFeel.setupLookAndFeel();
start();
}
public static void start() {
SwingUtilities.invokeLater(() -> {
final MapXmlCreator creator = new MapXmlCreator();
creator.setSize(800, 600);
creator.setPreferredSize(creator.getSize());
creator.goToStep(GAME_STEP_FIRST);
creator.setLocationRelativeTo(null);
creator.setVisible(true);
});
}
public MapXmlCreator() {
super("TripleA Map XML Creator");
mapFolderLocation = getDefaultMapFolderLocation();
final File myFile = getDefaultMapXmlFile();
if (myFile.exists()) {
try {
loadXmlFromFilePath(myFile.getAbsolutePath());
} catch (SAXException | IOException | ParserConfigurationException e) {
getLogger().log(Level.WARNING,
"Default Map XML File could not be loaded from '" + myFile.getAbsolutePath() + "'.", e);
throw new IllegalStateException(
"Default Map XML File could not be loaded from '" + myFile.getAbsolutePath() + "'.");
}
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Action openAction = createMenuBar();
// components
mainPanel = new JPanel();
sidePanel = new JPanel();
createStepListPanel();
sidePanel.setLayout(new BoxLayout(sidePanel, BoxLayout.Y_AXIS));
sidePanel.add(Box.createVerticalStrut(2));
sidePanel.add(stepListPanel);
sidePanel.add(Box.createVerticalGlue());
stepListPanel.setLayout(new GridLayout(stepList.size(), 1, 0, 10));
stepListPanel.setBorder(new EmptyBorder(10, 2, 0, 5));
stepListPanel.setPreferredSize(new Dimension(170, 410));
// set up the layout manager
this.getContentPane().setLayout(new BorderLayout());
final JScrollPane scrollPane = new JScrollPane(sidePanel);
scrollPane.setBorder(new MatteBorder(1, 1, 1, 1, Color.DARK_GRAY));
this.getContentPane().add(scrollPane, BorderLayout.WEST);
this.getContentPane().add(mainPanel, BorderLayout.CENTER);
// now set up the main screen
setupMainPanel(stepPanel);
stepPanel.setLayout(new BoxLayout(stepPanel, BoxLayout.PAGE_AXIS));
stepPanel.add(Box.createVerticalStrut(20));
stepTitleLabel = new JLabel("Map Properties");
stepTitleLabel.setFont(new Font(MapXmlUIHelper.defaultMapXMLCreatorFontName, Font.BOLD, 12));
stepTitleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
stepPanel.add(stepTitleLabel);
stepPanel.add(Box.createVerticalStrut(20));
actionPanel = new JPanel();
actionPanel.setLayout(new BorderLayout());
actionPanel.setBorder(new MatteBorder(1, 0, 0, 0, Color.DARK_GRAY));
stepActionPanel = new JPanel();
stepPanel.add(actionPanel);
actionPanel.add(stepActionPanel, BorderLayout.CENTER);
layoutSouthPanel();
if (!myFile.exists()) {
openAction.actionPerformed(null);
}
}
public File getDefaultMapXmlFile() {
return new File(getDefaultMapFolderLocation() + File.separator + "new_world_order"
+ File.separator + "games" + File.separator + "new_world_order.xml");
}
private static File getDefaultMapFolderLocation() {
return ClientFileSystemHelper.getUserMapsFolder();
}
private Action createMenuBar() {
// set up the actions
final Action openAction = SwingAction.of("Load Map XML", e -> {
final GameStep goToStep;
goToStep = MapXmlCreator.loadXML();
highestStep = goToStep;
DynamicRowsPanel.me = Optional.empty();
SwingUtilities.invokeLater(() -> {
goToStep(goToStep);
validateAndRepaint();
});
});
openAction.putValue(Action.SHORT_DESCRIPTION, "Load an existing Map XML File");
final Action saveAction = SwingAction.of(BUTTON_LABEL_SAVE_MAP_XML, e -> {
stepActionPanel.requestFocus();
if (!DynamicRowsPanel.me.isPresent() || DynamicRowsPanel.me.get().dataIsConsistent()) {
MapXmlCreator.saveXML();
}
});
saveAction.putValue(Action.SHORT_DESCRIPTION, "Save the Map XML to File");
final Action exitAction = SwingAction.of("Exit", e -> System.exit(0));
exitAction.putValue(Action.SHORT_DESCRIPTION, "Exit The Program");
// set up the menu items
final JMenuItem openItem = new JMenuItem(openAction);
openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
final JMenuItem saveItem = new JMenuItem(saveAction);
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
final JMenuItem exitItem = new JMenuItem(exitAction);
// set up the menu bar
final JMenuBar menuBar = new JMenuBar();
final JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);
fileMenu.add(openItem);
fileMenu.add(saveItem);
fileMenu.addSeparator();
fileMenu.add(exitItem);
menuBar.add(fileMenu);
setJMenuBar(menuBar);
return openAction;
}
private void createStepListPanel() {
stepListPanel = new JPanel();
GameStep stepCur = null;
GameStep stepNext = GAME_STEP_FIRST;
int stepCounter = 1;
while (stepCur != stepNext) {
stepCur = stepNext;
final GameStepLabel gameStepLabelCur =
new GameStepLabel(stepCounter + ": " + getGameStepName(stepCur), stepCur);
stepListPanel.add(gameStepLabelCur);
stepList.add(gameStepLabelCur);
++stepCounter;
stepNext = getNextGameStepTo(stepCur);
}
}
private void layoutSouthPanel() {
mainPanel.add(southPanel, BorderLayout.SOUTH);
southPanel.setLayout(new BoxLayout(southPanel, BoxLayout.X_AXIS));
final JPanel southLeftPanel = new JPanel();
southLeftPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
final FlowLayout southLeftPanelFlowLayout = (FlowLayout) southLeftPanel.getLayout();
southLeftPanelFlowLayout.setAlignment(FlowLayout.LEFT);
southLeftPanel.setBorder(null);
southPanel.add(southLeftPanel);
southPanel.add(Box.createHorizontalGlue());
createButtonHelp();
southLeftPanel.add(buttonHelp);
southCenterPanel = new JPanel();
southPanel.add(southCenterPanel);
southPanel.add(Box.createHorizontalGlue());
addSouthCenterPanelButtons();
final JPanel southRightPanel = new JPanel();
final FlowLayout southRightPanelFlowLayout = (FlowLayout) southRightPanel.getLayout();
southRightPanelFlowLayout.setAlignment(FlowLayout.RIGHT);
southPanel.add(southRightPanel);
final JButton buttonAvailableChoices = MapXmlUIHelper.createButton("Available Choices", KeyEvent.VK_C);
buttonAvailableChoices.addActionListener(e -> {
switch (currentStep) {
case MAP_PROPERTIES: // TODO: Verify message text.
// showInfoMessage("Map Name: The map name that is displayed in the New Game window in TripleA.
// Examples: Revised, Classic, Big World, and Great War\r\rMap Version: The version of the map's
// xml file. Examples: 0.0.1, 1.0.0.1, and 1.1\r\rResource Name: The name of the resource used in
// the map. Resources can be thought of as buying tokens or currency used to buy units, technology,
// etc. 'IPCs' have recently been replaced by 'PUs'. 'IPCs' will no longer work as the map resource.
// \r\rMap Image Location: The location of the map image. Example: C:/My Maps/Sleeping
// Giant/full_map.png\r\rMap Centers File: The location of the centers file produced by the
// 'Center Picker' program. The centers file is used to automatically add the map's territories.
// Example: C:/My Maps/Sleeping Giant/centers.txt\r\rWater Territory Filter: An optional setting
// that makes the program automatically apply the 'Is Water' property to every territory that contains
// the filter text. Examples: SZ, Sea Zone, Pacific, and Atlantic.", "Help For Current Step");
break;
case TERRITORY_DEFINITIONS: // TODO: Verify message text.
// showInfoMessage("To add a new territory, click somewhere on the map and enter a name for the
// territory in the window that appears. \r If you want to change the properties of a territory,
// left click on it and answer each question. The color of the territory label changes for each
// property that is applies. If you want to remove a territory label, right click on it and click yes
// when it asks for confirmation.", "Help For Current Step");
// showInfoMessage("Right click to rename a territory. \r If you want to change the properties of a
// territory, left click on it. \r The color of the territory label changes for each property that is
// applied.", "Help For Current Step");
break;
case TERRITORY_CONNECTIONS: // TODO: Verify message text.
// showInfoMessage("To add a connection between two territories, click on the first territory in the
// connection and then the second. To remove all the connections from a certain territory, right click
// on it and click yes.\r\rNote: To have the program find the connections automatically, click the
// 'Auto-Fill' button between the Back and Next buttons.", "Help For Current Step");
break;
case PLAYERS_AND_ALLIANCES: // TODO: Verify message text.
// showInfoMessage("Player Name: The name of the player. Examples: Russians, Germans, British,
// Americans, Chinese, and Italians.\r\rPlayer Alliance: The name of the alliance that the player
// is part of. Examples: Allies, and Axis.\r\rInitial Resources: The amount of resources(PUs) the
// player begins with when the map is started.", "Help For Current Step");
break;
case UNIT_DEFINITIONS: // TODO: Verify message text.
// showInfoMessage("Unit Name: The name of the unit. Examples: infantry, artillery, armour, fighter,
// bomber, and transport.\r\rBuy Cost: The amount of resources it takes to buy the
// unit.\r\rBuy Quantity: The amount of units to be placed with each purchase of the
// unit.\r\rTo have the program automatically enter some of the commonly used units, click the
// 'Auto-Fill' button between the Back and Next buttons.", "Help For Current Step");
break;
case GAMEPLAY_SEQUENCE:
showInfoMessage(
"Here is a list of all the available gameplay sequences with their class name and display name:\r\r "
+ "initDelegate-InitializationDelegate-Initializing Delegates,\r "
+ "bid-BidPurchaseDelegate-Bid Purchase,\r "
+ "placeBid-BidPlaceDelegate-Bid Placement,\r "
+ "tech-TechnologyDelegate-Research Technology,\r "
+ "tech_Activation-TechActivationDelegate-Activate Technology,\r "
+ "purchase-PurchaseDelegate-Purchase Units,\r "
+ "move-MoveDelegate-Combat Move,\r "
+ "battle-BattleDelegate-Combat,\r "
+ "place-PlaceDelegate-Place Units,\r "
+ "endTurn-EndTurnDelegate-Turn Complete,\r "
+ "endRound-EndRoundDelegate-Round Complete",
"List Of Available Gameplay Sequence Choices (As Of TripleA 1.0.3.4)");
break;
case PLAYER_SEQUENCE: // TODO: Verify message text.
// showInfoMessage("Sequence Name: The name of the sequence. Examples: russianBid, germanBidPlace,
// chineseTech, americanCombatMove, and germanPlace.\r\rGameplay Sequence: The name of the
// Gameplay Sequence that the player sequence uses. Examples: bid, tech, move, place,
// endTurn.\r\rPlayer: The name of the player that the Player Delegate is attached to. Examples:
// Russians, Germans, Americans, and Chinese.\r\rMax Run Count: The maximum number of times the
// Sequence can be used in the game. (You can set this value to 0 if you do not want the sequence to
// have a run limit).\r\rTo have the program automatically enter the default Player Sequences,
// click the 'Auto-Fill' button between the Back and Next buttons.", "Help For Current Step");
break;
case TECHNOLOGY_DEFINITIONS:
showInfoMessage(
"Here is a list of all the available technology types: "
+ "heavyBomber, longRangeAir, jetPower, rocket, industrialTechnology, superSub, destroyerBombard, "
+ "improvedArtillerySupport, paratroopers, increasedFactoryProduction, warBonds, mechanizedInfantry, "
+ "aARadar, shipyards",
"List Of Available Technology Choices (As Of TripleA 1.0.3.4)");
break;
case PRODUCTION_FRONTIERS: // TODO: Verify message text.
// showInfoMessage("Unit Name: The name of the unit that is included in the production frontier.
// Examples: infantry, artillery, and armour.\r\rTo have the program automatically add all the
// units to the production frontier being shown, click the 'Auto-Fill' button between the Back and
// Next buttons.\r\rNote: A production frontier is just a list of units that a player is allowed
// to purchase.", "Help For Current Step");
break;
case UNIT_ATTACHMENTS:
showInfoMessage(
"Here is a list of all the available unit attachments: "
+ "movement, attack, defense, isAir, isSea, isAA, isFactory, canBlitz, isSub, canBombard, "
+ "isStrategicBomber, hitPoints, isDestroyer, isArtillery, isArtillerySupportable, isMarine, "
+ "isInfantry, isAirTransportable, isInfantry, transportCapacity, transportCost, carrierCapacity, "
+ "carrierCost",
"List Of Available Unit Attachment Choices (As Of TripleA 1.0.3.4)");
break;
case TERRITORY_PRODUCTION: // TODO: Verify message text.
// showInfoMessage("To change the production value of a territory, click on the territory and enter
// the territory's new production value in the window that appears.", "Help For Current Step");
break;
case CANAL_DEFINITIONS: // TODO: Verify message text.
// showInfoMessage("To add a new canal, click on both of the land territories that form the
// canal(Touch the canal) and click yes when it asks for confirmation. To remove all the canals from
// the map, right click on one of the territories and click 'Yes' to confirm.", "Help For Current
// Step");
break;
case TERRITORY_OWNERSHIP: // TODO: Verify message text.
// showInfoMessage("To change the initial owner of a territory, click on the territory and type in
// its new owner when it asks for it.", "Help For Current Step");
break;
case UNIT_PLACEMENTS: // TODO: Verify message text.
// showInfoMessage("To change the units that a territory begins with, click on the territory and use
// the window that opens to set the territory's units. To do so, use the + and - buttons below each
// unit's name to change the quantity of each unit in the territory. You can also edit the text in
// the result textbox directly to change the territory units. Just type the name of each unit you
// want to add, followed by ':', followed by the unit quantitiy: Example: 'infantry: 1, artillery: 3,
// armour: 2, fighter: 1'.", "Help For Current Step");
break;
case GAME_SETTINGS:
showInfoMessageOfAvailableGameSettingsChoices();
break;
case MAP_FINISHED:
showInfoMessage(
"The map notes can be entered in the textbox. You can enter plain text or html code. "
+ "Then just click the '" + BUTTON_LABEL_SAVE_MAP_XML + "' button, and save the file in the map's "
+ "'games' folder. (Create the 'games' folder if not already created)",
"Help For Current Step");
break;
}
});
southRightPanel.add(buttonAvailableChoices);
}
private void createButtonHelp() {
buttonHelp = new JButton("Help");
buttonHelp.setMnemonic(KeyEvent.VK_H);
buttonHelp.setFont(MapXmlUIHelper.defaultMapXMLCreatorFont);
buttonHelp.addActionListener(e -> {
switch (currentStep) {
case MAP_PROPERTIES:
showInfoMessage(
"Map Name: The map name that is displayed in the New Game window in TripleA. Examples: Revised, Classic, "
+ "Big World, and Great War\r\r"
+ "Map Version: The version of the map's xml file. Examples: 0.0.1, 1.0.0.1, and 1.1\r\r"
+ "Resource Name: The name of the resource used in the map. Resources can be thought of as buying "
+ "tokens or currency used to buy units, technology, etc. 'IPCs' have recently been replaced by "
+ "'PUs'. 'IPCs' will no longer work as the map resource. \r\r"
+ "Map Image Location: The location of the map image. Example: "
+ "C:/My Maps/Sleeping Giant/full_map.png\r\r"
+ "Map Centers File: The location of the centers file produced by the 'Center Picker' program. The "
+ "centers file is used to automatically add the map's territories. Example: "
+ "C:/My Maps/Sleeping Giant/centers.txt\r\r"
+ "Water Territory Filter: An optional setting that makes the program automatically apply the "
+ "'Is Water' property to every territory that contains the filter text. Examples: SZ, Sea Zone, "
+ "Pacific, and Atlantic.",
"Help For Current Step");
break;
case TERRITORY_DEFINITIONS:
showInfoMessage(
"Right click to rename a territory. \r "
+ "If you want to change the properties of a territory, left click on it. \r "
+ "The color of the territory label changes for each property that is applied.",
"Help For Current Step");
break;
case TERRITORY_CONNECTIONS:
showInfoMessage(
"To add a connection between two territories, click on the first territory in the connection and then "
+ "the second. To remove all the connections from a certain territory, right click on it and click "
+ "yes.\r\r"
+ "Note: To have the program find the connections automatically, click the 'Auto-Fill' button "
+ "between the Back and Next buttons.",
"Help For Current Step");
break;
case PLAYERS_AND_ALLIANCES:
showInfoMessage(
"Player Name: The name of the player. Examples: Russians, Germans, British, Americans, Chinese, and "
+ "Italians.\r\r"
+ "Player Alliance: The name of the alliance that the player is part of. Examples: Allies, and "
+ "Axis.\r\r"
+ "Initial Resources: The amount of resources(PUs) the player begins with when the map is started.",
"Help For Current Step");
break;
case UNIT_DEFINITIONS:
showInfoMessage(
"Unit Name: The name of the unit. Examples: infantry, artillery, armour, fighter, bomber, and "
+ "transport.\r\r"
+ "Buy Cost: The amount of resources it takes to buy the unit.\r\r"
+ "Buy Quantity: The amount of units to be placed with each purchase of the unit.\r\r"
+ "To have the program automatically enter some of the commonly used units, click the 'Auto-Fill' "
+ "button between the Back and Next buttons.",
"Help For Current Step");
break;
case GAMEPLAY_SEQUENCE:
showInfoMessage(
"Sequence Name: The name of the sequence. Examples(Typical): tech, techActivation, battle, move, place, "
+ "purchase, endTurn, placeBid, bid.\r\r"
+ "Class Name: The name of the java delegate. Examples(Typical): TechnologyDelegate, "
+ "TechActivationDelegate, BattleDelegate, MoveDelegate, PlaceDelegate, PurchaseDelegate, "
+ "EndTurnDelegate, BidPlaceDelegate, BidPurchaseDelegate.\r\r"
+ "Display: The text displayed for the delegate in TripleA. Examples(Typical): Research Technology, "
+ "Activate Technology, Combat, Combat Move, Place Units, Purchase Units, Turn Complete, "
+ "Bid Placement, and Bid Purchase\r\r"
+ "To have the program automatically enter the default Gameplay Sequences, click the 'Auto-Fill' "
+ "button between the Back and Next buttons.",
"Help For Current Step");
break;
case PLAYER_SEQUENCE:
showInfoMessage(
"Sequence Name: The name of the sequence. Examples: russianBid, germanBidPlace, chineseTech, "
+ "americanCombatMove, and germanPlace.\r\r"
+ "Gameplay Sequence: The name of the Gameplay Sequence that the player sequence uses. Examples: "
+ "bid, tech, move, place, endTurn.\r\r"
+ "Player: The name of the player that the Player Delegate is attached to. Examples: Russians, "
+ "Germans, Americans, and Chinese.\r\r"
+ "Max Run Count: The maximum number of times the Sequence can be used in the game. (You can set "
+ "this value to 0 if you do not want the sequence to have a run limit).\r\r"
+ "To have the program automatically enter the default Player Sequences, click the 'Auto-Fill' "
+ "button between the Back and Next buttons.",
"Help For Current Step");
break;
case TECHNOLOGY_DEFINITIONS:
showInfoMessage(
"Technology Name: The name of the technology that can be researched and unlocked by the player. "
+ "Examples(Typical): heavyBomber, jetPower, industrialTechnology, superSub, rocket, and "
+ "longRangeAir.\r\r"
+ "Player: The name of the player that is able to research the technology. Examples: Russians, "
+ "Germans, Americans, and Chinese.\r\r"
+ "Already Enabled: Determines if the technology should be unlocked for the selected player when the "
+ "game first starts.\r\r"
+ "To have the program automatically enter some of the commonly used technologies, click the "
+ "'Auto-Fill' button between the Back and Next buttons.",
"Help For Current Step");
break;
case PRODUCTION_FRONTIERS:
showInfoMessage(
"Unit Name: The name of the unit that is included in the production frontier. Examples: infantry, "
+ "artillery, and armour.\r\r"
+ "To have the program automatically add all the units to the production frontier being shown, click "
+ "the 'Auto-Fill' button between the Back and Next buttons.\r\r"
+ "Note: A production frontier is just a list of units that a player is allowed to purchase.",
"Help For Current Step");
break;
case UNIT_ATTACHMENTS:
showInfoMessage(
"Attachment Name: The name of the unit attachment that is applied to the unit. Examples: movement, "
+ "attack, defense, isAir, isSea, and isStrategicBomber.\r\r"
+ "Value: The attachment value. Examples: True, False, 1, 2\r\r"
+ "To have the program automatically enter the default attachments for the units that are commonly "
+ "used, click the 'Auto-Fill' button between the Back and Next buttons.",
"Help For Current Step");
break;
case TERRITORY_PRODUCTION:
showInfoMessage(
"To change the production value of a territory, click on the territory and enter the territory's new "
+ "production value in the window that appears.",
"Help For Current Step");
break;
case CANAL_DEFINITIONS:
showInfoMessage(
"To add a new canal, click on both of the land territories that form the canal(Touch the canal) and "
+ "click yes when it asks for confirmation. To remove all the canals from the map, right click on "
+ "one of the territories and click 'Yes' to confirm.",
"Help For Current Step");
break;
case TERRITORY_OWNERSHIP:
showInfoMessage(
"To change the initial owner of a territory, click on the territory and type in its new owner when it "
+ "asks for it.",
"Help For Current Step");
break;
case UNIT_PLACEMENTS:
showInfoMessage(
"To change the units that a territory begins with, click on the territory and use the window that opens "
+ "to set the territory's units. To do so, use the + and - buttons below each unit's name to change "
+ "the quantity of each unit in the territory. You can also edit the text in the result textbox "
+ "directly to change the territory units. Just type the name of each unit you want to add, followed "
+ "by ':', followed by the unit quantitiy: Example: 'infantry: 1, artillery: 3, armour: 2, "
+ "fighter: 1'.",
"Help For Current Step");
break;
case GAME_SETTINGS:
showInfoMessage(
"Setting Name: The name of the setting that is applied to the map. Examples: Always on AA, Two hit "
+ "battleship, and Japanese bid.\r\r"
+ "Value: The value of the game setting. Examples: true, false, 0, 5, 32.\r\r"
+ "Editable: Whether players are allowed to change the value of the setting when the map is being "
+ "started.\r\r"
+ "Min. N. (Optional): The lowest number that the value can be set to when the user sets the game "
+ "options in TripleA. Only change this if the setting is a number.\r\r"
+ "Max. N.(Optional): The highest number that the value can be set to when the user sets the game "
+ "options in TripleA. Only change this if the setting is a number.\r\r"
+ "To have the program automatically enter some of the commonly used Game Settings, click the "
+ "'Auto-Fill' button between the Back and Next buttons.",
"Help For Current Step");
break;
case MAP_FINISHED:
showInfoMessage(
"The map notes can be entered in the textbox. You can enter plain text or html code. Then just click the "
+ "'Save Map To File' button, and save the file in the map's 'games' folder. (Create the 'games' "
+ "folder if not already created)",
"Help For Current Step");
break;
}
});
}
private void addSouthCenterPanelButtons() {
buttonBack = new JButton("Back");
buttonBack.setMnemonic(KeyEvent.VK_B);
buttonBack.setFont(MapXmlUIHelper.defaultMapXMLCreatorFont);
buttonBack.addActionListener(e -> {
goToStep(getPrevGameStepTo(currentStep));
invokeLaterRepaintActionPanel();
});
southCenterPanel.add(buttonBack);
autoFillButton = MapXmlUIHelper.createButton("Auto-Fill", KeyEvent.VK_A);
autoFillButton.setMinimumSize(new Dimension(50, 23));
autoFillButton.setMaximumSize(new Dimension(50, 23));
southCenterPanel.add(autoFillButton);
nextButton = MapXmlUIHelper.createButton("Next", KeyEvent.VK_N, e -> {
goToStep(getNextGameStepTo(currentStep));
invokeLaterRepaintActionPanel();
});
southCenterPanel.add(nextButton);
}
private void invokeLaterRepaintActionPanel() {
SwingUtilities.invokeLater(() -> {
actionPanel.validate();
actionPanel.repaint();
});
}
private void showInfoMessageOfAvailableGameSettingsChoices() {
/*
* Build alphabetically sorted table in HTML of the setting names
* in which the first letter is displayed bigger in case it is
* different to the previous first letter to improve readability
*/
final String[] settings = GameSettingsPanel.allSettings.split(", ");
Arrays.sort(settings);
final StringBuilder sb = new StringBuilder();
sb.append(
"<html>Here is a list of all the available game settings:<table border=0><tr><td><table border=0>");
int settingNr = 1;
char lastFirstLetteretter = 'z';
final int third_size_setting = (settings.length + 2) / 3;
for (final String settingName : settings) {
final char firstLetter = settingName.charAt(0);
if (firstLetter == lastFirstLetteretter) {
sb.append("<tr><td>").append(settingName).append("</td></tr>");
} else {
sb.append("<tr><td><big>").append(firstLetter).append("</big>").append(settingName.substring(1))
.append("</td></tr>");
}
lastFirstLetteretter = firstLetter;
if (settingNr % third_size_setting == 0) {
sb.append("</table></td><td><table border=0>");
}
++settingNr;
}
sb.append("</table></td></tr></table></html>");
showInfoMessage(
sb.toString(), "List Of Available Game Settings Choices");
}
private void showInfoMessage(final String message, final String title) {
JOptionPane.showMessageDialog(null, message, title, JOptionPane.INFORMATION_MESSAGE);
}
private void setupMainPanel(final JPanel panel) {
mainPanel.removeAll();
mainPanel.setLayout(new BorderLayout());
panel.setBorder(new MatteBorder(1, 0, 1, 1, Color.DARK_GRAY));
mainPanel.add(panel, BorderLayout.CENTER);
validateAndRepaint();
}
void validateAndRepaint() {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(() -> validateAndRepaint());
return;
}
mainPanel.revalidate();
mainPanel.repaint();
this.validate();
this.repaint();
}
private final String stepLabelFontName = MapXmlUIHelper.defaultMapXMLCreatorFontName;
private final Font stepLabelFontDefault = new Font(stepLabelFontName, Font.PLAIN, 13);
private final Font stepLabelFontHighlighted = new Font(stepLabelFontName, Font.BOLD, 13);
private void goToStep(final GameStep step) {
if (currentStep != step) {
final GameStepLabel stepLabelOld = stepList.get(currentStep.ordinal());
stepLabelOld.setFont(stepLabelFontDefault);
stepLabelOld.repaint();
}
if (step.ordinal() < stepList.size()) {
currentStep = step;
if (step.ordinal() > highestStep.ordinal()) {
highestStep = step;
}
layoutStepActionPanel();
final GameStepLabel stepLabelNew = stepList.get(step.ordinal());
stepLabelNew.setFont(stepLabelFontHighlighted);
stepLabelNew.repaint();
setStepTitleLabelTextFromStepLabel(stepLabelNew);
if (currentStep.ordinal() + 1 == stepList.size()) {
nextButton.setEnabled(false);
} else {
nextButton.setEnabled(true);
}
if (step != GAME_STEP_FIRST) {
buttonBack.setEnabled(true);
} else {
buttonBack.setEnabled(false);
}
}
}
protected void setStepTitleLabelTextFromStepLabel(final JLabel stepLabel) {
String title = stepLabel.getText();
final String titleSep = ": ";
final int titleSepPos = title.indexOf(titleSep);
title = title.substring(titleSepPos + titleSep.length(), title.length());
stepTitleLabel.setText(title);
}
public void setAutoFillAction(final AbstractAction action) {
for (final ActionListener actionListener : autoFillButton.getActionListeners()) {
autoFillButton.removeActionListener(actionListener);
}
autoFillButton.addActionListener(action);
autoFillButton.setEnabled(true);
SwingUtilities.invokeLater(() -> autoFillButton.repaint());
}
private void layoutStepActionPanel() {
stepActionPanel.removeAll();
autoFillButton.setEnabled(false);
switch (currentStep) {
case MAP_PROPERTIES:
MapPropertiesPanel.layout(this);
break;
case TERRITORY_DEFINITIONS:
TerritoryDefinitionsPanel.layout(this);
break;
case TERRITORY_CONNECTIONS:
TerritoryConnectionsPanel.layout(this);
break;
case PLAYERS_AND_ALLIANCES:
PlayerAndAlliancesPanel.layout(this);
break;
case UNIT_DEFINITIONS:
UnitDefinitionsPanel.layout(this);
break;
case GAMEPLAY_SEQUENCE:
GameSequencePanel.layout(this);
break;
case PLAYER_SEQUENCE:
PlayerSequencePanel.layout(this);
break;
case TECHNOLOGY_DEFINITIONS:
TechnologyDefinitionsPanel.layout(this);
break;
case PRODUCTION_FRONTIERS:
layoutTabbedPaneWith(MapXmlHelper.getProductionFrontiersMap().keySet());
break;
case UNIT_ATTACHMENTS:
layoutTabbedPaneWith(MapXmlHelper.getUnitDefinitionsMap().keySet());
break;
case TERRITORY_PRODUCTION:
TerritoryProductionPanel.layout(this);
break;
case CANAL_DEFINITIONS:
CanalDefinitionsPanel.layout(this);
break;
case TERRITORY_OWNERSHIP:
TerritoryOwnershipPanel.layout(this);
break;
case UNIT_PLACEMENTS:
UnitPlacementsPanel.layout(this);
break;
case GAME_SETTINGS:
GameSettingsPanel.layout(this);
break;
case MAP_FINISHED:
layoutNotesPanel();
break;
default:
break;
}
final JFrame me = this;
SwingUtilities.invokeLater(() -> {
me.pack();
stepActionPanel.revalidate();
stepActionPanel.repaint();
});
}
public void setAutoFillActionListener(final ActionListener autoFillActionListener) {
if (autoFillActionListener == null) {
autoFillButton.setEnabled(false);
} else {
autoFillButton.setEnabled(true);
for (final ActionListener curr_actionListener : autoFillButton.getActionListeners()) {
autoFillButton.removeActionListener(curr_actionListener);
}
autoFillButton.addActionListener(autoFillActionListener);
}
}
protected void layoutNotesPanel() {
stepActionPanel.setLayout(new GridBagLayout());
final JTextArea taNotes = new JTextArea(MapXmlHelper.getNotes());
taNotes.addFocusListener(FocusListenerFocusLost.withAction(() -> {
if (!MapXmlHelper.getNotes().equals(taNotes.getText())) {
MapXmlHelper.setNotes(taNotes.getText().trim());
}
}));
final JScrollPane spTaNotes = new JScrollPane(taNotes);
final Dimension size = stepActionPanel.getSize();
size.height -= 100;
spTaNotes.setMinimumSize(size);
final GridBagConstraints gridBadConstLabelNotesRow = new GridBagConstraints();
gridBadConstLabelNotesRow.insets = new Insets(0, 0, 5, 0);
gridBadConstLabelNotesRow.gridy = 0;
gridBadConstLabelNotesRow.gridx = 0;
gridBadConstLabelNotesRow.anchor = GridBagConstraints.NORTH;
gridBadConstLabelNotesRow.weightx = 1.0;
gridBadConstLabelNotesRow.weighty = 1.0;
gridBadConstLabelNotesRow.gridwidth = 3;
stepActionPanel.add(spTaNotes, gridBadConstLabelNotesRow);
final GridBagConstraints gridBadConstButtonPreviewHTMLRow = (GridBagConstraints) gridBadConstLabelNotesRow.clone();
gridBadConstButtonPreviewHTMLRow.weighty = 0.0;
gridBadConstButtonPreviewHTMLRow.insets = new Insets(0, 0, 0, 0);
gridBadConstButtonPreviewHTMLRow.gridwidth = 1;
gridBadConstButtonPreviewHTMLRow.gridx = 1;
gridBadConstButtonPreviewHTMLRow.gridy = 1;
final JButton buttonPreviewHTML = new JButton("Preview HTML");
buttonPreviewHTML.setPreferredSize(new Dimension(300, 30));
buttonPreviewHTML.setAction(SwingAction.of("Preview HTML", e -> showHTML(MapXmlHelper.getNotes(), "HTML Preview")));
stepActionPanel.add(buttonPreviewHTML, gridBadConstButtonPreviewHTMLRow);
final GridBagConstraints gridBadConstLabelCongratsRow =
(GridBagConstraints) gridBadConstButtonPreviewHTMLRow.clone();
gridBadConstLabelCongratsRow.gridy = 2;
stepActionPanel.add(new JLabel("<html><big>Congratulation!</big></html>"), gridBadConstLabelCongratsRow);
final GridBagConstraints gridBadConstLabelAllCompletedRow =
(GridBagConstraints) gridBadConstButtonPreviewHTMLRow.clone();
gridBadConstLabelAllCompletedRow.gridy = 3;
stepActionPanel.add(
new JLabel("<html><nobr>You have completed all the steps for creating the map XML.</nobr></html>"),
gridBadConstLabelAllCompletedRow);
final JButton buttonSave = new JButton("Save Entries to XML");
buttonSave.setPreferredSize(new Dimension(600, 35));
buttonSave.setAction(SwingAction.of(BUTTON_LABEL_SAVE_MAP_XML, e -> MapXmlCreator.saveXML()));
final GridBagConstraints gridBadConstButtonSaveRow = (GridBagConstraints) gridBadConstButtonPreviewHTMLRow.clone();
gridBadConstButtonSaveRow.insets = new Insets(5, 0, 0, 0);
gridBadConstButtonSaveRow.gridy = 4;
stepActionPanel.add(buttonSave, gridBadConstButtonSaveRow);
}
protected void layoutTabbedPaneWith(final Set<String> keySet) {
stepActionPanel.setLayout(new BorderLayout());
final JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.SCROLL_TAB_LAYOUT);
for (final String key : keySet) {
final JPanel innerTabPane = new JPanel();
tabbedPane.addTab(key, innerTabPane);
ProductionFrontiersPanel.layout(this, innerTabPane, key);
}
stepActionPanel.add(tabbedPane, BorderLayout.CENTER);
}
public void showHTML(final String htmlString, final String title) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JEditorPane jEditorPane = new JEditorPane();
jEditorPane.setEditable(false);
final JScrollPane scrollPane = new JScrollPane(jEditorPane);
final HTMLEditorKit kit = new HTMLEditorKit();
jEditorPane.setEditorKit(kit);
final Document doc = kit.createDefaultDocument();
jEditorPane.setDocument(doc);
jEditorPane.setText(htmlString);
final JFrame j = new JFrame(title);
j.getContentPane().add(scrollPane, BorderLayout.CENTER);
// make it easy to close the application
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// display the frame
j.setSize(new Dimension(800, 600));
// center the jframe, then make it visible
j.setLocationRelativeTo(null);
j.setVisible(true);
}
});
}
static void saveXML() {
try {
final String fileName =
new FileSave("Where to Save the Game XML ?",
MapXmlHelper.getXmlStringsMap().get("info_@name") + FILE_NAME_ENDING_XML,
mapFolderLocation).getPathString();
if (fileName == null) {
return;
}
// write the content into xml file
final TransformerFactory transformerFactory = TransformerFactory.newInstance();
final Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, GameParser.DTD_FILE_NAME);
final DOMSource source = new DOMSource(MapXmlHelper.getXMLDocument());
final File newFile = new File(fileName);
final StreamResult result = new StreamResult(newFile);
transformer.transform(source, result);
Logger.getLogger(MapXmlCreator.MAP_XML_CREATOR_LOGGER_NAME).log(Level.INFO,
"Game XML written to " + newFile.getCanonicalPath());
} catch (final IOException | HeadlessException | TransformerException | ParserConfigurationException e) {
ClientLogger.logQuietly(e);
}
}
/**
* Log a message, with no arguments.
*
* <p>
* If the logger is currently enabled for the given message
* level then the given message is forwarded to all the
* registered output Handler objects.
* </p>
*
* @param level One of the message level identifiers, e.g., SEVERE
* @param msg The string message (or a key in the message catalog)
*/
public static void log(final Level level, final String msg) {
getLogger().log(level, msg);
}
static GameStep loadXML() {
final String gameXMLPath =
MapXmlUIHelper.selectFile("Game XML File", MapXmlHelper.getMapXMLFile(), FILE_NAME_ENDING_XML).getPathString();
MapXmlCreator.log(Level.INFO, "Load Game XML from " + gameXMLPath);
try {
return loadXmlFromFilePath(gameXMLPath);
} catch (SAXException | IOException | ParserConfigurationException e) {
ClientLogger.logError("Failed to load XML File: " + gameXMLPath, e);
return loadXML();
}
}
public static GameStep loadXmlFromFilePath(final String gameXMLPath)
throws SAXException, IOException, ParserConfigurationException {
final FileInputStream in = new FileInputStream(gameXMLPath);
// parse using builder to get DOM representation of the XML file
final org.w3c.dom.Document dom = new GameParser(gameXMLPath).getDocument(in);
GameStep goToStep = MapXmlHelper.parseValuesFromXML(dom);
// set map file, image file and map folder
MapXmlHelper.setMapXMLFile(new File(gameXMLPath));
File mapFolder = MapXmlHelper.getMapXMLFile().getParentFile();
if (mapFolder.getName().equals(GameSelectorModel.DEFAULT_GAME_XML_DIRECTORY_NAME)) {
mapFolder = mapFolder.getParentFile();
}
mapFolderLocation = mapFolder;
final File[] imageFiles = mapFolderLocation.listFiles(new FilenameFilter() {
@Override
public boolean accept(final File arg0, final String arg1) {
return (arg1.endsWith(FILE_NAME_ENDING_GIF) || arg1.endsWith(FILE_NAME_ENDING_PNG));
}
});
if (imageFiles != null && imageFiles.length == 1) {
mapImageFile = imageFiles[0];
} else {
MapPropertiesPanel.selectMapImageFile();
}
final File fileGuess = new File(mapFolderLocation, FILE_NAME_CENTERS_TXT);
if (fileGuess != null && fileGuess.exists()) {
mapCentersFile = fileGuess;
} else {
MapPropertiesPanel.selectCentersFile();
}
if (mapImageFile == null || mapCentersFile == null) {
goToStep = GAME_STEP_FIRST;
}
ImageScrollPanePanel.polygonsInvalid = true;
return goToStep;
}
class GameStepLabel extends JLabel {
private static final long serialVersionUID = -2034374214878411484L;
private final GameStep gameStep;
/**
* Creates a <code>JLabel</code> instance with the specified text.
* The label is aligned against the leading edge of its display area,
* and centered vertically.
*
* @param text The text to be displayed by the label.
*/
public GameStepLabel(final String text, final GameStep step) {
super(text);
gameStep = step;
final GameStepLabel me = this;
addMouseListener(new MouseListener() {
@Override
public void mouseReleased(final MouseEvent e) {}
@Override
public void mousePressed(final MouseEvent e) {}
@Override
public void mouseExited(final MouseEvent e) {
if (gameStep != currentStep) {
me.setOpaque(false);
me.setBackground(me.getBackground().darker().darker());
me.updateUI();
}
}
@Override
public void mouseEntered(final MouseEvent e) {
if (gameStep != currentStep) {
me.setOpaque(true);
me.setBackground(me.getBackground().brighter().brighter());
me.updateUI();
}
}
@Override
public void mouseClicked(final MouseEvent e) {
me.requestFocus();
if (gameStep != currentStep
&& (!DynamicRowsPanel.me.isPresent() || DynamicRowsPanel.me.get().dataIsConsistent())) {
me.setOpaque(false);
goToStep(gameStep);
}
}
});
}
}
}