+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2;
+
+import java.util.logging.Logger;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.log.TraceCompassLog;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalThrottler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+public class SignallingContext {
+
+ private static final Logger LOGGER = TraceCompassLog.getLogger(SignallingContext.class);
+
+ private static final int SIGNAL_DELAY_MS = 200;
+
+ private final TmfSignalThrottler fVisibleRangeSignalThrottler = new TmfSignalThrottler(null, SIGNAL_DELAY_MS);
+
+ private final TimeGraphModelViewer fViewer;
+
+ private @Nullable ITmfTrace fCurrentTrace = null;
+
+ public SignallingContext(TimeGraphModelViewer viewer) {
+ TmfSignalManager.register(this);
+ fViewer = viewer;
+ }
+
+ public void dispose() {
+ TmfSignalManager.deregister(this);
+ }
+
+ @Nullable ITmfTrace getCurrentTrace() {
+ return fCurrentTrace;
+ }
+
+ public void sendTimeRangeSelectionUpdate(long startTs, long endTs) {
+ TmfSignal signal = new TmfSelectionRangeUpdatedSignal(this,
+ TmfTimestamp.fromNanos(startTs),
+ TmfTimestamp.fromNanos(endTs));
+ TmfSignalManager.dispatchSignal(signal);
+ }
+
+ public void sendVisibleWindowRangeUpdate(long startTs, long endTs) {
+ TmfSignal signal = new TmfWindowRangeUpdatedSignal(this,
+ new TmfTimeRange(TmfTimestamp.fromNanos(startTs), TmfTimestamp.fromNanos(endTs)));
+ fVisibleRangeSignalThrottler.queue(signal);
+ }
+
+ public void initializeForTrace(@Nullable ITmfTrace trace) {
+ fCurrentTrace = trace;
+
+ if (trace == null) {
+ // TODO Clear the viewer?
+ return;
+ }
+
+ long traceStartTime = trace.getStartTime().toNanos();
+ long traceEndTime = trace.getEndTime().toNanos();
+
+ /* The window's start time is the same as the trace's start time initially */
+ long windowStartTime = traceStartTime;
+ long windowEndtime = Math.min(traceEndTime, traceStartTime + trace.getInitialRangeOffset().toNanos());
+
+ fViewer.setTimeGraphAreaRange(traceStartTime, traceEndTime);
+ fViewer.seekVisibleRange(windowStartTime, windowEndtime);
+ fViewer.paintArea(trace, windowStartTime, windowEndtime);
+ }
+
+ // ------------------------------------------------------------------------
+ // Signal handlers
+ // ------------------------------------------------------------------------
+
+ @TmfSignalHandler
+ public void traceOpened(TmfTraceOpenedSignal signal) {
+ LOGGER.fine(() -> "[SignallingContext:ReceivedTraceOpen] trace=" + signal.getTrace().toString()); //$NON-NLS-1$
+
+ ITmfTrace newTrace = signal.getTrace();
+ fCurrentTrace = newTrace;
+ initializeForTrace(newTrace);
+ }
+
+ @TmfSignalHandler
+ public void traceSelected(final TmfTraceSelectedSignal signal) {
+ LOGGER.fine(() -> "[SignallingContext:ReceivedTraceSelected] trace=" + signal.getTrace().toString());
+
+ ITmfTrace newTrace = signal.getTrace();
+ fCurrentTrace = newTrace;
+ initializeForTrace(newTrace);
+ }
+
+ /**
+ * @param signal
+ */
+ @TmfSignalHandler
+ public void traceClosed(final TmfTraceClosedSignal signal) {
+ LOGGER.fine(() -> "[SignallingContext:ReceivedTraceClosed] " + //$NON-NLS-1$
+ signal.getTrace().getName());
+
+ // How does this signal work anyway?
+ // TODO Implement this!
+ //fViewer.clearViewer()
+ }
+
+ /**
+ * @param signal
+ */
+ @TmfSignalHandler
+ public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal) {
+ long rangeStart = signal.getRange().getStartTime().toNanos();
+ long rangeEnd = signal.getRange().getEndTime().toNanos();
+
+ LOGGER.finer(() -> "[SignallingContext:ReceivedTraceRangeUpdated] " + //$NON-NLS-1$
+ String.format("rangeStart=%,d, rangeEnd=%,d", //$NON-NLS-1$
+ rangeStart, rangeEnd));
+ /*
+ * This signal is a disaster, it's very inconsistent, has no guarantee
+ * of even showing up and sometimes gives values outside of the trace's
+ * own range. Best to ignore its contents completely.
+ */
+
+ ITmfTrace trace = fCurrentTrace;
+ if (trace != null) {
+ long traceStart = trace.getStartTime().toNanos();
+ long traceEnd = trace.getEndTime().toNanos();
+ fViewer.setTimeGraphAreaRange(traceStart, traceEnd);
+ }
+ }
+
+ /**
+ * @param signal
+ */
+ @TmfSignalHandler
+ public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
+ long rangeStart = signal.getBeginTime().toNanos();
+ long rangeEnd = signal.getEndTime().toNanos();
+
+ LOGGER.finer(() -> "[SignallingContext:ReceivedSelectionRangeUpdated] " + //$NON-NLS-1$
+ String.format("rangeStart=%,d, rangeEnd=%,d", //$NON-NLS-1$
+ rangeStart, rangeEnd));
+
+ if (rangeStart > rangeEnd) {
+ /* This signal's end can be before its start time, against all logic */
+ fViewer.drawSelection(rangeEnd, rangeStart);
+ } else {
+ fViewer.drawSelection(rangeStart, rangeEnd);
+ }
+ }
+
+ /**
+ * @param signal
+ */
+ @TmfSignalHandler
+ public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
+ ITmfTrace trace = fCurrentTrace;
+ if (trace == null) {
+ return;
+ }
+
+ long traceStart = trace.getStartTime().toNanos();
+ long traceEnd = trace.getEndTime().toNanos();
+
+ TmfTimeRange windowRange = signal.getCurrentRange();
+ long windowStart = Math.max(traceStart, windowRange.getStartTime().toNanos());
+ long windowEnd = Math.min(traceEnd, windowRange.getEndTime().toNanos());
+
+ LOGGER.finer(() -> "[SignallingContext:ReceivedWindowRangeUpdated] " + //$NON-NLS-1$
+ String.format("windowStart=%,d, windowEnd=%,d", //$NON-NLS-1$
+ windowStart, windowEnd));
+
+ fViewer.setTimeGraphAreaRange(traceStart, traceEnd);
+
+ if (signal.getSource() != this) {
+ /*
+ * If the signal came from the time graph's own scrollbar, then the
+ * zoom level did not change, and the view is already at the
+ * position we want it.
+ *
+ * TODO May not be true when it comes from a zoom in/out event
+ */
+ fViewer.seekVisibleRange(windowStart, windowEnd);
+ } else {
+ fViewer.updateLatestVisibleRange(windowStart, windowEnd);
+ }
+
+ fViewer.paintArea(trace, windowStart, windowEnd);
+ }
+}