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

Last change on this file since 5266 was 5266, checked in by bastiK, 12 years ago

fixed majority of javadoc warnings by replacing "{@see" by "{@link"

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