--- /dev/null
+/*******************************************************************************
+ * 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());
+ }
+ }
+}
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
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"
--- /dev/null
+/*******************************************************************************
+ * 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));
+}
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+}
--- /dev/null
+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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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() {
+ }
+}
--- /dev/null
+###############################################################################
+# 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
--- /dev/null
+/*******************************************************************************
+ * 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;
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
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">
--- /dev/null
+/*******************************************************************************
+ * 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());
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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());
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
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",
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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);
+}
--- /dev/null
+/*******************************************************************************
+ * 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() {}
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+###############################################################################
+# 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
--- /dev/null
+/*******************************************************************************
+ * 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;
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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));
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
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,
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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() {
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
--- /dev/null
+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);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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() {
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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);
+ }
+
+}
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+.highlight {
+ -fx-effect: dropshadow(three-pass-box, red, 4, 4, 0, 0);
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * 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;
--- /dev/null
+/*******************************************************************************
+ * 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;