//
// MUXMapFrame.java
// Thud
//
// Created by asp on Wed Nov 28 2001.
// Copyright (c) 2001-2002 Anthony Parker. All rights reserved.
// Please see LICENSE.TXT for more information.
//
//
package btthud.ui;
import btthud.data.*;
import btthud.util.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.font.*;
import javax.swing.*;
import javax.swing.text.*;
import java.lang.*;
import java.util.*;
import java.awt.print.*;
import java.io.*;
import javax.imageio.*;
import java.awt.image.*;
public class MUXMapFrame extends JInternalFrame implements MouseListener, MouseMotionListener, MouseWheelListener {
Thump mapper;
MUXMap map;
MPrefs prefs;
Thread thread = null;
private boolean go = true;
MUXMapComponent mapComponent = null;
JScrollPane scrollPane = null;
File file;
int h;
static int documentsOpened = 1; // Only for naming new untitled docs
boolean newFile;
ToolManager tools;
static final int MAX_UNDO = 20;
LinkedList undoableChanges;
boolean dragging = false; // True when we've detected a drag
LinkedList changedHexes = new LinkedList(); // List of changed hexes this drag or click
boolean pasting = false; // True when we're pasting some hexes
LinkedList pasteHexes; // List of hexes to paste
int lastVerticalScrollBarValue = 0;
int lastHorizontalScrollBarValue = 0;
// -----------------
public MUXMapFrame(Thump mapper, File file, int mapSize, MPrefs prefs, int hexHeight, ToolManager tools)
{
super("Untitled");
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
this.mapper = mapper;
this.tools = tools;
this.file = file;
if (file == null)
{
map = new MUXMap(mapSize, mapSize);
map.clearMap();
setTitle("Untitled " + documentsOpened + sizeString());
this.file = new File("Untitled " + documentsOpened);
documentsOpened++;
newFile = true;
}
else
{
readMap();
setTitle(file.getName() + sizeString());
newFile = false;
}
// Set a bunch of 'able's
setIconifiable(true);
setMaximizable(true);
setResizable(true);
setClosable(true);
// Let the InternalFrameListener handle this
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
this.prefs = prefs;
this.h = hexHeight;
// Setup the map component
mapComponent = new MUXMapComponent(map, prefs, h);
mapComponent.setPreferredSize(new Dimension(mapComponent.getTotalWidth(), mapComponent.getTotalHeight()));
mapComponent.addMouseListener(this);
mapComponent.addMouseMotionListener(this);
mapComponent.addMouseWheelListener(this);
resetCursor();
// Setup the rulers (hex indicators on the side/top)
Rule xRule = new Rule(Rule.HORIZONTAL, h, map.getSizeX(), prefs.hexNumberFontSize);
Rule yRule = new Rule(Rule.VERTICAL, h, map.getSizeY(), prefs.hexNumberFontSize);
xRule.setPreferredWidth(mapComponent.getTotalWidth());
yRule.setPreferredHeight(mapComponent.getTotalHeight());
// .. and the scroll pane we put them in
// Create the scroll pane & the view
scrollPane = new JScrollPane();
// Create our own viewport, instead of the default one
scrollPane.setViewport(new JViewport() {
public void setViewPosition(Point p) {
// Make sure another thread will not gain control
// while scrolling the view !!!
synchronized (scrollPane.getTreeLock()) {
// Scroll the view now...
super.setViewPosition(p);
}
}
});
// Setup our view in the scroll pane's viewport
scrollPane.getViewport().add(mapComponent, null);
//scrollPane = new JScrollPane(mapComponent);
scrollPane.setColumnHeaderView(xRule);
scrollPane.setRowHeaderView(yRule);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, new Corner());
scrollPane.setWheelScrollingEnabled(false);
scrollPane.doLayout();
setContentPane(scrollPane);
// Our size, loc
setSize(prefs.mapFrameSize);
setLocation((int) prefs.mapFrameLoc.getX() + ((documentsOpened-1)*10 % (int) prefs.desktopSize.getWidth()),
(int) prefs.mapFrameLoc.getY() + ((documentsOpened-1)*10 % (int) prefs.desktopSize.getHeight()));
// Setup undo
undoableChanges = new LinkedList();
// Show the window now
this.show();
// We're done
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
public void resetCursor()
{
if (pasting)
mapComponent.setCursor(CustomCursors.getPasteCursor());
else if (prefs.paintType == ToolManager.TERRAIN_ONLY)
mapComponent.setCursor(CustomCursors.getTerrainCursor());
else if (prefs.paintType == ToolManager.ELEVATION_ONLY)
mapComponent.setCursor(CustomCursors.getElevationCursor());
else if (tools.selectedTool() == ToolPalette.SELECTIVE_UNDO_TOOL)
mapComponent.setCursor(CustomCursors.getUndoCursor());
else
mapComponent.setCursor(CustomCursors.getCrosshairCursor());
}
// --------------------------------------
public void adjustZoom(int zoom, Point mouseCoords)
{
// Find the hex currently in the center of the view
Rectangle viewRect = scrollPane.getViewport().getViewRect();
Point p = scrollPane.getViewport().toViewCoordinates(mouseCoords);
Point centerHex = mapComponent.realToHex(p.getX() == -1 ? (int) (viewRect.getX() + viewRect.getWidth() / 2f) : (int) p.getX(),
p.getY() == -1 ? (int) (viewRect.getY() + viewRect.getHeight() / 2f) : (int) p.getY());
Point2D newRealCenterOfHex;
h += zoom;
if (h < 5)
h = 5;
if (h > 300)
h = 300;
newPreferences(prefs, h);
//mapComponent.revalidate();
newRealCenterOfHex = mapComponent.centerOfHex((int) centerHex.getX(), (int) centerHex.getY());
mapComponent.scrollRectToVisible(new Rectangle((int) (newRealCenterOfHex.getX() - viewRect.getWidth() / 2f),
(int) (newRealCenterOfHex.getY() - viewRect.getHeight() / 2f),
(int) viewRect.getWidth(),
(int) viewRect.getHeight()));
}
public void adjustScrollbars(boolean displayRulers) {
mapComponent.setPreferredSize(new Dimension(mapComponent.getTotalWidth(), mapComponent.getTotalHeight()));
if (displayRulers) {
Rule xRule = new Rule(Rule.HORIZONTAL, h, map.getSizeX(), prefs.hexNumberFontSize);
Rule yRule = new Rule(Rule.VERTICAL, h, map.getSizeY(), prefs.hexNumberFontSize);
xRule.setPreferredWidth(mapComponent.getTotalWidth());
yRule.setPreferredHeight(mapComponent.getTotalHeight());
scrollPane.setColumnHeaderView(xRule);
scrollPane.setRowHeaderView(yRule);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, new Corner());
} else {
scrollPane.setColumnHeaderView(null);
scrollPane.setRowHeaderView(null);
}
scrollPane.doLayout();
scrollPane.repaint();
}
public void newPreferences(MPrefs prefs, int hexHeight)
{
mapComponent.newPreferences(prefs, hexHeight);
h = hexHeight;
adjustScrollbars(!mapComponent.getDrawOverview());
}
/**
* Read values for a map from a File
*/
void readMap()
{
try {
FileReader mapFile = new FileReader(file);
StringBuffer buf = new StringBuffer();
int read;
boolean done = false;
while (!done)
{
read = mapFile.read();
if (read == -1)
done = true;
else
buf.append((char) read);
}
mapFile.close();
parseMap(buf.toString());
} catch (Exception e) {
ErrorHandler.displayError("Could not read the map file data.", ErrorHandler.ERR_OPEN_FAIL);
}
}
/**
* Parse the data read in from the file
*/
void parseMap(String mapData)
{
try {
StringTokenizer st = new StringTokenizer(mapData);
int sizeX, sizeY;
int x = 0;
int y = 0;
int e;
char t;
// Get the size of the map
sizeX = Integer.parseInt(st.nextToken());
sizeY = Integer.parseInt(st.nextToken());
map = new MUXMap(sizeX, sizeY);
// Loop thru each line
while (st.hasMoreTokens())
{
String thisLine = st.nextToken();
// Think the map is over if we hit this thing
if (thisLine.equals("-1") || thisLine.startsWith("-1 "))
break;
for (x = 0; x < sizeX * 2; x+=2)
{
// Get terrain and elevation, then set the data in the map
t = thisLine.charAt(x);
e = Character.digit(thisLine.charAt(x + 1), 10);
map.setHex(x/2, y, t, e);
}
// One more line down in y
y++;
}
} catch (Exception e) {
System.out.println("Error: readMap: " + e);
}
}
/**
* Writes a map to a different file
*/
public boolean saveMapAs(File newFile)
{
this.file = newFile;
return saveMap();
}
/**
* Writes a map to the file specified in the class
* Returns true if success, otherwise false
*/
public boolean saveMap()
{
// This should probably write all the data to a temporary file, then copy it over the old one at the end
try {
StringBuffer buf = new StringBuffer();
FileWriter mapWriter;
if (!file.canWrite())
{
ErrorHandler.displayError("Could not write to map file. Maybe it's locked.", ErrorHandler.ERR_SAVE_FAIL);
return false;
}
file.createNewFile();
mapWriter = new FileWriter(file);
// Write the size in x, y
buf.append(map.getSizeX());
buf.append(" ");
buf.append(map.getSizeY());
buf.append("\n");
// Write all of the data
for (int y = 0; y < map.getSizeY(); y++)
{
for (int x = 0; x < map.getSizeX(); x++)
{
buf.append(MUXHex.terrainForId(map.getHexTerrain(x, y)));
buf.append(map.getHexAbsoluteElevation(x, y));
}
buf.append("\n");
}
// Now write it to the file
mapWriter.write(buf.toString());
mapWriter.close();
// Musta been okay...
map.setChanged(false);
// Change our name
setTitle(file.getName() + sizeString());
return true;
} catch (Exception e) {
ErrorHandler.displayError("Could not write data to map file:\n" + e, ErrorHandler.ERR_SAVE_FAIL);
return false;
}
}
public boolean saveMapAsImage(File imageFile)
{
// This should probably write all the data to a temporary file, then copy it over the old one at the end
try {
BufferedImage mapImage = new BufferedImage((int) mapComponent.getPreferredSize().getWidth(),
(int) mapComponent.getPreferredSize().getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D mapImageGraphics = mapImage.createGraphics();
FileWriter mapWriter;
if (!imageFile.canWrite())
{
ErrorHandler.displayError("Could not write to image file. Maybe it's locked.", ErrorHandler.ERR_SAVE_FAIL);
return false;
}
mapComponent.paint2d(mapImageGraphics);
ImageIO.write(mapImage, "png", imageFile);
return true;
} catch (Exception e) {
ErrorHandler.displayError("Could not write data to map file:\n" + e, ErrorHandler.ERR_SAVE_FAIL);
return false;
}
}
// ----------------------------------------------------------------------------
// ****************************************************************************
protected boolean terrainToolClicked(ListIterator it)
{
Point h = null;
boolean hadHexes = it.hasNext();
// Go through the list and get rid of hexes we don't want to change
// Also, set the data in the map object
while (it.hasNext())
{
h = (Point) it.next();
if (map.getHexTerrain(h) != tools.selectedTerrain())
{
if (!hexAlreadyChanged(h))
changedHexes.addLast(new ChangedMUXHex(h, map.getHex(h)));
map.setHexTerrain(h, tools.selectedTerrain());
mapComponent.repaint(mapComponent.rectForHex(h));
}
else
it.remove();
}
return hadHexes;
}
// ----
protected boolean elevationToolClicked(ListIterator it)
{
Point h;
boolean hadHexes = it.hasNext();
// Go through the list and get rid of hexes we don't want to change
// Also, set the data in the map object
while (it.hasNext())
{
h = (Point) it.next();
if (map.getHexElevation(h) != tools.selectedElevation())
{
if (!hexAlreadyChanged(h))
changedHexes.addLast(new ChangedMUXHex(h, map.getHex(h)));
map.setHexElevation(h, tools.selectedElevation());
mapComponent.repaint(mapComponent.rectForHex(h));
}
else
it.remove();
}
return hadHexes;
}
// ----
protected boolean pasteTool(ArrayList hexes, ArrayList terrain, ArrayList elevation)
{
boolean changedHex = false;
for (int i = 0; i < hexes.size(); i++)
{
// We need to make sure we actually changed something while we are pasting
if (map.getHexTerrain((Point) hexes.get(i)) != ((Integer) terrain.get(i)).intValue() ||
map.getHexElevation((Point) hexes.get(i)) != ((Integer) elevation.get(i)).intValue())
{
changedHex = true;
changedHexes.addLast(new ChangedMUXHex((Point) hexes.get(i), map.getHex((Point) hexes.get(i))));
map.setHex((Point) hexes.get(i),
((Integer) terrain.get(i)).intValue(),
((Integer) elevation.get(i)).intValue());
mapComponent.repaint(mapComponent.rectForHex((Point) hexes.get(i)));
}
}
return changedHex;
}
// --------------------------
protected boolean bothToolClicked(ListIterator it, boolean erase)
{
Point h;
int selectedTerrain = tools.selectedTerrain();
int selectedElevation = tools.selectedElevation();
boolean hadHexes = it.hasNext();
if (erase)
{
selectedTerrain = MUXHex.PLAIN;
selectedElevation = 0;
}
// Go through the list and get rid of hexes we don't want to change
// Also, set the data in the map object
while (it.hasNext())
{
h = (Point) it.next();
if (map.getHexElevation(h) != selectedElevation || map.getHexTerrain(h) != selectedTerrain)
{
// This is a hex we will change
if (!hexAlreadyChanged(h))
changedHexes.addLast(new ChangedMUXHex(h, map.getHex(h)));
map.setHex(h, selectedTerrain, selectedElevation);
mapComponent.repaint(mapComponent.rectForHex(h));
}
else
it.remove();
}
return hadHexes;
}
// ----
protected boolean selectToolClicked(ListIterator it, MouseEvent e)
{
Point h;
ListIterator selectedIt;
Rectangle2D r = new Rectangle2D.Double();
// If control is down, then a control-click removes the selection
if (e.isControlDown())
{
map.deselectAll();
mapComponent.repaint();
}
else
{
while (it.hasNext())
{
h = (Point) it.next();
if (!map.getHexSelected(h))
{
map.setHexSelected(h, true);
mapComponent.repaint(mapComponent.rectForHex(h));
}
else
it.remove();
}
// Now repaint all the selected hexes
if (map.anyHexesSelected())
{
selectedIt = map.selectedHexesIterator();
while (selectedIt.hasNext())
{
// Get the next hex
h = (Point) selectedIt.next();
mapComponent.expandedRectForHex(h, r);
mapComponent.repaint(r);
}
}
}
mapper.resetMenus();
// didn't change anything (no need for an undo)
return false;
}
// ----------------------------------------------------------------------------
// ****************************************************************************
/**
* Handle a click on a hex
*/
protected boolean hexClicked(Point hex, MouseEvent e)
{
int whichTool = tools.selectedTool();
LinkedList hexes = new LinkedList();
Point thisHex;
// Add all the affected hexes to our LinkedList
for (int i = 0; i <= tools.selectedBrushSize(); i++)
{
for (int j = 0; j < BrushToolOptions.brushHexSizes[i]; j++)
{
thisHex = new Point((int) (hex.getX() + BrushToolOptions.brushX[i][j]),
(int) (hex.getY() + BrushToolOptions.brushY[hex.getX() % 2 == 1 ? 1 : 0][i][j]));
if (map.validHex(thisHex))
hexes.add(thisHex);
}
}
// Now send it off to see which tool deals with it
if (tools.selectedTool() == ToolPalette.SELECTIVE_UNDO_TOOL ||
(e.getModifiers() & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASK ||
(e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
{
return selectiveUndoClicked(hex);
}
else if (tools.selectedTool() == ToolPalette.PAINT_TOOL)
{
if (prefs.paintType == ToolManager.TERRAIN_ONLY)
return terrainToolClicked(hexes.listIterator(0));
else if (prefs.paintType == ToolManager.ELEVATION_ONLY)
return elevationToolClicked(hexes.listIterator(0));
else
return bothToolClicked(hexes.listIterator(0), false);
}
else if (tools.selectedTool() == ToolPalette.SELECT_TOOL)
{
return selectToolClicked(hexes.listIterator(0), e);
}
else if (tools.selectedTool() == ToolPalette.ERASE_TOOL)
{
return bothToolClicked(hexes.listIterator(0), true); // Erase
}
return false;
}
// ----
/**
* Handle a selective undo on a hex (undo only this hex from the last undo)
*/
public boolean selectiveUndoClicked(Point h)
{
LinkedList lastChangedHexes;
ListIterator it, lastIt;
ChangedMUXHex changedHex;
if (!canUndo())
return false; // Nothing to do
// Check to see if we have any data on this hex in any of our undos
// have to go /backwards/ in the Undoable changes.. the last item is the most recent
it = undoableChanges.listIterator(undoableChanges.size());
while (it.hasPrevious())
{
lastChangedHexes = (LinkedList) it.previous();
// Now iterate through the hexes changed in this change (order doesn't matter here, each hex appears only once)
lastIt = lastChangedHexes.listIterator();
while (lastIt.hasNext())
{
changedHex = (ChangedMUXHex) lastIt.next();
if (changedHex.getLocation().getX() == h.getX() &&
changedHex.getLocation().getY() == h.getY())
{
// Match!
map.setHex(changedHex.getLocation(), changedHex.getPrevTerrain(), changedHex.getPrevElevation());
mapComponent.repaint(mapComponent.rectForHex(changedHex.getLocation()));
// We've found our match, so let's get out of this nasty looping
return false;
}
}
}
// Always return false
return false;
}
// ----
protected boolean pasteHexClicked(Point hex)
{
boolean changedHex = false;
if (!pasteHexes.isEmpty())
{
changedHexes = new LinkedList();
int x = (int) hex.getX();
int y = (int) hex.getY();
ListIterator it = pasteHexes.listIterator();
CopyableMUXHex copyThisHex;
Point relativeHex, thisHex;
ArrayList hexes = new ArrayList();
ArrayList terrains = new ArrayList();
ArrayList elevations = new ArrayList();
boolean pastedIsEven, locIsEven;
int evenXAdjust = 0;
int oddXAdjust = 0;
// figure out what even and odd situation we're in
locIsEven = x % 2 == 0 ? true : false;
pastedIsEven = ((CopyableMUXHex) it.next()).isEven();
if ((pastedIsEven && locIsEven) || (!pastedIsEven && !locIsEven))
{
// Even->Even or Odd->Odd
evenXAdjust = 0; // no problem here
oddXAdjust = 0;
}
else if (pastedIsEven && !locIsEven)
{
// Even->Odd
evenXAdjust = -1;
oddXAdjust = 0;
}
else if (!pastedIsEven && locIsEven)
{
// Odd->Even
evenXAdjust = 0;
oddXAdjust = 1;
}
// go back to where we started
it.previous();
while (it.hasNext())
{
copyThisHex = (CopyableMUXHex) it.next();
thisHex = new Point(x + (int) copyThisHex.getDx(),
y + (int) copyThisHex.getDy());
// We have to store the x,y to base the next hex off of before we adjust it, otherwise things go beserk
x = (int) thisHex.getX();
y = (int) thisHex.getY();
if ((int) thisHex.getX() % 2 == 0)
thisHex.translate(0, evenXAdjust);
else
thisHex.translate(0, oddXAdjust);
// Add this hex to our list of hexes to change
if (map.validHex(thisHex))
{
hexes.add(thisHex);
terrains.add(new Integer(copyThisHex.getTerrain()));
elevations.add(new Integer(copyThisHex.getElevation()));
}
}
changedHex = pasteTool(hexes, terrains, elevations);
// Add these hexes to our Undoable list
if (changedHex)
addUndoableHexChange(changedHexes);
}
pasting = false;
resetCursor();
return changedHex;
}
// -----------------------------
public void mouseClicked(MouseEvent e)
{
Point hex = mapComponent.realToHex(e.getX(), e.getY());
// Make a new list
changedHexes = new LinkedList();
if (map.validHex(hex))
{
boolean hexesChanged = false;
if (pasting && !pasteHexes.isEmpty())
pasteHexClicked(hex);
else
hexesChanged = hexClicked(hex, e);
// Add this click to our undoable list
if (hexesChanged)
addUndoableHexChange(changedHexes);
}
}
public void mouseDragged(MouseEvent e)
{
Point hex = mapComponent.realToHex(e.getX(), e.getY());
// Note that we're dragging the mouse
dragging = true;
if (map.validHex(hex))
hexClicked(hex, e);
}
public void mouseMoved(MouseEvent e)
{
Point hex = mapComponent.realToHex(e.getX(), e.getY());
// Update the inspector
if (map.validHex(hex))
mapper.updateInspector(hex, map.getHex(hex));
}
public void mouseEntered(MouseEvent e)
{
// Set the proper cursor
resetCursor();
}
public void mouseExited(MouseEvent e)
{
// Clear the inspector
mapper.updateInspector(null, null);
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e)
{
// If we were dragging, then add the list of currently changed hexes to our undoable list
if (dragging)
{
// Add this list of hexes to our undoable
if (changedHexes.size() > 0)
addUndoableHexChange(changedHexes);
// Reset some things
dragging = false;
changedHexes = new LinkedList();
}
}
public void mouseWheelMoved(MouseWheelEvent e)
{
int rotateAmount = e.getWheelRotation();
if (rotateAmount > 0)
rotateAmount = -5;
else
rotateAmount = 5;
// Negative rotateAmount means up/away from user (zoom in), positive means down/towards user (zoom out)
adjustZoom(rotateAmount, e.getPoint());
}
// ----------------------------
protected boolean hexAlreadyChanged(Point p)
{
ListIterator it = changedHexes.listIterator();
while (it.hasNext())
{
if (((ChangedMUXHex) it.next()).matchesHex(p))
return true;
}
return false;
}
// ----------------------------
protected void addUndoableHexChange(LinkedList changedHexes)
{
if (changedHexes.size() > 0)
{
// We changed some stuff - add this list of hexes to our list of undoable stuff
undoableChanges.addLast(changedHexes);
// we only keep a limited size of undo
if (undoableChanges.size() > MAX_UNDO)
undoableChanges.removeFirst();
// Tell our menu bar to enable the undo button
mapper.resetMenus();
}
}
/**
* Handle an undo event
*/
public void doUndo()
{
// Get the last thing we did and reverse it, then remove it from the undoable stuff
// This process is similar to 'Both Tool' being clicked on a hex with old values
LinkedList lastChange = (LinkedList) undoableChanges.getLast();
if (lastChange != null)
{
ListIterator it = lastChange.listIterator(0);
ChangedMUXHex changedHex;
while (it.hasNext())
{
changedHex = (ChangedMUXHex) it.next();
// We'll assume the hex is valid since it's in this list
map.setHex(changedHex.getLocation(), changedHex.getPrevTerrain(), changedHex.getPrevElevation());
mapComponent.repaint(mapComponent.rectForHex(changedHex.getLocation()));
}
// Repaint the hexes
//mapComponent.repaint();
// Remove what we just undid from our undoable list
undoableChanges.removeLast();
}
}
public void doToggleSmallMapView(boolean smallOn) {
if (smallOn) {
// Get the scroll bar values and keep them
if (scrollPane.getVerticalScrollBar() != null) {
lastVerticalScrollBarValue = scrollPane.getVerticalScrollBar().getValue();
}
if (scrollPane.getHorizontalScrollBar() != null) {
lastHorizontalScrollBarValue = scrollPane.getHorizontalScrollBar().getValue();
}
}
mapComponent.setDrawOverview(smallOn);
adjustScrollbars(!smallOn);
if (!smallOn) {
// Restore the scroll bar values
if (scrollPane.getVerticalScrollBar() != null) {
scrollPane.getVerticalScrollBar().setValue(lastVerticalScrollBarValue);
}
if (scrollPane.getHorizontalScrollBar() != null) {
scrollPane.getHorizontalScrollBar().setValue(lastHorizontalScrollBarValue);
}
scrollPane.validate();
}
}
// -----------------------------
/**
* Can we undo anything?
*/
public boolean canUndo()
{
if (undoableChanges == null || undoableChanges.size() > 0)
return true;
else
return false;
}
public boolean canCopy()
{
return map.anyHexesSelected();
}
// -----------------------------
/**
* Has our map data changed?
*/
public boolean hasChanged()
{
return map.hasChanged();
}
// ------------------------------------------------
// ************************************************
// Cut&Paste + Selection stuff
/**
* Paste in some stuff (sets the pasting flag)
*/
public void pasteHexes(LinkedList hexes)
{
pasting = true;
resetCursor();
pasteHexes = hexes;
}
/**
* Clears our deselectable hexes
*/
public void deselectAll()
{
map.deselectAll();
mapComponent.repaint();
mapper.resetMenus();
}
/**
* Erase our selected hexes
*/
public void doCut()
{
bothToolClicked(map.selectedHexesIterator(), true);
}
/**
* Handle printing of this frame
*/
public void doPrint()
{
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable((Printable) mapComponent);
if (printJob.printDialog()) {
try {
printJob.print();
} catch (Exception e) {
ErrorHandler.displayError("An error occured during printing:\n" + e, ErrorHandler.ERR_PRINT_FAIL);
}
}
}
/**
* Return a list of the copyable hexes
*/
public LinkedList copyableHexes()
{
LinkedList copyableHexes = new LinkedList();
ListIterator it = map.selectedHexesIterator();
int x = 0;
int y = 0;
Point h;
if (!map.anyHexesSelected())
return null;
// Create our new list of copyable hexes
// Get the first hex, initialize x,y (the delta between this and the next hex)
h = (Point) it.next();
x = (int) h.getX();
y = (int) h.getY();
// Make sure to set the 'isEven' argument (last one)
copyableHexes.addLast(new CopyableMUXHex(map.getHexTerrain(h), map.getHexElevation(h), 0, 0, x % 2 == 0 ? true : false));
while (it.hasNext())
{
// Get the next hex
h = (Point) it.next();
copyableHexes.addLast(new CopyableMUXHex(map.getHexTerrain(h), map.getHexElevation(h), (int) h.getX() - x, (int) h.getY() - y));
// Set up these values for our next hex
x = (int) h.getX();
y = (int) h.getY();
}
return copyableHexes;
}
// ---------------------------------------------------------------
/**
* Get file name
*/
public String fileName()
{
return file.getName();
}
/**
* Returns true if this is a new file (ie, can be saved with just a 'Save')
*/
public boolean newFile()
{
return newFile;
}
/**
* Returns a string representing the size of our map (used in title)
*/
protected String sizeString()
{
return (" (" + map.getSizeX() + " x " + map.getSizeY() + ")");
}
}