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

Last change on this file since 6380 was 6380, checked in by Don-vip, 11 years ago

update license/copyright information

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