source: josm/trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverModel.java@ 2996

Last change on this file since 2996 was 2996, checked in by jttt, 14 years ago

Fix #4406 tags disapear: merging node with ID:0 and tag to existing node without tags

File size: 7.9 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.Collections;
8import java.util.Comparator;
9import java.util.HashMap;
10import java.util.HashSet;
11import java.util.List;
12import java.util.Set;
13
14import javax.swing.table.DefaultTableModel;
15
16import org.openstreetmap.josm.data.osm.TagCollection;
17import org.openstreetmap.josm.tools.CheckParameterUtil;
18
19public class TagConflictResolverModel extends DefaultTableModel {
20 static public final String NUM_CONFLICTS_PROP = TagConflictResolverModel.class.getName() + ".numConflicts";
21
22 private TagCollection tags;
23 private List<String> displayedKeys;
24 private Set<String> keysWithConflicts;
25 private HashMap<String, MultiValueResolutionDecision> decisions;
26 private int numConflicts;
27 private PropertyChangeSupport support;
28 private boolean showTagsWithConflictsOnly = false;
29 private boolean showTagsWithMultiValuesOnly = false;
30
31 public TagConflictResolverModel() {
32 numConflicts = 0;
33 support = new PropertyChangeSupport(this);
34 }
35
36 public void addPropertyChangeListener(PropertyChangeListener listener) {
37 support.addPropertyChangeListener(listener);
38 }
39
40 public void removePropertyChangeListener(PropertyChangeListener listener) {
41 support.removePropertyChangeListener(listener);
42 }
43
44 protected void setNumConflicts(int numConflicts) {
45 int oldValue = this.numConflicts;
46 this.numConflicts = numConflicts;
47 if (oldValue != this.numConflicts) {
48 support.firePropertyChange(NUM_CONFLICTS_PROP, oldValue, this.numConflicts);
49 }
50 }
51
52 protected void refreshNumConflicts() {
53 int count = 0;
54 for (MultiValueResolutionDecision d : decisions.values()) {
55 if (!d.isDecided()) {
56 count++;
57 }
58 }
59 setNumConflicts(count);
60 }
61
62 protected void sort() {
63 Collections.sort(
64 displayedKeys,
65 new Comparator<String>() {
66 public int compare(String key1, String key2) {
67 if (decisions.get(key1).isDecided() && ! decisions.get(key2).isDecided())
68 return 1;
69 else if (!decisions.get(key1).isDecided() && decisions.get(key2).isDecided())
70 return -1;
71 return key1.compareTo(key2);
72 }
73 }
74 );
75 }
76
77 /**
78 * initializes the model from the current tags
79 *
80 */
81 protected void rebuild() {
82 if (tags == null) return;
83 for(String key: tags.getKeys()) {
84 MultiValueResolutionDecision decision = new MultiValueResolutionDecision(tags.getTagsFor(key));
85 if (decisions.get(key) == null) {
86 decisions.put(key,decision);
87 }
88 }
89 displayedKeys.clear();
90 Set<String> keys = tags.getKeys();
91 if (showTagsWithConflictsOnly) {
92 keys.retainAll(keysWithConflicts);
93 if (showTagsWithMultiValuesOnly) {
94 Set<String> keysWithMultiValues = new HashSet<String>();
95 for (String key: keys) {
96 if (decisions.get(key).canKeepAll()) {
97 keysWithMultiValues.add(key);
98 }
99 }
100 keys.retainAll(keysWithMultiValues);
101 }
102 for (String key: tags.getKeys()) {
103 if (!decisions.get(key).isDecided() && !keys.contains(key)) {
104 keys.add(key);
105 }
106 }
107 }
108 displayedKeys.addAll(keys);
109 refreshNumConflicts();
110 sort();
111 fireTableDataChanged();
112 }
113
114 /**
115 * Populates the model with the tags for which conflicts are to be resolved.
116 *
117 * @param tags the tag collection with the tags. Must not be null.
118 * @param keysWithConflicts the set of tag keys with conflicts
119 * @throws IllegalArgumentException thrown if tags is null
120 */
121 public void populate(TagCollection tags, Set<String> keysWithConflicts) {
122 CheckParameterUtil.ensureParameterNotNull(tags, "tags");
123 this.tags = tags;
124 displayedKeys = new ArrayList<String>();
125 this.keysWithConflicts = keysWithConflicts == null ? new HashSet<String>() : keysWithConflicts;
126 decisions = new HashMap<String, MultiValueResolutionDecision>();
127 rebuild();
128 }
129
130 @Override
131 public int getRowCount() {
132 if (displayedKeys == null) return 0;
133 return displayedKeys.size();
134 }
135
136 @Override
137 public Object getValueAt(int row, int column) {
138 return decisions.get(displayedKeys.get(row));
139 }
140
141 @Override
142 public boolean isCellEditable(int row, int column) {
143 return column == 2;
144 }
145
146 @Override
147 public void setValueAt(Object value, int row, int column) {
148 MultiValueResolutionDecision decision = decisions.get(displayedKeys.get(row));
149 if (value instanceof String) {
150 decision.keepOne((String)value);
151 } else if (value instanceof MultiValueDecisionType) {
152 MultiValueDecisionType type = (MultiValueDecisionType)value;
153 switch(type) {
154 case KEEP_NONE:
155 decision.keepNone();
156 break;
157 case KEEP_ALL:
158 decision.keepAll();
159 break;
160 }
161 }
162 fireTableDataChanged();
163 refreshNumConflicts();
164 }
165
166 /**
167 * Replies true if each {@see MultiValueResolutionDecision} is decided.
168 *
169 * @return true if each {@see MultiValueResolutionDecision} is decided; false
170 * otherwise
171 */
172 public boolean isResolvedCompletely() {
173 return numConflicts == 0;
174 }
175
176 public int getNumConflicts() {
177 return numConflicts;
178 }
179
180 public int getNumDecisions() {
181 return getRowCount();
182 }
183
184 //TODO Should this method work with all decisions or only with displayed decisions? For MergeNodes it should be
185 //all decisions, but this method is also used on other places, so I've made new method just for MergeNodes
186 public TagCollection getResolution() {
187 TagCollection tc = new TagCollection();
188 for (String key: displayedKeys) {
189 tc.add(decisions.get(key).getResolution());
190 }
191 return tc;
192 }
193
194 public TagCollection getAllResolutions() {
195 TagCollection tc = new TagCollection();
196 for (MultiValueResolutionDecision value: decisions.values()) {
197 tc.add(value.getResolution());
198 }
199 return tc;
200 }
201
202 public MultiValueResolutionDecision getDecision(int row) {
203 return decisions.get(displayedKeys.get(row));
204 }
205
206 /**
207 * Sets whether all tags or only tags with conflicts are displayed
208 *
209 * @param showTagsWithConflictsOnly if true, only tags with conflicts are displayed
210 */
211 public void setShowTagsWithConflictsOnly(boolean showTagsWithConflictsOnly) {
212 this.showTagsWithConflictsOnly = showTagsWithConflictsOnly;
213 rebuild();
214 }
215
216 /**
217 * Sets whether all conflicts or only conflicts with multiple values are displayed
218 *
219 * @param showTagsWithMultiValuesOnly if true, only tags with multiple values are displayed
220 */
221 public void setShowTagsWithMultiValuesOnly(boolean showTagsWithMultiValuesOnly) {
222 this.showTagsWithMultiValuesOnly = showTagsWithMultiValuesOnly;
223 rebuild();
224 }
225
226 /**
227 * Prepare the default decisions for the current model
228 *
229 */
230 public void prepareDefaultTagDecisions() {
231 for (MultiValueResolutionDecision decision: decisions.values()) {
232 List<String> values = decision.getValues();
233 values.remove("");
234 if (values.size() == 1) {
235 decision.keepOne(values.get(0));
236 } else {
237 decision.keepAll();
238 }
239 }
240 rebuild();
241 }
242
243}
Note: See TracBrowser for help on using the repository browser.