package net.sf.colossus.tools; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.print.Book; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import javax.swing.AbstractAction; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import net.sf.colossus.gui.GUIBattleHex; import net.sf.colossus.server.VariantSupport; import net.sf.colossus.util.StaticResourceLoader; import net.sf.colossus.variant.BattleHex; import net.sf.colossus.variant.HazardHexside; import net.sf.colossus.variant.HazardTerrain; import net.sf.colossus.xmlparser.BattlelandLoader; /** * Class ShowBuilderHexMap displays a battle map. * * @author David Ripton * @author Romain Dolbeau */ final class ShowBuilderHexMap extends BuilderHexMap implements Printable { private final JFrame frame; private final JPopupMenu popupMenuTerrain; private final JPopupMenu popupMenuBorder; private Point lastPoint; private int lastSide; private final JCheckBoxMenuItem towerItem; private final AbstractAction towerAction; private final AbstractAction clearStartListAction; private String mapName = null; class rndFileFilter extends javax.swing.filechooser.FileFilter { @Override public boolean accept(java.io.File f) { if (f.isDirectory()) { return (true); } if (f.getName().endsWith(".rnd")) { return (true); } return (false); } @Override public String getDescription() { return ("Colossus RaNDom generator files"); } } class xmlFileFilter extends javax.swing.filechooser.FileFilter { @Override public boolean accept(java.io.File f) { if (f.isDirectory()) { return (true); } if (f.getName().endsWith(".xml")) { return (true); } return (false); } @Override public String getDescription() { return ("XML files"); } } private void doLoadRandom(BattleHex[][] h) { javax.swing.JFileChooser loadFileChooser = new JFileChooser("."); loadFileChooser.setFileFilter(new rndFileFilter()); loadFileChooser .setDialogTitle("Choose the RaNDom file to open (or cancel for nothing)"); int returnVal = loadFileChooser.showOpenDialog(loadFileChooser); if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION) { java.io.File rndFile = loadFileChooser.getSelectedFile(); String tempRndName = rndFile.getName(); String tempRndDirectory = rndFile.getParentFile() .getAbsolutePath(); List<String> directories = new java.util.ArrayList<String>(); directories.add(tempRndDirectory); InputStream inputFile = StaticResourceLoader.getInputStream( tempRndName, directories); if (inputFile != null) { doRandomization(h, inputFile); setMapName(getDisplayName()); towerItem.setState(isTower); } } } private void doLoadFile(BattleHex[][] h) { JFileChooser loadFileChooser = new JFileChooser(); loadFileChooser.setFileFilter(new xmlFileFilter()); loadFileChooser .setDialogTitle("Choose the battleland file to open (or cancel for nothing)"); int returnVal = loadFileChooser.showOpenDialog(loadFileChooser); if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION) { File loadFileFile = loadFileChooser.getSelectedFile(); String temploadFileName = loadFileFile.getName(); String temploadFileDirectory = loadFileFile.getParentFile() .getAbsolutePath(); List<String> directories = new ArrayList<String>(); directories.add(temploadFileDirectory); InputStream inputFile = net.sf.colossus.util.StaticResourceLoader .getInputStream(temploadFileName, directories); if (inputFile != null) { BattlelandLoader parser = new BattlelandLoader(inputFile, h); try { towerItem.setState(parser.isTower()); isTower = parser.isTower(); List<String> startList = parser.getStartList(); if (startList != null) { Set<BattleHex> startHexes = new HashSet<BattleHex>(); for (String string : startList) { startHexes.add(getHexByLabel(string)); } selectHexes(startHexes); } setSubtitle(parser.getSubtitle()); String lMapName = temploadFileName.replaceAll(".xml", ""); setDisplayName(lMapName); setBasicName(lMapName); setMapName(lMapName); super.repaint(); } catch (Exception e) { System.err.println(e); } } } } private void doSaveFile() { javax.swing.JFileChooser saveFileChooser = new JFileChooser(); saveFileChooser .setDialogTitle("Choose the battleland file to save (or cancel for nothing)"); int returnVal = saveFileChooser.showSaveDialog(saveFileChooser); if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION) { java.io.File saveFileFile = saveFileChooser.getSelectedFile(); String tempsaveFileName = saveFileFile.getName(); String tempsaveFileDirectory = saveFileFile.getParentFile() .getAbsolutePath(); List<String> directories = new ArrayList<String>(); directories.add(tempsaveFileDirectory); OutputStream outputFile = net.sf.colossus.util.StaticResourceLoader .getOutputStream(tempsaveFileName, directories); if (outputFile != null) { String outStr = dumpAsString(); try { outputFile.write(outStr.getBytes()); outputFile.flush(); outputFile.close(); String lMapName = tempsaveFileName.replaceAll(".xml", ""); setDisplayName(lMapName); setBasicName(lMapName); setMapName(getDisplayName()); super.repaint(); } catch (Exception e) { System.err.println(e); } } } } private void doPrintBattleland() { PrinterJob printerJob = PrinterJob.getPrinterJob(); Book book = new Book(); book.append(this, new PageFormat()); printerJob.setPageable(book); boolean doPrint = printerJob.printDialog(); if (doPrint) { try { printerJob.print(); } catch (PrinterException exception) { System.err.println("Printing error: " + exception); } } } /* Printable */ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) { if (pageIndex >= 1) { return Printable.NO_SUCH_PAGE; } Graphics2D g2 = (Graphics2D)graphics; g2.scale(.5, .5); g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); paint(g2); return Printable.PAGE_EXISTS; } private void doFillEdge(BattleHex[][] h, HazardHexside hazard) { for (int i = 0; i < h.length; i++) { for (int j = 0; j < h[i].length; j++) { if (h[i][j] != null) { for (int k = 0; k < 6; k++) { if ((h[i][j].getHexsideHazard(k) == HazardHexside.NOTHING) && (h[i][j].getOppositeHazard(k) == HazardHexside.NOTHING)) { BattleHex n = h[i][j].getNeighbor(k); if (n != null) { if (hazard == HazardHexside.CLIFF) { if (h[i][j].getElevation() > (n .getElevation() + 1)) { h[i][j].setHexsideHazard(k, HazardHexside.CLIFF); } } else if (hazard == HazardHexside.DUNE) { if (h[i][j].getTerrain().isSand() && n.getTerrain().isPlains()) { h[i][j].setHexsideHazard(k, HazardHexside.DUNE); } } else if (hazard == HazardHexside.SLOPE) { if (h[i][j].getElevation() == (n .getElevation() + 1)) { h[i][j].setHexsideHazard(k, HazardHexside.SLOPE); } } } } } } } } } class TerrainAction extends AbstractAction { HazardTerrain te; TerrainAction(String t, HazardTerrain te) { super(t); this.te = te; } public void actionPerformed(ActionEvent e) { GUIBattleHex h = getHexContainingPoint(lastPoint); h.getHexModel().setTerrain(te); h.repaint(); } } class CleanAllHexsideAction extends AbstractAction { boolean myself; CleanAllHexsideAction(String t, boolean myself) { super(t); this.myself = myself; } public void actionPerformed(ActionEvent e) { GUIBattleHex h = getHexContainingPoint(lastPoint); if (myself) { for (int i = 0; i < 6; i++) { h.getHexModel().setHexsideHazard(i, HazardHexside.NOTHING); GUIBattleHex n = h.getNeighbor(i); if (n != null) { n.repaint(); } } } else { for (int i = 0; i < 6; i++) { GUIBattleHex n = h.getNeighbor(i); if (n != null) { n.getHexModel().setHexsideHazard((i + 3) % 6, HazardHexside.NOTHING); n.repaint(); } } } h.repaint(); } } class ElevationAction extends AbstractAction { int el; ElevationAction(String t, int el) { super(t); this.el = el; } public void actionPerformed(ActionEvent e) { GUIBattleHex h = getHexContainingPoint(lastPoint); h.getHexModel().setElevation(el); h.repaint(); } } class HexsideAction extends AbstractAction { HazardHexside hazard; HexsideAction(String t, HazardHexside h) { super(t); this.hazard = h; } public void actionPerformed(ActionEvent e) { GUIBattleHex h = getHexContainingPoint(lastPoint); h.getHexModel().setHexsideHazard(lastSide, hazard); h.repaint(); (h.getNeighbor(lastSide)).repaint(); } } private final AbstractAction showBattlelandAction; private final AbstractAction saveBattlelandAsAction; private final AbstractAction printBattlelandAction; private final AbstractAction quitAction; private final AbstractAction eraseAction; private final AbstractAction randomizeAction; private final AbstractAction fillWithSlopeAction; private final AbstractAction fillWithCliffAction; private final AbstractAction fillWithDuneAction; private final AbstractAction loadFileAction; JMenuBar menuBar; private class randomizeActionPredef extends AbstractAction { private final String filename; randomizeActionPredef(String name, String filename) { super(name); this.filename = filename; } public void actionPerformed(ActionEvent e) { InputStream inputFile = StaticResourceLoader.getInputStream( filename, VariantSupport.getVarDirectoriesList()); doRandomization(getBattleHexArray(), inputFile); setMapName(getDisplayName()); towerItem.setState(isTower); repaint(); } } ShowBuilderHexMap() { super(); menuBar = new JMenuBar(); JMenu fileMenu = new JMenu("File"); fileMenu.setMnemonic(KeyEvent.VK_F); menuBar.add(fileMenu); JMenuItem mi; showBattlelandAction = new AbstractAction("Show Battleland") { public void actionPerformed(ActionEvent e) { System.out.print(dumpAsString()); } }; saveBattlelandAsAction = new AbstractAction( "Save Battleland as file...") { public void actionPerformed(ActionEvent e) { doSaveFile(); } }; printBattlelandAction = new AbstractAction("Print Battleland...") { public void actionPerformed(ActionEvent e) { doPrintBattleland(); } }; quitAction = new AbstractAction("Quit") { public void actionPerformed(ActionEvent e) { System.exit(0); } }; eraseAction = new AbstractAction("Erase all map hexes & hexsides") { public void actionPerformed(ActionEvent e) { eraseMap(); repaint(); } }; randomizeAction = new AbstractAction("Randomize Map from file...") { public void actionPerformed(ActionEvent e) { doLoadRandom(getBattleHexArray()); repaint(); } }; loadFileAction = new AbstractAction("Load Map from file...") { public void actionPerformed(ActionEvent e) { doLoadFile(getBattleHexArray()); repaint(); } }; mi = fileMenu.add(loadFileAction); mi.setMnemonic(KeyEvent.VK_O); mi = fileMenu.add(saveBattlelandAsAction); mi.setMnemonic(KeyEvent.VK_S); mi = fileMenu.add(printBattlelandAction); mi = fileMenu.add(showBattlelandAction); mi = fileMenu.add(quitAction); mi.setMnemonic(KeyEvent.VK_Q); JMenu specialMenu = new JMenu("Special"); menuBar.add(specialMenu); mi = specialMenu.add(eraseAction); specialMenu.addSeparator(); towerAction = new AbstractAction("Terrain is a Tower") { public void actionPerformed(ActionEvent e) { JCheckBoxMenuItem mi = (JCheckBoxMenuItem)e.getSource(); isTower = !isTower; mi.setState(isTower); } }; towerItem = (JCheckBoxMenuItem)specialMenu.add(new JCheckBoxMenuItem( towerAction)); clearStartListAction = new AbstractAction("Remove StartList") { public void actionPerformed(ActionEvent e) { for (int i = 0; i < h.length; i++) { for (int j = 0; j < h[0].length; j++) { if ((h[i][j] != null) && (h[i][j].isSelected())) { h[i][j].unselect(); h[i][j].repaint(); } } } } }; mi = specialMenu.add(clearStartListAction); specialMenu.addSeparator(); fillWithSlopeAction = new AbstractAction("Fill Low Edge with Slope") { public void actionPerformed(ActionEvent e) { doFillEdge(getBattleHexArray(), HazardHexside.SLOPE); repaint(); } }; fillWithCliffAction = new AbstractAction("Fill High Edge with Cliff") { public void actionPerformed(ActionEvent e) { doFillEdge(getBattleHexArray(), HazardHexside.CLIFF); repaint(); } }; fillWithDuneAction = new AbstractAction("Fill Sand Edge with Dune") { public void actionPerformed(ActionEvent e) { doFillEdge(getBattleHexArray(), HazardHexside.DUNE); repaint(); } }; mi = specialMenu.add(fillWithSlopeAction); mi = specialMenu.add(fillWithCliffAction); mi = specialMenu.add(fillWithDuneAction); JMenu randomMenu = new JMenu("Randomize as "); final Map<String, String> defaultRandom = new TreeMap<String, String>(); defaultRandom.put("Brush", "Battlelands/Brush.rnd"); defaultRandom.put("Desert", "Battlelands/Desert.rnd"); defaultRandom.put("Hills", "Battlelands/Hills.rnd"); defaultRandom.put("Jungle", "Battlelands/Jungle.rnd"); defaultRandom.put("Marsh", "Battlelands/Marsh.rnd"); defaultRandom.put("Mountains", "Battlelands/Mountains.rnd"); defaultRandom.put("Plains", "Battlelands/Plains.rnd"); defaultRandom.put("Swamp", "Battlelands/Swamp.rnd"); defaultRandom.put("Tower", "Battlelands/Tower.rnd"); defaultRandom.put("Tundra", "Battlelands/Tundra.rnd"); defaultRandom.put("Woods", "Battlelands/Woods.rnd"); for (String name : defaultRandom.keySet()) { mi = randomMenu.add(new randomizeActionPredef(name, defaultRandom .get(name))); } randomMenu.addSeparator(); defaultRandom.clear(); defaultRandom.put("Beach", "Battlelands/Custom_Beach.rnd"); for (String name : defaultRandom.keySet()) { mi = randomMenu.add(new randomizeActionPredef(name, defaultRandom .get(name))); } randomMenu.addSeparator(); mi = randomMenu.add(randomizeAction); specialMenu.addSeparator(); specialMenu.add(randomMenu); frame = new JFrame("BattlelandBuilder"); Container contentPane = frame.getContentPane(); contentPane.setLayout(new BorderLayout()); contentPane.add(menuBar, BorderLayout.NORTH); addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { lastPoint = e.getPoint(); GUIBattleHex h = getHexContainingPoint(lastPoint); if (h != null) { Point c = h.findCenter(); if (c.y >= lastPoint.y) { // uppper half if (lastPoint.x >= ((c.x) + (h.getBounds().x + h .getBounds().width)) / 2) { lastSide = 1; } else if (lastPoint.x <= ((c.x) + (h.getBounds().x)) / 2) { lastSide = 5; } else { lastSide = 0; } } else { // lower half if (lastPoint.x >= ((c.x) + (h.getBounds().x + h .getBounds().width)) / 2) { lastSide = 2; } else if (lastPoint.x <= ((c.x) + (h.getBounds().x)) / 2) { lastSide = 4; } else { lastSide = 3; } } if (h.innerContains(lastPoint) || (h.getNeighbor(lastSide) == null)) { // change content popupMenuTerrain.show(e.getComponent(), lastPoint.x, lastPoint.y); } else { // change border popupMenuBorder.show(e.getComponent(), lastPoint.x, lastPoint.y); } } } }); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { // TODO: we should exit cleanly System.exit(0); } }); contentPane.add(this, BorderLayout.CENTER); frame.pack(); frame.setVisible(true); popupMenuTerrain = new JPopupMenu("Choose Terrain"); contentPane.add(popupMenuTerrain); Collection<HazardTerrain> terrains = HazardTerrain .getAllHazardTerrains(); GUIBattleHex tempH = new GUIBattleHex(0, 0, 1, this, 0, 0); for (HazardTerrain terrain : terrains) { tempH.getHexModel().setTerrain(terrain); mi = popupMenuTerrain.add(new TerrainAction(terrain.getName(), terrain)); } popupMenuTerrain.addSeparator(); for (int i = 0; i < 4; i++) { mi = popupMenuTerrain.add(new ElevationAction("Set Elevation to: " + i, i)); } popupMenuTerrain.addSeparator(); popupMenuTerrain.add(new CleanAllHexsideAction("Clear my hexsides", true)); popupMenuTerrain.add(new CleanAllHexsideAction( "Clear my neighbors' hexsides", false)); popupMenuTerrain.addSeparator(); AbstractAction select = new AbstractAction( "Select/Unselect (StartList)") { public void actionPerformed(ActionEvent e) { GUIBattleHex h = getHexContainingPoint(lastPoint); if (h.isSelected()) { h.unselect(); } else { h.select(); } h.repaint(); } }; mi = popupMenuTerrain.add(select); popupMenuBorder = new JPopupMenu("Choose Border"); contentPane.add(popupMenuBorder); Collection<HazardHexside> hazardTypes = HazardHexside .getAllHazardHexsides(); for (HazardHexside hazard : hazardTypes) { tempH.getHexModel().setHexsideHazard(0, hazard); mi = popupMenuBorder.add(new HexsideAction(tempH.getHexModel() .getHexsideHazard(0).getName(), hazard)); } lastPoint = new Point(0, 0); lastSide = 0; } private void setMapName(String name) { mapName = name; frame.setTitle("BattlelandBuilder" + (mapName == null ? "" : ": " + mapName)); } }