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 {
|
| 138 | 140 | return getMembers().stream().filter(rmv -> role.equals(rmv.getRole())) |
| 139 | 141 | .map(IRelationMember::getMember).collect(Collectors.toList()); |
| 140 | 142 | } |
| | 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 | } |
| 141 | 152 | } |
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;
|
| 47 | 47 | import javax.swing.JTable; |
| 48 | 48 | import javax.swing.JToolBar; |
| 49 | 49 | import javax.swing.KeyStroke; |
| | 50 | import javax.swing.event.TableModelListener; |
| 50 | 51 | |
| 51 | 52 | import org.openstreetmap.josm.actions.JosmAction; |
| 52 | 53 | import org.openstreetmap.josm.command.ChangeMembersCommand; |
| … |
… |
import org.openstreetmap.josm.command.Command;
|
| 54 | 55 | import org.openstreetmap.josm.data.UndoRedoHandler; |
| 55 | 56 | import org.openstreetmap.josm.data.UndoRedoHandler.CommandQueueListener; |
| 56 | 57 | import org.openstreetmap.josm.data.osm.DefaultNameFormatter; |
| | 58 | import org.openstreetmap.josm.data.osm.IRelation; |
| 57 | 59 | import org.openstreetmap.josm.data.osm.OsmPrimitive; |
| 58 | 60 | import org.openstreetmap.josm.data.osm.Relation; |
| 59 | 61 | import org.openstreetmap.josm.data.osm.RelationMember; |
| … |
… |
public class GenericRelationEditor extends RelationEditor implements CommandQueu
|
| 132 | 134 | private final SelectionTableModel selectionTableModel; |
| 133 | 135 | |
| 134 | 136 | private final AutoCompletingTextField tfRole; |
| | 137 | private final RelationEditorActionAccess actionAccess; |
| 135 | 138 | |
| 136 | 139 | /** |
| 137 | 140 | * the menu item in the windows menu. Required to properly hide on dialog close. |
| … |
… |
public class GenericRelationEditor extends RelationEditor implements CommandQueu
|
| 262 | 265 | selectedTabPane = sourceTabbedPane.getSelectedComponent(); |
| 263 | 266 | }); |
| 264 | 267 | |
| 265 | | IRelationEditorActionAccess actionAccess = new RelationEditorActionAccess(); |
| | 268 | actionAccess = new RelationEditorActionAccess(); |
| 266 | 269 | |
| 267 | 270 | refreshAction = new RefreshAction(actionAccess); |
| 268 | 271 | applyAction = new ApplyAction(actionAccess); |
| 269 | 272 | selectAction = new SelectAction(actionAccess); |
| 270 | 273 | duplicateAction = new DuplicateRelationAction(actionAccess); |
| 271 | 274 | deleteAction = new DeleteCurrentRelationAction(actionAccess); |
| | 275 | |
| | 276 | this.memberTableModel.addTableModelListener(applyAction); |
| | 277 | this.tagEditorPanel.getModel().addTableModelListener(applyAction); |
| | 278 | |
| 272 | 279 | addPropertyChangeListener(deleteAction); |
| 273 | 280 | |
| 274 | 281 | okAction = new OKAction(actionAccess); |
| … |
… |
public class GenericRelationEditor extends RelationEditor implements CommandQueu
|
| 276 | 283 | |
| 277 | 284 | getContentPane().add(buildToolBar(refreshAction, applyAction, selectAction, duplicateAction, deleteAction), BorderLayout.NORTH); |
| 278 | 285 | getContentPane().add(tabbedPane, BorderLayout.CENTER); |
| 279 | | getContentPane().add(buildOkCancelButtonPanel(okAction, cancelAction), BorderLayout.SOUTH); |
| | 286 | getContentPane().add(buildOkCancelButtonPanel(okAction, deleteAction, cancelAction), BorderLayout.SOUTH); |
| 280 | 287 | |
| 281 | 288 | setSize(findMaxDialogSize()); |
| 282 | 289 | |
| … |
… |
public class GenericRelationEditor extends RelationEditor implements CommandQueu
|
| 407 | 414 | * |
| 408 | 415 | * @return the panel with the OK and the Cancel button |
| 409 | 416 | */ |
| 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); |
| 413 | 425 | pnl.add(new JButton(cancelAction)); |
| 414 | 426 | 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); |
| 415 | 433 | return pnl; |
| 416 | 434 | } |
| 417 | 435 | |
| | 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 | |
| 418 | 452 | /** |
| 419 | 453 | * builds the panel with the tag editor |
| 420 | 454 | * @param tagEditorPanel tag editor panel |
| … |
… |
public class GenericRelationEditor extends RelationEditor implements CommandQueu
|
| 1001 | 1035 | @Override |
| 1002 | 1036 | public void mouseClicked(MouseEvent e) { |
| 1003 | 1037 | if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { |
| 1004 | | new EditAction(new RelationEditorActionAccess()).actionPerformed(null); |
| | 1038 | new EditAction(actionAccess).actionPerformed(null); |
| 1005 | 1039 | } |
| 1006 | 1040 | } |
| 1007 | 1041 | } |
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 {
|
| 35 | 35 | |
| 36 | 36 | @Override |
| 37 | 37 | public void updateEnabledState() { |
| 38 | | setEnabled(isEditorDirty()); |
| | 38 | setEnabled(this.editorAccess.getChangedRelation().isUseful() && isEditorDirty()); |
| 39 | 39 | } |
| 40 | 40 | } |
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;
|
| 8 | 8 | import javax.swing.JOptionPane; |
| 9 | 9 | import javax.swing.RootPaneContainer; |
| 10 | 10 | |
| | 11 | import org.openstreetmap.josm.data.osm.IRelation; |
| 11 | 12 | import org.openstreetmap.josm.data.osm.Relation; |
| 12 | 13 | import org.openstreetmap.josm.gui.HelpAwareOptionPane; |
| 13 | 14 | import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec; |
| … |
… |
public class CancelAction extends SavingAction {
|
| 47 | 48 | if ((!getMemberTableModel().hasSameMembersAs(snapshot) || getTagModel().isDirty()) |
| 48 | 49 | && !(snapshot == null && getTagModel().getTags().isEmpty())) { |
| 49 | 50 | //give the user a chance to save the changes |
| 50 | | int ret = confirmClosingByCancel(); |
| | 51 | int ret = confirmClosingByCancel(this.editorAccess.getChangedRelation()); |
| 51 | 52 | if (ret == 0) { //Yes, save the changes |
| 52 | 53 | //copied from OKAction.run() |
| 53 | 54 | Config.getPref().put("relation.editor.generic.lastrole", Utils.strip(tfRole.getText())); |
| … |
… |
public class CancelAction extends SavingAction {
|
| 60 | 61 | hideEditor(); |
| 61 | 62 | } |
| 62 | 63 | |
| 63 | | protected int confirmClosingByCancel() { |
| | 64 | protected int confirmClosingByCancel(final IRelation<?> newRelation) { |
| 64 | 65 | ButtonSpec[] options = { |
| 65 | 66 | new ButtonSpec( |
| 66 | 67 | tr("Yes, save the changes and close"), |
| … |
… |
public class CancelAction extends SavingAction {
|
| 82 | 83 | ) |
| 83 | 84 | }; |
| 84 | 85 | |
| | 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 | |
| 85 | 90 | return HelpAwareOptionPane.showOptionDialog( |
| 86 | 91 | MainApplication.getMainFrame(), |
| 87 | 92 | tr("<html>The relation has been changed.<br><br>Do you want to save your changes?</html>"), |
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;
|
| 3 | 3 | |
| 4 | 4 | import javax.swing.Action; |
| 5 | 5 | |
| | 6 | import org.openstreetmap.josm.data.osm.IRelation; |
| | 7 | import org.openstreetmap.josm.data.osm.Relation; |
| 6 | 8 | import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor; |
| 7 | 9 | import org.openstreetmap.josm.gui.dialogs.relation.MemberTable; |
| 8 | 10 | import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel; |
| … |
… |
public interface IRelationEditorActionAccess {
|
| 65 | 67 | */ |
| 66 | 68 | TagEditorModel getTagModel(); |
| 67 | 69 | |
| | 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 | |
| 68 | 87 | /** |
| 69 | 88 | * Get the text field that is used to edit the role. |
| 70 | 89 | * @return The role text field. |
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 {
|
| 54 | 54 | tagEditorModel.applyToPrimitive(newRelation); |
| 55 | 55 | getMemberTableModel().applyToRelation(newRelation); |
| 56 | 56 | // 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()) |
| 59 | 59 | return; |
| 60 | 60 | UndoRedoHandler.getInstance().add(new AddCommand(getLayer().getDataSet(), newRelation)); |
| 61 | 61 | |