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

Last change on this file since 77 was 77, checked in by imi, 18 years ago

added customizable colores for raw gps layers (popup menu in layer list)

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