source: josm/trunk/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java@ 2040

Last change on this file since 2040 was 2040, checked in by Gubaer, 15 years ago

improved upload dialog
new: tags for changesets
new: multiple uploads to the same changeset
fixed #3381: simple imput of a changeset source
fixed #2491: Allow arbitrary key-value pairs in changesets
fixed #2436: Allow multiple uploads to one changeset

File size: 12.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.tagging;
3
4import static org.openstreetmap.josm.tools.I18n.trn;
5
6import java.beans.PropertyChangeListener;
7import java.beans.PropertyChangeSupport;
8import java.util.ArrayList;
9import java.util.Collection;
10import java.util.Comparator;
11import java.util.List;
12import java.util.logging.Logger;
13
14import javax.swing.table.AbstractTableModel;
15
16import org.openstreetmap.josm.command.ChangePropertyCommand;
17import org.openstreetmap.josm.command.Command;
18import org.openstreetmap.josm.command.SequenceCommand;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20
21
22/**
23 * TagEditorModel is a table model.
24 *
25 *
26 * @author gubaer
27 *
28 */
29@SuppressWarnings("serial")
30public class TagEditorModel extends AbstractTableModel {
31 static private final Logger logger = Logger.getLogger(TagEditorModel.class.getName());
32
33 static public final String PROP_DIRTY = TagEditorModel.class.getName() + ".dirty";
34
35 /** the list holding the tags */
36 private ArrayList<TagModel> tags = null;
37
38 /** indicates whether the model is dirty */
39 private boolean dirty = false;
40 private PropertyChangeSupport propChangeSupport = null;
41
42 /**
43 * constructor
44 */
45 public TagEditorModel(){
46 tags = new ArrayList<TagModel>();
47 propChangeSupport = new PropertyChangeSupport(this);
48 }
49
50 public void addPropertyChangeListener(PropertyChangeListener listener) {
51 propChangeSupport.addPropertyChangeListener(listener);
52 }
53
54 public void removeProperyChangeListener(PropertyChangeListener listener) {
55 propChangeSupport.removePropertyChangeListener(listener);
56 }
57
58 protected void fireDirtyStateChanged(final boolean oldValue, final boolean newValue) {
59 propChangeSupport.firePropertyChange(PROP_DIRTY, oldValue, newValue);
60 }
61
62 protected void setDirty(boolean newValue) {
63 boolean oldValue = dirty;
64 dirty = newValue;
65 if (oldValue != newValue) {
66 fireDirtyStateChanged(oldValue, newValue);
67 }
68 }
69
70 public int getColumnCount() {
71 return 2;
72 }
73
74 public int getRowCount() {
75 return tags.size();
76 }
77
78 public Object getValueAt(int rowIndex, int columnIndex) {
79 if (rowIndex >= getRowCount())
80 throw new IndexOutOfBoundsException("unexpected rowIndex: rowIndex=" + rowIndex);
81
82 TagModel tag = tags.get(rowIndex);
83 switch(columnIndex) {
84 case 0:
85 case 1: return tag;
86
87 default:
88 throw new IndexOutOfBoundsException("unexpected columnIndex: columnIndex=" + columnIndex);
89 }
90 }
91
92
93 /**
94 * removes all tags in the model
95 */
96 public void clear() {
97 tags.clear();
98 setDirty(true);
99 fireTableDataChanged();
100 }
101
102 /**
103 * adds a tag to the model
104 *
105 * @param tag the tag. Must not be null.
106 *
107 * @exception IllegalArgumentException thrown, if tag is null
108 */
109 public void add(TagModel tag) {
110 if (tag == null)
111 throw new IllegalArgumentException("argument 'tag' must not be null");
112 tags.add(tag);
113 setDirty(true);
114 fireTableDataChanged();
115 }
116
117
118 public void prepend(TagModel tag) {
119 if (tag == null)
120 throw new IllegalArgumentException("argument 'tag' must not be null");
121 tags.add(0, tag);
122 setDirty(true);
123 fireTableDataChanged();
124 }
125
126
127 /**
128 * adds a tag given by a name/value pair to the tag editor model.
129 *
130 * If there is no tag with name <code>name</name> yet, a new {@link TagModel} is created
131 * and append to this model.
132 *
133 * If there is a tag with name <code>name</name>, <code>value</code> is merged to the list
134 * of values for this tag.
135 *
136 * @param name the name; converted to "" if null
137 * @param value the value; converted to "" if null
138 */
139 public void add(String name, String value) {
140 name = (name == null) ? "" : name;
141 value = (value == null) ? "" : value;
142
143 TagModel tag = get(name);
144 if (tag == null) {
145 tag = new TagModel(name, value);
146 add(tag);
147 } else {
148 tag.addValue(value);
149 }
150 setDirty(true);
151 }
152
153
154 /**
155 * replies the tag with name <code>name</code>; null, if no such tag exists
156 * @param name the tag name
157 * @return the tag with name <code>name</code>; null, if no such tag exists
158 */
159 public TagModel get(String name) {
160 name = (name == null) ? "" : name;
161 for (TagModel tag : tags) {
162 if (tag.getName().equals(name))
163 return tag;
164 }
165 return null;
166 }
167
168 public TagModel get(int idx) {
169 TagModel tagModel = tags.get(idx);
170 return tagModel;
171 }
172
173
174
175 @Override public boolean isCellEditable(int row, int col) {
176 // all cells are editable
177 return true;
178 }
179
180
181 /**
182 * deletes the names of the tags given by tagIndices
183 *
184 * @param tagIndices a list of tag indices
185 */
186 public void deleteTagNames(int [] tagIndices) {
187 if (tags == null)
188 return;
189 for (int tagIdx : tagIndices) {
190 TagModel tag = tags.get(tagIdx);
191 if (tag != null) {
192 tag.setName("");
193 }
194 }
195 fireTableDataChanged();
196 setDirty(true);
197 }
198
199 /**
200 * deletes the values of the tags given by tagIndices
201 *
202 * @param tagIndices the lit of tag indices
203 */
204 public void deleteTagValues(int [] tagIndices) {
205 if (tags == null)
206 return;
207 for (int tagIdx : tagIndices) {
208 TagModel tag = tags.get(tagIdx);
209 if (tag != null) {
210 tag.setValue("");
211 }
212 }
213 fireTableDataChanged();
214 setDirty(true);
215 }
216
217 /**
218 * deletes the tags given by tagIndices
219 *
220 * @param tagIndices the list of tag indices
221 */
222 public void deleteTags(int [] tagIndices) {
223 if (tags == null)
224 return;
225 ArrayList<TagModel> toDelete = new ArrayList<TagModel>();
226 for (int tagIdx : tagIndices) {
227 TagModel tag = tags.get(tagIdx);
228 if (tag != null) {
229 toDelete.add(tag);
230 }
231 }
232 for (TagModel tag : toDelete) {
233 tags.remove(tag);
234 }
235 fireTableDataChanged();
236 setDirty(true);
237 }
238
239
240 /**
241 * creates a new tag and appends it to the model
242 */
243 public void appendNewTag() {
244 TagModel tag = new TagModel();
245 tags.add(tag);
246 fireTableDataChanged();
247 setDirty(true);
248 }
249
250 /**
251 * makes sure the model includes at least one (empty) tag
252 */
253 public void ensureOneTag() {
254 if (tags.size() == 0) {
255 appendNewTag();
256 }
257 }
258
259 /**
260 * initializes the model with the tags of an OSM primitive
261 *
262 * @param primitive the OSM primitive
263 */
264 public void initFromPrimitive(OsmPrimitive primitive) {
265 clear();
266 for (String key : primitive.keySet()) {
267 String value = primitive.get(key);
268 add(key,value);
269 }
270 TagModel tag = new TagModel();
271 sort();
272 tags.add(tag);
273 setDirty(false);
274 }
275
276 /**
277 * applies the current state of the tag editor model to a primitive
278 *
279 * @param primitive the primitive
280 *
281 */
282 public void applyToPrimitive(OsmPrimitive primitive) {
283 primitive.removeAll();
284 for (TagModel tag: tags) {
285 // tag still holds an unchanged list of different values for the same key.
286 // no property change command required
287 if (tag.getValueCount() > 1) {
288 continue;
289 }
290
291 // tag name holds an empty key. Don't apply it to the selection.
292 //
293 if (tag.getName().trim().equals("")) {
294 continue;
295 }
296 primitive.put(tag.getName(), tag.getValue());
297 }
298 }
299
300 /**
301 * checks whether the tag model includes a tag with a given key
302 *
303 * @param key the key
304 * @return true, if the tag model includes the tag; false, otherwise
305 */
306 public boolean includesTag(String key) {
307 if (key == null) return false;
308 for (TagModel tag : tags) {
309 if (tag.getName().equals(key))
310 return true;
311 }
312 return false;
313 }
314
315
316 protected Command createUpdateTagCommand(Collection<OsmPrimitive> primitives, TagModel tag) {
317
318 // tag still holds an unchanged list of different values for the same key.
319 // no property change command required
320 if (tag.getValueCount() > 1)
321 return null;
322
323 // tag name holds an empty key. Don't apply it to the selection.
324 //
325 if (tag.getName().trim().equals(""))
326 return null;
327
328 String newkey = tag.getName();
329 String newvalue = tag.getValue();
330
331 ChangePropertyCommand command = new ChangePropertyCommand(primitives,newkey, newvalue);
332 return command;
333 }
334
335 protected Command createDeleteTagsCommand(Collection<OsmPrimitive> primitives) {
336
337 List<String> currentkeys = getKeys();
338 ArrayList<Command> commands = new ArrayList<Command>();
339
340 for (OsmPrimitive primitive : primitives) {
341 for (String oldkey : primitive.keySet()) {
342 if (!currentkeys.contains(oldkey)) {
343 ChangePropertyCommand deleteCommand =
344 new ChangePropertyCommand(primitive,oldkey,null);
345 commands.add(deleteCommand);
346 }
347 }
348 }
349
350 SequenceCommand command = new SequenceCommand(
351 trn("Remove old keys from up to {0} object", "Remove old keys from up to {0} objects", primitives.size(), primitives.size()),
352 commands
353 );
354
355 return command;
356 }
357
358 /**
359 * replies the list of keys of the tags managed by this model
360 *
361 * @return the list of keys managed by this model
362 */
363 public List<String> getKeys() {
364 ArrayList<String> keys = new ArrayList<String>();
365 for (TagModel tag: tags) {
366 if (!tag.getName().trim().equals("")) {
367 keys.add(tag.getName());
368 }
369 }
370 return keys;
371 }
372
373 /**
374 * sorts the current tags according alphabetical order of names
375 */
376 protected void sort() {
377 java.util.Collections.sort(
378 tags,
379 new Comparator<TagModel>() {
380 public int compare(TagModel self, TagModel other) {
381 return self.getName().compareTo(other.getName());
382 }
383 }
384 );
385 }
386
387 /**
388 * updates the name of a tag and sets the dirty state to true if
389 * the new name is different from the old name.
390 *
391 * @param tag the tag
392 * @param newName the new name
393 */
394 public void updateTagName(TagModel tag, String newName) {
395 String oldName = tag.getName();
396 tag.setName(newName);
397 if (! newName.equals(oldName)) {
398 setDirty(true);
399 }
400 }
401
402 /**
403 * updates the value value of a tag and sets the dirty state to true if the
404 * new name is different from the old name
405 *
406 * @param tag the tag
407 * @param newValue the new value
408 */
409 public void updateTagValue(TagModel tag, String newValue) {
410 String oldValue = tag.getValue();
411 tag.setValue(newValue);
412 if (! newValue.equals(oldValue)) {
413 setDirty(true);
414 }
415 }
416
417 /**
418 * replies true, if this model has been updated
419 *
420 * @return true, if this model has been updated
421 */
422 public boolean isDirty() {
423 return dirty;
424 }
425}
Note: See TracBrowser for help on using the repository browser.