1 13 package org.eclipse.core.databinding.observable.value; 14 15 import org.eclipse.core.databinding.observable.ChangeEvent; 16 import org.eclipse.core.databinding.observable.IChangeListener; 17 import org.eclipse.core.databinding.observable.IObservable; 18 import org.eclipse.core.databinding.observable.IStaleListener; 19 import org.eclipse.core.databinding.observable.ObservableTracker; 20 import org.eclipse.core.databinding.observable.Realm; 21 import org.eclipse.core.databinding.observable.StaleEvent; 22 23 34 public abstract class ComputedValue extends AbstractObservableValue { 35 36 private boolean dirty = true; 37 38 private boolean stale = false; 39 40 private Object cachedValue = null; 41 42 47 private IObservable[] dependencies = new IObservable[0]; 48 49 52 public ComputedValue() { 53 this(Realm.getDefault(), null); 54 } 55 56 59 public ComputedValue(Object valueType) { 60 this(Realm.getDefault(), valueType); 61 } 62 63 67 public ComputedValue(Realm realm) { 68 this(realm, null); 69 } 70 71 75 public ComputedValue(Realm realm, Object valueType) { 76 super(realm); 77 this.valueType = valueType; 78 } 79 80 101 private class PrivateInterface implements Runnable , IChangeListener, 102 IStaleListener { 103 public void run() { 104 cachedValue = calculate(); 105 } 106 107 public void handleStale(StaleEvent event) { 108 if (!dirty && !stale) { 109 stale = true; 110 fireStale(); 111 } 112 } 113 114 public void handleChange(ChangeEvent event) { 115 makeDirty(); 116 } 117 } 118 119 private PrivateInterface privateInterface = new PrivateInterface(); 120 121 private Object valueType; 122 123 protected final Object doGetValue() { 124 if (dirty) { 125 IObservable[] newDependencies = ObservableTracker.runAndMonitor( 130 privateInterface, privateInterface, null); 131 132 stale = false; 133 for (int i = 0; i < newDependencies.length; i++) { 134 IObservable observable = newDependencies[i]; 135 if (observable.isStale()) { 137 stale = true; 138 } else { 139 observable.addStaleListener(privateInterface); 140 } 141 } 142 143 dependencies = newDependencies; 144 145 dirty = false; 146 } 147 148 return cachedValue; 149 } 150 151 156 protected abstract Object calculate(); 157 158 protected final void makeDirty() { 159 if (!dirty) { 160 dirty = true; 161 162 stopListening(); 163 164 final Object oldValue = cachedValue; 166 fireValueChange(new ValueDiff() { 169 170 public Object getOldValue() { 171 return oldValue; 172 } 173 174 public Object getNewValue() { 175 return getValue(); 176 } 177 }); 178 } 179 } 180 181 184 private void stopListening() { 185 for (int i = 0; i < dependencies.length; i++) { 187 IObservable observable = dependencies[i]; 188 189 observable.removeChangeListener(privateInterface); 190 observable.removeStaleListener(privateInterface); 191 } 192 } 193 194 public boolean isStale() { 195 getValue(); 197 return stale; 198 } 199 200 public Object getValueType() { 201 return valueType; 202 } 203 204 public synchronized void addChangeListener(IChangeListener listener) { 205 super.addChangeListener(listener); 206 getValue(); 209 } 210 211 public synchronized void addValueChangeListener(IValueChangeListener listener) { 212 super.addValueChangeListener(listener); 213 getValue(); 216 } 217 218 public synchronized void dispose() { 219 super.dispose(); 220 stopListening(); 221 } 222 223 } 224 | Popular Tags |