// License: GPL. See LICENSE file for details. Copyright 2012 by Josh Doe and others. package org.openstreetmap.josm.plugins.conflation; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import org.openstreetmap.josm.data.osm.OsmPrimitive; /** * Holds a list of {@see Match}es and provides convenience functions. */ public class SimpleMatchList implements Iterable<SimpleMatch> { private CopyOnWriteArrayList<SimpleMatchListListener> listeners = new CopyOnWriteArrayList<SimpleMatchListListener>(); List<SimpleMatch> matches; Collection<SimpleMatch> selected; public SimpleMatchList() { matches = new LinkedList<SimpleMatch>(); selected = new ArrayList<SimpleMatch>(); } public boolean hasMatch(SimpleMatch c) { return hasMatchForReference(c.getReferenceObject()); } public boolean hasMatch(OsmPrimitive referenceObject, OsmPrimitive subjectObject) { return hasMatchForReference(referenceObject) || hasMatchForSubject(subjectObject); } public boolean hasMatchForReference(OsmPrimitive referenceObject) { return getMatchByReference(referenceObject) != null; } public boolean hasMatchForSubject(OsmPrimitive subjectObject) { return getMatchBySubject(subjectObject) != null; } public SimpleMatch getMatchByReference(OsmPrimitive referenceObject) { for (SimpleMatch c : matches) { if (c.getReferenceObject() == referenceObject) { return c; } } return null; } public SimpleMatch getMatchBySubject(OsmPrimitive subjectObject) { for (SimpleMatch c : matches) { if (c.getSubjectObject() == subjectObject) { return c; } } return null; } @Override public Iterator<SimpleMatch> iterator() { return matches.iterator(); } public boolean add(SimpleMatch c) { return addAll(Collections.singleton(c)); } public boolean addAll(Collection<SimpleMatch> toAdd) { boolean changed = matches.addAll(toAdd); if (changed) fireListChanged(); return changed; } public int size() { return matches.size(); } public SimpleMatch get(int index) { return matches.get(index); } public int indexOf(SimpleMatch match) { return matches.indexOf(match); } /** * Remove all matches and clear selection. */ public void clear() { if (matches.size() > 0) { setSelected(new ArrayList<SimpleMatch>()); matches.clear(); fireListChanged(); } } public boolean remove(SimpleMatch c) { return removeAll(Collections.singleton(c)); } public SimpleMatch findNextSelection() { SimpleMatch next = null; // if gap in selection exists, use that as the next selection for (int i = 1; i < matches.size() - 1; i++) { if (selected.contains(matches.get(i - 1)) && !selected.contains(matches.get(i)) && selected.contains(matches.get(i + 1))) { next = matches.get(i); break; } } if (next == null) { int first = matches.size(); int last = -1; for (SimpleMatch c : selected) { first = Math.min(first, matches.indexOf(c)); last = Math.max(last, matches.indexOf(c)); } if (last + 1 < matches.size()) next = matches.get(last + 1); else if (first - 1 >= 0) next = matches.get(first - 1); else next = null; } return next; } public boolean removeAll(Collection<SimpleMatch> matchesToRemove) { // find next to select if entire selection is removed SimpleMatch next = findNextSelection(); boolean ret = matches.removeAll(matchesToRemove); if (selected.removeAll(matchesToRemove)) { if (selected.isEmpty() && next != null) selected.add(next); fireSelectionChanged(); } if (ret) fireListChanged(); return ret; } public void addConflationListChangedListener(SimpleMatchListListener listener) { listeners.addIfAbsent(listener); } public void fireListChanged(){ for (SimpleMatchListListener l : listeners) { l.simpleMatchListChanged(this); } } public void fireSelectionChanged(){ for (SimpleMatchListListener l : listeners) { l.simpleMatchSelectionChanged(selected); } } public Collection<SimpleMatch> getSelected() { return selected; } /** * Set which {@see SimpleMatch} is currently selected. Set to null to clear selection. * @param match */ public void setSelected(SimpleMatch match) { if (match != null) setSelected(Collections.singleton(match)); else setSelected(new ArrayList<SimpleMatch>()); } public void setSelected(Collection<SimpleMatch> matches) { if (selected.containsAll(matches) && selected.size() == matches.size()) return; selected.clear(); selected.addAll(matches); fireSelectionChanged(); } }