source: josm/trunk/src/org/openstreetmap/josm/gui/conflict/pair/tags/TagMergeModel.java@ 2945

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

Improvements in conflicts gui

File size: 7.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.conflict.pair.tags;
3
4import java.beans.PropertyChangeEvent;
5import java.beans.PropertyChangeListener;
6import java.util.ArrayList;
7import java.util.HashSet;
8import java.util.List;
9import java.util.Set;
10
11import javax.swing.table.DefaultTableModel;
12
13import org.openstreetmap.josm.command.TagConflictResolveCommand;
14import org.openstreetmap.josm.data.osm.OsmPrimitive;
15import org.openstreetmap.josm.gui.conflict.pair.MergeDecisionType;
16
17/**
18 * This is the {@see TableModel} used in the tables of the {@see TagMerger}.
19 *
20 * The model can {@see #populate(OsmPrimitive, OsmPrimitive)} itself from the conflicts
21 * in the tag sets of two {@see OsmPrimitive}s. Internally, it keeps a list of {@see TagMergeItem}s.
22 *
23 * {@see #decide(int, MergeDecisionType)} and {@see #decide(int[], MergeDecisionType)} can be used
24 * to remember a merge decision for a specific row in the model.
25 *
26 * The model notifies {@see PropertyChangeListener}s about updates of the number of
27 * undecided tags (see {@see #PROP_NUM_UNDECIDED_TAGS}).
28 *
29 */
30public class TagMergeModel extends DefaultTableModel {
31 //private static final Logger logger = Logger.getLogger(TagMergeModel.class.getName());
32
33 static public final String PROP_NUM_UNDECIDED_TAGS = TagMergeModel.class.getName() + ".numUndecidedTags";
34
35 /** the list of tag merge items */
36 private final List<TagMergeItem> tagMergeItems;
37
38 /** the property change listeners */
39 private final List<PropertyChangeListener> listeners;
40
41 private int numUndecidedTags = 0;
42
43 public TagMergeModel() {
44 tagMergeItems = new ArrayList<TagMergeItem>();
45 listeners = new ArrayList<PropertyChangeListener>();
46 }
47
48 public void addPropertyChangeListener(PropertyChangeListener listener) {
49 synchronized(listeners) {
50 if (listener == null) return;
51 if (listeners.contains(listener)) return;
52 listeners.add(listener);
53 }
54 }
55
56 public void removePropertyChangeListener(PropertyChangeListener listener) {
57 synchronized(listeners) {
58 if (listener == null) return;
59 if (!listeners.contains(listener)) return;
60 listeners.remove(listener);
61 }
62 }
63
64 /**
65 * notifies {@see PropertyChangeListener}s about an update of {@see TagMergeModel#PROP_NUM_UNDECIDED_TAGS}
66
67 * @param oldValue the old value
68 * @param newValue the new value
69 */
70 protected void fireNumUndecidedTagsChanged(int oldValue, int newValue) {
71 PropertyChangeEvent evt = new PropertyChangeEvent(this,PROP_NUM_UNDECIDED_TAGS,oldValue, newValue);
72 synchronized(listeners) {
73 for(PropertyChangeListener l : listeners) {
74 l.propertyChange(evt);
75 }
76 }
77 }
78
79 /**
80 * refreshes the number of undecided tag conflicts after an update in the list of
81 * {@see TagMergeItem}s. Notifies {@see PropertyChangeListener} if necessary.
82 *
83 */
84 protected void refreshNumUndecidedTags() {
85 int newValue=0;
86 for(TagMergeItem item: tagMergeItems) {
87 if (MergeDecisionType.UNDECIDED.equals(item.getMergeDecision())) {
88 newValue++;
89 }
90 }
91 int oldValue = numUndecidedTags;
92 numUndecidedTags = newValue;
93 fireNumUndecidedTagsChanged(oldValue, numUndecidedTags);
94
95 }
96
97 /**
98 * Populate the model with conflicts between the tag sets of the two
99 * {@see OsmPrimitive} <code>my</code> and <code>their</code>.
100 *
101 * @param my my primitive (i.e. the primitive from the local dataset)
102 * @param their their primitive (i.e. the primitive from the server dataset)
103 *
104 */
105 public void populate(OsmPrimitive my, OsmPrimitive their) {
106 tagMergeItems.clear();
107 Set<String> keys = new HashSet<String>();
108 keys.addAll(my.keySet());
109 keys.addAll(their.keySet());
110 for(String key : keys) {
111 String myValue = my.get(key);
112 String theirValue = their.get(key);
113 if (myValue == null || theirValue == null || ! myValue.equals(theirValue)) {
114 tagMergeItems.add(
115 new TagMergeItem(key, my, their)
116 );
117 }
118 }
119 fireTableDataChanged();
120 refreshNumUndecidedTags();
121 }
122
123 /**
124 * add a {@see TagMergeItem} to the model
125 *
126 * @param item the item
127 */
128 public void addItem(TagMergeItem item) {
129 if (item != null) {
130 tagMergeItems.add(item);
131 fireTableDataChanged();
132 refreshNumUndecidedTags();
133 }
134 }
135
136 protected void rememberDecision(int row, MergeDecisionType decision) {
137 TagMergeItem item = tagMergeItems.get(row);
138 item.decide(decision);
139 }
140
141 /**
142 * set the merge decision of the {@see TagMergeItem} in row <code>row</code>
143 * to <code>decision</code>.
144 *
145 * @param row the row
146 * @param decision the decision
147 */
148 public void decide(int row, MergeDecisionType decision) {
149 rememberDecision(row, decision);
150 fireTableRowsUpdated(row, row);
151 refreshNumUndecidedTags();
152 }
153
154 /**
155 * set the merge decision of all {@see TagMergeItem} given by indices in <code>rows</code>
156 * to <code>decision</code>.
157 *
158 * @param row the array of row indices
159 * @param decision the decision
160 */
161
162 public void decide(int [] rows, MergeDecisionType decision) {
163 if (rows == null || rows.length == 0)
164 return;
165 for (int row : rows) {
166 rememberDecision(row, decision);
167 }
168 fireTableDataChanged();
169 refreshNumUndecidedTags();
170 }
171
172 @Override
173 public int getRowCount() {
174 return tagMergeItems == null ? 0 : tagMergeItems.size();
175 }
176
177 @Override
178 public Object getValueAt(int row, int column) {
179 // return the tagMergeItem for both columns. The cell
180 // renderer will dispatch on the column index and get
181 // the key or the value from the TagMergeItem
182 //
183 return tagMergeItems.get(row);
184 }
185
186 @Override
187 public boolean isCellEditable(int row, int column) {
188 return false;
189 }
190
191 public TagConflictResolveCommand buildResolveCommand(OsmPrimitive my, OsmPrimitive their) {
192 return new TagConflictResolveCommand(my, their, tagMergeItems);
193 }
194
195 public boolean isResolvedCompletely() {
196 for (TagMergeItem item: tagMergeItems) {
197 if (item.getMergeDecision().equals(MergeDecisionType.UNDECIDED))
198 return false;
199 }
200 return true;
201 }
202
203 public int getNumResolvedConflicts() {
204 int n = 0;
205 for (TagMergeItem item: tagMergeItems) {
206 if (!item.getMergeDecision().equals(MergeDecisionType.UNDECIDED)) {
207 n++;
208 }
209 }
210 return n;
211
212 }
213
214 public int getFirstUndecided(int startIndex) {
215 for (int i=startIndex; i<tagMergeItems.size(); i++) {
216 if (tagMergeItems.get(i).getMergeDecision() == MergeDecisionType.UNDECIDED)
217 return i;
218 }
219 return -1;
220 }
221}
Note: See TracBrowser for help on using the repository browser.