source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictResolutionDialog.java @ 14134

Last change on this file since 14134 was 14134, checked in by Don-vip, 2 months ago

see #15229 - deprecate Main*.undoRedo - make UndoRedoHandler a singleton

  • Property svn:eol-style set to native
File size: 8.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.BorderLayout;
8import java.awt.Component;
9import java.awt.event.ActionEvent;
10import java.beans.PropertyChangeEvent;
11import java.beans.PropertyChangeListener;
12
13import javax.swing.AbstractAction;
14import javax.swing.Action;
15import javax.swing.JLabel;
16import javax.swing.JOptionPane;
17import javax.swing.JPanel;
18
19import org.openstreetmap.josm.Main;
20import org.openstreetmap.josm.data.UndoRedoHandler;
21import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
22import org.openstreetmap.josm.data.osm.OsmPrimitive;
23import org.openstreetmap.josm.gui.ExtendedDialog;
24import org.openstreetmap.josm.gui.conflict.pair.ConflictResolver;
25import org.openstreetmap.josm.gui.help.HelpBrowser;
26import org.openstreetmap.josm.gui.help.HelpUtil;
27import org.openstreetmap.josm.tools.ImageProvider;
28
29/**
30 * This is an extended dialog for resolving conflict between {@link OsmPrimitive}s.
31 * @since 1622
32 */
33public class ConflictResolutionDialog extends ExtendedDialog implements PropertyChangeListener {
34    /** the conflict resolver component */
35    private final ConflictResolver resolver = new ConflictResolver();
36    private final JLabel titleLabel = new JLabel("", null, JLabel.CENTER);
37
38    private final ApplyResolutionAction applyResolutionAction = new ApplyResolutionAction();
39
40    private boolean isRegistered;
41
42    /**
43     * Constructs a new {@code ConflictResolutionDialog}.
44     * @param parent parent component
45     */
46    public ConflictResolutionDialog(Component parent) {
47        // We define our own actions, but need to give a hint about number of buttons
48        super(parent, tr("Resolve conflicts"), null, null, null);
49        setDefaultButton(1);
50        setCancelButton(2);
51        build();
52        pack();
53        if (getInsets().top > 0) {
54            titleLabel.setVisible(false);
55        }
56    }
57
58    @Override
59    public void removeNotify() {
60        super.removeNotify();
61        unregisterListeners();
62    }
63
64    @Override
65    public void addNotify() {
66        super.addNotify();
67        registerListeners();
68    }
69
70    private synchronized void registerListeners() {
71        if (!isRegistered) {
72            resolver.addPropertyChangeListener(applyResolutionAction);
73            resolver.registerListeners();
74            isRegistered = true;
75        }
76    }
77
78    private synchronized void unregisterListeners() {
79        // See #13479 - See https://bugs.openjdk.java.net/browse/JDK-4387314
80        // Owner window keep a list of owned windows, and does not remove the references when the child is disposed.
81        // There's no easy way to remove ourselves from this list, so we must keep track of register state
82        if (isRegistered) {
83            resolver.removePropertyChangeListener(applyResolutionAction);
84            resolver.unregisterListeners();
85            isRegistered = false;
86        }
87    }
88
89    /**
90     * builds the GUI
91     */
92    protected void build() {
93        JPanel p = new JPanel(new BorderLayout());
94
95        p.add(titleLabel, BorderLayout.NORTH);
96
97        updateTitle();
98
99        resolver.setName("panel.conflictresolver");
100        p.add(resolver, BorderLayout.CENTER);
101
102        resolver.addPropertyChangeListener(this);
103        HelpUtil.setHelpContext(this.getRootPane(), ht("Dialog/Conflict"));
104
105        setContent(p, false);
106    }
107
108    @Override
109    protected Action createButtonAction(int i) {
110        switch (i) {
111            case 0: return applyResolutionAction;
112            case 1: return new CancelAction();
113            case 2: return new HelpAction();
114            default: return super.createButtonAction(i);
115        }
116    }
117
118    /**
119     * Replies the conflict resolver component.
120     * @return the conflict resolver component
121     */
122    public ConflictResolver getConflictResolver() {
123        return resolver;
124    }
125
126    /**
127     * Action for canceling conflict resolution
128     */
129    class CancelAction extends AbstractAction {
130        CancelAction() {
131            putValue(Action.SHORT_DESCRIPTION, tr("Cancel conflict resolution and close the dialog"));
132            putValue(Action.NAME, tr("Cancel"));
133            new ImageProvider("cancel").getResource().attachImageIcon(this);
134            setEnabled(true);
135        }
136
137        @Override
138        public void actionPerformed(ActionEvent evt) {
139            buttonAction(2, evt);
140        }
141    }
142
143    /**
144     * Action for canceling conflict resolution
145     */
146    static class HelpAction extends AbstractAction {
147        HelpAction() {
148            putValue(Action.SHORT_DESCRIPTION, tr("Show help information"));
149            putValue(Action.NAME, tr("Help"));
150            new ImageProvider("help").getResource().attachImageIcon(this);
151            setEnabled(true);
152        }
153
154        @Override
155        public void actionPerformed(ActionEvent evt) {
156            HelpBrowser.setUrlForHelpTopic(ht("/Dialog/Conflict"));
157        }
158    }
159
160    /**
161     * Action for applying resolved differences in a conflict
162     *
163     */
164    class ApplyResolutionAction extends AbstractAction implements PropertyChangeListener {
165        ApplyResolutionAction() {
166            putValue(Action.SHORT_DESCRIPTION, tr("Apply resolved conflicts and close the dialog"));
167            putValue(Action.NAME, tr("Apply Resolution"));
168            new ImageProvider("dialogs", "conflict").getResource().attachImageIcon(this);
169            updateEnabledState();
170        }
171
172        protected void updateEnabledState() {
173            setEnabled(resolver.isResolvedCompletely());
174        }
175
176        @Override
177        public void actionPerformed(ActionEvent evt) {
178            if (!resolver.isResolvedCompletely()) {
179                Object[] options = {
180                        tr("Close anyway"),
181                        tr("Continue resolving")};
182                int ret = JOptionPane.showOptionDialog(Main.parent,
183                        tr("<html>You did not finish to merge the differences in this conflict.<br>"
184                                + "Conflict resolutions will not be applied unless all differences<br>"
185                                + "are resolved.<br>"
186                                + "Click <strong>{0}</strong> to close anyway.<strong> Already<br>"
187                                + "resolved differences will not be applied.</strong><br>"
188                                + "Click <strong>{1}</strong> to return to resolving conflicts.</html>",
189                                options[0].toString(), options[1].toString()
190                        ),
191                        tr("Conflict not resolved completely"),
192                        JOptionPane.YES_NO_OPTION,
193                        JOptionPane.WARNING_MESSAGE,
194                        null,
195                        options,
196                        options[1]
197                );
198                switch(ret) {
199                case JOptionPane.YES_OPTION:
200                    buttonAction(1, evt);
201                    break;
202                default:
203                    return;
204                }
205            }
206            UndoRedoHandler.getInstance().add(resolver.buildResolveCommand());
207            buttonAction(1, evt);
208        }
209
210        @Override
211        public void propertyChange(PropertyChangeEvent evt) {
212            if (evt.getPropertyName().equals(ConflictResolver.RESOLVED_COMPLETELY_PROP)) {
213                updateEnabledState();
214            }
215        }
216    }
217
218    protected void updateTitle() {
219        updateTitle(null);
220    }
221
222    protected void updateTitle(OsmPrimitive my) {
223        if (my == null) {
224            setTitle(tr("Resolve conflicts"));
225        } else {
226            setTitle(tr("Resolve conflicts for ''{0}''", my.getDisplayName(DefaultNameFormatter.getInstance())));
227        }
228    }
229
230    @Override
231    public void setTitle(String title) {
232        super.setTitle(title);
233        if (titleLabel != null) {
234            titleLabel.setText(title);
235        }
236    }
237
238    @Override
239    public void propertyChange(PropertyChangeEvent evt) {
240        if (evt.getPropertyName().equals(ConflictResolver.MY_PRIMITIVE_PROP)) {
241            updateTitle((OsmPrimitive) evt.getNewValue());
242        }
243    }
244}
Note: See TracBrowser for help on using the repository browser.