source: josm/trunk/src/org/openstreetmap/josm/gui/conflict/tags/RelationMemberConflictResolverModel.java@ 8444

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

remove extra whitespaces

  • Property svn:eol-style set to native
File size: 10.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.conflict.tags;
3
4import java.beans.PropertyChangeListener;
5import java.beans.PropertyChangeSupport;
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.HashSet;
9import java.util.LinkedList;
10import java.util.List;
11import java.util.Set;
12
13import javax.swing.table.DefaultTableModel;
14
15import org.openstreetmap.josm.command.ChangeCommand;
16import org.openstreetmap.josm.command.Command;
17import org.openstreetmap.josm.data.osm.OsmPrimitive;
18import org.openstreetmap.josm.data.osm.Relation;
19import org.openstreetmap.josm.data.osm.RelationMember;
20import org.openstreetmap.josm.data.osm.RelationToChildReference;
21import org.openstreetmap.josm.gui.util.GuiHelper;
22
23/**
24 * This model manages a list of conflicting relation members.
25 *
26 * It can be used as {@link javax.swing.table.TableModel}.
27 */
28public class RelationMemberConflictResolverModel extends DefaultTableModel {
29 /** the property name for the number conflicts managed by this model */
30 public static final String NUM_CONFLICTS_PROP = RelationMemberConflictResolverModel.class.getName() + ".numConflicts";
31
32 /** the list of conflict decisions */
33 protected final transient List<RelationMemberConflictDecision> decisions;
34 /** the collection of relations for which we manage conflicts */
35 protected transient Collection<Relation> relations;
36 /** the number of conflicts */
37 private int numConflicts;
38 private final PropertyChangeSupport support;
39
40 /**
41 * Replies true if each {@link MultiValueResolutionDecision} is decided.
42 *
43 * @return true if each {@link MultiValueResolutionDecision} is decided; false otherwise
44 */
45 public boolean isResolvedCompletely() {
46 return numConflicts == 0;
47 }
48
49 /**
50 * Replies the current number of conflicts
51 *
52 * @return the current number of conflicts
53 */
54 public int getNumConflicts() {
55 return numConflicts;
56 }
57
58 /**
59 * Updates the current number of conflicts from list of decisions and emits
60 * a property change event if necessary.
61 *
62 */
63 protected void updateNumConflicts() {
64 int count = 0;
65 for (RelationMemberConflictDecision decision: decisions) {
66 if (!decision.isDecided()) {
67 count++;
68 }
69 }
70 int oldValue = numConflicts;
71 numConflicts = count;
72 if (numConflicts != oldValue) {
73 support.firePropertyChange(getProperty(), oldValue, numConflicts);
74 }
75 }
76
77 protected String getProperty() {
78 return NUM_CONFLICTS_PROP;
79 }
80
81 public void addPropertyChangeListener(PropertyChangeListener l) {
82 support.addPropertyChangeListener(l);
83 }
84
85 public void removePropertyChangeListener(PropertyChangeListener l) {
86 support.removePropertyChangeListener(l);
87 }
88
89 public RelationMemberConflictResolverModel() {
90 decisions = new ArrayList<>();
91 support = new PropertyChangeSupport(this);
92 }
93
94 @Override
95 public int getRowCount() {
96 return getNumDecisions();
97 }
98
99 @Override
100 public Object getValueAt(int row, int column) {
101 if (decisions == null) return null;
102
103 RelationMemberConflictDecision d = decisions.get(row);
104 switch(column) {
105 case 0: /* relation */ return d.getRelation();
106 case 1: /* pos */ return Integer.toString(d.getPos() + 1); // position in "user space" starting at 1
107 case 2: /* role */ return d.getRole();
108 case 3: /* original */ return d.getOriginalPrimitive();
109 case 4: /* decision */ return d.getDecision();
110 }
111 return null;
112 }
113
114 @Override
115 public void setValueAt(Object value, int row, int column) {
116 RelationMemberConflictDecision d = decisions.get(row);
117 switch(column) {
118 case 2: /* role */
119 d.setRole((String)value);
120 break;
121 case 4: /* decision */
122 d.decide((RelationMemberConflictDecisionType)value);
123 refresh();
124 break;
125 }
126 fireTableDataChanged();
127 }
128
129 /**
130 * Populates the model with the members of the relation <code>relation</code>
131 * referring to <code>primitive</code>.
132 *
133 * @param relation the parent relation
134 * @param primitive the child primitive
135 */
136 protected void populate(Relation relation, OsmPrimitive primitive) {
137 for (int i =0; i<relation.getMembersCount();i++) {
138 if (relation.getMember(i).refersTo(primitive)) {
139 decisions.add(new RelationMemberConflictDecision(relation, i));
140 }
141 }
142 }
143
144 /**
145 * Populates the model with the relation members belonging to one of the relations in <code>relations</code>
146 * and referring to one of the primitives in <code>memberPrimitives</code>.
147 *
148 * @param relations the parent relations. Empty list assumed if null.
149 * @param memberPrimitives the child primitives. Empty list assumed if null.
150 */
151 public void populate(Collection<Relation> relations, Collection<? extends OsmPrimitive> memberPrimitives) {
152 decisions.clear();
153 relations = relations == null ? new LinkedList<Relation>() : relations;
154 memberPrimitives = memberPrimitives == null ? new LinkedList<OsmPrimitive>() : memberPrimitives;
155 for (Relation r : relations) {
156 for (OsmPrimitive p: memberPrimitives) {
157 populate(r,p);
158 }
159 }
160 this.relations = relations;
161 refresh();
162 }
163
164 /**
165 * Populates the model with the relation members represented as a collection of
166 * {@link RelationToChildReference}s.
167 *
168 * @param references the references. Empty list assumed if null.
169 */
170 public void populate(Collection<RelationToChildReference> references) {
171 references = references == null ? new LinkedList<RelationToChildReference>() : references;
172 decisions.clear();
173 this.relations = new HashSet<>(references.size());
174 for (RelationToChildReference reference: references) {
175 decisions.add(new RelationMemberConflictDecision(reference.getParent(), reference.getPosition()));
176 relations.add(reference.getParent());
177 }
178 refresh();
179 }
180
181 /**
182 * Replies the decision at position <code>row</code>
183 *
184 * @param row
185 * @return the decision at position <code>row</code>
186 */
187 public RelationMemberConflictDecision getDecision(int row) {
188 return decisions.get(row);
189 }
190
191 /**
192 * Replies the number of decisions managed by this model
193 *
194 * @return the number of decisions managed by this model
195 */
196 public int getNumDecisions() {
197 return decisions == null ? 0 : decisions.size();
198 }
199
200 /**
201 * Refreshes the model state. Invoke this method to trigger necessary change
202 * events after an update of the model data.
203 *
204 */
205 public void refresh() {
206 updateNumConflicts();
207 GuiHelper.runInEDTAndWait(new Runnable() {
208 @Override public void run() {
209 fireTableDataChanged();
210 }
211 });
212 }
213
214 /**
215 * Apply a role to all member managed by this model.
216 *
217 * @param role the role. Empty string assumed if null.
218 */
219 public void applyRole(String role) {
220 role = role == null ? "" : role;
221 for (RelationMemberConflictDecision decision : decisions) {
222 decision.setRole(role);
223 }
224 refresh();
225 }
226
227 protected RelationMemberConflictDecision getDecision(Relation relation, int pos) {
228 for(RelationMemberConflictDecision decision: decisions) {
229 if (decision.matches(relation, pos)) return decision;
230 }
231 return null;
232 }
233
234 protected Command buildResolveCommand(Relation relation, OsmPrimitive newPrimitive) {
235 final Relation modifiedRelation = new Relation(relation);
236 modifiedRelation.setMembers(null);
237 boolean isChanged = false;
238 for (int i=0; i < relation.getMembersCount(); i++) {
239 final RelationMember member = relation.getMember(i);
240 RelationMemberConflictDecision decision = getDecision(relation, i);
241 if (decision == null) {
242 modifiedRelation.addMember(member);
243 } else {
244 switch(decision.getDecision()) {
245 case KEEP:
246 final RelationMember newMember = new RelationMember(decision.getRole(),newPrimitive);
247 modifiedRelation.addMember(newMember);
248 isChanged |= !member.equals(newMember);
249 break;
250 case REMOVE:
251 isChanged = true;
252 // do nothing
253 break;
254 case UNDECIDED:
255 // FIXME: this is an error
256 break;
257 }
258 }
259 }
260 if (isChanged)
261 return new ChangeCommand(relation, modifiedRelation);
262 return null;
263 }
264
265 /**
266 * Builds a collection of commands executing the decisions made in this model.
267 *
268 * @param newPrimitive the primitive which members shall refer to
269 * @return a list of commands
270 */
271 public List<Command> buildResolutionCommands(OsmPrimitive newPrimitive) {
272 List<Command> command = new LinkedList<>();
273 for (Relation relation : relations) {
274 Command cmd = buildResolveCommand(relation, newPrimitive);
275 if (cmd != null) {
276 command.add(cmd);
277 }
278 }
279 return command;
280 }
281
282 protected boolean isChanged(Relation relation, OsmPrimitive newPrimitive) {
283 for (int i=0; i < relation.getMembersCount(); i++) {
284 RelationMemberConflictDecision decision = getDecision(relation, i);
285 if (decision == null) {
286 continue;
287 }
288 switch(decision.getDecision()) {
289 case REMOVE: return true;
290 case KEEP:
291 if (!relation.getMember(i).getRole().equals(decision.getRole()))
292 return true;
293 if (relation.getMember(i).getMember() != newPrimitive)
294 return true;
295 case UNDECIDED:
296 // FIXME: handle error
297 }
298 }
299 return false;
300 }
301
302 /**
303 * Replies the set of relations which have to be modified according
304 * to the decisions managed by this model.
305 *
306 * @param newPrimitive the primitive which members shall refer to
307 *
308 * @return the set of relations which have to be modified according
309 * to the decisions managed by this model
310 */
311 public Set<Relation> getModifiedRelations(OsmPrimitive newPrimitive) {
312 Set<Relation> ret = new HashSet<>();
313 for (Relation relation: relations) {
314 if (isChanged(relation, newPrimitive)) {
315 ret.add(relation);
316 }
317 }
318 return ret;
319 }
320}
Note: See TracBrowser for help on using the repository browser.