/** * Copyright (C) 2002-2012 The FreeCol Team * * This file is part of FreeCol. * * FreeCol is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * FreeCol is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with FreeCol. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.freecol.client.gui; import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; import java.util.logging.Logger; import org.freecolandroid.repackaged.java.awt.Color; import org.freecolandroid.repackaged.java.awt.Graphics2D; import org.freecolandroid.repackaged.java.awt.Point; import org.freecolandroid.repackaged.java.awt.event.MouseEvent; import org.freecolandroid.repackaged.java.awt.event.MouseListener; import org.freecolandroid.repackaged.java.awt.event.MouseMotionListener; import org.freecolandroid.repackaged.javax.swing.JComponent; import org.freecolandroid.repackaged.javax.swing.SwingUtilities; import net.sf.freecol.FreeCol; import net.sf.freecol.client.ClientOptions; import net.sf.freecol.client.FreeColClient; import net.sf.freecol.client.control.MapEditorController; import net.sf.freecol.client.gui.panel.MapEditorTransformPanel.TileTypeTransform; import net.sf.freecol.common.model.Map; import net.sf.freecol.common.model.Map.Direction; import net.sf.freecol.common.model.Tile; import net.sf.freecol.common.model.TileImprovement; import net.sf.freecol.common.resources.ResourceManager; import net.sf.freecol.server.generator.TerrainGenerator; /** * Listens to the mouse being moved at the level of the Canvas. */ public final class CanvasMapEditorMouseListener implements MouseListener, MouseMotionListener { private static final Logger logger = Logger.getLogger(CanvasMapEditorMouseListener.class.getName()); private final Canvas canvas; private final MapViewer mapViewer; private ScrollThread scrollThread; private static final int DRAG_SCROLLSPACE = 100; private static final int AUTO_SCROLLSPACE = 1; private Point oldPoint; private Point startPoint; private FreeColClient freeColClient; private GUI gui; /** * The constructor to use. * * @param canvas The component this object gets created for. * @param gui The GUI that holds information such as screen resolution. */ public CanvasMapEditorMouseListener(FreeColClient freeColClient, GUI gui, Canvas canvas) { this.freeColClient = freeColClient; this.gui = gui; this.canvas = canvas; this.mapViewer = gui.getMapViewer(); this.scrollThread = null; } /** * This method can be called to make sure the map is loaded * There is no point executing mouse events if the map is not loaded */ private Map getMap() { Map map = null; if (freeColClient.getGame() != null) map = freeColClient.getGame().getMap(); return map; } /** * Invoked when a mouse button was clicked. * * @param e The MouseEvent that holds all the information. */ public void mouseClicked(MouseEvent e) { if (getMap() == null) { return; } try { if (e.getClickCount() > 1) { Tile tile = mapViewer.convertToMapTile(e.getX(), e.getY()); canvas.showColonyPanel(tile); } else { canvas.requestFocus(); } } catch (Exception ex) { logger.log(Level.WARNING, "Error in mouseClicked!", ex); } } /** * Invoked when the mouse enters the component. * * @param e The MouseEvent that holds all the information. */ public void mouseEntered(MouseEvent e) { // Ignore for now. } /** * Invoked when the mouse exits the component. * * @param e The MouseEvent that holds all the information. */ public void mouseExited(MouseEvent e) { // Ignore for now. } /** * Invoked when a mouse button was pressed. * * @param e The MouseEvent that holds all the information. */ public void mousePressed(MouseEvent e) { if (!e.getComponent().isEnabled()) { return; } if (getMap() == null) { return; } try { if (e.getButton() == MouseEvent.BUTTON3 || e.isPopupTrigger()) { Tile tile = mapViewer.convertToMapTile(e.getX(), e.getY()); if (tile != null) { if (tile.hasRiver()) { TileImprovement river = tile.getRiver(); int style = canvas.showRiverStyleDialog(); if (style == -1) { // user canceled } else if (style == 0) { tile.getTileItemContainer().removeTileItem(river); } else if (0 < style && style < ResourceManager.RIVER_STYLES) { river.setStyle(style); } else { logger.warning("Unknown river style: " + style); } } if (tile.getIndianSettlement() != null) { canvas.showEditSettlementDialog(tile.getIndianSettlement()); } } else { gui.setSelectedTile(null, true); } } else if (e.getButton() == MouseEvent.BUTTON1) { startPoint = e.getPoint(); oldPoint = e.getPoint(); JComponent component = (JComponent)e.getSource(); drawBox(component, startPoint, oldPoint); } } catch (Exception ex) { logger.log(Level.WARNING, "Error in mousePressed!", ex); } } /** * Invoked when a mouse button was released. * * @param e The MouseEvent that holds all the information. */ public void mouseReleased(MouseEvent e) { if (getMap() == null) { return; } JComponent component = (JComponent)e.getSource(); MapEditorController controller = freeColClient .getMapEditorController(); boolean isTransformActive = controller.getMapTransform() != null; if(startPoint == null){ startPoint = e.getPoint(); } if(oldPoint == null){ oldPoint = e.getPoint(); } drawBox(component, startPoint, oldPoint); if (gui.getFocus() != null) { Tile start = mapViewer.convertToMapTile(startPoint.x, startPoint.y); Tile end = start; //Optimization, only check if the points are different if(startPoint.x != oldPoint.x || startPoint.y != oldPoint.y){ end = mapViewer.convertToMapTile(oldPoint.x, oldPoint.y); } // no option selected, just center map if(!isTransformActive){ gui.setFocus(end); return; } // find the area to transform int min_x, max_x, min_y, max_y; if (start.getX() < end.getX()) { min_x = start.getX(); max_x = end.getX(); } else { min_x = end.getX(); max_x = start.getX(); } if (start.getY() < end.getY()) { min_y = start.getY(); max_y = end.getY(); } else { min_y = end.getY(); max_y = start.getY(); } // apply transformation to all tiles in the area Tile t = null; for (int x = min_x; x <= max_x; x++) { for (int y = min_y; y <= max_y; y++) { t = getMap().getTile(x, y); if (t != null) { controller.transform(t); } } } if (controller.getMapTransform() instanceof TileTypeTransform) { for (int x = min_x - 2; x <= max_x + 2; x++) { for (int y = min_y - 2; y <= max_y + 2; y++) { t = getMap().getTile(x, y); if (t != null && t.getType().isWater()) { TerrainGenerator.encodeStyle(t); } } } } gui.refresh(); canvas.requestFocus(); } } /** * Invoked when the mouse has been moved. * * @param e The MouseEvent that holds all the information. */ public void mouseMoved(MouseEvent e) { if (getMap() == null) { return; } if (e.getComponent().isEnabled() && freeColClient.getClientOptions() .getBoolean(ClientOptions.AUTO_SCROLL)) { auto_scroll(e.getX(), e.getY()); } else if (scrollThread != null) { scrollThread.stopScrolling(); scrollThread = null; } } /** * Invoked when the mouse has been dragged. * * @param e The MouseEvent that holds all the information. */ public void mouseDragged(MouseEvent e) { if (getMap() == null) { return; } JComponent component = (JComponent)e.getSource(); drawBox(component, startPoint, oldPoint); oldPoint = e.getPoint(); drawBox(component, startPoint, oldPoint); if (e.getComponent().isEnabled() && freeColClient.getClientOptions() .getBoolean(ClientOptions.MAP_SCROLL_ON_DRAG)) { drag_scroll(e.getX(), e.getY()); } else if (scrollThread != null) { scrollThread.stopScrolling(); scrollThread = null; } gui.refresh(); } private void drawBox(JComponent component, Point startPoint, Point endPoint) { if(startPoint == null || endPoint == null){ return; } if(startPoint.distance(endPoint) == 0){ return; } // only bother to draw if a transformation is active MapEditorController controller = freeColClient.getMapEditorController(); if(controller.getMapTransform() == null){ return; } Graphics2D graphics = (Graphics2D) component.getGraphics (); graphics.setColor(Color.WHITE); int x = Math.min(startPoint.x, endPoint.x); int y = Math.min(startPoint.y, endPoint.y); int width = Math.abs(startPoint.x - endPoint.x); int height = Math.abs(startPoint.y - endPoint.y); graphics.drawRect(x, y, width, height); } private void auto_scroll(int x, int y){ scroll(x, y, AUTO_SCROLLSPACE); } private void drag_scroll(int x, int y){ scroll(x, y, DRAG_SCROLLSPACE); } private void scroll(int x, int y, int scrollspace) { if (getMap() == null) { return; } /* * if (y < canvas.getMenuBarHeight()) { if (scrollThread != null) { * scrollThread.stopScrolling(); scrollThread = null; } return; } else * if (y < canvas.getMenuBarHeight() + SCROLLSPACE) { y -= * canvas.getMenuBarHeight(); } */ Direction direction; if ((x < scrollspace) && (y < scrollspace)) { // Upper-Left direction = Direction.NW; } else if ((x >= mapViewer.getWidth() - scrollspace) && (y < scrollspace)) { // Upper-Right direction = Direction.NE; } else if ((x >= mapViewer.getWidth() - scrollspace) && (y >= mapViewer.getHeight() - scrollspace)) { // Bottom-Right direction = Direction.SE; } else if ((x < scrollspace) && (y >= mapViewer.getHeight() - scrollspace)) { // Bottom-Left direction = Direction.SW; } else if (y < scrollspace) { // Top direction = Direction.N; } else if (x >= mapViewer.getWidth() - scrollspace) { // Right direction = Direction.E; } else if (y >= mapViewer.getHeight() - scrollspace) { // Bottom direction = Direction.S; } else if (x < scrollspace) { // Left direction = Direction.W; } else { // Center if (scrollThread != null) { scrollThread.stopScrolling(); scrollThread = null; } return; } if (scrollThread != null) { // continue scrolling in a (perhaps new) direction scrollThread.setDirection(direction); } else { // start scrolling in a direction scrollThread = new ScrollThread(mapViewer); scrollThread.setDirection(direction); scrollThread.start(); } } /** * Scrolls the view of the Map by moving its focus. */ private class ScrollThread extends Thread { private final MapViewer mapViewer; private Direction direction; private boolean cont; /** * The constructor to use. * * @param mapViewer The GUI that holds information such as screen resolution. */ public ScrollThread(MapViewer mapViewer) { super(FreeCol.CLIENT_THREAD+"Mouse scroller"); this.mapViewer = mapViewer; this.cont = true; } /** * Sets the direction in which this ScrollThread will scroll. * * @param d The direction in which this ScrollThread will scroll. */ public void setDirection(Direction d) { direction = d; } /** * Makes this ScrollThread stop doing what it is supposed to do. */ public void stopScrolling() { cont = false; } /** * Performs the actual scrolling. */ @Override public void run() { do { try { sleep(100); } catch (InterruptedException e) { } try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { try { int x, y; Tile t = mapViewer.getFocus(); if (t == null) { return; } t = t.getNeighbourOrNull(direction); if (t == null) { return; } if (mapViewer.isMapNearTop(t.getY()) && mapViewer.isMapNearTop(mapViewer.getFocus().getY())) { if (t.getY() > mapViewer.getFocus().getY()) { y = t.getY(); do { y += 2; } while (mapViewer.isMapNearTop(y)); } else { y = mapViewer.getFocus().getY(); } } else if (mapViewer.isMapNearBottom(t.getY()) && mapViewer.isMapNearBottom(mapViewer.getFocus().getY())) { if (t.getY() < mapViewer.getFocus().getY()) { y = t.getY(); do { y -= 2; } while (mapViewer.isMapNearBottom(y)); } else { y = mapViewer.getFocus().getY(); } } else { y = t.getY(); } if (mapViewer.isMapNearLeft(t.getX(), t.getY()) && mapViewer.isMapNearLeft(mapViewer.getFocus().getX(), mapViewer.getFocus().getY())) { if (t.getX() > mapViewer.getFocus().getX()) { x = t.getX(); do { x++; } while (mapViewer.isMapNearLeft(x, y)); } else { x = mapViewer.getFocus().getX(); } } else if (mapViewer.isMapNearRight(t.getX(), t.getY()) && mapViewer.isMapNearRight(mapViewer.getFocus().getX(), mapViewer.getFocus().getY())) { if (t.getX() < mapViewer.getFocus().getX()) { x = t.getX(); do { x--; } while (mapViewer.isMapNearRight(x, y)); } else { x = mapViewer.getFocus().getX(); } } else { x = t.getX(); } mapViewer.setFocus(getMap().getTile(x,y)); } catch (Exception e) { logger.log(Level.WARNING, "Exception while scrolling!", e); } } }); } catch (InvocationTargetException e) { logger.log(Level.WARNING, "Scroll thread caught error", e); cont = false; } catch (InterruptedException e) { logger.log(Level.WARNING, "Scroll thread interrupted", e); cont = false; } } while (cont); } } }