source: josm/trunk/src/org/openstreetmap/josm/actions/AutoScaleAction.java@ 6569

Last change on this file since 6569 was 6509, checked in by Don-vip, 10 years ago

fix #9459 - initialize default center view of MapView to last download location, if any, instead of (0,0)

  • Property svn:eol-style set to native
File size: 13.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.marktr;
6import static org.openstreetmap.josm.tools.I18n.tr;
7
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.util.Arrays;
11import java.util.Collection;
12import java.util.Collections;
13import java.util.HashSet;
14import java.util.List;
15
16import javax.swing.JOptionPane;
17import javax.swing.event.ListSelectionEvent;
18import javax.swing.event.ListSelectionListener;
19import javax.swing.event.TreeSelectionEvent;
20import javax.swing.event.TreeSelectionListener;
21
22import org.openstreetmap.josm.Main;
23import org.openstreetmap.josm.data.Bounds;
24import org.openstreetmap.josm.data.conflict.Conflict;
25import org.openstreetmap.josm.data.osm.OsmPrimitive;
26import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
27import org.openstreetmap.josm.data.validation.TestError;
28import org.openstreetmap.josm.gui.MapFrame;
29import org.openstreetmap.josm.gui.MapFrameListener;
30import org.openstreetmap.josm.gui.MapView;
31import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
32import org.openstreetmap.josm.gui.dialogs.ValidatorDialog.ValidatorBoundingXYVisitor;
33import org.openstreetmap.josm.gui.download.DownloadDialog;
34import org.openstreetmap.josm.gui.layer.Layer;
35import org.openstreetmap.josm.tools.Shortcut;
36
37/**
38 * Toggles the autoScale feature of the mapView
39 * @author imi
40 */
41public class AutoScaleAction extends JosmAction {
42
43 public static final Collection<String> MODES = Collections.unmodifiableList(Arrays.asList(
44 marktr("data"),
45 marktr("layer"),
46 marktr("selection"),
47 marktr("conflict"),
48 marktr("download"),
49 marktr("problem"),
50 marktr("previous"),
51 marktr("next")));
52
53 private final String mode;
54
55 protected ZoomChangeAdapter zoomChangeAdapter;
56 protected MapFrameAdapter mapFrameAdapter;
57
58 /**
59 * Zooms the current map view to the currently selected primitives.
60 * Does nothing if there either isn't a current map view or if there isn't a current data
61 * layer.
62 *
63 */
64 public static void zoomToSelection() {
65 if (Main.main == null || !Main.main.hasEditLayer()) return;
66 Collection<OsmPrimitive> sel = Main.main.getEditLayer().data.getSelected();
67 if (sel.isEmpty()) {
68 JOptionPane.showMessageDialog(
69 Main.parent,
70 tr("Nothing selected to zoom to."),
71 tr("Information"),
72 JOptionPane.INFORMATION_MESSAGE
73 );
74 return;
75 }
76 zoomTo(sel);
77 }
78
79 public static void zoomTo(Collection<OsmPrimitive> sel) {
80 BoundingXYVisitor bboxCalculator = new BoundingXYVisitor();
81 bboxCalculator.computeBoundingBox(sel);
82 // increase bbox by 0.001 degrees on each side. this is required
83 // especially if the bbox contains one single node, but helpful
84 // in most other cases as well.
85 bboxCalculator.enlargeBoundingBox();
86 if (bboxCalculator.getBounds() != null) {
87 Main.map.mapView.recalculateCenterScale(bboxCalculator);
88 }
89 }
90
91 public static void autoScale(String mode) {
92 new AutoScaleAction(mode, false).autoScale();
93 }
94
95 private static int getModeShortcut(String mode) {
96 int shortcut = -1;
97
98 /* leave as single line for shortcut overview parsing! */
99 if (mode.equals("data")) { shortcut = KeyEvent.VK_1; }
100 else if (mode.equals("layer")) { shortcut = KeyEvent.VK_2; }
101 else if (mode.equals("selection")) { shortcut = KeyEvent.VK_3; }
102 else if (mode.equals("conflict")) { shortcut = KeyEvent.VK_4; }
103 else if (mode.equals("download")) { shortcut = KeyEvent.VK_5; }
104 else if (mode.equals("problem")) { shortcut = KeyEvent.VK_6; }
105 else if (mode.equals("previous")) { shortcut = KeyEvent.VK_8; }
106 else if (mode.equals("next")) { shortcut = KeyEvent.VK_9; }
107
108 return shortcut;
109 }
110
111 /**
112 * Constructs a new {@code AutoScaleAction}.
113 * @param mode The autoscale mode (one of {@link AutoScaleAction#MODES})
114 * @param marker Used only to differentiate from default constructor
115 */
116 private AutoScaleAction(String mode, boolean marker) {
117 super(false);
118 this.mode = mode;
119 }
120
121 /**
122 * Constructs a new {@code AutoScaleAction}.
123 * @param mode The autoscale mode (one of {@link AutoScaleAction#MODES})
124 */
125 public AutoScaleAction(final String mode) {
126 super(tr("Zoom to {0}", tr(mode)), "dialogs/autoscale/" + mode, tr("Zoom the view to {0}.", tr(mode)),
127 Shortcut.registerShortcut("view:zoom"+mode, tr("View: {0}", tr("Zoom to {0}", tr(mode))), getModeShortcut(mode), Shortcut.DIRECT),
128 true, null, false);
129 String modeHelp = Character.toUpperCase(mode.charAt(0)) + mode.substring(1);
130 putValue("help", "Action/AutoScale/" + modeHelp);
131 this.mode = mode;
132 if (mode.equals("data")) {
133 putValue("help", ht("/Action/ZoomToData"));
134 } else if (mode.equals("layer")) {
135 putValue("help", ht("/Action/ZoomToLayer"));
136 } else if (mode.equals("selection")) {
137 putValue("help", ht("/Action/ZoomToSelection"));
138 } else if (mode.equals("conflict")) {
139 putValue("help", ht("/Action/ZoomToConflict"));
140 } else if (mode.equals("problem")) {
141 putValue("help", ht("/Action/ZoomToProblem"));
142 } else if (mode.equals("download")) {
143 putValue("help", ht("/Action/ZoomToDownload"));
144 } else if (mode.equals("previous")) {
145 putValue("help", ht("/Action/ZoomToPrevious"));
146 } else if (mode.equals("next")) {
147 putValue("help", ht("/Action/ZoomToNext"));
148 } else {
149 throw new IllegalArgumentException("Unknown mode: "+mode);
150 }
151 installAdapters();
152 }
153
154 public void autoScale() {
155 if (Main.isDisplayingMapView()) {
156 if (mode.equals("previous")) {
157 Main.map.mapView.zoomPrevious();
158 } else if (mode.equals("next")) {
159 Main.map.mapView.zoomNext();
160 } else {
161 BoundingXYVisitor bbox = getBoundingBox();
162 if (bbox != null && bbox.getBounds() != null) {
163 Main.map.mapView.recalculateCenterScale(bbox);
164 }
165 }
166 }
167 putValue("active", true);
168 }
169
170 @Override
171 public void actionPerformed(ActionEvent e) {
172 autoScale();
173 }
174
175 protected Layer getActiveLayer() {
176 try {
177 return Main.map.mapView.getActiveLayer();
178 } catch(NullPointerException e) {
179 return null;
180 }
181 }
182
183 /**
184 * Replies the first selected layer in the layer list dialog. null, if no
185 * such layer exists, either because the layer list dialog is not yet created
186 * or because no layer is selected.
187 *
188 * @return the first selected layer in the layer list dialog
189 */
190 protected Layer getFirstSelectedLayer() {
191 List<Layer> layers = LayerListDialog.getInstance().getModel().getSelectedLayers();
192 if (layers.isEmpty()) return null;
193 return layers.get(0);
194 }
195
196 private BoundingXYVisitor getBoundingBox() {
197 BoundingXYVisitor v = mode.equals("problem") ? new ValidatorBoundingXYVisitor() : new BoundingXYVisitor();
198
199 if (mode.equals("problem")) {
200 TestError error = Main.map.validatorDialog.getSelectedError();
201 if (error == null) return null;
202 ((ValidatorBoundingXYVisitor) v).visit(error);
203 if (v.getBounds() == null) return null;
204 v.enlargeBoundingBox(Main.pref.getDouble("validator.zoom-enlarge-bbox", 0.0002));
205 } else if (mode.equals("data")) {
206 for (Layer l : Main.map.mapView.getAllLayers()) {
207 l.visitBoundingBox(v);
208 }
209 } else if (mode.equals("layer")) {
210 if (getActiveLayer() == null)
211 return null;
212 // try to zoom to the first selected layer
213 //
214 Layer l = getFirstSelectedLayer();
215 if (l == null) return null;
216 l.visitBoundingBox(v);
217 } else if (mode.equals("selection") || mode.equals("conflict")) {
218 Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();
219 if (mode.equals("selection")) {
220 sel = getCurrentDataSet().getSelected();
221 } else if (mode.equals("conflict")) {
222 Conflict<? extends OsmPrimitive> c = Main.map.conflictDialog.getSelectedConflict();
223 if (c != null) {
224 sel.add(c.getMy());
225 } else if (Main.map.conflictDialog.getConflicts() != null) {
226 sel = Main.map.conflictDialog.getConflicts().getMyConflictParties();
227 }
228 }
229 if (sel.isEmpty()) {
230 JOptionPane.showMessageDialog(
231 Main.parent,
232 (mode.equals("selection") ? tr("Nothing selected to zoom to.") : tr("No conflicts to zoom to")),
233 tr("Information"),
234 JOptionPane.INFORMATION_MESSAGE
235 );
236 return null;
237 }
238 for (OsmPrimitive osm : sel) {
239 osm.accept(v);
240 }
241 // increase bbox by 0.001 degrees on each side. this is required
242 // especially if the bbox contains one single node, but helpful
243 // in most other cases as well.
244 v.enlargeBoundingBox();
245 }
246 else if (mode.equals("download")) {
247 Bounds bounds = DownloadDialog.getSavedDownloadBounds();
248 if (bounds != null) {
249 try {
250 v.visit(bounds);
251 } catch (Exception e) {
252 Main.warn(e);
253 }
254 }
255 }
256 return v;
257 }
258
259 @Override
260 protected void updateEnabledState() {
261 if ("selection".equals(mode)) {
262 setEnabled(getCurrentDataSet() != null && ! getCurrentDataSet().getSelected().isEmpty());
263 } else if ("layer".equals(mode)) {
264 if (!Main.isDisplayingMapView() || Main.map.mapView.getAllLayersAsList().isEmpty()) {
265 setEnabled(false);
266 } else {
267 // FIXME: should also check for whether a layer is selected in the layer list dialog
268 setEnabled(true);
269 }
270 } else if ("conflict".equals(mode)) {
271 setEnabled(Main.map != null && Main.map.conflictDialog.getSelectedConflict() != null);
272 } else if ("problem".equals(mode)) {
273 setEnabled(Main.map != null && Main.map.validatorDialog.getSelectedError() != null);
274 } else if ("previous".equals(mode)) {
275 setEnabled(Main.isDisplayingMapView() && Main.map.mapView.hasZoomUndoEntries());
276 } else if ("next".equals(mode)) {
277 setEnabled(Main.isDisplayingMapView() && Main.map.mapView.hasZoomRedoEntries());
278 } else {
279 setEnabled(
280 Main.isDisplayingMapView()
281 && Main.map.mapView.hasLayers()
282 );
283 }
284 }
285
286 @Override
287 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
288 if ("selection".equals(mode)) {
289 setEnabled(selection != null && !selection.isEmpty());
290 }
291 }
292
293 @Override
294 protected void installAdapters() {
295 super.installAdapters();
296 // make this action listen to zoom and mapframe change events
297 //
298 MapView.addZoomChangeListener(zoomChangeAdapter = new ZoomChangeAdapter());
299 Main.addMapFrameListener(mapFrameAdapter = new MapFrameAdapter());
300 initEnabledState();
301 }
302
303 /**
304 * Adapter for zoom change events
305 */
306 private class ZoomChangeAdapter implements MapView.ZoomChangeListener {
307 @Override
308 public void zoomChanged() {
309 updateEnabledState();
310 }
311 }
312
313 /**
314 * Adapter for MapFrame change events
315 */
316 private class MapFrameAdapter implements MapFrameListener {
317 private ListSelectionListener conflictSelectionListener;
318 private TreeSelectionListener validatorSelectionListener;
319
320 public MapFrameAdapter() {
321 if (mode.equals("conflict")) {
322 conflictSelectionListener = new ListSelectionListener() {
323 @Override public void valueChanged(ListSelectionEvent e) {
324 updateEnabledState();
325 }
326 };
327 } else if (mode.equals("problem")) {
328 validatorSelectionListener = new TreeSelectionListener() {
329 @Override public void valueChanged(TreeSelectionEvent e) {
330 updateEnabledState();
331 }
332 };
333 }
334 }
335
336 @Override public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
337 if (conflictSelectionListener != null) {
338 if (newFrame != null) {
339 newFrame.conflictDialog.addListSelectionListener(conflictSelectionListener);
340 } else if (oldFrame != null) {
341 oldFrame.conflictDialog.removeListSelectionListener(conflictSelectionListener);
342 }
343 } else if (validatorSelectionListener != null) {
344 if (newFrame != null) {
345 newFrame.validatorDialog.addTreeSelectionListener(validatorSelectionListener);
346 } else if (oldFrame != null) {
347 oldFrame.validatorDialog.removeTreeSelectionListener(validatorSelectionListener);
348 }
349 }
350 }
351 }
352}
Note: See TracBrowser for help on using the repository browser.