[WIP] CFV Refactor wip-cfv-refactor
authorAlexandre Montplaisir <alexmonthy@efficios.com>
Wed, 27 Jul 2016 18:48:21 +0000 (14:48 -0400)
committerAlexandre Montplaisir <alexmonthy@efficios.com>
Tue, 1 Nov 2016 19:52:20 +0000 (15:52 -0400)
To use the JavaFX views:

1) Make sure you have JavaFX installed
   If you use Oracle's JVM, you already have it.
   If you use OpenJDK, you may need to "apt-get install openjfx"
   or equivalent.

2) Install the following feature into your development Eclipse:
     e(fx)clipse - IDE
   It should be available from the default update sites.

3) Add the following to the Run Configuration's VM Arguments:
   -Dosgi.framework.extensions=org.eclipse.fx.osgi

The prototype view is called "Control Flow (JFX)" and is
accessible from the "Show View" menu.

Change-Id: I6d8b4db85ae17579d57a150f8c44460e86d0003d
Signed-off-by: Alexandre Montplaisir <alexmonthy@efficios.com>
60 files changed:
analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/views/controlflow2/ControlFlowRenderProviderTest.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowConfigModes.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowRenderProvider.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowTreeElement.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/Messages.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/messages.properties [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/package-info.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtControlFlowView.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtJfxControlFlowView.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/package-info.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ColorDefinition.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ITimeGraphModelRenderProvider.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/Messages.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrow.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrowSeries.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphDrawnEvent.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphEvent.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRender.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRenderProvider.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphStateInterval.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeElement.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeModel.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeRender.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/messages.properties [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/package-info.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemModelRenderProvider.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemTimeGraphTreeElement.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/package-info.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStaticTest.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerTest.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/ModelRenderProviderStub.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStub.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/package-info.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/SignallingContext.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelView.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelViewer.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/package-info.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtColorFactory.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtTimeGraphView.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/package-info.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/ActionFactory.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/JfxColorFactory.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/LatestJobExecutor.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphView.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphViewer.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/Example.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/Example2.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/ExampleCanvas.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/ExampleMouseDrag.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/ExampleMouseDrag2.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/SwtToobar2.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/TestSwtToolbar.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/application.css [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/package-info.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/package-info.java [new file with mode: 0644]

diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/views/controlflow2/ControlFlowRenderProviderTest.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/views/controlflow2/ControlFlowRenderProviderTest.java
new file mode 100644 (file)
index 0000000..7212388
--- /dev/null
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * 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.analysis.os.linux.core.tests.views.controlflow2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
+import org.eclipse.tracecompass.analysis.os.linux.core.tests.stubs.trace.KernelCtfTraceStub;
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2.ControlFlowRenderProvider;
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2.ControlFlowTreeElement;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRender;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.tracecompass.testtraces.ctf.CtfTestTrace;
+import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for {@link ControlFlowRenderProvider}.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class ControlFlowRenderProviderTest {
+
+//    /** Timeout the tests after 2 minutes */
+//    @Rule
+//    public TestRule timeoutRule = new Timeout(2, TimeUnit.MINUTES);
+
+    private static final long NANOS_PER_SECOND = 1000000000L;
+
+    private static final @NonNull CtfTestTrace TEST_TRACE = CtfTestTrace.KERNEL;
+
+    private static ITmfTrace sfTrace;
+    private static ITmfStateSystem sfSS;
+
+    private ControlFlowRenderProvider provider = new ControlFlowRenderProvider();
+
+    /**
+     * Test class setup
+     */
+    @Before
+    public void setupClass() {
+        TmfTrace trace = KernelCtfTraceStub.getTrace(TEST_TRACE);
+        trace.traceOpened(new TmfTraceOpenedSignal(ControlFlowRenderProviderTest.class, trace, null));
+
+        IAnalysisModule analysis = TmfTraceUtils.getAnalysisModuleOfClass(trace, KernelAnalysisModule.class, KernelAnalysisModule.ID);
+        assertNotNull(analysis);
+        analysis.schedule(); // Should have run, just in case
+        analysis.waitForCompletion();
+
+        ITmfStateSystem ss = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
+        assertNotNull(ss);
+
+        sfTrace = trace;
+        sfSS = ss;
+    }
+
+    /**
+     * Test class teardown
+     */
+    @After
+    public void teardownClass() {
+        if (sfTrace != null) {
+            /* Trace's dispose will dispose its state systems */
+            sfTrace.dispose();
+        }
+    }
+
+    /**
+     * Check that the info in a render for the first second of the trace matches
+     * the corresponding info found in the state system.
+     */
+    @Test
+    public void test1s() {
+        try {
+            final ITmfTrace trace = sfTrace;
+            final ITmfStateSystem ss = sfSS;
+            assertNotNull(trace);
+            assertNotNull(ss);
+
+            final long start = trace.getStartTime().toNanos();
+            final long end = start + 1 * NANOS_PER_SECOND;
+
+            TimeGraphModelRender modelRender = provider.getRender(trace, start, end, 1);
+
+            /* Check that the list of attributes (tree render) are the same */
+            TimeGraphTreeRender treeRender = modelRender.getTreeRender();
+            List<TimeGraphTreeElement> treeElems = treeRender.getAllTreeElements();
+
+            List<String> tidsFromRender = treeElems.stream()
+                    .map(e -> (ControlFlowTreeElement) e)
+                    .mapToInt(ControlFlowTreeElement::getTid)
+                    .mapToObj(tid -> String.valueOf(tid))
+                    .sorted()
+                    .collect(Collectors.toList());
+
+            int threadsQuark = ss.getQuarkAbsolute(Attributes.THREADS);
+            List<String> tidsFromSS = ss.getSubAttributes(threadsQuark, false).stream()
+                    .map(quark -> ss.getAttributeName(quark))
+                    .map(name -> {
+                        if (name.startsWith(Attributes.THREAD_0_PREFIX)) {
+                            return "0";
+                        }
+                        return name;
+                    })
+                    .sorted()
+                    .collect(Collectors.toList());
+
+            assertEquals(tidsFromSS, tidsFromRender);
+            // TODO Also verify against known hard-coded list
+
+
+            /* Check that the state intervals are the same */
+            List<String> tidsInSS = ss.getQuarks(threadsQuark, "*").stream()
+                    .map(ss::getAttributeName)
+                    .sorted()
+                    .collect(Collectors.toList());
+
+            for (String tid : tidsInSS) {
+                int threadQuark = ss.getQuarkRelative(threadsQuark, tid);
+                List<ITmfStateInterval> intervalsFromSS =
+                        StateSystemUtils.queryHistoryRange(ss, threadQuark, start, end);
+
+                TimeGraphTreeElement elem = treeElems.stream()
+                        .map(e -> (ControlFlowTreeElement) e)
+                        .filter(e -> e.getSourceQuark() == threadQuark)
+                        .findFirst()
+                        .get();
+
+                int index = treeElems.indexOf(elem);
+                List<TimeGraphStateInterval> intervalsFromRender = modelRender.getStateIntervals().get(index);
+
+                verifySameIntervals(intervalsFromSS, intervalsFromRender);
+                // TODO Also verify against known hard-coded list
+            }
+
+        } catch (AttributeNotFoundException | StateSystemDisposedException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    private static void verifySameIntervals(List<ITmfStateInterval> ssIntervals,
+            List<TimeGraphStateInterval> renderIntervals) {
+        assertEquals(ssIntervals.size(), renderIntervals.size());
+
+        for (int i = 0; i < ssIntervals.size(); i++) {
+            ITmfStateInterval ssInterval = ssIntervals.get(i);
+            TimeGraphStateInterval renderInterval = renderIntervals.get(i);
+
+            assertEquals(ssInterval.getStartTime(), renderInterval.getStartEvent().getTimestamp());
+            assertEquals(ssInterval.getEndTime(), renderInterval.getEndEvent().getTimestamp());
+
+            int stateValue = ssInterval.getStateValue().unboxInt();
+            String stateName = ControlFlowRenderProvider.mapStateValueToStateName(stateValue);
+            assertEquals(stateName, renderInterval.getStateName());
+        }
+    }
+}
index 3a05843db1b277c00f6590cb89856fc3305ea18e..8fb0e9ae71461765b451e65ee167edf12c67e916 100644 (file)
@@ -15,7 +15,8 @@ Require-Bundle: org.eclipse.core.runtime,
  org.eclipse.tracecompass.segmentstore.core,
  org.eclipse.tracecompass.analysis.timing.core,
  org.eclipse.tracecompass.statesystem.core
-Import-Package: com.google.common.base,
+Import-Package: com.google.common.annotations,
+ com.google.common.base,
  com.google.common.collect,
  com.google.common.hash,
  com.google.common.primitives
@@ -35,4 +36,5 @@ Export-Package: org.eclipse.tracecompass.analysis.os.linux.core.contextswitch,
  org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests,org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests",
  org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests",
  org.eclipse.tracecompass.internal.analysis.os.linux.core.latency;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests,org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests",
- org.eclipse.tracecompass.internal.analysis.os.linux.core.latency.statistics;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.analysis.os.linux.core.tests"
+ org.eclipse.tracecompass.internal.analysis.os.linux.core.latency.statistics;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.analysis.os.linux.core.tests",
+ org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.analysis.os.linux.core.tests"
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowConfigModes.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowConfigModes.java
new file mode 100644 (file)
index 0000000..6560774
--- /dev/null
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * 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.analysis.os.linux.core.views.controlflow2;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
+
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider.FilterMode;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider.SortingMode;
+
+public interface ControlFlowConfigModes {
+
+    SortingMode SORTING_BY_TID = new SortingMode(nullToEmptyString(Messages.ControlFlowSortingModes_ByTid));
+
+    SortingMode SORTING_BY_THREAD_NAME = new SortingMode(nullToEmptyString(Messages.ControlFlowSortingModes_ByThreadName));
+
+    FilterMode FILTERING_INACTIVE_ENTRIES = new FilterMode(nullToEmptyString(Messages.ControlFlowFilterModes_InactiveEntries));
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowRenderProvider.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowRenderProvider.java
new file mode 100644 (file)
index 0000000..c8447ec
--- /dev/null
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * 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.analysis.os.linux.core.views.controlflow2;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues;
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval.LineThickness;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem.StateSystemModelRenderProvider;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+public class ControlFlowRenderProvider extends StateSystemModelRenderProvider {
+
+    private static final List<SortingMode> SORTING_MODES = ImmutableList.of(
+            ControlFlowConfigModes.SORTING_BY_TID,
+            ControlFlowConfigModes.SORTING_BY_THREAD_NAME);
+
+    private static final List<FilterMode> FILTER_MODES = ImmutableList.of(
+            ControlFlowConfigModes.FILTERING_INACTIVE_ENTRIES);
+
+    /**
+     * State values that are considered inactive, for purposes of filtering out
+     * when the "filter inactive entries" mode is enabled.
+     */
+    private static final Set<ITmfStateValue> INACTIVE_STATE_VALUES = ImmutableSet.of(
+            TmfStateValue.nullValue(),
+            StateValues.PROCESS_STATUS_UNKNOWN_VALUE,
+            StateValues.PROCESS_STATUS_WAIT_UNKNOWN_VALUE,
+            StateValues.PROCESS_STATUS_WAIT_BLOCKED_VALUE
+            );
+
+    /**
+     * Each "Thread" attribute has the following children:
+     *
+     * <ul>
+     * <li>Prio</li>
+     * <li>System_call</li>
+     * <li>Exec_name</li>
+     * <li>PPID</li>
+     * </ul>
+     *
+     * The "Thread" is considered the base quark.
+     */
+    private static final String[] BASE_QUARK_PATTERN = { Attributes.THREADS, "*" }; //$NON-NLS-1$
+
+    /**
+     * Get the tree element name for every thread. It consists of the TID
+     * followed by the first available exec_name for this thread.
+     *
+     * FIXME This implies a static tree definition for every TID, which does not
+     * handle TID re-use correctly. The state system structure should be updated
+     * accordingly.
+     */
+    @VisibleForTesting
+    public static final Function<TreeRenderContext, TimeGraphTreeRender> SS_TO_TREE_RENDER_FUNCTION = (treeContext) -> {
+        ITmfStateSystem ss = treeContext.ss;
+        List<ITmfStateInterval> fullState = treeContext.fullQueryAtRangeStart;
+
+        Stream<ControlFlowTreeElement> treeElems = ss.getQuarks(BASE_QUARK_PATTERN).stream()
+                .map(baseQuark -> {
+                    String tid = ss.getAttributeName(baseQuark);
+
+                    String threadName;
+                    try {
+                        int execNameQuark = ss.getQuarkRelative(baseQuark, Attributes.EXEC_NAME);
+                        // TODO We should look starting at treeContext.renderTimeRangeStart
+                        // first, and if we don't find anything use ss.getStartTime(), so that
+                        // we catch subsequent process name changes
+                        ITmfStateInterval firstInterval = StateSystemUtils.queryUntilNonNullValue(ss,
+                                execNameQuark, ss.getStartTime(), Long.MAX_VALUE);
+                        if (firstInterval == null) {
+                            threadName = null;
+                        } else {
+                            threadName = firstInterval.getStateValue().unboxStr();
+                        }
+                    } catch (AttributeNotFoundException | StateValueTypeException e) {
+                        threadName = null;
+                    }
+
+                    return new ControlFlowTreeElement(tid, threadName, Collections.emptyList(), baseQuark);
+                });
+
+        /* Run the entries through the active filter modes */
+        Set<FilterMode> filterModes = treeContext.filterModes;
+        if (filterModes.contains(ControlFlowConfigModes.FILTERING_INACTIVE_ENTRIES)) {
+            /*
+             * Filter out the tree elements whose state is considered inactive
+             * for the whole duration of the configured time range.
+             */
+            treeElems = treeElems.filter(elem -> {
+                ITmfStateInterval interval = fullState.get(elem.getSourceQuark());
+                if (interval.getEndTime() > treeContext.renderTimeRangeEnd &&
+                        INACTIVE_STATE_VALUES.contains(interval.getStateValue())) {
+                    return false;
+                }
+                return true;
+            });
+        }
+
+        /* Sort entries according to the active sorting mode */
+        SortingMode sortingMode = treeContext.sortingMode;
+        if (sortingMode == ControlFlowConfigModes.SORTING_BY_TID) {
+            treeElems = treeElems.sorted(Comparator.comparingInt(ControlFlowTreeElement::getTid));
+        } else if (sortingMode == ControlFlowConfigModes.SORTING_BY_THREAD_NAME) {
+            treeElems = treeElems.sorted((elem1, elem2) -> {
+                return elem1.getThreadName().compareToIgnoreCase(elem2.getThreadName());
+            });
+        }
+
+        List<TimeGraphTreeElement> treeElemsList = treeElems.collect(Collectors.toList());
+        return new TimeGraphTreeRender(treeElemsList);
+    };
+
+
+
+    /**
+     * Function mapping state names
+     *
+     * @param value
+     *            State value representing the state
+     * @return The state name to display, should be localized
+     */
+    @VisibleForTesting
+    public static String mapStateValueToStateName(int value) {
+        try {
+            switch (value) {
+            case StateValues.PROCESS_STATUS_WAIT_UNKNOWN:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_WaitUnknown);
+            case StateValues.PROCESS_STATUS_WAIT_BLOCKED:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_WaitBlocked);
+            case StateValues.PROCESS_STATUS_WAIT_FOR_CPU:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_WaitForCpu);
+            case StateValues.PROCESS_STATUS_RUN_USERMODE:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_UserMode);
+            case StateValues.PROCESS_STATUS_RUN_SYSCALL:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Syscall);
+            case StateValues.PROCESS_STATUS_INTERRUPTED:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Interrupted);
+            default:
+                return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Unknown);
+            }
+
+        } catch (StateValueTypeException e) {
+            return nullToEmptyString(Messages.ControlFlowRenderProvider_State_Unknown);
+        }
+    }
+
+    private static final Function<StateIntervalContext, String> STATE_NAME_MAPPING_FUNCTION = ssCtx -> {
+        int statusQuark = ssCtx.baseTreeElement.getSourceQuark();
+        ITmfStateValue val = ssCtx.fullQueryAtIntervalStart.get(statusQuark).getStateValue();
+        int status = val.unboxInt();
+        return mapStateValueToStateName(status);
+    };
+
+
+    private static final ColorDefinition NO_COLOR           = new ColorDefinition(  0,   0,   0,  0);
+    private static final ColorDefinition COLOR_UNKNOWN      = new ColorDefinition(100, 100, 100);
+    private static final ColorDefinition COLOR_WAIT_UNKNOWN = new ColorDefinition(200, 200, 200);
+    private static final ColorDefinition COLOR_WAIT_BLOCKED = new ColorDefinition(200, 200,   0);
+    private static final ColorDefinition COLOR_WAIT_FOR_CPU = new ColorDefinition(200, 100,   0);
+    private static final ColorDefinition COLOR_USERMODE     = new ColorDefinition(  0, 200,   0);
+    private static final ColorDefinition COLOR_SYSCALL      = new ColorDefinition(  0,   0, 200);
+    private static final ColorDefinition COLOR_INTERRUPTED  = new ColorDefinition(200,   0, 100);
+
+    private static final Function<StateIntervalContext, ColorDefinition> COLOR_MAPPING_FUNCTION = ssCtx -> {
+        try {
+            int statusQuark = ssCtx.baseTreeElement.getSourceQuark();
+            ITmfStateValue val = ssCtx.fullQueryAtIntervalStart.get(statusQuark).getStateValue();
+
+            if (val.isNull()) {
+                return NO_COLOR;
+            }
+
+            int status = val.unboxInt();
+            switch (status) {
+            case StateValues.PROCESS_STATUS_WAIT_UNKNOWN:
+                return COLOR_WAIT_UNKNOWN;
+            case StateValues.PROCESS_STATUS_WAIT_BLOCKED:
+                return COLOR_WAIT_BLOCKED;
+            case StateValues.PROCESS_STATUS_WAIT_FOR_CPU:
+                return COLOR_WAIT_FOR_CPU;
+            case StateValues.PROCESS_STATUS_RUN_USERMODE:
+                return COLOR_USERMODE;
+            case StateValues.PROCESS_STATUS_RUN_SYSCALL:
+                return COLOR_SYSCALL;
+            case StateValues.PROCESS_STATUS_INTERRUPTED:
+                return COLOR_INTERRUPTED;
+            default:
+                return COLOR_UNKNOWN;
+            }
+
+        } catch (StateValueTypeException e) {
+            return COLOR_UNKNOWN;
+        }
+    };
+
+    /* No variation for now */
+    private static final Function<StateIntervalContext, LineThickness> LINE_THICKNESS_MAPPING_FUNCTION = ssCtx -> {
+//        int statusQuark = ssCtx.baseTreeElement.getSourceQuark();
+//        ITmfStateValue val = ssCtx.fullQueryAtIntervalStart.get(statusQuark).getStateValue();
+//
+//        // For demo purposes only!
+//        if (val.equals(StateValues.PROCESS_STATUS_RUN_SYSCALL_VALUE)) {
+//            return LineThickness.SMALL;
+//        }
+
+        return LineThickness.NORMAL;
+    };
+
+    // TODO
+    private static final Function<StateIntervalContext, @Nullable Supplier<Map<String, String>>> PROPERTY_MAPPING_FUNCTION = ssCtx -> {
+        return null;
+    };
+
+    /**
+     * Constructor
+     */
+    public ControlFlowRenderProvider() {
+        super(SORTING_MODES,
+                FILTER_MODES,
+                /* Parameters specific to state system render providers */
+                KernelAnalysisModule.ID,
+                SS_TO_TREE_RENDER_FUNCTION,
+                STATE_NAME_MAPPING_FUNCTION,
+                COLOR_MAPPING_FUNCTION,
+                LINE_THICKNESS_MAPPING_FUNCTION,
+                PROPERTY_MAPPING_FUNCTION);
+
+        enableFilterMode(0);
+    }
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowTreeElement.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowTreeElement.java
new file mode 100644 (file)
index 0000000..3964d12
--- /dev/null
@@ -0,0 +1,51 @@
+package org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem.StateSystemTimeGraphTreeElement;
+
+public class ControlFlowTreeElement extends StateSystemTimeGraphTreeElement {
+
+    private static final String UNKNOWN_THREAD_NAME = "???"; //$NON-NLS-1$
+
+    private final int fTid;
+    private final String fThreadName;
+
+    public ControlFlowTreeElement(String tidStr, @Nullable String threadName,
+            List<TimeGraphTreeElement> children, int sourceQuark) {
+        super(getElementName(tidStr, threadName),
+                children,
+                sourceQuark);
+
+        if (tidStr.startsWith(Attributes.THREAD_0_PREFIX)) {
+            fTid = 0;
+        } else {
+            fTid = Integer.parseInt(tidStr);
+        }
+
+        fThreadName = (threadName == null ? UNKNOWN_THREAD_NAME : threadName);
+    }
+
+    private static String getElementName(String tidStr, @Nullable String threadName) {
+        String tidPart = tidStr;
+        if (tidPart.startsWith(Attributes.THREAD_0_PREFIX)) {
+            /* Display "0/0" instead of "0_0" */
+            tidPart = tidPart.replace('_', '/');
+        }
+
+        String threadNamePart = (threadName == null ? UNKNOWN_THREAD_NAME : threadName);
+        return (tidPart + " - " + threadNamePart); //$NON-NLS-1$
+    }
+
+    public int getTid() {
+        return fTid;
+    }
+
+    public String getThreadName() {
+        return fThreadName;
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/Messages.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/Messages.java
new file mode 100644 (file)
index 0000000..ddf18e3
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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.analysis.os.linux.core.views.controlflow2;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages class
+ *
+ * @author Alexandre Montplaisir
+ */
+@SuppressWarnings("javadoc")
+@NonNullByDefault({})
+public class Messages extends NLS {
+
+    private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
+
+    public static String ControlFlowRenderProvider_State_WaitUnknown;
+    public static String ControlFlowRenderProvider_State_WaitBlocked;
+    public static String ControlFlowRenderProvider_State_WaitForCpu;
+    public static String ControlFlowRenderProvider_State_UserMode;
+    public static String ControlFlowRenderProvider_State_Syscall;
+    public static String ControlFlowRenderProvider_State_Interrupted;
+    public static String ControlFlowRenderProvider_State_Unknown;
+
+    public static String ControlFlowSortingModes_ByTid;
+    public static String ControlFlowSortingModes_ByThreadName;
+
+    public static String ControlFlowFilterModes_InactiveEntries;
+
+    static {
+        NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+    }
+
+    private Messages() {
+    }
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/messages.properties b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/messages.properties
new file mode 100644 (file)
index 0000000..8df078e
--- /dev/null
@@ -0,0 +1,21 @@
+###############################################################################
+# 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
+###############################################################################
+
+ControlFlowRenderProvider_State_WaitUnknown = WAIT_UNKNOWN
+ControlFlowRenderProvider_State_WaitBlocked = WAIT_BLOCKED
+ControlFlowRenderProvider_State_WaitForCpu = WAIT_FOR_CPU
+ControlFlowRenderProvider_State_UserMode = USERMODE
+ControlFlowRenderProvider_State_Syscall = SYSCALL
+ControlFlowRenderProvider_State_Interrupted = INTERRUPTED
+ControlFlowRenderProvider_State_Unknown = UNKNOWN
+
+ControlFlowSortingModes_ByTid = Sort by TID
+ControlFlowSortingModes_ByThreadName = Sort by Thread Name
+
+ControlFlowFilterModes_InactiveEntries = Filter inactive entries
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/package-info.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/package-info.java
new file mode 100644 (file)
index 0000000..8f93066
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2;
index 2826638360a2849afc7aef0feba4eaa4b707cfde..b743add7f0523c48ea59607a4b8ac3191c1d97ac 100644 (file)
@@ -26,4 +26,7 @@ latency.density.view.name = System Call Density
 kernelmemoryusageview.view.name = Kernel Memory Usage View
 diskioactivity.view.name = Disk I/O Activity
 
-perspective.name = OS Tracing Overview
\ No newline at end of file
+perspective.name = OS Tracing Overview
+
+controlflow2.swt.view.name = Control Flow (staging)
+controlflow2.swtjfx.view.name = Control Flow (JFX)
\ No newline at end of file
index 0137f5b79782d854ee03236b93842642766cd4e4..97392c2ec0b01a87a33ff3e93c184bba5de69ffd 100644 (file)
             name="%diskioactivity.view.name"
             restorable="true">
       </view>
+      <view
+            allowMultiple="true"
+            category="org.eclipse.linuxtools.lttng2.ui.views.category"
+            class="org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow2.SwtControlFlowView"
+            icon="icons/eview16/control_flow_view.gif"
+            id="org.eclipse.tracecompass.analysis.os.linux.views.controlflow2.swt"
+            name="%controlflow2.swt.view.name"
+            restorable="true">
+      </view>
+      <view
+            allowMultiple="true"
+            category="org.eclipse.linuxtools.lttng2.ui.views.category"
+            class="org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow2.SwtJfxControlFlowView"
+            id="org.eclipse.tracecompass.analysis.os.linux.views.controlflow2.swtjfx"
+            name="%controlflow2.swtjfx.view.name"
+            restorable="true">
+      </view>
    </extension>
    <extension
          point="org.eclipse.linuxtools.tmf.core.analysis">
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtControlFlowView.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtControlFlowView.java
new file mode 100644 (file)
index 0000000..6054834
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * 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.analysis.os.linux.ui.views.controlflow2;
+
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2.ControlFlowRenderProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swt.SwtTimeGraphView;
+
+public class SwtControlFlowView extends SwtTimeGraphView {
+
+    private static final String VIEW_ID = "org.eclipse.tracecompass.analysis.os.linux.views.controlflow2.swt"; //$NON-NLS-1$
+
+    public SwtControlFlowView() {
+        super(VIEW_ID, new ControlFlowRenderProvider());
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtJfxControlFlowView.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtJfxControlFlowView.java
new file mode 100644 (file)
index 0000000..454d450
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * 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.analysis.os.linux.ui.views.controlflow2;
+
+import org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2.ControlFlowRenderProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.SwtJfxTimeGraphView;
+
+public class SwtJfxControlFlowView extends SwtJfxTimeGraphView {
+
+    private static final String VIEW_ID = "org.eclipse.tracecompass.analysis.os.linux.views.controlflow2.swtjfx"; //$NON-NLS-1$
+
+    public SwtJfxControlFlowView() {
+        super(VIEW_ID, new ControlFlowRenderProvider());
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/package-info.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/package-info.java
new file mode 100644 (file)
index 0000000..3574722
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc. and others
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow2;
index a7722916a2ac54baf80e3bddd7946c4cf00dbf0f..54224be2af06c34a4b9ee2bb27a373d5a5784ba3 100644 (file)
@@ -14,7 +14,14 @@ Require-Bundle: org.eclipse.core.runtime,
  org.eclipse.tracecompass.segmentstore.core,
  org.eclipse.tracecompass.statesystem.core;visibility:=reexport,
  org.eclipse.cdt.core
-Export-Package: org.eclipse.tracecompass.internal.tmf.core;x-friends:="org.eclipse.tracecompass.tmf.core.tests,org.eclipse.tracecompass.tmf.ui.swtbot.tests",
+Export-Package: org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2;
+  x-friends:="org.eclipse.tracecompass.analysis.os.linux.core,
+   org.eclipse.tracecompass.analysis.os.linux.core.tests,
+   org.eclipse.tracecompass.analysis.os.linux.ui,
+   org.eclipse.tracecompass.tmf.ui,
+   org.eclipse.tracecompass.tmf.ui.tests",
+ org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core,org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.analysis.os.linux.core.tests",
+ org.eclipse.tracecompass.internal.tmf.core;x-friends:="org.eclipse.tracecompass.tmf.core.tests,org.eclipse.tracecompass.tmf.ui.swtbot.tests",
  org.eclipse.tracecompass.internal.tmf.core.analysis;x-friends:="org.eclipse.tracecompass.tmf.core.tests",
  org.eclipse.tracecompass.internal.tmf.core.callstack;x-friends:="org.eclipse.tracecompass.tmf.ui,org.eclipse.tracecompass.tmf.core.tests",
  org.eclipse.tracecompass.internal.tmf.core.component;x-friends:="org.eclipse.tracecompass.tmf.core.tests",
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ColorDefinition.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ColorDefinition.java
new file mode 100644 (file)
index 0000000..5e61ab9
--- /dev/null
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import java.util.Objects;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+public class ColorDefinition {
+
+    public static final int MIN = 0;
+    public static final int MAX = 255;
+
+    public final int fRed;
+    public final int fGreen;
+    public final int fBlue;
+    public final int fAlpha;
+
+    public ColorDefinition(int red, int green, int blue) {
+        this(red, green, blue, MAX);
+    }
+
+    public ColorDefinition(int red, int green, int blue, int alpha) {
+        checkValue(red);
+        checkValue(green);
+        checkValue(blue);
+        checkValue(alpha);
+
+        fRed = red;
+        fGreen = green;
+        fBlue = blue;
+        fAlpha = alpha;
+    }
+
+    private static void checkValue(int value) throws IllegalArgumentException {
+        if (value < MIN || value > MAX) {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(fRed, fGreen, fBlue, fAlpha);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ColorDefinition other = (ColorDefinition) obj;
+        if (fAlpha != other.fAlpha ||
+                fBlue != other.fBlue ||
+                fGreen != other.fGreen ||
+                fRed != other.fRed) {
+            return false;
+        }
+        return true;
+    }
+
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ITimeGraphModelRenderProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ITimeGraphModelRenderProvider.java
new file mode 100644 (file)
index 0000000..7a5ec40
--- /dev/null
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+public interface ITimeGraphModelRenderProvider {
+
+    // ------------------------------------------------------------------------
+    // Configuration option classes
+    // ------------------------------------------------------------------------
+
+    class SortingMode {
+
+        private final String fName;
+
+        public SortingMode(String name) {
+            fName = name;
+        }
+
+        public String getName() {
+            return fName;
+        }
+    }
+
+    class FilterMode {
+
+        private final String fName;
+
+        public FilterMode(String name) {
+            fName = name;
+        }
+
+        public String getName() {
+            return fName;
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // Render generation methods
+    // ------------------------------------------------------------------------
+
+    default TimeGraphModelRender getRender(ITmfTrace trace,
+            long rangeStart, long rangeEnd, long resolution) {
+        return getRender(trace, rangeStart, rangeEnd, resolution, null);
+    }
+
+    TimeGraphModelRender getRender(ITmfTrace trace, long rangeStart, long rangeEnd,
+            long resolution, @Nullable IProgressMonitor monitor);
+
+    // ------------------------------------------------------------------------
+    // Sorting modes
+    // ------------------------------------------------------------------------
+
+    List<SortingMode> getSortingModes();
+
+    SortingMode getCurrentSortingMode();
+
+    void setCurrentSortingMode(int index);
+
+    // ------------------------------------------------------------------------
+    // Filter modes
+    // ------------------------------------------------------------------------
+
+    List<FilterMode> getFilterModes();
+
+    void enableFilterMode(int index);
+
+    void disableFilterMode(int index);
+
+    Set<FilterMode> getActiveFilterModes();
+
+    // ------------------------------------------------------------------------
+    // Other configuration options
+    // ------------------------------------------------------------------------
+
+    /**
+     * Set the time range configuration option. The timestamps should normally
+     * refer to a valid time range within the backing trace or other database.
+     * For GUI views it will usually refer to the visible time range of a
+     * zoomed-in viewport.
+     *
+     * This can then be used by other configuration options. For example, a
+     * filtering mode could be provided to filter out entries that do not change
+     * state within the configured time range.
+     *
+     * The implementation is free to ignore the configured time range if it does
+     * not provide anything special for it.
+     *
+     * @param startTime
+     *            The start of the configured time range
+     * @param endTime
+     *            The end of the configured time range.
+     */
+    void setConfiguredTimeRange(long startTime, long endTime);
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/Messages.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/Messages.java
new file mode 100644 (file)
index 0000000..130fbb8
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Package message bundle
+ *
+ * @noreference Messages class
+ */
+@NonNullByDefault({})
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+
+    private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
+
+    public static String DefaultSortingModeName;
+
+    static {
+        NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+    }
+
+    private Messages() {}
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrow.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrow.java
new file mode 100644 (file)
index 0000000..f1c4b21
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+public class TimeGraphArrow {
+
+    private final TimeGraphEvent fStartEvent;
+    private final TimeGraphEvent fEndEvent;
+
+    public TimeGraphArrow(TimeGraphEvent startEvent, TimeGraphEvent endEvent) {
+        fStartEvent = startEvent;
+        fEndEvent = endEvent;
+    }
+
+    public TimeGraphEvent getStartEvent() {
+        return fStartEvent;
+    }
+
+    public TimeGraphEvent getEndEvent() {
+        return fEndEvent;
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrowSeries.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrowSeries.java
new file mode 100644 (file)
index 0000000..398c5f7
--- /dev/null
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import java.util.Collection;
+
+import com.google.common.collect.ImmutableList;
+
+public class TimeGraphArrowSeries {
+
+    public enum LineStyle {
+        FULL,
+        DOTTED,
+        DASHED;
+    }
+
+    private final String fSeriesName;
+    private final ColorDefinition fColor;
+    private final LineStyle fLineStyle;
+    private final Collection<TimeGraphArrow> fArrows;
+
+    public TimeGraphArrowSeries(String seriesName, ColorDefinition color,
+            LineStyle lineStyle, Collection<TimeGraphArrow> arrows) {
+        fSeriesName = seriesName;
+        fColor = color;
+        fLineStyle = lineStyle;
+        fArrows = ImmutableList.copyOf(arrows);
+    }
+
+    public String getSeriesName() {
+        return fSeriesName;
+    }
+
+    public ColorDefinition getColor() {
+        return fColor;
+    }
+
+    public LineStyle getLineStyle() {
+        return fLineStyle;
+    }
+
+    public Collection<TimeGraphArrow> getArrows() {
+        return fArrows;
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphDrawnEvent.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphDrawnEvent.java
new file mode 100644 (file)
index 0000000..7a9f6f0
--- /dev/null
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+public class TimeGraphDrawnEvent {
+
+    public enum SymbolStyle {
+        CIRCLE,
+        CROSS,
+        STAR;
+    }
+
+    private final TimeGraphEvent fTimeGraphEvent;
+    private final String fEventName;
+    private final ColorDefinition fColor;
+    private final SymbolStyle fSymbolStyle;
+    private final @Nullable Supplier<Map<String, String>> fPropertySupplier;
+
+    public TimeGraphDrawnEvent(TimeGraphEvent event, String eventName,
+            ColorDefinition color, SymbolStyle style,
+            @Nullable Supplier<Map<String, String>> propertySupplier) {
+        fTimeGraphEvent = event;
+        fEventName = eventName;
+        fColor = color;
+        fSymbolStyle = style;
+        fPropertySupplier = propertySupplier;
+    }
+
+    public TimeGraphEvent getEvent() {
+        return fTimeGraphEvent;
+    }
+
+    public String getEventName() {
+        return fEventName;
+    }
+
+    public ColorDefinition getColor() {
+        return fColor;
+    }
+
+    public SymbolStyle getSymbolStyle() {
+        return fSymbolStyle;
+    }
+
+    public Map<String, String> getProperties() {
+        Supplier<Map<String, String>> supplier = fPropertySupplier;
+        if (supplier == null) {
+            return Collections.EMPTY_MAP;
+        }
+        return supplier.get();
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphEvent.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphEvent.java
new file mode 100644 (file)
index 0000000..0ff6e6d
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+public class TimeGraphEvent {
+
+    private final long fTimestamp;
+    private final TimeGraphTreeElement fTreeElement;
+
+    public TimeGraphEvent(long timestamp, TimeGraphTreeElement treeElement) {
+        fTimestamp = timestamp;
+        fTreeElement = treeElement;
+    }
+
+    public long getTimestamp() {
+        return fTimestamp;
+    }
+
+    public TimeGraphTreeElement getTreeElement() {
+        return fTreeElement;
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRender.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRender.java
new file mode 100644 (file)
index 0000000..444cbb0
--- /dev/null
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import com.google.common.collect.ImmutableList;
+
+public class TimeGraphModelRender {
+
+    public static final TimeGraphModelRender EMPTY_RENDER =
+            new TimeGraphModelRender(0, 0,
+                    new TimeGraphTreeRender(Collections.EMPTY_LIST),
+                    Collections.EMPTY_LIST,
+                    Collections.EMPTY_LIST,
+                    Collections.EMPTY_LIST);
+
+    private final long fStartTime;
+    private final long fEndTime;
+    private final TimeGraphTreeRender fTreeRender;
+    private final List<List<TimeGraphStateInterval>> fStateIntervals;
+    private final List<List<TimeGraphDrawnEvent>> fDrawnEvents;
+    private final Collection<TimeGraphArrowSeries> fArrowSeries;
+
+    public TimeGraphModelRender(long startTime, long endTime,
+            TimeGraphTreeRender treeRender,
+            List<List<TimeGraphStateInterval>> stateIntervals,
+            List<List<TimeGraphDrawnEvent>> drawnEvents,
+            Collection<TimeGraphArrowSeries> arrowSeries) {
+        fStartTime = startTime;
+        fEndTime = endTime;
+        fTreeRender = treeRender;
+        fStateIntervals = ImmutableList.copyOf(stateIntervals);
+        fDrawnEvents = ImmutableList.copyOf(drawnEvents);
+        fArrowSeries = ImmutableList.copyOf(arrowSeries);
+    }
+
+    public long getStartTime() {
+        return fStartTime;
+    }
+
+    public long getEndTime() {
+        return fEndTime;
+    }
+
+    public TimeGraphTreeRender getTreeRender() {
+        return fTreeRender;
+    }
+
+    public List<List<TimeGraphStateInterval>> getStateIntervals() {
+        return fStateIntervals;
+    }
+
+    public List<List<TimeGraphDrawnEvent>> getDrawnEvents() {
+        return fDrawnEvents;
+    }
+
+    public Collection<TimeGraphArrowSeries> getArrowsSeries() {
+        return fArrowSeries;
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRenderProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRenderProvider.java
new file mode 100644 (file)
index 0000000..2181506
--- /dev/null
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+public abstract class TimeGraphModelRenderProvider implements ITimeGraphModelRenderProvider {
+
+    protected static final SortingMode DEFAULT_SORTING_MODE = new SortingMode(nullToEmptyString(Messages.DefaultSortingModeName));
+
+    private final List<SortingMode> fSortingModes;
+    private final List<FilterMode> fFilterModes;
+
+    private SortingMode fCurrentSortingMode;
+    private Set<FilterMode> fActiveFilterModes = new HashSet<>();
+
+    private long fConfiguredTimeRangeStart = 0L;
+    private long fConfiguredTimeRangeEnd = Long.MAX_VALUE;
+
+    protected TimeGraphModelRenderProvider(@Nullable List<SortingMode> sortingModes,
+            @Nullable List<FilterMode> filterModes) {
+        if (sortingModes == null || sortingModes.isEmpty()) {
+            fSortingModes = ImmutableList.of(DEFAULT_SORTING_MODE);
+        } else {
+            fSortingModes = ImmutableList.copyOf(sortingModes);
+
+        }
+        fCurrentSortingMode = fSortingModes.get(0);
+
+        if (filterModes == null || filterModes.isEmpty()) {
+            fFilterModes = ImmutableList.of();
+        } else {
+            fFilterModes = ImmutableList.copyOf(filterModes);
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // Sorting modes
+    // ------------------------------------------------------------------------
+
+    @Override
+    public List<SortingMode> getSortingModes() {
+        return fSortingModes;
+    }
+
+    @Override
+    public SortingMode getCurrentSortingMode() {
+        return fCurrentSortingMode;
+    }
+
+    @Override
+    public void setCurrentSortingMode(int index) {
+        fCurrentSortingMode = fSortingModes.get(index);
+    }
+
+    // ------------------------------------------------------------------------
+    // Filter modes
+    // ------------------------------------------------------------------------
+
+    @Override
+    public List<FilterMode> getFilterModes() {
+        return fFilterModes;
+    }
+
+    @Override
+    public void enableFilterMode(int index) {
+        fActiveFilterModes.add(fFilterModes.get(index));
+    }
+
+    @Override
+    public void disableFilterMode(int index) {
+        fActiveFilterModes.remove(fFilterModes.get(index));
+    }
+
+    @Override
+    public Set<FilterMode> getActiveFilterModes() {
+        return ImmutableSet.copyOf(fActiveFilterModes);
+    }
+
+    // ------------------------------------------------------------------------
+    // Other configuration options
+    // ------------------------------------------------------------------------
+
+    public long getConfiguredTimeRangeStart() {
+        return fConfiguredTimeRangeStart;
+    }
+
+    public long getConfiguredTimeRangeEnd() {
+        return fConfiguredTimeRangeEnd;
+    }
+
+    @Override
+    public void setConfiguredTimeRange(long start, long end) {
+        if (start < 0 || start > end) {
+            throw new IllegalArgumentException();
+        }
+        fConfiguredTimeRangeStart = start;
+        fConfiguredTimeRangeEnd = end;
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphStateInterval.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphStateInterval.java
new file mode 100644 (file)
index 0000000..5539485
--- /dev/null
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import com.google.common.base.Objects;
+
+public class TimeGraphStateInterval {
+
+    public enum LineThickness {
+        NORMAL,
+        SMALL
+    }
+
+    private final TimeGraphEvent fStartEvent;
+    private final TimeGraphEvent fEndEvent;
+
+    private final String fStateName;
+    private final ColorDefinition fColor;
+    private final LineThickness fLineThickness;
+
+    private final @Nullable Supplier<Map<String, String>> fPropertySupplier;
+
+    public TimeGraphStateInterval(long start,
+            long end,
+            TimeGraphTreeElement treeElement,
+            String stateName,
+            ColorDefinition color,
+            LineThickness lineThickness,
+            @Nullable Supplier<Map<String, String>> propertySupplier) {
+
+        fStartEvent = new TimeGraphEvent(start, treeElement);
+        fEndEvent = new TimeGraphEvent(end, treeElement);
+
+        fStateName = stateName;
+        fColor = color;
+        fLineThickness = lineThickness;
+        fPropertySupplier = propertySupplier;
+
+    }
+
+    public TimeGraphEvent getStartEvent() {
+        return fStartEvent;
+    }
+
+    public TimeGraphEvent getEndEvent() {
+        return fEndEvent;
+    }
+
+    public String getStateName() {
+        return fStateName;
+    }
+
+    public ColorDefinition getColorDefinition() {
+        return fColor;
+    }
+
+    public LineThickness getLineThickness() {
+        return fLineThickness;
+    }
+
+    public Map<String, String> getProperties() {
+        Supplier<Map<String, String>> supplier = fPropertySupplier;
+        if (supplier == null) {
+            return Collections.EMPTY_MAP;
+        }
+        return supplier.get();
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(this)
+                .add("start", fStartEvent.getTimestamp())
+                .add("end", fEndEvent.getTimestamp())
+                .add("name", fStateName)
+                .toString();
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeElement.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeElement.java
new file mode 100644 (file)
index 0000000..4843fd2
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import java.util.List;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+
+public class TimeGraphTreeElement {
+
+    private final String fName;
+    private final List<TimeGraphTreeElement> fChildElements;
+
+    public TimeGraphTreeElement(String name, List<TimeGraphTreeElement> children) {
+        fName = name;
+        fChildElements = ImmutableList.copyOf(children);
+    }
+
+    public String getName() {
+        return fName;
+    }
+
+    public List<TimeGraphTreeElement> getChildElements() {
+        return fChildElements;
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(this)
+            .add("fName", fName) //$NON-NLS-1$
+            .add("fChildElements", fChildElements.toString()) //$NON-NLS-1$
+            .toString();
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeModel.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeModel.java
new file mode 100644 (file)
index 0000000..5502667
--- /dev/null
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.google.common.collect.ImmutableList;
+
+public class TimeGraphTreeModel {
+
+    private final List<TimeGraphTreeElement> fTreeElements = Collections.synchronizedList(new ArrayList<>());
+
+    public TimeGraphTreeModel() {
+    }
+
+    public int getNbElements() {
+        return fTreeElements.size();
+    }
+
+    public void addElement(TimeGraphTreeElement element) {
+        fTreeElements.add(element);
+    }
+
+    public TimeGraphTreeRender getSnapshot() {
+        /* Safe to use concurrently */
+        List<TimeGraphTreeElement> list = ImmutableList.copyOf(fTreeElements);
+        return new TimeGraphTreeRender(list);
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeRender.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeRender.java
new file mode 100644 (file)
index 0000000..ad2ce5d
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2;
+
+import java.util.List;
+
+import com.google.common.collect.ImmutableList;
+
+public class TimeGraphTreeRender {
+
+    private final List<TimeGraphTreeElement> fTreeElements;
+
+    public TimeGraphTreeRender(List<TimeGraphTreeElement> elements) {
+        fTreeElements = ImmutableList.copyOf(elements);
+    }
+
+    public List<TimeGraphTreeElement> getAllTreeElements() {
+        return fTreeElements;
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/messages.properties b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/messages.properties
new file mode 100644 (file)
index 0000000..96fad2f
--- /dev/null
@@ -0,0 +1,10 @@
+###############################################################################
+# 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
+###############################################################################
+
+DefaultSortingModeName = Default
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/package-info.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/package-info.java
new file mode 100644 (file)
index 0000000..aaf6b5e
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc. and others
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2;
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemModelRenderProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemModelRenderProvider.java
new file mode 100644 (file)
index 0000000..60ecb2f
--- /dev/null
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2.statesystem;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRender;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRenderProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval.LineThickness;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+public abstract class StateSystemModelRenderProvider extends TimeGraphModelRenderProvider {
+
+    /**
+     * The context of a tree render. Should contain all the information to
+     * generate the corresponding tree render, according to all configuration
+     * options like sorting, filtering etc. specified by the user.
+     */
+    protected static final class TreeRenderContext {
+
+        public final ITmfStateSystem ss;
+        public final SortingMode sortingMode;
+        public final Set<FilterMode> filterModes;
+        public final long renderTimeRangeStart;
+        public final long renderTimeRangeEnd;
+        public final List<ITmfStateInterval> fullQueryAtRangeStart;
+
+        public TreeRenderContext(ITmfStateSystem ss,
+                SortingMode sortingMode,
+                Set<FilterMode> filterModes,
+                long renderTimeRangeStart,
+                long renderTimeRangeEnd,
+                List<ITmfStateInterval> fullQueryAtRangeStart) {
+            this.ss = ss;
+            this.sortingMode = sortingMode;
+            this.filterModes = filterModes;
+            this.renderTimeRangeStart = renderTimeRangeStart;
+            this.renderTimeRangeEnd = renderTimeRangeEnd;
+            this.fullQueryAtRangeStart = fullQueryAtRangeStart;
+        }
+    }
+
+    /**
+     * The context of a single state interval. Should contain all the
+     * information required to generate the state interval in the render (name,
+     * color, etc.)
+     */
+    protected static final class StateIntervalContext {
+
+        public final ITmfStateSystem ss;
+        public final StateSystemTimeGraphTreeElement baseTreeElement;
+        public final ITmfStateInterval sourceInterval;
+        public final List<ITmfStateInterval> fullQueryAtIntervalStart;
+
+        public StateIntervalContext(ITmfStateSystem ss,
+                StateSystemTimeGraphTreeElement baseTreeElement,
+                ITmfStateInterval sourceInterval,
+                List<ITmfStateInterval> fullQueryAtIntervalStart) {
+            this.ss = ss;
+            this.baseTreeElement = baseTreeElement;
+            this.sourceInterval = sourceInterval;
+            this.fullQueryAtIntervalStart = fullQueryAtIntervalStart;
+        }
+    }
+
+    private final String fStateSystemModuleId;
+    private final Function<TreeRenderContext, TimeGraphTreeRender> fTreeRenderFunction;
+    private final Function<StateIntervalContext, TimeGraphStateInterval> fIntervalMappingFunction;
+
+//    private final Map<ITmfStateSystem, TimeGraphTreeRender> fLastTreeRenders = new WeakHashMap<>();
+
+    /**
+     * @param stateSystemModuleId
+     * @param stateNameMappingFunction
+     * @param colorMappingFunction
+     * @param lineThicknessMappingFunction
+     * @param propertyMappingFunction
+     * @param baseQuarkPattern
+     */
+    protected StateSystemModelRenderProvider(
+            @Nullable List<SortingMode> sortingModes,
+            @Nullable List<FilterMode> filterModes,
+            String stateSystemModuleId,
+            Function<TreeRenderContext, TimeGraphTreeRender> treeRenderFunction,
+            Function<StateIntervalContext, String> stateNameMappingFunction,
+            Function<StateIntervalContext, ColorDefinition> colorMappingFunction,
+            Function<StateIntervalContext, LineThickness> lineThicknessMappingFunction,
+            Function<StateIntervalContext, @Nullable Supplier<Map<String, String>>> propertyMappingFunction) {
+
+        super(sortingModes, filterModes);
+
+        fStateSystemModuleId = stateSystemModuleId;
+        fTreeRenderFunction = treeRenderFunction;
+
+        fIntervalMappingFunction = ssCtx -> {
+            return new TimeGraphStateInterval(
+                    ssCtx.sourceInterval.getStartTime(),
+                    ssCtx.sourceInterval.getEndTime(),
+                    ssCtx.baseTreeElement,
+                    stateNameMappingFunction.apply(ssCtx),
+                    colorMappingFunction.apply(ssCtx),
+                    lineThicknessMappingFunction.apply(ssCtx),
+                    propertyMappingFunction.apply(ssCtx));
+        };
+    }
+
+    private synchronized TimeGraphTreeRender getTreeRender(final ITmfStateSystem ss) {
+        TimeGraphTreeRender lastRender = null;
+//        TimeGraphTreeRender lastRender = fLastTreeRenders.get(ss);
+//        if (lastRender != null && lastRender.getAllTreeElements().size() == ss.getNbAttributes()) {
+//            /* The last render is still valid, we can re-use it */
+//            return lastRender;
+//        }
+
+        /* First generate the tree render context */
+        long start = getConfiguredTimeRangeStart();
+        long end = getConfiguredTimeRangeEnd();
+        List<ITmfStateInterval> fullStateAtStart;
+        try {
+            fullStateAtStart = ss.queryFullState(start);
+        } catch (StateSystemDisposedException e) {
+            return new TimeGraphTreeRender(Collections.EMPTY_LIST);
+        }
+
+        TreeRenderContext treeContext = new TreeRenderContext(ss,
+                getCurrentSortingMode(),
+                getActiveFilterModes(),
+                start,
+                end,
+                fullStateAtStart);
+
+        /* Generate a new tree render */
+        lastRender = fTreeRenderFunction.apply(treeContext);
+
+//        fLastTreeRenders.put(ss, lastRender);
+        return lastRender;
+    }
+
+    @Override
+    public @NonNull TimeGraphModelRender getRender(ITmfTrace trace, long rangeStart, long rangeEnd,
+            long resolution, @Nullable IProgressMonitor monitor) {
+        // FIXME Potentially costly to query this every time, cache it?
+        final ITmfStateSystem ss = TmfStateSystemAnalysisModule.getStateSystem(trace, fStateSystemModuleId);
+        if (ss == null) {
+            /* This trace does not provide the expected state system */
+            return TimeGraphModelRender.EMPTY_RENDER;
+        }
+        TimeGraphTreeRender treeRender = getTreeRender(ss);
+
+        /* Prepare the state intervals */
+        /*
+         * FIXME Inefficient series of queryHistoryRange() calls, replace with a
+         * 2D query once those become available.
+         */
+        List<List<TimeGraphStateInterval>> stateIntervals = treeRender.getAllTreeElements().stream()
+            .map(treeElem -> (StateSystemTimeGraphTreeElement) treeElem) // FIXME, generic type?
+            .map(treeElem -> {
+                List<ITmfStateInterval> intervals;
+                try {
+                    intervals = StateSystemUtils.queryHistoryRange(ss, treeElem.getSourceQuark(), rangeStart, rangeEnd, resolution, monitor);
+                } catch (AttributeNotFoundException | StateSystemDisposedException e) {
+                    intervals = Collections.emptyList();
+                }
+                return intervals.stream()
+                    .map(interval -> {
+                        List<ITmfStateInterval> fullState;
+                        try {
+                            fullState = ss.queryFullState(interval.getStartTime());
+                        } catch (StateSystemDisposedException e) {
+                            fullState = Collections.emptyList();
+                        }
+                        return new StateIntervalContext(ss, treeElem, interval, fullState);
+                    })
+                    .map(fIntervalMappingFunction)
+                    .collect(Collectors.toList());
+            })
+            .collect(Collectors.toList());
+
+        /* TODO Prepare the drawn events */
+
+        /* TODO Prepare the arrows series */
+
+        TimeGraphModelRender render = new TimeGraphModelRender(
+                rangeStart, rangeEnd,
+                treeRender,
+                stateIntervals,
+                Collections.EMPTY_LIST,
+                Collections.EMPTY_LIST);
+        return render;
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemTimeGraphTreeElement.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemTimeGraphTreeElement.java
new file mode 100644 (file)
index 0000000..239d06b
--- /dev/null
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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.core.views.timegraph2.statesystem;
+
+import java.util.List;
+
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement;
+
+public class StateSystemTimeGraphTreeElement extends TimeGraphTreeElement {
+
+    private final int fSourceQuark;
+
+    public StateSystemTimeGraphTreeElement(String name,
+            List<TimeGraphTreeElement> children,
+            int sourceQuark) {
+        super(name, children);
+        fSourceQuark = sourceQuark;
+    }
+
+    public int getSourceQuark() {
+        return fSourceQuark;
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/package-info.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/package-info.java
new file mode 100644 (file)
index 0000000..6d3472b
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc. and others
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem;
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStaticTest.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStaticTest.java
new file mode 100644 (file)
index 0000000..db1bc21
--- /dev/null
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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.tmf.ui.tests.views.timegraph2.swtjfx;
+
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.SwtJfxTimeGraphViewer;
+import org.junit.Test;
+
+public class SwtJfxTimeGraphViewerStaticTest {
+
+    private static final double DELTA = 0.1;
+
+    /**
+     * Test area consisting of 100 pixels representing a timerange from 1000 to
+     * 2000.
+     */
+    private static class TestArea1 {
+        private static final long START_TIMESTAMP = 1000;
+        private static final long END_TIMESTAMP = 2000;
+        private static final double NANOS_PER_PIXEL = 10.0;
+    }
+
+    @Test
+    public void testTimeToPosition() {
+        double yPos = SwtJfxTimeGraphViewer.timestampToPaneXPos(1500,
+                TestArea1.START_TIMESTAMP,
+                TestArea1.END_TIMESTAMP,
+                TestArea1.NANOS_PER_PIXEL);
+        assertEquals(50.0, yPos, DELTA);
+
+        long start = 1332170682440133097L;
+        long end   = 1332170692664579801L;
+        long ts1   = 1332170683481793497L;
+        long ts2   = 1332170683485732407L;
+        double yPos1 = SwtJfxTimeGraphViewer.timestampToPaneXPos(ts1, start, end, 10.0);
+        double yPos2 = SwtJfxTimeGraphViewer.timestampToPaneXPos(ts2, start, end, 10.0);
+        assertEquals(104166039.959, yPos1, DELTA);
+        assertEquals(104559930.959, yPos2, DELTA);
+
+    }
+
+    @Test
+    public void testPositionToTimestamp() {
+        long ts = SwtJfxTimeGraphViewer.paneXPosToTimestamp(50.0,
+                TestArea1.START_TIMESTAMP * TestArea1.NANOS_PER_PIXEL,
+                TestArea1.START_TIMESTAMP,
+                TestArea1.NANOS_PER_PIXEL);
+        assertEquals(1500, ts);
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerTest.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerTest.java
new file mode 100644 (file)
index 0000000..2a751e1
--- /dev/null
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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.tmf.ui.tests.views.timegraph2.swtjfx;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+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.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SwtJfxTimeGraphViewerTest {
+
+//    private static final double DELTA = 0.1;
+
+    private static final long FULL_TRACE_START_TIME = 100000L;
+    private static final long FULL_TRACE_END_TIME = 200000L;
+
+    private @Nullable SwtJfxTimeGraphViewerStub fViewer;
+
+    @Before
+    public void setup() {
+        Shell shell = checkNotNull(Display.getDefault().getActiveShell());
+        SwtJfxTimeGraphViewerStub viewer = new SwtJfxTimeGraphViewerStub(shell, new ModelRenderProviderStub());
+        viewer.setTimeGraphAreaRange(FULL_TRACE_START_TIME, FULL_TRACE_END_TIME);
+
+        viewer.getTimeGraphScrollPane().setMinWidth(1000.0);
+        fViewer = viewer;
+    }
+
+    @After
+    public void tearDown() {
+        if (fViewer != null) {
+            fViewer.dispose();
+        }
+        fViewer = null;
+    }
+
+    @Test
+    public void testSeekVisibleRange() {
+        SwtJfxTimeGraphViewerStub viewer = checkNotNull(fViewer);
+
+        TmfTimeRange range = createTimeRange(150000L, 160000L);
+        TmfSignal signal = new TmfWindowRangeUpdatedSignal(this, range);
+        TmfSignalManager.dispatchSignal(signal);
+
+        double visibleWidth = viewer.getTimeGraphScrollPane().getWidth();
+        System.out.println("width=" + visibleWidth);
+    }
+
+    @Test
+    public void testZoomOut() {
+
+    }
+
+    private static TmfTimeRange createTimeRange(long start, long end) {
+        return new TmfTimeRange(TmfTimestamp.fromNanos(start), TmfTimestamp.fromNanos(end));
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/ModelRenderProviderStub.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/ModelRenderProviderStub.java
new file mode 100644 (file)
index 0000000..878b7a7
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.tmf.ui.tests.views.timegraph2.swtjfx;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRender;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRenderProvider;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+public class ModelRenderProviderStub extends TimeGraphModelRenderProvider {
+
+    protected ModelRenderProviderStub() {
+        super(null, null);
+    }
+
+    @Override
+    public @NonNull TimeGraphModelRender getRender(@NonNull ITmfTrace trace, long rangeStart, long rangeEnd, long resolution, @Nullable IProgressMonitor monitor) {
+        return TimeGraphModelRender.EMPTY_RENDER;
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStub.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStub.java
new file mode 100644 (file)
index 0000000..820fa9e
--- /dev/null
@@ -0,0 +1,34 @@
+package org.eclipse.tracecompass.tmf.ui.tests.views.timegraph2.swtjfx;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.SwtJfxTimeGraphViewer;
+
+import javafx.scene.control.ScrollPane;
+import javafx.scene.layout.Pane;
+
+public class SwtJfxTimeGraphViewerStub extends SwtJfxTimeGraphViewer {
+
+    public SwtJfxTimeGraphViewerStub(Composite parent, ITimeGraphModelRenderProvider provider) {
+        super(parent, provider);
+    }
+
+    // ------------------------------------------------------------------------
+    // Visibility-increasing overrides
+    // ------------------------------------------------------------------------
+
+    @Override
+    public void setTimeGraphAreaRange(long fullAreaStartTime, long fullAreaEndTime) {
+        super.setTimeGraphAreaRange(fullAreaStartTime, fullAreaEndTime);
+    }
+
+    @Override
+    protected Pane getTimeGraphPane() {
+        return super.getTimeGraphPane();
+    }
+
+    @Override
+    protected ScrollPane getTimeGraphScrollPane() {
+        return super.getTimeGraphScrollPane();
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/package-info.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/package-info.java
new file mode 100644 (file)
index 0000000..ac75f7b
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc. and others
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.tmf.ui.tests.views.timegraph2.swtjfx;
index 6dfaeac829cfa0bda42a06adf1bc5fbf884a820f..0ba62fee6e8853487ac71577780d72311499b774 100644 (file)
@@ -26,7 +26,10 @@ Require-Bundle: org.eclipse.core.expressions,
  org.eclipse.linuxtools.dataviewers.piechart,
  org.eclipse.tracecompass.segmentstore.core,
  org.apache.commons.compress
-Export-Package: org.eclipse.tracecompass.internal.tmf.ui;x-friends:="org.eclipse.tracecompass.tmf.ui.tests,org.eclipse.tracecompass.tmf.ctf.ui.tests",
+Export-Package: org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2;x-friends:="org.eclipse.tracecompass.tmf.ui.tests",
+ org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swt;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui",
+ org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.tmf.ui.tests",
+ org.eclipse.tracecompass.internal.tmf.ui;x-friends:="org.eclipse.tracecompass.tmf.ui.tests,org.eclipse.tracecompass.tmf.ctf.ui.tests",
  org.eclipse.tracecompass.internal.tmf.ui.commands;x-internal:=true,
  org.eclipse.tracecompass.internal.tmf.ui.dialogs;x-internal:=true,
  org.eclipse.tracecompass.internal.tmf.ui.editors;x-internal:=true,
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/SignallingContext.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/SignallingContext.java
new file mode 100644 (file)
index 0000000..3c810d2
--- /dev/null
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * 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);
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelView.java
new file mode 100644 (file)
index 0000000..e4c4871
--- /dev/null
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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 org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+
+public abstract class TimeGraphModelView extends TmfView {
+
+    private final ITimeGraphModelRenderProvider fTimeGraphProvider;
+
+    protected TimeGraphModelView(String viewName, ITimeGraphModelRenderProvider provider) {
+        super(viewName);
+        fTimeGraphProvider = provider;
+    }
+
+    protected ITimeGraphModelRenderProvider getRenderProvider() {
+        return fTimeGraphProvider;
+    }
+
+    @Override
+    public void setFocus() {
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelViewer.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelViewer.java
new file mode 100644 (file)
index 0000000..1a11860
--- /dev/null
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * 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 org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+public abstract class TimeGraphModelViewer {
+
+    private static final long UNINITIALIZED = -1;
+
+    private final ITimeGraphModelRenderProvider fModelRenderProvider;
+    private final SignallingContext fSignallingContext;
+
+    private long fFullTimeGraphStartTime = 1;
+    private long fFullTimeGraphEndTime = 1;
+
+    private long fLatestVisibleRangeStartTime = UNINITIALIZED;
+    private long fLatestVisibleRangeEndTime = UNINITIALIZED;
+
+    protected TimeGraphModelViewer(ITimeGraphModelRenderProvider modelRenderProvider) {
+        fModelRenderProvider = modelRenderProvider;
+        fSignallingContext = new SignallingContext(this);
+    }
+
+    public void dispose() {
+        fSignallingContext.dispose();
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    public ITimeGraphModelRenderProvider getModelRenderProvider() {
+        return fModelRenderProvider;
+    }
+
+    protected SignallingContext getSignalingContext() {
+        return fSignallingContext;
+    }
+
+    protected long getFullTimeGraphStartTime() {
+        return fFullTimeGraphStartTime;
+    }
+
+    protected long getFullTimeGraphEndTime() {
+        return fFullTimeGraphEndTime;
+    }
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    public final void repaintCurrentArea() {
+        ITmfTrace trace = fSignallingContext.getCurrentTrace();
+        long start = fLatestVisibleRangeStartTime;
+        long end = fLatestVisibleRangeEndTime;
+        if (trace == null || start == UNINITIALIZED || end == UNINITIALIZED) {
+            return;
+        }
+        paintArea(trace, fLatestVisibleRangeStartTime, fLatestVisibleRangeEndTime);
+    }
+
+    public final void seekVisibleRange(long visibleWindowStartTime, long visibleWindowEndTime) {
+        checkWindowTimeRange(visibleWindowStartTime, visibleWindowEndTime);
+
+        seekVisibleRangeImpl(visibleWindowStartTime, visibleWindowEndTime);
+        updateLatestVisibleRange(visibleWindowStartTime, visibleWindowEndTime);
+    }
+
+    protected final void paintArea(ITmfTrace trace, long windowStartTime, long windowEndTime) {
+        checkWindowTimeRange(windowStartTime, windowEndTime);
+
+        paintAreaImpl(trace, windowStartTime, windowEndTime);
+    }
+
+    protected final void drawSelection(long selectionStartTime, long selectionEndTime) {
+        checkWindowTimeRange(selectionStartTime, selectionEndTime);
+
+        drawSelectionImpl(selectionStartTime, selectionEndTime);
+    }
+
+    void updateLatestVisibleRange(long visibleWindowStartTime, long visibleWindowEndTime) {
+        fLatestVisibleRangeStartTime = visibleWindowStartTime;
+        fLatestVisibleRangeEndTime = visibleWindowEndTime;
+    }
+
+    /**
+     * Recompute the total virtual size of the time graph area, and assigns the
+     * given timestamps as the start and end positions.
+     *
+     * All subsquent operations (seek, paint, etc.) that use timestamp expect
+     * these timestamps to be within the range passed here!
+     *
+     * Should be called when the trace changes, or the trace's total time range
+     * is updated (while indexing, or in live cases).
+     */
+    protected void setTimeGraphAreaRange(long fullAreaStartTime, long fullAreaEndTime) {
+        checkTimeRange(fullAreaStartTime, fullAreaEndTime);
+
+        if (fFullTimeGraphStartTime == fullAreaStartTime &&
+                fFullTimeGraphEndTime == fullAreaEndTime) {
+            /* No need to update */
+            return;
+        }
+
+        fFullTimeGraphStartTime = fullAreaStartTime;
+        fFullTimeGraphEndTime = fullAreaEndTime;
+    }
+
+    // ------------------------------------------------------------------------
+    // Template methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * This should be called whenever the visible window moves, including zoom
+     * level changes.
+     */
+    protected abstract void seekVisibleRangeImpl(long visibleWindowStartTime, long visibleWindowEndTime);
+
+    /**
+     * Paint an area of the viewer. This will also update the tree pane
+     * accordingly.
+     *
+     * It is encouraged to actually paint a bit more of the area on both sides,
+     * so that small scrolling and resizing operations do not require fetching
+     * new data to display the area.
+     */
+    protected abstract void paintAreaImpl(ITmfTrace trace, long windowStartTime, long windowEndTime);
+
+    /**
+     * Draw a new selection rectangle. The previous one, if any, will be
+     * removed.
+     */
+    protected abstract void drawSelectionImpl(long selectionStartTime, long selectionEndTime);
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    private static void checkTimeRange(long rangeStart, long rangeEnd) {
+        if (rangeStart > rangeEnd) {
+            throw new IllegalArgumentException("Time range start " + rangeStart + "is after its end time " + rangeEnd); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (rangeStart < 0 || rangeEnd < 0) {
+            throw new IllegalArgumentException("One of the time range bounds is negative"); //$NON-NLS-1$
+        }
+        if (rangeStart == Long.MAX_VALUE) {
+            throw new IllegalArgumentException("You are trying to make me believe the range starts at " + //$NON-NLS-1$
+                    rangeStart + ". I do not believe you."); //$NON-NLS-1$
+        }
+        if (rangeEnd == Long.MAX_VALUE) {
+            throw new IllegalArgumentException("You are trying to make me believe the range ends at " + //$NON-NLS-1$
+                    rangeEnd + ". I do not believe you."); //$NON-NLS-1$
+        }
+    }
+
+    private void checkWindowTimeRange(long windowStartTime, long windowEndTime) {
+        checkTimeRange(windowStartTime, windowEndTime);
+
+        if (windowStartTime < fFullTimeGraphStartTime) {
+            throw new IllegalArgumentException("Requested window start time: " + windowStartTime +
+                    " is smaller than trace start time " + fFullTimeGraphStartTime);
+        }
+        if (windowEndTime > fFullTimeGraphEndTime) {
+            throw new IllegalArgumentException("Requested window end time: " + windowEndTime +
+                    " is greater than trace end time " + fFullTimeGraphEndTime);
+        }
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/package-info.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/package-info.java
new file mode 100644 (file)
index 0000000..a13a8bd
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc. and others
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2;
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtColorFactory.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtColorFactory.java
new file mode 100644 (file)
index 0000000..1db44db
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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.swt;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition;
+
+final class SwtColorFactory {
+
+    private SwtColorFactory() {}
+
+    private static final Map<ColorDefinition, Color> COLOR_MAP = new HashMap<>();
+
+    /**
+     * Instantiate a {@link Color} from a {@link ColorDefinition} object.
+     *
+     * Must be called by the UI thread only, so it should not need any special
+     * synchronization.
+     *
+     * @param colorDef
+     *            The ColorDefinition
+     * @return The Color object
+     */
+    public static Color getColorFromDef(ColorDefinition colorDef) {
+        Color color = COLOR_MAP.get(colorDef);
+        if (color == null) {
+            color = new Color(Display.getDefault(), colorDef.fRed, colorDef.fGreen, colorDef.fBlue, colorDef.fAlpha);
+            COLOR_MAP.put(colorDef, color);
+        }
+        return color;
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtTimeGraphView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtTimeGraphView.java
new file mode 100644 (file)
index 0000000..09f1814
--- /dev/null
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * 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.swt;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.TimeGraphModelView;
+import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
+import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
+
+/**
+ * @author alexandre
+ *
+ */
+public abstract class SwtTimeGraphView extends TimeGraphModelView implements ITmfTimeAligned {
+
+    private @Nullable TimeGraphViewer fTimeGraphViewer;
+
+    protected SwtTimeGraphView(String viewName, ITimeGraphModelRenderProvider modelRenderProvider) {
+        super(viewName, modelRenderProvider);
+    }
+
+    @Override
+    public void createPartControl(@Nullable Composite parent) {
+        if (parent == null) {
+            return;
+        }
+        TimeGraphViewer viewer = new TimeGraphViewer(parent, SWT.NONE);
+//        viewer.setTimeGraphContentProvider(new SwtTimeGraphContentProvider());
+//        viewer.setTimeGraphProvider(new SwtTimeGraphPresentationProvider());
+
+        fTimeGraphViewer = viewer;
+    }
+
+    @Override
+    public void setFocus() {
+    }
+
+    // ------------------------------------------------------------------------
+    // Time Alignment
+    // ------------------------------------------------------------------------
+
+    @Override
+    public @Nullable TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
+        if (fTimeGraphViewer != null) {
+            return fTimeGraphViewer.getTimeViewAlignmentInfo();
+        }
+        return null;
+    }
+
+    @Override
+    public int getAvailableWidth(int requestedOffset) {
+        if (fTimeGraphViewer != null) {
+            return fTimeGraphViewer.getAvailableWidth(requestedOffset);
+        }
+        return 0;
+    }
+
+    @Override
+    public void performAlign(int offset, int width) {
+        if (fTimeGraphViewer != null) {
+            fTimeGraphViewer.performAlign(offset, width);
+        }
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/package-info.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/package-info.java
new file mode 100644 (file)
index 0000000..ff5df7a
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc. and others
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swt;
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/ActionFactory.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/ActionFactory.java
new file mode 100644 (file)
index 0000000..e66ba39
--- /dev/null
@@ -0,0 +1,147 @@
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider.FilterMode;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider.SortingMode;
+import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.TimeGraphModelViewer;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+
+final class ActionFactory {
+
+    private ActionFactory() {}
+
+    private static abstract class DrowDownMenuCreator implements IMenuCreator {
+
+        private @Nullable Menu fMenu = null;
+
+        @Override
+        public final @Nullable Menu getMenu(@Nullable Menu parent) {
+            return null; // Not used?
+        }
+
+        @Override
+        public final Menu getMenu(@Nullable Control parent) {
+            if (fMenu != null) {
+                fMenu.dispose();
+            }
+            Menu menu = new Menu(parent);
+            getMenuActions().forEach(action -> {
+                new ActionContributionItem(action).fill(menu, -1);
+            });
+            fMenu = menu;
+            return menu;
+        }
+
+        @Override
+        public final void dispose() {
+            if (fMenu != null) {
+                fMenu.dispose();
+                fMenu = null;
+            }
+        }
+
+        protected abstract List<Action> getMenuActions();
+    }
+
+    private static class SelectSortingModeAction extends Action {
+
+        public SelectSortingModeAction(TimeGraphModelViewer viewer) {
+            super("Sorting Mode", IAction.AS_DROP_DOWN_MENU);
+            ITimeGraphModelRenderProvider provider = viewer.getModelRenderProvider();
+
+            setToolTipText("Select Sorting Mode");
+            setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_LEGEND));
+            setMenuCreator(new DrowDownMenuCreator() {
+                @Override
+                protected List<Action> getMenuActions() {
+                    return IntStream.range(0, provider.getSortingModes().size())
+                            .mapToObj(index -> {
+                                SortingMode sortingMode = provider.getSortingModes().get(index);
+                                Action action = new Action(sortingMode.getName(), IAction.AS_RADIO_BUTTON) {
+                                    @Override
+                                    public void runWithEvent(@Nullable Event event) {
+                                        if (isChecked()) {
+                                            provider.setCurrentSortingMode(index);
+                                            System.out.println("repainting viewer");
+                                            viewer.repaintCurrentArea();
+                                        }
+                                    }
+                                };
+                                action.setEnabled(true);
+                                action.setChecked(provider.getCurrentSortingMode() == sortingMode);
+                                return action;
+                            })
+                            .collect(Collectors.toList());
+                }
+            });
+        }
+
+        @Override
+        public void runWithEvent(@Nullable Event event) {
+            // TODO Also open the menu, need to figure out how
+        }
+    }
+
+    private static class SelectFilterModesAction extends Action {
+
+        public SelectFilterModesAction(TimeGraphModelViewer viewer) {
+            super("Filters", IAction.AS_DROP_DOWN_MENU);
+            ITimeGraphModelRenderProvider provider = viewer.getModelRenderProvider();
+
+            setToolTipText("Configure Filters");
+            setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FILTERS));
+            setMenuCreator(new DrowDownMenuCreator() {
+                @Override
+                protected List<Action> getMenuActions() {
+                    return IntStream.range(0, provider.getFilterModes().size())
+                            .mapToObj(index -> {
+                                FilterMode filterMode = provider.getFilterModes().get(index);
+                                Action action = new Action(filterMode.getName(), IAction.AS_CHECK_BOX) {
+                                    @Override
+                                    public void runWithEvent(@Nullable Event event) {
+                                        if (isChecked()) {
+                                            provider.enableFilterMode(index);
+                                        } else {
+                                            provider.disableFilterMode(index);
+                                        }
+                                        System.out.println("repainting viewer");
+                                        viewer.repaintCurrentArea();
+                                    }
+                                };
+                                action.setEnabled(true);
+                                action.setChecked(provider.getActiveFilterModes().contains(filterMode));
+                                return action;
+                            })
+                            .collect(Collectors.toList());
+                }
+            });
+        }
+
+        @Override
+        public void runWithEvent(@Nullable Event event) {
+            // TODO Also open the menu, need to figure out how
+        }
+    }
+
+    public static Action getSelectSortingModeAction(TimeGraphModelViewer viewer) {
+        return new SelectSortingModeAction(viewer);
+    }
+
+    public static Action getSelectFilterModesAction(TimeGraphModelViewer viewer) {
+        return new SelectFilterModesAction(viewer);
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/JfxColorFactory.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/JfxColorFactory.java
new file mode 100644 (file)
index 0000000..3fc6547
--- /dev/null
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.swtjfx;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition;
+
+import javafx.scene.paint.Color;
+
+final class JfxColorFactory {
+
+    private JfxColorFactory() {}
+
+    private static final Map<ColorDefinition, Color> COLOR_MAP = new ConcurrentHashMap<>();
+
+    /**
+     * Instantiate a {@link Color} from a {@link ColorDefinition} object.
+     *
+     * @param colorDef
+     *            The ColorDefinition
+     * @return The Color object
+     */
+    public static Color getColorFromDef(ColorDefinition colorDef) {
+        Color color = COLOR_MAP.get(colorDef);
+        if (color == null) {
+            color = Color.rgb(colorDef.fRed, colorDef.fGreen, colorDef.fBlue, (double) colorDef.fAlpha / (double) ColorDefinition.MAX);
+            COLOR_MAP.put(colorDef, color);
+        }
+        return color;
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/LatestJobExecutor.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/LatestJobExecutor.java
new file mode 100644 (file)
index 0000000..1ff199c
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * 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.swtjfx;
+
+import java.lang.ref.WeakReference;
+
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.annotation.Nullable;
+
+public class LatestJobExecutor {
+
+    /**
+     * The latest job that was schedule in this queue.
+     */
+    private WeakReference<@Nullable Job> fLatestJob = new WeakReference<>(null);
+
+    public LatestJobExecutor() {
+    }
+
+    public synchronized void schedule(Job newJob) {
+        Job latestJob = fLatestJob.get();
+        if (latestJob != null) {
+            /*
+             * Cancel the existing job. Here's hoping it cooperates and ends
+             * quickly!
+             */
+            latestJob.cancel();
+        }
+
+        /* Start the new job */
+        fLatestJob = new WeakReference<>(newJob);
+        newJob.schedule();
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphView.java
new file mode 100644 (file)
index 0000000..17fff31
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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.swtjfx;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.TimeGraphModelView;
+
+public abstract class SwtJfxTimeGraphView extends TimeGraphModelView {
+
+    private @Nullable SwtJfxTimeGraphViewer fViewer;
+
+    protected SwtJfxTimeGraphView(String viewName, ITimeGraphModelRenderProvider modelRenderProvider) {
+        super(viewName, modelRenderProvider);
+    }
+
+    @Override
+    public void createPartControl(@Nullable Composite parent) {
+        if (parent == null) {
+            return;
+        }
+        SwtJfxTimeGraphViewer viewer = new SwtJfxTimeGraphViewer(parent, getRenderProvider());
+        fViewer = viewer;
+
+        IToolBarManager toolbarMgr = getViewSite().getActionBars().getToolBarManager();
+        toolbarMgr.add(ActionFactory.getSelectSortingModeAction(viewer));
+        toolbarMgr.add(ActionFactory.getSelectFilterModesAction(viewer));
+    }
+
+    @Override
+    public void dispose() {
+        if (fViewer != null) {
+            fViewer.dispose();
+        }
+    }
+
+    @Override
+    public void setFocus() {
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphViewer.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphViewer.java
new file mode 100644 (file)
index 0000000..05b824a
--- /dev/null
@@ -0,0 +1,734 @@
+/*******************************************************************************
+ * 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.swtjfx;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRender;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender;
+import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.TimeGraphModelViewer;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+
+import javafx.beans.value.ChangeListener;
+import javafx.embed.swt.FXCanvas;
+import javafx.event.EventHandler;
+import javafx.geometry.Insets;
+import javafx.scene.Group;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.canvas.Canvas;
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.control.Label;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.ScrollPane.ScrollBarPolicy;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.StackPane;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.scene.shape.StrokeLineCap;
+
+/**
+ * Viewer for the {@link SwtJfxTimeGraphView}, encapsulating all the view's
+ * controls.
+ *
+ * Its contents consist of:
+ *
+ * TODO update this to its final form
+ * <pre>
+ * SashForm fBaseControl (parent is passed from the view)
+ *  + FXCanvas
+ *  |   + ScrollPane
+ *  |       + TreeView (?), contains the list of threads
+ *  + FXCanvas
+ *      + ScrollPane, will contain the time graph area
+ *          + Pane, gets resized to very large horizontal size to represent the whole trace range
+ *             + Canvas, canvas children are tiled on the Pane to show the content of one Render each
+ *             + Canvas
+ *             +  ...
+ * </pre>
+ *
+ * Both ScrolledPanes's vertical scrollbars are bound together, so that they
+ * scroll together.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class SwtJfxTimeGraphViewer extends TimeGraphModelViewer {
+
+    private static final double MAX_CANVAS_WIDTH = 2000.0;
+    private static final double MAX_CANVAS_HEIGHT = 2000.0;
+
+    // ------------------------------------------------------------------------
+    // Style definitions
+    // (Could eventually be moved to separate .css file?)
+    // ------------------------------------------------------------------------
+
+    private static final Color BACKGROUD_LINES_COLOR = checkNotNull(Color.LIGHTBLUE);
+    private static final String BACKGROUND_STYLE = "-fx-background-color: rgba(255, 255, 255, 255);"; //$NON-NLS-1$
+
+    private static final double SELECTION_STROKE_WIDTH = 1;
+    private static final Color SELECTION_STROKE_COLOR = checkNotNull(Color.BLUE);
+    private static final Color SELECTION_FILL_COLOR = checkNotNull(Color.LIGHTBLUE.deriveColor(0, 1.2, 1, 0.4));
+
+    private static final int LABEL_SIDE_MARGIN = 10;
+
+    // ------------------------------------------------------------------------
+    // Class fields
+    // ------------------------------------------------------------------------
+
+    private final SelectionContext fSelectionCtx = new SelectionContext();
+    private final ScrollingContext fScrollingCtx = new ScrollingContext();
+
+    private final LatestJobExecutor fJobExecutor = new LatestJobExecutor();
+
+    private final SashForm fBaseControl;
+
+    private final FXCanvas fTreeFXCanvas;
+    private final FXCanvas fTimeGraphFXCanvas;
+
+    private final Pane fTreePane;
+    private final ScrollPane fTreeScrollPane;
+    private final Pane fTimeGraphPane;
+    private final ScrollPane fTimeGraphScrollPane;
+
+    /*
+     * Children of the time graph pane are split into groups, so we can easily
+     * redraw or add only some of them.
+     */
+    private final Group fTimeGraphStatesLayer;
+    private final Group fTimeGraphSelectionLayer;
+    // TODO Layers for markers, arrows
+
+    private final Rectangle fSelectionRect;
+    private final Rectangle fOngoingSelectionRect;
+
+    /**
+     * Height of individual entries (text + states), including padding.
+     *
+     * TODO Make this configurable (vertical zoom feature)
+     */
+    private static final double ENTRY_HEIGHT = 20;
+
+
+    /** Current zoom level */
+    private double fNanosPerPixel = 1.0;
+
+
+    /**
+     * Constructor
+     *
+     * @param parent
+     *            Parent SWT composite
+     */
+    public SwtJfxTimeGraphViewer(Composite parent, ITimeGraphModelRenderProvider provider) {
+        super(provider);
+
+        // TODO Convert this sash to JavaFX too?
+        fBaseControl = new SashForm(parent, SWT.NONE);
+
+        fTreeFXCanvas = new FXCanvas(fBaseControl, SWT.NONE);
+        fTimeGraphFXCanvas = new FXCanvas(fBaseControl, SWT.NONE);
+
+        // TODO Base on time-alignment
+        fBaseControl.setWeights(new int[] { 15, 85 });
+
+        // --------------------------------------------------------------------
+        // Prepare the tree part's scene graph
+        // --------------------------------------------------------------------
+
+        fTreePane = new Pane();
+
+        fTreeScrollPane = new ScrollPane(fTreePane);
+        /* We only show the time graph's vertical scrollbar */
+        fTreeScrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
+        fTreeScrollPane.setHbarPolicy(ScrollBarPolicy.ALWAYS);
+
+        // --------------------------------------------------------------------
+        // Prepare the time graph's part scene graph
+        // --------------------------------------------------------------------
+
+        fSelectionRect = new Rectangle();
+        fOngoingSelectionRect = new Rectangle();
+
+        Stream.of(fSelectionRect, fOngoingSelectionRect).forEach(rect -> {
+            rect.setStroke(SELECTION_STROKE_COLOR);
+            rect.setStrokeWidth(SELECTION_STROKE_WIDTH);
+            rect.setStrokeLineCap(StrokeLineCap.ROUND);
+            rect.setFill(SELECTION_FILL_COLOR);
+        });
+
+        fTimeGraphStatesLayer = new Group();
+        fTimeGraphSelectionLayer = new Group(fSelectionRect, fOngoingSelectionRect);
+
+        fTimeGraphPane = new Pane(fTimeGraphStatesLayer, fTimeGraphSelectionLayer);
+        fTimeGraphPane.setStyle(BACKGROUND_STYLE);
+        fTimeGraphPane.addEventHandler(MouseEvent.MOUSE_PRESSED, fSelectionCtx.fMousePressedEventHandler);
+        fTimeGraphPane.addEventHandler(MouseEvent.MOUSE_DRAGGED, fSelectionCtx.fMouseDraggedEventHandler);
+        fTimeGraphPane.addEventHandler(MouseEvent.MOUSE_RELEASED, fSelectionCtx.fMouseReleasedEventHandler);
+
+        /*
+         * We control the width of the time graph pane programatically, so
+         * ensure that calls to setPrefWidth set the actual width right away.
+         */
+        fTimeGraphPane.minWidthProperty().bind(fTimeGraphPane.prefWidthProperty());
+        fTimeGraphPane.maxWidthProperty().bind(fTimeGraphPane.prefWidthProperty());
+
+        /*
+         * Ensure the time graph pane is always exactly the same vertical size
+         * as the tree pane, so they remain aligned.
+         */
+        fTimeGraphPane.minHeightProperty().bind(fTreePane.heightProperty());
+        fTimeGraphPane.prefHeightProperty().bind(fTreePane.heightProperty());
+        fTimeGraphPane.maxHeightProperty().bind(fTreePane.heightProperty());
+
+        fTimeGraphScrollPane = new ScrollPane(fTimeGraphPane);
+        fTimeGraphScrollPane.setVbarPolicy(ScrollBarPolicy.ALWAYS);
+        fTimeGraphScrollPane.setHbarPolicy(ScrollBarPolicy.ALWAYS);
+
+//        fTimeGraphScrollPane.viewportBoundsProperty().addListener(fScrollingCtx.fHScrollChangeListener);
+        fTimeGraphScrollPane.setOnMouseEntered(fScrollingCtx.fMouseEnteredEventHandler);
+        fTimeGraphScrollPane.setOnMouseExited(fScrollingCtx.fMouseExitedEventHandler);
+        fTimeGraphScrollPane.hvalueProperty().addListener(fScrollingCtx.fHScrollChangeListener);
+
+        /* Synchronize the two scrollpanes' vertical scroll bars together */
+        fTreeScrollPane.vvalueProperty().bindBidirectional(fTimeGraphScrollPane.vvalueProperty());
+
+        // --------------------------------------------------------------------
+        // Hook the parts into the SWT window
+        // --------------------------------------------------------------------
+
+        fTreeFXCanvas.setScene(new Scene(fTreeScrollPane));
+        fTimeGraphFXCanvas.setScene(new Scene(fTimeGraphScrollPane));
+
+        /*
+         * Initially populate the viewer with the context of the current trace.
+         */
+        ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
+        getSignalingContext().initializeForTrace(trace);
+    }
+
+    // ------------------------------------------------------------------------
+    // Test accessors
+    // ------------------------------------------------------------------------
+
+    @VisibleForTesting
+    protected Pane getTimeGraphPane() {
+        return fTimeGraphPane;
+    }
+
+    @VisibleForTesting
+    protected ScrollPane getTimeGraphScrollPane() {
+        return fTimeGraphScrollPane;
+    }
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    @Override
+    protected void seekVisibleRangeImpl(long visibleWindowStartTime, long visibleWindowEndTime) {
+        final long fullTimeGraphStart = getFullTimeGraphStartTime();
+        final long fullTimeGraphEnd = getFullTimeGraphEndTime();
+
+        /* Update the zoom level */
+        long windowTimeRange = visibleWindowEndTime - visibleWindowStartTime;
+        double timeGraphWidth = fTimeGraphScrollPane.getWidth();
+        fNanosPerPixel = windowTimeRange / timeGraphWidth;
+
+        double timeGraphAreaWidth = timestampToPaneXPos(fullTimeGraphEnd) - timestampToPaneXPos(fullTimeGraphStart);
+        if (timeGraphAreaWidth < 1.0) {
+            // FIXME
+            return;
+        }
+
+        double newValue;
+        if (visibleWindowStartTime == fullTimeGraphStart) {
+            newValue = fTimeGraphScrollPane.getHmin();
+        } else if (visibleWindowEndTime == fullTimeGraphEnd) {
+            newValue = fTimeGraphScrollPane.getHmax();
+        } else {
+            // FIXME Not aligned perfectly yet, see how the scrolling
+            // listener does it?
+            long targetTs = (visibleWindowStartTime + visibleWindowEndTime) / 2;
+            double xPos = timestampToPaneXPos(targetTs);
+            newValue = xPos / timeGraphAreaWidth;
+        }
+
+        fTimeGraphPane.setPrefWidth(timeGraphAreaWidth);
+        fTimeGraphScrollPane.setHvalue(newValue);
+    }
+
+    @Override
+    protected void paintAreaImpl(ITmfTrace trace, long windowStartTime, long windowEndTime) {
+        final long fullTimeGraphStart = getFullTimeGraphStartTime();
+        final long fullTimeGraphEnd = getFullTimeGraphEndTime();
+
+        /*
+         * Get the current target width of the viewer, so we know at which
+         * resolution we must do state system queries.
+         *
+         * Yes! We can query the size of visible components outside of the UI
+         * thread! Praise the JavaFX!
+         */
+        long treePaneWidth = Math.round(fTreeScrollPane.getWidth());
+
+        long windowTimeRange = windowEndTime - windowStartTime;
+
+        Job job = new Job("Time Graph Update") {
+            @Override
+            protected IStatus run(@Nullable IProgressMonitor monitor) {
+                IProgressMonitor mon = checkNotNull(monitor);
+
+                /* Apply the configuration options to the render provider */
+                ITimeGraphModelRenderProvider renderProvider = getModelRenderProvider();
+                renderProvider.setConfiguredTimeRange(windowStartTime, windowEndTime);
+
+                /*
+                 * Request the needed renders and prepare the corresponding
+                 * canvases. We target at most one "window width" before and
+                 * after the current window, clamped by the trace's start and
+                 * end.
+                 */
+                final long renderingStartTime = Math.max(fullTimeGraphStart, windowStartTime - windowTimeRange);
+                final long renderingEndTime = Math.min(fullTimeGraphEnd, windowEndTime + windowTimeRange);
+                final long renderTimeRange = (long) (MAX_CANVAS_WIDTH * fNanosPerPixel);
+
+                List<TimeGraphModelRender> renders = new ArrayList<>();
+                long renderStart = renderingStartTime - renderTimeRange;
+                // TODO Find a way to streamize/parallelize this loop?
+                do {
+                    renderStart += renderTimeRange;
+                    long renderEnd = Math.min(renderStart + renderTimeRange, renderingEndTime);
+                    // FIXME Even with /10 we sometimes get holes in the view. Subpixel rendering?
+                    // Needs to be debugged/tested further.
+                    long resolution = Math.max(1, Math.round(fNanosPerPixel / 10));
+
+                    System.out.printf("requesting render from %,d to %,d, resolution=%d%n",
+                            renderStart, renderEnd, resolution);
+
+                    TimeGraphModelRender render = renderProvider.getRender(trace,
+                            renderStart, renderEnd, resolution, monitor);
+                    renders.add(render);
+                } while ((renderStart + renderTimeRange) < renderingEndTime);
+
+                if (mon.isCanceled()) {
+                    /* Job was cancelled, no need to update the UI */
+                    System.out.println("job was cancelled before it could end");
+                    return Status.CANCEL_STATUS;
+                }
+
+                if (renders.isEmpty()) {
+                    /* Nothing to show yet, keep the view empty */
+                    return Status.OK_STATUS;
+                }
+
+                /* Prepare the time graph part */
+                Node timeGraphContents = prepareTimeGraphContents(renders);
+
+                /* Prepare the tree part */
+                Node treeContents = prepareTreeContents(renders.get(0).getTreeRender(), treePaneWidth);
+
+                if (mon.isCanceled()) {
+                    /* Job was cancelled, no need to update the UI */
+                    System.out.println("job was cancelled before it could end");
+                    return Status.CANCEL_STATUS;
+                }
+
+                /* Update the view! */
+                Display.getDefault().syncExec( () -> {
+                    fTreePane.getChildren().clear();
+                    fTreePane.getChildren().add(treeContents);
+
+                    fTimeGraphStatesLayer.getChildren().clear();
+                    fTimeGraphStatesLayer.getChildren().add(timeGraphContents);
+                });
+
+                return Status.OK_STATUS;
+            }
+        };
+
+        fJobExecutor.schedule(job);
+    }
+
+    @Override
+    protected void drawSelectionImpl(long selectionStartTime, long selectionEndTime) {
+        double xStart = timestampToPaneXPos(selectionStartTime);
+        double xEnd = timestampToPaneXPos(selectionEndTime);
+        double xWidth = xEnd - xStart;
+
+        fSelectionRect.setX(xStart);
+        fSelectionRect.setY(0);
+        fSelectionRect.setWidth(xWidth);
+        fSelectionRect.setHeight(fTimeGraphPane.getHeight());
+
+        fSelectionRect.setVisible(true);
+    }
+
+    // ------------------------------------------------------------------------
+    // Methods related to the Tree area
+    // ------------------------------------------------------------------------
+
+    private static Node prepareTreeContents(TimeGraphTreeRender treeRender, double paneWidth) {
+        /* Prepare the tree element objects */
+        List<Label> treeElements = treeRender.getAllTreeElements().stream()
+                // TODO Put as a real tree. TreeView ?
+                .map(elem -> new Label(elem.getName()))
+                .peek(label -> {
+                    label.setPrefHeight(ENTRY_HEIGHT);
+                    label.setPadding(new Insets(0, LABEL_SIDE_MARGIN, 0, LABEL_SIDE_MARGIN));
+                    /*
+                     * Re-set the solid background for the labels, so we do not
+                     * see the background lines through.
+                     */
+                    label.setStyle(BACKGROUND_STYLE);
+                })
+                .collect(Collectors.toList());
+
+        VBox treeElemsBox = new VBox(); // Change to TreeView eventually ?
+        treeElemsBox.getChildren().addAll(treeElements);
+
+        /* Prepare the Canvases with the horizontal alignment lines */
+        List<Canvas> canvases = new ArrayList<>();
+        int maxEntriesPerCanvas = (int) (MAX_CANVAS_HEIGHT / ENTRY_HEIGHT);
+        Lists.partition(treeElements, maxEntriesPerCanvas).forEach(subList -> {
+            int nbElements = subList.size();
+            double height = nbElements * ENTRY_HEIGHT;
+
+            Canvas canvas = new Canvas(paneWidth, height);
+            drawBackgroundLines(canvas, ENTRY_HEIGHT);
+            canvas.setCache(true);
+            canvases.add(canvas);
+        });
+        VBox canvasBox = new VBox();
+        canvasBox.getChildren().addAll(canvases);
+
+        /* Put the background Canvas and the Tree View into their containers */
+        StackPane stackPane = new StackPane(canvasBox, treeElemsBox);
+        stackPane.setStyle(BACKGROUND_STYLE);
+        return stackPane;
+    }
+
+    // ------------------------------------------------------------------------
+    // Methods related to the Time Graph area
+    // ------------------------------------------------------------------------
+
+    private Node prepareTimeGraphContents(List<TimeGraphModelRender> renders) {
+        Set<Node> canvases = renders.stream()
+                .parallel() // order doesn't matter here
+                .flatMap(render -> getCanvasesForRender(render).stream())
+                .collect(Collectors.toSet());
+
+        return new Group(canvases);
+    }
+
+    /**
+     * Get the vertically-tiled Canvas's for a single render. They will
+     * be already relocated correctly, so the collection's order does not
+     * matter.
+     *
+     * @param render
+     *            The render
+     * @return The vertical set of canvases
+     */
+    private Collection<Canvas> getCanvasesForRender(TimeGraphModelRender render) {
+        List<List<TimeGraphStateInterval>> stateIntervals = render.getStateIntervals();
+        /* The canvas will be put on the Pane at this offset */
+        final double xOffset = timestampToPaneXPos(render.getStartTime());
+        final double xEnd = timestampToPaneXPos(render.getEndTime());
+        final double canvasWidth = xEnd - xOffset;
+        final int maxEntriesPerCanvas = (int) (MAX_CANVAS_HEIGHT / ENTRY_HEIGHT);
+
+        /*
+         * Split the full list of intervals into smaller partitions, and draw
+         * one Canvas per partition.
+         */
+        List<Canvas> canvases = new ArrayList<>();
+        double yOffset = 0;
+        List<List<List<TimeGraphStateInterval>>> partitionedIntervals =
+                Lists.partition(stateIntervals, maxEntriesPerCanvas);
+        for (int i = 0; i < partitionedIntervals.size(); i++) {
+            /* "states" represent the subset of intervals to draw on this Canvas */
+            List<List<TimeGraphStateInterval>> states = partitionedIntervals.get(i);
+            final double canvasHeight = ENTRY_HEIGHT * states.size();
+
+            Canvas canvas = new Canvas(canvasWidth, canvasHeight);
+            drawBackgroundLines(canvas, ENTRY_HEIGHT);
+            drawStates(states, canvas.getGraphicsContext2D(), xOffset);
+
+//            System.out.println("relocating canvas of size + (" + canvasWidth + ", " + canvasHeight + ") to " + xOffset + ", " + yOffset);
+            canvas.relocate(xOffset, yOffset);
+            canvas.setCache(true); // TODO Test?
+            canvases.add(canvas);
+
+            yOffset += canvasHeight;
+        }
+        return canvases;
+    }
+
+    private void drawStates(List<List<TimeGraphStateInterval>> stateIntervalsToDraw, GraphicsContext gc, double xOffset) {
+        IntStream.range(0, stateIntervalsToDraw.size()).forEach(index -> {
+            /*
+             * The base (top) of each full-thickness rectangle object we will
+             * draw for this entry
+             */
+            final double xBase = index * ENTRY_HEIGHT;
+
+            List<TimeGraphStateInterval> intervals = stateIntervalsToDraw.get(index);
+            for (TimeGraphStateInterval interval : intervals) {
+                try {
+                    /*
+                     * These coordinates are relative to the canvas itself, so
+                     * we need to substract the value of the offset of the
+                     * canvas relative to the Pane.
+                     */
+                    final double xStart = timestampToPaneXPos(interval.getStartEvent().getTimestamp()) - xOffset;
+                    final double xEnd = timestampToPaneXPos(interval.getEndEvent().getTimestamp()) - xOffset;
+                    final double xWidth = Math.max(1.0, xEnd - xStart);
+
+                    double yStart, yHeight;
+                    switch (interval.getLineThickness()) {
+                    case NORMAL:
+                    default:
+                        yStart = xBase + 4;
+                        yHeight = ENTRY_HEIGHT - 4;
+                        break;
+                    case SMALL:
+                        yStart = xBase + 8;
+                        yHeight = ENTRY_HEIGHT - 8;
+                        break;
+                    }
+
+                    gc.setFill(JfxColorFactory.getColorFromDef(interval.getColorDefinition()));
+                    gc.fillRect(xStart, yStart, xWidth, yHeight);
+
+                } catch (IllegalArgumentException iae) { // TODO Temp
+                    System.out.println("out of bounds interval:" + interval.toString());
+                    continue;
+                }
+
+                // TODO Paint the state's name if applicable
+            }
+        });
+
+    }
+
+    // ------------------------------------------------------------------------
+    // Mouse event listeners
+    // ------------------------------------------------------------------------
+
+    /**
+     * Class encapsulating the time range selection, related drawing and
+     * listeners.
+     */
+    private class SelectionContext {
+
+        private boolean fOngoingSelection;
+        private double fMouseOriginX;
+
+        public final EventHandler<MouseEvent> fMousePressedEventHandler = e -> {
+            if (e.isShiftDown() ||
+                    e.isControlDown() ||
+                    e.isSecondaryButtonDown() ||
+                    e.isMiddleButtonDown()) {
+                /* Do other things! */
+                // TODO!
+                return;
+            }
+
+            if (fOngoingSelection) {
+                return;
+            }
+
+            /* Remove the current selection, if there is one */
+            fSelectionRect.setVisible(false);
+
+            fMouseOriginX = e.getX();
+
+            fOngoingSelectionRect.setX(fMouseOriginX);
+            fOngoingSelectionRect.setY(0);
+            fOngoingSelectionRect.setWidth(0);
+            fOngoingSelectionRect.setHeight(fTimeGraphPane.getHeight());
+
+            fOngoingSelectionRect.setVisible(true);
+
+            e.consume();
+
+            fOngoingSelection = true;
+        };
+
+        public final EventHandler<MouseEvent> fMouseDraggedEventHandler = e -> {
+            double newX = e.getX();
+            double offsetX = newX - fMouseOriginX;
+
+            if (offsetX > 0) {
+                fOngoingSelectionRect.setX(fMouseOriginX);
+                fOngoingSelectionRect.setWidth(offsetX);
+            } else {
+                fOngoingSelectionRect.setX(newX);
+                fOngoingSelectionRect.setWidth(-offsetX);
+            }
+
+            e.consume();
+        };
+
+        public final EventHandler<MouseEvent> fMouseReleasedEventHandler = e -> {
+            fOngoingSelectionRect.setVisible(false);
+
+            e.consume();
+
+            /* Send a time range selection signal for the currently selected time range */
+            double startX = Math.max(0, fOngoingSelectionRect.getX());
+            // FIXME Possible glitch when selecting backwards outside of the window
+            double endX = Math.min(fTimeGraphPane.getWidth(), startX + fOngoingSelectionRect.getWidth());
+            long tsStart = paneXPosToTimestamp(startX);
+            long tsEnd = paneXPosToTimestamp(endX);
+
+            getSignalingContext().sendTimeRangeSelectionUpdate(tsStart, tsEnd);
+
+            fOngoingSelection = false;
+        };
+    }
+
+    /**
+     * Class encapsulating the scrolling operations of the time graph pane.
+     *
+     * The mouse entered/exited handlers ensure only the scrollpane being
+     * interacted by the user is the one sending the synchronization signals.
+     */
+    private class ScrollingContext {
+
+        private boolean fUserActionOngoing = false;
+
+        private final EventHandler<MouseEvent> fMouseEnteredEventHandler = e -> {
+            fUserActionOngoing = true;
+        };
+
+        private final EventHandler<MouseEvent> fMouseExitedEventHandler = e -> {
+            fUserActionOngoing = false;
+        };
+
+        /**
+         * Listener for the horizontal scrollbar changes
+         */
+        private final ChangeListener<Object> fHScrollChangeListener = (observable, oldValue, newValue) -> {
+            if (!fUserActionOngoing) {
+                System.out.println("Listener triggered but inactive");
+                return;
+            }
+
+            System.out.println("Change listener triggered, oldval=" + oldValue.toString() + ", newval=" + newValue.toString());
+
+            /*
+             * Determine the X position represented by the left edge of the pane
+             */
+            double hmin = fTimeGraphScrollPane.getHmin();
+            double hmax = fTimeGraphScrollPane.getHmax();
+            double hvalue = fTimeGraphScrollPane.getHvalue();
+            double contentWidth = fTimeGraphPane.getLayoutBounds().getWidth();
+            double viewportWidth = fTimeGraphScrollPane.getViewportBounds().getWidth();
+            double hoffset = Math.max(0, contentWidth - viewportWidth) * (hvalue - hmin) / (hmax - hmin);
+
+            /*
+             * Convert the positions of the left and right edges to timestamps,
+             * and send a window range update signal
+             */
+            long tsStart = paneXPosToTimestamp(hoffset);
+            long tsEnd = paneXPosToTimestamp(hoffset + viewportWidth);
+
+            System.out.printf("Offset: %.1f, width: %.1f %n", hoffset, viewportWidth);
+            System.out.printf("Sending visible range update: %,d to %,d%n", tsStart, tsEnd);
+
+            getSignalingContext().sendVisibleWindowRangeUpdate(tsStart, tsEnd);
+        };
+    }
+
+    // ------------------------------------------------------------------------
+    // Common utils
+    // ------------------------------------------------------------------------
+
+    private static void drawBackgroundLines(Canvas canvas, double entryHeight) {
+        double width = canvas.getWidth();
+        int nbLines = (int) (canvas.getHeight() / entryHeight);
+
+
+        GraphicsContext gc = canvas.getGraphicsContext2D();
+        gc.save();
+
+        gc.setStroke(BACKGROUD_LINES_COLOR);
+        gc.setLineWidth(1);
+        /* average+2 gives the best-looking output */
+        DoubleStream.iterate((ENTRY_HEIGHT / 2) + 2, i -> i + entryHeight).limit(nbLines).forEach(yPos -> {
+            gc.strokeLine(0, yPos, width, yPos);
+        });
+
+        gc.restore();
+    }
+
+    private double timestampToPaneXPos(long timestamp) {
+        return timestampToPaneXPos(timestamp, getFullTimeGraphStartTime(), getFullTimeGraphEndTime(), fNanosPerPixel);
+    }
+
+    @VisibleForTesting
+    public static double timestampToPaneXPos(long timestamp, long start, long end, double nanosPerPixel) {
+        if (timestamp < start) {
+            throw new IllegalArgumentException(timestamp + " is smaller than trace start time " + start); //$NON-NLS-1$
+        }
+        if (timestamp > end) {
+            throw new IllegalArgumentException(timestamp + " is greater than trace end time " + end); //$NON-NLS-1$
+        }
+
+        double traceTimeRange = end - start;
+        double timeStampRatio = (timestamp - start) / traceTimeRange;
+
+        long fullTraceWidthInPixels = (long) (traceTimeRange / nanosPerPixel);
+        double xPos = fullTraceWidthInPixels * timeStampRatio;
+        return Math.round(xPos);
+    }
+
+    private long paneXPosToTimestamp(double x) {
+        return paneXPosToTimestamp(x, fTimeGraphPane.getWidth(), getFullTimeGraphStartTime(), fNanosPerPixel);
+    }
+
+    @VisibleForTesting
+    public static long paneXPosToTimestamp(double x, double totalWidth, long startTimestamp, double nanosPerPixel) {
+        if (x < 0.0 || totalWidth < 1.0 || x > totalWidth) {
+            throw new IllegalArgumentException("Invalid position arguments: pos=" + x + ", width=" + totalWidth);
+        }
+
+        long ts = Math.round(x * nanosPerPixel);
+        return ts + startTimestamp;
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/Example.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/Example.java
new file mode 100644 (file)
index 0000000..0d14c60
--- /dev/null
@@ -0,0 +1,61 @@
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.examples;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import javafx.application.Application;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.stage.Stage;
+
+@NonNullByDefault({})
+public class Example extends Application {
+    @Override
+    public void start(Stage stage) {
+        Node content = new Rectangle(1000, 700, Color.GREEN);
+        ScrollPane scrollPane = new ScrollPane(content);
+        scrollPane.setPrefSize(500, 300);
+
+        ChangeListener<Object> changeListener = new ChangeListener<Object>() {
+            @Override
+            public void changed(ObservableValue<? extends Object> observable, Object oldValue, Object newValue) {
+                double hmin = scrollPane.getHmin();
+                double hmax = scrollPane.getHmax();
+                double hvalue = scrollPane.getHvalue();
+                double contentWidth = content.getLayoutBounds().getWidth();
+                double viewportWidth = scrollPane.getViewportBounds().getWidth();
+
+                double hoffset =
+                    Math.max(0, contentWidth - viewportWidth) * (hvalue - hmin) / (hmax - hmin);
+
+                double vmin = scrollPane.getVmin();
+                double vmax = scrollPane.getVmax();
+                double vvalue = scrollPane.getVvalue();
+                double contentHeight = content.getLayoutBounds().getHeight();
+                double viewportHeight = scrollPane.getViewportBounds().getHeight();
+
+                double voffset =
+                    Math.max(0,  contentHeight - viewportHeight) * (vvalue - vmin) / (vmax - vmin);
+
+                System.out.printf("Offset: [%.1f, %.1f] width: %.1f height: %.1f %n",
+                        hoffset, voffset, viewportWidth, viewportHeight);
+            }
+        };
+        scrollPane.viewportBoundsProperty().addListener(changeListener);
+        scrollPane.hvalueProperty().addListener(changeListener);
+        scrollPane.vvalueProperty().addListener(changeListener);
+
+        Scene scene = new Scene(scrollPane, 640, 480);
+        stage.setScene(scene);
+
+        stage.show();
+    }
+
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
\ No newline at end of file
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/Example2.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/Example2.java
new file mode 100644 (file)
index 0000000..34777fd
--- /dev/null
@@ -0,0 +1,79 @@
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.examples;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import javafx.application.Application;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.scene.Scene;
+import javafx.scene.canvas.Canvas;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.layout.Pane;
+import javafx.stage.Stage;
+
+@NonNullByDefault({})
+public class Example2 extends Application {
+
+    private static final double TEN_BILLIONS = 10000000000.0;
+
+    @Override
+    public void start(Stage stage) {
+//        Node content = new Rectangle(1000, 700, Color.GREEN);
+        Pane pane = new Pane();
+        pane.setPrefSize(TEN_BILLIONS, TEN_BILLIONS);
+        ScrollPane scrollPane = new ScrollPane(pane);
+        scrollPane.setPrefSize(500, 300);
+
+        ChangeListener<Object> changeListener = new ChangeListener<Object>() {
+            @Override
+            public void changed(ObservableValue<? extends Object> observable, Object oldValue, Object newValue) {
+                System.out.println("source=" + observable.toString());
+
+                double hmin = scrollPane.getHmin();
+                double hmax = scrollPane.getHmax();
+                double hvalue = scrollPane.getHvalue();
+                double contentWidth = pane.getLayoutBounds().getWidth();
+                double viewportWidth = scrollPane.getViewportBounds().getWidth();
+
+                double hoffset =
+                    Math.max(0, contentWidth - viewportWidth) * (hvalue - hmin) / (hmax - hmin);
+
+                double vmin = scrollPane.getVmin();
+                double vmax = scrollPane.getVmax();
+                double vvalue = scrollPane.getVvalue();
+                double contentHeight = pane.getLayoutBounds().getHeight();
+                double viewportHeight = scrollPane.getViewportBounds().getHeight();
+
+                double voffset =
+                    Math.max(0,  contentHeight - viewportHeight) * (vvalue - vmin) / (vmax - vmin);
+
+                System.out.printf("Offset: [%.1f, %.1f] width: %.1f height: %.1f %n",
+                        hoffset, voffset, viewportWidth, viewportHeight);
+            }
+        };
+        scrollPane.viewportBoundsProperty().addListener(changeListener);
+        scrollPane.hvalueProperty().addListener(changeListener);
+        scrollPane.vvalueProperty().addListener(changeListener);
+
+        /* Drawing on the region */
+        Canvas canvas1 = new Canvas(100, 100);
+        canvas1.relocate(TEN_BILLIONS - 100, 0);
+        canvas1.getGraphicsContext2D().strokeOval(60, 60, 30, 30);
+
+        Canvas canvas2 = new Canvas(100, 100);
+        canvas2.relocate(TEN_BILLIONS - 100, TEN_BILLIONS - 100);
+        canvas2.getGraphicsContext2D().fillOval(60, 60, 30, 30);
+
+        pane.getChildren().addAll(canvas1, canvas2);
+
+        /* Showing the scene */
+        Scene scene = new Scene(scrollPane, 640, 480);
+        stage.setScene(scene);
+
+        stage.show();
+    }
+
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
\ No newline at end of file
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/ExampleCanvas.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/ExampleCanvas.java
new file mode 100644 (file)
index 0000000..85cbe41
--- /dev/null
@@ -0,0 +1,55 @@
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.examples;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+import javafx.application.Application;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.canvas.Canvas;
+import javafx.scene.canvas.GraphicsContext;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.ArcType;
+import javafx.stage.Stage;
+
+@NonNullByDefault({})
+public class ExampleCanvas extends Application {
+
+    public static void main(String[] args) {
+        launch(args);
+    }
+
+    @Override
+    public void start(Stage primaryStage) {
+        primaryStage.setTitle("Drawing Operations Test");
+        Group root = new Group();
+        Canvas canvas = new Canvas(300, 250);
+        GraphicsContext gc = canvas.getGraphicsContext2D();
+        drawShapes(gc);
+        root.getChildren().add(canvas);
+        primaryStage.setScene(new Scene(root));
+        primaryStage.show();
+    }
+
+    private static void drawShapes(GraphicsContext gc) {
+        gc.setFill(Color.GREEN);
+        gc.setStroke(Color.BLUE);
+        gc.setLineWidth(5);
+        gc.strokeLine(40, 10, 10, 40);
+        gc.fillOval(10, 60, 30, 30);
+        gc.strokeOval(60, 60, 30, 30);
+        gc.fillRoundRect(110, 60, 30, 30, 10, 10);
+        gc.strokeRoundRect(160, 60, 30, 30, 10, 10);
+        gc.fillArc(10, 110, 30, 30, 45, 240, ArcType.OPEN);
+        gc.fillArc(60, 110, 30, 30, 45, 240, ArcType.CHORD);
+        gc.fillArc(110, 110, 30, 30, 45, 240, ArcType.ROUND);
+        gc.strokeArc(10, 160, 30, 30, 45, 240, ArcType.OPEN);
+        gc.strokeArc(60, 160, 30, 30, 45, 240, ArcType.CHORD);
+        gc.strokeArc(110, 160, 30, 30, 45, 240, ArcType.ROUND);
+        gc.fillPolygon(new double[]{10, 40, 10, 40},
+                       new double[]{210, 210, 240, 240}, 4);
+        gc.strokePolygon(new double[]{60, 90, 60, 90},
+                         new double[]{210, 210, 240, 240}, 4);
+        gc.strokePolyline(new double[]{110, 140, 110, 140},
+                          new double[]{210, 210, 240, 240}, 4);
+    }
+}
\ No newline at end of file
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/ExampleMouseDrag.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/ExampleMouseDrag.java
new file mode 100644 (file)
index 0000000..4996b86
--- /dev/null
@@ -0,0 +1,85 @@
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.examples;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import javafx.application.Application;
+import javafx.event.EventHandler;
+import javafx.scene.Cursor;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Circle;
+import javafx.stage.Stage;
+
+/**
+ * @web http://java-buddy.blogspot.com/
+ */
+public class ExampleMouseDrag extends Application {
+
+    private double orgSceneX, orgSceneY;
+    private double orgTranslateX, orgTranslateY;
+
+    @Override
+    public void start(@Nullable Stage primaryStage) {
+        if (primaryStage == null) {
+            return;
+        }
+
+        //Create Circles
+        Circle circleRed = new Circle(50.0, Color.RED);
+        circleRed.setCursor(Cursor.HAND);
+        circleRed.setOnMousePressed(circleOnMousePressedEventHandler);
+        circleRed.setOnMouseDragged(circleOnMouseDraggedEventHandler);
+
+        Circle circleGreen = new Circle(50.0, Color.GREEN);
+        circleGreen.setCursor(Cursor.MOVE);
+        circleGreen.setCenterX(150);
+        circleGreen.setCenterY(150);
+        circleGreen.setOnMousePressed(circleOnMousePressedEventHandler);
+        circleGreen.setOnMouseDragged(circleOnMouseDraggedEventHandler);
+
+        Circle circleBlue = new Circle(50.0, Color.BLUE);
+        circleBlue.setCursor(Cursor.CROSSHAIR);
+        circleBlue.setTranslateX(300);
+        circleBlue.setTranslateY(100);
+        circleBlue.setOnMousePressed(circleOnMousePressedEventHandler);
+        circleBlue.setOnMouseDragged(circleOnMouseDraggedEventHandler);
+
+        Group root = new Group();
+        root.getChildren().addAll(circleRed, circleGreen, circleBlue);
+
+        primaryStage.setResizable(false);
+        primaryStage.setScene(new Scene(root, 400,350));
+
+        primaryStage.setTitle("java-buddy");
+        primaryStage.show();
+    }
+
+    public static void main(String[] args) {
+        launch(args);
+    }
+
+    private EventHandler<MouseEvent> circleOnMousePressedEventHandler = new EventHandler<MouseEvent>() {
+        @Override
+        public void handle(MouseEvent t) {
+            orgSceneX = t.getSceneX();
+            orgSceneY = t.getSceneY();
+            orgTranslateX = ((Circle)(t.getSource())).getTranslateX();
+            orgTranslateY = ((Circle)(t.getSource())).getTranslateY();
+        }
+    };
+
+    private EventHandler<MouseEvent> circleOnMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
+        @Override
+        public void handle(MouseEvent t) {
+            double offsetX = t.getSceneX() - orgSceneX;
+            double offsetY = t.getSceneY() - orgSceneY;
+            double newTranslateX = orgTranslateX + offsetX;
+            double newTranslateY = orgTranslateY + offsetY;
+
+            ((Circle)(t.getSource())).setTranslateX(newTranslateX);
+            ((Circle)(t.getSource())).setTranslateY(newTranslateY);
+        }
+    };
+}
\ No newline at end of file
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/ExampleMouseDrag2.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/ExampleMouseDrag2.java
new file mode 100644 (file)
index 0000000..6a49588
--- /dev/null
@@ -0,0 +1,382 @@
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.examples;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import javafx.application.Application;
+import javafx.event.EventHandler;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Region;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.scene.shape.StrokeLineCap;
+import javafx.stage.Stage;
+
+public class ExampleMouseDrag2 extends Application {
+
+//    public static Image image = new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/320px-Siberischer_tiger_de_edit02.jpg");
+    public Image image = new Image("file:///home/alexandre/Desktop/tiger.jpg");
+//    public Image image = new Image( getClass().getResource( "/home/alexandre/Desktop/tiger.jpg").toExternalForm());
+
+    SelectionModel selectionModel = new SelectionModel();
+
+    DragMouseGestures dragMouseGestures = new DragMouseGestures();
+
+    static Random rnd = new Random();
+
+    @Override
+    public void start(@Nullable Stage primaryStage) {
+        if (primaryStage == null) {
+            return;
+        }
+
+        Pane pane = new Pane();
+        pane.setStyle("-fx-background-color:white");
+
+        new RubberBandSelection( pane);
+
+        double width = 200;
+        double height = 160;
+
+        double padding = 20;
+        for( int row=0; row < 4; row++) {
+            for( int col=0; col < 4; col++) {
+
+                Selectable selectable = new Selectable( width, height);
+                selectable.relocate( padding * (col+1) + width * col, padding * (row + 1) + height * row);
+
+                pane.getChildren().add(selectable);
+
+                dragMouseGestures.makeDraggable(selectable);
+
+            }
+        }
+
+        Label infoLabel = new Label( "Drag on scene for Rubberband Selection. Shift+Click to add to selection, CTRL+Click to toggle selection. Drag selected nodes for multi-dragging.");
+        pane.getChildren().add( infoLabel);
+
+        Scene scene = new Scene( pane, 1600, 900);
+        scene.getStylesheets().add( getClass().getResource("application.css").toExternalForm());
+
+        primaryStage.setScene( scene);
+        primaryStage.show();
+
+
+
+    }
+
+    private class Selectable extends Region {
+
+        ImageView view;
+
+        public Selectable( double width, double height) {
+
+            view = new ImageView( image);
+            view.setFitWidth(width);
+            view.setFitHeight(height);
+
+            getChildren().add( view);
+
+            this.setPrefSize(width, height);
+        }
+
+    }
+
+    private class SelectionModel {
+
+        Set<Node> selection = new HashSet<>();
+
+        public void add( Node node) {
+
+            if( !node.getStyleClass().contains("highlight")) {
+                node.getStyleClass().add( "highlight");
+            }
+
+            selection.add( node);
+        }
+
+        public void remove( Node node) {
+            node.getStyleClass().remove( "highlight");
+            selection.remove( node);
+        }
+
+        public void clear() {
+
+            while( !selection.isEmpty()) {
+                remove( selection.iterator().next());
+            }
+
+        }
+
+        public boolean contains( Node node) {
+            return selection.contains(node);
+        }
+
+//        public int size() {
+//            return selection.size();
+//        }
+
+        public void log() {
+            System.out.println( "Items in model: " + Arrays.asList( selection.toArray()));
+        }
+
+    }
+
+    private class DragMouseGestures {
+
+        final DragContext dragContext = new DragContext();
+
+        private boolean enabled = false;
+
+        public void makeDraggable(final Node node) {
+
+            node.setOnMousePressed(onMousePressedEventHandler);
+            node.setOnMouseDragged(onMouseDraggedEventHandler);
+            node.setOnMouseReleased(onMouseReleasedEventHandler);
+
+        }
+
+        EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
+
+            @Override
+            public void handle(MouseEvent event) {
+
+                // don't do anything if the user is in the process of adding to the selection model
+                if( event.isControlDown() || event.isShiftDown()) {
+                    return;
+                }
+
+                Node node = (Node) event.getSource();
+
+                dragContext.x = node.getTranslateX() - event.getSceneX();
+                dragContext.y = node.getTranslateY() - event.getSceneY();
+
+                // clear the model if the current node isn't in the selection => new selection
+                if( !selectionModel.contains(node)) {
+                    selectionModel.clear();
+                    selectionModel.add( node);
+                }
+
+                // flag that the mouse released handler should consume the event, so it won't bubble up to the pane which has a rubberband selection mouse released handler
+                enabled = true;
+
+                // prevent rubberband selection handler
+                event.consume();
+            }
+        };
+
+        EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
+
+            @Override
+            public void handle(MouseEvent event) {
+
+                if( !enabled) {
+                    return;
+                }
+
+                // all in selection
+                for( Node node: selectionModel.selection) {
+                    node.setTranslateX( dragContext.x + event.getSceneX());
+                    node.setTranslateY( dragContext.y + event.getSceneY());
+                }
+
+            }
+        };
+
+        EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {
+
+            @Override
+            public void handle(MouseEvent event) {
+
+                // prevent rubberband selection handler
+                if( enabled) {
+
+                    // set node's layout position to current position,remove translate coordinates
+                    for( Node node: selectionModel.selection) {
+                        fixPosition(node);
+                    }
+
+                    enabled = false;
+
+                    event.consume();
+                }
+            }
+        };
+
+        /**
+         * Set node's layout position to current position, remove translate coordinates.
+         * @param node
+         */
+        private void fixPosition( Node node) {
+
+            double x = node.getTranslateX();
+            double y = node.getTranslateY();
+
+            node.relocate(node.getLayoutX() + x, node.getLayoutY() + y);
+
+            node.setTranslateX(0);
+            node.setTranslateY(0);
+
+        }
+
+        class DragContext {
+
+            double x;
+            double y;
+
+        }
+
+    }
+
+    private class RubberBandSelection {
+
+        final DragContext dragContext = new DragContext();
+        final Rectangle rect;
+
+        Pane group;
+        boolean enabled = false;
+
+        public RubberBandSelection( Pane group) {
+
+            this.group = group;
+
+            rect = new Rectangle( 0,0,0,0);
+            rect.setStroke(Color.BLUE);
+            rect.setStrokeWidth(1);
+            rect.setStrokeLineCap(StrokeLineCap.ROUND);
+            rect.setFill(Color.LIGHTBLUE.deriveColor(0, 1.2, 1, 0.6));
+
+            group.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler);
+            group.addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler);
+            group.addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler);
+
+        }
+
+        EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
+
+            @Override
+            public void handle(MouseEvent event) {
+
+                // simple flag to prevent multiple handling of this event or we'd get an exception because rect is already on the scene
+                // eg if you drag with left mouse button and while doing that click the right mouse button
+                if( enabled) {
+                    return;
+                }
+
+                dragContext.mouseAnchorX = event.getSceneX();
+                dragContext.mouseAnchorY = event.getSceneY();
+
+                rect.setX(dragContext.mouseAnchorX);
+                rect.setY(dragContext.mouseAnchorY);
+                rect.setWidth(0);
+                rect.setHeight(0);
+
+                group.getChildren().add( rect);
+
+                event.consume();
+
+                enabled = true;
+            }
+        };
+
+        EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {
+
+            @Override
+            public void handle(MouseEvent event) {
+
+                if( !event.isShiftDown() && !event.isControlDown()) {
+                    selectionModel.clear();
+                }
+
+                for( Node node: group.getChildren()) {
+
+                    if( node instanceof Selectable) {
+                        if( node.getBoundsInParent().intersects( rect.getBoundsInParent())) {
+
+                            if( event.isShiftDown()) {
+
+                                selectionModel.add( node);
+
+                            } else if( event.isControlDown()) {
+
+                                if( selectionModel.contains( node)) {
+                                    selectionModel.remove( node);
+                                } else {
+                                    selectionModel.add( node);
+                                }
+                            } else {
+                                selectionModel.add( node);
+                            }
+
+                        }
+                    }
+
+                }
+
+                selectionModel.log();
+
+                rect.setX(0);
+                rect.setY(0);
+                rect.setWidth(0);
+                rect.setHeight(0);
+
+                group.getChildren().remove( rect);
+
+                event.consume();
+
+                enabled = false;
+            }
+        };
+
+        EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
+
+            @Override
+            public void handle(MouseEvent event) {
+
+                double offsetX = event.getSceneX() - dragContext.mouseAnchorX;
+                double offsetY = event.getSceneY() - dragContext.mouseAnchorY;
+
+                if( offsetX > 0) {
+                    rect.setWidth( offsetX);
+                } else {
+                    rect.setX(event.getSceneX());
+                    rect.setWidth(dragContext.mouseAnchorX - rect.getX());
+                }
+
+                if( offsetY > 0) {
+                    rect.setHeight( offsetY);
+                } else {
+                    rect.setY(event.getSceneY());
+                    rect.setHeight(dragContext.mouseAnchorY - rect.getY());
+                }
+
+                event.consume();
+
+            }
+        };
+
+        private final class DragContext {
+
+            public double mouseAnchorX;
+            public double mouseAnchorY;
+
+
+        }
+    }
+
+
+    public static void main(String[] args) {
+        launch(args);
+    }
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/SwtToobar2.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/SwtToobar2.java
new file mode 100644 (file)
index 0000000..a010e50
--- /dev/null
@@ -0,0 +1,78 @@
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.examples;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+@NonNullByDefault({})
+public class SwtToobar2 {
+
+    private Shell shell;
+
+    public SwtToobar2() {
+        Display display = new Display();
+        shell = new Shell(display, SWT.SHELL_TRIM);
+        shell.setLayout(new FillLayout(SWT.VERTICAL));
+        shell.setSize(50, 100);
+
+        ToolBar toolbar = new ToolBar(shell, SWT.FLAT);
+        ToolItem itemDrop = new ToolItem(toolbar, SWT.DROP_DOWN);
+        itemDrop.setText("drop menu");
+
+        itemDrop.addSelectionListener(new SelectionAdapter() {
+
+            Menu dropMenu = null;
+
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                if (dropMenu == null) {
+                    dropMenu = new Menu(shell, SWT.POP_UP);
+                    shell.setMenu(dropMenu);
+                    MenuItem itemCheck = new MenuItem(dropMenu, SWT.CHECK);
+                    itemCheck.setText("checkbox");
+                    MenuItem itemRadio = new MenuItem(dropMenu, SWT.RADIO);
+                    itemRadio.setText("radio1");
+                    MenuItem itemRadio2 = new MenuItem(dropMenu, SWT.RADIO);
+                    itemRadio2.setText("radio2");
+                }
+
+                if (e.detail == SWT.ARROW) {
+                    // Position the menu below and vertically aligned with the
+                    // the drop down tool button.
+                    final ToolItem toolItem = (ToolItem) e.widget;
+                    final ToolBar toolBar = toolItem.getParent();
+
+                    Point point = toolBar.toDisplay(new Point(e.x, e.y));
+                    dropMenu.setLocation(point.x, point.y);
+                    dropMenu.setVisible(true);
+                }
+
+            }
+
+        });
+
+        shell.open();
+
+        while (!shell.isDisposed()) {
+            if (!display.readAndDispatch()) {
+                display.sleep();
+            }
+        }
+
+        display.dispose();
+    }
+
+    public static void main(String[] args) {
+        new SwtToobar2();
+    }
+
+}
\ No newline at end of file
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/TestSwtToolbar.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/TestSwtToolbar.java
new file mode 100644 (file)
index 0000000..0706130
--- /dev/null
@@ -0,0 +1,62 @@
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.examples;
+
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * ToolBar example snippet: place a drop down menu in a tool bar
+ *
+ * For a list of all SWT example snippets see
+ * http://www.eclipse.org/swt/snippets/
+ */
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+public class TestSwtToolbar {
+
+    public static void main(String[] args) {
+        final Display display = new Display();
+        final Shell shell = new Shell(display);
+
+        final ToolBar toolBar = new ToolBar(shell, SWT.NONE);
+        Rectangle clientArea = shell.getClientArea();
+        toolBar.setLocation(clientArea.x, clientArea.y);
+
+        final Menu menu = new Menu(shell, SWT.POP_UP);
+        for (int i = 0; i < 8; i++) {
+            MenuItem item = new MenuItem(menu, SWT.PUSH);
+            item.setText("Item " + i);
+        }
+
+        final ToolItem item = new ToolItem(toolBar, SWT.DROP_DOWN);
+        item.addListener(SWT.Selection, event -> {
+            if (event.detail == SWT.ARROW) {
+                Rectangle rect = item.getBounds();
+                Point pt = new Point(rect.x, rect.y + rect.height);
+                pt = toolBar.toDisplay(pt);
+                menu.setLocation(pt.x, pt.y);
+                menu.setVisible(true);
+            }
+        });
+
+        toolBar.pack();
+        shell.pack();
+        shell.open();
+        while (!shell.isDisposed()) {
+            if (!display.readAndDispatch()) {
+                display.sleep();
+            }
+        }
+        menu.dispose();
+        display.dispose();
+    }
+}
\ No newline at end of file
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/application.css b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/application.css
new file mode 100644 (file)
index 0000000..517666b
--- /dev/null
@@ -0,0 +1,3 @@
+.highlight {
+    -fx-effect: dropshadow(three-pass-box, red, 4, 4, 0, 0);
+}
\ No newline at end of file
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/package-info.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/examples/package-info.java
new file mode 100644 (file)
index 0000000..4003238
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc. and others
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.examples;
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/package-info.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/package-info.java
new file mode 100644 (file)
index 0000000..22015f1
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc. and others
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx;
This page took 0.076377 seconds and 5 git commands to generate.