Ticket #21825: 21825.7.patch

File 21825.7.patch, 11.7 KB (added by taylor.smock, 3 years ago)

Restrict patch to only empty relations with no tags, add missing @since xxx

  • src/org/openstreetmap/josm/data/osm/IRelation.java

    diff --git a/src/org/openstreetmap/josm/data/osm/IRelation.java b/src/org/openstreetmap/josm/data/osm/IRelation.java
    index 6d59bd427a..9a7897d36f 100644
    a b public interface IRelation<M extends IRelationMember<?>> extends IPrimitive {  
    138140        return getMembers().stream().filter(rmv -> role.equals(rmv.getRole()))
    139141                .map(IRelationMember::getMember).collect(Collectors.toList());
    140142    }
     143
     144    /**
     145     * Check if this relation is useful
     146     * @return {@code true} if this relation is useful
     147     * @since xxx
     148     */
     149    default boolean isUseful() {
     150        return !this.isEmpty() && this.hasKeys();
     151    }
    141152}
  • src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java b/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
    index 743e05f4e0..f597a078c0 100644
    a b import javax.swing.JTabbedPane;  
    4747import javax.swing.JTable;
    4848import javax.swing.JToolBar;
    4949import javax.swing.KeyStroke;
     50import javax.swing.event.TableModelListener;
    5051
    5152import org.openstreetmap.josm.actions.JosmAction;
    5253import org.openstreetmap.josm.command.ChangeMembersCommand;
    import org.openstreetmap.josm.command.Command;  
    5455import org.openstreetmap.josm.data.UndoRedoHandler;
    5556import org.openstreetmap.josm.data.UndoRedoHandler.CommandQueueListener;
    5657import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
     58import org.openstreetmap.josm.data.osm.IRelation;
    5759import org.openstreetmap.josm.data.osm.OsmPrimitive;
    5860import org.openstreetmap.josm.data.osm.Relation;
    5961import org.openstreetmap.josm.data.osm.RelationMember;
    public class GenericRelationEditor extends RelationEditor implements CommandQueu  
    132134    private final SelectionTableModel selectionTableModel;
    133135
    134136    private final AutoCompletingTextField tfRole;
     137    private final RelationEditorActionAccess actionAccess;
    135138
    136139    /**
    137140     * the menu item in the windows menu. Required to properly hide on dialog close.
    public class GenericRelationEditor extends RelationEditor implements CommandQueu  
    262265            selectedTabPane = sourceTabbedPane.getSelectedComponent();
    263266        });
    264267
    265         IRelationEditorActionAccess actionAccess = new RelationEditorActionAccess();
     268        actionAccess = new RelationEditorActionAccess();
    266269
    267270        refreshAction = new RefreshAction(actionAccess);
    268271        applyAction = new ApplyAction(actionAccess);
    269272        selectAction = new SelectAction(actionAccess);
    270273        duplicateAction = new DuplicateRelationAction(actionAccess);
    271274        deleteAction = new DeleteCurrentRelationAction(actionAccess);
     275
     276        this.memberTableModel.addTableModelListener(applyAction);
     277        this.tagEditorPanel.getModel().addTableModelListener(applyAction);
     278
    272279        addPropertyChangeListener(deleteAction);
    273280
    274281        okAction = new OKAction(actionAccess);
    public class GenericRelationEditor extends RelationEditor implements CommandQueu  
    276283
    277284        getContentPane().add(buildToolBar(refreshAction, applyAction, selectAction, duplicateAction, deleteAction), BorderLayout.NORTH);
    278285        getContentPane().add(tabbedPane, BorderLayout.CENTER);
    279         getContentPane().add(buildOkCancelButtonPanel(okAction, cancelAction), BorderLayout.SOUTH);
     286        getContentPane().add(buildOkCancelButtonPanel(okAction, deleteAction, cancelAction), BorderLayout.SOUTH);
    280287
    281288        setSize(findMaxDialogSize());
    282289
    public class GenericRelationEditor extends RelationEditor implements CommandQueu  
    407414     *
    408415     * @return the panel with the OK and the Cancel button
    409416     */
    410     protected static JPanel buildOkCancelButtonPanel(OKAction okAction, CancelAction cancelAction) {
    411         JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
    412         pnl.add(new JButton(okAction));
     417    protected final JPanel buildOkCancelButtonPanel(OKAction okAction, DeleteCurrentRelationAction deleteAction,
     418            CancelAction cancelAction) {
     419        final JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER));
     420        final JButton okButton = new JButton(okAction);
     421        final JButton deleteButton = new JButton(deleteAction);
     422        okButton.setPreferredSize(deleteButton.getPreferredSize());
     423        pnl.add(okButton);
     424        pnl.add(deleteButton);
    413425        pnl.add(new JButton(cancelAction));
    414426        pnl.add(new JButton(new ContextSensitiveHelpAction(ht("/Dialog/RelationEditor"))));
     427        // Keep users from saving invalid relations -- a relation MUST have at least a tag with the key "type"
     428        // AND must contain at least one other OSM object.
     429        final TableModelListener listener = l -> updateOkPanel(this.actionAccess.getChangedRelation(), okButton, deleteButton);
     430        listener.tableChanged(null);
     431        this.memberTableModel.addTableModelListener(listener);
     432        this.tagEditorPanel.getModel().addTableModelListener(listener);
    415433        return pnl;
    416434    }
    417435
     436    /**
     437     * Update the OK panel area
     438     * @param newRelation What the new relation would "look" like if it were to be saved now
     439     * @param okButton The OK button
     440     * @param deleteButton The delete button
     441     */
     442    private void updateOkPanel(IRelation<?> newRelation, JButton okButton, JButton deleteButton) {
     443        okButton.setVisible(newRelation.isUseful() || this.getRelationSnapshot() == null);
     444        deleteButton.setVisible(!newRelation.isUseful() && this.getRelationSnapshot() != null);
     445        if (this.getRelationSnapshot() == null && !newRelation.isUseful()) {
     446            okButton.setText(tr("Delete"));
     447        } else {
     448            okButton.setText(tr("OK"));
     449        }
     450    }
     451
    418452    /**
    419453     * builds the panel with the tag editor
    420454     * @param tagEditorPanel tag editor panel
    public class GenericRelationEditor extends RelationEditor implements CommandQueu  
    10011035        @Override
    10021036        public void mouseClicked(MouseEvent e) {
    10031037            if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
    1004                 new EditAction(new RelationEditorActionAccess()).actionPerformed(null);
     1038                new EditAction(actionAccess).actionPerformed(null);
    10051039            }
    10061040        }
    10071041    }
  • src/org/openstreetmap/josm/gui/dialogs/relation/actions/ApplyAction.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/ApplyAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/ApplyAction.java
    index 7ddfae63ac..0b65d27cb5 100644
    a b public class ApplyAction extends SavingAction {  
    3535
    3636    @Override
    3737    public void updateEnabledState() {
    38         setEnabled(isEditorDirty());
     38        setEnabled(this.editorAccess.getChangedRelation().isUseful() && isEditorDirty());
    3939    }
    4040}
  • src/org/openstreetmap/josm/gui/dialogs/relation/actions/CancelAction.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CancelAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CancelAction.java
    index 6efdaeabdf..a51be40834 100644
    a b import java.awt.event.ActionEvent;  
    88import javax.swing.JOptionPane;
    99import javax.swing.RootPaneContainer;
    1010
     11import org.openstreetmap.josm.data.osm.IRelation;
    1112import org.openstreetmap.josm.data.osm.Relation;
    1213import org.openstreetmap.josm.gui.HelpAwareOptionPane;
    1314import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
    public class CancelAction extends SavingAction {  
    4748        if ((!getMemberTableModel().hasSameMembersAs(snapshot) || getTagModel().isDirty())
    4849         && !(snapshot == null && getTagModel().getTags().isEmpty())) {
    4950            //give the user a chance to save the changes
    50             int ret = confirmClosingByCancel();
     51            int ret = confirmClosingByCancel(this.editorAccess.getChangedRelation());
    5152            if (ret == 0) { //Yes, save the changes
    5253                //copied from OKAction.run()
    5354                Config.getPref().put("relation.editor.generic.lastrole", Utils.strip(tfRole.getText()));
    public class CancelAction extends SavingAction {  
    6061        hideEditor();
    6162    }
    6263
    63     protected int confirmClosingByCancel() {
     64    protected int confirmClosingByCancel(final IRelation<?> newRelation) {
    6465        ButtonSpec[] options = {
    6566                new ButtonSpec(
    6667                        tr("Yes, save the changes and close"),
    public class CancelAction extends SavingAction {  
    8283                )
    8384        };
    8485
     86        // Keep users from saving invalid relations -- a relation MUST have at least a tag with the key "type"
     87        // AND must contain at least one other OSM object.
     88        options[0].setEnabled(newRelation.isUseful());
     89
    8590        return HelpAwareOptionPane.showOptionDialog(
    8691                MainApplication.getMainFrame(),
    8792                tr("<html>The relation has been changed.<br><br>Do you want to save your changes?</html>"),
  • src/org/openstreetmap/josm/gui/dialogs/relation/actions/IRelationEditorActionAccess.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/IRelationEditorActionAccess.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/IRelationEditorActionAccess.java
    index cddedaf165..b1b79a3128 100644
    a b package org.openstreetmap.josm.gui.dialogs.relation.actions;  
    33
    44import javax.swing.Action;
    55
     6import org.openstreetmap.josm.data.osm.IRelation;
     7import org.openstreetmap.josm.data.osm.Relation;
    68import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor;
    79import org.openstreetmap.josm.gui.dialogs.relation.MemberTable;
    810import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel;
    public interface IRelationEditorActionAccess {  
    6567     */
    6668    TagEditorModel getTagModel();
    6769
     70    /**
     71     * Get the changed relation
     72     * @return The changed relation (note: will not be part of a dataset). This should never be {@code null}.
     73     * @since xxx
     74     */
     75    default IRelation<?> getChangedRelation() {
     76        final Relation newRelation;
     77        if (getEditor().getRelation() != null) {
     78            newRelation = new Relation(getEditor().getRelation());
     79        } else {
     80            newRelation = new Relation();
     81        }
     82        getTagModel().applyToPrimitive(newRelation);
     83        getMemberTableModel().applyToRelation(newRelation);
     84        return newRelation;
     85    }
     86
    6887    /**
    6988     * Get the text field that is used to edit the role.
    7089     * @return The role text field.
  • src/org/openstreetmap/josm/gui/dialogs/relation/actions/SavingAction.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/SavingAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/SavingAction.java
    index 26813f23c1..35ca1dcfb7 100644
    a b abstract class SavingAction extends AbstractRelationEditorAction {  
    5454        tagEditorModel.applyToPrimitive(newRelation);
    5555        getMemberTableModel().applyToRelation(newRelation);
    5656        // If the user wanted to create a new relation, but hasn't added any members or
    57         // tags, don't add an empty relation
    58         if (newRelation.isEmpty() && !newRelation.hasKeys())
     57        // tags (specifically the "type" tag), don't add the relation
     58        if (!newRelation.isUseful())
    5959            return;
    6060        UndoRedoHandler.getInstance().add(new AddCommand(getLayer().getDataSet(), newRelation));
    6161