292 lines
6.3 KiB
Java
292 lines
6.3 KiB
Java
|
|
package net.sourceforge.filebot.ui.panel.rename;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
|
|
import net.sourceforge.filebot.similarity.Match;
|
|
import ca.odell.glazedlists.BasicEventList;
|
|
import ca.odell.glazedlists.EventList;
|
|
import ca.odell.glazedlists.TransformedList;
|
|
import ca.odell.glazedlists.event.ListEvent;
|
|
|
|
|
|
public class MatchModel<Value, Candidate> {
|
|
|
|
private final EventList<Match<Value, Candidate>> source = new BasicEventList<Match<Value, Candidate>>();
|
|
|
|
private final EventList<Value> values;
|
|
|
|
private final EventList<Candidate> candidates;
|
|
|
|
|
|
public MatchModel() {
|
|
this.values = new MatchView<Value, Candidate>(source) {
|
|
|
|
@Override
|
|
public Value getElement(Match<Value, Candidate> match) {
|
|
return match.getValue();
|
|
}
|
|
|
|
|
|
@Override
|
|
public Candidate getComplement(Match<Value, Candidate> match) {
|
|
return match.getCandidate();
|
|
}
|
|
|
|
|
|
@Override
|
|
public Match<Value, Candidate> createMatch(Value element, Candidate complement) {
|
|
return new Match<Value, Candidate>(element, complement);
|
|
}
|
|
};
|
|
|
|
this.candidates = new MatchView<Candidate, Value>(source) {
|
|
|
|
@Override
|
|
public Candidate getElement(Match<Value, Candidate> match) {
|
|
return match.getCandidate();
|
|
}
|
|
|
|
|
|
@Override
|
|
public Value getComplement(Match<Value, Candidate> match) {
|
|
return match.getValue();
|
|
}
|
|
|
|
|
|
@Override
|
|
public Match<Value, Candidate> createMatch(Candidate element, Value complement) {
|
|
return new Match<Value, Candidate>(complement, element);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
public void clear() {
|
|
source.clear();
|
|
}
|
|
|
|
|
|
public int size() {
|
|
return source.size();
|
|
}
|
|
|
|
|
|
public Match<Value, Candidate> getMatch(int index) {
|
|
return source.get(index);
|
|
}
|
|
|
|
|
|
public boolean hasComplement(int index) {
|
|
return source.get(index).getValue() != null && source.get(index).getCandidate() != null;
|
|
}
|
|
|
|
|
|
public EventList<Match<Value, Candidate>> matches() {
|
|
return source;
|
|
}
|
|
|
|
|
|
public EventList<Value> values() {
|
|
return values;
|
|
}
|
|
|
|
|
|
public EventList<Candidate> candidates() {
|
|
return candidates;
|
|
}
|
|
|
|
|
|
public void addAll(Collection<Match<Value, Candidate>> matches) {
|
|
source.addAll(matches);
|
|
}
|
|
|
|
|
|
public void addAll(Collection<Value> values, Collection<Candidate> candidates) {
|
|
if (this.values.size() != this.candidates.size())
|
|
throw new IllegalStateException("Existing matches are not balanced");
|
|
|
|
Iterator<Value> valueIterator = values.iterator();
|
|
Iterator<Candidate> candidateIterator = candidates.iterator();
|
|
|
|
while (valueIterator.hasNext() || candidateIterator.hasNext()) {
|
|
Value value = valueIterator.hasNext() ? valueIterator.next() : null;
|
|
Candidate candidate = candidateIterator.hasNext() ? candidateIterator.next() : null;
|
|
|
|
source.add(new Match<Value, Candidate>(value, candidate));
|
|
}
|
|
}
|
|
|
|
|
|
private abstract class MatchView<Element, Complement> extends TransformedList<Match<Value, Candidate>, Element> {
|
|
|
|
public MatchView(EventList<Match<Value, Candidate>> source) {
|
|
super(source);
|
|
|
|
source.addListEventListener(this);
|
|
}
|
|
|
|
|
|
public abstract Element getElement(Match<Value, Candidate> match);
|
|
|
|
|
|
public abstract Complement getComplement(Match<Value, Candidate> match);
|
|
|
|
|
|
public abstract Match<Value, Candidate> createMatch(Element element, Complement complement);
|
|
|
|
|
|
@Override
|
|
public Element get(int index) {
|
|
return getElement(index);
|
|
}
|
|
|
|
|
|
public Element getElement(int index) {
|
|
return getElement(source.get(index));
|
|
}
|
|
|
|
|
|
public Complement getComplement(int index) {
|
|
return getComplement(source.get(index));
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean addAll(Collection<? extends Element> values) {
|
|
return put(size(), values);
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean add(Element value) {
|
|
return put(size(), Collections.singleton(value));
|
|
};
|
|
|
|
|
|
@Override
|
|
public void add(int index, Element value) {
|
|
List<Element> range = new ArrayList<Element>();
|
|
|
|
range.add(value);
|
|
range.addAll(subList(index, size()));
|
|
|
|
put(index, range);
|
|
}
|
|
|
|
|
|
@Override
|
|
public Element remove(int index) {
|
|
Element old = getElement(index);
|
|
|
|
int lastIndex = size() - 1;
|
|
|
|
// shift subsequent elements
|
|
put(index, new ArrayList<Element>(subList(index + 1, lastIndex + 1)));
|
|
|
|
// remove last element
|
|
if (getComplement(lastIndex) == null) {
|
|
source.remove(lastIndex);
|
|
} else {
|
|
set(lastIndex, null);
|
|
}
|
|
|
|
return old;
|
|
}
|
|
|
|
|
|
@Override
|
|
public Element set(int index, Element element) {
|
|
Element old = getElement(index);
|
|
|
|
source.set(index, createMatch(element, getComplement(index)));
|
|
|
|
return old;
|
|
}
|
|
|
|
|
|
@Override
|
|
public void clear() {
|
|
// remove in reverse, because null matches may only
|
|
// exist at the and of the source model
|
|
for (int i = size() - 1; i >= 0; i--) {
|
|
Complement complement = getComplement(i);
|
|
|
|
if (complement != null) {
|
|
// replace original match with null match
|
|
source.set(i, createMatch(null, complement));
|
|
} else {
|
|
// remove match if value and candidate are null
|
|
source.remove(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private boolean put(int index, Collection<? extends Element> elements) {
|
|
for (Element element : elements) {
|
|
if (index < source.size()) {
|
|
set(index, element);
|
|
} else {
|
|
source.add(index, createMatch(element, null));
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
@Override
|
|
protected boolean isWritable() {
|
|
// can't write to source directly
|
|
return false;
|
|
}
|
|
|
|
private int size = 0;
|
|
|
|
|
|
@Override
|
|
public int size() {
|
|
return size;
|
|
}
|
|
|
|
|
|
@Override
|
|
public void listChanged(ListEvent<Match<Value, Candidate>> listChanges) {
|
|
updates.beginEvent(true);
|
|
|
|
while (listChanges.next()) {
|
|
int index = listChanges.getIndex();
|
|
int type = listChanges.getType();
|
|
|
|
if (type == ListEvent.INSERT || type == ListEvent.UPDATE) {
|
|
if (index < size) {
|
|
if (index == size - 1 && getElement(index) == null) {
|
|
updates.elementDeleted(index, null);
|
|
size--;
|
|
} else {
|
|
updates.elementUpdated(index, null, getElement(index));
|
|
}
|
|
} else if (index == size && getElement(index) != null) {
|
|
updates.elementInserted(index, getElement(index));
|
|
size++;
|
|
}
|
|
} else if (type == ListEvent.DELETE && index < size) {
|
|
updates.elementDeleted(index, null);
|
|
size--;
|
|
}
|
|
}
|
|
|
|
updates.commitEvent();
|
|
}
|
|
}
|
|
|
|
}
|