1 package org.xpilot.jxpmap;
2 
3 import java.awt.Color;
4 import java.awt.Dimension;
5 import java.awt.Graphics;
6 import java.awt.Graphics2D;
7 import java.awt.Point;
8 import java.awt.Rectangle;
9 import java.awt.Shape;
10 import java.awt.RenderingHints;
11 import java.awt.event.MouseEvent;
12 import java.awt.event.InputEvent;
13 import java.awt.geom.AffineTransform;
14 import java.math.BigDecimal;
15 import java.util.List;
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.Map;
19 
20 import javax.swing.JComponent;
21 import javax.swing.undo.AbstractUndoableEdit;
22 import javax.swing.undo.CompoundEdit;
23 import javax.swing.undo.UndoManager;
24 import javax.swing.undo.UndoableEdit;
25 
26 public class MapCanvas extends JComponent {
27 
28     public static final int MODE_SELECT = 0;
29     public static final int MODE_EDIT = 1;
30     public static final int MODE_ERASE = 2;
31     public static final int MODE_COPY = 3;
32 
33     private MapModel model;
34     private float scale;
35     private AffineTransform at, it;
36     private CanvasEventHandler eventHandler;
37     private CanvasEventHandler dragHandler, selectHandler;
38     private int mode;
39     private Point offset;
40     private UndoManager undoManager;
41     private MapEdit currentEdit;
42     private boolean fastRendering;
43     private List selected;
44     private int grid;
45 
MapCanvas()46     public MapCanvas() {
47 
48         setOpaque(true);
49         offset = new Point(0, 0);
50         AwtEventHandler handler = new AwtEventHandler();
51         addMouseListener(handler);
52         addMouseMotionListener(handler);
53         undoManager = new UndoManager();
54         dragHandler = new DragHandler();
55         selectHandler = new SelectHandler();
56         selected = new ArrayList();
57         grid = -1;
58         mode = MODE_SELECT;
59     }
60 
setCanvasEventHandler(CanvasEventHandler h)61     public void setCanvasEventHandler(CanvasEventHandler h) {
62         eventHandler = h;
63     }
64 
getCanvasEventHandler()65     public CanvasEventHandler getCanvasEventHandler() {
66         return eventHandler;
67     }
68 
getUndoManager()69     public UndoManager getUndoManager() {
70         return undoManager;
71     }
72 
getModel()73     public MapModel getModel() {
74         return model;
75     }
76 
setFastRendering(boolean value)77     public void setFastRendering(boolean value) {
78         this.fastRendering = value;
79     }
80 
isFastRendering()81     public boolean isFastRendering() {
82         return this.fastRendering;
83     }
84 
getSelectedObjects()85     public List getSelectedObjects() {
86         return selected;
87     }
88 
setSelectedObject(MapObject object)89     public void setSelectedObject(MapObject object) {
90         if (!selected.isEmpty()) {
91             for (Iterator i = selected.iterator(); i.hasNext();)
92                 ((MapObject)i.next()).setSelected(false);
93         }
94         selected.clear();
95         if (object != null) {
96             object.setSelected(true);
97             selected.add(object);
98         }
99     }
100 
addSelectedObject(MapObject object)101     public void addSelectedObject(MapObject object) {
102         object.setSelected(true);
103         selected.add(object);
104     }
105 
setModel(MapModel m)106     public void setModel(MapModel m) {
107         this.model = m;
108         this.scale = m.getDefaultScale();
109         this.at = null;
110         this.it = null;
111         eventHandler = null;
112         repaint();
113     }
114 
getScale()115     public float getScale() {
116         return scale;
117     }
118 
setScale(float s)119     public void setScale(float s) {
120         this.offset.x = (int)(this.offset.x * s / this.scale);
121         this.offset.y = (int)(this.offset.y * s / this.scale);
122         this.scale = s;
123         this.at = null;
124         this.it = null;
125         eventHandler = null;
126         revalidate();
127     }
128 
setMode(int mode)129     public void setMode(int mode) {
130         this.mode = mode;
131     }
132 
getMode()133     public int getMode() {
134         return mode;
135     }
136 
setGrid(int grid)137     public void setGrid(int grid) {
138         this.grid = grid;
139     }
140 
getGrid()141     public int getGrid() {
142         return grid;
143     }
144 
paint(Graphics _g)145     public void paint(Graphics _g) {
146 
147         if (model == null)
148             return;
149 
150         Graphics2D g = (Graphics2D) _g;
151         if (fastRendering)
152             g.setRenderingHint(RenderingHints.KEY_RENDERING,
153                 RenderingHints.VALUE_RENDER_SPEED);
154         Dimension mapSize = model.options.getSize();
155 
156         g.setColor(Color.black);
157         g.fill(g.getClipBounds());
158 
159         AffineTransform rootTx = new AffineTransform(g.getTransform());
160         rootTx.concatenate(getTransform());
161         g.setTransform(rootTx);
162 
163         g.setColor(Color.red);
164         Rectangle world = new Rectangle(0, 0, mapSize.width, mapSize.height);
165         g.draw(world);
166         //drawShapeNoTx(g, world);
167 
168         Rectangle view = g.getClipBounds();
169         Point min = new Point();
170         Point max = new Point();
171 
172         for (int i = model.objects.size() - 1; i >= 0; i--) {
173             MapObject o = (MapObject) model.objects.get(i);
174             computeBounds(min, max, view, o.getBounds(), mapSize);
175 
176             for (int xoff = min.x; xoff <= max.x; xoff++) {
177                 for (int yoff = min.y; yoff <= max.y; yoff++) {
178 
179                     AffineTransform tx = new AffineTransform(rootTx);
180                     tx.translate(xoff * mapSize.width, yoff * mapSize.height);
181                     g.setTransform(tx);
182                     o.paint(g, scale);
183                 }
184             }
185         }
186         g.setTransform(rootTx);
187     }
188 
drawShape(Graphics2D g, Shape s)189     public void drawShape(Graphics2D g, Shape s) {
190         if (g.getClipBounds() == null)
191             g.setClip(getBounds());
192         AffineTransform origTx = g.getTransform();
193         AffineTransform rootTx = new AffineTransform(origTx);
194         rootTx.concatenate(getTransform());
195         g.setTransform(rootTx);
196         drawShapeNoTx(g, s);
197         g.setTransform(origTx);
198     }
199 
drawShapeNoTx(Graphics2D g, Shape s)200     private void drawShapeNoTx(Graphics2D g, Shape s) {
201 
202         Rectangle view = g.getClipBounds();
203         AffineTransform origTx = g.getTransform();
204         Point min = new Point();
205         Point max = new Point();
206         Dimension mapSize = model.options.getSize();
207 
208         computeBounds(min, max, view, s.getBounds(), mapSize);
209 
210         AffineTransform tx = new AffineTransform();
211         for (int xoff = min.x; xoff <= max.x; xoff++) {
212             for (int yoff = min.y; yoff <= max.y; yoff++) {
213                 tx.setTransform(origTx);
214                 tx.translate(xoff * mapSize.width, yoff * mapSize.height);
215                 g.setTransform(tx);
216                 g.draw(s);
217             }
218         }
219 
220         g.setTransform(origTx);
221     }
222 
computeBounds( Point min, Point max, Rectangle view, Rectangle b, Dimension map)223     private void computeBounds(
224         Point min,
225         Point max,
226         Rectangle view,
227         Rectangle b,
228         Dimension map) {
229         if (model.options.isEdgeWrap()) {
230             min.x = (view.x - (b.x + b.width)) / map.width;
231             if (view.x > b.x + b.width)
232                 min.x++;
233             max.x = (view.x + view.width - b.x) / map.width;
234             if (view.x + view.width < b.x)
235                 max.x--;
236             min.y = (view.y - (b.y + b.height)) / map.height;
237             if (view.y > b.y + b.height)
238                 min.y++;
239             max.y = (view.y + view.height - b.y) / map.height;
240             if (view.y + view.height < b.y)
241                 max.y--;
242         } else {
243             min.x = min.y = max.x = min.y = 0;
244         }
245     }
246 
computeWraps(Rectangle r, Point p)247     public Point[] computeWraps(Rectangle r, Point p) {
248         Dimension mapSize = model.options.getSize();
249         Point min = new Point();
250         Point max = new Point();
251         Rectangle b = new Rectangle(p.x, p.y, 0, 0);
252 
253         computeBounds(min, max, r, b, mapSize);
254         Point[] wraps = new Point[(max.x - min.x + 1) * (max.y - min.y + 1)];
255         int i = 0;
256         for (int xoff = min.x; xoff <= max.x; xoff++) {
257             for (int yoff = min.y; yoff <= max.y; yoff++) {
258                 wraps[i++] =
259                     new Point(
260                         xoff * mapSize.width + p.x,
261                         yoff * mapSize.height + p.y);
262             }
263         }
264         return wraps;
265     }
266 
containsWrapped(Rectangle r, Point p)267     public boolean containsWrapped(Rectangle r, Point p) {
268         return computeWraps(r, p).length > 0;
269     }
270 
containsWrapped(MapObject o, Point p)271     public boolean containsWrapped(MapObject o, Point p) {
272         Point[] wraps = computeWraps(o.getBounds(), p);
273         for (int i = 0; i < wraps.length; i++)
274             if (o.contains(wraps[i]))
275                 return true;
276         return false;
277     }
278 
getTransform()279     public AffineTransform getTransform() {
280         if (at == null) {
281             at = new AffineTransform();
282             at.translate(
283                 -scale * model.options.getSize().width / 2
284                     + getSize().width / 2
285                     - offset.x,
286                 scale * model.options.getSize().height / 2
287                     + getSize().height / 2
288                     - offset.y);
289             at.scale(scale, -scale);
290         }
291         return at;
292     }
293 
getInverse()294     public AffineTransform getInverse() {
295         try {
296             if (it == null)
297                 it = getTransform().createInverse();
298             return it;
299         } catch (Exception e) {
300             e.printStackTrace();
301             return null;
302         }
303     }
304 
305 
beginEdit()306     public void beginEdit() {
307         currentEdit = new CompoundMapEdit();
308     }
309 
commitEdit()310     public void commitEdit() {
311         currentEdit.edit();
312         getUndoManager().addEdit(currentEdit);
313         repaint();
314         currentEdit = null;
315     }
316 
cancelEdit()317     public void cancelEdit() {
318         currentEdit = null;
319     }
320 
doEdit(MapEdit e)321     private void doEdit(MapEdit e) {
322         if (currentEdit != null) {
323             currentEdit.addEdit(e);
324         } else {
325             e.edit();
326             getUndoManager().addEdit(e);
327             repaint();
328         }
329     }
330 
331     private interface MapEdit extends UndoableEdit {
edit()332         public void edit();
unedit()333         public void unedit();
334     }
335 
336     private abstract class AbstractMapEdit
337     extends AbstractUndoableEdit implements MapEdit {
redo()338         public void redo() {
339             super.redo();
340             edit();
341         }
undo()342         public void undo() {
343             super.undo();
344             unedit();
345         }
346     }
347 
348     private class CompoundMapEdit
349     extends CompoundEdit implements MapEdit {
edit()350         public void edit() {
351             for (Iterator i = edits.iterator(); i.hasNext();)
352                 ((MapEdit)i.next()).edit();
353         }
unedit()354         public void unedit() {}
355     }
356 
setPolygonEdgeStyle( final MapPolygon p, final int edgeIndex, final LineStyle newStyle)357     public void setPolygonEdgeStyle(
358         final MapPolygon p,
359         final int edgeIndex,
360         final LineStyle newStyle) {
361         final LineStyle oldStyle = p.getEdgeStyle(edgeIndex);
362         doEdit(new AbstractMapEdit() {
363             public void unedit() {
364                 p.setEdgeStyle(edgeIndex, oldStyle);
365             }
366             public void edit() {
367                 p.setEdgeStyle(edgeIndex, newStyle);
368             }
369         });
370     }
371 
removePolygonPoint(final MapPolygon p, final int i)372     public void removePolygonPoint(final MapPolygon p, final int i) {
373         final Point point = p.getPoint(i);
374         doEdit(new AbstractMapEdit() {
375             public void unedit() {
376                 p.insertPoint(i, point);
377             }
378             public void edit() {
379                 p.removePoint(i);
380             }
381         });
382     }
383 
insertPolygonPoint( final MapPolygon p, final int i, final Point point)384     public void insertPolygonPoint(
385         final MapPolygon p,
386         final int i,
387         final Point point) {
388         doEdit(new AbstractMapEdit() {
389             public void unedit() {
390                 p.removePoint(i);
391             }
392             public void edit() {
393                 p.insertPoint(i, point);
394             }
395         });
396     }
397 
movePolygonPoint( final MapPolygon p, final int i, final int newX, final int newY)398     public void movePolygonPoint(
399         final MapPolygon p,
400         final int i,
401         final int newX,
402         final int newY) {
403         final Point oldPoint = p.getPoint(i);
404         doEdit(new AbstractMapEdit() {
405             public void unedit() {
406                 p.setPoint(i, oldPoint.x, oldPoint.y);
407             }
408             public void edit() {
409                 p.setPoint(i, newX, newY);
410             }
411         });
412     }
413 
setPolygonStyles( final MapPolygon p, final Map newStyles)414     public void setPolygonStyles(
415         final MapPolygon p,
416         final Map newStyles) {
417         doEdit(new AbstractMapEdit() {
418             Map oldStyles = p.getStyles();
419             Map oldDefaultStyles = model.getDefaultPolygonStyles();
420             public void unedit() {
421                 p.setStyles(oldStyles);
422                 model.setDefaultPolygonStyles(oldDefaultStyles);
423             }
424             public void edit() {
425                 p.setStyles(newStyles);
426                 model.setDefaultPolygonStyles(newStyles);
427             }
428         });
429     }
430 
rotatePolygon( final MapPolygon p, final double angle)431     public void rotatePolygon(
432         final MapPolygon p,
433         final double angle) {
434         final MapPolygon rotated = (MapPolygon)p.copy();
435         rotated.rotate(angle);
436         doEdit(new AbstractMapEdit() {
437             public void unedit() {
438                 getModel().replace(rotated, p);
439             }
440             public void edit() {
441                 getModel().replace(p, rotated);
442             }
443         });
444     }
445 
setObjectTeam(final MapObject o, final int newTeam)446     public void setObjectTeam(final MapObject o, final int newTeam) {
447         final int oldTeam = o.getTeam();
448         doEdit(new AbstractMapEdit() {
449             public void unedit() {
450                 o.setTeam(oldTeam);
451             }
452             public void edit() {
453                 o.setTeam(newTeam);
454             }
455         });
456     }
457 
setBaseProperties( final Base b, final int newTeam, final int newDir, final int newOrder)458     public void setBaseProperties(
459         final Base b,
460         final int newTeam,
461         final int newDir,
462         final int newOrder) {
463         final int oldTeam = b.getTeam();
464         final int oldDir = b.getDir();
465         final int oldOrder = b.getOrder();
466         doEdit(new AbstractMapEdit() {
467             public void unedit() {
468                 b.setTeam(oldTeam);
469                 b.setDir(oldDir);
470                 b.setOrder(oldOrder);
471             }
472             public void edit() {
473                 b.setTeam(newTeam);
474                 b.setDir(newDir);
475                 b.setOrder(newOrder);
476             }
477         });
478     }
479 
setBallProperties( final Ball b, final int newTeam, final PolygonStyle newStyle)480     public void setBallProperties(
481         final Ball b,
482         final int newTeam,
483         final PolygonStyle newStyle) {
484         final int oldTeam = b.getTeam();
485         final PolygonStyle oldStyle = b.getStyle();
486         doEdit(new AbstractMapEdit() {
487             public void unedit() {
488                 b.setTeam(oldTeam);
489                 b.setStyle(oldStyle);
490             }
491             public void edit() {
492                 b.setTeam(newTeam);
493                 b.setStyle(newStyle);
494             }
495         });
496     }
497 
setGravProperties( final Grav grav, final int newType, final BigDecimal newForce)498     public void setGravProperties(
499         final Grav grav,
500         final int newType,
501         final BigDecimal newForce) {
502         final int oldType = grav.getType();
503         final BigDecimal oldForce = grav.getForce();
504         doEdit(new AbstractMapEdit() {
505             public void unedit() {
506                 grav.setType(oldType);
507                 grav.setForce(oldForce);
508             }
509             public void edit() {
510                 grav.setType(newType);
511                 grav.setForce(newForce);
512             }
513         });
514     }
515 
setWormholeType(final Wormhole o, final int newType)516     public void setWormholeType(final Wormhole o, final int newType) {
517         final int oldType = o.getType();
518         doEdit(new AbstractMapEdit() {
519             public void unedit() {
520                 o.setType(oldType);
521             }
522             public void edit() {
523                 o.setType(newType);
524             }
525         });
526     }
527 
setWormholePoint(final Wormhole o, final int x, final int y)528     public void setWormholePoint(final Wormhole o, final int x, final int y) {
529         doEdit(new AbstractMapEdit() {
530             private Point oldPoint = o.getPoint();
531             public void unedit() {
532                 o.setPoint(oldPoint);
533             }
534             public void edit() {
535                 o.setPoint(new Point(x, y));
536             }
537         });
538     }
539 
setCannonDir(final Cannon c, final int newDir)540     public void setCannonDir(final Cannon c, final int newDir) {
541         final int oldDir = c.getDir();
542         doEdit(new AbstractMapEdit() {
543             public void unedit() {
544                 c.setDir(oldDir);
545             }
546             public void edit() {
547                 c.setDir(newDir);
548             }
549         });
550     }
551 
setCannonPoint(final Cannon c, final int x, final int y)552     public void setCannonPoint(final Cannon c, final int x, final int y) {
553         final Point oldPoint = c.getPoint();
554         doEdit(new AbstractMapEdit() {
555             public void unedit() {
556                 c.setPoint(oldPoint);
557             }
558             public void edit() {
559                 c.setPoint(new Point(x, y));
560             }
561         });
562     }
563 
removeMapObject(final MapObject o)564     public void removeMapObject(final MapObject o) {
565         final int i = getModel().indexOf(o);
566         if (i == -1)
567             return;
568         doEdit(new AbstractMapEdit() {
569             public void unedit() {
570                 getModel().addObject(i, o);
571             }
572             public void edit() {
573                 getModel().removeObject(i);
574             }
575         });
576     }
577 
addMapObject(final MapObject o)578     public void addMapObject(final MapObject o) {
579         doEdit(new AbstractMapEdit() {
580             public void unedit() {
581                 getModel().removeObject(o);
582             }
583             public void edit() {
584                 getModel().addToFront(o);
585             }
586         });
587     }
588 
bringMapObject(final MapObject o, final boolean front)589     public void bringMapObject(final MapObject o, final boolean front) {
590         final int i = getModel().indexOf(o);
591         doEdit(new AbstractMapEdit() {
592             public void unedit() {
593                 getModel().removeObject(o);
594                 getModel().addObject(i, o);
595             }
596             public void edit() {
597                 getModel().removeObject(o);
598                 getModel().addObject(o, front);
599             }
600         });
601     }
602 
makeBallAreaFromSelected()603     public void makeBallAreaFromSelected() {
604         if (selected.isEmpty()) return;
605         makeGroup(new BallArea(selected));
606     }
607 
makeBallTargetFromSelected()608     public void makeBallTargetFromSelected() {
609         if (selected.isEmpty()) return;
610         makeGroup(new BallTarget(selected));
611     }
612 
makeCannonFromSelected()613     public void makeCannonFromSelected() {
614         if (selected.isEmpty()) return;
615         makeGroup(new Cannon(selected));
616     }
617 
makeDecorationFromSelected()618     public void makeDecorationFromSelected() {
619         if (selected.isEmpty()) return;
620         makeGroup(new Decoration(selected));
621     }
622 
makeFrictionAreaFromSelected()623     public void makeFrictionAreaFromSelected() {
624         if (selected.isEmpty()) return;
625         makeGroup(new FrictionArea(selected));
626     }
627 
makeGroupFromSelected()628     public void makeGroupFromSelected() {
629         if (selected.isEmpty()) return;
630         makeGroup(new Group(selected));
631     }
632 
makeTargetFromSelected()633     public void makeTargetFromSelected() {
634         if (selected.isEmpty()) return;
635         makeGroup(new Target(selected));
636     }
637 
makeWormholeFromSelected()638     public void makeWormholeFromSelected() {
639         if (selected.isEmpty()) return;
640         makeGroup(new Wormhole(selected));
641     }
642 
makeGroup(final Group g)643     private void makeGroup(final Group g) {
644         doEdit(new AbstractMapEdit() {
645             public void unedit() {
646                 for (Iterator i = g.getMembers().iterator(); i.hasNext();) {
647                     MapObject o = (MapObject)i.next();
648                     o.setParent(null);
649                     getModel().addToFront(o);
650                 }
651             }
652             public void edit() {
653                 for (Iterator i = selected.iterator(); i.hasNext();) {
654                     MapObject o = (MapObject)i.next();
655                     o.setParent(g);
656                     getModel().removeObject(o);
657                 }
658                 getModel().addToFront(g);
659                 setSelectedObject(g);
660             }
661         });
662     }
663 
ungroupSelected()664     public void ungroupSelected() {
665         if (selected.isEmpty()
666             || !(selected.get(0) instanceof Group))
667             return;
668         doEdit(new AbstractMapEdit() {
669             Group g = (Group)selected.get(0);
670             public void unedit() {
671                 getModel().addToFront(g);
672                 for (Iterator i = g.getMembers().iterator(); i.hasNext();)
673                     getModel().removeObject((MapObject)i.next());
674             }
675             public void edit() {
676                 getModel().removeObject(g);
677                 setSelectedObject(null);
678                 for (Iterator i = g.getMembers().iterator(); i.hasNext();) {
679                     MapObject o = (MapObject)i.next();
680                     getModel().addToFront(o);
681                     addSelectedObject(o);
682                 }
683             }
684         });
685     }
686 
regroupSelected()687     public void regroupSelected() {
688         if (selected.isEmpty()
689             || ((MapObject)selected.get(0)).getParent() == null)
690             return;
691         doEdit(new AbstractMapEdit() {
692             Group g = ((MapObject)selected.get(0)).getParent();
693             public void unedit() {
694                 getModel().removeObject(g);
695                 for (Iterator i = g.getMembers().iterator(); i.hasNext();)
696                     getModel().addToFront((MapObject)i.next());
697             }
698             public void edit() {
699                 getModel().addToFront(g);
700                 for (Iterator i = g.getMembers().iterator(); i.hasNext();)
701                     getModel().removeObject((MapObject)i.next());
702                 setSelectedObject(g);
703             }
704         });
705     }
706 
moveMapObject( final MapObject o, final int newX, final int newY)707     public void moveMapObject(
708         final MapObject o,
709         final int newX,
710         final int newY) {
711         final int oldX = o.getBounds().x;
712         final int oldY = o.getBounds().y;
713         doEdit(new AbstractMapEdit() {
714             public void unedit() {
715                 o.moveTo(oldX, oldY);
716             }
717             public void edit() {
718                 o.moveTo(newX, newY);
719             }
720         });
721     }
722 
addEdgeStyle(final LineStyle style)723     public void addEdgeStyle(final LineStyle style) {
724         doEdit(new AbstractMapEdit() {
725             public void unedit() {
726                 getModel().edgeStyles.remove(style);
727             }
728             public void edit() {
729                 getModel().edgeStyles.add(style);
730             }
731         });
732     }
733 
removeEdgeStyle(final LineStyle style)734     public void removeEdgeStyle(final LineStyle style) {
735         final java.util.List oldStyles = getModel().edgeStyles;
736         doEdit(new AbstractMapEdit() {
737             public void unedit() {
738                 getModel().edgeStyles = oldStyles;
739             }
740             public void edit() {
741                 getModel().edgeStyles.remove(style);
742             }
743         });
744     }
745 
addPolygonStyle(final PolygonStyle style)746     public void addPolygonStyle(final PolygonStyle style) {
747         doEdit(new AbstractMapEdit() {
748             public void unedit() {
749                 getModel().polyStyles.remove(style);
750             }
751             public void edit() {
752                 getModel().polyStyles.add(style);
753             }
754         });
755     }
756 
removePolygonStyle(final PolygonStyle style)757     public void removePolygonStyle(final PolygonStyle style) {
758         final java.util.List oldStyles = new ArrayList(getModel().polyStyles);
759         doEdit(new AbstractMapEdit() {
760             public void unedit() {
761                 getModel().polyStyles = oldStyles;
762             }
763             public void edit() {
764                 getModel().polyStyles.remove(style);
765             }
766         });
767     }
768 
setEdgeStyleProperties( final LineStyle style, final String newId, final int newStyle, final int newWidth, final Color newColor)769     public void setEdgeStyleProperties(
770         final LineStyle style,
771         final String newId,
772         final int newStyle,
773         final int newWidth,
774         final Color newColor) {
775         final String oldId = style.getId();
776         final int oldStyle = style.getStyle();
777         final int oldWidth = style.getWidth();
778         final Color oldColor = style.getColor();
779         doEdit(new AbstractMapEdit() {
780             public void unedit() {
781                 set(oldId, oldStyle, oldWidth, oldColor);
782             }
783             public void edit() {
784                 set(newId, newStyle, newWidth, newColor);
785             }
786             private void set(String id, int s, int w, Color c) {
787                 style.setId(id);
788                 style.setStyle(s);
789                 style.setWidth(w);
790                 style.setColor(c);
791             }
792         });
793     }
794 
setPolygonStyleProperties( final PolygonStyle style, final String newId, final int newFillStyle, final Color newColor, final Pixmap newTexture, final LineStyle newDefEdgeStyle, final boolean newVisible, final boolean newVisInRadar)795     public void setPolygonStyleProperties(
796         final PolygonStyle style,
797         final String newId,
798         final int newFillStyle,
799         final Color newColor,
800         final Pixmap newTexture,
801         final LineStyle newDefEdgeStyle,
802         final boolean newVisible,
803         final boolean newVisInRadar) {
804         final String oldId = style.getId();
805         final int oldFillStyle = style.getFillStyle();
806         final Color oldColor = style.getColor();
807         final Pixmap oldTexture = style.getTexture();
808         final LineStyle oldDefEdgeStyle = style.getDefaultEdgeStyle();
809         final boolean oldVisible = style.isVisible();
810         final boolean oldVisInRadar = style.isVisibleInRadar();
811         doEdit(new AbstractMapEdit() {
812             public void unedit() {
813                 set(
814                     oldId,
815                     oldFillStyle,
816                     oldColor,
817                     oldTexture,
818                     oldDefEdgeStyle,
819                     oldVisible,
820                     oldVisInRadar);
821             }
822             public void edit() {
823                 set(
824                     newId,
825                     newFillStyle,
826                     newColor,
827                     newTexture,
828                     newDefEdgeStyle,
829                     newVisible,
830                     newVisInRadar);
831             }
832             private void set(
833                 String id,
834                 int fs,
835                 Color c,
836                 Pixmap t,
837                 LineStyle es,
838                 boolean v,
839                 boolean vr) {
840                 style.setId(id);
841                 style.setFillStyle(fs);
842                 style.setColor(c);
843                 style.setTexture(t);
844                 style.setDefaultEdgeStyle(es);
845                 model.setDefaultEdgeStyle(es);
846                 style.setVisible(v);
847                 style.setVisibleInRadar(vr);
848             }
849         });
850     }
851 
852     private class AwtEventHandler implements CanvasEventHandler {
853 
mouseClicked(MouseEvent evt)854         public void mouseClicked(MouseEvent evt) {
855             if (model == null)
856                 return;
857             transformEvent(evt, true);
858             if (eventHandler != null) {
859                 eventHandler.mouseClicked(evt);
860                 return;
861             }
862             for (Iterator iter = model.objects.iterator(); iter.hasNext();) {
863                 MapObject o = (MapObject) iter.next();
864                 if (o.checkAwtEvent(MapCanvas.this, evt)) {
865                     return;
866                 }
867             }
868         }
869 
mouseEntered(MouseEvent evt)870         public void mouseEntered(MouseEvent evt) {
871             if (model == null)
872                 return;
873             if (eventHandler != null) {
874                 transformEvent(evt, true);
875                 eventHandler.mouseEntered(evt);
876                 return;
877             }
878         }
879 
mouseExited(MouseEvent evt)880         public void mouseExited(MouseEvent evt) {
881             if (model == null)
882                 return;
883             if (eventHandler != null) {
884                 transformEvent(evt, true);
885                 eventHandler.mouseExited(evt);
886                 return;
887             }
888         }
889 
mousePressed(MouseEvent evt)890         public void mousePressed(MouseEvent evt) {
891             if (model == null)
892                 return;
893             transformEvent(evt, true);
894             if (eventHandler != null) {
895                 eventHandler.mousePressed(evt);
896                 return;
897             }
898             for (Iterator iter = model.objects.iterator(); iter.hasNext();) {
899                 MapObject o = (MapObject) iter.next();
900                 if (o.checkAwtEvent(MapCanvas.this, evt)) {
901                     return;
902                 }
903             }
904             if ((evt.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
905                 if (evt.isControlDown()) {
906                     setSelectedObject(null);
907                     setCanvasEventHandler(selectHandler);
908                     selectHandler.mousePressed(evt);
909                 } else {
910                     dragHandler.mousePressed(evt);
911                     setCanvasEventHandler(dragHandler);
912                     setSelectedObject(null);
913                 }
914             }
915         }
916 
mouseReleased(MouseEvent evt)917         public void mouseReleased(MouseEvent evt) {
918             if (model == null)
919                 return;
920             transformEvent(evt, true);
921             if (eventHandler != null) {
922                 eventHandler.mouseReleased(evt);
923                 return;
924             }
925             for (Iterator iter = model.objects.iterator(); iter.hasNext();) {
926                 MapObject o = (MapObject) iter.next();
927                 if (o.checkAwtEvent(MapCanvas.this, evt)) {
928                     return;
929                 }
930             }
931         }
932 
mouseDragged(MouseEvent evt)933         public void mouseDragged(MouseEvent evt) {
934             if (model == null)
935                 return;
936             transformEvent(evt, true);
937             if (eventHandler != null) {
938                 eventHandler.mouseDragged(evt);
939                 return;
940             }
941         }
942 
mouseMoved(MouseEvent evt)943         public void mouseMoved(MouseEvent evt) {
944             if (model == null)
945                 return;
946             if (eventHandler != null) {
947                 transformEvent(evt, true);
948                 eventHandler.mouseMoved(evt);
949                 return;
950             }
951         }
952 
transformEvent(MouseEvent evt, boolean snap)953         private void transformEvent(MouseEvent evt, boolean snap) {
954             int x = evt.getX();
955             int y = evt.getY();
956             int g = grid * 64;
957             Point mapp = new Point(x, y);
958             getInverse().transform(mapp, mapp);
959             if (snap && g > 0) {
960                 mapp.x = (mapp.x / g) * g;
961                 mapp.y = (mapp.y / g) * g;
962             }
963             evt.translatePoint(mapp.x - evt.getX(), mapp.y - evt.getY());
964         }
965     }
966 
967     private class DragHandler extends CanvasEventAdapter {
968 
969         private Point dragStart;
970         private Point offsetStart;
971         private boolean wasFastRendering;
972 
mousePressed(MouseEvent evt)973         public void mousePressed(MouseEvent evt) {
974             toScreen(evt);
975             dragStart = evt.getPoint();
976             offsetStart = new Point(offset);
977             wasFastRendering = isFastRendering();
978             setFastRendering(true);
979         }
980 
mouseDragged(MouseEvent evt)981         public void mouseDragged(MouseEvent evt) {
982             toScreen(evt);
983             at = null;
984             it = null;
985             offset.x = offsetStart.x + (dragStart.x - evt.getX());
986             offset.y = offsetStart.y + (dragStart.y - evt.getY());
987             repaint();
988         }
989 
mouseReleased(MouseEvent evt)990         public void mouseReleased(MouseEvent evt) {
991             setFastRendering(wasFastRendering);
992             setCanvasEventHandler(null);
993             repaint();
994         }
995 
toScreen(MouseEvent evt)996         private void toScreen(MouseEvent evt) {
997             Point mapp = new Point();
998             Point evtp = evt.getPoint();
999             getTransform().transform(evtp, mapp);
1000             evt.translatePoint(mapp.x - evtp.x, mapp.y - evtp.y);
1001         }
1002     }
1003 
1004     private class SelectHandler extends CanvasEventAdapter {
1005 
1006         private Point selectStart;
1007         private Rectangle selectShape = new Rectangle();
1008 
mousePressed(MouseEvent evt)1009         public void mousePressed(MouseEvent evt) {
1010             if ((evt.getModifiers()
1011             & InputEvent.BUTTON1_MASK) != 0) {
1012                 selectStart = evt.getPoint();
1013                 paintSelectArea(evt, false, true);
1014             }
1015         }
1016 
mouseDragged(MouseEvent evt)1017         public void mouseDragged(MouseEvent evt) {
1018             if ((evt.getModifiers()
1019             & InputEvent.BUTTON1_MASK) != 0)
1020                 paintSelectArea(evt, true, true);
1021         }
1022 
mouseReleased(MouseEvent evt)1023         public void mouseReleased(MouseEvent evt) {
1024             if ((evt.getModifiers()
1025             & InputEvent.BUTTON1_MASK) != 0) {
1026                 paintSelectArea(evt, true, false);
1027                 setCanvasEventHandler(null);
1028                 repaint();
1029             }
1030         }
1031 
paintSelectArea( MouseEvent evt, boolean erase, boolean paint)1032         private void paintSelectArea(
1033         MouseEvent evt, boolean erase, boolean paint) {
1034             Graphics2D g = (Graphics2D)getGraphics();
1035             g.setXORMode(Color.black);
1036             g.setColor(Color.white);
1037             if (erase) drawShape(g, selectShape);
1038             selectShape.setBounds(
1039                 Math.min(selectStart.x, evt.getX()),
1040                 Math.min(selectStart.y, evt.getY()),
1041                 Math.abs(selectStart.x - evt.getX()),
1042                 Math.abs(selectStart.y - evt.getY()));
1043             if (paint) drawShape(g, selectShape);
1044         }
1045     }
1046 }
1047