/** * Creates a new {@link ListProperty>} of type {@code F}. * * <p>Only changes in this list will be reflected in the returned list, e.g. it's a one way * conversion. */ public <F> ListProperty<F> map(final ElementMapper<E, F> mapper) { // make an intial copy of all the elements currently in our list List<F> initial = null; if (get() != null) { initial = new ArrayList<F>(); for (E e : get()) { initial.add(mapper.map(e)); } } final ListProperty<F> mapped = listProperty(getName(), initial); // keep converting E -> F into as addListChangedHandler( new ListChangedHandler<E>() { public void onListChanged(ListChangedEvent<E> event) { if (get() != null && mapped.get() == null) { mapped.setInitialValue(new ArrayList<F>()); } event .getDiff() .apply( mapped.getDirect(), new ListDiff.Mapper<E, F>() { public F map(E e) { return mapper.map(e); } }); if (isTouched() && !mapped.isTouched()) { mapped.setTouched(true); } else { mapped.reassess(); } } }); return mapped; }
/** * Sorts our values by {@code comparator} (and continually applies the comparator as new values * are added/removed/set). */ public void setComparator(Comparator<E> comparator) { this.persistentComparator = comparator; List<E> copy = copyLastValue(getDirect()); if (copy != null && !copy.equals(getDirect())) { set(copy); } }
/** * Checks equality between a and b by ignoring list order. * * <p>This is because a frequent use case of "listA.is(listB)" is for "Select All" functionality, * and if a user selects items in a different order, we still want to consider listA equal to * listB. */ @Override protected boolean isEqual(List<E> a, List<E> b) { if (ObjectUtils.eq(a, b)) { return true; } else if (a != null && b != null && a.size() == b.size()) { List<E> b2 = new ArrayList<E>(b); for (E e : a) { if (!b2.remove(e)) { return false; } } return true; } else { return false; } }
@Override public String toString() { List<E> e = getDirect(); if (e == null) { return getValueObject().getName() + " null"; } // Janky, but keep ListProperty.toString from being huge and accidentally ruining perf String s = getValueObject().getName() + " ["; for (int i = 0; i < e.size() && i < 20; i++) { s += ObjectUtils.toStr(e.get(i), "null"); if (i != e.size() - 1) { s += ", "; } } if (e.size() > 20) { s += "..."; } s += "]"; return s; }
/** * Creates a new {@link ListProperty>} of type {@code F}. * * <p>Any changes made to either list will be reflected in the other, using {@code converter} to * go between {@code E} and {@code F}. */ public <F> ListProperty<F> as(final ElementConverter<E, F> converter) { // make an intial copy of all the elements currently in our list List<F> initial = null; if (get() != null) { initial = new ArrayList<F>(); for (E e : get()) { F f = converter.to(e); initial.add(f); } } final ListProperty<F> as = listProperty(getName(), initial); final boolean[] active = {false}; // keep converting E -> F into as addListChangedHandler( new ListChangedHandler<E>() { public void onListChanged(ListChangedEvent<E> event) { if (!active[0]) { active[0] = true; if (get() != null && as.get() == null) { as.setInitialValue(new ArrayList<F>()); } event .getDiff() .apply( as.getDirect(), new ListDiff.Mapper<E, F>() { public F map(E e) { return converter.to(e); } }); if (isTouched() && !as.isTouched()) { as.setTouched(true); } else { as.reassess(); } active[0] = false; } } }); // also convert new Fs back into Es as.addListChangedHandler( new ListChangedHandler<F>() { public void onListChanged(ListChangedEvent<F> event) { if (!active[0]) { active[0] = true; if (get() == null && as.get() != null) { setInitialValue(new ArrayList<E>()); } event .getDiff() .apply( getDirect(), new ListDiff.Mapper<F, E>() { public E map(F f) { return converter.from(f); } }); if (as.isTouched() && !isTouched()) { setTouched(true); } else { reassess(); } active[0] = false; } } }); return as; }