// License: GPL. Copyright 2007 by Immanuel Scholz and others package org.openstreetmap.josm.actions; import static org.openstreetmap.josm.gui.help.HelpUtil.ht; import static org.openstreetmap.josm.tools.I18n.marktr; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.Collection; import java.util.HashSet; import java.util.List; import javax.swing.JOptionPane; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; import org.openstreetmap.josm.gui.MapView; import org.openstreetmap.josm.gui.dialogs.LayerListDialog; import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.tools.Shortcut; /** * Toggles the autoScale feature of the mapView * @author imi */ public class AutoScaleAction extends JosmAction { public static final String[] MODES = { marktr("data"), marktr("layer"), marktr("selection"), marktr("conflict"), marktr("download"), marktr("previous"), marktr("next")}; /** * Zooms the current map view to the currently selected primitives. * Does nothing if there either isn't a current map view or if there isn't a current data * layer. * */ public static void zoomToSelection() { if (Main.main == null || Main.main.getEditLayer() == null) return; if (Main.map == null || Main.map.mapView == null) return; Collection<OsmPrimitive> sel = Main.main.getEditLayer().data.getSelected(); if (sel.isEmpty()) { JOptionPane.showMessageDialog( Main.parent, tr("Nothing selected to zoom to."), tr("Information"), JOptionPane.INFORMATION_MESSAGE ); return; } BoundingXYVisitor bboxCalculator = new BoundingXYVisitor(); bboxCalculator.computeBoundingBox(sel); // increase bbox by 0.001 degrees on each side. this is required // especially if the bbox contains one single node, but helpful // in most other cases as well. bboxCalculator.enlargeBoundingBox(); if (bboxCalculator.getBounds() != null) { Main.map.mapView.recalculateCenterScale(bboxCalculator); } } private final String mode; private static int getModeShortcut(String mode) { int shortcut = -1; if (mode.equals("data")) { shortcut = KeyEvent.VK_1; } if (mode.equals("layer")) { shortcut = KeyEvent.VK_2; } if (mode.equals("selection")) { shortcut = KeyEvent.VK_3; } if (mode.equals("conflict")) { shortcut = KeyEvent.VK_4; } if (mode.equals("download")) { shortcut = KeyEvent.VK_5; } if (mode.equals("previous")) { shortcut = KeyEvent.VK_8; } if (mode.equals("next")) { shortcut = KeyEvent.VK_9; } return shortcut; } public AutoScaleAction(String mode) { super(tr("Zoom to {0}", tr(mode)), "dialogs/autoscale/" + mode, tr("Zoom the view to {0}.", tr(mode)), Shortcut.registerShortcut("view:zoom"+mode, tr("View: {0}", tr("Zoom to {0}", tr(mode))), getModeShortcut(mode), Shortcut.GROUP_EDIT), true); String modeHelp = Character.toUpperCase(mode.charAt(0)) + mode.substring(1); putValue("help", "Action/AutoScale/" + modeHelp); this.mode = mode; if (mode.equals("data")) { putValue("help", ht("/Action/ZoomToData")); } else if (mode.equals("layer")) { putValue("help", ht("/Action/ZoomToLayer")); } else if (mode.equals("selection")) { putValue("help", ht("/Action/ZoomToSelection")); } else if (mode.equals("conflict")) { putValue("help", ht("/Action/ZoomToConflict")); } else if (mode.equals("download")) { putValue("help", ht("/Action/ZoomToDownload")); } else if (mode.equals("previous")) { putValue("help", ht("/Action/ZoomPrevious")); } else if (mode.equals("next")) { putValue("help", ht("/Action/ZoomNext")); } } public void autoScale() { if (Main.map != null) { if (mode.equals("previous")) { Main.map.mapView.zoomPrevious(); } else if (mode.equals("next")) { Main.map.mapView.zoomNext(); } else { BoundingXYVisitor bbox = getBoundingBox(); if (bbox != null && bbox.getBounds() != null) { Main.map.mapView.recalculateCenterScale(bbox); } } } putValue("active", true); } public void actionPerformed(ActionEvent e) { autoScale(); } protected Layer getActiveLayer() { try { return Main.map.mapView.getActiveLayer(); } catch(NullPointerException e) { return null; } } /** * Replies the first selected layer in the layer list dialog. null, if no * such layer exists, either because the layer list dialog is not yet created * or because no layer is selected. * * @return the first selected layer in the layer list dialog */ protected Layer getFirstSelectedLayer() { if (LayerListDialog.getInstance() == null) return null; List<Layer> layers = LayerListDialog.getInstance().getModel().getSelectedLayers(); if (layers.isEmpty()) return null; return layers.get(0); } private BoundingXYVisitor getBoundingBox() { BoundingXYVisitor v = new BoundingXYVisitor(); if (mode.equals("data")) { for (Layer l : Main.map.mapView.getAllLayers()) { l.visitBoundingBox(v); } } else if (mode.equals("layer")) { if (getActiveLayer() == null) return null; // try to zoom to the first selected layer // Layer l = getFirstSelectedLayer(); if (l == null) return null; l.visitBoundingBox(v); } else if (mode.equals("selection") || mode.equals("conflict")) { Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>(); if (mode.equals("selection")) { sel = getCurrentDataSet().getSelected(); } else if (mode.equals("conflict")) { if (Main.map.conflictDialog.getConflicts() != null) { sel = Main.map.conflictDialog.getConflicts().getMyConflictParties(); } } if (sel.isEmpty()) { JOptionPane.showMessageDialog( Main.parent, (mode.equals("selection") ? tr("Nothing selected to zoom to.") : tr("No conflicts to zoom to")), tr("Information"), JOptionPane.INFORMATION_MESSAGE ); return null; } for (OsmPrimitive osm : sel) { osm.visit(v); } // increase bbox by 0.001 degrees on each side. this is required // especially if the bbox contains one single node, but helpful // in most other cases as well. v.enlargeBoundingBox(); } else if (mode.equals("download")) { if (Main.pref.hasKey("osm-download.bounds")) { try { v.visit(new Bounds(Main.pref.get("osm-download.bounds"), ";")); } catch (Exception e) { e.printStackTrace(); } } } return v; } @Override protected void updateEnabledState() { if ("selection".equals(mode)) { setEnabled(getCurrentDataSet() != null && ! getCurrentDataSet().getSelected().isEmpty()); } else if ("layer".equals(mode)) { if (Main.map == null || Main.map.mapView == null || Main.map.mapView.getAllLayersAsList().isEmpty()) { setEnabled(false); } else { // FIXME: should also check for whether a layer is selected in the layer list dialog setEnabled(true); } } else if ("previous".equals(mode)) { setEnabled(Main.map != null && Main.map.mapView != null && Main.map.mapView.hasZoomUndoEntries()); } else if ("next".equals(mode)) { setEnabled(Main.map != null && Main.map.mapView != null && Main.map.mapView.hasZoomRedoEntries()); } else { setEnabled( Main.isDisplayingMapView() && Main.map.mapView.hasLayers() ); } } @Override protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) { if ("selection".equals(mode)) { setEnabled(selection != null && !selection.isEmpty()); } } @Override protected void installAdapters() { super.installAdapters(); // make this action listen to zoom change events // zoomChangeAdapter = new ZoomChangeAdapter(); MapView.addZoomChangeListener(zoomChangeAdapter); initEnabledState(); } /** * Adapter for selection change events * */ private class ZoomChangeAdapter implements MapView.ZoomChangeListener { public void zoomChanged() { updateEnabledState(); } } private ZoomChangeAdapter zoomChangeAdapter; }