source: josm/trunk/src/org/openstreetmap/josm/gui/conflict/pair/properties/PropertiesMergeModel.java@ 18489

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

see #22104 - fix deprecation warnings

  • Property svn:eol-style set to native
File size: 11.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.conflict.pair.properties;
3
4import static org.openstreetmap.josm.gui.conflict.pair.MergeDecisionType.UNDECIDED;
5
6import java.beans.PropertyChangeListener;
7import java.beans.PropertyChangeSupport;
8import java.util.ArrayList;
9import java.util.Collections;
10import java.util.List;
11
12import org.openstreetmap.josm.command.Command;
13import org.openstreetmap.josm.command.conflict.CoordinateConflictResolveCommand;
14import org.openstreetmap.josm.command.conflict.DeletedStateConflictResolveCommand;
15import org.openstreetmap.josm.data.conflict.Conflict;
16import org.openstreetmap.josm.data.coor.ILatLon;
17import org.openstreetmap.josm.data.coor.LatLon;
18import org.openstreetmap.josm.data.osm.Node;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.gui.conflict.pair.MergeDecisionType;
21import org.openstreetmap.josm.gui.util.ChangeNotifier;
22import org.openstreetmap.josm.tools.CheckParameterUtil;
23
24/**
25 * This is the model for resolving conflicts in the properties of the
26 * {@link OsmPrimitive}s. In particular, it represents conflicts in the coordinates of {@link Node}s and
27 * the deleted or visible state of {@link OsmPrimitive}s.
28 *
29 * This model is a {@link ChangeNotifier}. It notifies registered {@link javax.swing.event.ChangeListener}s whenever the
30 * internal state changes.
31 *
32 * This model also emits property changes for {@link #RESOLVED_COMPLETELY_PROP}. Property change
33 * listeners may register themselves using {@link #addPropertyChangeListener(PropertyChangeListener)}.
34 *
35 * @see Node#getCoor()
36 * @see OsmPrimitive#isDeleted
37 * @see OsmPrimitive#isVisible
38 *
39 */
40public class PropertiesMergeModel extends ChangeNotifier {
41
42 public static final String RESOLVED_COMPLETELY_PROP = PropertiesMergeModel.class.getName() + ".resolvedCompletely";
43 public static final String DELETE_PRIMITIVE_PROP = PropertiesMergeModel.class.getName() + ".deletePrimitive";
44
45 private OsmPrimitive my;
46
47 private LatLon myCoords;
48 private LatLon theirCoords;
49 private MergeDecisionType coordMergeDecision;
50
51 private boolean myDeletedState;
52 private boolean theirDeletedState;
53 private List<OsmPrimitive> myReferrers;
54 private List<OsmPrimitive> theirReferrers;
55 private MergeDecisionType deletedMergeDecision;
56 private final PropertyChangeSupport support;
57 private Boolean resolvedCompletely;
58
59 public void addPropertyChangeListener(PropertyChangeListener listener) {
60 support.addPropertyChangeListener(listener);
61 }
62
63 public void removePropertyChangeListener(PropertyChangeListener listener) {
64 support.removePropertyChangeListener(listener);
65 }
66
67 public void fireCompletelyResolved() {
68 Boolean oldValue = resolvedCompletely;
69 resolvedCompletely = isResolvedCompletely();
70 support.firePropertyChange(RESOLVED_COMPLETELY_PROP, oldValue, resolvedCompletely);
71 }
72
73 /**
74 * Constructs a new {@code PropertiesMergeModel}.
75 */
76 public PropertiesMergeModel() {
77 coordMergeDecision = UNDECIDED;
78 deletedMergeDecision = UNDECIDED;
79 support = new PropertyChangeSupport(this);
80 resolvedCompletely = null;
81 }
82
83 /**
84 * replies true if there is a coordinate conflict and if this conflict is resolved
85 *
86 * @return true if there is a coordinate conflict and if this conflict is resolved; false, otherwise
87 */
88 public boolean isDecidedCoord() {
89 return coordMergeDecision != UNDECIDED;
90 }
91
92 /**
93 * replies true if there is a conflict in the deleted state and if this conflict is resolved
94 *
95 * @return true if there is a conflict in the deleted state and if this conflict is
96 * resolved; false, otherwise
97 */
98 public boolean isDecidedDeletedState() {
99 return deletedMergeDecision != UNDECIDED;
100 }
101
102 /**
103 * replies true if the current decision for the coordinate conflict is <code>decision</code>
104 * @param decision conflict resolution decision
105 *
106 * @return true if the current decision for the coordinate conflict is <code>decision</code>;
107 * false, otherwise
108 */
109 public boolean isCoordMergeDecision(MergeDecisionType decision) {
110 return coordMergeDecision == decision;
111 }
112
113 /**
114 * replies true if the current decision for the deleted state conflict is <code>decision</code>
115 * @param decision conflict resolution decision
116 *
117 * @return true if the current decision for the deleted state conflict is <code>decision</code>;
118 * false, otherwise
119 */
120 public boolean isDeletedStateDecision(MergeDecisionType decision) {
121 return deletedMergeDecision == decision;
122 }
123
124 /**
125 * Populates the model with the differences between local and server version
126 *
127 * @param conflict The conflict information
128 */
129 public void populate(Conflict<? extends OsmPrimitive> conflict) {
130 this.my = conflict.getMy();
131 OsmPrimitive their = conflict.getTheir();
132 if (my instanceof Node) {
133 myCoords = ((Node) my).getCoor();
134 theirCoords = ((Node) their).getCoor();
135 } else {
136 myCoords = null;
137 theirCoords = null;
138 }
139
140 myDeletedState = conflict.isMyDeleted() || my.isDeleted();
141 theirDeletedState = their.isDeleted();
142
143 myReferrers = my.getDataSet() == null ? Collections.<OsmPrimitive>emptyList() : my.getReferrers();
144 theirReferrers = their.getDataSet() == null ? Collections.<OsmPrimitive>emptyList() : their.getReferrers();
145
146 coordMergeDecision = UNDECIDED;
147 deletedMergeDecision = UNDECIDED;
148 fireStateChanged();
149 fireCompletelyResolved();
150 }
151
152 /**
153 * replies the coordinates of my {@link OsmPrimitive}. null, if my primitive hasn't
154 * coordinates (i.e. because it is a {@link org.openstreetmap.josm.data.osm.Way}).
155 *
156 * @return the coordinates of my {@link OsmPrimitive}. null, if my primitive hasn't
157 * coordinates (i.e. because it is a {@link org.openstreetmap.josm.data.osm.Way}).
158 */
159 public LatLon getMyCoords() {
160 return myCoords;
161 }
162
163 /**
164 * replies the coordinates of their {@link OsmPrimitive}. null, if their primitive hasn't
165 * coordinates (i.e. because it is a {@link org.openstreetmap.josm.data.osm.Way}).
166 *
167 * @return the coordinates of my {@link OsmPrimitive}. null, if my primitive hasn't
168 * coordinates (i.e. because it is a {@link org.openstreetmap.josm.data.osm.Way}).
169 */
170 public LatLon getTheirCoords() {
171 return theirCoords;
172 }
173
174 /**
175 * replies the coordinates of the merged {@link OsmPrimitive}. null, if the current primitives
176 * have no coordinates or if the conflict is yet {@link MergeDecisionType#UNDECIDED}
177 *
178 * @return the coordinates of the merged {@link OsmPrimitive}. null, if the current primitives
179 * have no coordinates or if the conflict is yet {@link MergeDecisionType#UNDECIDED}
180 */
181 public LatLon getMergedCoords() {
182 switch(coordMergeDecision) {
183 case KEEP_MINE: return myCoords;
184 case KEEP_THEIR: return theirCoords;
185 case UNDECIDED: return null;
186 }
187 // should not happen
188 return null;
189 }
190
191 /**
192 * Decides a conflict between local and server coordinates
193 *
194 * @param decision the decision
195 */
196 public void decideCoordsConflict(MergeDecisionType decision) {
197 coordMergeDecision = decision;
198 fireStateChanged();
199 fireCompletelyResolved();
200 }
201
202 /**
203 * Replies deleted state of local dataset
204 * @return The state of deleted flag
205 */
206 public Boolean getMyDeletedState() {
207 return myDeletedState;
208 }
209
210 /**
211 * Replies deleted state of Server dataset
212 * @return The state of deleted flag
213 */
214 public Boolean getTheirDeletedState() {
215 return theirDeletedState;
216 }
217
218 /**
219 * Replies deleted state of combined dataset
220 * @return The state of deleted flag
221 */
222 public Boolean getMergedDeletedState() {
223 switch(deletedMergeDecision) {
224 case KEEP_MINE: return myDeletedState;
225 case KEEP_THEIR: return theirDeletedState;
226 case UNDECIDED: return null;
227 }
228 // should not happen
229 return null;
230 }
231
232 /**
233 * Returns local referrers
234 * @return The referrers
235 */
236 public List<OsmPrimitive> getMyReferrers() {
237 return myReferrers;
238 }
239
240 /**
241 * Returns server referrers
242 * @return The referrers
243 */
244 public List<OsmPrimitive> getTheirReferrers() {
245 return theirReferrers;
246 }
247
248 private boolean getMergedDeletedState(MergeDecisionType decision) {
249 switch (decision) {
250 case KEEP_MINE:
251 return myDeletedState;
252 case KEEP_THEIR:
253 return theirDeletedState;
254 default:
255 return false;
256 }
257 }
258
259 /**
260 * decides the conflict between two deleted states
261 * @param decision the decision (must not be null)
262 *
263 * @throws IllegalArgumentException if decision is null
264 */
265 public void decideDeletedStateConflict(MergeDecisionType decision) {
266 CheckParameterUtil.ensureParameterNotNull(decision, "decision");
267
268 boolean oldMergedDeletedState = getMergedDeletedState(this.deletedMergeDecision);
269 boolean newMergedDeletedState = getMergedDeletedState(decision);
270
271 this.deletedMergeDecision = decision;
272 fireStateChanged();
273 fireCompletelyResolved();
274
275 if (oldMergedDeletedState != newMergedDeletedState) {
276 support.firePropertyChange(DELETE_PRIMITIVE_PROP, oldMergedDeletedState, newMergedDeletedState);
277 }
278 }
279
280 /**
281 * replies true if my and their primitive have a conflict between
282 * their coordinate values
283 *
284 * @return true if my and their primitive have a conflict between
285 * their coordinate values; false otherwise
286 */
287 public boolean hasCoordConflict() {
288 if (myCoords == null && theirCoords != null) return true;
289 if (myCoords != null && theirCoords == null) return true;
290 if (myCoords == null && theirCoords == null) return false;
291 return myCoords != null && !myCoords.equalsEpsilon(theirCoords, ILatLon.MAX_SERVER_PRECISION);
292 }
293
294 /**
295 * replies true if my and their primitive have a conflict between
296 * their deleted states
297 *
298 * @return <code>true</code> if my and their primitive have a conflict between
299 * their deleted states
300 */
301 public boolean hasDeletedStateConflict() {
302 return myDeletedState != theirDeletedState;
303 }
304
305 /**
306 * replies true if all conflict in this model are resolved
307 *
308 * @return <code>true</code> if all conflict in this model are resolved; <code>false</code> otherwise
309 */
310 public boolean isResolvedCompletely() {
311 boolean ret = true;
312 if (hasCoordConflict()) {
313 ret = ret && coordMergeDecision != UNDECIDED;
314 }
315 if (hasDeletedStateConflict()) {
316 ret = ret && deletedMergeDecision != UNDECIDED;
317 }
318 return ret;
319 }
320
321 /**
322 * Builds the command(s) to apply the conflict resolutions to my primitive
323 *
324 * @param conflict The conflict information
325 * @return The list of commands
326 */
327 public List<Command> buildResolveCommand(Conflict<? extends OsmPrimitive> conflict) {
328 List<Command> cmds = new ArrayList<>();
329 if (hasCoordConflict() && isDecidedCoord()) {
330 cmds.add(new CoordinateConflictResolveCommand(conflict, coordMergeDecision));
331 }
332 if (hasDeletedStateConflict() && isDecidedDeletedState()) {
333 cmds.add(new DeletedStateConflictResolveCommand(conflict, deletedMergeDecision));
334 }
335 return cmds;
336 }
337
338 public OsmPrimitive getMyPrimitive() {
339 return my;
340 }
341
342}
Note: See TracBrowser for help on using the repository browser.