[2512] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
| 2 | package org.openstreetmap.josm.gui.tagging;
|
---|
| 3 |
|
---|
| 4 | import static org.openstreetmap.josm.tools.I18n.trn;
|
---|
| 5 |
|
---|
| 6 | import java.beans.PropertyChangeListener;
|
---|
| 7 | import java.beans.PropertyChangeSupport;
|
---|
| 8 | import java.util.ArrayList;
|
---|
| 9 | import java.util.Collection;
|
---|
| 10 | import java.util.Comparator;
|
---|
| 11 | import java.util.HashMap;
|
---|
| 12 | import java.util.Iterator;
|
---|
| 13 | import java.util.List;
|
---|
| 14 | import java.util.Map;
|
---|
[6258] | 15 | import java.util.Map.Entry;
|
---|
[2512] | 16 |
|
---|
[2974] | 17 | import javax.swing.DefaultListSelectionModel;
|
---|
[2512] | 18 | import javax.swing.table.AbstractTableModel;
|
---|
| 19 |
|
---|
| 20 | import org.openstreetmap.josm.command.ChangePropertyCommand;
|
---|
| 21 | import org.openstreetmap.josm.command.Command;
|
---|
| 22 | import org.openstreetmap.josm.command.SequenceCommand;
|
---|
| 23 | import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
---|
[6092] | 24 | import org.openstreetmap.josm.data.osm.Tag;
|
---|
[3137] | 25 | import org.openstreetmap.josm.data.osm.TagCollection;
|
---|
[2512] | 26 | import org.openstreetmap.josm.data.osm.Tagged;
|
---|
[3141] | 27 | import org.openstreetmap.josm.tools.CheckParameterUtil;
|
---|
[2512] | 28 |
|
---|
| 29 | /**
|
---|
| 30 | * TagEditorModel is a table model.
|
---|
| 31 | *
|
---|
| 32 | */
|
---|
| 33 | public class TagEditorModel extends AbstractTableModel {
|
---|
[6883] | 34 | public static final String PROP_DIRTY = TagEditorModel.class.getName() + ".dirty";
|
---|
[2512] | 35 |
|
---|
| 36 | /** the list holding the tags */
|
---|
[8510] | 37 | protected final transient List<TagModel> tags = new ArrayList<>();
|
---|
[2512] | 38 |
|
---|
| 39 | /** indicates whether the model is dirty */
|
---|
[8840] | 40 | private boolean dirty;
|
---|
[3141] | 41 | private final PropertyChangeSupport propChangeSupport = new PropertyChangeSupport(this);
|
---|
| 42 |
|
---|
[9078] | 43 | private final DefaultListSelectionModel rowSelectionModel;
|
---|
| 44 | private final DefaultListSelectionModel colSelectionModel;
|
---|
[2512] | 45 |
|
---|
| 46 | /**
|
---|
[3141] | 47 | * Creates a new tag editor model. Internally allocates two selection models
|
---|
| 48 | * for row selection and column selection.
|
---|
[3518] | 49 | *
|
---|
[5891] | 50 | * To create a {@link javax.swing.JTable} with this model:
|
---|
[3141] | 51 | * <pre>
|
---|
| 52 | * TagEditorModel model = new TagEditorModel();
|
---|
| 53 | * TagTable tbl = new TagTabel(model);
|
---|
| 54 | * </pre>
|
---|
[3518] | 55 | *
|
---|
[3141] | 56 | * @see #getRowSelectionModel()
|
---|
| 57 | * @see #getColumnSelectionModel()
|
---|
[2512] | 58 | */
|
---|
[3141] | 59 | public TagEditorModel() {
|
---|
| 60 | this.rowSelectionModel = new DefaultListSelectionModel();
|
---|
| 61 | this.colSelectionModel = new DefaultListSelectionModel();
|
---|
| 62 | }
|
---|
[9059] | 63 |
|
---|
[3141] | 64 | /**
|
---|
| 65 | * Creates a new tag editor model.
|
---|
[3518] | 66 | *
|
---|
[3141] | 67 | * @param rowSelectionModel the row selection model. Must not be null.
|
---|
| 68 | * @param colSelectionModel the column selection model. Must not be null.
|
---|
[8291] | 69 | * @throws IllegalArgumentException if {@code rowSelectionModel} is null
|
---|
| 70 | * @throws IllegalArgumentException if {@code colSelectionModel} is null
|
---|
[3141] | 71 | */
|
---|
[8291] | 72 | public TagEditorModel(DefaultListSelectionModel rowSelectionModel, DefaultListSelectionModel colSelectionModel) {
|
---|
[3141] | 73 | CheckParameterUtil.ensureParameterNotNull(rowSelectionModel, "rowSelectionModel");
|
---|
| 74 | CheckParameterUtil.ensureParameterNotNull(colSelectionModel, "colSelectionModel");
|
---|
[2974] | 75 | this.rowSelectionModel = rowSelectionModel;
|
---|
| 76 | this.colSelectionModel = colSelectionModel;
|
---|
[2512] | 77 | }
|
---|
| 78 |
|
---|
| 79 | public void addPropertyChangeListener(PropertyChangeListener listener) {
|
---|
| 80 | propChangeSupport.addPropertyChangeListener(listener);
|
---|
| 81 | }
|
---|
| 82 |
|
---|
[3141] | 83 | /**
|
---|
| 84 | * Replies the row selection model used by this tag editor model
|
---|
[3518] | 85 | *
|
---|
[3141] | 86 | * @return the row selection model used by this tag editor model
|
---|
| 87 | */
|
---|
| 88 | public DefaultListSelectionModel getRowSelectionModel() {
|
---|
| 89 | return rowSelectionModel;
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | /**
|
---|
| 93 | * Replies the column selection model used by this tag editor model
|
---|
[3518] | 94 | *
|
---|
[3141] | 95 | * @return the column selection model used by this tag editor model
|
---|
| 96 | */
|
---|
| 97 | public DefaultListSelectionModel getColumnSelectionModel() {
|
---|
| 98 | return colSelectionModel;
|
---|
| 99 | }
|
---|
| 100 |
|
---|
[2512] | 101 | public void removeProperyChangeListener(PropertyChangeListener listener) {
|
---|
| 102 | propChangeSupport.removePropertyChangeListener(listener);
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | protected void fireDirtyStateChanged(final boolean oldValue, final boolean newValue) {
|
---|
| 106 | propChangeSupport.firePropertyChange(PROP_DIRTY, oldValue, newValue);
|
---|
| 107 | }
|
---|
| 108 |
|
---|
| 109 | protected void setDirty(boolean newValue) {
|
---|
| 110 | boolean oldValue = dirty;
|
---|
| 111 | dirty = newValue;
|
---|
| 112 | if (oldValue != newValue) {
|
---|
| 113 | fireDirtyStateChanged(oldValue, newValue);
|
---|
| 114 | }
|
---|
| 115 | }
|
---|
| 116 |
|
---|
[6064] | 117 | @Override
|
---|
[2512] | 118 | public int getColumnCount() {
|
---|
| 119 | return 2;
|
---|
| 120 | }
|
---|
| 121 |
|
---|
[6064] | 122 | @Override
|
---|
[2512] | 123 | public int getRowCount() {
|
---|
| 124 | return tags.size();
|
---|
| 125 | }
|
---|
| 126 |
|
---|
[6064] | 127 | @Override
|
---|
[2512] | 128 | public Object getValueAt(int rowIndex, int columnIndex) {
|
---|
| 129 | if (rowIndex >= getRowCount())
|
---|
| 130 | throw new IndexOutOfBoundsException("unexpected rowIndex: rowIndex=" + rowIndex);
|
---|
| 131 |
|
---|
| 132 | TagModel tag = tags.get(rowIndex);
|
---|
| 133 | switch(columnIndex) {
|
---|
| 134 | case 0:
|
---|
[2974] | 135 | case 1:
|
---|
| 136 | return tag;
|
---|
[2512] | 137 |
|
---|
| 138 | default:
|
---|
| 139 | throw new IndexOutOfBoundsException("unexpected columnIndex: columnIndex=" + columnIndex);
|
---|
| 140 | }
|
---|
| 141 | }
|
---|
| 142 |
|
---|
[2974] | 143 | @Override
|
---|
| 144 | public void setValueAt(Object value, int row, int col) {
|
---|
| 145 | TagModel tag = get(row);
|
---|
| 146 | if (tag == null) return;
|
---|
| 147 | switch(col) {
|
---|
| 148 | case 0:
|
---|
[8510] | 149 | updateTagName(tag, (String) value);
|
---|
[2974] | 150 | break;
|
---|
| 151 | case 1:
|
---|
[8510] | 152 | String v = (String) value;
|
---|
[6087] | 153 | if (tag.getValueCount() > 1 && !v.isEmpty()) {
|
---|
[2974] | 154 | updateTagValue(tag, v);
|
---|
| 155 | } else if (tag.getValueCount() <= 1) {
|
---|
| 156 | updateTagValue(tag, v);
|
---|
| 157 | }
|
---|
| 158 | }
|
---|
| 159 | }
|
---|
| 160 |
|
---|
[2512] | 161 | /**
|
---|
| 162 | * removes all tags in the model
|
---|
| 163 | */
|
---|
| 164 | public void clear() {
|
---|
| 165 | tags.clear();
|
---|
| 166 | setDirty(true);
|
---|
| 167 | fireTableDataChanged();
|
---|
| 168 | }
|
---|
| 169 |
|
---|
| 170 | /**
|
---|
| 171 | * adds a tag to the model
|
---|
| 172 | *
|
---|
| 173 | * @param tag the tag. Must not be null.
|
---|
| 174 | *
|
---|
[8291] | 175 | * @throws IllegalArgumentException if tag is null
|
---|
[2512] | 176 | */
|
---|
| 177 | public void add(TagModel tag) {
|
---|
[7864] | 178 | CheckParameterUtil.ensureParameterNotNull(tag, "tag");
|
---|
[2512] | 179 | tags.add(tag);
|
---|
| 180 | setDirty(true);
|
---|
| 181 | fireTableDataChanged();
|
---|
| 182 | }
|
---|
| 183 |
|
---|
| 184 | public void prepend(TagModel tag) {
|
---|
[7864] | 185 | CheckParameterUtil.ensureParameterNotNull(tag, "tag");
|
---|
[2512] | 186 | tags.add(0, tag);
|
---|
| 187 | setDirty(true);
|
---|
| 188 | fireTableDataChanged();
|
---|
| 189 | }
|
---|
| 190 |
|
---|
| 191 | /**
|
---|
| 192 | * adds a tag given by a name/value pair to the tag editor model.
|
---|
| 193 | *
|
---|
[6830] | 194 | * If there is no tag with name <code>name</code> yet, a new {@link TagModel} is created
|
---|
[2512] | 195 | * and append to this model.
|
---|
| 196 | *
|
---|
[6830] | 197 | * If there is a tag with name <code>name</code>, <code>value</code> is merged to the list
|
---|
[2512] | 198 | * of values for this tag.
|
---|
| 199 | *
|
---|
| 200 | * @param name the name; converted to "" if null
|
---|
| 201 | * @param value the value; converted to "" if null
|
---|
| 202 | */
|
---|
| 203 | public void add(String name, String value) {
|
---|
| 204 | name = (name == null) ? "" : name;
|
---|
| 205 | value = (value == null) ? "" : value;
|
---|
| 206 |
|
---|
| 207 | TagModel tag = get(name);
|
---|
| 208 | if (tag == null) {
|
---|
| 209 | tag = new TagModel(name, value);
|
---|
[3640] | 210 | int index = tags.size();
|
---|
| 211 | while (index >= 1 && tags.get(index - 1).getName().isEmpty() && tags.get(index - 1).getValue().isEmpty()) {
|
---|
| 212 | index--; // If last line(s) is empty, add new tag before it
|
---|
| 213 | }
|
---|
| 214 | tags.add(index, tag);
|
---|
[2512] | 215 | } else {
|
---|
| 216 | tag.addValue(value);
|
---|
| 217 | }
|
---|
| 218 | setDirty(true);
|
---|
[3141] | 219 | fireTableDataChanged();
|
---|
[2512] | 220 | }
|
---|
| 221 |
|
---|
| 222 | /**
|
---|
| 223 | * replies the tag with name <code>name</code>; null, if no such tag exists
|
---|
| 224 | * @param name the tag name
|
---|
| 225 | * @return the tag with name <code>name</code>; null, if no such tag exists
|
---|
| 226 | */
|
---|
| 227 | public TagModel get(String name) {
|
---|
| 228 | name = (name == null) ? "" : name;
|
---|
| 229 | for (TagModel tag : tags) {
|
---|
| 230 | if (tag.getName().equals(name))
|
---|
| 231 | return tag;
|
---|
| 232 | }
|
---|
| 233 | return null;
|
---|
| 234 | }
|
---|
| 235 |
|
---|
| 236 | public TagModel get(int idx) {
|
---|
[2974] | 237 | if (idx >= tags.size()) return null;
|
---|
[6792] | 238 | return tags.get(idx);
|
---|
[2512] | 239 | }
|
---|
| 240 |
|
---|
[6792] | 241 | @Override
|
---|
| 242 | public boolean isCellEditable(int row, int col) {
|
---|
[2512] | 243 | // all cells are editable
|
---|
| 244 | return true;
|
---|
| 245 | }
|
---|
| 246 |
|
---|
| 247 | /**
|
---|
| 248 | * deletes the names of the tags given by tagIndices
|
---|
| 249 | *
|
---|
| 250 | * @param tagIndices a list of tag indices
|
---|
| 251 | */
|
---|
[8444] | 252 | public void deleteTagNames(int[] tagIndices) {
|
---|
[2512] | 253 | if (tags == null)
|
---|
| 254 | return;
|
---|
| 255 | for (int tagIdx : tagIndices) {
|
---|
| 256 | TagModel tag = tags.get(tagIdx);
|
---|
| 257 | if (tag != null) {
|
---|
| 258 | tag.setName("");
|
---|
| 259 | }
|
---|
| 260 | }
|
---|
| 261 | fireTableDataChanged();
|
---|
| 262 | setDirty(true);
|
---|
| 263 | }
|
---|
| 264 |
|
---|
| 265 | /**
|
---|
| 266 | * deletes the values of the tags given by tagIndices
|
---|
| 267 | *
|
---|
| 268 | * @param tagIndices the lit of tag indices
|
---|
| 269 | */
|
---|
[8444] | 270 | public void deleteTagValues(int[] tagIndices) {
|
---|
[2512] | 271 | if (tags == null)
|
---|
| 272 | return;
|
---|
| 273 | for (int tagIdx : tagIndices) {
|
---|
| 274 | TagModel tag = tags.get(tagIdx);
|
---|
| 275 | if (tag != null) {
|
---|
| 276 | tag.setValue("");
|
---|
| 277 | }
|
---|
| 278 | }
|
---|
| 279 | fireTableDataChanged();
|
---|
| 280 | setDirty(true);
|
---|
| 281 | }
|
---|
| 282 |
|
---|
| 283 | /**
|
---|
| 284 | * Deletes all tags with name <code>name</code>
|
---|
| 285 | *
|
---|
| 286 | * @param name the name. Ignored if null.
|
---|
| 287 | */
|
---|
| 288 | public void delete(String name) {
|
---|
| 289 | if (name == null) return;
|
---|
| 290 | Iterator<TagModel> it = tags.iterator();
|
---|
[2599] | 291 | boolean changed = false;
|
---|
[8510] | 292 | while (it.hasNext()) {
|
---|
[2512] | 293 | TagModel tm = it.next();
|
---|
| 294 | if (tm.getName().equals(name)) {
|
---|
[2599] | 295 | changed = true;
|
---|
[2512] | 296 | it.remove();
|
---|
| 297 | }
|
---|
| 298 | }
|
---|
[2599] | 299 | if (changed) {
|
---|
| 300 | fireTableDataChanged();
|
---|
| 301 | setDirty(true);
|
---|
| 302 | }
|
---|
[2512] | 303 | }
|
---|
[9059] | 304 |
|
---|
[2512] | 305 | /**
|
---|
| 306 | * deletes the tags given by tagIndices
|
---|
| 307 | *
|
---|
| 308 | * @param tagIndices the list of tag indices
|
---|
| 309 | */
|
---|
[8444] | 310 | public void deleteTags(int[] tagIndices) {
|
---|
[2512] | 311 | if (tags == null)
|
---|
| 312 | return;
|
---|
[8338] | 313 | List<TagModel> toDelete = new ArrayList<>();
|
---|
[2512] | 314 | for (int tagIdx : tagIndices) {
|
---|
| 315 | TagModel tag = tags.get(tagIdx);
|
---|
| 316 | if (tag != null) {
|
---|
| 317 | toDelete.add(tag);
|
---|
| 318 | }
|
---|
| 319 | }
|
---|
| 320 | for (TagModel tag : toDelete) {
|
---|
| 321 | tags.remove(tag);
|
---|
| 322 | }
|
---|
| 323 | fireTableDataChanged();
|
---|
| 324 | setDirty(true);
|
---|
| 325 | }
|
---|
| 326 |
|
---|
| 327 | /**
|
---|
| 328 | * creates a new tag and appends it to the model
|
---|
| 329 | */
|
---|
| 330 | public void appendNewTag() {
|
---|
| 331 | TagModel tag = new TagModel();
|
---|
| 332 | tags.add(tag);
|
---|
| 333 | fireTableDataChanged();
|
---|
| 334 | setDirty(true);
|
---|
| 335 | }
|
---|
| 336 |
|
---|
| 337 | /**
|
---|
| 338 | * makes sure the model includes at least one (empty) tag
|
---|
| 339 | */
|
---|
| 340 | public void ensureOneTag() {
|
---|
[6064] | 341 | if (tags.isEmpty()) {
|
---|
[2512] | 342 | appendNewTag();
|
---|
| 343 | }
|
---|
| 344 | }
|
---|
| 345 |
|
---|
| 346 | /**
|
---|
| 347 | * initializes the model with the tags of an OSM primitive
|
---|
| 348 | *
|
---|
| 349 | * @param primitive the OSM primitive
|
---|
| 350 | */
|
---|
| 351 | public void initFromPrimitive(Tagged primitive) {
|
---|
[3138] | 352 | this.tags.clear();
|
---|
[2512] | 353 | for (String key : primitive.keySet()) {
|
---|
| 354 | String value = primitive.get(key);
|
---|
[8510] | 355 | this.tags.add(new TagModel(key, value));
|
---|
[2512] | 356 | }
|
---|
| 357 | TagModel tag = new TagModel();
|
---|
| 358 | sort();
|
---|
| 359 | tags.add(tag);
|
---|
| 360 | setDirty(false);
|
---|
[3518] | 361 | fireTableDataChanged();
|
---|
[2512] | 362 | }
|
---|
| 363 |
|
---|
| 364 | /**
|
---|
[5891] | 365 | * Initializes the model with the tags of an OSM primitive
|
---|
[2512] | 366 | *
|
---|
[5891] | 367 | * @param tags the tags of an OSM primitive
|
---|
[2512] | 368 | */
|
---|
[8510] | 369 | public void initFromTags(Map<String, String> tags) {
|
---|
[3138] | 370 | this.tags.clear();
|
---|
[6258] | 371 | for (Entry<String, String> entry : tags.entrySet()) {
|
---|
| 372 | this.tags.add(new TagModel(entry.getKey(), entry.getValue()));
|
---|
[2512] | 373 | }
|
---|
[3141] | 374 | sort();
|
---|
[2512] | 375 | TagModel tag = new TagModel();
|
---|
| 376 | this.tags.add(tag);
|
---|
| 377 | setDirty(false);
|
---|
| 378 | }
|
---|
| 379 |
|
---|
| 380 | /**
|
---|
[3137] | 381 | * Initializes the model with the tags in a tag collection. Removes
|
---|
| 382 | * all tags if {@code tags} is null.
|
---|
| 383 | *
|
---|
| 384 | * @param tags the tags
|
---|
| 385 | */
|
---|
| 386 | public void initFromTags(TagCollection tags) {
|
---|
[3138] | 387 | this.tags.clear();
|
---|
[8510] | 388 | if (tags == null) {
|
---|
[3137] | 389 | setDirty(false);
|
---|
| 390 | return;
|
---|
| 391 | }
|
---|
| 392 | for (String key : tags.getKeys()) {
|
---|
| 393 | String value = tags.getJoinedValues(key);
|
---|
[8510] | 394 | this.tags.add(new TagModel(key, value));
|
---|
[3137] | 395 | }
|
---|
| 396 | sort();
|
---|
| 397 | // add an empty row
|
---|
| 398 | TagModel tag = new TagModel();
|
---|
| 399 | this.tags.add(tag);
|
---|
| 400 | setDirty(false);
|
---|
| 401 | }
|
---|
| 402 |
|
---|
| 403 | /**
|
---|
[2512] | 404 | * applies the current state of the tag editor model to a primitive
|
---|
| 405 | *
|
---|
| 406 | * @param primitive the primitive
|
---|
| 407 | *
|
---|
| 408 | */
|
---|
| 409 | public void applyToPrimitive(Tagged primitive) {
|
---|
[8581] | 410 | primitive.setKeys(applyToTags(false));
|
---|
[2512] | 411 | }
|
---|
| 412 |
|
---|
| 413 | /**
|
---|
| 414 | * applies the current state of the tag editor model to a map of tags
|
---|
[9231] | 415 | * @param keepEmpty {@code true} to keep empty tags
|
---|
[2512] | 416 | *
|
---|
[8581] | 417 | * @return the map of key/value pairs
|
---|
[2512] | 418 | */
|
---|
[8581] | 419 | private Map<String, String> applyToTags(boolean keepEmpty) {
|
---|
| 420 | Map<String, String> result = new HashMap<>();
|
---|
[2512] | 421 | for (TagModel tag: this.tags) {
|
---|
| 422 | // tag still holds an unchanged list of different values for the same key.
|
---|
| 423 | // no property change command required
|
---|
| 424 | if (tag.getValueCount() > 1) {
|
---|
| 425 | continue;
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 | // tag name holds an empty key. Don't apply it to the selection.
|
---|
| 429 | //
|
---|
[6309] | 430 | if (!keepEmpty && (tag.getName().trim().isEmpty() || tag.getValue().trim().isEmpty())) {
|
---|
[2512] | 431 | continue;
|
---|
| 432 | }
|
---|
[8581] | 433 | result.put(tag.getName().trim(), tag.getValue().trim());
|
---|
[2512] | 434 | }
|
---|
[8581] | 435 | return result;
|
---|
[2512] | 436 | }
|
---|
| 437 |
|
---|
[8510] | 438 | public Map<String, String> getTags() {
|
---|
[6309] | 439 | return getTags(false);
|
---|
| 440 | }
|
---|
| 441 |
|
---|
[8510] | 442 | public Map<String, String> getTags(boolean keepEmpty) {
|
---|
[8581] | 443 | return applyToTags(keepEmpty);
|
---|
[2512] | 444 | }
|
---|
| 445 |
|
---|
| 446 | /**
|
---|
[5266] | 447 | * Replies the tags in this tag editor model as {@link TagCollection}.
|
---|
[3518] | 448 | *
|
---|
[5266] | 449 | * @return the tags in this tag editor model as {@link TagCollection}
|
---|
[3137] | 450 | */
|
---|
| 451 | public TagCollection getTagCollection() {
|
---|
| 452 | return TagCollection.from(getTags());
|
---|
| 453 | }
|
---|
| 454 |
|
---|
| 455 | /**
|
---|
[2512] | 456 | * checks whether the tag model includes a tag with a given key
|
---|
| 457 | *
|
---|
| 458 | * @param key the key
|
---|
| 459 | * @return true, if the tag model includes the tag; false, otherwise
|
---|
| 460 | */
|
---|
| 461 | public boolean includesTag(String key) {
|
---|
| 462 | if (key == null) return false;
|
---|
| 463 | for (TagModel tag : tags) {
|
---|
| 464 | if (tag.getName().equals(key))
|
---|
| 465 | return true;
|
---|
| 466 | }
|
---|
| 467 | return false;
|
---|
| 468 | }
|
---|
| 469 |
|
---|
| 470 | protected Command createUpdateTagCommand(Collection<OsmPrimitive> primitives, TagModel tag) {
|
---|
| 471 |
|
---|
| 472 | // tag still holds an unchanged list of different values for the same key.
|
---|
| 473 | // no property change command required
|
---|
| 474 | if (tag.getValueCount() > 1)
|
---|
| 475 | return null;
|
---|
| 476 |
|
---|
| 477 | // tag name holds an empty key. Don't apply it to the selection.
|
---|
| 478 | //
|
---|
[6087] | 479 | if (tag.getName().trim().isEmpty())
|
---|
[2512] | 480 | return null;
|
---|
| 481 |
|
---|
[6792] | 482 | return new ChangePropertyCommand(primitives, tag.getName(), tag.getValue());
|
---|
[2512] | 483 | }
|
---|
| 484 |
|
---|
| 485 | protected Command createDeleteTagsCommand(Collection<OsmPrimitive> primitives) {
|
---|
| 486 |
|
---|
| 487 | List<String> currentkeys = getKeys();
|
---|
[8338] | 488 | List<Command> commands = new ArrayList<>();
|
---|
[2512] | 489 |
|
---|
| 490 | for (OsmPrimitive primitive : primitives) {
|
---|
| 491 | for (String oldkey : primitive.keySet()) {
|
---|
| 492 | if (!currentkeys.contains(oldkey)) {
|
---|
| 493 | ChangePropertyCommand deleteCommand =
|
---|
[8510] | 494 | new ChangePropertyCommand(primitive, oldkey, null);
|
---|
[2512] | 495 | commands.add(deleteCommand);
|
---|
| 496 | }
|
---|
| 497 | }
|
---|
| 498 | }
|
---|
| 499 |
|
---|
[7024] | 500 | return new SequenceCommand(
|
---|
[2512] | 501 | trn("Remove old keys from up to {0} object", "Remove old keys from up to {0} objects", primitives.size(), primitives.size()),
|
---|
| 502 | commands
|
---|
| 503 | );
|
---|
| 504 | }
|
---|
| 505 |
|
---|
| 506 | /**
|
---|
| 507 | * replies the list of keys of the tags managed by this model
|
---|
| 508 | *
|
---|
| 509 | * @return the list of keys managed by this model
|
---|
| 510 | */
|
---|
| 511 | public List<String> getKeys() {
|
---|
[8338] | 512 | List<String> keys = new ArrayList<>();
|
---|
[2512] | 513 | for (TagModel tag: tags) {
|
---|
[6087] | 514 | if (!tag.getName().trim().isEmpty()) {
|
---|
[2512] | 515 | keys.add(tag.getName());
|
---|
| 516 | }
|
---|
| 517 | }
|
---|
| 518 | return keys;
|
---|
| 519 | }
|
---|
| 520 |
|
---|
| 521 | /**
|
---|
| 522 | * sorts the current tags according alphabetical order of names
|
---|
| 523 | */
|
---|
| 524 | protected void sort() {
|
---|
| 525 | java.util.Collections.sort(
|
---|
| 526 | tags,
|
---|
| 527 | new Comparator<TagModel>() {
|
---|
[6064] | 528 | @Override
|
---|
[2512] | 529 | public int compare(TagModel self, TagModel other) {
|
---|
| 530 | return self.getName().compareTo(other.getName());
|
---|
| 531 | }
|
---|
| 532 | }
|
---|
| 533 | );
|
---|
| 534 | }
|
---|
| 535 |
|
---|
| 536 | /**
|
---|
| 537 | * updates the name of a tag and sets the dirty state to true if
|
---|
| 538 | * the new name is different from the old name.
|
---|
| 539 | *
|
---|
| 540 | * @param tag the tag
|
---|
| 541 | * @param newName the new name
|
---|
| 542 | */
|
---|
| 543 | public void updateTagName(TagModel tag, String newName) {
|
---|
| 544 | String oldName = tag.getName();
|
---|
| 545 | tag.setName(newName);
|
---|
[8444] | 546 | if (!newName.equals(oldName)) {
|
---|
[2512] | 547 | setDirty(true);
|
---|
| 548 | }
|
---|
[2974] | 549 | SelectionStateMemento memento = new SelectionStateMemento();
|
---|
[2599] | 550 | fireTableDataChanged();
|
---|
[2974] | 551 | memento.apply();
|
---|
[2512] | 552 | }
|
---|
| 553 |
|
---|
| 554 | /**
|
---|
| 555 | * updates the value value of a tag and sets the dirty state to true if the
|
---|
| 556 | * new name is different from the old name
|
---|
| 557 | *
|
---|
| 558 | * @param tag the tag
|
---|
| 559 | * @param newValue the new value
|
---|
| 560 | */
|
---|
| 561 | public void updateTagValue(TagModel tag, String newValue) {
|
---|
| 562 | String oldValue = tag.getValue();
|
---|
| 563 | tag.setValue(newValue);
|
---|
[8444] | 564 | if (!newValue.equals(oldValue)) {
|
---|
[2512] | 565 | setDirty(true);
|
---|
| 566 | }
|
---|
[2974] | 567 | SelectionStateMemento memento = new SelectionStateMemento();
|
---|
[2599] | 568 | fireTableDataChanged();
|
---|
[2974] | 569 | memento.apply();
|
---|
[2512] | 570 | }
|
---|
| 571 |
|
---|
| 572 | /**
|
---|
[6092] | 573 | * Load tags from given list
|
---|
| 574 | * @param tags - the list
|
---|
| 575 | */
|
---|
| 576 | public void updateTags(List<Tag> tags) {
|
---|
| 577 | if (tags.isEmpty())
|
---|
| 578 | return;
|
---|
| 579 |
|
---|
[7005] | 580 | Map<String, TagModel> modelTags = new HashMap<>();
|
---|
[8510] | 581 | for (int i = 0; i < getRowCount(); i++) {
|
---|
[6092] | 582 | TagModel tagModel = get(i);
|
---|
| 583 | modelTags.put(tagModel.getName(), tagModel);
|
---|
| 584 | }
|
---|
| 585 | for (Tag tag: tags) {
|
---|
| 586 | TagModel existing = modelTags.get(tag.getKey());
|
---|
| 587 |
|
---|
| 588 | if (tag.getValue().isEmpty()) {
|
---|
| 589 | if (existing != null) {
|
---|
| 590 | delete(tag.getKey());
|
---|
| 591 | }
|
---|
| 592 | } else {
|
---|
| 593 | if (existing != null) {
|
---|
| 594 | updateTagValue(existing, tag.getValue());
|
---|
| 595 | } else {
|
---|
| 596 | add(tag.getKey(), tag.getValue());
|
---|
| 597 | }
|
---|
| 598 | }
|
---|
| 599 | }
|
---|
| 600 | }
|
---|
| 601 |
|
---|
| 602 | /**
|
---|
[2512] | 603 | * replies true, if this model has been updated
|
---|
| 604 | *
|
---|
| 605 | * @return true, if this model has been updated
|
---|
| 606 | */
|
---|
| 607 | public boolean isDirty() {
|
---|
| 608 | return dirty;
|
---|
| 609 | }
|
---|
[2974] | 610 |
|
---|
| 611 | class SelectionStateMemento {
|
---|
[9078] | 612 | private final int rowMin;
|
---|
| 613 | private final int rowMax;
|
---|
| 614 | private final int colMin;
|
---|
| 615 | private final int colMax;
|
---|
[2974] | 616 |
|
---|
[8836] | 617 | SelectionStateMemento() {
|
---|
[2974] | 618 | rowMin = rowSelectionModel.getMinSelectionIndex();
|
---|
| 619 | rowMax = rowSelectionModel.getMaxSelectionIndex();
|
---|
| 620 | colMin = colSelectionModel.getMinSelectionIndex();
|
---|
| 621 | colMax = colSelectionModel.getMaxSelectionIndex();
|
---|
| 622 | }
|
---|
| 623 |
|
---|
| 624 | public void apply() {
|
---|
| 625 | rowSelectionModel.setValueIsAdjusting(true);
|
---|
| 626 | colSelectionModel.setValueIsAdjusting(true);
|
---|
[8510] | 627 | if (rowMin >= 0 && rowMax >= 0) {
|
---|
[2974] | 628 | rowSelectionModel.setSelectionInterval(rowMin, rowMax);
|
---|
| 629 | }
|
---|
[8510] | 630 | if (colMin >= 0 && colMax >= 0) {
|
---|
[2974] | 631 | colSelectionModel.setSelectionInterval(colMin, colMax);
|
---|
| 632 | }
|
---|
| 633 | rowSelectionModel.setValueIsAdjusting(false);
|
---|
| 634 | colSelectionModel.setValueIsAdjusting(false);
|
---|
| 635 | }
|
---|
| 636 | }
|
---|
[2512] | 637 | }
|
---|