package org.archstudio.bna.logics.coordinating; import static com.google.common.base.Preconditions.checkNotNull; import org.archstudio.bna.IBNAModelListener; import org.archstudio.bna.IBNAWorld; import org.archstudio.bna.IThing; import org.archstudio.bna.ThingEvent; import org.archstudio.bna.keys.IThingKey; import org.archstudio.bna.logics.AbstractCoordinatingThingLogic; import org.archstudio.bna.logics.coordinating.MirrorValueLogic.MirrorUpdater; import org.archstudio.bna.utils.BNAUtils; import com.google.common.base.Function; import com.google.common.base.Functions; public class MirrorValueLogic extends AbstractCoordinatingThingLogic<MirrorUpdater<?, ?>> implements IBNAModelListener { protected class MirrorUpdater<FV, TV> extends AbstractCoordinatingThingLogic.Updater { final Object fromThingID; final IThingKey<FV> fromKey; final Object toThingID; final IThingKey<TV> toKey; final Function<? super FV, ? extends TV> transformFunction; boolean updating; public MirrorUpdater(IThing fromThing, IThingKey<FV> fromKey, IThing toThing, IThingKey<TV> toKey, Function<? super FV, ? extends TV> transformFunction) { this.fromThingID = fromThing.getID(); this.fromKey = fromKey; this.toThingID = toThing.getID(); this.toKey = toKey; this.transformFunction = transformFunction; } @Override public void update(ThingEvent event) { if (updating) { return; } if (event != null) { if (event.getTargetThing().getID().equals(fromThingID)) { if (!event.getPropertyName().equals(fromKey)) { return; } } else { if (!event.getPropertyName().equals(toKey)) { return; } } } IThing fromThing = model.getThing(fromThingID); if (fromThing != null) { IThing toThing = model.getThing(toThingID); if (toThing != null) { updating = true; try { toThing.set(toKey, transformFunction.apply(fromThing.get(fromKey))); } finally { updating = false; } } } } } public MirrorValueLogic(IBNAWorld world) { super(world); } public <V> void mirrorValue(IThing fromThing, IThingKey<V> key, IThing toThing) { mirrorValue(fromThing, key, toThing, key, Functions.<V> identity()); } public <V> void mirrorValue(IThing fromThing, IThingKey<V> fromKey, IThing toThing, IThingKey<V> toKey) { mirrorValue(fromThing, fromKey, toThing, toKey, Functions.<V> identity()); } public <FV, TV> void mirrorValue(IThing fromThing, IThingKey<FV> fromKey, IThing toThing, IThingKey<TV> toKey, Function<? super FV, ? extends TV> transformFunction) { checkNotNull(fromThing); checkNotNull(fromKey); checkNotNull(toThing); checkNotNull(toKey); checkNotNull(transformFunction); BNAUtils.checkLock(); MirrorUpdater<FV, TV> updater = new MirrorUpdater<FV, TV>(fromThing, fromKey, toThing, toKey, transformFunction); register(updater, toThing, toKey); removeWithThing(updater, fromThing, toThing); track(updater, fromThing); } public void unmirror(IThing toThing, IThingKey<?> toKey) { checkNotNull(toThing); checkNotNull(toKey); BNAUtils.checkLock(); unregister(toThing, toKey); } }