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

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

fix some Sonar issues

  • Property svn:eol-style set to native
File size: 13.5 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[403]2package org.openstreetmap.josm.actions;
3
[2477]4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
[948]5import static org.openstreetmap.josm.tools.I18n.marktr;
[403]6import static org.openstreetmap.josm.tools.I18n.tr;
7
8import java.awt.event.ActionEvent;
[458]9import java.awt.event.KeyEvent;
[6246]10import java.util.Arrays;
[403]11import java.util.Collection;
[6246]12import java.util.Collections;
[1750]13import java.util.HashSet;
[1953]14import java.util.List;
[403]15
16import javax.swing.JOptionPane;
[5958]17import javax.swing.event.ListSelectionEvent;
18import javax.swing.event.ListSelectionListener;
19import javax.swing.event.TreeSelectionEvent;
20import javax.swing.event.TreeSelectionListener;
[403]21
22import org.openstreetmap.josm.Main;
[2477]23import org.openstreetmap.josm.data.Bounds;
[3973]24import org.openstreetmap.josm.data.conflict.Conflict;
[403]25import org.openstreetmap.josm.data.osm.OsmPrimitive;
26import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
[5958]27import org.openstreetmap.josm.data.validation.TestError;
28import org.openstreetmap.josm.gui.MapFrame;
29import org.openstreetmap.josm.gui.MapFrameListener;
[2759]30import org.openstreetmap.josm.gui.MapView;
[1953]31import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
[5958]32import org.openstreetmap.josm.gui.dialogs.ValidatorDialog.ValidatorBoundingXYVisitor;
[6509]33import org.openstreetmap.josm.gui.download.DownloadDialog;
[403]34import org.openstreetmap.josm.gui.layer.Layer;
[1084]35import org.openstreetmap.josm.tools.Shortcut;
[403]36
37/**
38 * Toggles the autoScale feature of the mapView
39 * @author imi
40 */
41public class AutoScaleAction extends JosmAction {
42
[6246]43 public static final Collection<String> MODES = Collections.unmodifiableList(Arrays.asList(
[2758]44 marktr("data"),
45 marktr("layer"),
46 marktr("selection"),
47 marktr("conflict"),
48 marktr("download"),
[5958]49 marktr("problem"),
[2758]50 marktr("previous"),
[6246]51 marktr("next")));
[6069]52
[5958]53 private final String mode;
[2685]54
[5958]55 protected ZoomChangeAdapter zoomChangeAdapter;
56 protected MapFrameAdapter mapFrameAdapter;
57
[2685]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.
[2711]62 *
[2685]63 */
64 public static void zoomToSelection() {
[6336]65 if (Main.main == null || !Main.main.hasEditLayer()) return;
[2986]66 Collection<OsmPrimitive> sel = Main.main.getEditLayer().data.getSelected();
[2685]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 }
[3251]76 zoomTo(sel);
77 }
78
79 public static void zoomTo(Collection<OsmPrimitive> sel) {
[2685]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
[3327]91 public static void autoScale(String mode) {
92 new AutoScaleAction(mode, false).autoScale();
93 }
94
[948]95 private static int getModeShortcut(String mode) {
96 int shortcut = -1;
[458]97
[4921]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; }
[5958]104 else if (mode.equals("problem")) { shortcut = KeyEvent.VK_6; }
[4921]105 else if (mode.equals("previous")) { shortcut = KeyEvent.VK_8; }
106 else if (mode.equals("next")) { shortcut = KeyEvent.VK_9; }
[458]107
[948]108 return shortcut;
109 }
[403]110
[3327]111 /**
[5958]112 * Constructs a new {@code AutoScaleAction}.
113 * @param mode The autoscale mode (one of {@link AutoScaleAction#MODES})
[3327]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
[5958]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) {
[948]126 super(tr("Zoom to {0}", tr(mode)), "dialogs/autoscale/" + mode, tr("Zoom the view to {0}.", tr(mode)),
[6069]127 Shortcut.registerShortcut("view:zoom"+mode, tr("View: {0}", tr("Zoom to {0}", tr(mode))), getModeShortcut(mode), Shortcut.DIRECT),
[5958]128 true, null, false);
[948]129 String modeHelp = Character.toUpperCase(mode.charAt(0)) + mode.substring(1);
130 putValue("help", "Action/AutoScale/" + modeHelp);
131 this.mode = mode;
[2323]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"));
[5958]140 } else if (mode.equals("problem")) {
141 putValue("help", ht("/Action/ZoomToProblem"));
[2758]142 } else if (mode.equals("download")) {
[2323]143 putValue("help", ht("/Action/ZoomToDownload"));
[2758]144 } else if (mode.equals("previous")) {
[3760]145 putValue("help", ht("/Action/ZoomToPrevious"));
[2758]146 } else if (mode.equals("next")) {
[3760]147 putValue("help", ht("/Action/ZoomToNext"));
[5958]148 } else {
149 throw new IllegalArgumentException("Unknown mode: "+mode);
[2477]150 }
[5958]151 installAdapters();
[948]152 }
[403]153
[1868]154 public void autoScale() {
[5460]155 if (Main.isDisplayingMapView()) {
[2758]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 }
[948]165 }
166 }
167 putValue("active", true);
168 }
169
[6084]170 @Override
[1868]171 public void actionPerformed(ActionEvent e) {
172 autoScale();
173 }
174
[1953]175 /**
176 * Replies the first selected layer in the layer list dialog. null, if no
177 * such layer exists, either because the layer list dialog is not yet created
178 * or because no layer is selected.
[2512]179 *
[1953]180 * @return the first selected layer in the layer list dialog
181 */
182 protected Layer getFirstSelectedLayer() {
183 List<Layer> layers = LayerListDialog.getInstance().getModel().getSelectedLayers();
184 if (layers.isEmpty()) return null;
185 return layers.get(0);
186 }
187
[948]188 private BoundingXYVisitor getBoundingBox() {
[5958]189 BoundingXYVisitor v = mode.equals("problem") ? new ValidatorBoundingXYVisitor() : new BoundingXYVisitor();
190
191 if (mode.equals("problem")) {
192 TestError error = Main.map.validatorDialog.getSelectedError();
193 if (error == null) return null;
194 ((ValidatorBoundingXYVisitor) v).visit(error);
195 if (v.getBounds() == null) return null;
196 v.enlargeBoundingBox(Main.pref.getDouble("validator.zoom-enlarge-bbox", 0.0002));
197 } else if (mode.equals("data")) {
[1750]198 for (Layer l : Main.map.mapView.getAllLayers()) {
[948]199 l.visitBoundingBox(v);
[1750]200 }
201 } else if (mode.equals("layer")) {
[6783]202 if (Main.main.getActiveLayer() == null)
[1903]203 return null;
[1953]204 // try to zoom to the first selected layer
205 Layer l = getFirstSelectedLayer();
206 if (l == null) return null;
207 l.visitBoundingBox(v);
[1750]208 } else if (mode.equals("selection") || mode.equals("conflict")) {
209 Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();
210 if (mode.equals("selection")) {
[1814]211 sel = getCurrentDataSet().getSelected();
[1750]212 } else if (mode.equals("conflict")) {
[3973]213 Conflict<? extends OsmPrimitive> c = Main.map.conflictDialog.getSelectedConflict();
214 if (c != null) {
215 sel.add(c.getMy());
216 } else if (Main.map.conflictDialog.getConflicts() != null) {
[1750]217 sel = Main.map.conflictDialog.getConflicts().getMyConflictParties();
218 }
219 }
[948]220 if (sel.isEmpty()) {
[2017]221 JOptionPane.showMessageDialog(
[1847]222 Main.parent,
223 (mode.equals("selection") ? tr("Nothing selected to zoom to.") : tr("No conflicts to zoom to")),
224 tr("Information"),
225 JOptionPane.INFORMATION_MESSAGE
226 );
[948]227 return null;
228 }
[1750]229 for (OsmPrimitive osm : sel) {
[6009]230 osm.accept(v);
[1750]231 }
[6608]232
233 // Increase the bounding box by up to 100% to give more context.
234 v.enlargeBoundingBoxLogarithmically(100);
235 // Make the bounding box at least 0.0005 degrees (≈ 56 m) wide to
236 // ensure reasonable zoom level when zooming onto single nodes.
237 v.enlargeToMinDegrees(0.0005);
[6623]238 } else if (mode.equals("download")) {
[6509]239 Bounds bounds = DownloadDialog.getSavedDownloadBounds();
240 if (bounds != null) {
[1302]241 try {
[6509]242 v.visit(bounds);
[2477]243 } catch (Exception e) {
[6509]244 Main.warn(e);
[1302]245 }
246 }
247 }
[948]248 return v;
249 }
[1820]250
251 @Override
252 protected void updateEnabledState() {
[1854]253 if ("selection".equals(mode)) {
254 setEnabled(getCurrentDataSet() != null && ! getCurrentDataSet().getSelected().isEmpty());
[1903]255 } else if ("layer".equals(mode)) {
[6333]256 if (!Main.isDisplayingMapView() || Main.map.mapView.getAllLayersAsList().isEmpty()) {
[1953]257 setEnabled(false);
258 } else {
259 // FIXME: should also check for whether a layer is selected in the layer list dialog
260 setEnabled(true);
261 }
[5958]262 } else if ("conflict".equals(mode)) {
263 setEnabled(Main.map != null && Main.map.conflictDialog.getSelectedConflict() != null);
264 } else if ("problem".equals(mode)) {
265 setEnabled(Main.map != null && Main.map.validatorDialog.getSelectedError() != null);
[2759]266 } else if ("previous".equals(mode)) {
[5460]267 setEnabled(Main.isDisplayingMapView() && Main.map.mapView.hasZoomUndoEntries());
[2759]268 } else if ("next".equals(mode)) {
[5460]269 setEnabled(Main.isDisplayingMapView() && Main.map.mapView.hasZoomRedoEntries());
[1854]270 } else {
271 setEnabled(
[2343]272 Main.isDisplayingMapView()
[1895]273 && Main.map.mapView.hasLayers()
[1854]274 );
275 }
[1820]276 }
[2256]277
278 @Override
279 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
280 if ("selection".equals(mode)) {
281 setEnabled(selection != null && !selection.isEmpty());
282 }
283 }
[2759]284
285 @Override
286 protected void installAdapters() {
287 super.installAdapters();
[5958]288 // make this action listen to zoom and mapframe change events
[2759]289 //
[5958]290 MapView.addZoomChangeListener(zoomChangeAdapter = new ZoomChangeAdapter());
291 Main.addMapFrameListener(mapFrameAdapter = new MapFrameAdapter());
[2759]292 initEnabledState();
293 }
294
295 /**
[5958]296 * Adapter for zoom change events
[2759]297 */
298 private class ZoomChangeAdapter implements MapView.ZoomChangeListener {
[6084]299 @Override
[2759]300 public void zoomChanged() {
301 updateEnabledState();
302 }
303 }
304
[5958]305 /**
306 * Adapter for MapFrame change events
307 */
308 private class MapFrameAdapter implements MapFrameListener {
309 private ListSelectionListener conflictSelectionListener;
310 private TreeSelectionListener validatorSelectionListener;
311
312 public MapFrameAdapter() {
313 if (mode.equals("conflict")) {
314 conflictSelectionListener = new ListSelectionListener() {
315 @Override public void valueChanged(ListSelectionEvent e) {
316 updateEnabledState();
317 }
318 };
319 } else if (mode.equals("problem")) {
320 validatorSelectionListener = new TreeSelectionListener() {
321 @Override public void valueChanged(TreeSelectionEvent e) {
322 updateEnabledState();
323 }
324 };
325 }
326 }
327
328 @Override public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
329 if (conflictSelectionListener != null) {
330 if (newFrame != null) {
331 newFrame.conflictDialog.addListSelectionListener(conflictSelectionListener);
332 } else if (oldFrame != null) {
333 oldFrame.conflictDialog.removeListSelectionListener(conflictSelectionListener);
334 }
335 } else if (validatorSelectionListener != null) {
336 if (newFrame != null) {
337 newFrame.validatorDialog.addTreeSelectionListener(validatorSelectionListener);
338 } else if (oldFrame != null) {
339 oldFrame.validatorDialog.removeTreeSelectionListener(validatorSelectionListener);
340 }
341 }
342 }
343 }
[403]344}
Note: See TracBrowser for help on using the repository browser.