tmf: Introduce a central trace manager
authorAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Mon, 29 Apr 2013 15:47:15 +0000 (11:47 -0400)
committerAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Wed, 1 May 2013 15:04:08 +0000 (11:04 -0400)
This manager will track all currently opened traces and their
currently selected timestamps and time ranges.

This will also give both views and *.core analysis plugins
a centralized way to get the current active trace/experiment.
This was not an easy thing to do reliably if you were not an
instance of TmfView.

Basic unit tests are included, more complete tests will be added
later.

Change-Id: Ie0056252908ae8bb9e5da33242c3141665eb161c
Signed-off-by: Alexandre Montplaisir <alexmonthy@voxpopuli.im>
Reviewed-on: https://git.eclipse.org/r/12079
Tested-by: Hudson CI
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
IP-Clean: Bernd Hufmann <bernd.hufmann@ericsson.com>

org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/AllTests.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/TmfTraceManagerTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/Activator.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTraceContext.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTraceManager.java [new file with mode: 0644]

index 8e280f0e23627019b1105fc09cc137d2356c3669..52eb7f0000a5e9a59ccec890ecbf164741e5b4d5 100644 (file)
@@ -30,6 +30,7 @@ import org.junit.runners.Suite;
     TmfExperimentTest.class,
     TmfLocationTest.class,
     TmfMultiTraceExperimentTest.class,
+    TmfTraceManagerTest.class,
     TmfTraceTest.class
 })
 public class AllTests {
diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/TmfTraceManagerTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/TmfTraceManagerTest.java
new file mode 100644 (file)
index 0000000..35545eb
--- /dev/null
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Alexandre Montplaisir - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
+import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfSignalManager;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.linuxtools.tmf.core.tests.shared.CtfTmfTestTraces;
+import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test suite for the {@link TmfTraceManager}.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class TmfTraceManagerTest {
+
+    private static final int SCALE = ITmfTimestamp.NANOSECOND_SCALE;
+
+    private static ITmfTrace trace1;
+    private static final long t1start = 1331668247314038062L;
+    private static final long t1end =   1331668259054285979L;
+
+    private static ITmfTrace trace2;
+    private static final long t2start = 1332170682440133097L;
+    private static final long t2end =   1332170692664579801L;
+
+    private static final long ONE_SECOND = 1000000000L;
+
+    private TmfTraceManager tm;
+
+
+    /**
+     * Test class initialization
+     */
+    @BeforeClass
+    public static void setUpClass() {
+        assumeTrue(CtfTmfTestTraces.tracesExist());
+        trace1 = CtfTmfTestTraces.getTestTrace(1);
+        trace2 = CtfTmfTestTraces.getTestTrace(0);
+
+        trace1.indexTrace(true);
+        trace2.indexTrace(true);
+    }
+
+    /**
+     * Test initialization
+     */
+    @Before
+    public void setUp() {
+        tm = TmfTraceManager.getInstance();
+    }
+
+    /**
+     * Test clean-up
+     */
+    @After
+    public void tearDown() {
+        while (tm.getActiveTrace() != null) {
+            closeTrace(tm.getActiveTrace());
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // Dummy actions (fake signals)
+    // ------------------------------------------------------------------------
+
+    private void openTrace(ITmfTrace trace) {
+        TmfSignalManager.dispatchSignal(new TmfTraceOpenedSignal(this, trace, null));
+        selectTrace(trace);
+    }
+
+    private void closeTrace(ITmfTrace trace) {
+        TmfSignalManager.dispatchSignal(new TmfTraceClosedSignal(this, trace));
+    }
+
+    private void selectTrace(ITmfTrace trace) {
+        TmfSignalManager.dispatchSignal(new TmfTraceSelectedSignal(this, trace));
+    }
+
+    private void selectTimestamp(ITmfTimestamp ts) {
+        TmfSignalManager.dispatchSignal(new TmfTimeSynchSignal(this, ts));
+    }
+
+    private void selectTimeRange(TmfTimeRange tr) {
+        TmfSignalManager.dispatchSignal(new TmfRangeSynchSignal(this, tr, null));
+    }
+
+    // ------------------------------------------------------------------------
+    // General tests
+    // ------------------------------------------------------------------------
+
+    /**
+     * Test that the manager is correctly initialized
+     */
+    @Test
+    public void testInitialize() {
+        TmfTraceManager mgr = TmfTraceManager.getInstance();
+        assertNotNull(mgr);
+    }
+
+    // ------------------------------------------------------------------------
+    // Test a single trace
+    // ------------------------------------------------------------------------
+
+    /**
+     * Test the initial range of a single trace.
+     */
+    @Test
+    public void testTraceInitialRange() {
+        openTrace(trace2);
+        final TmfTimeRange expectedRange = new TmfTimeRange(
+                trace2.getStartTime(),
+                calculateOffset(trace2.getStartTime(), trace2.getInitialRangeOffset()));
+        TmfTimeRange actualRange = tm.getCurrentRange();
+        assertEquals(expectedRange, actualRange);
+    }
+
+    /**
+     * Try selecting a timestamp contained inside the trace's range. The trace's
+     * current time should get updated correctly.
+     */
+    @Test
+    public void testNewTimestamp() {
+        openTrace(trace2);
+        ITmfTimestamp ts = new TmfTimestamp(t2start + ONE_SECOND, SCALE);
+        selectTimestamp(ts);
+
+        ITmfTimestamp afterTs = tm.getCurrentTime();
+        assertEquals(ts, afterTs);
+    }
+
+    /**
+     * Try selecting a timestamp happening before the trace's start. The change
+     * should be ignored.
+     */
+    @Test
+    public void testTimestampBefore() {
+        openTrace(trace2);
+        ITmfTimestamp beforeTs = tm.getCurrentTime();
+        ITmfTimestamp ts = new TmfTimestamp(t2start - ONE_SECOND, SCALE);
+        selectTimestamp(ts);
+
+        ITmfTimestamp curTs = tm.getCurrentTime();
+        assertEquals(beforeTs, curTs);
+    }
+
+    /**
+     * Try selecting a timestamp happening after the trace's end. The change
+     * should be ignored.
+     */
+    @Test
+    public void testTimestampAfter() {
+        openTrace(trace2);
+        ITmfTimestamp beforeTs = tm.getCurrentTime();
+        ITmfTimestamp ts = new TmfTimestamp(t2end + ONE_SECOND, SCALE);
+        selectTimestamp(ts);
+
+        ITmfTimestamp curTs = tm.getCurrentTime();
+        assertEquals(beforeTs, curTs);
+    }
+
+    /**
+     * Test selecting a normal sub-range of a single trace.
+     */
+    @Test
+    public void testTraceNewTimeRange() {
+        openTrace(trace2);
+        TmfTimeRange range = new TmfTimeRange(
+                new TmfTimestamp(t2start + ONE_SECOND, SCALE),
+                new TmfTimestamp(t2end - ONE_SECOND, SCALE));
+        selectTimeRange(range);
+
+        TmfTimeRange curRange = tm.getCurrentRange();
+        assertEquals(range.getStartTime(), curRange.getStartTime());
+        assertEquals(range.getEndTime(), curRange.getEndTime());
+    }
+
+    /**
+     * Test selecting a range whose start time is before the trace's start time.
+     * The selected range should get clamped to the trace's range.
+     */
+    @Test
+    public void testTraceTimeRangeClampingStart() {
+        openTrace(trace2);
+        TmfTimeRange range = new TmfTimeRange(
+                new TmfTimestamp(t2start - ONE_SECOND, SCALE), // minus here
+                new TmfTimestamp(t2end - ONE_SECOND, SCALE));
+        selectTimeRange(range);
+
+        TmfTimeRange curRange = tm.getCurrentRange();
+        assertEquals(t2start, curRange.getStartTime().getValue());
+        assertEquals(range.getEndTime(), curRange.getEndTime());
+    }
+
+    /**
+     * Test selecting a range whose end time is after the trace's end time.
+     * The selected range should get clamped to the trace's range.
+     */
+    @Test
+    public void testTraceTimeRangeClampingEnd() {
+        openTrace(trace2);
+        TmfTimeRange range = new TmfTimeRange(
+                new TmfTimestamp(t2start + ONE_SECOND, SCALE),
+                new TmfTimestamp(t2end + ONE_SECOND, SCALE)); // plus here
+        selectTimeRange(range);
+
+        TmfTimeRange curRange = tm.getCurrentRange();
+        assertEquals(range.getStartTime(), curRange.getStartTime());
+        assertEquals(t2end, curRange.getEndTime().getValue());
+    }
+
+    /**
+     * Test selecting a range whose both start and end times are outside of the
+     * trace's range. The selected range should get clamped to the trace's
+     * range.
+     */
+    @Test
+    public void testTraceTimeRangeClampingBoth() {
+        openTrace(trace2);
+        TmfTimeRange range = new TmfTimeRange(
+                new TmfTimestamp(t2start - ONE_SECOND, SCALE), // minus here
+                new TmfTimestamp(t2end + ONE_SECOND, SCALE)); // plus here
+        selectTimeRange(range);
+
+        TmfTimeRange curRange = tm.getCurrentRange();
+        assertEquals(t2start, curRange.getStartTime().getValue());
+        assertEquals(t2end, curRange.getEndTime().getValue());
+    }
+
+    // ------------------------------------------------------------------------
+    // Test multiple traces in parallel
+    // ------------------------------------------------------------------------
+
+    // ------------------------------------------------------------------------
+    // Test an experiment
+    // ------------------------------------------------------------------------
+
+    /**
+     * Test the initial range of an experiment.
+     */
+    @Test
+    public void testExperimentInitialRange() {
+        TmfExperiment exp = createExperiment(trace1, trace2);
+        openTrace(exp);
+        /*
+         * The initial range should be == to the initial range of the earliest
+         * trace (here trace1).
+         */
+        final TmfTimeRange traceInitialRange = new TmfTimeRange(
+                trace1.getStartTime(),
+                calculateOffset(trace1.getStartTime(), trace1.getInitialRangeOffset()));
+
+        final TmfTimeRange expInitialRange = new TmfTimeRange(
+                exp.getStartTime(),
+                calculateOffset(exp.getStartTime(), exp.getInitialRangeOffset()));
+
+        final TmfTimeRange actualRange = tm.getCurrentRange();
+
+        assertEquals(traceInitialRange, actualRange);
+        assertEquals(expInitialRange, actualRange);
+    }
+
+    /**
+     * Test the range clamping when both the start and end times of the signal's
+     * range are outside of the trace's range. The range should clamp to the
+     * experiment's range.
+     */
+    @Test
+    public void testExperimentRangeClampingBoth() {
+        TmfExperiment exp = createExperiment(trace1, trace2);
+        openTrace(exp);
+
+        final TmfTimeRange range = new TmfTimeRange(
+                new TmfTimestamp(t1start - ONE_SECOND, SCALE),
+                new TmfTimestamp(t2end + ONE_SECOND, SCALE));
+        selectTimeRange(range);
+
+        TmfTimeRange actualRange = tm.getCurrentRange();
+        assertEquals(t1start, actualRange.getStartTime().getValue());
+        assertEquals(t2end, actualRange.getEndTime().getValue());
+    }
+
+    /**
+     * Test selecting a range in-between two disjoint traces in an experiment.
+     * The range should still get correctly selected, even if no trace has any
+     * events in that range.
+     */
+    @Test
+    public void testExperimentRangeInBetween() {
+        TmfExperiment exp = createExperiment(trace1, trace2);
+        openTrace(exp);
+
+        final TmfTimeRange range = new TmfTimeRange(
+                new TmfTimestamp(t1end + ONE_SECOND, SCALE),
+                new TmfTimestamp(t2start - ONE_SECOND, SCALE));
+        selectTimeRange(range);
+
+        TmfTimeRange actualRange = tm.getCurrentRange();
+        assertEquals(range, actualRange);
+    }
+
+    // ------------------------------------------------------------------------
+    // Utility methods
+    // ------------------------------------------------------------------------
+
+    private static TmfExperiment createExperiment(ITmfTrace t1, ITmfTrace t2) {
+        ITmfTrace[] traces = new ITmfTrace[] { t1, t2 };
+        TmfExperiment exp = new TmfExperiment(ITmfEvent.class, "test-exp", traces);
+        exp.indexTrace(true);
+        return exp;
+    }
+
+    /**
+     * Basically a "initial + offset" operation, but for ITmfTimetamp objects.
+     */
+    private static ITmfTimestamp calculateOffset(ITmfTimestamp initialTs, ITmfTimestamp offsetTs) {
+        long start = initialTs.normalize(0, SCALE).getValue();
+        long offset = offsetTs.normalize(0, SCALE).getValue();
+        return new TmfTimestamp(start + offset, SCALE);
+    }
+}
index 0e8a46f0e632b66cfa2bdc3b14842d2d89ea47df..f2f2b95df31def04988b0dc6149aacd136834210 100644 (file)
@@ -15,6 +15,7 @@ package org.eclipse.linuxtools.internal.tmf.core;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Plugin;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
 import org.osgi.framework.BundleContext;
 
 /**
@@ -78,6 +79,8 @@ public class Activator extends Plugin {
         super.start(context);
         setDefault(this);
         TmfCoreTracer.init();
+        /* Initialize the trace manager */
+        TmfTraceManager.getInstance();
     }
 
     @Override
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTraceContext.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTraceContext.java
new file mode 100644 (file)
index 0000000..29e895a
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Alexandre Montplaisir - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.trace;
+
+import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+
+/**
+ * Context of a trace, which is the representation of the "view" the user
+ * currently has on this trace (selected time range, selected time stamp).
+ *
+ * TODO could be extended to support the notion of current location too.
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+final class TmfTraceContext {
+
+    static final TmfTraceContext NULL_CONTEXT =
+            new TmfTraceContext(TmfTimestamp.BIG_CRUNCH, TmfTimeRange.NULL_RANGE);
+
+    private final ITmfTimestamp fTimestamp;
+    private final TmfTimeRange fTimerange;
+
+    public TmfTraceContext(ITmfTimestamp ts, TmfTimeRange tr) {
+        fTimestamp = ts;
+        fTimerange = tr;
+    }
+
+    public TmfTraceContext(TmfTraceContext prevCtx, ITmfTimestamp ts) {
+        fTimestamp = ts;
+        fTimerange = prevCtx.fTimerange;
+    }
+
+    public ITmfTimestamp getTimestamp() {
+        return fTimestamp;
+    }
+
+    public TmfTimeRange getTimerange() {
+        return fTimerange;
+    }
+
+    public boolean isValid() {
+        if (fTimestamp.compareTo(TmfTimestamp.ZERO) <= 0 ||
+                fTimerange.getEndTime().compareTo(fTimerange.getStartTime()) <= 0) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[fTimestamp=" + fTimestamp.toString() + //$NON-NLS-1$
+                ", fTimerange=" + fTimerange + ']'; //$NON-NLS-1$
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTraceManager.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTraceManager.java
new file mode 100644 (file)
index 0000000..d524b8f
--- /dev/null
@@ -0,0 +1,308 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Alexandre Montplaisir - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.trace;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.linuxtools.tmf.core.signal.TmfSignalManager;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+
+/**
+ * Central trace manager for TMF. It tracks the currently opened traces and
+ * experiment, as well as the currently-selected timestamps and time ranges for
+ * each one of those.
+ *
+ * It's a singleton class, so only one instance should exist (available via
+ * {@link #getInstance()}).
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+public final class TmfTraceManager {
+
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+
+    private final Map<ITmfTrace, TmfTraceContext> fTraces;
+
+    /** The currently-selected trace. Should always be part of the trace map */
+    private ITmfTrace fCurrentTrace = null;
+
+    // ------------------------------------------------------------------------
+    // Constructor
+    // ------------------------------------------------------------------------
+
+    private TmfTraceManager() {
+        fTraces = new LinkedHashMap<ITmfTrace, TmfTraceContext>();
+        TmfSignalManager.registerVIP(this);
+    }
+
+    /** Singleton instance */
+    private static TmfTraceManager tm = null;
+
+    /**
+     * Get an instance of the trace manager.
+     *
+     * @return The trace manager
+     */
+    public static synchronized TmfTraceManager getInstance() {
+        if (tm == null) {
+            tm = new TmfTraceManager();
+        }
+        return tm;
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    /**
+     * Return the current selected time.
+     *
+     * @return the current time stamp
+     */
+    public synchronized ITmfTimestamp getCurrentTime() {
+        return getCurrentTraceContext().getTimestamp();
+    }
+
+    /**
+     * Return the current selected range.
+     *
+     * @return the current time range
+     */
+    public synchronized TmfTimeRange getCurrentRange() {
+        return getCurrentTraceContext().getTimerange();
+    }
+
+    /**
+     * Get the currently selected trace (normally, the focused editor).
+     *
+     * @return The active trace
+     */
+    public synchronized ITmfTrace getActiveTrace() {
+        return fCurrentTrace;
+    }
+
+    /**
+     * Get the currently active trace set. For a 'normal' trace, this is simply
+     * an array with only that trace in it. For trace experiments, this will be
+     * an array containing the 'real' child traces in the experiment.
+     *
+     * @return The active trace set
+     */
+    public synchronized ITmfTrace[] getActiveTraceSet() {
+        final ITmfTrace trace = fCurrentTrace;
+        if (trace instanceof TmfExperiment) {
+            final TmfExperiment exp = (TmfExperiment) trace;
+            return exp.getTraces();
+        }
+        return new ITmfTrace[] { trace };
+    }
+
+    private TmfTraceContext getCurrentTraceContext() {
+        TmfTraceContext curCtx = fTraces.get(fCurrentTrace);
+        if (curCtx == null) {
+            /* There are no traces opened at the moment. */
+            return TmfTraceContext.NULL_CONTEXT;
+        }
+        return curCtx;
+    }
+
+    // ------------------------------------------------------------------------
+    // Signal handlers
+    // ------------------------------------------------------------------------
+
+    /**
+     * Signal handler for the traceOpened signal.
+     *
+     * @param signal
+     *            The incoming signal
+     */
+    @TmfSignalHandler
+    public synchronized void traceOpened(final TmfTraceOpenedSignal signal) {
+        final ITmfTrace trace = signal.getTrace();
+        final ITmfTimestamp startTs = trace.getStartTime();
+
+        /* Calculate the initial time range */
+        final int SCALE = ITmfTimestamp.NANOSECOND_SCALE;
+        long offset = trace.getInitialRangeOffset().normalize(0, SCALE).getValue();
+        long endTime = startTs.normalize(0, SCALE).getValue() + offset;
+        final TmfTimeRange startTr = new TmfTimeRange(startTs, new TmfTimestamp(endTime, SCALE));
+
+        final TmfTraceContext startCtx = new TmfTraceContext(startTs, startTr);
+
+        fTraces.put(trace, startCtx);
+
+        /* We also want to set the newly-opened trace as the active trace */
+        fCurrentTrace = trace;
+    }
+
+
+    /**
+     * Handler for the TmfTraceSelectedSignal.
+     *
+     * @param signal
+     *            The incoming signal
+     */
+    @TmfSignalHandler
+    public synchronized void traceSelected(final TmfTraceSelectedSignal signal) {
+        final ITmfTrace newTrace = signal.getTrace();
+        if (!fTraces.containsKey(newTrace)) {
+            throw new RuntimeException();
+        }
+        fCurrentTrace = newTrace;
+    }
+
+    /**
+     * Signal handler for the traceClosed signal.
+     *
+     * @param signal
+     *            The incoming signal
+     */
+    @TmfSignalHandler
+    public synchronized void traceClosed(final TmfTraceClosedSignal signal) {
+        TmfTraceContext ret = fTraces.remove(signal.getTrace());
+        if (ret == null) {
+            throw new RuntimeException();
+        }
+        if (fTraces.size() == 0) {
+            fCurrentTrace = null;
+            /*
+             * In other cases, we should receive a traceSelected signal that
+             * will indicate which trace is the new one.
+             */
+        }
+    }
+
+    /**
+     * Signal handler for the TmfTimeSynchSignal signal.
+     *
+     * The current time of *all* traces whose range contains the requested new
+     * time will be updated.
+     *
+     * @param signal
+     *            The incoming signal
+     */
+    @TmfSignalHandler
+    public synchronized void timeUpdated(final TmfTimeSynchSignal signal) {
+        final ITmfTimestamp ts = signal.getCurrentTime();
+
+        for (Map.Entry<ITmfTrace, TmfTraceContext> entry : fTraces.entrySet()) {
+            final ITmfTrace trace = entry.getKey();
+            if (ts.intersects(getValidTimeRange(trace))) {
+                TmfTraceContext prevCtx = entry.getValue();
+                TmfTraceContext newCtx = new TmfTraceContext(prevCtx, ts);
+                entry.setValue(newCtx);
+            }
+        }
+    }
+
+    /**
+     * Signal handler for the TmfRangeSynchSignal signal.
+     *
+     * The current timestamp and timerange of *all* valid traces will be updated
+     * to the new requested times.
+     *
+     * @param signal
+     *            The incoming signal
+     */
+    @TmfSignalHandler
+    public synchronized void timeRangeUpdated(final TmfRangeSynchSignal signal) {
+        final ITmfTimestamp signalTs = signal.getCurrentTime();
+
+        for (Map.Entry<ITmfTrace, TmfTraceContext> entry : fTraces.entrySet()) {
+            final ITmfTrace trace = entry.getKey();
+            final TmfTraceContext curCtx = entry.getValue();
+
+            final TmfTimeRange validTr = getValidTimeRange(trace);
+
+            /* Determine the new time stamp */
+            ITmfTimestamp newTs;
+            if (signalTs != null && signalTs.intersects(validTr)) {
+                newTs = signalTs;
+            } else {
+                newTs = curCtx.getTimestamp();
+            }
+
+            /* Determine the new time range */
+            TmfTimeRange targetTr = signal.getCurrentRange().getIntersection(validTr);
+            TmfTimeRange newTr = (targetTr == null ? curCtx.getTimerange() : targetTr);
+
+            /* Update the values */
+            TmfTraceContext newCtx = new TmfTraceContext(newTs, newTr);
+            entry.setValue(newCtx);
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // Utility methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Return the valid time range of a trace (not the "current time range", but
+     * the range of all possible valid timestamps).
+     *
+     * For a real trace this is the whole range of the trace. For an experiment,
+     * it goes from the start time of the earliest trace to the end time of the
+     * latest one.
+     *
+     * @param trace
+     *            The trace to check for
+     * @return The valid time span, or 'null' if the trace is not valid
+     */
+    private TmfTimeRange getValidTimeRange(ITmfTrace trace) {
+        if (!fTraces.containsKey(trace)) {
+            /* Trace is not part of the currently opened traces */
+            return null;
+        }
+        if (!(trace instanceof TmfExperiment)) {
+            /* "trace" is a single trace, return its time range directly */
+            return trace.getTimeRange();
+        }
+        final ITmfTrace[] traces = ((TmfExperiment) trace).getTraces();
+        if (traces.length == 0) {
+            /* We are being trolled */
+            return null;
+        }
+        if (traces.length == 1) {
+            /* Trace is an experiment with only 1 trace */
+            return traces[0].getTimeRange();
+        }
+        /*
+         * Trace is an experiment with 2+ traces, so get the earliest start and
+         * the latest end.
+         */
+        ITmfTimestamp start = traces[0].getStartTime();
+        ITmfTimestamp end = traces[0].getEndTime();
+        for (int i = 1; i < traces.length; i++) {
+            ITmfTrace curTrace = traces[i];
+            if (curTrace.getStartTime().compareTo(start) < 0) {
+                start = curTrace.getStartTime();
+            }
+            if (curTrace.getEndTime().compareTo(end) > 0) {
+                end = curTrace.getEndTime();
+            }
+        }
+        return new TmfTimeRange(start, end);
+    }
+}
This page took 0.040685 seconds and 5 git commands to generate.