From: Alexandre Montplaisir Date: Wed, 27 Jul 2016 18:48:21 +0000 (-0400) Subject: [WIP] CFV Refactor X-Git-Url: http://git.efficios.com/?p=deliverable%2Ftracecompass.git;a=commitdiff_plain;h=refs%2Fheads%2Fwip-cfv-refactor [WIP] CFV Refactor To use the JavaFX views: 1) Make sure you have JavaFX installed If you use Oracle's JVM, you already have it. If you use OpenJDK, you may need to "apt-get install openjfx" or equivalent. 2) Install the following feature into your development Eclipse: e(fx)clipse - IDE It should be available from the default update sites. 3) Add the following to the Run Configuration's VM Arguments: -Dosgi.framework.extensions=org.eclipse.fx.osgi The prototype view is called "Control Flow (JFX)" and is accessible from the "Show View" menu. Change-Id: I6d8b4db85ae17579d57a150f8c44460e86d0003d Signed-off-by: Alexandre Montplaisir --- diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/views/controlflow2/ControlFlowRenderProviderTest.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/views/controlflow2/ControlFlowRenderProviderTest.java new file mode 100644 index 0000000000..7212388175 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core.tests/src/org/eclipse/tracecompass/analysis/os/linux/core/tests/views/controlflow2/ControlFlowRenderProviderTest.java @@ -0,0 +1,185 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.analysis.os.linux.core.tests.views.controlflow2; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule; +import org.eclipse.tracecompass.analysis.os.linux.core.tests.stubs.trace.KernelCtfTraceStub; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2.ControlFlowRenderProvider; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2.ControlFlowTreeElement; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRender; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; +import org.eclipse.tracecompass.statesystem.core.StateSystemUtils; +import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; +import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; +import org.eclipse.tracecompass.testtraces.ctf.CtfTestTrace; +import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; +import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for {@link ControlFlowRenderProvider}. + * + * @author Alexandre Montplaisir + */ +public class ControlFlowRenderProviderTest { + +// /** Timeout the tests after 2 minutes */ +// @Rule +// public TestRule timeoutRule = new Timeout(2, TimeUnit.MINUTES); + + private static final long NANOS_PER_SECOND = 1000000000L; + + private static final @NonNull CtfTestTrace TEST_TRACE = CtfTestTrace.KERNEL; + + private static ITmfTrace sfTrace; + private static ITmfStateSystem sfSS; + + private ControlFlowRenderProvider provider = new ControlFlowRenderProvider(); + + /** + * Test class setup + */ + @Before + public void setupClass() { + TmfTrace trace = KernelCtfTraceStub.getTrace(TEST_TRACE); + trace.traceOpened(new TmfTraceOpenedSignal(ControlFlowRenderProviderTest.class, trace, null)); + + IAnalysisModule analysis = TmfTraceUtils.getAnalysisModuleOfClass(trace, KernelAnalysisModule.class, KernelAnalysisModule.ID); + assertNotNull(analysis); + analysis.schedule(); // Should have run, just in case + analysis.waitForCompletion(); + + ITmfStateSystem ss = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID); + assertNotNull(ss); + + sfTrace = trace; + sfSS = ss; + } + + /** + * Test class teardown + */ + @After + public void teardownClass() { + if (sfTrace != null) { + /* Trace's dispose will dispose its state systems */ + sfTrace.dispose(); + } + } + + /** + * Check that the info in a render for the first second of the trace matches + * the corresponding info found in the state system. + */ + @Test + public void test1s() { + try { + final ITmfTrace trace = sfTrace; + final ITmfStateSystem ss = sfSS; + assertNotNull(trace); + assertNotNull(ss); + + final long start = trace.getStartTime().toNanos(); + final long end = start + 1 * NANOS_PER_SECOND; + + TimeGraphModelRender modelRender = provider.getRender(trace, start, end, 1); + + /* Check that the list of attributes (tree render) are the same */ + TimeGraphTreeRender treeRender = modelRender.getTreeRender(); + List treeElems = treeRender.getAllTreeElements(); + + List 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 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 tidsInSS = ss.getQuarks(threadsQuark, "*").stream() + .map(ss::getAttributeName) + .sorted() + .collect(Collectors.toList()); + + for (String tid : tidsInSS) { + int threadQuark = ss.getQuarkRelative(threadsQuark, tid); + List 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 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 ssIntervals, + List 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()); + } + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF index 3a05843db1..8fb0e9ae71 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/META-INF/MANIFEST.MF @@ -15,7 +15,8 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.tracecompass.segmentstore.core, org.eclipse.tracecompass.analysis.timing.core, org.eclipse.tracecompass.statesystem.core -Import-Package: com.google.common.base, +Import-Package: com.google.common.annotations, + com.google.common.base, com.google.common.collect, com.google.common.hash, com.google.common.primitives @@ -35,4 +36,5 @@ Export-Package: org.eclipse.tracecompass.analysis.os.linux.core.contextswitch, org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests,org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests", org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.handlers;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests", org.eclipse.tracecompass.internal.analysis.os.linux.core.latency;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests,org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.lttng2.kernel.core.tests", - org.eclipse.tracecompass.internal.analysis.os.linux.core.latency.statistics;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.analysis.os.linux.core.tests" + org.eclipse.tracecompass.internal.analysis.os.linux.core.latency.statistics;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.analysis.os.linux.core.tests", + org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.analysis.os.linux.core.tests" diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowConfigModes.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowConfigModes.java new file mode 100644 index 0000000000..6560774986 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowConfigModes.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString; + +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider.FilterMode; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider.SortingMode; + +public interface ControlFlowConfigModes { + + SortingMode SORTING_BY_TID = new SortingMode(nullToEmptyString(Messages.ControlFlowSortingModes_ByTid)); + + SortingMode SORTING_BY_THREAD_NAME = new SortingMode(nullToEmptyString(Messages.ControlFlowSortingModes_ByThreadName)); + + FilterMode FILTERING_INACTIVE_ENTRIES = new FilterMode(nullToEmptyString(Messages.ControlFlowFilterModes_InactiveEntries)); +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowRenderProvider.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowRenderProvider.java new file mode 100644 index 0000000000..c8447eca6e --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowRenderProvider.java @@ -0,0 +1,264 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule; +import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval.LineThickness; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem.StateSystemModelRenderProvider; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; +import org.eclipse.tracecompass.statesystem.core.StateSystemUtils; +import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException; +import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; +import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; +import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +public class ControlFlowRenderProvider extends StateSystemModelRenderProvider { + + private static final List SORTING_MODES = ImmutableList.of( + ControlFlowConfigModes.SORTING_BY_TID, + ControlFlowConfigModes.SORTING_BY_THREAD_NAME); + + private static final List 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 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: + * + *
    + *
  • Prio
  • + *
  • System_call
  • + *
  • Exec_name
  • + *
  • PPID
  • + *
+ * + * 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 SS_TO_TREE_RENDER_FUNCTION = (treeContext) -> { + ITmfStateSystem ss = treeContext.ss; + List fullState = treeContext.fullQueryAtRangeStart; + + Stream 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 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 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 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 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 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>> PROPERTY_MAPPING_FUNCTION = ssCtx -> { + return null; + }; + + /** + * Constructor + */ + public ControlFlowRenderProvider() { + super(SORTING_MODES, + FILTER_MODES, + /* Parameters specific to state system render providers */ + KernelAnalysisModule.ID, + SS_TO_TREE_RENDER_FUNCTION, + STATE_NAME_MAPPING_FUNCTION, + COLOR_MAPPING_FUNCTION, + LINE_THICKNESS_MAPPING_FUNCTION, + PROPERTY_MAPPING_FUNCTION); + + enableFilterMode(0); + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowTreeElement.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowTreeElement.java new file mode 100644 index 0000000000..3964d12399 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/ControlFlowTreeElement.java @@ -0,0 +1,51 @@ +package org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2; + +import java.util.List; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem.StateSystemTimeGraphTreeElement; + +public class ControlFlowTreeElement extends StateSystemTimeGraphTreeElement { + + private static final String UNKNOWN_THREAD_NAME = "???"; //$NON-NLS-1$ + + private final int fTid; + private final String fThreadName; + + public ControlFlowTreeElement(String tidStr, @Nullable String threadName, + List children, int sourceQuark) { + super(getElementName(tidStr, threadName), + children, + sourceQuark); + + if (tidStr.startsWith(Attributes.THREAD_0_PREFIX)) { + fTid = 0; + } else { + fTid = Integer.parseInt(tidStr); + } + + fThreadName = (threadName == null ? UNKNOWN_THREAD_NAME : threadName); + } + + private static String getElementName(String tidStr, @Nullable String threadName) { + String tidPart = tidStr; + if (tidPart.startsWith(Attributes.THREAD_0_PREFIX)) { + /* Display "0/0" instead of "0_0" */ + tidPart = tidPart.replace('_', '/'); + } + + String threadNamePart = (threadName == null ? UNKNOWN_THREAD_NAME : threadName); + return (tidPart + " - " + threadNamePart); //$NON-NLS-1$ + } + + public int getTid() { + return fTid; + } + + public String getThreadName() { + return fThreadName; + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/Messages.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/Messages.java new file mode 100644 index 0000000000..ddf18e32b3 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/Messages.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + + +package org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.osgi.util.NLS; + +/** + * Messages class + * + * @author Alexandre Montplaisir + */ +@SuppressWarnings("javadoc") +@NonNullByDefault({}) +public class Messages extends NLS { + + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ + + public static String ControlFlowRenderProvider_State_WaitUnknown; + public static String ControlFlowRenderProvider_State_WaitBlocked; + public static String ControlFlowRenderProvider_State_WaitForCpu; + public static String ControlFlowRenderProvider_State_UserMode; + public static String ControlFlowRenderProvider_State_Syscall; + public static String ControlFlowRenderProvider_State_Interrupted; + public static String ControlFlowRenderProvider_State_Unknown; + + public static String ControlFlowSortingModes_ByTid; + public static String ControlFlowSortingModes_ByThreadName; + + public static String ControlFlowFilterModes_InactiveEntries; + + static { + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/messages.properties b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/messages.properties new file mode 100644 index 0000000000..8df078e14a --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/messages.properties @@ -0,0 +1,21 @@ +############################################################################### +# Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################### + +ControlFlowRenderProvider_State_WaitUnknown = WAIT_UNKNOWN +ControlFlowRenderProvider_State_WaitBlocked = WAIT_BLOCKED +ControlFlowRenderProvider_State_WaitForCpu = WAIT_FOR_CPU +ControlFlowRenderProvider_State_UserMode = USERMODE +ControlFlowRenderProvider_State_Syscall = SYSCALL +ControlFlowRenderProvider_State_Interrupted = INTERRUPTED +ControlFlowRenderProvider_State_Unknown = UNKNOWN + +ControlFlowSortingModes_ByTid = Sort by TID +ControlFlowSortingModes_ByThreadName = Sort by Thread Name + +ControlFlowFilterModes_InactiveEntries = Filter inactive entries diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/package-info.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/package-info.java new file mode 100644 index 0000000000..8f9306664e --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.core/src/org/eclipse/tracecompass/internal/analysis/os/linux/core/views/controlflow2/package-info.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2; diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties index 2826638360..b743add7f0 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.properties @@ -26,4 +26,7 @@ latency.density.view.name = System Call Density kernelmemoryusageview.view.name = Kernel Memory Usage View diskioactivity.view.name = Disk I/O Activity -perspective.name = OS Tracing Overview \ No newline at end of file +perspective.name = OS Tracing Overview + +controlflow2.swt.view.name = Control Flow (staging) +controlflow2.swtjfx.view.name = Control Flow (JFX) \ No newline at end of file diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml index 0137f5b797..97392c2ec0 100644 --- a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/plugin.xml @@ -81,6 +81,23 @@ name="%diskioactivity.view.name" restorable="true"> + + + + diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtControlFlowView.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtControlFlowView.java new file mode 100644 index 0000000000..60548342bd --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtControlFlowView.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow2; + +import org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2.ControlFlowRenderProvider; +import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swt.SwtTimeGraphView; + +public class SwtControlFlowView extends SwtTimeGraphView { + + private static final String VIEW_ID = "org.eclipse.tracecompass.analysis.os.linux.views.controlflow2.swt"; //$NON-NLS-1$ + + public SwtControlFlowView() { + super(VIEW_ID, new ControlFlowRenderProvider()); + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtJfxControlFlowView.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtJfxControlFlowView.java new file mode 100644 index 0000000000..454d45043f --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/SwtJfxControlFlowView.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow2; + +import org.eclipse.tracecompass.internal.analysis.os.linux.core.views.controlflow2.ControlFlowRenderProvider; +import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.SwtJfxTimeGraphView; + +public class SwtJfxControlFlowView extends SwtJfxTimeGraphView { + + private static final String VIEW_ID = "org.eclipse.tracecompass.analysis.os.linux.views.controlflow2.swtjfx"; //$NON-NLS-1$ + + public SwtJfxControlFlowView() { + super(VIEW_ID, new ControlFlowRenderProvider()); + } + +} diff --git a/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/package-info.java b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/package-info.java new file mode 100644 index 0000000000..3574722e45 --- /dev/null +++ b/analysis/org.eclipse.tracecompass.analysis.os.linux.ui/src/org/eclipse/tracecompass/internal/analysis/os/linux/ui/views/controlflow2/package-info.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow2; diff --git a/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF b/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF index a7722916a2..54224be2af 100644 --- a/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF +++ b/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF @@ -14,7 +14,14 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.tracecompass.segmentstore.core, org.eclipse.tracecompass.statesystem.core;visibility:=reexport, org.eclipse.cdt.core -Export-Package: org.eclipse.tracecompass.internal.tmf.core;x-friends:="org.eclipse.tracecompass.tmf.core.tests,org.eclipse.tracecompass.tmf.ui.swtbot.tests", +Export-Package: org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + x-friends:="org.eclipse.tracecompass.analysis.os.linux.core, + org.eclipse.tracecompass.analysis.os.linux.core.tests, + org.eclipse.tracecompass.analysis.os.linux.ui, + org.eclipse.tracecompass.tmf.ui, + org.eclipse.tracecompass.tmf.ui.tests", + org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core,org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.analysis.os.linux.core.tests", + org.eclipse.tracecompass.internal.tmf.core;x-friends:="org.eclipse.tracecompass.tmf.core.tests,org.eclipse.tracecompass.tmf.ui.swtbot.tests", org.eclipse.tracecompass.internal.tmf.core.analysis;x-friends:="org.eclipse.tracecompass.tmf.core.tests", org.eclipse.tracecompass.internal.tmf.core.callstack;x-friends:="org.eclipse.tracecompass.tmf.ui,org.eclipse.tracecompass.tmf.core.tests", org.eclipse.tracecompass.internal.tmf.core.component;x-friends:="org.eclipse.tracecompass.tmf.core.tests", diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ColorDefinition.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ColorDefinition.java new file mode 100644 index 0000000000..5e61ab99a3 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ColorDefinition.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import java.util.Objects; + +import org.eclipse.jdt.annotation.Nullable; + +public class ColorDefinition { + + public static final int MIN = 0; + public static final int MAX = 255; + + public final int fRed; + public final int fGreen; + public final int fBlue; + public final int fAlpha; + + public ColorDefinition(int red, int green, int blue) { + this(red, green, blue, MAX); + } + + public ColorDefinition(int red, int green, int blue, int alpha) { + checkValue(red); + checkValue(green); + checkValue(blue); + checkValue(alpha); + + fRed = red; + fGreen = green; + fBlue = blue; + fAlpha = alpha; + } + + private static void checkValue(int value) throws IllegalArgumentException { + if (value < MIN || value > MAX) { + throw new IllegalArgumentException(); + } + } + + @Override + public int hashCode() { + return Objects.hash(fRed, fGreen, fBlue, fAlpha); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ColorDefinition other = (ColorDefinition) obj; + if (fAlpha != other.fAlpha || + fBlue != other.fBlue || + fGreen != other.fGreen || + fRed != other.fRed) { + return false; + } + return true; + } + + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ITimeGraphModelRenderProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ITimeGraphModelRenderProvider.java new file mode 100644 index 0000000000..7a5ec40786 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/ITimeGraphModelRenderProvider.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import java.util.List; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +public interface ITimeGraphModelRenderProvider { + + // ------------------------------------------------------------------------ + // Configuration option classes + // ------------------------------------------------------------------------ + + class SortingMode { + + private final String fName; + + public SortingMode(String name) { + fName = name; + } + + public String getName() { + return fName; + } + } + + class FilterMode { + + private final String fName; + + public FilterMode(String name) { + fName = name; + } + + public String getName() { + return fName; + } + } + + // ------------------------------------------------------------------------ + // Render generation methods + // ------------------------------------------------------------------------ + + default TimeGraphModelRender getRender(ITmfTrace trace, + long rangeStart, long rangeEnd, long resolution) { + return getRender(trace, rangeStart, rangeEnd, resolution, null); + } + + TimeGraphModelRender getRender(ITmfTrace trace, long rangeStart, long rangeEnd, + long resolution, @Nullable IProgressMonitor monitor); + + // ------------------------------------------------------------------------ + // Sorting modes + // ------------------------------------------------------------------------ + + List getSortingModes(); + + SortingMode getCurrentSortingMode(); + + void setCurrentSortingMode(int index); + + // ------------------------------------------------------------------------ + // Filter modes + // ------------------------------------------------------------------------ + + List getFilterModes(); + + void enableFilterMode(int index); + + void disableFilterMode(int index); + + Set getActiveFilterModes(); + + // ------------------------------------------------------------------------ + // Other configuration options + // ------------------------------------------------------------------------ + + /** + * Set the time range configuration option. The timestamps should normally + * refer to a valid time range within the backing trace or other database. + * For GUI views it will usually refer to the visible time range of a + * zoomed-in viewport. + * + * This can then be used by other configuration options. For example, a + * filtering mode could be provided to filter out entries that do not change + * state within the configured time range. + * + * The implementation is free to ignore the configured time range if it does + * not provide anything special for it. + * + * @param startTime + * The start of the configured time range + * @param endTime + * The end of the configured time range. + */ + void setConfiguredTimeRange(long startTime, long endTime); +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/Messages.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/Messages.java new file mode 100644 index 0000000000..130fbb875f --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/Messages.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.osgi.util.NLS; + +/** + * Package message bundle + * + * @noreference Messages class + */ +@NonNullByDefault({}) +@SuppressWarnings("javadoc") +public class Messages extends NLS { + + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ + + public static String DefaultSortingModeName; + + static { + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() {} +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrow.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrow.java new file mode 100644 index 0000000000..f1c4b2121d --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrow.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +public class TimeGraphArrow { + + private final TimeGraphEvent fStartEvent; + private final TimeGraphEvent fEndEvent; + + public TimeGraphArrow(TimeGraphEvent startEvent, TimeGraphEvent endEvent) { + fStartEvent = startEvent; + fEndEvent = endEvent; + } + + public TimeGraphEvent getStartEvent() { + return fStartEvent; + } + + public TimeGraphEvent getEndEvent() { + return fEndEvent; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrowSeries.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrowSeries.java new file mode 100644 index 0000000000..398c5f785d --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphArrowSeries.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import java.util.Collection; + +import com.google.common.collect.ImmutableList; + +public class TimeGraphArrowSeries { + + public enum LineStyle { + FULL, + DOTTED, + DASHED; + } + + private final String fSeriesName; + private final ColorDefinition fColor; + private final LineStyle fLineStyle; + private final Collection fArrows; + + public TimeGraphArrowSeries(String seriesName, ColorDefinition color, + LineStyle lineStyle, Collection 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 getArrows() { + return fArrows; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphDrawnEvent.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphDrawnEvent.java new file mode 100644 index 0000000000..7a9f6f0095 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphDrawnEvent.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import java.util.Collections; +import java.util.Map; +import java.util.function.Supplier; + +import org.eclipse.jdt.annotation.Nullable; + +public class TimeGraphDrawnEvent { + + public enum SymbolStyle { + CIRCLE, + CROSS, + STAR; + } + + private final TimeGraphEvent fTimeGraphEvent; + private final String fEventName; + private final ColorDefinition fColor; + private final SymbolStyle fSymbolStyle; + private final @Nullable Supplier> fPropertySupplier; + + public TimeGraphDrawnEvent(TimeGraphEvent event, String eventName, + ColorDefinition color, SymbolStyle style, + @Nullable Supplier> 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 getProperties() { + Supplier> supplier = fPropertySupplier; + if (supplier == null) { + return Collections.EMPTY_MAP; + } + return supplier.get(); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphEvent.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphEvent.java new file mode 100644 index 0000000000..0ff6e6d291 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphEvent.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +public class TimeGraphEvent { + + private final long fTimestamp; + private final TimeGraphTreeElement fTreeElement; + + public TimeGraphEvent(long timestamp, TimeGraphTreeElement treeElement) { + fTimestamp = timestamp; + fTreeElement = treeElement; + } + + public long getTimestamp() { + return fTimestamp; + } + + public TimeGraphTreeElement getTreeElement() { + return fTreeElement; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRender.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRender.java new file mode 100644 index 0000000000..444cbb0d0e --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRender.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import com.google.common.collect.ImmutableList; + +public class TimeGraphModelRender { + + public static final TimeGraphModelRender EMPTY_RENDER = + new TimeGraphModelRender(0, 0, + new TimeGraphTreeRender(Collections.EMPTY_LIST), + Collections.EMPTY_LIST, + Collections.EMPTY_LIST, + Collections.EMPTY_LIST); + + private final long fStartTime; + private final long fEndTime; + private final TimeGraphTreeRender fTreeRender; + private final List> fStateIntervals; + private final List> fDrawnEvents; + private final Collection fArrowSeries; + + public TimeGraphModelRender(long startTime, long endTime, + TimeGraphTreeRender treeRender, + List> stateIntervals, + List> drawnEvents, + Collection 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> getStateIntervals() { + return fStateIntervals; + } + + public List> getDrawnEvents() { + return fDrawnEvents; + } + + public Collection getArrowsSeries() { + return fArrowSeries; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRenderProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRenderProvider.java new file mode 100644 index 0000000000..2181506238 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphModelRenderProvider.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.jdt.annotation.Nullable; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +public abstract class TimeGraphModelRenderProvider implements ITimeGraphModelRenderProvider { + + protected static final SortingMode DEFAULT_SORTING_MODE = new SortingMode(nullToEmptyString(Messages.DefaultSortingModeName)); + + private final List fSortingModes; + private final List fFilterModes; + + private SortingMode fCurrentSortingMode; + private Set fActiveFilterModes = new HashSet<>(); + + private long fConfiguredTimeRangeStart = 0L; + private long fConfiguredTimeRangeEnd = Long.MAX_VALUE; + + protected TimeGraphModelRenderProvider(@Nullable List sortingModes, + @Nullable List 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 getSortingModes() { + return fSortingModes; + } + + @Override + public SortingMode getCurrentSortingMode() { + return fCurrentSortingMode; + } + + @Override + public void setCurrentSortingMode(int index) { + fCurrentSortingMode = fSortingModes.get(index); + } + + // ------------------------------------------------------------------------ + // Filter modes + // ------------------------------------------------------------------------ + + @Override + public List 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 getActiveFilterModes() { + return ImmutableSet.copyOf(fActiveFilterModes); + } + + // ------------------------------------------------------------------------ + // Other configuration options + // ------------------------------------------------------------------------ + + public long getConfiguredTimeRangeStart() { + return fConfiguredTimeRangeStart; + } + + public long getConfiguredTimeRangeEnd() { + return fConfiguredTimeRangeEnd; + } + + @Override + public void setConfiguredTimeRange(long start, long end) { + if (start < 0 || start > end) { + throw new IllegalArgumentException(); + } + fConfiguredTimeRangeStart = start; + fConfiguredTimeRangeEnd = end; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphStateInterval.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphStateInterval.java new file mode 100644 index 0000000000..553948593f --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphStateInterval.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import java.util.Collections; +import java.util.Map; +import java.util.function.Supplier; + +import org.eclipse.jdt.annotation.Nullable; + +import com.google.common.base.Objects; + +public class TimeGraphStateInterval { + + public enum LineThickness { + NORMAL, + SMALL + } + + private final TimeGraphEvent fStartEvent; + private final TimeGraphEvent fEndEvent; + + private final String fStateName; + private final ColorDefinition fColor; + private final LineThickness fLineThickness; + + private final @Nullable Supplier> fPropertySupplier; + + public TimeGraphStateInterval(long start, + long end, + TimeGraphTreeElement treeElement, + String stateName, + ColorDefinition color, + LineThickness lineThickness, + @Nullable Supplier> 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 getProperties() { + Supplier> supplier = fPropertySupplier; + if (supplier == null) { + return Collections.EMPTY_MAP; + } + return supplier.get(); + } + + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("start", fStartEvent.getTimestamp()) + .add("end", fEndEvent.getTimestamp()) + .add("name", fStateName) + .toString(); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeElement.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeElement.java new file mode 100644 index 0000000000..4843fd245c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeElement.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import java.util.List; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; + +public class TimeGraphTreeElement { + + private final String fName; + private final List fChildElements; + + public TimeGraphTreeElement(String name, List children) { + fName = name; + fChildElements = ImmutableList.copyOf(children); + } + + public String getName() { + return fName; + } + + public List getChildElements() { + return fChildElements; + } + + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("fName", fName) //$NON-NLS-1$ + .add("fChildElements", fChildElements.toString()) //$NON-NLS-1$ + .toString(); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeModel.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeModel.java new file mode 100644 index 0000000000..5502667f0c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeModel.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.google.common.collect.ImmutableList; + +public class TimeGraphTreeModel { + + private final List 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 list = ImmutableList.copyOf(fTreeElements); + return new TimeGraphTreeRender(list); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeRender.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeRender.java new file mode 100644 index 0000000000..ad2ce5dcd8 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/TimeGraphTreeRender.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; + +import java.util.List; + +import com.google.common.collect.ImmutableList; + +public class TimeGraphTreeRender { + + private final List fTreeElements; + + public TimeGraphTreeRender(List elements) { + fTreeElements = ImmutableList.copyOf(elements); + } + + public List getAllTreeElements() { + return fTreeElements; + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/messages.properties b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/messages.properties new file mode 100644 index 0000000000..96fad2f2c3 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/messages.properties @@ -0,0 +1,10 @@ +############################################################################### +# Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +############################################################################### + +DefaultSortingModeName = Default diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/package-info.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/package-info.java new file mode 100644 index 0000000000..aaf6b5e335 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/package-info.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2; diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemModelRenderProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemModelRenderProvider.java new file mode 100644 index 0000000000..60ecb2fb03 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemModelRenderProvider.java @@ -0,0 +1,217 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRender; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRenderProvider; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval.LineThickness; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; +import org.eclipse.tracecompass.statesystem.core.StateSystemUtils; +import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; +import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException; +import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval; +import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +public abstract class StateSystemModelRenderProvider extends TimeGraphModelRenderProvider { + + /** + * The context of a tree render. Should contain all the information to + * generate the corresponding tree render, according to all configuration + * options like sorting, filtering etc. specified by the user. + */ + protected static final class TreeRenderContext { + + public final ITmfStateSystem ss; + public final SortingMode sortingMode; + public final Set filterModes; + public final long renderTimeRangeStart; + public final long renderTimeRangeEnd; + public final List fullQueryAtRangeStart; + + public TreeRenderContext(ITmfStateSystem ss, + SortingMode sortingMode, + Set filterModes, + long renderTimeRangeStart, + long renderTimeRangeEnd, + List 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 fullQueryAtIntervalStart; + + public StateIntervalContext(ITmfStateSystem ss, + StateSystemTimeGraphTreeElement baseTreeElement, + ITmfStateInterval sourceInterval, + List fullQueryAtIntervalStart) { + this.ss = ss; + this.baseTreeElement = baseTreeElement; + this.sourceInterval = sourceInterval; + this.fullQueryAtIntervalStart = fullQueryAtIntervalStart; + } + } + + private final String fStateSystemModuleId; + private final Function fTreeRenderFunction; + private final Function fIntervalMappingFunction; + +// private final Map fLastTreeRenders = new WeakHashMap<>(); + + /** + * @param stateSystemModuleId + * @param stateNameMappingFunction + * @param colorMappingFunction + * @param lineThicknessMappingFunction + * @param propertyMappingFunction + * @param baseQuarkPattern + */ + protected StateSystemModelRenderProvider( + @Nullable List sortingModes, + @Nullable List filterModes, + String stateSystemModuleId, + Function treeRenderFunction, + Function stateNameMappingFunction, + Function colorMappingFunction, + Function lineThicknessMappingFunction, + Function>> 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 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> stateIntervals = treeRender.getAllTreeElements().stream() + .map(treeElem -> (StateSystemTimeGraphTreeElement) treeElem) // FIXME, generic type? + .map(treeElem -> { + List 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 fullState; + try { + fullState = ss.queryFullState(interval.getStartTime()); + } catch (StateSystemDisposedException e) { + fullState = Collections.emptyList(); + } + return new StateIntervalContext(ss, treeElem, interval, fullState); + }) + .map(fIntervalMappingFunction) + .collect(Collectors.toList()); + }) + .collect(Collectors.toList()); + + /* TODO Prepare the drawn events */ + + /* TODO Prepare the arrows series */ + + TimeGraphModelRender render = new TimeGraphModelRender( + rangeStart, rangeEnd, + treeRender, + stateIntervals, + Collections.EMPTY_LIST, + Collections.EMPTY_LIST); + return render; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemTimeGraphTreeElement.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemTimeGraphTreeElement.java new file mode 100644 index 0000000000..239d06bbe9 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/StateSystemTimeGraphTreeElement.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem; + +import java.util.List; + +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeElement; + +public class StateSystemTimeGraphTreeElement extends TimeGraphTreeElement { + + private final int fSourceQuark; + + public StateSystemTimeGraphTreeElement(String name, + List children, + int sourceQuark) { + super(name, children); + fSourceQuark = sourceQuark; + } + + public int getSourceQuark() { + return fSourceQuark; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/package-info.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/package-info.java new file mode 100644 index 0000000000..6d3472b6f1 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/views/timegraph2/statesystem/package-info.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.statesystem; diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStaticTest.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStaticTest.java new file mode 100644 index 0000000000..db1bc21329 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStaticTest.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.tmf.ui.tests.views.timegraph2.swtjfx; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.SwtJfxTimeGraphViewer; +import org.junit.Test; + +public class SwtJfxTimeGraphViewerStaticTest { + + private static final double DELTA = 0.1; + + /** + * Test area consisting of 100 pixels representing a timerange from 1000 to + * 2000. + */ + private static class TestArea1 { + private static final long START_TIMESTAMP = 1000; + private static final long END_TIMESTAMP = 2000; + private static final double NANOS_PER_PIXEL = 10.0; + } + + @Test + public void testTimeToPosition() { + double yPos = SwtJfxTimeGraphViewer.timestampToPaneXPos(1500, + TestArea1.START_TIMESTAMP, + TestArea1.END_TIMESTAMP, + TestArea1.NANOS_PER_PIXEL); + assertEquals(50.0, yPos, DELTA); + + long start = 1332170682440133097L; + long end = 1332170692664579801L; + long ts1 = 1332170683481793497L; + long ts2 = 1332170683485732407L; + double yPos1 = SwtJfxTimeGraphViewer.timestampToPaneXPos(ts1, start, end, 10.0); + double yPos2 = SwtJfxTimeGraphViewer.timestampToPaneXPos(ts2, start, end, 10.0); + assertEquals(104166039.959, yPos1, DELTA); + assertEquals(104559930.959, yPos2, DELTA); + + } + + @Test + public void testPositionToTimestamp() { + long ts = SwtJfxTimeGraphViewer.paneXPosToTimestamp(50.0, + TestArea1.START_TIMESTAMP * TestArea1.NANOS_PER_PIXEL, + TestArea1.START_TIMESTAMP, + TestArea1.NANOS_PER_PIXEL); + assertEquals(1500, ts); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerTest.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerTest.java new file mode 100644 index 0000000000..2a751e17b2 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerTest.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.tmf.ui.tests.views.timegraph2.swtjfx; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tracecompass.tmf.core.signal.TmfSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager; +import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal; +import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange; +import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class SwtJfxTimeGraphViewerTest { + +// private static final double DELTA = 0.1; + + private static final long FULL_TRACE_START_TIME = 100000L; + private static final long FULL_TRACE_END_TIME = 200000L; + + private @Nullable SwtJfxTimeGraphViewerStub fViewer; + + @Before + public void setup() { + Shell shell = checkNotNull(Display.getDefault().getActiveShell()); + SwtJfxTimeGraphViewerStub viewer = new SwtJfxTimeGraphViewerStub(shell, new ModelRenderProviderStub()); + viewer.setTimeGraphAreaRange(FULL_TRACE_START_TIME, FULL_TRACE_END_TIME); + + viewer.getTimeGraphScrollPane().setMinWidth(1000.0); + fViewer = viewer; + } + + @After + public void tearDown() { + if (fViewer != null) { + fViewer.dispose(); + } + fViewer = null; + } + + @Test + public void testSeekVisibleRange() { + SwtJfxTimeGraphViewerStub viewer = checkNotNull(fViewer); + + TmfTimeRange range = createTimeRange(150000L, 160000L); + TmfSignal signal = new TmfWindowRangeUpdatedSignal(this, range); + TmfSignalManager.dispatchSignal(signal); + + double visibleWidth = viewer.getTimeGraphScrollPane().getWidth(); + System.out.println("width=" + visibleWidth); + } + + @Test + public void testZoomOut() { + + } + + private static TmfTimeRange createTimeRange(long start, long end) { + return new TmfTimeRange(TmfTimestamp.fromNanos(start), TmfTimestamp.fromNanos(end)); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/ModelRenderProviderStub.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/ModelRenderProviderStub.java new file mode 100644 index 0000000000..878b7a78ec --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/ModelRenderProviderStub.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.tmf.ui.tests.views.timegraph2.swtjfx; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRender; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRenderProvider; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +public class ModelRenderProviderStub extends TimeGraphModelRenderProvider { + + protected ModelRenderProviderStub() { + super(null, null); + } + + @Override + public @NonNull TimeGraphModelRender getRender(@NonNull ITmfTrace trace, long rangeStart, long rangeEnd, long resolution, @Nullable IProgressMonitor monitor) { + return TimeGraphModelRender.EMPTY_RENDER; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStub.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStub.java new file mode 100644 index 0000000000..820fa9ed9d --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/SwtJfxTimeGraphViewerStub.java @@ -0,0 +1,34 @@ +package org.eclipse.tracecompass.tmf.ui.tests.views.timegraph2.swtjfx; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider; +import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx.SwtJfxTimeGraphViewer; + +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.Pane; + +public class SwtJfxTimeGraphViewerStub extends SwtJfxTimeGraphViewer { + + public SwtJfxTimeGraphViewerStub(Composite parent, ITimeGraphModelRenderProvider provider) { + super(parent, provider); + } + + // ------------------------------------------------------------------------ + // Visibility-increasing overrides + // ------------------------------------------------------------------------ + + @Override + public void setTimeGraphAreaRange(long fullAreaStartTime, long fullAreaEndTime) { + super.setTimeGraphAreaRange(fullAreaStartTime, fullAreaEndTime); + } + + @Override + protected Pane getTimeGraphPane() { + return super.getTimeGraphPane(); + } + + @Override + protected ScrollPane getTimeGraphScrollPane() { + return super.getTimeGraphScrollPane(); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/package-info.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/package-info.java new file mode 100644 index 0000000000..ac75f7b47e --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui.tests/widgetStubs/org/eclipse/tracecompass/tmf/ui/tests/views/timegraph2/swtjfx/package-info.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.tmf.ui.tests.views.timegraph2.swtjfx; diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF b/tmf/org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF index 6dfaeac829..0ba62fee6e 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF +++ b/tmf/org.eclipse.tracecompass.tmf.ui/META-INF/MANIFEST.MF @@ -26,7 +26,10 @@ Require-Bundle: org.eclipse.core.expressions, org.eclipse.linuxtools.dataviewers.piechart, org.eclipse.tracecompass.segmentstore.core, org.apache.commons.compress -Export-Package: org.eclipse.tracecompass.internal.tmf.ui;x-friends:="org.eclipse.tracecompass.tmf.ui.tests,org.eclipse.tracecompass.tmf.ctf.ui.tests", +Export-Package: org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2;x-friends:="org.eclipse.tracecompass.tmf.ui.tests", + org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swt;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui", + org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx;x-friends:="org.eclipse.tracecompass.analysis.os.linux.ui,org.eclipse.tracecompass.tmf.ui.tests", + org.eclipse.tracecompass.internal.tmf.ui;x-friends:="org.eclipse.tracecompass.tmf.ui.tests,org.eclipse.tracecompass.tmf.ctf.ui.tests", org.eclipse.tracecompass.internal.tmf.ui.commands;x-internal:=true, org.eclipse.tracecompass.internal.tmf.ui.dialogs;x-internal:=true, org.eclipse.tracecompass.internal.tmf.ui.editors;x-internal:=true, diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/SignallingContext.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/SignallingContext.java new file mode 100644 index 0000000000..3c810d2f4b --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/SignallingContext.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2; + +import java.util.logging.Logger; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.common.core.log.TraceCompassLog; +import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; +import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager; +import org.eclipse.tracecompass.tmf.core.signal.TmfSignalThrottler; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; +import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal; +import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange; +import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +public class SignallingContext { + + private static final Logger LOGGER = TraceCompassLog.getLogger(SignallingContext.class); + + private static final int SIGNAL_DELAY_MS = 200; + + private final TmfSignalThrottler fVisibleRangeSignalThrottler = new TmfSignalThrottler(null, SIGNAL_DELAY_MS); + + private final TimeGraphModelViewer fViewer; + + private @Nullable ITmfTrace fCurrentTrace = null; + + public SignallingContext(TimeGraphModelViewer viewer) { + TmfSignalManager.register(this); + fViewer = viewer; + } + + public void dispose() { + TmfSignalManager.deregister(this); + } + + @Nullable ITmfTrace getCurrentTrace() { + return fCurrentTrace; + } + + public void sendTimeRangeSelectionUpdate(long startTs, long endTs) { + TmfSignal signal = new TmfSelectionRangeUpdatedSignal(this, + TmfTimestamp.fromNanos(startTs), + TmfTimestamp.fromNanos(endTs)); + TmfSignalManager.dispatchSignal(signal); + } + + public void sendVisibleWindowRangeUpdate(long startTs, long endTs) { + TmfSignal signal = new TmfWindowRangeUpdatedSignal(this, + new TmfTimeRange(TmfTimestamp.fromNanos(startTs), TmfTimestamp.fromNanos(endTs))); + fVisibleRangeSignalThrottler.queue(signal); + } + + public void initializeForTrace(@Nullable ITmfTrace trace) { + fCurrentTrace = trace; + + if (trace == null) { + // TODO Clear the viewer? + return; + } + + long traceStartTime = trace.getStartTime().toNanos(); + long traceEndTime = trace.getEndTime().toNanos(); + + /* The window's start time is the same as the trace's start time initially */ + long windowStartTime = traceStartTime; + long windowEndtime = Math.min(traceEndTime, traceStartTime + trace.getInitialRangeOffset().toNanos()); + + fViewer.setTimeGraphAreaRange(traceStartTime, traceEndTime); + fViewer.seekVisibleRange(windowStartTime, windowEndtime); + fViewer.paintArea(trace, windowStartTime, windowEndtime); + } + + // ------------------------------------------------------------------------ + // Signal handlers + // ------------------------------------------------------------------------ + + @TmfSignalHandler + public void traceOpened(TmfTraceOpenedSignal signal) { + LOGGER.fine(() -> "[SignallingContext:ReceivedTraceOpen] trace=" + signal.getTrace().toString()); //$NON-NLS-1$ + + ITmfTrace newTrace = signal.getTrace(); + fCurrentTrace = newTrace; + initializeForTrace(newTrace); + } + + @TmfSignalHandler + public void traceSelected(final TmfTraceSelectedSignal signal) { + LOGGER.fine(() -> "[SignallingContext:ReceivedTraceSelected] trace=" + signal.getTrace().toString()); + + ITmfTrace newTrace = signal.getTrace(); + fCurrentTrace = newTrace; + initializeForTrace(newTrace); + } + + /** + * @param signal + */ + @TmfSignalHandler + public void traceClosed(final TmfTraceClosedSignal signal) { + LOGGER.fine(() -> "[SignallingContext:ReceivedTraceClosed] " + //$NON-NLS-1$ + signal.getTrace().getName()); + + // How does this signal work anyway? + // TODO Implement this! + //fViewer.clearViewer() + } + + /** + * @param signal + */ + @TmfSignalHandler + public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal) { + long rangeStart = signal.getRange().getStartTime().toNanos(); + long rangeEnd = signal.getRange().getEndTime().toNanos(); + + LOGGER.finer(() -> "[SignallingContext:ReceivedTraceRangeUpdated] " + //$NON-NLS-1$ + String.format("rangeStart=%,d, rangeEnd=%,d", //$NON-NLS-1$ + rangeStart, rangeEnd)); + /* + * This signal is a disaster, it's very inconsistent, has no guarantee + * of even showing up and sometimes gives values outside of the trace's + * own range. Best to ignore its contents completely. + */ + + ITmfTrace trace = fCurrentTrace; + if (trace != null) { + long traceStart = trace.getStartTime().toNanos(); + long traceEnd = trace.getEndTime().toNanos(); + fViewer.setTimeGraphAreaRange(traceStart, traceEnd); + } + } + + /** + * @param signal + */ + @TmfSignalHandler + public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) { + long rangeStart = signal.getBeginTime().toNanos(); + long rangeEnd = signal.getEndTime().toNanos(); + + LOGGER.finer(() -> "[SignallingContext:ReceivedSelectionRangeUpdated] " + //$NON-NLS-1$ + String.format("rangeStart=%,d, rangeEnd=%,d", //$NON-NLS-1$ + rangeStart, rangeEnd)); + + if (rangeStart > rangeEnd) { + /* This signal's end can be before its start time, against all logic */ + fViewer.drawSelection(rangeEnd, rangeStart); + } else { + fViewer.drawSelection(rangeStart, rangeEnd); + } + } + + /** + * @param signal + */ + @TmfSignalHandler + public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) { + ITmfTrace trace = fCurrentTrace; + if (trace == null) { + return; + } + + long traceStart = trace.getStartTime().toNanos(); + long traceEnd = trace.getEndTime().toNanos(); + + TmfTimeRange windowRange = signal.getCurrentRange(); + long windowStart = Math.max(traceStart, windowRange.getStartTime().toNanos()); + long windowEnd = Math.min(traceEnd, windowRange.getEndTime().toNanos()); + + LOGGER.finer(() -> "[SignallingContext:ReceivedWindowRangeUpdated] " + //$NON-NLS-1$ + String.format("windowStart=%,d, windowEnd=%,d", //$NON-NLS-1$ + windowStart, windowEnd)); + + fViewer.setTimeGraphAreaRange(traceStart, traceEnd); + + if (signal.getSource() != this) { + /* + * If the signal came from the time graph's own scrollbar, then the + * zoom level did not change, and the view is already at the + * position we want it. + * + * TODO May not be true when it comes from a zoom in/out event + */ + fViewer.seekVisibleRange(windowStart, windowEnd); + } else { + fViewer.updateLatestVisibleRange(windowStart, windowEnd); + } + + fViewer.paintArea(trace, windowStart, windowEnd); + } +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelView.java new file mode 100644 index 0000000000..e4c4871fac --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelView.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2; + +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider; +import org.eclipse.tracecompass.tmf.ui.views.TmfView; + +public abstract class TimeGraphModelView extends TmfView { + + private final ITimeGraphModelRenderProvider fTimeGraphProvider; + + protected TimeGraphModelView(String viewName, ITimeGraphModelRenderProvider provider) { + super(viewName); + fTimeGraphProvider = provider; + } + + protected ITimeGraphModelRenderProvider getRenderProvider() { + return fTimeGraphProvider; + } + + @Override + public void setFocus() { + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelViewer.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelViewer.java new file mode 100644 index 0000000000..1a11860268 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/TimeGraphModelViewer.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2; + +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; + +public abstract class TimeGraphModelViewer { + + private static final long UNINITIALIZED = -1; + + private final ITimeGraphModelRenderProvider fModelRenderProvider; + private final SignallingContext fSignallingContext; + + private long fFullTimeGraphStartTime = 1; + private long fFullTimeGraphEndTime = 1; + + private long fLatestVisibleRangeStartTime = UNINITIALIZED; + private long fLatestVisibleRangeEndTime = UNINITIALIZED; + + protected TimeGraphModelViewer(ITimeGraphModelRenderProvider modelRenderProvider) { + fModelRenderProvider = modelRenderProvider; + fSignallingContext = new SignallingContext(this); + } + + public void dispose() { + fSignallingContext.dispose(); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + public ITimeGraphModelRenderProvider getModelRenderProvider() { + return fModelRenderProvider; + } + + protected SignallingContext getSignalingContext() { + return fSignallingContext; + } + + protected long getFullTimeGraphStartTime() { + return fFullTimeGraphStartTime; + } + + protected long getFullTimeGraphEndTime() { + return fFullTimeGraphEndTime; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + public final void repaintCurrentArea() { + ITmfTrace trace = fSignallingContext.getCurrentTrace(); + long start = fLatestVisibleRangeStartTime; + long end = fLatestVisibleRangeEndTime; + if (trace == null || start == UNINITIALIZED || end == UNINITIALIZED) { + return; + } + paintArea(trace, fLatestVisibleRangeStartTime, fLatestVisibleRangeEndTime); + } + + public final void seekVisibleRange(long visibleWindowStartTime, long visibleWindowEndTime) { + checkWindowTimeRange(visibleWindowStartTime, visibleWindowEndTime); + + seekVisibleRangeImpl(visibleWindowStartTime, visibleWindowEndTime); + updateLatestVisibleRange(visibleWindowStartTime, visibleWindowEndTime); + } + + protected final void paintArea(ITmfTrace trace, long windowStartTime, long windowEndTime) { + checkWindowTimeRange(windowStartTime, windowEndTime); + + paintAreaImpl(trace, windowStartTime, windowEndTime); + } + + protected final void drawSelection(long selectionStartTime, long selectionEndTime) { + checkWindowTimeRange(selectionStartTime, selectionEndTime); + + drawSelectionImpl(selectionStartTime, selectionEndTime); + } + + void updateLatestVisibleRange(long visibleWindowStartTime, long visibleWindowEndTime) { + fLatestVisibleRangeStartTime = visibleWindowStartTime; + fLatestVisibleRangeEndTime = visibleWindowEndTime; + } + + /** + * Recompute the total virtual size of the time graph area, and assigns the + * given timestamps as the start and end positions. + * + * All subsquent operations (seek, paint, etc.) that use timestamp expect + * these timestamps to be within the range passed here! + * + * Should be called when the trace changes, or the trace's total time range + * is updated (while indexing, or in live cases). + */ + protected void setTimeGraphAreaRange(long fullAreaStartTime, long fullAreaEndTime) { + checkTimeRange(fullAreaStartTime, fullAreaEndTime); + + if (fFullTimeGraphStartTime == fullAreaStartTime && + fFullTimeGraphEndTime == fullAreaEndTime) { + /* No need to update */ + return; + } + + fFullTimeGraphStartTime = fullAreaStartTime; + fFullTimeGraphEndTime = fullAreaEndTime; + } + + // ------------------------------------------------------------------------ + // Template methods + // ------------------------------------------------------------------------ + + /** + * This should be called whenever the visible window moves, including zoom + * level changes. + */ + protected abstract void seekVisibleRangeImpl(long visibleWindowStartTime, long visibleWindowEndTime); + + /** + * Paint an area of the viewer. This will also update the tree pane + * accordingly. + * + * It is encouraged to actually paint a bit more of the area on both sides, + * so that small scrolling and resizing operations do not require fetching + * new data to display the area. + */ + protected abstract void paintAreaImpl(ITmfTrace trace, long windowStartTime, long windowEndTime); + + /** + * Draw a new selection rectangle. The previous one, if any, will be + * removed. + */ + protected abstract void drawSelectionImpl(long selectionStartTime, long selectionEndTime); + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + private static void checkTimeRange(long rangeStart, long rangeEnd) { + if (rangeStart > rangeEnd) { + throw new IllegalArgumentException("Time range start " + rangeStart + "is after its end time " + rangeEnd); //$NON-NLS-1$ //$NON-NLS-2$ + } + if (rangeStart < 0 || rangeEnd < 0) { + throw new IllegalArgumentException("One of the time range bounds is negative"); //$NON-NLS-1$ + } + if (rangeStart == Long.MAX_VALUE) { + throw new IllegalArgumentException("You are trying to make me believe the range starts at " + //$NON-NLS-1$ + rangeStart + ". I do not believe you."); //$NON-NLS-1$ + } + if (rangeEnd == Long.MAX_VALUE) { + throw new IllegalArgumentException("You are trying to make me believe the range ends at " + //$NON-NLS-1$ + rangeEnd + ". I do not believe you."); //$NON-NLS-1$ + } + } + + private void checkWindowTimeRange(long windowStartTime, long windowEndTime) { + checkTimeRange(windowStartTime, windowEndTime); + + if (windowStartTime < fFullTimeGraphStartTime) { + throw new IllegalArgumentException("Requested window start time: " + windowStartTime + + " is smaller than trace start time " + fFullTimeGraphStartTime); + } + if (windowEndTime > fFullTimeGraphEndTime) { + throw new IllegalArgumentException("Requested window end time: " + windowEndTime + + " is greater than trace end time " + fFullTimeGraphEndTime); + } + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/package-info.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/package-info.java new file mode 100644 index 0000000000..a13a8bdeca --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/package-info.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2; diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtColorFactory.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtColorFactory.java new file mode 100644 index 0000000000..1db44dba0c --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtColorFactory.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swt; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition; + +final class SwtColorFactory { + + private SwtColorFactory() {} + + private static final Map COLOR_MAP = new HashMap<>(); + + /** + * Instantiate a {@link Color} from a {@link ColorDefinition} object. + * + * Must be called by the UI thread only, so it should not need any special + * synchronization. + * + * @param colorDef + * The ColorDefinition + * @return The Color object + */ + public static Color getColorFromDef(ColorDefinition colorDef) { + Color color = COLOR_MAP.get(colorDef); + if (color == null) { + color = new Color(Display.getDefault(), colorDef.fRed, colorDef.fGreen, colorDef.fBlue, colorDef.fAlpha); + COLOR_MAP.put(colorDef, color); + } + return color; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtTimeGraphView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtTimeGraphView.java new file mode 100644 index 0000000000..09f1814aac --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/SwtTimeGraphView.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swt; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider; +import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.TimeGraphModelView; +import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo; +import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned; +import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer; + +/** + * @author alexandre + * + */ +public abstract class SwtTimeGraphView extends TimeGraphModelView implements ITmfTimeAligned { + + private @Nullable TimeGraphViewer fTimeGraphViewer; + + protected SwtTimeGraphView(String viewName, ITimeGraphModelRenderProvider modelRenderProvider) { + super(viewName, modelRenderProvider); + } + + @Override + public void createPartControl(@Nullable Composite parent) { + if (parent == null) { + return; + } + TimeGraphViewer viewer = new TimeGraphViewer(parent, SWT.NONE); +// viewer.setTimeGraphContentProvider(new SwtTimeGraphContentProvider()); +// viewer.setTimeGraphProvider(new SwtTimeGraphPresentationProvider()); + + fTimeGraphViewer = viewer; + } + + @Override + public void setFocus() { + } + + // ------------------------------------------------------------------------ + // Time Alignment + // ------------------------------------------------------------------------ + + @Override + public @Nullable TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() { + if (fTimeGraphViewer != null) { + return fTimeGraphViewer.getTimeViewAlignmentInfo(); + } + return null; + } + + @Override + public int getAvailableWidth(int requestedOffset) { + if (fTimeGraphViewer != null) { + return fTimeGraphViewer.getAvailableWidth(requestedOffset); + } + return 0; + } + + @Override + public void performAlign(int offset, int width) { + if (fTimeGraphViewer != null) { + fTimeGraphViewer.performAlign(offset, width); + } + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/package-info.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/package-info.java new file mode 100644 index 0000000000..ff5df7a50e --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swt/package-info.java @@ -0,0 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc. and others + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swt; diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/ActionFactory.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/ActionFactory.java new file mode 100644 index 0000000000..e66ba397b6 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/ActionFactory.java @@ -0,0 +1,147 @@ +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuCreator; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider.FilterMode; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider.SortingMode; +import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.TimeGraphModelViewer; +import org.eclipse.tracecompass.internal.tmf.ui.Activator; +import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants; + +final class ActionFactory { + + private ActionFactory() {} + + private static abstract class DrowDownMenuCreator implements IMenuCreator { + + private @Nullable Menu fMenu = null; + + @Override + public final @Nullable Menu getMenu(@Nullable Menu parent) { + return null; // Not used? + } + + @Override + public final Menu getMenu(@Nullable Control parent) { + if (fMenu != null) { + fMenu.dispose(); + } + Menu menu = new Menu(parent); + getMenuActions().forEach(action -> { + new ActionContributionItem(action).fill(menu, -1); + }); + fMenu = menu; + return menu; + } + + @Override + public final void dispose() { + if (fMenu != null) { + fMenu.dispose(); + fMenu = null; + } + } + + protected abstract List 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 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 getMenuActions() { + return IntStream.range(0, provider.getFilterModes().size()) + .mapToObj(index -> { + FilterMode filterMode = provider.getFilterModes().get(index); + Action action = new Action(filterMode.getName(), IAction.AS_CHECK_BOX) { + @Override + public void runWithEvent(@Nullable Event event) { + if (isChecked()) { + provider.enableFilterMode(index); + } else { + provider.disableFilterMode(index); + } + System.out.println("repainting viewer"); + viewer.repaintCurrentArea(); + } + }; + action.setEnabled(true); + action.setChecked(provider.getActiveFilterModes().contains(filterMode)); + return action; + }) + .collect(Collectors.toList()); + } + }); + } + + @Override + public void runWithEvent(@Nullable Event event) { + // TODO Also open the menu, need to figure out how + } + } + + public static Action getSelectSortingModeAction(TimeGraphModelViewer viewer) { + return new SelectSortingModeAction(viewer); + } + + public static Action getSelectFilterModesAction(TimeGraphModelViewer viewer) { + return new SelectFilterModesAction(viewer); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/JfxColorFactory.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/JfxColorFactory.java new file mode 100644 index 0000000000..3fc654762f --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/JfxColorFactory.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ColorDefinition; + +import javafx.scene.paint.Color; + +final class JfxColorFactory { + + private JfxColorFactory() {} + + private static final Map COLOR_MAP = new ConcurrentHashMap<>(); + + /** + * Instantiate a {@link Color} from a {@link ColorDefinition} object. + * + * @param colorDef + * The ColorDefinition + * @return The Color object + */ + public static Color getColorFromDef(ColorDefinition colorDef) { + Color color = COLOR_MAP.get(colorDef); + if (color == null) { + color = Color.rgb(colorDef.fRed, colorDef.fGreen, colorDef.fBlue, (double) colorDef.fAlpha / (double) ColorDefinition.MAX); + COLOR_MAP.put(colorDef, color); + } + return color; + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/LatestJobExecutor.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/LatestJobExecutor.java new file mode 100644 index 0000000000..1ff199cc36 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/LatestJobExecutor.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx; + +import java.lang.ref.WeakReference; + +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.annotation.Nullable; + +public class LatestJobExecutor { + + /** + * The latest job that was schedule in this queue. + */ + private WeakReference<@Nullable Job> fLatestJob = new WeakReference<>(null); + + public LatestJobExecutor() { + } + + public synchronized void schedule(Job newJob) { + Job latestJob = fLatestJob.get(); + if (latestJob != null) { + /* + * Cancel the existing job. Here's hoping it cooperates and ends + * quickly! + */ + latestJob.cancel(); + } + + /* Start the new job */ + fLatestJob = new WeakReference<>(newJob); + newJob.schedule(); + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphView.java new file mode 100644 index 0000000000..17fff319c8 --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphView.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider; +import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.TimeGraphModelView; + +public abstract class SwtJfxTimeGraphView extends TimeGraphModelView { + + private @Nullable SwtJfxTimeGraphViewer fViewer; + + protected SwtJfxTimeGraphView(String viewName, ITimeGraphModelRenderProvider modelRenderProvider) { + super(viewName, modelRenderProvider); + } + + @Override + public void createPartControl(@Nullable Composite parent) { + if (parent == null) { + return; + } + SwtJfxTimeGraphViewer viewer = new SwtJfxTimeGraphViewer(parent, getRenderProvider()); + fViewer = viewer; + + IToolBarManager toolbarMgr = getViewSite().getActionBars().getToolBarManager(); + toolbarMgr.add(ActionFactory.getSelectSortingModeAction(viewer)); + toolbarMgr.add(ActionFactory.getSelectFilterModesAction(viewer)); + } + + @Override + public void dispose() { + if (fViewer != null) { + fViewer.dispose(); + } + } + + @Override + public void setFocus() { + } + +} diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphViewer.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphViewer.java new file mode 100644 index 0000000000..05b824a66b --- /dev/null +++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/provisional/tmf/ui/views/timegraph2/swtjfx/SwtJfxTimeGraphViewer.java @@ -0,0 +1,734 @@ +/******************************************************************************* + * Copyright (c) 2016 EfficiOS Inc., Alexandre Montplaisir + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.swtjfx; + +import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.ITimeGraphModelRenderProvider; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphModelRender; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphStateInterval; +import org.eclipse.tracecompass.internal.provisional.tmf.core.views.timegraph2.TimeGraphTreeRender; +import org.eclipse.tracecompass.internal.provisional.tmf.ui.views.timegraph2.TimeGraphModelViewer; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; + +import javafx.beans.value.ChangeListener; +import javafx.embed.swt.FXCanvas; +import javafx.event.EventHandler; +import javafx.geometry.Insets; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.canvas.Canvas; +import javafx.scene.canvas.GraphicsContext; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.ScrollPane.ScrollBarPolicy; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Pane; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; +import javafx.scene.shape.Rectangle; +import javafx.scene.shape.StrokeLineCap; + +/** + * Viewer for the {@link SwtJfxTimeGraphView}, encapsulating all the view's + * controls. + * + * Its contents consist of: + * + * TODO update this to its final form + *
+ * 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
+ *             +  ...
+ * 
+ * + * 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 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