001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs.relation.actions;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.event.ActionEvent;
007import java.awt.event.KeyEvent;
008
009import javax.swing.JComponent;
010import javax.swing.JOptionPane;
011import javax.swing.JRootPane;
012
013import org.openstreetmap.josm.data.UndoRedoHandler;
014import org.openstreetmap.josm.data.UndoRedoHandler.CommandQueueListener;
015import org.openstreetmap.josm.data.osm.Relation;
016import org.openstreetmap.josm.gui.HelpAwareOptionPane;
017import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
018import org.openstreetmap.josm.gui.MainApplication;
019import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor;
020import org.openstreetmap.josm.tools.ImageProvider;
021import org.openstreetmap.josm.tools.Shortcut;
022
023/**
024 * Refresh relation.
025 * @since 9657
026 */
027public class RefreshAction extends SavingAction implements CommandQueueListener {
028    private static final long serialVersionUID = 1L;
029
030    /**
031     * Constructs a new {@code RefreshAction}.
032     * @param editorAccess An interface to access the relation editor contents.
033     */
034    public RefreshAction(IRelationEditorActionAccess editorAccess) {
035        super(editorAccess);
036        // CHECKSTYLE.OFF: LineLength
037        Shortcut sc = Shortcut.registerShortcut("relationeditor:refresh", tr("Relation Editor: Refresh"), KeyEvent.CHAR_UNDEFINED, Shortcut.NONE);
038        // CHECKSTYLE.ON: LineLength
039        sc.setTooltip(this, tr("Refresh relation from data layer"));
040        new ImageProvider("dialogs/refresh").getResource().attachImageIcon(this, true);
041        putValue(NAME, tr("Refresh"));
042        IRelationEditor editor = editorAccess.getEditor();
043        if (editor instanceof JComponent) {
044            JRootPane rootPane = ((JComponent) editor).getRootPane();
045            rootPane.getActionMap().put("refresh", this);
046            rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), "refresh");
047        }
048        UndoRedoHandler.getInstance().addCommandQueueListener(this);
049        updateEnabledState();
050    }
051
052    @Override
053    public void actionPerformed(ActionEvent e) {
054        Relation relation = editorAccess.getEditor().getRelation();
055        if (relation == null)
056            return;
057        if (relation.isDeleted()) {
058            if (confirmCloseDeletedRelation() == 0) {
059                hideEditor();
060            }
061            return;
062        }
063        if (isEditorDirty() && confirmDiscardDirtyData() != 0)
064            return;
065        editorAccess.getEditor().reloadDataFromRelation();
066    }
067
068    @Override
069    public void updateEnabledState() {
070        Relation snapshot = getEditor().getRelationSnapshot();
071        Relation relation = getEditor().getRelation();
072        if (relation != null && relation.getDataSet() == null)
073            relation = null; // see #19915
074        if (relation != null && snapshot != null && snapshot.getDataSet() == null) {
075            // relation was changed outside of the editor
076            // either it was modified or deleted or changed by an undo
077            setEnabled(!snapshot.hasEqualSemanticAttributes(relation, false /* don't ignore uninteresting keys */));
078            return;
079        }
080        setEnabled(false);
081    }
082
083    protected int confirmDiscardDirtyData() {
084        ButtonSpec[] options = {
085                new ButtonSpec(
086                        tr("Yes, discard changes and reload"),
087                        new ImageProvider("ok"),
088                        tr("Click to discard the changes and reload data from layer"),
089                        null /* no specific help topic */
090                ),
091                new ButtonSpec(
092                        tr("Cancel, continue editing"),
093                        new ImageProvider("cancel"),
094                        tr("Click to return to the relation editor and to resume relation editing"),
095                        null /* no specific help topic */
096                )
097        };
098
099        return HelpAwareOptionPane.showOptionDialog(
100                MainApplication.getMainFrame(),
101                tr("<html>You have unsaved changes in this editor window.<br>"+
102                   "<br>Do you want to discard these changes and reload data from layer?</html>"),
103                        tr("Unsaved changes"),
104                        JOptionPane.WARNING_MESSAGE,
105                        null,
106                        options,
107                        options[1], // Cancel is default
108                        "/Dialog/RelationEditor#Reload"
109        );
110    }
111
112    protected int confirmCloseDeletedRelation() {
113        ButtonSpec[] options = {
114                new ButtonSpec(
115                        tr("Yes"),
116                        new ImageProvider("ok"),
117                        tr("Click to close window"),
118                        null /* no specific help topic */
119                ),
120                new ButtonSpec(
121                        tr("No, continue editing"),
122                        new ImageProvider("cancel"),
123                        tr("Click to return to the relation editor and to resume relation editing"),
124                        null /* no specific help topic */
125                )
126        };
127
128        return HelpAwareOptionPane.showOptionDialog(
129                MainApplication.getMainFrame(),
130                tr("<html>Relation has been deleted outside editor.<br><br>Do you want to close this window?</html>"),
131                        tr("Deleted relation"),
132                        JOptionPane.WARNING_MESSAGE,
133                        null,
134                        options,
135                        options[0], // Yes is default
136                        "/Dialog/RelationEditor#Reload"
137        );
138    }
139
140    @Override
141    public void commandChanged(int queueSize, int redoSize) {
142        updateEnabledState();
143    }
144
145    /**
146     * Allow GC to do its work
147     */
148    public void destroy() {
149        UndoRedoHandler.getInstance().removeCommandQueueListener(this);
150    }
151}