001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.event.ActionEvent;
007
008import javax.swing.AbstractAction;
009import javax.swing.event.ListSelectionEvent;
010import javax.swing.event.ListSelectionListener;
011
012import org.openstreetmap.josm.actions.AutoScaleAction.AutoScaleMode;
013import org.openstreetmap.josm.data.osm.OsmPrimitive;
014import org.openstreetmap.josm.gui.MainApplication;
015import org.openstreetmap.josm.gui.conflict.pair.nodes.NodeListTable;
016import org.openstreetmap.josm.gui.conflict.pair.relation.RelationMemberTable;
017import org.openstreetmap.josm.gui.dialogs.relation.MemberTable;
018import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
019import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
020import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
021import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
022import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent;
023import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
024import org.openstreetmap.josm.gui.layer.OsmDataLayer;
025import org.openstreetmap.josm.gui.widgets.OsmPrimitivesTable;
026import org.openstreetmap.josm.tools.CheckParameterUtil;
027
028/**
029 * An action that zooms to the selected OSM primitive in a table of primitives.
030 */
031public class ZoomToAction extends AbstractAction implements LayerChangeListener, ActiveLayerChangeListener, ListSelectionListener {
032
033    private final OsmPrimitivesTable table;
034
035    private final String descriptionNominal;
036    private final String descriptionInactiveLayer;
037    private final String descriptionNoSelection;
038
039    /**
040     * Creates a new, generic zoom to action
041     * @param table The table to get the selected element from
042     * @param descriptionNominal The description to display if zooming is possible
043     * @param descriptionInactiveLayer The description to display if zooming is impossible because the layer is not active
044     * @param descriptionNoSelection The description to display if zooming is impossible because the table selection is empty
045     */
046    public ZoomToAction(OsmPrimitivesTable table, String descriptionNominal, String descriptionInactiveLayer, String descriptionNoSelection) {
047        CheckParameterUtil.ensureParameterNotNull(table);
048        this.table = table;
049        this.descriptionNominal = descriptionNominal;
050        this.descriptionInactiveLayer = descriptionInactiveLayer;
051        this.descriptionNoSelection = descriptionNoSelection;
052        putValue(NAME, tr("Zoom to"));
053        putValue(SHORT_DESCRIPTION, descriptionNominal);
054        updateEnabledState();
055    }
056
057    /**
058     * Creates a new zoom to action for a {@link MemberTable} using the matching description strings
059     * @param table The table to get the selected element from
060     */
061    public ZoomToAction(MemberTable table) {
062        this(table,
063                tr("Zoom to the object the first selected member refers to"),
064                tr("Zooming disabled because layer of this relation is not active"),
065                tr("Zooming disabled because there is no selected member"));
066    }
067
068    /**
069     * Creates a new zoom to action for a {@link RelationMemberTable} using the matching description strings
070     * @param table The table to get the selected element from
071     */
072    public ZoomToAction(RelationMemberTable table) {
073        this(table,
074                tr("Zoom to the object the first selected member refers to"),
075                tr("Zooming disabled because layer of this relation is not active"),
076                tr("Zooming disabled because there is no selected member"));
077    }
078
079    /**
080     * Creates a new zoom to action for a {@link NodeListTable} using the matching description strings
081     * @param table The table to get the selected element from
082     */
083    public ZoomToAction(NodeListTable table) {
084        this(table,
085                tr("Zoom to the first selected node"),
086                tr("Zooming disabled because layer of this way is not active"),
087                tr("Zooming disabled because there is no selected node"));
088    }
089
090    @Override
091    public void actionPerformed(ActionEvent e) {
092        if (!isEnabled())
093            return;
094        int[] rows = this.table.getSelectedRows();
095        if (rows.length == 0)
096            return;
097        int row = rows[0];
098        OsmDataLayer layer = this.table.getLayer();
099        OsmPrimitive primitive = this.table.getPrimitiveInLayer(row, layer);
100        if (layer != null && primitive != null) {
101            layer.data.setSelected(primitive);
102            AutoScaleAction.autoScale(AutoScaleMode.SELECTION);
103        }
104    }
105
106    protected final void updateEnabledState() {
107        if (MainApplication.getLayerManager().getActiveDataLayer() != this.table.getLayer()) {
108            setEnabled(false);
109            putValue(SHORT_DESCRIPTION, descriptionInactiveLayer);
110            return;
111        }
112        if (this.table.getSelectedRowCount() == 0) {
113            setEnabled(false);
114            putValue(SHORT_DESCRIPTION, descriptionNoSelection);
115            return;
116        }
117        setEnabled(true);
118        putValue(SHORT_DESCRIPTION, descriptionNominal);
119    }
120
121    @Override
122    public void valueChanged(ListSelectionEvent e) {
123        updateEnabledState();
124    }
125
126    @Override
127    public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) {
128        updateEnabledState();
129    }
130
131    @Override
132    public void layerAdded(LayerAddEvent e) {
133        updateEnabledState();
134    }
135
136    @Override
137    public void layerRemoving(LayerRemoveEvent e) {
138        updateEnabledState();
139    }
140
141    @Override
142    public void layerOrderChanged(LayerOrderChangeEvent e) {
143        // Do nothing
144    }
145}