private P getWithUpstreamTracking() { // this logic should probably go in DerivedValue somehow, except that // it's only a value and does not know about it's parent property if (value instanceof DerivedValue) { // Turn on implicitUpstream, which watches for properties called during value.get. // Also, keep track if anyone was already tracking derived values so we can put it back. List<Property<?>> tempUpstream = implicitUpstream; implicitUpstream = new ArrayList<Property<?>>(); P tempValue = value.get(); List<Property<?>> newUpstream = new ArrayList<Property<?>>(implicitUpstream); // Put back the previous upstream before we do anything else implicitUpstream = tempUpstream; // Only update our upstream properties if they've changed if (lastUpstream == null || !lastUpstream.equals(newUpstream)) { ListDiff<Property<?>> diff = ListDiff.of(lastUpstream, newUpstream); for (Property<?> removed : diff.removed) { removed.removeDerived(this); } for (Property<?> added : diff.added) { added.addDerived(this); } // Remember for change tracking next time lastUpstream = newUpstream; } return tempValue; } else { return value.get(); } }
@Override protected void fireChanged(List<E> oldValue, List<E> newValue) { ListDiff<E> diff = ListDiff.of(oldValue, newValue); for (Location<E> added : diff.added) { fireEvent(new ValueAddedEvent<E>(added.element)); listenForMemberChanged(added.element); addToAllValidIfNeeded(added.element); } for (Location<E> removed : diff.removed) { fireEvent(new ValueRemovedEvent<E>(removed.element)); removeFromAllValidIfNeeded(removed.element); } fireEvent(new ListChangedEvent<E>(this, oldValue, newValue, diff)); // if someone is listening for "did one of your models change", they // probably also care about a new model showing up/old model going away fireEvent(new MemberChangedEvent()); super.fireChanged(oldValue, newValue); }