source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java@ 9632

Last change on this file since 9632 was 9632, checked in by Don-vip, 8 years ago

fix #12443 - NPE (regression from r9588, see #12412)

  • Property svn:eol-style set to native
File size: 27.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.relation;
3
4import java.util.ArrayList;
5import java.util.Arrays;
6import java.util.Collection;
7import java.util.Collections;
8import java.util.EnumSet;
9import java.util.HashSet;
10import java.util.Iterator;
11import java.util.List;
12import java.util.Set;
13import java.util.TreeSet;
14import java.util.concurrent.CopyOnWriteArrayList;
15
16import javax.swing.DefaultListSelectionModel;
17import javax.swing.ListSelectionModel;
18import javax.swing.event.TableModelEvent;
19import javax.swing.event.TableModelListener;
20import javax.swing.table.AbstractTableModel;
21
22import org.openstreetmap.josm.Main;
23import org.openstreetmap.josm.data.SelectionChangedListener;
24import org.openstreetmap.josm.data.osm.DataSet;
25import org.openstreetmap.josm.data.osm.OsmPrimitive;
26import org.openstreetmap.josm.data.osm.Relation;
27import org.openstreetmap.josm.data.osm.RelationMember;
28import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
29import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
30import org.openstreetmap.josm.data.osm.event.DataSetListener;
31import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
32import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
33import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
34import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
35import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
36import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
37import org.openstreetmap.josm.gui.dialogs.relation.sort.RelationSorter;
38import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType;
39import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionTypeCalculator;
40import org.openstreetmap.josm.gui.layer.OsmDataLayer;
41import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset;
42import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetHandler;
43import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetType;
44import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets;
45import org.openstreetmap.josm.gui.util.GuiHelper;
46import org.openstreetmap.josm.gui.widgets.OsmPrimitivesTableModel;
47
48public class MemberTableModel extends AbstractTableModel
49implements TableModelListener, SelectionChangedListener, DataSetListener, OsmPrimitivesTableModel {
50
51 /**
52 * data of the table model: The list of members and the cached WayConnectionType of each member.
53 **/
54 private final transient List<RelationMember> members;
55 private transient List<WayConnectionType> connectionType;
56 private final transient Relation relation;
57
58 private DefaultListSelectionModel listSelectionModel;
59 private final transient CopyOnWriteArrayList<IMemberModelListener> listeners;
60 private final transient OsmDataLayer layer;
61 private final transient TaggingPresetHandler presetHandler;
62
63 private final transient WayConnectionTypeCalculator wayConnectionTypeCalculator = new WayConnectionTypeCalculator();
64 private final transient RelationSorter relationSorter = new RelationSorter();
65
66 /**
67 * constructor
68 * @param relation relation
69 * @param layer data layer
70 * @param presetHandler tagging preset handler
71 */
72 public MemberTableModel(Relation relation, OsmDataLayer layer, TaggingPresetHandler presetHandler) {
73 this.relation = relation;
74 this.members = new ArrayList<>();
75 this.listeners = new CopyOnWriteArrayList<>();
76 this.layer = layer;
77 this.presetHandler = presetHandler;
78 addTableModelListener(this);
79 }
80
81 /**
82 * Returns the data layer.
83 * @return the data layer
84 */
85 public OsmDataLayer getLayer() {
86 return layer;
87 }
88
89 public void register() {
90 DataSet.addSelectionListener(this);
91 getLayer().data.addDataSetListener(this);
92 }
93
94 public void unregister() {
95 DataSet.removeSelectionListener(this);
96 getLayer().data.removeDataSetListener(this);
97 }
98
99 /* --------------------------------------------------------------------------- */
100 /* Interface SelectionChangedListener */
101 /* --------------------------------------------------------------------------- */
102 @Override
103 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
104 if (Main.main.getEditLayer() != this.layer) return;
105 // just trigger a repaint
106 Collection<RelationMember> sel = getSelectedMembers();
107 fireTableDataChanged();
108 setSelectedMembers(sel);
109 }
110
111 /* --------------------------------------------------------------------------- */
112 /* Interface DataSetListener */
113 /* --------------------------------------------------------------------------- */
114 @Override
115 public void dataChanged(DataChangedEvent event) {
116 // just trigger a repaint - the display name of the relation members may have changed
117 Collection<RelationMember> sel = getSelectedMembers();
118 GuiHelper.runInEDT(new Runnable() {
119 @Override
120 public void run() {
121 fireTableDataChanged();
122 }
123 });
124 setSelectedMembers(sel);
125 }
126
127 @Override
128 public void nodeMoved(NodeMovedEvent event) {
129 // ignore
130 }
131
132 @Override
133 public void primitivesAdded(PrimitivesAddedEvent event) {
134 // ignore
135 }
136
137 @Override
138 public void primitivesRemoved(PrimitivesRemovedEvent event) {
139 // ignore - the relation in the editor might become out of sync with the relation
140 // in the dataset. We will deal with it when the relation editor is closed or
141 // when the changes in the editor are applied.
142 }
143
144 @Override
145 public void relationMembersChanged(RelationMembersChangedEvent event) {
146 // ignore - the relation in the editor might become out of sync with the relation
147 // in the dataset. We will deal with it when the relation editor is closed or
148 // when the changes in the editor are applied.
149 }
150
151 @Override
152 public void tagsChanged(TagsChangedEvent event) {
153 // just refresh the respective table cells
154 //
155 Collection<RelationMember> sel = getSelectedMembers();
156 for (int i = 0; i < members.size(); i++) {
157 if (members.get(i).getMember() == event.getPrimitive()) {
158 fireTableCellUpdated(i, 1 /* the column with the primitive name */);
159 }
160 }
161 setSelectedMembers(sel);
162 }
163
164 @Override
165 public void wayNodesChanged(WayNodesChangedEvent event) {
166 // ignore
167 }
168
169 @Override
170 public void otherDatasetChange(AbstractDatasetChangedEvent event) {
171 // ignore
172 }
173
174 /* --------------------------------------------------------------------------- */
175
176 public void addMemberModelListener(IMemberModelListener listener) {
177 if (listener != null) {
178 listeners.addIfAbsent(listener);
179 }
180 }
181
182 public void removeMemberModelListener(IMemberModelListener listener) {
183 listeners.remove(listener);
184 }
185
186 protected void fireMakeMemberVisible(int index) {
187 for (IMemberModelListener listener : listeners) {
188 listener.makeMemberVisible(index);
189 }
190 }
191
192 public void populate(Relation relation) {
193 members.clear();
194 if (relation != null) {
195 // make sure we work with clones of the relation members in the model.
196 members.addAll(new Relation(relation).getMembers());
197 }
198 fireTableDataChanged();
199 }
200
201 @Override
202 public int getColumnCount() {
203 return 3;
204 }
205
206 @Override
207 public int getRowCount() {
208 return members.size();
209 }
210
211 @Override
212 public Object getValueAt(int rowIndex, int columnIndex) {
213 switch (columnIndex) {
214 case 0:
215 return members.get(rowIndex).getRole();
216 case 1:
217 return members.get(rowIndex).getMember();
218 case 2:
219 return getWayConnection(rowIndex);
220 }
221 // should not happen
222 return null;
223 }
224
225 @Override
226 public boolean isCellEditable(int rowIndex, int columnIndex) {
227 return columnIndex == 0;
228 }
229
230 @Override
231 public void setValueAt(Object value, int rowIndex, int columnIndex) {
232 // fix #10524 - IndexOutOfBoundsException: Index: 2, Size: 2
233 if (rowIndex >= members.size()) {
234 return;
235 }
236 RelationMember member = members.get(rowIndex);
237 RelationMember newMember = new RelationMember(value.toString(), member.getMember());
238 members.remove(rowIndex);
239 members.add(rowIndex, newMember);
240 }
241
242 @Override
243 public OsmPrimitive getReferredPrimitive(int idx) {
244 return members.get(idx).getMember();
245 }
246
247 public void moveUp(int[] selectedRows) {
248 if (!canMoveUp(selectedRows))
249 return;
250
251 for (int row : selectedRows) {
252 RelationMember member1 = members.get(row);
253 RelationMember member2 = members.get(row - 1);
254 members.set(row, member2);
255 members.set(row - 1, member1);
256 }
257 fireTableDataChanged();
258 getSelectionModel().setValueIsAdjusting(true);
259 getSelectionModel().clearSelection();
260 for (int row : selectedRows) {
261 row--;
262 getSelectionModel().addSelectionInterval(row, row);
263 }
264 getSelectionModel().setValueIsAdjusting(false);
265 fireMakeMemberVisible(selectedRows[0] - 1);
266 }
267
268 public void moveDown(int[] selectedRows) {
269 if (!canMoveDown(selectedRows))
270 return;
271
272 for (int i = selectedRows.length - 1; i >= 0; i--) {
273 int row = selectedRows[i];
274 RelationMember member1 = members.get(row);
275 RelationMember member2 = members.get(row + 1);
276 members.set(row, member2);
277 members.set(row + 1, member1);
278 }
279 fireTableDataChanged();
280 getSelectionModel();
281 getSelectionModel().setValueIsAdjusting(true);
282 getSelectionModel().clearSelection();
283 for (int row : selectedRows) {
284 row++;
285 getSelectionModel().addSelectionInterval(row, row);
286 }
287 getSelectionModel().setValueIsAdjusting(false);
288 fireMakeMemberVisible(selectedRows[0] + 1);
289 }
290
291 public void remove(int[] selectedRows) {
292 if (!canRemove(selectedRows))
293 return;
294 int offset = 0;
295 for (int row : selectedRows) {
296 row -= offset;
297 if (members.size() > row) {
298 members.remove(row);
299 offset++;
300 }
301 }
302 fireTableDataChanged();
303 }
304
305 public boolean canMoveUp(int[] rows) {
306 if (rows == null || rows.length == 0)
307 return false;
308 Arrays.sort(rows);
309 return rows[0] > 0 && !members.isEmpty();
310 }
311
312 public boolean canMoveDown(int[] rows) {
313 if (rows == null || rows.length == 0)
314 return false;
315 Arrays.sort(rows);
316 return !members.isEmpty() && rows[rows.length - 1] < members.size() - 1;
317 }
318
319 public boolean canRemove(int[] rows) {
320 if (rows == null || rows.length == 0)
321 return false;
322 return true;
323 }
324
325 public DefaultListSelectionModel getSelectionModel() {
326 if (listSelectionModel == null) {
327 listSelectionModel = new DefaultListSelectionModel();
328 listSelectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
329 }
330 return listSelectionModel;
331 }
332
333 public void removeMembersReferringTo(List<? extends OsmPrimitive> primitives) {
334 if (primitives == null)
335 return;
336 Iterator<RelationMember> it = members.iterator();
337 while (it.hasNext()) {
338 RelationMember member = it.next();
339 if (primitives.contains(member.getMember())) {
340 it.remove();
341 }
342 }
343 fireTableDataChanged();
344 }
345
346 public void applyToRelation(Relation relation) {
347 relation.setMembers(members);
348 }
349
350 public boolean hasSameMembersAs(Relation relation) {
351 if (relation == null)
352 return false;
353 if (relation.getMembersCount() != members.size())
354 return false;
355 for (int i = 0; i < relation.getMembersCount(); i++) {
356 if (!relation.getMember(i).equals(members.get(i)))
357 return false;
358 }
359 return true;
360 }
361
362 /**
363 * Replies the set of incomplete primitives
364 *
365 * @return the set of incomplete primitives
366 */
367 public Set<OsmPrimitive> getIncompleteMemberPrimitives() {
368 Set<OsmPrimitive> ret = new HashSet<>();
369 for (RelationMember member : members) {
370 if (member.getMember().isIncomplete()) {
371 ret.add(member.getMember());
372 }
373 }
374 return ret;
375 }
376
377 /**
378 * Replies the set of selected incomplete primitives
379 *
380 * @return the set of selected incomplete primitives
381 */
382 public Set<OsmPrimitive> getSelectedIncompleteMemberPrimitives() {
383 Set<OsmPrimitive> ret = new HashSet<>();
384 for (RelationMember member : getSelectedMembers()) {
385 if (member.getMember().isIncomplete()) {
386 ret.add(member.getMember());
387 }
388 }
389 return ret;
390 }
391
392 /**
393 * Replies true if at least one the relation members is incomplete
394 *
395 * @return true if at least one the relation members is incomplete
396 */
397 public boolean hasIncompleteMembers() {
398 for (RelationMember member : members) {
399 if (member.getMember().isIncomplete())
400 return true;
401 }
402 return false;
403 }
404
405 /**
406 * Replies true if at least one of the selected members is incomplete
407 *
408 * @return true if at least one of the selected members is incomplete
409 */
410 public boolean hasIncompleteSelectedMembers() {
411 for (RelationMember member : getSelectedMembers()) {
412 if (member.getMember().isIncomplete())
413 return true;
414 }
415 return false;
416 }
417
418 protected List<Integer> getSelectedIndices() {
419 List<Integer> selectedIndices = new ArrayList<>();
420 for (int i = 0; i < members.size(); i++) {
421 if (getSelectionModel().isSelectedIndex(i)) {
422 selectedIndices.add(i);
423 }
424 }
425 return selectedIndices;
426 }
427
428 private void addMembersAtIndex(List<? extends OsmPrimitive> primitives, int index) {
429 if (primitives == null)
430 return;
431 int idx = index;
432 for (OsmPrimitive primitive : primitives) {
433 final RelationMember member = getRelationMemberForPrimitive(primitive);
434 members.add(idx++, member);
435 }
436 fireTableDataChanged();
437 getSelectionModel().clearSelection();
438 getSelectionModel().addSelectionInterval(index, index + primitives.size() - 1);
439 fireMakeMemberVisible(index);
440 }
441
442 RelationMember getRelationMemberForPrimitive(final OsmPrimitive primitive) {
443 final Collection<TaggingPreset> presets = TaggingPresets.getMatchingPresets(
444 EnumSet.of(relation != null ? TaggingPresetType.forPrimitive(relation) : TaggingPresetType.RELATION),
445 presetHandler.getSelection().iterator().next().getKeys(), false);
446 Collection<String> potentialRoles = new TreeSet<>();
447 for (TaggingPreset tp : presets) {
448 String suggestedRole = tp.suggestRoleForOsmPrimitive(primitive);
449 if (suggestedRole != null) {
450 potentialRoles.add(suggestedRole);
451 }
452 }
453 // TODO: propose user to choose role among potential ones instead of picking first one
454 final String role = potentialRoles.isEmpty() ? "" : potentialRoles.iterator().next();
455 return new RelationMember(role == null ? "" : role, primitive);
456 }
457
458 void addMembersAtIndex(final Iterable<RelationMember> newMembers, final int index) {
459 int idx = index;
460 for (RelationMember member : newMembers) {
461 members.add(idx++, member);
462 }
463 invalidateConnectionType();
464 fireTableRowsInserted(index, idx - 1);
465 }
466
467 public void addMembersAtBeginning(List<? extends OsmPrimitive> primitives) {
468 addMembersAtIndex(primitives, 0);
469 }
470
471 public void addMembersAtEnd(List<? extends OsmPrimitive> primitives) {
472 addMembersAtIndex(primitives, members.size());
473 }
474
475 public void addMembersBeforeIdx(List<? extends OsmPrimitive> primitives, int idx) {
476 addMembersAtIndex(primitives, idx);
477 }
478
479 public void addMembersAfterIdx(List<? extends OsmPrimitive> primitives, int idx) {
480 addMembersAtIndex(primitives, idx + 1);
481 }
482
483 /**
484 * Replies the number of members which refer to a particular primitive
485 *
486 * @param primitive the primitive
487 * @return the number of members which refer to a particular primitive
488 */
489 public int getNumMembersWithPrimitive(OsmPrimitive primitive) {
490 int count = 0;
491 for (RelationMember member : members) {
492 if (member.getMember().equals(primitive)) {
493 count++;
494 }
495 }
496 return count;
497 }
498
499 /**
500 * updates the role of the members given by the indices in <code>idx</code>
501 *
502 * @param idx the array of indices
503 * @param role the new role
504 */
505 public void updateRole(int[] idx, String role) {
506 if (idx == null || idx.length == 0)
507 return;
508 for (int row : idx) {
509 // fix #7885 - IndexOutOfBoundsException: Index: 39, Size: 39
510 if (row >= members.size()) {
511 continue;
512 }
513 RelationMember oldMember = members.get(row);
514 RelationMember newMember = new RelationMember(role, oldMember.getMember());
515 members.remove(row);
516 members.add(row, newMember);
517 }
518 fireTableDataChanged();
519 for (int row : idx) {
520 getSelectionModel().addSelectionInterval(row, row);
521 }
522 }
523
524 /**
525 * Get the currently selected relation members
526 *
527 * @return a collection with the currently selected relation members
528 */
529 public Collection<RelationMember> getSelectedMembers() {
530 List<RelationMember> selectedMembers = new ArrayList<>();
531 for (int i : getSelectedIndices()) {
532 selectedMembers.add(members.get(i));
533 }
534 return selectedMembers;
535 }
536
537 /**
538 * Replies the set of selected referers. Never null, but may be empty.
539 *
540 * @return the set of selected referers
541 */
542 public Collection<OsmPrimitive> getSelectedChildPrimitives() {
543 Collection<OsmPrimitive> ret = new ArrayList<>();
544 for (RelationMember m: getSelectedMembers()) {
545 ret.add(m.getMember());
546 }
547 return ret;
548 }
549
550 /**
551 * Replies the set of selected referers. Never null, but may be empty.
552 * @param referenceSet reference set
553 *
554 * @return the set of selected referers
555 */
556 public Set<OsmPrimitive> getChildPrimitives(Collection<? extends OsmPrimitive> referenceSet) {
557 Set<OsmPrimitive> ret = new HashSet<>();
558 if (referenceSet == null) return null;
559 for (RelationMember m: members) {
560 if (referenceSet.contains(m.getMember())) {
561 ret.add(m.getMember());
562 }
563 }
564 return ret;
565 }
566
567 /**
568 * Selects the members in the collection selectedMembers
569 *
570 * @param selectedMembers the collection of selected members
571 */
572 public void setSelectedMembers(Collection<RelationMember> selectedMembers) {
573 if (selectedMembers == null || selectedMembers.isEmpty()) {
574 getSelectionModel().clearSelection();
575 return;
576 }
577
578 // lookup the indices for the respective members
579 //
580 Set<Integer> selectedIndices = new HashSet<>();
581 for (RelationMember member : selectedMembers) {
582 for (int idx = 0; idx < members.size(); ++idx) {
583 if (member.equals(members.get(idx))) {
584 selectedIndices.add(idx);
585 }
586 }
587 }
588 setSelectedMembersIdx(selectedIndices);
589 }
590
591 /**
592 * Selects the members in the collection selectedIndices
593 *
594 * @param selectedIndices the collection of selected member indices
595 */
596 public void setSelectedMembersIdx(Collection<Integer> selectedIndices) {
597 if (selectedIndices == null || selectedIndices.isEmpty()) {
598 getSelectionModel().clearSelection();
599 return;
600 }
601 // select the members
602 //
603 getSelectionModel().setValueIsAdjusting(true);
604 getSelectionModel().clearSelection();
605 for (int row : selectedIndices) {
606 getSelectionModel().addSelectionInterval(row, row);
607 }
608 getSelectionModel().setValueIsAdjusting(false);
609 // make the first selected member visible
610 //
611 if (!selectedIndices.isEmpty()) {
612 fireMakeMemberVisible(Collections.min(selectedIndices));
613 }
614 }
615
616 /**
617 * Replies true if the index-th relation members referrs
618 * to an editable relation, i.e. a relation which is not
619 * incomplete.
620 *
621 * @param index the index
622 * @return true, if the index-th relation members referrs
623 * to an editable relation, i.e. a relation which is not
624 * incomplete
625 */
626 public boolean isEditableRelation(int index) {
627 if (index < 0 || index >= members.size())
628 return false;
629 RelationMember member = members.get(index);
630 if (!member.isRelation())
631 return false;
632 Relation r = member.getRelation();
633 return !r.isIncomplete();
634 }
635
636 /**
637 * Replies true if there is at least one relation member given as {@code members}
638 * which refers to at least on the primitives in {@code primitives}.
639 *
640 * @param members the members
641 * @param primitives the collection of primitives
642 * @return true if there is at least one relation member in this model
643 * which refers to at least on the primitives in <code>primitives</code>; false
644 * otherwise
645 */
646 public static boolean hasMembersReferringTo(Collection<RelationMember> members, Collection<OsmPrimitive> primitives) {
647 if (primitives == null || primitives.isEmpty())
648 return false;
649 Set<OsmPrimitive> referrers = new HashSet<>();
650 for (RelationMember member : members) {
651 referrers.add(member.getMember());
652 }
653 for (OsmPrimitive referred : primitives) {
654 if (referrers.contains(referred))
655 return true;
656 }
657 return false;
658 }
659
660 /**
661 * Replies true if there is at least one relation member in this model
662 * which refers to at least on the primitives in <code>primitives</code>.
663 *
664 * @param primitives the collection of primitives
665 * @return true if there is at least one relation member in this model
666 * which refers to at least on the primitives in <code>primitives</code>; false
667 * otherwise
668 */
669 public boolean hasMembersReferringTo(Collection<OsmPrimitive> primitives) {
670 return hasMembersReferringTo(members, primitives);
671 }
672
673 /**
674 * Selects all mebers which refer to {@link OsmPrimitive}s in the collections
675 * <code>primitmives</code>. Does nothing is primitives is null.
676 *
677 * @param primitives the collection of primitives
678 */
679 public void selectMembersReferringTo(Collection<? extends OsmPrimitive> primitives) {
680 if (primitives == null) return;
681 getSelectionModel().setValueIsAdjusting(true);
682 getSelectionModel().clearSelection();
683 for (int i = 0; i < members.size(); i++) {
684 RelationMember m = members.get(i);
685 if (primitives.contains(m.getMember())) {
686 this.getSelectionModel().addSelectionInterval(i, i);
687 }
688 }
689 getSelectionModel().setValueIsAdjusting(false);
690 if (!getSelectedIndices().isEmpty()) {
691 fireMakeMemberVisible(getSelectedIndices().get(0));
692 }
693 }
694
695 /**
696 * Replies true if <code>primitive</code> is currently selected in the layer this
697 * model is attached to
698 *
699 * @param primitive the primitive
700 * @return true if <code>primitive</code> is currently selected in the layer this
701 * model is attached to, false otherwise
702 */
703 public boolean isInJosmSelection(OsmPrimitive primitive) {
704 return layer.data.isSelected(primitive);
705 }
706
707 /**
708 * Sort the selected relation members by the way they are linked.
709 */
710 public void sort() {
711 List<RelationMember> selectedMembers = new ArrayList<>(getSelectedMembers());
712 List<RelationMember> sortedMembers;
713 List<RelationMember> newMembers;
714 if (selectedMembers.size() <= 1) {
715 newMembers = relationSorter.sortMembers(members);
716 sortedMembers = newMembers;
717 } else {
718 sortedMembers = relationSorter.sortMembers(selectedMembers);
719 List<Integer> selectedIndices = getSelectedIndices();
720 newMembers = new ArrayList<>();
721 boolean inserted = false;
722 for (int i = 0; i < members.size(); i++) {
723 if (selectedIndices.contains(i)) {
724 if (!inserted) {
725 newMembers.addAll(sortedMembers);
726 inserted = true;
727 }
728 } else {
729 newMembers.add(members.get(i));
730 }
731 }
732 }
733
734 if (members.size() != newMembers.size())
735 throw new AssertionError();
736
737 members.clear();
738 members.addAll(newMembers);
739 fireTableDataChanged();
740 setSelectedMembers(sortedMembers);
741 }
742
743 /**
744 * Sort the selected relation members and all members below by the way they are linked.
745 */
746 public void sortBelow() {
747 final List<RelationMember> subList = members.subList(Math.max(0, getSelectionModel().getMinSelectionIndex()), members.size());
748 final List<RelationMember> sorted = relationSorter.sortMembers(subList);
749 subList.clear();
750 subList.addAll(sorted);
751 fireTableDataChanged();
752 setSelectedMembers(sorted);
753 }
754
755 WayConnectionType getWayConnection(int i) {
756 if (connectionType == null) {
757 connectionType = wayConnectionTypeCalculator.updateLinks(members);
758 }
759 return connectionType.get(i);
760 }
761
762 @Override
763 public void tableChanged(TableModelEvent e) {
764 invalidateConnectionType();
765 }
766
767 private void invalidateConnectionType() {
768 connectionType = null;
769 }
770
771 /**
772 * Reverse the relation members.
773 */
774 public void reverse() {
775 List<Integer> selectedIndices = getSelectedIndices();
776 List<Integer> selectedIndicesReversed = getSelectedIndices();
777
778 if (selectedIndices.size() <= 1) {
779 Collections.reverse(members);
780 fireTableDataChanged();
781 setSelectedMembers(members);
782 } else {
783 Collections.reverse(selectedIndicesReversed);
784
785 List<RelationMember> newMembers = new ArrayList<>(members);
786
787 for (int i = 0; i < selectedIndices.size(); i++) {
788 newMembers.set(selectedIndices.get(i), members.get(selectedIndicesReversed.get(i)));
789 }
790
791 if (members.size() != newMembers.size()) throw new AssertionError();
792 members.clear();
793 members.addAll(newMembers);
794 fireTableDataChanged();
795 setSelectedMembersIdx(selectedIndices);
796 }
797 }
798}
Note: See TracBrowser for help on using the repository browser.