001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions.mapmode;
003
004import java.awt.Cursor;
005import java.awt.event.ActionEvent;
006import java.awt.event.InputEvent;
007import java.awt.event.MouseEvent;
008import java.awt.event.MouseListener;
009import java.awt.event.MouseMotionListener;
010
011import org.openstreetmap.josm.Main;
012import org.openstreetmap.josm.actions.JosmAction;
013import org.openstreetmap.josm.gui.MapFrame;
014import org.openstreetmap.josm.gui.layer.Layer;
015import org.openstreetmap.josm.tools.ImageProvider;
016import org.openstreetmap.josm.tools.Shortcut;
017
018/**
019 * A class implementing MapMode is able to be selected as an mode for map editing.
020 * As example scrolling the map is a MapMode, connecting Nodes to new Ways
021 * is another.
022 *
023 * MapModes should register/deregister all necessary listeners on the map's view control.
024 */
025public abstract class MapMode extends JosmAction implements MouseListener, MouseMotionListener {
026    protected final Cursor cursor;
027    protected boolean ctrl;
028    protected boolean alt;
029    protected boolean shift;
030
031    /**
032     * Constructor for mapmodes without an menu
033     * @param mapFrame unused but kept for plugin compatibility. Can be {@code null}
034     */
035    public MapMode(String name, String iconName, String tooltip, Shortcut shortcut, MapFrame mapFrame, Cursor cursor) {
036        super(name, "mapmode/"+iconName, tooltip, shortcut, false);
037        this.cursor = cursor;
038        putValue("active", Boolean.FALSE);
039    }
040
041    /**
042     * Constructor for mapmodes with an menu (no shortcut will be registered)
043     * @param mapFrame unused but kept for plugin compatibility. Can be {@code null}
044     */
045    public MapMode(String name, String iconName, String tooltip, MapFrame mapFrame, Cursor cursor) {
046        putValue(NAME, name);
047        putValue(SMALL_ICON, ImageProvider.get("mapmode", iconName));
048        putValue(SHORT_DESCRIPTION, tooltip);
049        this.cursor = cursor;
050    }
051
052    /**
053     * Makes this map mode active.
054     */
055    public void enterMode() {
056        putValue("active", Boolean.TRUE);
057        Main.map.mapView.setNewCursor(cursor, this);
058        updateStatusLine();
059    }
060
061    /**
062     * Makes this map mode inactive.
063     */
064    public void exitMode() {
065        putValue("active", Boolean.FALSE);
066        Main.map.mapView.resetCursor(this);
067    }
068
069    protected void updateStatusLine() {
070        Main.map.statusLine.setHelpText(getModeHelpText());
071        Main.map.statusLine.repaint();
072    }
073
074    public String getModeHelpText() {
075        return "";
076    }
077
078    /**
079     * Call selectMapMode(this) on the parent mapFrame.
080     */
081    @Override
082    public void actionPerformed(ActionEvent e) {
083        if (Main.isDisplayingMapView()) {
084            Main.map.selectMapMode(this);
085        }
086    }
087
088    /**
089     * Determines if layer {@code l} is supported by this map mode.
090     * By default, all tools will work with all layers.
091     * Can be overwritten to require a special type of layer
092     * @param l layer
093     * @return {@code true} if the layer is supported by this map mode
094     */
095    public boolean layerIsSupported(Layer l) {
096        return l != null;
097    }
098
099    protected void updateKeyModifiers(InputEvent e) {
100        updateKeyModifiers(e.getModifiers());
101    }
102
103    protected void updateKeyModifiers(MouseEvent e) {
104        updateKeyModifiers(e.getModifiers());
105    }
106
107    protected void updateKeyModifiers(int modifiers) {
108        ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
109        alt = (modifiers & (ActionEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0;
110        shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
111    }
112
113    protected void requestFocusInMapView() {
114        if (isEnabled()) {
115            // request focus in order to enable the expected keyboard shortcuts (see #8710)
116            Main.map.mapView.requestFocus();
117        }
118    }
119
120    @Override
121    public void mouseReleased(MouseEvent e) {
122        requestFocusInMapView();
123    }
124
125    @Override
126    public void mouseExited(MouseEvent e) {
127        // Do nothing
128    }
129
130    @Override
131    public void mousePressed(MouseEvent e) {
132        requestFocusInMapView();
133    }
134
135    @Override
136    public void mouseClicked(MouseEvent e) {
137        // Do nothing
138    }
139
140    @Override
141    public void mouseEntered(MouseEvent e) {
142        // Do nothing
143    }
144
145    @Override
146    public void mouseMoved(MouseEvent e) {
147        // Do nothing
148    }
149
150    @Override
151    public void mouseDragged(MouseEvent e) {
152        // Do nothing
153    }
154}