source: josm/src/org/openstreetmap/josm/gui/MapView.java@ 98

Last change on this file since 98 was 98, checked in by imi, 18 years ago
  • added Applet version of JOSM (unfinished)
  • fixed display bug if --no-fullscreen and --geometry was specified
File size: 8.9 KB
Line 
1package org.openstreetmap.josm.gui;
2
3import java.awt.Color;
4import java.awt.Graphics;
5import java.awt.Point;
6import java.awt.event.ComponentAdapter;
7import java.awt.event.ComponentEvent;
8import java.util.ArrayList;
9import java.util.Collection;
10import java.util.Collections;
11import java.util.LinkedList;
12
13import javax.swing.JOptionPane;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.actions.AutoScaleAction;
17import org.openstreetmap.josm.data.Bounds;
18import org.openstreetmap.josm.data.SelectionChangedListener;
19import org.openstreetmap.josm.data.coor.EastNorth;
20import org.openstreetmap.josm.data.coor.LatLon;
21import org.openstreetmap.josm.data.osm.OsmPrimitive;
22import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
23import org.openstreetmap.josm.data.projection.Projection;
24import org.openstreetmap.josm.gui.layer.Layer;
25import org.openstreetmap.josm.gui.layer.OsmDataLayer;
26import org.openstreetmap.josm.gui.layer.WmsServerLayer;
27import org.openstreetmap.josm.gui.layer.OsmDataLayer.ModifiedChangedListener;
28
29/**
30 * This is a component used in the MapFrame for browsing the map. It use is to
31 * provide the MapMode's enough capabilities to operate.
32 *
33 * MapView hold meta-data about the data set currently displayed, as scale level,
34 * center point viewed, what scrolling mode or editing mode is selected or with
35 * what projection the map is viewed etc..
36 *
37 * MapView is able to administrate several layers, but there must be always at
38 * least one layer with a dataset in it (Layer.getDataSet returning non-null).
39 *
40 * @author imi
41 */
42public class MapView extends NavigatableComponent {
43
44 /**
45 * Interface to notify listeners of the change of the active layer.
46 * @author imi
47 */
48 public interface LayerChangeListener {
49 void activeLayerChange(Layer oldLayer, Layer newLayer);
50 void layerAdded(Layer newLayer);
51 void layerRemoved(Layer oldLayer);
52 }
53
54 /**
55 * Whether to adjust the scale property on every resize.
56 */
57 private boolean autoScale = true;
58
59 /**
60 * A list of all layers currently loaded.
61 */
62 private ArrayList<Layer> layers = new ArrayList<Layer>();
63 /**
64 * Direct link to the edit layer (if any) in the layers list.
65 */
66 public OsmDataLayer editLayer;
67 /**
68 * The layer from the layers list that is currently active.
69 */
70 private Layer activeLayer;
71 /**
72 * The listener of the active layer changes.
73 */
74 private Collection<LayerChangeListener> listeners = new LinkedList<LayerChangeListener>();
75
76 private final AutoScaleAction autoScaleAction;
77
78 public MapView(AutoScaleAction autoScaleAction) {
79 this.autoScaleAction = autoScaleAction;
80 addComponentListener(new ComponentAdapter(){
81 @Override public void componentResized(ComponentEvent e) {
82 recalculateCenterScale();
83 }
84 });
85 new MapMover(this);
86
87 // listend to selection changes to redraw the map
88 Main.ds.addSelectionChangedListener(new SelectionChangedListener(){
89 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
90 repaint();
91 }
92 });
93 }
94
95 /**
96 * Add a layer to the current MapView. The layer will be added at topmost
97 * position.
98 */
99 public void addLayer(Layer layer) {
100 if (layer instanceof OsmDataLayer) {
101 final OsmDataLayer dataLayer = (OsmDataLayer)layer;
102 if (editLayer != null) {
103 editLayer.mergeFrom(layer);
104 repaint();
105 return;
106 }
107 editLayer = dataLayer;
108 dataLayer.data.addAllSelectionListener(Main.ds);
109 Main.ds = dataLayer.data;
110 dataLayer.listenerModified.add(new ModifiedChangedListener(){
111 public void modifiedChanged(boolean value, OsmDataLayer source) {
112 JOptionPane.getFrameForComponent(Main.parent).setTitle((value?"*":"")+"Java Open Street Map - Editor");
113 }
114 });
115 }
116
117 // add as a new layer
118 if (layer instanceof WmsServerLayer)
119 layers.add(layers.size(), layer);
120 else
121 layers.add(0, layer);
122
123 for (LayerChangeListener l : listeners)
124 l.layerAdded(layer);
125
126 // autoselect the new layer
127 setActiveLayer(layer);
128 }
129
130 /**
131 * Remove the layer from the mapview. If the layer was in the list before,
132 * an LayerChange event is fired.
133 */
134 public void removeLayer(Layer layer) {
135 if (layers.remove(layer))
136 for (LayerChangeListener l : listeners)
137 l.layerRemoved(layer);
138 if (layer == editLayer)
139 editLayer = null;
140 }
141
142 /**
143 * Moves the layer to the given new position. No event is fired.
144 * @param layer The layer to move
145 * @param pos The new position of the layer
146 */
147 public void moveLayer(Layer layer, int pos) {
148 int curLayerPos = layers.indexOf(layer);
149 if (curLayerPos == -1)
150 throw new IllegalArgumentException("layer not in list.");
151 if (pos == curLayerPos)
152 return; // already in place.
153 layers.remove(curLayerPos);
154 if (pos >= layers.size())
155 layers.add(layer);
156 else
157 layers.add(pos, layer);
158 }
159
160 /**
161 * Draw the component.
162 */
163 @Override public void paint(Graphics g) {
164 g.setColor(Color.BLACK);
165 g.fillRect(0, 0, getWidth(), getHeight());
166
167 for (int i = layers.size()-1; i >= 0; --i) {
168 Layer l = layers.get(i);
169 if (l.visible)
170 l.paint(g, this);
171 }
172
173 // draw world borders
174 g.setColor(Color.WHITE);
175 Bounds b = new Bounds();
176 Point min = getPoint(getProjection().latlon2eastNorth(b.min));
177 Point max = getPoint(getProjection().latlon2eastNorth(b.max));
178 int x1 = Math.min(min.x, max.x);
179 int y1 = Math.min(min.y, max.y);
180 int x2 = Math.max(min.x, max.x);
181 int y2 = Math.max(min.y, max.y);
182 if (x1 > 0 || y1 > 0 || x2 < getWidth() || y2 < getHeight())
183 g.drawRect(x1, y1, x2-x1+1, y2-y1+1);
184 }
185
186 /**
187 * @return Returns the autoScale.
188 */
189 public boolean isAutoScale() {
190 return autoScale;
191 }
192
193 /**
194 * @param autoScale The autoScale to set.
195 */
196 public void setAutoScale(boolean autoScale) {
197 if (this.autoScale != autoScale) {
198 this.autoScale = autoScale;
199 firePropertyChange("autoScale", !autoScale, autoScale);
200 recalculateCenterScale();
201 }
202 }
203 /**
204 * Set the new dimension to the projection class. Also adjust the components
205 * scale, if in autoScale mode.
206 */
207 public void recalculateCenterScale() {
208 if (autoScale) {
209 // -20 to leave some border
210 int w = getWidth()-20;
211 if (w < 20)
212 w = 20;
213 int h = getHeight()-20;
214 if (h < 20)
215 h = 20;
216
217 BoundingXYVisitor v = autoScaleAction.getBoundingBox();
218
219 boolean oldAutoScale = autoScale;
220 EastNorth oldCenter = center;
221 double oldScale = this.scale;
222
223 if (v.min == null || v.max == null || v.min.equals(v.max)) {
224 // no bounds means whole world
225 center = getProjection().latlon2eastNorth(new LatLon(0,0));
226 EastNorth world = getProjection().latlon2eastNorth(new LatLon(Projection.MAX_LAT,Projection.MAX_LON));
227 double scaleX = world.east()*2/w;
228 double scaleY = world.north()*2/h;
229 scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
230 } else {
231 center = new EastNorth(v.min.east()/2+v.max.east()/2, v.min.north()/2+v.max.north()/2);
232 double scaleX = (v.max.east()-v.min.east())/w;
233 double scaleY = (v.max.north()-v.min.north())/h;
234 scale = Math.max(scaleX, scaleY); // minimum scale to see all of the screen
235 }
236
237 if (!center.equals(oldCenter))
238 firePropertyChange("center", oldCenter, center);
239 if (oldAutoScale != autoScale)
240 firePropertyChange("autoScale", oldAutoScale, autoScale);
241 if (oldScale != scale)
242 firePropertyChange("scale", oldScale, scale);
243 }
244 repaint();
245 }
246
247 /**
248 * Add a listener for changes of active layer.
249 * @param listener The listener that get added.
250 */
251 public void addLayerChangeListener(LayerChangeListener listener) {
252 if (listener != null)
253 listeners.add(listener);
254 }
255
256 /**
257 * Remove the listener.
258 * @param listener The listener that get removed from the list.
259 */
260 public void removeLayerChangeListener(LayerChangeListener listener) {
261 listeners.remove(listener);
262 }
263
264 /**
265 * @return An unmodificable list of all layers
266 */
267 public Collection<Layer> getAllLayers() {
268 return Collections.unmodifiableCollection(layers);
269 }
270
271 /**
272 * Set the active selection to the given value and raise an layerchange event.
273 */
274 public void setActiveLayer(Layer layer) {
275 if (!layers.contains(layer))
276 throw new IllegalArgumentException("layer must be in layerlist");
277 Layer old = activeLayer;
278 activeLayer = layer;
279 if (old != layer) {
280 for (LayerChangeListener l : listeners)
281 l.activeLayerChange(old, layer);
282 recalculateCenterScale();
283 }
284 }
285
286 /**
287 * @return The current active layer
288 */
289 public Layer getActiveLayer() {
290 return activeLayer;
291 }
292
293 /**
294 * In addition to the base class funcitonality, this keep trak of the autoscale
295 * feature.
296 */
297 @Override public void zoomTo(EastNorth newCenter, double scale) {
298 boolean oldAutoScale = autoScale;
299 EastNorth oldCenter = center;
300 double oldScale = this.scale;
301 autoScale = false;
302
303 super.zoomTo(newCenter, scale);
304
305 recalculateCenterScale();
306
307 if (!oldCenter.equals(center))
308 firePropertyChange("center", oldCenter, center);
309 if (oldAutoScale != autoScale)
310 firePropertyChange("autoScale", oldAutoScale, autoScale);
311 if (oldScale != scale)
312 firePropertyChange("scale", oldScale, scale);
313 }
314}
Note: See TracBrowser for help on using the repository browser.