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

Last change on this file since 5832 was 5832, checked in by stoecker, 11 years ago

i18n update and javadoc fixes

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