package tools.map.making;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import games.strategy.debug.ClientLogger;
import games.strategy.engine.ClientFileSystemHelper;
import games.strategy.engine.framework.ProcessRunnerUtil;
import games.strategy.engine.framework.lookandfeel.LookAndFeel;
import games.strategy.net.OpenFileUtility;
import games.strategy.triplea.image.UnitImageFactory;
import games.strategy.ui.SwingAction;
import tools.image.AutoPlacementFinder;
import tools.image.CenterPicker;
import tools.image.DecorationPlacer;
import tools.image.FileSave;
import tools.image.PolygonGrabber;
import tools.image.ReliefImageBreaker;
import tools.image.TileImageBreaker;
import tools.image.TileImageReconstructor;
/**
* A frame that will run the different map making utilities we have.
*/
public class MapCreator extends JFrame {
private static final long serialVersionUID = 3593102638082774498L;
private static final String TRIPLEA_MAP_FOLDER = "triplea.map.folder";
private static final String TRIPLEA_UNIT_ZOOM = "triplea.unit.zoom";
private static final String TRIPLEA_UNIT_WIDTH = "triplea.unit.width";
private static final String TRIPLEA_UNIT_HEIGHT = "triplea.unit.height";
private static long s_memory = Runtime.getRuntime().maxMemory();
private static File s_mapFolderLocation = null;
private static double s_unit_zoom = 0.75;
private static int s_unit_width = UnitImageFactory.DEFAULT_UNIT_ICON_SIZE;
private static int s_unit_height = UnitImageFactory.DEFAULT_UNIT_ICON_SIZE;
private static boolean s_runUtilitiesAsSeperateProcesses = true;
final JPanel mainPanel;
final JPanel sidePanel;
final JButton part1;
final JButton part2;
final JButton part3;
final JButton part4;
final JPanel panel1 = new JPanel();
final JPanel panel2 = new JPanel();
final JPanel panel3 = new JPanel();
final JPanel panel4 = new JPanel();
public static String[] getProperties() {
return new String[] {TRIPLEA_MAP_FOLDER, TRIPLEA_UNIT_ZOOM, TRIPLEA_UNIT_WIDTH, TRIPLEA_UNIT_HEIGHT};
}
public static void main(final String[] args) {
LookAndFeel.setupLookAndFeel();
final MapCreator creator = new MapCreator();
creator.setSize(800, 600);
creator.setLocationRelativeTo(null);
creator.setVisible(true);
}
public MapCreator() {
super("TripleA Map Creator");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// components
mainPanel = new JPanel();
sidePanel = new JPanel();
part1 = new JButton("Step 1: Map Properties");
part2 = new JButton("Step 2: Map Utilities");
part3 = new JButton("Step 3: Game XML");
part4 = new JButton("Other: Optional Things");
sidePanel.setLayout(new BoxLayout(sidePanel, BoxLayout.PAGE_AXIS));
sidePanel.add(Box.createVerticalGlue());
sidePanel.add(part1);
part1.setAlignmentX(Component.CENTER_ALIGNMENT);
sidePanel.add(Box.createVerticalGlue());
sidePanel.add(part2);
part2.setAlignmentX(Component.CENTER_ALIGNMENT);
sidePanel.add(Box.createVerticalGlue());
sidePanel.add(part3);
part3.setAlignmentX(Component.CENTER_ALIGNMENT);
sidePanel.add(Box.createVerticalGlue());
sidePanel.add(part4);
part4.setAlignmentX(Component.CENTER_ALIGNMENT);
sidePanel.add(Box.createVerticalGlue());
createPart1Panel();
createPart2Panel();
createPart3Panel();
createPart4Panel();
part1.addActionListener(SwingAction.of("Part 1", e -> setupMainPanel(panel1)));
part2.addActionListener(SwingAction.of("Part 2", e -> setupMainPanel(panel2)));
part3.addActionListener(SwingAction.of("Part 3", e -> setupMainPanel(panel3)));
part4.addActionListener(SwingAction.of("Part 4", e -> setupMainPanel(panel4)));
// set up the menu actions
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 exitItem = new JMenuItem(exitAction);
// set up the menu bar
final JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
final JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic('F');
fileMenu.addSeparator();
fileMenu.add(exitItem);
menuBar.add(fileMenu);
// set up the layout manager
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(new JScrollPane(sidePanel), BorderLayout.WEST);
this.getContentPane().add(new JScrollPane(mainPanel), BorderLayout.CENTER);
// now set up the main screen
setupMainPanel(panel1);
}
private void setupMainPanel(final JPanel panel) {
mainPanel.removeAll();
mainPanel.add(panel);
setWidgetActivation();
}
private void setWidgetActivation() {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
setWidgetActivation();
}
});
return;
}
mainPanel.validate();
mainPanel.repaint();
this.validate();
this.repaint();
}
private void createPart1Panel() {
panel1.removeAll();
panel1.setLayout(new BoxLayout(panel1, BoxLayout.PAGE_AXIS));
panel1.add(Box.createVerticalStrut(30));
final JTextArea text = new JTextArea(12, 10);
text.setWrapStyleWord(true);
text.setLineWrap(true);
text.setText("Welcome to Veqryn's map creator program for TripleA."
+ "\r\nThis program just runs utilities inside the triplea.jar file for you, and you could easily "
+ "run them yourself from the command line by reading the docs/developer_documentation.html"
+ "\r\n\r\nBefore you begin, go create a folder in your directory: Users\\yourname\\triplea\\maps"
+ "\r\nName the folder with a short name of your map, do not use any special characters in the name."
+ "\r\nNext, create 5 folders inside your map folder, with these names: "
+ "flags, units, baseTiles, reliefTiles, games"
+ "\r\nThen, create a text file and rename it \"map.properties\" or use one created by this utility."
+ "\r\n\r\nTo start the Map Utilities, have a png image of your map with just the territory borders "
+ "and nothing else. The borders must be in black (hex: 000000) and there should not be any "
+ "anti-aliasing (smoothing) of the lines or edges that stick out."
+ "\r\nCreate a small image of the map (approx 250 pixels wide) and name it \"smallMap.jpeg\"."
+ "\r\nPut these in the map's root folder. You can now start the map maker by clicking and filling "
+ "in the details below, before moving on to 'Step 2' and running the map utilities.");
final JScrollPane scrollText = new JScrollPane(text);
panel1.add(scrollText);
panel1.add(Box.createVerticalStrut(30));
panel1.add(new JLabel("Click button open up the readme file on how to make maps:"));
final JButton helpButton = new JButton("Start Tutorial / Show Help Document");
helpButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
try {
OpenFileUtility.openFile(
new File(ClientFileSystemHelper.getRootFolder(),
"doc" + File.separator + "map_and_map_skin_making_overview.html"));
} catch (final Exception e1) {
e1.printStackTrace();
}
}
});
panel1.add(helpButton);
panel1.add(Box.createVerticalStrut(30));
panel1.add(new JLabel("Click button to select where your map folder is:"));
final JButton mapFolderButton = new JButton("Select Map Folder");
mapFolderButton.addActionListener(SwingAction.of("Select Map Folder", e -> {
final String path = new FileSave("Where is your map's folder?", null, s_mapFolderLocation).getPathString();
if (path != null) {
final File mapFolder = new File(path);
if (mapFolder.exists()) {
s_mapFolderLocation = mapFolder;
System.setProperty(TRIPLEA_MAP_FOLDER, s_mapFolderLocation.getPath());
}
}
}));
panel1.add(mapFolderButton);
panel1.add(Box.createVerticalStrut(30));
panel1.add(new JLabel("Set the unit scaling (unit image zoom): "));
panel1.add(new JLabel("Choose one of: 1.25, 1, 0.875, 0.8333, 0.75, 0.6666, 0.5625, 0.5"));
final JTextField unitZoomText = new JTextField("" + s_unit_zoom);
unitZoomText.setMaximumSize(new Dimension(100, 20));
unitZoomText.addFocusListener(new FocusListener() {
@Override
public void focusGained(final FocusEvent e) {}
@Override
public void focusLost(final FocusEvent e) {
try {
s_unit_zoom = Math.min(4.0, Math.max(0.1, Double.parseDouble(unitZoomText.getText())));
System.setProperty(TRIPLEA_UNIT_ZOOM, "" + s_unit_zoom);
} catch (final Exception ex) {
// ignore malformed input
}
unitZoomText.setText("" + s_unit_zoom);
}
});
panel1.add(unitZoomText);
panel1.add(Box.createVerticalStrut(30));
panel1.add(new JLabel("Set the width of the unit images: "));
final JTextField unitWidthText = new JTextField("" + s_unit_width);
unitWidthText.setMaximumSize(new Dimension(100, 20));
unitWidthText.addFocusListener(new FocusListener() {
@Override
public void focusGained(final FocusEvent e) {}
@Override
public void focusLost(final FocusEvent e) {
try {
s_unit_width = Math.min(400, Math.max(1, Integer.parseInt(unitWidthText.getText())));
System.setProperty(TRIPLEA_UNIT_WIDTH, "" + s_unit_width);
} catch (final Exception ex) {
// ignore malformed input
}
unitWidthText.setText("" + s_unit_width);
}
});
panel1.add(unitWidthText);
panel1.add(Box.createVerticalStrut(30));
panel1.add(new JLabel("Set the height of the unit images: "));
final JTextField unitHeightText = new JTextField("" + s_unit_height);
unitHeightText.setMaximumSize(new Dimension(100, 20));
unitHeightText.addFocusListener(new FocusListener() {
@Override
public void focusGained(final FocusEvent e) {}
@Override
public void focusLost(final FocusEvent e) {
try {
s_unit_height = Math.min(400, Math.max(1, Integer.parseInt(unitHeightText.getText())));
System.setProperty(TRIPLEA_UNIT_HEIGHT, "" + s_unit_height);
} catch (final Exception ex) {
// ignore malformed input
}
unitHeightText.setText("" + s_unit_height);
}
});
panel1.add(unitHeightText);
panel1.add(Box.createVerticalStrut(30));
panel1
.add(new JLabel("<html>Here you can set the 'max memory' that utilities like the Polygon Grabber will use.<br>"
+ "This is useful is you have a very large map, or ever get any Java Heap Space errors.</html>"));
panel1.add(new JLabel("Set the amount of memory to use when running new processes (in megabytes [mb]):"));
final JTextField memoryText = new JTextField("" + (s_memory / (1024 * 1024)));
memoryText.setMaximumSize(new Dimension(100, 20));
memoryText.addFocusListener(new FocusListener() {
@Override
public void focusGained(final FocusEvent e) {}
@Override
public void focusLost(final FocusEvent e) {
try {
s_memory = (long) 1024 * 1024 * Math.min(4096, Math.max(256, Integer.parseInt(memoryText.getText())));
} catch (final Exception ex) {
// ignore malformed input
}
memoryText.setText("" + (s_memory / (1024 * 1024)));
}
});
panel1.add(memoryText);
final JCheckBox runTypeBox = new JCheckBox("Run All Utilities as Separate Processes");
runTypeBox.setSelected(s_runUtilitiesAsSeperateProcesses);
runTypeBox.addActionListener(SwingAction.of("Run All Utilities as Separate Processes",
e -> s_runUtilitiesAsSeperateProcesses = runTypeBox.isSelected()));
panel1.add(runTypeBox);
panel1.add(Box.createVerticalStrut(30));
panel1.validate();
}
private void createPart2Panel() {
panel2.removeAll();
panel2.setLayout(new BoxLayout(panel2, BoxLayout.PAGE_AXIS));
panel2.add(Box.createVerticalStrut(30));
panel2.add(new JLabel("Map Skin Utilities:"));
panel2.add(Box.createVerticalStrut(30));
final JButton mapPropertiesMakerButton = new JButton("Run the Map Properties Maker");
mapPropertiesMakerButton.addActionListener(SwingAction.of("Run the Map Properties Maker", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(MapPropertiesMaker.class);
} else {
(new Thread() {
@Override
public void run() {
MapPropertiesMaker.main(new String[0]);
}
}).start();
}
}));
panel2.add(mapPropertiesMakerButton);
panel2.add(Box.createVerticalStrut(30));
final JButton centerPickerButton = new JButton("Run the Center Picker");
centerPickerButton.addActionListener(SwingAction.of("Run the Center Picker", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(CenterPicker.class);
} else {
(new Thread() {
@Override
public void run() {
CenterPicker.main(new String[0]);
}
}).start();
}
}));
panel2.add(centerPickerButton);
panel2.add(Box.createVerticalStrut(30));
final JButton polygonGrabberButton = new JButton("Run the Polygon Grabber");
polygonGrabberButton.addActionListener(SwingAction.of("Run the Polygon Grabber", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(PolygonGrabber.class);
} else {
(new Thread() {
@Override
public void run() {
PolygonGrabber.main(new String[0]);
}
}).start();
}
}));
panel2.add(polygonGrabberButton);
panel2.add(Box.createVerticalStrut(30));
final JButton autoPlacerButton = new JButton("Run the Automatic Placement Finder");
autoPlacerButton.addActionListener(SwingAction.of("Run the Automatic Placement Finder", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(AutoPlacementFinder.class);
} else {
(new Thread() {
@Override
public void run() {
AutoPlacementFinder.main(new String[0]);
}
}).start();
}
}));
panel2.add(autoPlacerButton);
panel2.add(Box.createVerticalStrut(30));
final JButton placementPickerButton = new JButton("Run the Placement Picker");
placementPickerButton.addActionListener(SwingAction.of("Run the Placement Picker", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(PlacementPicker.class);
} else {
(new Thread() {
@Override
public void run() {
PlacementPicker.main(new String[0]);
}
}).start();
}
}));
panel2.add(placementPickerButton);
panel2.add(Box.createVerticalStrut(30));
final JButton tileBreakerButton = new JButton("Run the Tile Image Breaker");
tileBreakerButton.addActionListener(SwingAction.of("Run the Tile Image Breaker", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(TileImageBreaker.class);
} else {
(new Thread() {
@Override
public void run() {
try {
TileImageBreaker.main(new String[0]);
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
}).start();
}
}));
panel2.add(tileBreakerButton);
panel2.add(Box.createVerticalStrut(30));
final JButton decorationPlacerButton = new JButton("Run the Decoration Placer");
decorationPlacerButton.addActionListener(SwingAction.of("Run the Decoration Placer", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(DecorationPlacer.class);
} else {
(new Thread() {
@Override
public void run() {
try {
DecorationPlacer.main(new String[0]);
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
}).start();
}
}));
panel2.add(decorationPlacerButton);
panel2.add(Box.createVerticalStrut(30));
panel2.validate();
}
private void createPart3Panel() {
panel3.removeAll();
panel3.setLayout(new BoxLayout(panel3, BoxLayout.PAGE_AXIS));
panel3.add(Box.createVerticalStrut(30));
panel3.add(new JLabel("Game XML Utilities:"));
panel3.add(new JLabel("Sorry but for now the only XML creator is Wisconsin's 'Part 2' of his map maker."));
panel3.add(Box.createVerticalStrut(30));
final JButton connectionFinderButton = new JButton("Run the Connection Finder");
connectionFinderButton.addActionListener(SwingAction.of("Run the Connection Finder", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(ConnectionFinder.class);
} else {
(new Thread() {
@Override
public void run() {
try {
ConnectionFinder.main(new String[0]);
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
}).start();
}
}));
panel3.add(connectionFinderButton);
panel3.add(Box.createVerticalStrut(30));
panel3.validate();
}
private void createPart4Panel() {
panel4.removeAll();
panel4.setLayout(new BoxLayout(panel4, BoxLayout.PAGE_AXIS));
panel4.add(Box.createVerticalStrut(30));
panel4.add(new JLabel("Other or Optional Utilities:"));
panel4.add(Box.createVerticalStrut(30));
final JButton reliefBreakerButton = new JButton("Run the Relief Image Breaker");
reliefBreakerButton.addActionListener(SwingAction.of("Run the Relief Image Breaker", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(ReliefImageBreaker.class);
} else {
(new Thread() {
@Override
public void run() {
try {
ReliefImageBreaker.main(new String[0]);
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
}).start();
}
}));
panel4.add(reliefBreakerButton);
panel4.add(Box.createVerticalStrut(30));
final JButton imageShrinkerButton = new JButton("Run the Image Shrinker");
imageShrinkerButton.addActionListener(SwingAction.of("Run the Image Shrinker", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(ImageShrinker.class);
} else {
(new Thread() {
@Override
public void run() {
try {
ImageShrinker.main(new String[0]);
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
}).start();
}
}));
panel4.add(imageShrinkerButton);
panel4.add(Box.createVerticalStrut(30));
final JButton tileImageReconstructorButton = new JButton("Run the Tile Image Reconstructor");
tileImageReconstructorButton.addActionListener(SwingAction.of("Run the Tile Image Reconstructor", e -> {
if (s_runUtilitiesAsSeperateProcesses) {
runUtility(TileImageReconstructor.class);
} else {
(new Thread() {
@Override
public void run() {
try {
TileImageReconstructor.main(new String[0]);
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
}).start();
}
}));
panel4.add(tileImageReconstructorButton);
panel4.add(Box.createVerticalStrut(30));
panel4.validate();
}
private static void runUtility(final Class<?> javaClass) {
final List<String> commands = new ArrayList<>();
ProcessRunnerUtil.populateBasicJavaArgs(commands, s_memory);
if (s_mapFolderLocation != null && s_mapFolderLocation.exists()) {
// no need for quotes, that will just screw up the process builder
commands.add("-D" + TRIPLEA_MAP_FOLDER + "=" + s_mapFolderLocation.getAbsolutePath());
}
commands.add("-D" + TRIPLEA_UNIT_ZOOM + "=" + s_unit_zoom);
commands.add("-D" + TRIPLEA_UNIT_WIDTH + "=" + s_unit_width);
commands.add("-D" + TRIPLEA_UNIT_HEIGHT + "=" + s_unit_height);
commands.add(javaClass.getName());
ProcessRunnerUtil.exec(commands);
// example: java -classpath triplea.jar -Dtriplea.map.folder="C:/Users" tools/image/CenterPicker
}
}