source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/relation/actions/SavingAction.java@ 12048

Last change on this file since 12048 was 12048, checked in by michael2402, 7 years ago

Add per-layer selection listeners. Make selection listener code more generic.

File size: 8.4 KB
Line 
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.util.ArrayList;
8import java.util.List;
9
10import javax.swing.JOptionPane;
11import javax.swing.SwingUtilities;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.command.AddCommand;
15import org.openstreetmap.josm.command.ChangeCommand;
16import org.openstreetmap.josm.command.conflict.ConflictAddCommand;
17import org.openstreetmap.josm.data.conflict.Conflict;
18import org.openstreetmap.josm.data.osm.Relation;
19import org.openstreetmap.josm.data.osm.RelationMember;
20import org.openstreetmap.josm.gui.DefaultNameFormatter;
21import org.openstreetmap.josm.gui.HelpAwareOptionPane;
22import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
23import org.openstreetmap.josm.gui.dialogs.relation.IRelationEditor;
24import org.openstreetmap.josm.gui.dialogs.relation.MemberTable;
25import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel;
26import org.openstreetmap.josm.gui.dialogs.relation.RelationDialogManager;
27import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
28import org.openstreetmap.josm.gui.layer.OsmDataLayer;
29import org.openstreetmap.josm.gui.tagging.TagEditorModel;
30import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
31import org.openstreetmap.josm.tools.ImageProvider;
32import org.openstreetmap.josm.tools.Utils;
33
34/**
35 * Abstract superclass of relation saving actions (OK, Apply, Cancel).
36 * @since 9496
37 */
38abstract class SavingAction extends AbstractRelationEditorAction {
39
40 protected final TagEditorModel tagModel;
41 protected final AutoCompletingTextField tfRole;
42
43 protected SavingAction(MemberTable memberTable, MemberTableModel memberTableModel, TagEditorModel tagModel, OsmDataLayer layer,
44 IRelationEditor editor, AutoCompletingTextField tfRole) {
45 super(memberTable, memberTableModel, null, layer, editor);
46 this.tagModel = tagModel;
47 this.tfRole = tfRole;
48 }
49
50 /**
51 * apply updates to a new relation
52 * @param tagEditorModel tag editor model
53 */
54 protected void applyNewRelation(TagEditorModel tagEditorModel) {
55 final Relation newRelation = new Relation();
56 tagEditorModel.applyToPrimitive(newRelation);
57 memberTableModel.applyToRelation(newRelation);
58 List<RelationMember> newMembers = new ArrayList<>();
59 for (RelationMember rm: newRelation.getMembers()) {
60 if (!rm.getMember().isDeleted()) {
61 newMembers.add(rm);
62 }
63 }
64 if (newRelation.getMembersCount() != newMembers.size()) {
65 newRelation.setMembers(newMembers);
66 String msg = tr("One or more members of this new relation have been deleted while the relation editor\n" +
67 "was open. They have been removed from the relation members list.");
68 JOptionPane.showMessageDialog(Main.parent, msg, tr("Warning"), JOptionPane.WARNING_MESSAGE);
69 }
70 // If the user wanted to create a new relation, but hasn't added any members or
71 // tags, don't add an empty relation
72 if (newRelation.getMembersCount() == 0 && !newRelation.hasKeys())
73 return;
74 Main.main.undoRedo.add(new AddCommand(layer, newRelation));
75
76 // make sure everybody is notified about the changes
77 //
78 editor.setRelation(newRelation);
79 if (editor instanceof RelationEditor) {
80 RelationDialogManager.getRelationDialogManager().updateContext(
81 layer, editor.getRelation(), (RelationEditor) editor);
82 }
83 // Relation list gets update in EDT so selecting my be postponed to following EDT run
84 SwingUtilities.invokeLater(() -> Main.map.relationListDialog.selectRelation(newRelation));
85 }
86
87 /**
88 * Apply the updates for an existing relation which has been changed outside of the relation editor.
89 * @param tagEditorModel tag editor model
90 */
91 protected void applyExistingConflictingRelation(TagEditorModel tagEditorModel) {
92 Relation editedRelation = new Relation(editor.getRelation());
93 tagEditorModel.applyToPrimitive(editedRelation);
94 memberTableModel.applyToRelation(editedRelation);
95 Conflict<Relation> conflict = new Conflict<>(editor.getRelation(), editedRelation);
96 Main.main.undoRedo.add(new ConflictAddCommand(layer, conflict));
97 }
98
99 /**
100 * Apply the updates for an existing relation which has not been changed outside of the relation editor.
101 * @param tagEditorModel tag editor model
102 */
103 protected void applyExistingNonConflictingRelation(TagEditorModel tagEditorModel) {
104 Relation editedRelation = new Relation(editor.getRelation());
105 tagEditorModel.applyToPrimitive(editedRelation);
106 memberTableModel.applyToRelation(editedRelation);
107 if (!editedRelation.hasEqualSemanticAttributes(editor.getRelation(), false)) {
108 Main.main.undoRedo.add(new ChangeCommand(editor.getRelation(), editedRelation));
109 }
110 }
111
112 protected boolean confirmClosingBecauseOfDirtyState() {
113 ButtonSpec[] options = new ButtonSpec[] {
114 new ButtonSpec(
115 tr("Yes, create a conflict and close"),
116 ImageProvider.get("ok"),
117 tr("Click to create a conflict and close this relation editor"),
118 null /* no specific help topic */
119 ),
120 new ButtonSpec(
121 tr("No, continue editing"),
122 ImageProvider.get("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 int ret = HelpAwareOptionPane.showOptionDialog(
129 Main.parent,
130 tr("<html>This relation has been changed outside of the editor.<br>"
131 + "You cannot apply your changes and continue editing.<br>"
132 + "<br>"
133 + "Do you want to create a conflict and close the editor?</html>"),
134 tr("Conflict in data"),
135 JOptionPane.WARNING_MESSAGE,
136 null,
137 options,
138 options[0], // OK is default
139 "/Dialog/RelationEditor#RelationChangedOutsideOfEditor"
140 );
141 if (ret == 0) {
142 Main.map.conflictDialog.unfurlDialog();
143 }
144 return ret == 0;
145 }
146
147 protected void warnDoubleConflict() {
148 JOptionPane.showMessageDialog(
149 Main.parent,
150 tr("<html>Layer ''{0}'' already has a conflict for object<br>"
151 + "''{1}''.<br>"
152 + "Please resolve this conflict first, then try again.</html>",
153 Utils.escapeReservedCharactersHTML(layer.getName()),
154 Utils.escapeReservedCharactersHTML(editor.getRelation().getDisplayName(DefaultNameFormatter.getInstance()))
155 ),
156 tr("Double conflict"),
157 JOptionPane.WARNING_MESSAGE
158 );
159 }
160
161 @Override
162 protected void updateEnabledState() {
163 // Do nothing
164 }
165
166 protected boolean applyChanges() {
167 if (editor.getRelation() == null) {
168 applyNewRelation(tagModel);
169 } else if (isEditorDirty()) {
170 if (editor.isDirtyRelation()) {
171 if (confirmClosingBecauseOfDirtyState()) {
172 if (layer.getConflicts().hasConflictForMy(editor.getRelation())) {
173 warnDoubleConflict();
174 return false;
175 }
176 applyExistingConflictingRelation(tagModel);
177 hideEditor();
178 } else
179 return false;
180 } else {
181 applyExistingNonConflictingRelation(tagModel);
182 }
183 }
184 editor.setRelation(editor.getRelation());
185 return true;
186 }
187
188 protected void hideEditor() {
189 if (editor instanceof Component) {
190 ((Component) editor).setVisible(false);
191 }
192 }
193
194 protected boolean isEditorDirty() {
195 Relation snapshot = editor.getRelationSnapshot();
196 return (snapshot != null && !memberTableModel.hasSameMembersAs(snapshot)) || tagModel.isDirty();
197 }
198}
Note: See TracBrowser for help on using the repository browser.