Ticket #22623: 22623.2.patch

File 22623.2.patch, 13.0 KB (added by taylor.smock, 2 years ago)

Allow toggling between circle and rectangle modes (non-default behavior, requires user to change setting in Set buildings size -> Advanced)

  • src/org/openstreetmap/josm/plugins/buildings_tools/AdvancedSettingsDialog.java

     
    1919    private final JCheckBox cBigMode = new JCheckBox(tr("Big buildings mode"));
    2020    private final JCheckBox cSoftCur = new JCheckBox(tr("Rotate crosshair"));
    2121    private final JCheckBox cNoClickDrag = new JCheckBox(tr("Disable click+drag"));
     22    private final JCheckBox cToggleMapMode = new JCheckBox(tr("Switch between circle and rectangle modes"));
    2223
    2324    public AdvancedSettingsDialog() {
    2425        super(tr("Advanced settings"));
     
    3334        panel.add(cBigMode, GBC.eol().fill(GBC.HORIZONTAL));
    3435        panel.add(cSoftCur, GBC.eol().fill(GBC.HORIZONTAL));
    3536        panel.add(cNoClickDrag, GBC.eol().fill(GBC.HORIZONTAL));
     37        panel.add(cToggleMapMode, GBC.eol().fill(GBC.HORIZONTAL));
    3638
    3739        cBigMode.setSelected(ToolSettings.isBBMode());
    3840        cSoftCur.setSelected(ToolSettings.isSoftCursor());
    3941        cNoClickDrag.setSelected(ToolSettings.isNoClickAndDrag());
     42        cToggleMapMode.setSelected(ToolSettings.isTogglingBuildingTypeOnRepeatedKeyPress());
    4043
     44        cToggleMapMode.setToolTipText(tr("This is similar to the select action toggling between lasso and rectangle select modes"));
     45
    4146        setupDialog();
    4247        showDialog();
    4348    }
     
    4752        ToolSettings.setBBMode(cBigMode.isSelected());
    4853        ToolSettings.setSoftCursor(cSoftCur.isSelected());
    4954        ToolSettings.setNoClickAndDrag(cNoClickDrag.isSelected());
     55        ToolSettings.setTogglingBuildingTypeOnRepeatedKeyPress(cToggleMapMode.isSelected());
    5056    }
    5157}
  • src/org/openstreetmap/josm/plugins/buildings_tools/BuildingsToolsPlugin.java

     
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.plugins.buildings_tools;
    33
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import javax.swing.JMenu;
    57
    68import org.openstreetmap.josm.data.coor.EastNorth;
     
    1416import org.openstreetmap.josm.gui.MapFrame;
    1517import org.openstreetmap.josm.plugins.Plugin;
    1618import org.openstreetmap.josm.plugins.PluginInformation;
     19import org.openstreetmap.josm.tools.ImageProvider;
    1720
     21/**
     22 * The entry point for the buildings tools plugin
     23 */
    1824public class BuildingsToolsPlugin extends Plugin {
    1925    public static final Projection MERCATOR = Projections.getProjectionByCode("EPSG:3857"); // Mercator
    2026
     
    2834
    2935    public BuildingsToolsPlugin(PluginInformation info) {
    3036        super(info);
    31         JMenu dataMenu = MainApplication.getMenu().dataMenu;
    32         MainMenu.add(dataMenu, new BuildingSizeAction());
    33         MainMenu.add(dataMenu, new BuildingCircleAction());
    34         MainMenu.add(dataMenu, new BuildingRectangleAction());
    35         MainMenu.add(dataMenu, new MergeAddrPointsAction());
     37        JMenu moreToolsMenu = MainApplication.getMenu().moreToolsMenu;
     38        if (moreToolsMenu.getMenuComponentCount() > 0) {
     39            moreToolsMenu.addSeparator();
     40        }
     41        MainMenu.add(moreToolsMenu, new DrawBuildingAction());
     42        JMenu optionMenu = new JMenu(tr("Draw buildings modes"));
     43        optionMenu.setIcon(ImageProvider.get("preference_small", ImageProvider.ImageSizes.MENU));
     44        moreToolsMenu.add(optionMenu);
     45        MainMenu.add(optionMenu, new BuildingSizeAction());
     46        MainMenu.add(optionMenu, new BuildingCircleAction());
     47        MainMenu.add(optionMenu, new BuildingRectangleAction());
     48        MainMenu.add(optionMenu, new MergeAddrPointsAction());
    3649    }
    3750
    3851    @Override
    3952    public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
    4053        if (oldFrame == null && newFrame != null) {
    41             MainApplication.getMap().addMapMode(new IconToggleButton(new DrawBuildingAction()));
     54            newFrame.addMapMode(new IconToggleButton(new DrawBuildingAction()));
    4255        }
    4356    }
    4457}
  • src/org/openstreetmap/josm/plugins/buildings_tools/DrawBuildingAction.java

     
    4444import static org.openstreetmap.josm.tools.I18n.marktr;
    4545import static org.openstreetmap.josm.tools.I18n.tr;
    4646
     47/**
     48 * The action for drawing the building
     49 */
    4750public class DrawBuildingAction extends MapMode implements MapViewPaintable, DataSelectionListener,
    4851        KeyPressReleaseListener, ModifierExListener {
     52    private static final long serialVersionUID = -3515263157730927711L;
    4953    // We need to avoid opening many file descriptors on Linux under Wayland -- see JOSM #21929. This will probably also
    5054    // improve performance, since we aren't creating cursors all the time.
    5155    private static final Cursor CURSOR_SILO = ImageProvider.getCursor("crosshair", "silo");
     
    7276
    7377    private final PreferenceChangedListener shapeChangeListener = event -> updCursor();
    7478
     79    /**
     80     * Create a new {@link DrawBuildingAction} object
     81     */
    7582    public DrawBuildingAction() {
    7683        super(tr("Draw buildings"), "building", tr("Draw buildings"),
    7784                Shortcut.registerShortcut("mapmode:buildings",
     
    193200
    194201            cancelDrawing();
    195202        }
     203        if (!ToolSettings.isTogglingBuildingTypeOnRepeatedKeyPress()
     204                || !MainApplication.isDisplayingMapView() || !getShortcut().isEvent(e)) {
     205            return;
     206        }
     207        e.consume();
     208        switch (ToolSettings.getShape()) {
     209            case CIRCLE:
     210                ToolSettings.saveShape(ToolSettings.Shape.RECTANGLE);
     211                break;
     212            case RECTANGLE:
     213                ToolSettings.saveShape(ToolSettings.Shape.CIRCLE);
     214        }
    196215    }
    197216
    198217    @Override
  • src/org/openstreetmap/josm/plugins/buildings_tools/ToolSettings.java

     
    133133        Config.getPref().putBoolean("buildings_tools.autoselect_replace_selection", autoSelectReplace);
    134134    }
    135135
     136    /**
     137     * Check if we are toggling between {@link Shape} types if the user toggles the mapmode with a keypress
     138     * @return {@code true} if we want to change the shape type
     139     */
     140    public static boolean isTogglingBuildingTypeOnRepeatedKeyPress() {
     141        return Config.getPref().getBoolean("buildings_tools.toggle_building_type", false);
     142    }
     143
     144    /**
     145     * Set whether or not we are toggling between {@link Shape} types if the user toggles the mapmode with a keypress
     146     * @param toggle {@code true} if we want to change the shape type
     147     */
     148    public static void setTogglingBuildingTypeOnRepeatedKeyPress(boolean toggle) {
     149        Config.getPref().putBoolean("buildings_tools.toggle_building_type", toggle);
     150    }
     151
    136152    public static boolean isNoClickAndDrag() {
    137153        return Config.getPref().getBoolean("buildings_tools.noclickdrag", false);
    138154    }
  • test/unit/org/openstreetmap/josm/plugins/buildings_tools/BuildingsToolsPluginTest.java

     
     1package org.openstreetmap.josm.plugins.buildings_tools;
     2
     3import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
     4
     5import java.util.jar.Attributes;
     6
     7import org.junit.jupiter.api.Test;
     8import org.junit.jupiter.api.extension.RegisterExtension;
     9import org.openstreetmap.josm.data.osm.DataSet;
     10import org.openstreetmap.josm.gui.MainApplication;
     11import org.openstreetmap.josm.gui.layer.Layer;
     12import org.openstreetmap.josm.gui.layer.LayerManager;
     13import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     14import org.openstreetmap.josm.plugins.PluginException;
     15import org.openstreetmap.josm.plugins.PluginInformation;
     16import org.openstreetmap.josm.testutils.JOSMTestRules;
     17import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
     18
     19/**
     20 * Test class for {@link BuildingsToolsPlugin}
     21 */
     22@BasicPreferences
     23class BuildingsToolsPluginTest {
     24    @RegisterExtension
     25    static JOSMTestRules rule = new JOSMTestRules().projection().main();
     26
     27    /**
     28     * This makes certain we don't have an IAE after removing last layer and adding a new one
     29     * @throws PluginException If something occurs during {@link PluginInformation} construction
     30     */
     31    @Test
     32    void testMapReinitialization() throws PluginException {
     33        final BuildingsToolsPlugin plugin =
     34                new BuildingsToolsPlugin(new PluginInformation(new Attributes(), "buildings_tools", "https://example.com"));
     35        MainApplication.getMainPanel().addMapFrameListener(plugin);
     36        try {
     37            final LayerManager layerManager = MainApplication.getLayerManager();
     38            for (int i = 0; i < 20; i++) {
     39                final Layer layer = new OsmDataLayer(new DataSet(), "testMapReinitialization", null);
     40                assertDoesNotThrow(() -> layerManager.addLayer(layer));
     41                assertDoesNotThrow(() -> layerManager.removeLayer(layer));
     42            }
     43        } finally {
     44            MainApplication.getMainPanel().removeMapFrameListener(plugin);
     45        }
     46    }
     47
     48}
     49 No newline at end of file
  • test/unit/org/openstreetmap/josm/plugins/buildings_tools/DrawBuildingActionTest.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.plugins.buildings_tools;
     3
     4import static org.junit.jupiter.api.Assertions.assertEquals;
     5import static org.junit.jupiter.api.Assertions.assertNotEquals;
     6import static org.junit.jupiter.api.Assertions.assertNotNull;
     7
     8import java.awt.event.KeyEvent;
     9import java.time.Instant;
     10
     11import javax.swing.JLabel;
     12import javax.swing.KeyStroke;
     13
     14import org.junit.jupiter.api.AfterAll;
     15import org.junit.jupiter.api.BeforeAll;
     16import org.junit.jupiter.api.extension.RegisterExtension;
     17import org.junit.jupiter.params.ParameterizedTest;
     18import org.junit.jupiter.params.provider.ValueSource;
     19import org.openstreetmap.josm.data.osm.DataSet;
     20import org.openstreetmap.josm.gui.MainApplication;
     21import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     22import org.openstreetmap.josm.testutils.JOSMTestRules;
     23import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
     24
     25/**
     26 * Test class for {@link DrawBuildingAction}
     27 */
     28@BasicPreferences
     29class DrawBuildingActionTest {
     30    @RegisterExtension
     31    static JOSMTestRules rule = new JOSMTestRules().main().projection();
     32
     33    private static DrawBuildingAction action;
     34
     35    @BeforeAll
     36    static void setup() {
     37        action = new DrawBuildingAction();
     38    }
     39
     40    @AfterAll
     41    static void tearDown() {
     42        action.destroy();
     43        action = null;
     44    }
     45
     46
     47    /**
     48     * Ensure that we are toggling the map mode properly
     49     */
     50    @ParameterizedTest
     51    @ValueSource(booleans = {false, true})
     52    void testToggle(boolean setToggle) {
     53        // Ensure we are showing the main map
     54        MainApplication.getLayerManager().addLayer(new OsmDataLayer(new DataSet(), "testToggle", null));
     55        ToolSettings.setTogglingBuildingTypeOnRepeatedKeyPress(setToggle);
     56        assertEquals(setToggle, ToolSettings.isTogglingBuildingTypeOnRepeatedKeyPress());
     57        final ToolSettings.Shape shape = ToolSettings.getShape();
     58        final KeyStroke keyStroke = action.getShortcut().getKeyStroke();
     59        MainApplication.getMap().selectMapMode(action);
     60        action.doKeyPressed(getKeyEvent(keyStroke));
     61        assertNotEquals(setToggle, shape == ToolSettings.getShape());
     62        action.doKeyPressed(getKeyEvent(keyStroke));
     63        assertEquals(shape, ToolSettings.getShape());
     64    }
     65
     66    /**
     67     * Get a key event to send the action
     68     * @param keyStroke The keystroke to use
     69     * @return The event
     70     */
     71    private KeyEvent getKeyEvent(KeyStroke keyStroke) {
     72        assertNotNull(keyStroke);
     73        return new KeyEvent(new JLabel(), KeyEvent.KEY_PRESSED, Instant.now().toEpochMilli(),
     74                keyStroke.getModifiers(), keyStroke.getKeyCode(), keyStroke.getKeyChar());
     75    }
     76}