Ticket #12410: RefreshRelationEditor.patch

File RefreshRelationEditor.patch, 21.3 KB (added by kolesar, 5 years ago)
  • 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 be435fc..77a0643 100644
    a b import org.openstreetmap.josm.gui.dialogs.relation.actions.OKAction; 
    7878import org.openstreetmap.josm.gui.dialogs.relation.actions.PasteMembersAction;
    7979import org.openstreetmap.josm.gui.dialogs.relation.actions.RemoveAction;
    8080import org.openstreetmap.josm.gui.dialogs.relation.actions.RemoveSelectedAction;
     81import org.openstreetmap.josm.gui.dialogs.relation.actions.RefreshAction;
    8182import org.openstreetmap.josm.gui.dialogs.relation.actions.ReverseAction;
    8283import org.openstreetmap.josm.gui.dialogs.relation.actions.SelectPrimitivesForSelectedMembersAction;
    8384import org.openstreetmap.josm.gui.dialogs.relation.actions.SelectedMembersForSelectionAction;
    public class GenericRelationEditor extends RelationEditor { 
    127128     */
    128129    private JButton sortBelowButton;
    129130    /**
     131     * Action for performing the {@link RefreshAction}
     132     */
     133    private RefreshAction refreshAction;
     134    /**
     135     * Action for performing the {@link ApplyAction}
     136     */
     137    private ApplyAction applyAction;
     138    /**
    130139     * Action for performing the {@link CancelAction}
    131140     */
    132141    private CancelAction cancelAction;
    public class GenericRelationEditor extends RelationEditor { 
    171180        referrerModel = new ReferringRelationsBrowserModel(relation);
    172181
    173182        tagEditorPanel = new TagEditorPanel(relation, presetHandler);
    174 
    175         // populate the models
    176         //
    177         if (relation != null) {
    178             tagEditorPanel.getModel().initFromPrimitive(relation);
    179             this.memberTableModel.populate(relation);
    180             if (!getLayer().data.getRelations().contains(relation)) {
    181                 // treat it as a new relation if it doesn't exist in the
    182                 // data set yet.
    183                 setRelation(null);
    184             }
    185         } else {
    186             tagEditorPanel.getModel().clear();
    187             this.memberTableModel.populate(null);
    188         }
     183        populateModels(relation);
    189184        tagEditorPanel.getModel().ensureOneTag();
    190185
    191186        JSplitPane pane = buildSplitPane();
    public class GenericRelationEditor extends RelationEditor { 
    258253        HelpUtil.setHelpContext(getRootPane(), ht("/Dialog/RelationEditor"));
    259254    }
    260255
    261     protected void cancel() {
     256    public void reloadDataFromRelation() {
     257        setRelation(getRelation());
     258        populateModels(getRelation());
     259        refreshAction.updateEnabledState();
     260    }
     261
     262    private void populateModels(Relation relation) {
     263        if (relation != null) {
     264            tagEditorPanel.getModel().initFromPrimitive(relation);
     265            this.memberTableModel.populate(relation);
     266            if (!getLayer().data.getRelations().contains(relation)) {
     267                // treat it as a new relation if it doesn't exist in the
     268                // data set yet.
     269                setRelation(null);
     270            }
     271        } else {
     272            tagEditorPanel.getModel().clear();
     273            this.memberTableModel.populate(null);
     274        }
     275    }
     276
     277    public void apply() {
     278        applyAction.actionPerformed(null);
     279    }
     280
     281    public void cancel() {
    262282        cancelAction.actionPerformed(null);
    263283    }
    264284
    public class GenericRelationEditor extends RelationEditor { 
    270290    protected JToolBar buildToolBar() {
    271291        JToolBar tb  = new JToolBar();
    272292        tb.setFloatable(false);
    273         tb.add(new ApplyAction(memberTable, memberTableModel, tagEditorPanel.getModel(), getLayer(), this));
     293        tb.add(refreshAction = new RefreshAction(memberTable, memberTableModel, tagEditorPanel.getModel(), getLayer(), this));
     294        tb.add(applyAction = new ApplyAction(memberTable, memberTableModel, tagEditorPanel.getModel(), getLayer(), this));
    274295        tb.add(new DuplicateRelationAction(memberTableModel, tagEditorPanel.getModel(), getLayer()));
    275296        DeleteCurrentRelationAction deleteAction = new DeleteCurrentRelationAction(getLayer(), this);
    276297        addPropertyChangeListener(deleteAction);
  • src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java b/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
    index 06bad08..cd6a190 100644
    a b implements TableModelListener, SelectionChangedListener, DataSetListener, OsmPri 
    234234            return;
    235235        }
    236236        RelationMember member = members.get(rowIndex);
    237         RelationMember newMember = new RelationMember(value.toString(), member.getMember());
     237        String role = value.toString();
     238        if (member.hasRole(role)) return;
     239        RelationMember newMember = new RelationMember(role, member.getMember());
    238240        members.remove(rowIndex);
    239241        members.add(rowIndex, newMember);
     242        fireTableDataChanged();
    240243    }
    241244
    242245    @Override
  • 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 0e68e10..3777829 100644
    a b package org.openstreetmap.josm.gui.dialogs.relation.actions; 
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.Component;
    76import java.awt.event.ActionEvent;
    87
     8import java.beans.PropertyChangeEvent;
     9import java.beans.PropertyChangeListener;
     10
     11import javax.swing.event.TableModelEvent;
     12import javax.swing.event.TableModelListener;
     13
     14import org.openstreetmap.josm.gui.dialogs.relation.GenericRelationEditor;
    915import org.openstreetmap.josm.gui.dialogs.relation.MemberTable;
    1016import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel;
    1117import org.openstreetmap.josm.gui.dialogs.relation.RelationAware;
    import org.openstreetmap.josm.tools.ImageProvider; 
    1723 * Apply the current updates.
    1824 * @since 9496
    1925 */
    20 public class ApplyAction extends SavingAction {
     26public class ApplyAction extends SavingAction implements PropertyChangeListener, TableModelListener {
    2127
    2228    /**
    2329     * Constructs a new {@code ApplyAction}.
    public class ApplyAction extends SavingAction { 
    3339        putValue(SHORT_DESCRIPTION, tr("Apply the current updates"));
    3440        putValue(SMALL_ICON, ImageProvider.get("save"));
    3541        putValue(NAME, tr("Apply"));
    36         setEnabled(true);
     42        updateEnabledState();
     43        memberTableModel.addTableModelListener(this);
     44        tagModel.addPropertyChangeListener(this);
    3745    }
    3846
    3947    @Override
    4048    public void actionPerformed(ActionEvent e) {
    41         if (editor.getRelation() == null) {
    42             applyNewRelation(tagModel);
    43         } else if (!memberTableModel.hasSameMembersAs(editor.getRelationSnapshot()) || tagModel.isDirty()) {
    44             if (editor.isDirtyRelation()) {
    45                 if (confirmClosingBecauseOfDirtyState()) {
    46                     if (layer.getConflicts().hasConflictForMy(editor.getRelation())) {
    47                         warnDoubleConflict();
    48                         return;
    49                     }
    50                     applyExistingConflictingRelation(tagModel);
    51                     if (editor instanceof Component) {
    52                         ((Component) editor).setVisible(false);
    53                     }
    54                 }
    55             } else {
    56                 applyExistingNonConflictingRelation(tagModel);
    57             }
     49        if (applyChanges()) {
     50            ((GenericRelationEditor) editor).reloadDataFromRelation();
    5851        }
    5952    }
     53
     54    @Override
     55    protected void updateEnabledState() {
     56        setEnabled(isEditorDirty());
     57    }
     58
     59    @Override
     60    public void propertyChange(PropertyChangeEvent evt) {
     61        updateEnabledState();
     62    }
     63
     64    @Override
     65    public void tableChanged(TableModelEvent e) {
     66        updateEnabledState();
     67    }
    6068}
  • 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 980d5a5..8632285 100644
    a b package org.openstreetmap.josm.gui.dialogs.relation.actions; 
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.Component;
    76import java.awt.event.ActionEvent;
    87
    98import javax.swing.JComponent;
    public class CancelAction extends SavingAction { 
    6564            if (ret == 0) { //Yes, save the changes
    6665                //copied from OKAction.run()
    6766                Main.pref.put("relation.editor.generic.lastrole", tfRole.getText());
    68                 if (editor.getRelation() == null) {
    69                     applyNewRelation(tagModel);
    70                 } else if (!memberTableModel.hasSameMembersAs(snapshot) || tagModel.isDirty()) {
    71                     if (editor.isDirtyRelation()) {
    72                         if (confirmClosingBecauseOfDirtyState()) {
    73                             if (layer.getConflicts().hasConflictForMy(editor.getRelation())) {
    74                                 warnDoubleConflict();
    75                                 return;
    76                             }
    77                             applyExistingConflictingRelation(tagModel);
    78                         } else
    79                             return;
    80                     } else {
    81                         applyExistingNonConflictingRelation(tagModel);
    82                     }
    83                 }
     67                if (!applyChanges()) return;
    8468            } else if (ret == 2 || ret == JOptionPane.CLOSED_OPTION) //Cancel, continue editing
    8569                return;
    8670            //in case of "No, discard", there is no extra action to be performed here.
    8771        }
    88         if (editor instanceof Component) {
    89             ((Component) editor).setVisible(false);
    90         }
     72        hideEditor();
    9173    }
    9274
    9375    protected int confirmClosingByCancel() {
  • src/org/openstreetmap/josm/gui/dialogs/relation/actions/OKAction.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/OKAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/OKAction.java
    index 0cc65f3..5df5c69 100644
    a b package org.openstreetmap.josm.gui.dialogs.relation.actions; 
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.Component;
    76import java.awt.event.ActionEvent;
    87
    98import org.openstreetmap.josm.Main;
    public class OKAction extends SavingAction { 
    4241    public void actionPerformed(ActionEvent e) {
    4342        Main.pref.put("relation.editor.generic.lastrole", tfRole.getText());
    4443        memberTable.stopHighlighting();
    45         if (editor.getRelation() == null) {
    46             applyNewRelation(tagModel);
    47         } else if (!memberTableModel.hasSameMembersAs(editor.getRelationSnapshot()) || tagModel.isDirty()) {
    48             if (editor.isDirtyRelation()) {
    49                 if (confirmClosingBecauseOfDirtyState()) {
    50                     if (layer.getConflicts().hasConflictForMy(editor.getRelation())) {
    51                         warnDoubleConflict();
    52                         return;
    53                     }
    54                     applyExistingConflictingRelation(tagModel);
    55                 } else
    56                     return;
    57             } else {
    58                 applyExistingNonConflictingRelation(tagModel);
    59             }
    60         }
    61         if (editor instanceof Component) {
    62             ((Component) editor).setVisible(false);
    63         }
     44        if (!applyChanges()) return;
     45        hideEditor();
    6446    }
    6547}
  • new file src/org/openstreetmap/josm/gui/dialogs/relation/actions/RefreshAction.java

    diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/RefreshAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/RefreshAction.java
    new file mode 100644
    index 0000000..5734311
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.dialogs.relation.actions;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.awt.Component;
     7import java.awt.event.ActionEvent;
     8import java.awt.event.KeyEvent;
     9
     10import javax.swing.JComponent;
     11import javax.swing.JOptionPane;
     12
     13import org.openstreetmap.josm.Main;
     14import org.openstreetmap.josm.data.osm.Relation;
     15import org.openstreetmap.josm.gui.dialogs.relation.GenericRelationEditor;
     16import org.openstreetmap.josm.gui.dialogs.relation.MemberTable;
     17import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel;
     18import org.openstreetmap.josm.gui.dialogs.relation.RelationAware;
     19import org.openstreetmap.josm.gui.HelpAwareOptionPane;
     20import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
     21import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     22import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
     23import org.openstreetmap.josm.gui.tagging.TagEditorModel;
     24import org.openstreetmap.josm.tools.ImageProvider;
     25import org.openstreetmap.josm.tools.Shortcut;
     26
     27/**
     28 * Refresh relation.
     29 */
     30public class RefreshAction extends SavingAction implements CommandQueueListener {
     31
     32    /**
     33     * Constructs a new {@code ApplyAction}.
     34     * @param memberTable member table
     35     * @param memberTableModel member table model
     36     * @param layer OSM data layer
     37     * @param editor relation editor
     38     * @param tagModel tag editor model
     39     */
     40    public RefreshAction(MemberTable memberTable, MemberTableModel memberTableModel, TagEditorModel tagModel, OsmDataLayer layer,
     41            RelationAware editor) {
     42        super(memberTable, memberTableModel, tagModel, layer, editor, null);
     43        Shortcut sc = Shortcut.registerShortcut("relationeditor:refresh", tr("Relation Editor: Refresh"), KeyEvent.CHAR_UNDEFINED, Shortcut.NONE);
     44        putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tr("Refresh relation from data layer"), sc));
     45        putValue(SMALL_ICON, ImageProvider.get("dialogs/refresh"));
     46        putValue(NAME, tr("Refresh"));
     47        getEditor().getRootPane().getActionMap().put("refresh", this);
     48        getEditor().getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), "refresh");
     49        Main.main.undoRedo.addCommandQueueListener(this);
     50        updateEnabledState();
     51    }
     52
     53    private GenericRelationEditor getEditor() {
     54        return (GenericRelationEditor) editor;
     55    }
     56
     57    @Override
     58    public void actionPerformed(ActionEvent e) {
     59        Relation relation = editor.getRelation();
     60        if (relation == null) return;
     61        if (relation.isDeleted()) {
     62            if (confirmCloseDeletedRelation() == 0) {
     63                hideEditor();
     64            }
     65            return;
     66        }
     67        if (isEditorDirty() && confirmDiscardDirtyData() != 0) return;
     68        getEditor().reloadDataFromRelation();
     69    }
     70
     71    @Override
     72    public void updateEnabledState() {
     73        Relation relation = editor.getRelation();
     74        Relation snapshot = editor.getRelationSnapshot();
     75        setEnabled(snapshot != null && (
     76            !relation.hasEqualTechnicalAttributes(snapshot) ||
     77            !relation.hasEqualSemanticAttributes(snapshot)
     78        ));
     79    }
     80
     81    protected int confirmDiscardDirtyData() {
     82        ButtonSpec[] options = new ButtonSpec[] {
     83                new ButtonSpec(
     84                        tr("Yes, discard changes and reload"),
     85                        ImageProvider.get("ok"),
     86                        tr("Click to discard the changes and reload data from layer"),
     87                        null /* no specific help topic */
     88                ),
     89                new ButtonSpec(
     90                        tr("Cancel, continue editing"),
     91                        ImageProvider.get("cancel"),
     92                        tr("Click to return to the relation editor and to resume relation editing"),
     93                        null /* no specific help topic */
     94                )
     95        };
     96
     97        return HelpAwareOptionPane.showOptionDialog(
     98                Main.parent,
     99                tr("<html>You have unsaved changes in this editor window.<br><br>Do you want to discard these changes and reload data from layer?</html>"),
     100                        tr("Unsaved changes"),
     101                        JOptionPane.WARNING_MESSAGE,
     102                        null,
     103                        options,
     104                        options[1], // Cancel is default
     105                        "/Dialog/RelationEditor#Reload"
     106        );
     107    }
     108
     109    protected int confirmCloseDeletedRelation() {
     110        ButtonSpec[] options = new ButtonSpec[] {
     111                new ButtonSpec(
     112                        tr("Yes"),
     113                        ImageProvider.get("ok"),
     114                        tr("Click to close window"),
     115                        null /* no specific help topic */
     116                ),
     117                new ButtonSpec(
     118                        tr("No, continue editing"),
     119                        ImageProvider.get("cancel"),
     120                        tr("Click to return to the relation editor and to resume relation editing"),
     121                        null /* no specific help topic */
     122                )
     123        };
     124
     125        return HelpAwareOptionPane.showOptionDialog(
     126                Main.parent,
     127                tr("<html>Relation has been deleted outside editor.<br><br>Do you want to close this window?</html>"),
     128                        tr("Deleted relation"),
     129                        JOptionPane.WARNING_MESSAGE,
     130                        null,
     131                        options,
     132                        options[0], // Yes is default
     133                        "/Dialog/RelationEditor#Reload"
     134        );
     135    }
     136
     137    @Override
     138    public void commandChanged(int queueSize, int redoSize) {
     139        updateEnabledState();
     140    }
     141}
  • 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 e7525d2..96c51af 100644
    a b package org.openstreetmap.josm.gui.dialogs.relation.actions; 
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
     6import java.awt.Component;
    67import java.util.ArrayList;
    78import java.util.List;
    89
    abstract class SavingAction extends AbstractRelationEditorAction { 
    110111        memberTableModel.applyToRelation(editedRelation);
    111112        Main.main.undoRedo.add(new ChangeCommand(editor.getRelation(), editedRelation));
    112113        layer.data.fireSelectionChanged();
    113         // this will refresh the snapshot and update the dialog title
    114         //
    115         editor.setRelation(editor.getRelation());
    116114    }
    117115
    118116    protected boolean confirmClosingBecauseOfDirtyState() {
    abstract class SavingAction extends AbstractRelationEditorAction { 
    165163    protected void updateEnabledState() {
    166164        // Do nothing
    167165    }
     166
     167    protected boolean applyChanges() {
     168        if (editor.getRelation() == null) {
     169            applyNewRelation(tagModel);
     170        } else if (isEditorDirty()) {
     171            if (editor.isDirtyRelation()) {
     172                if (confirmClosingBecauseOfDirtyState()) {
     173                    if (layer.getConflicts().hasConflictForMy(editor.getRelation())) {
     174                        warnDoubleConflict();
     175                        return false;
     176                    }
     177                    applyExistingConflictingRelation(tagModel);
     178                    hideEditor();
     179                } else
     180                    return false;
     181            } else {
     182                applyExistingNonConflictingRelation(tagModel);
     183            }
     184        }
     185        editor.setRelation(editor.getRelation());
     186        return true;
     187    }
     188
     189    protected void hideEditor() {
     190        if (editor instanceof Component) {
     191            ((Component) editor).setVisible(false);
     192        }
     193    }
     194
     195    protected boolean isEditorDirty() {
     196        Relation snapshot = editor.getRelationSnapshot();
     197        return (snapshot != null && !memberTableModel.hasSameMembersAs(snapshot)) || tagModel.isDirty();
     198    }
    168199}
  • src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java

    diff --git a/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java b/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java
    index 6ad4926..954f42c 100644
    a b public class TagEditorModel extends AbstractTableModel { 
    165165     * removes all tags in the model
    166166     */
    167167    public void clear() {
     168        boolean wasEmpty = tags.isEmpty();
    168169        tags.clear();
    169         setDirty(true);
    170         fireTableDataChanged();
     170        if (!wasEmpty) {
     171            setDirty(true);
     172            fireTableDataChanged();
     173        }
    171174    }
    172175
    173176    /**
    public class TagEditorModel extends AbstractTableModel { 
    334337        TagModel tag = new TagModel();
    335338        tags.add(tag);
    336339        fireTableDataChanged();
    337         setDirty(true);
    338340    }
    339341
    340342    /**