Skip to content

Instantly share code, notes, and snippets.

@mikehearn
Created July 13, 2014 20:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikehearn/1ab3d4b129803d1da46d to your computer and use it in GitHub Desktop.
Save mikehearn/1ab3d4b129803d1da46d to your computer and use it in GitHub Desktop.
/**
* This list is created by dynamically concatenating all the source lists together.
*/
public class ConcatenatingList<T> extends ObservableListBase<T> implements ObservableList<T> {
private List<ObservableList<T>> sources = new ArrayList<>();
private ListChangeListener<T> listener = this::sourceChanged;
@SafeVarargs
public ConcatenatingList(ObservableList<T>... source) {
super();
for (ObservableList<T> s : source) {
sources.add(s);
s.addListener(new WeakListChangeListener<T>(listener));
}
if (sources.isEmpty())
throw new IllegalArgumentException();
}
private int calculateOffset(ObservableList<? extends T> source) {
int cursor = 0;
for (ObservableList<T> ts : sources) {
if (ts == source) return cursor;
cursor += ts.size();
}
return cursor;
}
private void sourceChanged(ListChangeListener.Change<? extends T> c) {
ObservableList<? extends T> source = c.getList();
int offset = calculateOffset(source);
beginChange();
while (c.next()) {
if (c.wasPermutated()) {
int[] perm = new int[c.getTo() - c.getFrom()];
for (int i = c.getFrom(); i < c.getTo(); i++)
perm[i - c.getFrom()] = c.getPermutation(i) + offset;
nextPermutation(c.getFrom() + offset, c.getTo() + offset, perm);
} else if (c.wasUpdated()) {
for (int i = c.getFrom(); i < c.getTo(); i++) {
nextUpdate(i + offset);
}
} else {
if (c.wasRemoved()) {
// Removed should come first to properly handle replacements, then add.
nextRemove(c.getFrom() + offset, c.getRemoved());
}
if (c.wasAdded()) {
nextAdd(c.getFrom() + offset, c.getTo() + offset);
}
}
}
endChange();
}
@Override
public T get(int index) {
for (ObservableList<T> source : sources) {
if (index < source.size()) {
return source.get(index);
} else {
index -= source.size();
}
}
throw new IndexOutOfBoundsException();
}
@Override
public int size() {
return sources.stream().mapToInt(List::size).sum();
}
}
public class ConcatenatingListTest {
@Test
public void basic() throws Exception {
ObservableList<String> a = FXCollections.observableArrayList();
ObservableList<String> b = FXCollections.observableArrayList();
ConcatenatingList<String> concat = new ConcatenatingList<>(a, b);
assertEquals(0, concat.size());
a.add("1");
assertEquals(1, concat.size());
assertEquals("1", concat.get(0));
b.add("2");
assertEquals(2, concat.size());
assertEquals("2", concat.get(1));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment