*******************************************************************************/
package org.simantics.charts.editor;
+import java.util.concurrent.atomic.AtomicInteger;
+
import org.simantics.databoard.annotations.Optional;
import org.simantics.db.Resource;
import org.simantics.history.Collector;
@Optional
public Collector collector;
+ /**
+ * This (shared instance) is used to track the amount of users of this ChartData
+ * instance. The same instance may end up in many ChartData instances through
+ * {@link #readFrom(ChartData)}.
+ */
+ public AtomicInteger refCount = new AtomicInteger();
+
public ChartData(Resource model, Resource run, IExperiment experiment, Datasource datasource, HistoryManager history, Collector collector) {
this.model = model;
this.run = run;
this.datasource = null;
this.history = null;
this.collector = null;
+ this.refCount = null;
} else {
this.model = other.model;
this.run = other.run;
this.datasource = other.datasource;
this.history = other.history;
this.collector = other.collector;
+ this.refCount = other.refCount;
}
}
}
}
+ public int reference() {
+ AtomicInteger i = refCount;
+ if (i == null)
+ return 0;
+ int result = i.incrementAndGet();
+ //System.out.println(this + ": reference: " + (result-1) + " -> " + result + " (" + System.identityHashCode(refCount) + ")");
+ return result;
+ }
+
+ public int dereference() {
+ AtomicInteger i = refCount;
+ if (i == null)
+ return 0;
+ int result = i.decrementAndGet();
+ //System.out.println(this + ": dereference: " + (result+1) + " -> " + result + " (" + System.identityHashCode(refCount) + ")");
+ if (result <= 0) {
+ synchronized (i) {
+ i.notifyAll();
+ }
+ }
+ return result;
+ }
+
+ public void waitUntilNotReferenced() throws InterruptedException {
+ AtomicInteger i = refCount;
+ if (i == null)
+ return;
+ synchronized (i) {
+ while (i.get() > 0) {
+ i.wait();
+ }
+ }
+ }
+
}
// Track data source and preinitialize chartData
project.addHintListener(chartDataListener);
chartData.readFrom( (ChartData) project.getHint( chartDataKey ) );
+ chartData.reference();
if (chartData.run != null) {
milestoneListener = new MilestoneSpecListener();
chartData.datasource.removeListener( stepListener );
if (chartData.experiment!=null)
chartData.experiment.removeListener( experimentStateListener );
+ chartData.dereference();
chartData.readFrom( null );
}
}
if (doLayout) trendNode.layout();
+ this.chartData.dereference();
this.chartData.readFrom( data );
+ this.chartData.reference();
tp.setDirty();
if (!ObjectUtils.objectEquals(oldExperimentResource, newExperimentResource)) {
tp.setDirty();
}
- @SuppressWarnings("rawtypes")
+ @SuppressWarnings("unchecked")
@Override
- public Object getAdapter(Class adapter) {
+ public <T> T getAdapter(Class<T> adapter) {
if (adapter == INode.class) {
ICanvasContext ctx = cvsCtx;
if (ctx != null)
- return ctx.getSceneGraph();
+ return (T) ctx.getSceneGraph();
}
if (adapter == IPropertyPage.class)
- return new StandardPropertyPage(getSite(), getPropertyPageContexts());
+ return (T) new StandardPropertyPage(getSite(), getPropertyPageContexts());
if (adapter == ICanvasContext.class)
- return cvsCtx;
+ return (T) cvsCtx;
return super.getAdapter(adapter);
}
import org.simantics.db.exception.ServiceNotFoundException;
import org.simantics.db.request.Read;
import org.simantics.fastlz.FastLZ;
-import org.simantics.history.Collector;
import org.simantics.history.HistoryException;
import org.simantics.history.HistoryManager;
import org.simantics.history.ItemManager;
+import org.simantics.history.impl.CollectorImpl;
import org.simantics.history.impl.CollectorState;
import org.simantics.history.impl.CollectorState.VariableState;
import org.simantics.history.util.Stream;
import org.simantics.history.util.ValueBand;
+import org.simantics.history.util.WeightedMedian;
import org.simantics.layer0.Layer0;
import org.simantics.simulation.Activator;
import org.simantics.simulation.ontology.HistoryResource;
return 0L;
}
- public static void truncateHistory(double toBeforeTime, HistoryManager history, Collector collector) throws AccessorException, BindingException, HistoryException {
+ public static CollectorState truncateHistory(double toBeforeTime, HistoryManager history, CollectorState state) throws AccessorException, BindingException, HistoryException {
Double t = toBeforeTime;
Binding timeBinding = null;
- CollectorState state = collector != null ? (CollectorState) collector.getState() : null;
Bean[] items = history.getItems();
//System.out.println("truncating all samples after t=" + toBeforeTime + " for " + items.length + " history items");
for (Bean item : items) {
String id = (String) item.getField("id");
- StreamAccessor sa = history.openStream(id, "w");
+ StreamAccessor sa = history.openStream(id, "rw");
try {
Stream s = new Stream(sa);
timeBinding = s.timeBinding;
if (state != null) {
Object prevTime = newSize > 0 ? s.getItemTime(s.timeBinding, newSize - 1) : null;
- Object prevValue = newSize > 0 ? sa.get(newSize - 1, s.valueBinding) : null;
+ Bean prevSample = newSize > 0 ? (Bean) sa.get(newSize - 1, s.sampleBinding) : null;
+ Object prevValue = prevSample != null ? prevSample.getField(s.valueIndex) : null;
boolean isNan = isNaN(prevValue);
VariableState vs = state.values.get(id);
CollectorState.Item is = state.itemStates.get(id);
if (is != null) {
- is.firstTime = Double.NaN;
- is.firstValue = null;
- is.currentTime = toTime(prevTime);
- is.currentValue = prevValue != null ? new MutableVariant(s.valueBinding, prevValue) : null;
- is.isNaN = isNaN(is.currentValue);
- is.isValid = is.currentValue != null;
+ is.firstTime = toTime(prevTime);
+ is.firstValue = toValue(s.valueBinding, prevValue);
+ is.currentTime = is.firstTime;
+ is.currentValue = toValue(s.valueBinding, prevValue);
+ is.isNaN = isNan;
+ is.isValid = prevValue != null;
is.sum = Double.NaN;
is.count = 0;
is.ooDeadband = false;
is.firstDisabledTime = Double.NaN;
is.lastDisabledTime = Double.NaN;
- is.median = null;
+ is.median = new WeightedMedian( CollectorImpl.MEDIAN_LIMIT );
}
}
}
if (timeBinding != null && state != null) {
state.time.setValue(timeBinding, t);
state.dT = 1.0;
- collector.setState(state);
}
+
+ return state;
}
private static double toTime(Object time) {
return time instanceof Number ? ((Number) time).doubleValue() : Double.NaN;
}
+ private static MutableVariant toValue(Binding valueBinding, Object value) {
+ return new MutableVariant(valueBinding, value != null ? value : valueBinding.createDefaultUnchecked());
+ }
+
private static boolean isNaN(Object value) {
return value instanceof Number ? Double.isNaN(((Number) value).doubleValue()) : false;
}