package tools.image;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.Action;
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.KeyStroke;
import javax.swing.SwingUtilities;
import games.strategy.debug.ClientLogger;
import games.strategy.ui.SwingAction;
import games.strategy.ui.Util;
import games.strategy.util.PointFileReaderWriter;
public class CenterPicker extends JFrame {
private static final long serialVersionUID = -5633998810385136625L;
// The map image will be stored here
private Image image;
// hash map for center points
private Map<String, Point> centers = new HashMap<>();
// hash map for polygon points
private Map<String, List<Polygon>> polygons = new HashMap<>();
private final JLabel locationLabel = new JLabel();
private static File s_mapFolderLocation = null;
private static final String TRIPLEA_MAP_FOLDER = "triplea.map.folder";
/**
* main(java.lang.String[])
* Main program begins here.
* Asks the user to select the map then runs the
* the actual picker.
*
* @param args The command line arguments.
*/
public static void main(final String[] args) {
handleCommandLineArgs(args);
System.out.println("Select the map");
final FileOpen mapSelection = new FileOpen("Select The Map", s_mapFolderLocation, ".gif", ".png");
final String mapName = mapSelection.getPathString();
if (s_mapFolderLocation == null && mapSelection.getFile() != null) {
s_mapFolderLocation = mapSelection.getFile().getParentFile();
}
if (mapName != null) {
System.out.println("Map : " + mapName);
final CenterPicker picker = new CenterPicker(mapName);
picker.setSize(800, 600);
picker.setLocationRelativeTo(null);
picker.setVisible(true);
JOptionPane.showMessageDialog(picker,
new JLabel("<html>" + "This is the CenterPicker, it will create a centers.txt file for you. "
+ "<br>Please click on the center of every single territory and sea zone on your map, and give each a "
+ "name. "
+ "<br>The point you clicked on will tell TripleA where to put things like any flags, text, unit "
+ "placements, etc, "
+ "<br>so be sure to click in the exact middle, or slight up and left of the middle, of each territory "
+ "<br>(but still within the territory borders)."
+ "<br>Do not use special or illegal characters in territory names."
+ "<br><br>You can also load an existing centers.txt file, then make modifications to it, then save it "
+ "again."
+ "<br><br>LEFT CLICK = create a new center point for a territory/zone."
+ "<br><br>RIGHT CLICK on an existing center = delete that center point."
+ "<br><br>When finished, save the centers and exit." + "</html>"));
} else {
System.out.println("No Image Map Selected. Shutting down.");
System.exit(0);
}
} // end main
/**
* Constructor CenterPicker(java.lang.String)
* Setus up all GUI components, initializes variables with
* default or needed values, and prepares the map for user
* commands.
*
* @param mapName Name of map file.
*/
public CenterPicker(final String mapName) {
super("Center Picker");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
File file = null;
if (s_mapFolderLocation != null && s_mapFolderLocation.exists()) {
file = new File(s_mapFolderLocation, "polygons.txt");
}
if (file == null || !file.exists()) {
file = new File(new File(mapName).getParent() + File.separator + "polygons.txt");
}
if (file.exists() && JOptionPane.showConfirmDialog(new JPanel(),
"A polygons.txt file was found in the map's folder, do you want to use the file to supply the territories "
+ "names?",
"File Suggestion", 1) == 0) {
try {
polygons = PointFileReaderWriter.readOneToManyPolygons(new FileInputStream(file.getPath()));
} catch (final IOException ex1) {
System.out.println("Something wrong with your Polygons file: " + ex1);
ex1.printStackTrace();
}
} else {
try {
final String polyPath = new FileOpen("Select A Polygon File", s_mapFolderLocation, ".txt").getPathString();
if (polyPath != null) {
polygons = PointFileReaderWriter.readOneToManyPolygons(new FileInputStream(polyPath));
}
} catch (final IOException ex1) {
System.out.println("Something wrong with your Polygons file: " + ex1);
ex1.printStackTrace();
}
}
createImage(mapName);
final JPanel imagePanel = createMainPanel();
/*
* Add a mouse listener to show
* X : Y coordinates on the lower
* left corner of the screen.
*/
imagePanel.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(final MouseEvent e) {
locationLabel.setText("x:" + e.getX() + " y:" + e.getY());
}
});
// Add a mouse listener to monitor for right mouse button being clicked.
imagePanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(final MouseEvent e) {
mouseEvent(e.getPoint(), SwingUtilities.isRightMouseButton(e));
}
});
// set up the image panel size dimensions ...etc
imagePanel.setMinimumSize(new Dimension(image.getWidth(this), image.getHeight(this)));
imagePanel.setPreferredSize(new Dimension(image.getWidth(this), image.getHeight(this)));
imagePanel.setMaximumSize(new Dimension(image.getWidth(this), image.getHeight(this)));
// set up the layout manager
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(new JScrollPane(imagePanel), BorderLayout.CENTER);
this.getContentPane().add(locationLabel, BorderLayout.SOUTH);
// set up the actions
final Action openAction = SwingAction.of("Load Centers", e -> loadCenters());
openAction.putValue(Action.SHORT_DESCRIPTION, "Load An Existing Center Points File");
final Action saveAction = SwingAction.of("Save Centers", e -> saveCenters());
saveAction.putValue(Action.SHORT_DESCRIPTION, "Save The Center Points 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();
setJMenuBar(menuBar);
final JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic('F');
fileMenu.add(openItem);
fileMenu.add(saveItem);
fileMenu.addSeparator();
fileMenu.add(exitItem);
menuBar.add(fileMenu);
} // end constructor
/**
* createImage(java.lang.String)
* creates the image map and makes sure
* it is properly loaded.
*
* @param mapName
* .lang.String mapName the path of image map
*/
private void createImage(final String mapName) {
image = Toolkit.getDefaultToolkit().createImage(mapName);
Util.ensureImageLoaded(image);
}
/**
* javax.swing.JPanel createMainPanel()
* Creates the main panel and returns
* a JPanel object.
*
* @return javax.swing.JPanel the panel to return
*/
private JPanel createMainPanel() {
final JPanel imagePanel = new JPanel() {
private static final long serialVersionUID = -7130828419508975924L;
@Override
public void paint(final Graphics g) {
// super.paint(g);
g.drawImage(image, 0, 0, this);
g.setColor(Color.red);
for (final String centerName : centers.keySet()) {
final Point item = centers.get(centerName);
g.fillOval(item.x, item.y, 15, 15);
g.drawString(centerName, item.x + 17, item.y + 13);
}
}
};
return imagePanel;
}
/**
* saveCenters()
* Saves the centers to disk.
*/
private void saveCenters() {
try {
final String fileName =
new FileSave("Where To Save centers.txt ?", "centers.txt", s_mapFolderLocation).getPathString();
if (fileName == null) {
return;
}
final FileOutputStream out = new FileOutputStream(fileName);
PointFileReaderWriter.writeOneToOne(out, centers);
out.flush();
out.close();
System.out.println("Data written to :" + new File(fileName).getCanonicalPath());
} catch (final Exception ex) {
ClientLogger.logQuietly(ex);
}
}
/**
* loadCenters()
* Loads a pre-defined file with map center points.
*/
private void loadCenters() {
try {
System.out.println("Load a center file");
final String centerName = new FileOpen("Load A Center File", s_mapFolderLocation, ".txt").getPathString();
if (centerName == null) {
return;
}
final FileInputStream in = new FileInputStream(centerName);
centers = PointFileReaderWriter.readOneToOne(in);
repaint();
} catch (final HeadlessException | IOException ex) {
ClientLogger.logQuietly(ex);
}
}
/**
* java.lang.String findTerritoryName(java.awt.Point)
* Finds a land territory name or
* some sea zone name.
*
* @param java
* .awt.point p a point on the map
*/
private String findTerritoryName(final Point p) {
return Util.findTerritoryName(p, polygons, "unknown");
}
/**
* mouseEvent(java.awt.Point, java.lang.boolean, java.lang.boolean)
*
* @param java
* .awt.Point point a point clicked by mouse
* @param java
* .lang.boolean ctrlDown true if ctrl key was hit
* @param java
* .lang.boolean rightMouse true if the right mouse button was hit
*/
private void mouseEvent(final Point point, final boolean rightMouse) {
if (!rightMouse) {
String name = findTerritoryName(point);
name = JOptionPane.showInputDialog(this, "Enter the territory name:", name);
if (name == null || name.trim().length() == 0) {
return;
}
if (centers.containsKey(name) && JOptionPane.showConfirmDialog(this,
"Another center exists with the same name. Are you sure you want to replace it with this one?") != 0) {
return;
}
centers.put(name, point);
} else {
String centerClicked = null;
for (final Entry<String, Point> cur : centers.entrySet()) {
if (new Rectangle(cur.getValue(), new Dimension(15, 15))
.intersects(new Rectangle(point, new Dimension(1, 1)))) {
centerClicked = cur.getKey();
}
}
if (centerClicked != null
&& JOptionPane.showConfirmDialog(this, "Are you sure you want to remove this center?") == 0) {
centers.remove(centerClicked);
}
}
repaint();
}
private static String getValue(final String arg) {
final int index = arg.indexOf('=');
if (index == -1) {
return "";
}
return arg.substring(index + 1);
}
private static void handleCommandLineArgs(final String[] args) {
// arg can only be the map folder location.
if (args.length == 1) {
String value;
if (args[0].startsWith(TRIPLEA_MAP_FOLDER)) {
value = getValue(args[0]);
} else {
value = args[0];
}
final File mapFolder = new File(value);
if (mapFolder.exists()) {
s_mapFolderLocation = mapFolder;
} else {
System.out.println("Could not find directory: " + value);
}
} else if (args.length > 1) {
System.out.println("Only argument allowed is the map directory.");
}
// might be set by -D
if (s_mapFolderLocation == null || s_mapFolderLocation.length() < 1) {
final String value = System.getProperty(TRIPLEA_MAP_FOLDER);
if (value != null && value.length() > 0) {
// value = value.replaceAll("\\(", " ");
final File mapFolder = new File(value);
if (mapFolder.exists()) {
s_mapFolderLocation = mapFolder;
} else {
System.out.println("Could not find directory: " + value);
}
}
}
}
}