1 /*******************************************************************************
2 * Copyright (c) 2012, 2017 Ericsson, École Polytechnique de Montréal
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Patrick Tasse - Initial API and implementation
11 * Bernd Hufmann - Updated signal handling
12 * Geneviève Bastien - Move code to provide base classes for time graph view
13 * Marc-Andre Laperle - Add time zone preference
14 * Geneviève Bastien - Add event links between entries
15 *******************************************************************************/
17 package org
.eclipse
.tracecompass
.tmf
.ui
.views
.timegraph
;
19 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
21 import java
.util
.ArrayList
;
22 import java
.util
.Collections
;
23 import java
.util
.Comparator
;
24 import java
.util
.HashMap
;
25 import java
.util
.LinkedHashSet
;
26 import java
.util
.List
;
29 import java
.util
.concurrent
.CopyOnWriteArrayList
;
30 import java
.util
.concurrent
.atomic
.AtomicInteger
;
31 import java
.util
.logging
.Logger
;
32 import java
.util
.regex
.Matcher
;
33 import java
.util
.regex
.Pattern
;
35 import org
.eclipse
.core
.filesystem
.EFS
;
36 import org
.eclipse
.core
.filesystem
.IFileStore
;
37 import org
.eclipse
.core
.resources
.IFile
;
38 import org
.eclipse
.core
.resources
.IMarker
;
39 import org
.eclipse
.core
.resources
.IMarkerDelta
;
40 import org
.eclipse
.core
.resources
.IResource
;
41 import org
.eclipse
.core
.resources
.IResourceChangeEvent
;
42 import org
.eclipse
.core
.resources
.IResourceChangeListener
;
43 import org
.eclipse
.core
.resources
.IWorkspaceRunnable
;
44 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
45 import org
.eclipse
.core
.runtime
.CoreException
;
46 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
47 import org
.eclipse
.core
.runtime
.IStatus
;
48 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
49 import org
.eclipse
.core
.runtime
.Status
;
50 import org
.eclipse
.core
.runtime
.jobs
.Job
;
51 import org
.eclipse
.jdt
.annotation
.NonNull
;
52 import org
.eclipse
.jdt
.annotation
.Nullable
;
53 import org
.eclipse
.jface
.action
.Action
;
54 import org
.eclipse
.jface
.action
.GroupMarker
;
55 import org
.eclipse
.jface
.action
.IAction
;
56 import org
.eclipse
.jface
.action
.IMenuListener
;
57 import org
.eclipse
.jface
.action
.IMenuManager
;
58 import org
.eclipse
.jface
.action
.IStatusLineManager
;
59 import org
.eclipse
.jface
.action
.IToolBarManager
;
60 import org
.eclipse
.jface
.action
.MenuManager
;
61 import org
.eclipse
.jface
.action
.Separator
;
62 import org
.eclipse
.jface
.commands
.ActionHandler
;
63 import org
.eclipse
.jface
.viewers
.AbstractTreeViewer
;
64 import org
.eclipse
.jface
.viewers
.ILabelProvider
;
65 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
66 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
67 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
68 import org
.eclipse
.jface
.viewers
.ViewerFilter
;
69 import org
.eclipse
.osgi
.util
.NLS
;
70 import org
.eclipse
.swt
.SWT
;
71 import org
.eclipse
.swt
.events
.MenuDetectEvent
;
72 import org
.eclipse
.swt
.events
.MenuDetectListener
;
73 import org
.eclipse
.swt
.events
.SelectionAdapter
;
74 import org
.eclipse
.swt
.events
.SelectionEvent
;
75 import org
.eclipse
.swt
.graphics
.Image
;
76 import org
.eclipse
.swt
.graphics
.Point
;
77 import org
.eclipse
.swt
.graphics
.RGBA
;
78 import org
.eclipse
.swt
.widgets
.Composite
;
79 import org
.eclipse
.swt
.widgets
.Display
;
80 import org
.eclipse
.swt
.widgets
.Event
;
81 import org
.eclipse
.swt
.widgets
.Menu
;
82 import org
.eclipse
.swt
.widgets
.Shell
;
83 import org
.eclipse
.swt
.widgets
.Tree
;
84 import org
.eclipse
.swt
.widgets
.TreeColumn
;
85 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
86 import org
.eclipse
.tracecompass
.common
.core
.log
.TraceCompassLog
;
87 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.markers
.MarkerConfigXmlParser
;
88 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.markers
.MarkerSet
;
89 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
90 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.markers
.ConfigurableMarkerEventSource
;
91 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.markers
.MarkerUtils
;
92 import org
.eclipse
.tracecompass
.tmf
.core
.resources
.ITmfMarker
;
93 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfMarkerEventSourceUpdatedSignal
;
94 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSelectionRangeUpdatedSignal
;
95 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
96 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTimestampFormatUpdateSignal
;
97 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
98 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
99 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
100 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfWindowRangeUpdatedSignal
;
101 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
102 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
103 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
104 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
105 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceAdapterManager
;
106 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceContext
;
107 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
108 import org
.eclipse
.tracecompass
.tmf
.ui
.TmfUiRefreshHandler
;
109 import org
.eclipse
.tracecompass
.tmf
.ui
.signal
.TmfTimeViewAlignmentInfo
;
110 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.ITmfTimeAligned
;
111 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
112 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphBookmarkListener
;
113 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphContentProvider
;
114 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphPresentationProvider2
;
115 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphRangeListener
;
116 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
117 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphBookmarkEvent
;
118 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
119 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphContentProvider
;
120 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphPresentationProvider
;
121 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphRangeUpdateEvent
;
122 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
123 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphViewer
;
124 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ILinkEvent
;
125 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.IMarkerEvent
;
126 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.IMarkerEventSource
;
127 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
128 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
129 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.MarkerEvent
;
130 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
131 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphControl
;
132 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
133 import org
.eclipse
.ui
.IActionBars
;
134 import org
.eclipse
.ui
.IPartListener
;
135 import org
.eclipse
.ui
.IWorkbenchActionConstants
;
136 import org
.eclipse
.ui
.IWorkbenchPage
;
137 import org
.eclipse
.ui
.IWorkbenchPart
;
138 import org
.eclipse
.ui
.PartInitException
;
139 import org
.eclipse
.ui
.PlatformUI
;
140 import org
.eclipse
.ui
.actions
.ActionFactory
;
141 import org
.eclipse
.ui
.handlers
.IHandlerActivation
;
142 import org
.eclipse
.ui
.handlers
.IHandlerService
;
143 import org
.eclipse
.ui
.ide
.IDE
;
146 * An abstract view all time graph views can inherit
148 * This view contains a time graph viewer.
150 public abstract class AbstractTimeGraphView
extends TmfView
implements ITmfTimeAligned
, IResourceChangeListener
{
152 /** Constant indicating that all levels of the time graph should be expanded */
153 protected static final int ALL_LEVELS
= AbstractTreeViewer
.ALL_LEVELS
;
155 private static final Pattern RGBA_PATTERN
= Pattern
.compile("RGBA \\{(\\d+), (\\d+), (\\d+), (\\d+)\\}"); //$NON-NLS-1$
157 private static final Logger LOGGER
= TraceCompassLog
.getLogger(AbstractTimeGraphView
.class);
158 private static final String LOG_STRING_WITH_PARAM
= "[TimeGraphView:%s] viewId=%s, %s"; //$NON-NLS-1$
159 private static final String LOG_STRING
= "[TimeGraphView:%s] viewId=%s"; //$NON-NLS-1$
168 // ------------------------------------------------------------------------
170 // ------------------------------------------------------------------------
172 /** The time graph viewer */
173 private TimeGraphViewer fTimeGraphViewer
;
175 private AtomicInteger fDirty
= new AtomicInteger();
177 private final Object fZoomThreadResultLock
= new Object();
179 /** The selected trace */
180 private ITmfTrace fTrace
;
182 /** The selected trace editor file*/
183 private IFile fEditorFile
;
185 /** The timegraph entry list */
186 private List
<TimeGraphEntry
> fEntryList
;
188 /** The trace to entry list hash map */
189 private final Map
<ITmfTrace
, List
<TimeGraphEntry
>> fEntryListMap
= new HashMap
<>();
191 /** The trace to filters hash map */
192 private final Map
<ITmfTrace
, @NonNull ViewerFilter
[]> fFiltersMap
= new HashMap
<>();
194 /** The trace to view context hash map */
195 private final Map
<ITmfTrace
, ViewContext
> fViewContext
= new HashMap
<>();
197 /** The trace to marker event sources hash map */
198 private final Map
<ITmfTrace
, List
<IMarkerEventSource
>> fMarkerEventSourcesMap
= new HashMap
<>();
200 /** The trace to build thread hash map */
201 private final Map
<ITmfTrace
, Job
> fBuildJobMap
= new HashMap
<>();
203 /** The start time */
204 private long fStartTime
= SWT
.DEFAULT
;
207 private long fEndTime
= SWT
.DEFAULT
;
209 /** The display width */
210 private final int fDisplayWidth
;
212 /** The zoom thread */
213 private ZoomThread fZoomThread
;
215 /** The next resource action */
216 private Action fNextResourceAction
;
218 /** The previous resource action */
219 private Action fPreviousResourceAction
;
221 /** A comparator class */
222 private Comparator
<ITimeGraphEntry
> fEntryComparator
= null;
224 /** The redraw state used to prevent unnecessary queuing of display runnables */
225 private State fRedrawState
= State
.IDLE
;
227 /** The redraw synchronization object */
228 private final Object fSyncObj
= new Object();
230 /** The presentation provider for this view */
231 private final TimeGraphPresentationProvider fPresentation
;
233 /** The tree column label array, or null for a single default column */
234 private String
[] fColumns
;
236 private Comparator
<ITimeGraphEntry
>[] fColumnComparators
;
238 /** The time graph label provider */
239 private ITableLabelProvider fLabelProvider
= new TreeLabelProvider();
241 /** The time graph content provider */
242 private @NonNull ITimeGraphContentProvider fTimeGraphContentProvider
= new TimeGraphContentProvider();
244 /** The relative weight of the time graph viewer parts */
245 private int[] fWeight
= { 1, 3 };
247 /** The filter column label array, or null if filter is not used */
248 private String
[] fFilterColumns
;
250 /** The filter content provider, or null if filter is not used */
251 private ITreeContentProvider fFilterContentProvider
;
253 /** The filter label provider, or null if filter is not used */
254 private TreeLabelProvider fFilterLabelProvider
;
256 private int fAutoExpandLevel
= ALL_LEVELS
;
258 /** The default column index for sorting */
259 private int fInitialSortColumn
= 0;
261 /** The default column index for sorting */
262 private int fCurrentSortColumn
= 0;
264 /** The current sort direction */
265 private int fSortDirection
= SWT
.DOWN
;
267 /** Flag to indicate to reveal selection */
268 private volatile boolean fIsRevealSelection
= false;
271 * Menu Manager for context-sensitive menu for time graph entries.
272 * This will be used on the name space of the time graph viewer.
274 private final @NonNull MenuManager fEntryMenuManager
= new MenuManager();
276 /** Time Graph View part listener */
277 private TimeGraphPartListener fPartListener
;
279 /** Action for the find command. There is only one for all Time Graph views */
280 private static final ShowFindDialogAction FIND_ACTION
= new ShowFindDialogAction();
282 /** The find action handler */
283 private ActionHandler fFindActionHandler
;
285 /** The find handler activation */
286 private IHandlerActivation fFindHandlerActivation
;
288 /** The find target to use */
289 private final FindTarget fFindTarget
;
291 /** The marker set menu */
292 private MenuManager fMarkerSetMenu
;
294 // ------------------------------------------------------------------------
296 // ------------------------------------------------------------------------
299 * Base class to provide the labels for the tree viewer. Views extending
300 * this class typically need to override the getColumnText method if they
301 * have more than one column to display
303 protected static class TreeLabelProvider
implements ITableLabelProvider
, ILabelProvider
{
306 public void addListener(ILabelProviderListener listener
) {
310 public void dispose() {
314 public boolean isLabelProperty(Object element
, String property
) {
319 public void removeListener(ILabelProviderListener listener
) {
323 public Image
getColumnImage(Object element
, int columnIndex
) {
328 public String
getColumnText(Object element
, int columnIndex
) {
329 TimeGraphEntry entry
= (TimeGraphEntry
) element
;
330 if (columnIndex
== 0) {
331 return entry
.getName();
337 public Image
getImage(Object element
) {
342 public String
getText(Object element
) {
343 TimeGraphEntry entry
= (TimeGraphEntry
) element
;
344 return entry
.getName();
349 // TODO: This can implement ICoreRunnable once support for Eclipse 4.5. is not necessary anymore.
350 private class BuildRunnable
{
351 private final @NonNull ITmfTrace fBuildTrace
;
352 private final @NonNull ITmfTrace fParentTrace
;
354 public BuildRunnable(final @NonNull ITmfTrace trace
, final @NonNull ITmfTrace parentTrace
) {
356 fParentTrace
= parentTrace
;
359 public void run(IProgressMonitor monitor
) {
360 LOGGER
.info(() -> getLogMessage("BuildThreadStart", "trace=" + fBuildTrace
.getName())); //$NON-NLS-1$ //$NON-NLS-2$
362 buildEntryList(fBuildTrace
, fParentTrace
, NonNullUtils
.checkNotNull(monitor
));
363 synchronized (fBuildJobMap
) {
364 fBuildJobMap
.remove(fBuildTrace
);
367 LOGGER
.info(() -> getLogMessage("BuildThreadEnd", null)); //$NON-NLS-1$
375 protected abstract class ZoomThread
extends Thread
{
376 private final long fZoomStartTime
;
377 private final long fZoomEndTime
;
378 private final long fResolution
;
379 private final @NonNull IProgressMonitor fMonitor
;
391 public ZoomThread(long startTime
, long endTime
, long resolution
) {
392 super(AbstractTimeGraphView
.this.getName() + " zoom"); //$NON-NLS-1$
393 fZoomStartTime
= startTime
;
394 fZoomEndTime
= endTime
;
395 fResolution
= resolution
;
396 fMonitor
= new NullProgressMonitor();
400 * @return the zoom start time
402 public long getZoomStartTime() {
403 return fZoomStartTime
;
407 * @return the zoom end time
409 public long getZoomEndTime() {
414 * @return the resolution
416 public long getResolution() {
421 * @return the monitor
423 public @NonNull IProgressMonitor
getMonitor() {
428 * Cancel the zoom thread
430 public void cancel() {
431 fMonitor
.setCanceled(true);
435 public final void run() {
436 LOGGER
.info(() -> getLogMessage("ZoomThreadStart", "start=" + fZoomStartTime
+ ", end=" + fZoomEndTime
)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
439 fDirty
.decrementAndGet();
441 LOGGER
.info(() -> getLogMessage("ZoomThreadEnd", null)); //$NON-NLS-1$
445 * Applies the results of the ZoomThread calculations.
447 * Note: This method makes sure that only the results of the last
448 * created ZoomThread are applied.
451 * the code to run in order to apply the results
454 protected void applyResults(Runnable runnable
) {
455 synchronized (fZoomThreadResultLock
) {
456 if (this == fZoomThread
) {
463 * Run the zoom operation.
466 public abstract void doRun();
469 private class ZoomThreadByEntry
extends ZoomThread
{
470 private final @NonNull List
<TimeGraphEntry
> fZoomEntryList
;
472 public ZoomThreadByEntry(@NonNull List
<TimeGraphEntry
> entryList
, long startTime
, long endTime
, long resolution
) {
473 super(startTime
, endTime
, resolution
);
474 fZoomEntryList
= entryList
;
478 public void doRun() {
479 LOGGER
.config(() -> getLogMessage("ZoomThreadGettingStates", null)); //$NON-NLS-1$
481 for (TimeGraphEntry entry
: fZoomEntryList
) {
482 if (getMonitor().isCanceled()) {
483 LOGGER
.info(() -> getLogMessage("ZoomThreadCanceled", null)); //$NON-NLS-1$
489 zoom(entry
, getMonitor());
491 /* Refresh the arrows when zooming */
492 LOGGER
.config(() -> getLogMessage("ZoomThreadGettingLinks", null)); //$NON-NLS-1$
493 List
<ILinkEvent
> events
= getLinkList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
495 /* Refresh the view-specific markers when zooming */
496 LOGGER
.config(() -> getLogMessage("ZoomThreadGettingMarkers", null)); //$NON-NLS-1$
497 List
<IMarkerEvent
> markers
= new ArrayList
<>(getViewMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
498 /* Refresh the trace-specific markers when zooming */
499 markers
.addAll(getTraceMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
501 if (events
!= null) {
502 fTimeGraphViewer
.setLinks(events
);
504 fTimeGraphViewer
.setMarkerCategories(getMarkerCategories());
505 fTimeGraphViewer
.setMarkers(markers
);
510 private void zoom(@NonNull TimeGraphEntry entry
, @NonNull IProgressMonitor monitor
) {
511 if (getZoomStartTime() <= fStartTime
&& getZoomEndTime() >= fEndTime
) {
513 entry
.setZoomedEventList(null);
516 List
<ITimeEvent
> zoomedEventList
= getEventList(entry
, getZoomStartTime(), getZoomEndTime(), getResolution(), monitor
);
517 if (zoomedEventList
!= null) {
519 entry
.setZoomedEventList(zoomedEventList
);
524 for (TimeGraphEntry child
: entry
.getChildren()) {
525 if (monitor
.isCanceled()) {
528 zoom(child
, monitor
);
534 // ------------------------------------------------------------------------
536 // ------------------------------------------------------------------------
539 * Constructs a time graph view that contains a time graph viewer.
541 * By default, the view uses a single default column in the name space that
542 * shows the time graph entry name. To use multiple columns and/or
543 * customized label texts, the subclass constructor must call
544 * {@link #setTreeColumns(String[])} and/or
545 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
550 * The presentation provider
552 public AbstractTimeGraphView(String id
, TimeGraphPresentationProvider pres
) {
554 fPresentation
= pres
;
555 fDisplayWidth
= Display
.getDefault().getBounds().width
;
556 fFindTarget
= new FindTarget();
559 // ------------------------------------------------------------------------
560 // Getters and setters
561 // ------------------------------------------------------------------------
564 * Getter for the time graph combo. No longer used.
567 * @deprecated Use {@link #getTimeGraphViewer()} instead.
570 protected TimeGraphCombo
getTimeGraphCombo() {
575 * Getter for the time graph viewer
577 * @return The time graph viewer
579 protected TimeGraphViewer
getTimeGraphViewer() {
580 return fTimeGraphViewer
;
584 * Getter for the presentation provider
586 * @return The time graph presentation provider
588 protected ITimeGraphPresentationProvider2
getPresentationProvider() {
589 return fPresentation
;
593 * Sets the tree column labels.
595 * This should be called from the constructor.
598 * The array of tree column labels
600 protected void setTreeColumns(final String
[] columns
) {
601 setTreeColumns(columns
, null, 0);
605 * Sets the tree column labels.
607 * This should be called from the constructor.
610 * The array of tree column labels
612 * An array of column comparators for sorting of columns when
613 * clicking on column header
614 * @param initialSortColumn
615 * Index of column to sort initially
618 protected void setTreeColumns(final String
[] columns
, final Comparator
<ITimeGraphEntry
>[] comparators
, int initialSortColumn
) {
619 checkPartNotCreated();
621 fColumnComparators
= comparators
;
622 fInitialSortColumn
= initialSortColumn
;
626 * Sets the tree label provider.
628 * This should be called from the constructor.
631 * The tree label provider
633 protected void setTreeLabelProvider(final TreeLabelProvider tlp
) {
634 checkPartNotCreated();
635 fLabelProvider
= tlp
;
639 * Sets the time graph content provider.
641 * This should be called from the constructor.
644 * The time graph content provider
647 protected void setTimeGraphContentProvider(final @NonNull ITimeGraphContentProvider tgcp
) {
648 checkPartNotCreated();
649 fTimeGraphContentProvider
= tgcp
;
653 * Sets the relative weight of each part of the time graph viewer. The first
654 * number is the name space width, and the second number is the time space
658 * The array of relative weights of each part of the viewer
660 protected void setWeight(final int[] weights
) {
662 if (fTimeGraphViewer
!= null) {
663 fTimeGraphViewer
.setWeights(weights
);
668 * Sets the filter column labels.
670 * This should be called from the constructor.
672 * @param filterColumns
673 * The array of filter column labels
675 protected void setFilterColumns(final String
[] filterColumns
) {
676 checkPartNotCreated();
677 fFilterColumns
= filterColumns
;
681 * Sets the filter content provider.
683 * This should be called from the constructor.
685 * @param contentProvider
686 * The filter content provider
689 protected void setFilterContentProvider(final ITreeContentProvider contentProvider
) {
690 checkPartNotCreated();
691 fFilterContentProvider
= contentProvider
;
695 * Sets the filter label provider.
697 * This should be called from the constructor.
699 * @param labelProvider
700 * The filter label provider
702 protected void setFilterLabelProvider(final TreeLabelProvider labelProvider
) {
703 checkPartNotCreated();
704 fFilterLabelProvider
= labelProvider
;
707 private void checkPartNotCreated() {
708 if (getParentComposite() != null) {
709 throw new IllegalStateException("This method must be called before createPartControl."); //$NON-NLS-1$
714 * Gets the display width
716 * @return the display width
718 protected int getDisplayWidth() {
719 return fDisplayWidth
;
723 * Gets the comparator for the entries
725 * @return The entry comparator
727 protected Comparator
<ITimeGraphEntry
> getEntryComparator() {
728 return fEntryComparator
;
732 * Sets the comparator class for the entries.
734 * This comparator will apply recursively to entries that implement
735 * {@link TimeGraphEntry#sortChildren(Comparator)}.
738 * A comparator object
740 protected void setEntryComparator(final Comparator
<ITimeGraphEntry
> comparator
) {
741 fEntryComparator
= comparator
;
745 * Gets the trace displayed in the view
749 protected ITmfTrace
getTrace() {
754 * Gets the start time
756 * @return The start time
758 protected long getStartTime() {
763 * Sets the start time
768 protected void setStartTime(long time
) {
775 * @return The end time
777 protected long getEndTime() {
787 protected void setEndTime(long time
) {
792 * Sets the auto-expand level to be used for the input of the view. The
793 * value 0 means that there is no auto-expand; 1 means that top-level
794 * elements are expanded, but not their children; 2 means that top-level
795 * elements are expanded, and their children, but not grand-children; and so
798 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
802 * non-negative level, or <code>ALL_LEVELS</code> to expand all
805 protected void setAutoExpandLevel(int level
) {
806 fAutoExpandLevel
= level
;
807 if (fTimeGraphViewer
!= null) {
808 fTimeGraphViewer
.setAutoExpandLevel(level
);
813 * Gets the entry list for a trace
818 * @return the entry list map
820 protected List
<TimeGraphEntry
> getEntryList(ITmfTrace trace
) {
821 synchronized (fEntryListMap
) {
822 return fEntryListMap
.get(trace
);
827 * Adds a trace entry list to the entry list map
832 * the list of time graph entries
834 protected void putEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
835 synchronized (fEntryListMap
) {
836 fEntryListMap
.put(trace
, new CopyOnWriteArrayList
<>(list
));
841 * Adds a list of entries to a trace's entry list
846 * the list of time graph entries to add
848 protected void addToEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
849 synchronized (fEntryListMap
) {
850 List
<TimeGraphEntry
> entryList
= fEntryListMap
.get(trace
);
851 if (entryList
== null) {
852 fEntryListMap
.put(trace
, new CopyOnWriteArrayList
<>(list
));
854 entryList
.addAll(list
);
860 * Removes a list of entries from a trace's entry list
865 * the list of time graph entries to remove
867 protected void removeFromEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
868 synchronized (fEntryListMap
) {
869 List
<TimeGraphEntry
> entryList
= fEntryListMap
.get(trace
);
870 if (entryList
!= null) {
871 entryList
.removeAll(list
);
877 * Text for the "next" button
879 * @return The "next" button text
881 protected String
getNextText() {
882 return Messages
.AbstractTimeGraphtView_NextText
;
886 * Tooltip for the "next" button
888 * @return Tooltip for the "next" button
890 protected String
getNextTooltip() {
891 return Messages
.AbstractTimeGraphView_NextTooltip
;
895 * Text for the "Previous" button
897 * @return The "Previous" button text
899 protected String
getPrevText() {
900 return Messages
.AbstractTimeGraphView_PreviousText
;
904 * Tooltip for the "previous" button
906 * @return Tooltip for the "previous" button
908 protected String
getPrevTooltip() {
909 return Messages
.AbstractTimeGraphView_PreviousTooltip
;
913 FindTarget
getFindTarget() {
918 * Formats a log message for this class
921 * The event to log, that will be appended to the class name to
922 * make the full event name
924 * The string of extra parameters to add to the log message, in
925 * the format name=value[, name=value]*, or <code>null</code> for
927 * @return The complete log message for this class
929 private String
getLogMessage(String event
, @Nullable String parameters
) {
930 if (parameters
== null) {
931 return String
.format(LOG_STRING
, event
, getViewId());
933 return String
.format(LOG_STRING_WITH_PARAM
, event
, getViewId(), parameters
);
936 // ------------------------------------------------------------------------
938 // ------------------------------------------------------------------------
941 public void createPartControl(Composite parent
) {
942 super.createPartControl(parent
);
943 fTimeGraphViewer
= new TimeGraphViewer(parent
, SWT
.NONE
);
944 if (fLabelProvider
!= null) {
945 fTimeGraphViewer
.setTimeGraphLabelProvider(fLabelProvider
);
947 if (fColumns
!= null) {
948 fTimeGraphViewer
.setColumns(fColumns
);
949 if (fColumnComparators
!= null) {
950 createColumnSelectionListener(fTimeGraphViewer
.getTree());
953 fTimeGraphViewer
.setTimeGraphContentProvider(fTimeGraphContentProvider
);
954 fTimeGraphViewer
.setFilterContentProvider(fFilterContentProvider
!= null ? fFilterContentProvider
: fTimeGraphContentProvider
);
955 fTimeGraphViewer
.setFilterLabelProvider(fFilterLabelProvider
);
956 fTimeGraphViewer
.setFilterColumns(fFilterColumns
);
958 fTimeGraphViewer
.setTimeGraphProvider(fPresentation
);
959 fTimeGraphViewer
.setAutoExpandLevel(fAutoExpandLevel
);
961 fTimeGraphViewer
.setWeights(fWeight
);
963 fTimeGraphViewer
.addRangeListener(new ITimeGraphRangeListener() {
965 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event
) {
966 final long startTime
= event
.getStartTime();
967 final long endTime
= event
.getEndTime();
968 TmfTimeRange range
= new TmfTimeRange(TmfTimestamp
.fromNanos(startTime
), TmfTimestamp
.fromNanos(endTime
));
969 broadcast(new TmfWindowRangeUpdatedSignal(AbstractTimeGraphView
.this, range
));
970 startZoomThread(startTime
, endTime
);
974 fTimeGraphViewer
.addTimeListener(new ITimeGraphTimeListener() {
976 public void timeSelected(TimeGraphTimeEvent event
) {
977 ITmfTimestamp startTime
= TmfTimestamp
.fromNanos(event
.getBeginTime());
978 ITmfTimestamp endTime
= TmfTimestamp
.fromNanos(event
.getEndTime());
979 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractTimeGraphView
.this, startTime
, endTime
));
983 fTimeGraphViewer
.addBookmarkListener(new ITimeGraphBookmarkListener() {
985 public void bookmarkAdded(final TimeGraphBookmarkEvent event
) {
987 ResourcesPlugin
.getWorkspace().run(new IWorkspaceRunnable() {
989 public void run(IProgressMonitor monitor
) throws CoreException
{
990 IMarkerEvent bookmark
= event
.getBookmark();
991 IMarker marker
= fEditorFile
.createMarker(IMarker
.BOOKMARK
);
992 marker
.setAttribute(IMarker
.MESSAGE
, bookmark
.getLabel());
993 marker
.setAttribute(ITmfMarker
.MARKER_TIME
, Long
.toString(bookmark
.getTime()));
994 if (bookmark
.getDuration() > 0) {
995 marker
.setAttribute(ITmfMarker
.MARKER_DURATION
, Long
.toString(bookmark
.getDuration()));
996 marker
.setAttribute(IMarker
.LOCATION
,
997 NLS
.bind(org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Messages
.TmfMarker_LocationTimeRange
,
998 TmfTimestamp
.fromNanos(bookmark
.getTime()),
999 TmfTimestamp
.fromNanos(bookmark
.getTime() + bookmark
.getDuration())));
1001 marker
.setAttribute(IMarker
.LOCATION
,
1002 NLS
.bind(org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Messages
.TmfMarker_LocationTime
,
1003 TmfTimestamp
.fromNanos(bookmark
.getTime())));
1005 marker
.setAttribute(ITmfMarker
.MARKER_COLOR
, bookmark
.getColor().toString());
1008 } catch (CoreException e
) {
1009 Activator
.getDefault().logError(e
.getMessage());
1014 public void bookmarkRemoved(TimeGraphBookmarkEvent event
) {
1016 IMarkerEvent bookmark
= event
.getBookmark();
1017 IMarker
[] markers
= fEditorFile
.findMarkers(IMarker
.BOOKMARK
, false, IResource
.DEPTH_ZERO
);
1018 for (IMarker marker
: markers
) {
1019 if (bookmark
.getLabel().equals(marker
.getAttribute(IMarker
.MESSAGE
)) &&
1020 Long
.toString(bookmark
.getTime()).equals(marker
.getAttribute(ITmfMarker
.MARKER_TIME
, (String
) null)) &&
1021 Long
.toString(bookmark
.getDuration()).equals(marker
.getAttribute(ITmfMarker
.MARKER_DURATION
, Long
.toString(0))) &&
1022 bookmark
.getColor().toString().equals(marker
.getAttribute(ITmfMarker
.MARKER_COLOR
))) {
1027 } catch (CoreException e
) {
1028 Activator
.getDefault().logError(e
.getMessage());
1033 fTimeGraphViewer
.setTimeFormat(TimeFormat
.CALENDAR
);
1035 IStatusLineManager statusLineManager
= getViewSite().getActionBars().getStatusLineManager();
1036 fTimeGraphViewer
.getTimeGraphControl().setStatusLineManager(statusLineManager
);
1038 // View Action Handling
1040 contributeToActionBars();
1042 ITmfTrace trace
= TmfTraceManager
.getInstance().getActiveTrace();
1043 if (trace
!= null) {
1044 traceSelected(new TmfTraceSelectedSignal(this, trace
));
1047 // make selection available to other views
1048 getSite().setSelectionProvider(fTimeGraphViewer
.getSelectionProvider());
1050 ResourcesPlugin
.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent
.POST_CHANGE
);
1052 createContextMenu();
1053 fPartListener
= new TimeGraphPartListener();
1054 getSite().getPage().addPartListener(fPartListener
);
1058 public void setFocus() {
1059 fTimeGraphViewer
.setFocus();
1063 public void dispose() {
1065 synchronized (fBuildJobMap
) {
1066 fBuildJobMap
.values().forEach(buildJob
-> {
1070 if (fZoomThread
!= null) {
1071 fZoomThread
.cancel();
1073 ResourcesPlugin
.getWorkspace().removeResourceChangeListener(this);
1074 getSite().getPage().removePartListener(fPartListener
);
1081 public void resourceChanged(final IResourceChangeEvent event
) {
1082 for (final IMarkerDelta delta
: event
.findMarkerDeltas(IMarker
.BOOKMARK
, false)) {
1083 if (delta
.getResource().equals(fEditorFile
)) {
1084 fTimeGraphViewer
.setBookmarks(refreshBookmarks(fEditorFile
));
1091 private static List
<IMarkerEvent
> refreshBookmarks(final IFile editorFile
) {
1092 List
<IMarkerEvent
> bookmarks
= new ArrayList
<>();
1093 if (editorFile
== null || !editorFile
.exists()) {
1097 IMarker
[] markers
= editorFile
.findMarkers(IMarker
.BOOKMARK
, false, IResource
.DEPTH_ZERO
);
1098 for (IMarker marker
: markers
) {
1099 String label
= marker
.getAttribute(IMarker
.MESSAGE
, (String
) null);
1100 String time
= marker
.getAttribute(ITmfMarker
.MARKER_TIME
, (String
) null);
1101 String duration
= marker
.getAttribute(ITmfMarker
.MARKER_DURATION
, Long
.toString(0));
1102 String rgba
= marker
.getAttribute(ITmfMarker
.MARKER_COLOR
, (String
) null);
1103 if (label
!= null && time
!= null && rgba
!= null) {
1104 Matcher matcher
= RGBA_PATTERN
.matcher(rgba
);
1105 if (matcher
.matches()) {
1107 int red
= Integer
.valueOf(matcher
.group(1));
1108 int green
= Integer
.valueOf(matcher
.group(2));
1109 int blue
= Integer
.valueOf(matcher
.group(3));
1110 int alpha
= Integer
.valueOf(matcher
.group(4));
1111 RGBA color
= new RGBA(red
, green
, blue
, alpha
);
1112 bookmarks
.add(new MarkerEvent(null, Long
.valueOf(time
), Long
.valueOf(duration
), IMarkerEvent
.BOOKMARKS
, color
, label
, true));
1113 } catch (NumberFormatException e
) {
1114 Activator
.getDefault().logError(e
.getMessage());
1119 } catch (CoreException e
) {
1120 Activator
.getDefault().logError(e
.getMessage());
1127 // ------------------------------------------------------------------------
1129 // ------------------------------------------------------------------------
1132 * Handler for the trace opened signal.
1135 * The incoming signal
1138 public void traceOpened(TmfTraceOpenedSignal signal
) {
1139 loadTrace(signal
.getTrace());
1143 * Handler for the trace selected signal
1146 * The incoming signal
1149 public void traceSelected(final TmfTraceSelectedSignal signal
) {
1150 if (signal
.getTrace() == fTrace
) {
1153 loadTrace(signal
.getTrace());
1157 * Trace is closed: clear the data structures and the view
1160 * the signal received
1163 public void traceClosed(final TmfTraceClosedSignal signal
) {
1164 resetView(signal
.getTrace());
1165 if (signal
.getTrace() == fTrace
) {
1168 setStartTime(SWT
.DEFAULT
);
1169 setEndTime(SWT
.DEFAULT
);
1175 * Handler for the selection range signal.
1178 * The signal that's received
1182 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal
) {
1183 if (signal
.getSource() == this || fTrace
== null) {
1186 final long beginTime
= signal
.getBeginTime().toNanos();
1187 final long endTime
= signal
.getEndTime().toNanos();
1189 Display
.getDefault().asyncExec(new Runnable() {
1192 if (fTimeGraphViewer
.getControl().isDisposed()) {
1195 if (beginTime
== endTime
) {
1196 fTimeGraphViewer
.setSelectedTime(beginTime
, true);
1198 fTimeGraphViewer
.setSelectionRange(beginTime
, endTime
, true);
1200 synchingToTime(fTimeGraphViewer
.getSelectionBegin());
1206 * Handler for the window range signal.
1209 * The signal that's received
1213 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal
) {
1214 if (signal
.getSource() == this || fTrace
== null) {
1217 if (signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange()) == null) {
1220 final long startTime
= signal
.getCurrentRange().getStartTime().toNanos();
1221 final long endTime
= signal
.getCurrentRange().getEndTime().toNanos();
1222 Display
.getDefault().asyncExec(new Runnable() {
1225 if (fTimeGraphViewer
.getControl().isDisposed()) {
1228 fTimeGraphViewer
.setStartFinishTime(startTime
, endTime
);
1229 startZoomThread(startTime
, endTime
);
1235 * @param signal the format of the timestamps was updated.
1238 public void updateTimeFormat( final TmfTimestampFormatUpdateSignal signal
){
1239 fTimeGraphViewer
.refresh();
1243 * A marker event source has been updated
1250 public void markerEventSourceUpdated(final TmfMarkerEventSourceUpdatedSignal signal
) {
1251 getTimeGraphViewer().setMarkerCategories(getMarkerCategories());
1252 getTimeGraphViewer().setMarkers(null);
1256 // ------------------------------------------------------------------------
1258 // ------------------------------------------------------------------------
1260 private void loadTrace(final ITmfTrace trace
) {
1261 if (fZoomThread
!= null) {
1262 fZoomThread
.cancel();
1265 if (fTrace
!= null) {
1266 /* save the filters of the previous trace */
1267 fFiltersMap
.put(fTrace
, fTimeGraphViewer
.getFilters());
1268 fViewContext
.put(fTrace
, new ViewContext(fCurrentSortColumn
, fSortDirection
, fTimeGraphViewer
.getSelection()));
1272 LOGGER
.info(() -> getLogMessage("LoadingTrace", "trace=" + trace
.getName())); //$NON-NLS-1$ //$NON-NLS-2$
1274 restoreViewContext();
1275 fEditorFile
= TmfTraceManager
.getInstance().getTraceEditorFile(trace
);
1276 synchronized (fEntryListMap
) {
1277 fEntryList
= fEntryListMap
.get(fTrace
);
1278 if (fEntryList
== null) {
1281 setStartTime(fTrace
.getStartTime().toNanos());
1282 setEndTime(fTrace
.getEndTime().toNanos());
1289 * Forces a rebuild of the entries list, even if entries already exist for this trace
1291 protected void rebuild() {
1292 setStartTime(Long
.MAX_VALUE
);
1293 setEndTime(Long
.MIN_VALUE
);
1295 ITmfTrace viewTrace
= fTrace
;
1296 if (viewTrace
== null) {
1299 resetView(viewTrace
);
1301 List
<IMarkerEventSource
> markerEventSources
= new ArrayList
<>();
1302 synchronized (fBuildJobMap
) {
1303 for (ITmfTrace trace
: getTracesToBuild(viewTrace
)) {
1304 if (trace
== null) {
1307 List
<@NonNull IMarkerEventSource
> adapters
= TmfTraceAdapterManager
.getAdapters(trace
, IMarkerEventSource
.class);
1308 markerEventSources
.addAll(adapters
);
1310 Job buildJob
= new Job(getTitle() + Messages
.AbstractTimeGraphView_BuildJob
) {
1312 protected IStatus
run(IProgressMonitor monitor
) {
1313 new BuildRunnable(trace
, viewTrace
).run(monitor
);
1315 return Status
.OK_STATUS
;
1318 fBuildJobMap
.put(trace
, buildJob
);
1319 buildJob
.schedule();
1322 fMarkerEventSourcesMap
.put(viewTrace
, markerEventSources
);
1326 * Method called when synching to a given timestamp. Inheriting classes can
1327 * perform actions here to update the view at the given timestamp.
1330 * The currently selected time
1332 protected void synchingToTime(long time
) {
1337 * Return the list of traces whose data or analysis results will be used to
1338 * populate the view. By default, if the trace is an experiment, the traces
1339 * under it will be returned, otherwise, the trace itself is returned.
1341 * A build thread will be started for each trace returned by this method,
1342 * some of which may receive events in live streaming mode.
1345 * The trace associated with this view, can be null
1346 * @return List of traces with data to display
1348 protected @NonNull Iterable
<ITmfTrace
> getTracesToBuild(@Nullable ITmfTrace trace
) {
1349 return TmfTraceManager
.getTraceSet(trace
);
1353 * Build the entry list to show in this time graph view.
1355 * Called from the BuildJob for each trace returned by
1356 * {@link #getTracesToBuild(ITmfTrace)}.
1358 * Root entries must be added to the entry list by calling the
1359 * {@link #addToEntryList(ITmfTrace, List)} method with the list of entries
1360 * to add and where the trace in parameter should be the parentTrace.
1361 * Entries that are children of other entries will be automatically picked
1362 * up after refreshing the root entries.
1364 * The full event list is also normally computed for every entry that is
1365 * created. It should be set for each entry by calling the
1366 * {@link TimeGraphEntry#setEventList(List)}. These full event lists will be
1367 * used to display something while the zoomed event lists are being
1368 * calculated when the window range is updated. Also, when fully zoomed out,
1369 * it is this list of events that is displayed.
1371 * Also, when all the entries have been added and their events set, this
1372 * method can finish by calling the refresh() method like this:
1375 * if (parentTrace.equals(getTrace())) {
1381 * The trace being built
1382 * @param parentTrace
1383 * The parent of the trace set, or the trace itself
1385 * The progress monitor object
1388 protected abstract void buildEntryList(@NonNull ITmfTrace trace
, @NonNull ITmfTrace parentTrace
, @NonNull IProgressMonitor monitor
);
1391 * Gets the list of event for an entry in a given time range.
1393 * Called from the ZoomThread for every entry to update the zoomed event
1394 * list. Can be an empty implementation if the view does not support zoomed
1395 * event lists. Can also be used to compute the full event list.
1398 * The entry to get events for
1400 * Start of the time range
1402 * End of the time range
1406 * The progress monitor object
1407 * @return The list of events for the entry
1409 protected abstract @Nullable List
<@NonNull ITimeEvent
> getEventList(@NonNull TimeGraphEntry entry
,
1410 long startTime
, long endTime
, long resolution
,
1411 @NonNull IProgressMonitor monitor
);
1414 * Gets the list of links (displayed as arrows) for a trace in a given
1415 * timerange. Default implementation returns an empty list.
1418 * Start of the time range
1420 * End of the time range
1424 * The progress monitor object
1425 * @return The list of link events
1427 protected @Nullable List
<@NonNull ILinkEvent
> getLinkList(long startTime
, long endTime
,
1428 long resolution
, @NonNull IProgressMonitor monitor
) {
1429 return new ArrayList
<>();
1433 * Gets the list of view-specific marker categories. Default implementation
1434 * returns an empty list.
1436 * @return The list of marker categories
1439 protected @NonNull List
<String
> getViewMarkerCategories() {
1440 return new ArrayList
<>();
1444 * Gets the list of view-specific markers for a trace in a given time range.
1445 * Default implementation returns an empty list.
1448 * Start of the time range
1450 * End of the time range
1454 * The progress monitor object
1455 * @return The list of marker events
1458 protected @NonNull List
<IMarkerEvent
> getViewMarkerList(long startTime
, long endTime
,
1459 long resolution
, @NonNull IProgressMonitor monitor
) {
1460 return new ArrayList
<>();
1464 * Gets the list of trace-specific markers for a trace in a given time range.
1467 * Start of the time range
1469 * End of the time range
1473 * The progress monitor object
1474 * @return The list of marker events
1477 protected @NonNull List
<IMarkerEvent
> getTraceMarkerList(long startTime
, long endTime
,
1478 long resolution
, @NonNull IProgressMonitor monitor
) {
1479 List
<IMarkerEvent
> markers
= new ArrayList
<>();
1480 for (IMarkerEventSource markerEventSource
: getMarkerEventSources(fTrace
)) {
1481 markers
.addAll(markerEventSource
.getMarkerList(startTime
, endTime
, resolution
, monitor
));
1487 * Get the list of current marker categories.
1489 * @return The list of marker categories
1492 protected @NonNull List
<String
> getMarkerCategories() {
1493 Set
<String
> categories
= new LinkedHashSet
<>(getViewMarkerCategories());
1494 for (IMarkerEventSource markerEventSource
: getMarkerEventSources(fTrace
)) {
1495 categories
.addAll(markerEventSource
.getMarkerCategories());
1497 return new ArrayList
<>(categories
);
1501 * Gets the list of marker event sources for a given trace.
1505 * @return The list of marker event sources
1508 private @NonNull List
<IMarkerEventSource
> getMarkerEventSources(ITmfTrace trace
) {
1509 List
<IMarkerEventSource
> markerEventSources
= fMarkerEventSourcesMap
.get(trace
);
1510 if (markerEventSources
== null) {
1511 markerEventSources
= Collections
.emptyList();
1513 return markerEventSources
;
1517 * Refresh the display
1519 protected void refresh() {
1520 LOGGER
.info(() -> getLogMessage("RefreshRequested", null)); //$NON-NLS-1$
1521 final boolean zoomThread
= Thread
.currentThread() instanceof ZoomThread
;
1522 TmfUiRefreshHandler
.getInstance().queueUpdate(this, new Runnable() {
1525 LOGGER
.info(() -> getLogMessage("RefreshStart", null)); //$NON-NLS-1$
1526 if (fTimeGraphViewer
.getControl().isDisposed()) {
1529 fDirty
.incrementAndGet();
1531 synchronized (fEntryListMap
) {
1532 fEntryList
= fEntryListMap
.get(fTrace
);
1533 if (fEntryList
== null) {
1534 fEntryList
= new CopyOnWriteArrayList
<>();
1535 } else if (fEntryComparator
!= null) {
1536 List
<TimeGraphEntry
> list
= new ArrayList
<>(fEntryList
);
1537 Collections
.sort(list
, fEntryComparator
);
1538 for (ITimeGraphEntry entry
: list
) {
1539 sortChildren(entry
, fEntryComparator
);
1542 fEntryList
.addAll(list
);
1545 boolean inputChanged
= fEntryList
!= fTimeGraphViewer
.getInput();
1547 fTimeGraphViewer
.setInput(fEntryList
);
1548 /* restore the previously saved filters, if any */
1549 fTimeGraphViewer
.setFilters(fFiltersMap
.get(fTrace
));
1550 fTimeGraphViewer
.setLinks(null);
1551 fTimeGraphViewer
.setBookmarks(refreshBookmarks(fEditorFile
));
1552 fTimeGraphViewer
.setMarkerCategories(getMarkerCategories());
1553 fTimeGraphViewer
.setMarkers(null);
1556 fTimeGraphViewer
.refresh();
1559 if (fIsRevealSelection
) {
1560 fIsRevealSelection
= false;
1561 fTimeGraphViewer
.setSelection(fTimeGraphViewer
.getSelection(), true);
1563 long startBound
= (fStartTime
== Long
.MAX_VALUE ? SWT
.DEFAULT
: fStartTime
);
1564 long endBound
= (fEndTime
== Long
.MIN_VALUE ? SWT
.DEFAULT
: fEndTime
);
1565 fTimeGraphViewer
.setTimeBounds(startBound
, endBound
);
1567 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
1568 long selectionBeginTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getSelectionRange().getStartTime().toNanos();
1569 long selectionEndTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getSelectionRange().getEndTime().toNanos();
1570 long startTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getWindowRange().getStartTime().toNanos();
1571 long endTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getWindowRange().getEndTime().toNanos();
1572 startTime
= (fStartTime
== Long
.MAX_VALUE ? SWT
.DEFAULT
: Math
.max(startTime
, fStartTime
));
1573 endTime
= (fEndTime
== Long
.MIN_VALUE ? SWT
.DEFAULT
: Math
.min(endTime
, fEndTime
));
1574 fTimeGraphViewer
.setSelectionRange(selectionBeginTime
, selectionEndTime
, false);
1575 fTimeGraphViewer
.setStartFinishTime(startTime
, endTime
);
1577 if (inputChanged
&& selectionBeginTime
!= SWT
.DEFAULT
) {
1578 synchingToTime(selectionBeginTime
);
1582 startZoomThread(startTime
, endTime
);
1584 fDirty
.decrementAndGet();
1585 LOGGER
.info(() -> getLogMessage("RefreshEnd", null)); //$NON-NLS-1$
1593 protected void redraw() {
1594 synchronized (fSyncObj
) {
1595 if (fRedrawState
== State
.IDLE
) {
1596 fRedrawState
= State
.BUSY
;
1598 fRedrawState
= State
.PENDING
;
1602 LOGGER
.info(() -> getLogMessage("RedrawRequested", null)); //$NON-NLS-1$
1603 Display
.getDefault().asyncExec(new Runnable() {
1606 LOGGER
.info(() -> getLogMessage("RedrawStart", null)); //$NON-NLS-1$
1607 if (fTimeGraphViewer
.getControl().isDisposed()) {
1610 fTimeGraphViewer
.getControl().redraw();
1611 fTimeGraphViewer
.getControl().update();
1612 synchronized (fSyncObj
) {
1613 if (fRedrawState
== State
.PENDING
) {
1614 fRedrawState
= State
.IDLE
;
1617 fRedrawState
= State
.IDLE
;
1620 LOGGER
.info(() -> getLogMessage("RedrawEnd", null)); //$NON-NLS-1$
1625 private void sortChildren(ITimeGraphEntry entry
, Comparator
<ITimeGraphEntry
> comparator
) {
1626 if (entry
instanceof TimeGraphEntry
) {
1627 ((TimeGraphEntry
) entry
).sortChildren(comparator
);
1629 for (ITimeGraphEntry child
: entry
.getChildren()) {
1630 sortChildren(child
, comparator
);
1635 * Start or restart the zoom thread.
1638 * the zoom start time
1643 protected final void startZoomThread(long startTime
, long endTime
) {
1644 long clampedStartTime
= (fStartTime
== Long
.MAX_VALUE ? startTime
: Math
.min(Math
.max(startTime
, fStartTime
), fEndTime
));
1645 long clampedEndTime
= (fEndTime
== Long
.MIN_VALUE ? endTime
: Math
.max(Math
.min(endTime
, fEndTime
), fStartTime
));
1646 fDirty
.incrementAndGet();
1647 boolean restart
= false;
1648 if (fZoomThread
!= null) {
1649 fZoomThread
.cancel();
1650 if (fZoomThread
.fZoomStartTime
== clampedStartTime
&& fZoomThread
.fZoomEndTime
== clampedEndTime
) {
1654 long resolution
= Math
.max(1, (clampedEndTime
- clampedStartTime
) / fDisplayWidth
);
1655 fZoomThread
= createZoomThread(clampedStartTime
, clampedEndTime
, resolution
, restart
);
1656 if (fZoomThread
!= null) {
1657 // Don't start a new thread right away if results are being applied
1658 // from an old ZoomThread. Otherwise, the old results might
1659 // overwrite the new results if it finishes after.
1660 synchronized (fZoomThreadResultLock
) {
1661 fZoomThread
.start();
1664 fDirty
.decrementAndGet();
1669 * Create a zoom thread.
1672 * the zoom start time
1678 * true if restarting zoom for the same time range
1679 * @return a zoom thread
1682 protected @Nullable ZoomThread
createZoomThread(long startTime
, long endTime
, long resolution
, boolean restart
) {
1683 final List
<TimeGraphEntry
> entryList
= fEntryList
;
1684 if (entryList
== null) {
1687 return new ZoomThreadByEntry(entryList
, startTime
, endTime
, resolution
);
1690 private void makeActions() {
1691 fPreviousResourceAction
= fTimeGraphViewer
.getPreviousItemAction();
1692 fPreviousResourceAction
.setText(getPrevText());
1693 fPreviousResourceAction
.setToolTipText(getPrevTooltip());
1694 fNextResourceAction
= fTimeGraphViewer
.getNextItemAction();
1695 fNextResourceAction
.setText(getNextText());
1696 fNextResourceAction
.setToolTipText(getNextTooltip());
1699 private class MarkerSetAction
extends Action
{
1701 private MarkerSet fMarkerSet
;
1703 public MarkerSetAction(MarkerSet markerSet
) {
1704 super(markerSet
== null ? Messages
.AbstractTimeGraphView_MarkerSetNoneActionText
: markerSet
.getName(), IAction
.AS_RADIO_BUTTON
);
1705 fMarkerSet
= markerSet
;
1709 public void runWithEvent(Event event
) {
1710 MarkerUtils
.setDefaultMarkerSetId(fMarkerSet
== null ?
null : fMarkerSet
.getId());
1711 for (ITmfTrace trace
: TmfTraceManager
.getInstance().getOpenedTraces()) {
1712 for (IMarkerEventSource source
: TmfTraceAdapterManager
.getAdapters(trace
, IMarkerEventSource
.class)) {
1713 if (source
instanceof ConfigurableMarkerEventSource
) {
1714 ((ConfigurableMarkerEventSource
) source
).configure(fMarkerSet
);
1718 broadcast(new TmfMarkerEventSourceUpdatedSignal(AbstractTimeGraphView
.this));
1723 * Get the marker set menu
1725 * @return the menu manager object
1728 protected MenuManager
getMarkerSetMenu() {
1729 if (fMarkerSetMenu
!= null) {
1730 return fMarkerSetMenu
;
1732 fMarkerSetMenu
= new MenuManager(Messages
.AbstractTimeGraphView_MarkerSetMenuText
);
1733 fMarkerSetMenu
.setRemoveAllWhenShown(true);
1734 fMarkerSetMenu
.addMenuListener(new IMenuListener() {
1736 public void menuAboutToShow(IMenuManager mgr
) {
1737 Action action
= new MarkerSetAction(null);
1738 String defaultMarkerSetId
= MarkerUtils
.getDefaultMarkerSetId();
1739 action
.setChecked(defaultMarkerSetId
== null || defaultMarkerSetId
.isEmpty());
1741 List
<MarkerSet
> markerSets
= MarkerConfigXmlParser
.getMarkerSets();
1742 for (MarkerSet markerSet
: markerSets
) {
1743 action
= new MarkerSetAction(markerSet
);
1744 action
.setChecked(markerSet
.getId().equals(defaultMarkerSetId
));
1747 mgr
.add(new Separator());
1748 mgr
.add(new Action(Messages
.AbstractTimeGraphView_MarkerSetEditActionText
) {
1751 MarkerConfigXmlParser
.initMarkerSets();
1752 IWorkbenchPage page
= PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getActivePage();
1753 IFileStore fileStore
= EFS
.getLocalFileSystem().getStore(MarkerConfigXmlParser
.MARKER_CONFIG_PATH
);
1755 IDE
.openEditorOnFileStore(page
, fileStore
);
1756 } catch (PartInitException e
) {
1757 Activator
.getDefault().logError("Error opening editor on " + MarkerConfigXmlParser
.MARKER_CONFIG_PATH
, e
); //$NON-NLS-1$
1763 return fMarkerSetMenu
;
1766 private void contributeToActionBars() {
1767 IActionBars bars
= getViewSite().getActionBars();
1768 fillLocalToolBar(bars
.getToolBarManager());
1769 fillLocalMenu(bars
.getMenuManager());
1773 * Add actions to local tool bar manager
1775 * @param manager the tool bar manager
1777 protected void fillLocalToolBar(IToolBarManager manager
) {
1778 if (fFilterColumns
!= null && fFilterLabelProvider
!= null && fFilterColumns
.length
> 0) {
1779 manager
.add(fTimeGraphViewer
.getShowFilterDialogAction());
1781 manager
.add(fTimeGraphViewer
.getShowLegendAction());
1782 manager
.add(new Separator());
1783 manager
.add(fTimeGraphViewer
.getResetScaleAction());
1784 manager
.add(fTimeGraphViewer
.getPreviousEventAction());
1785 manager
.add(fTimeGraphViewer
.getNextEventAction());
1786 manager
.add(new Separator());
1787 manager
.add(fTimeGraphViewer
.getToggleBookmarkAction());
1788 manager
.add(fTimeGraphViewer
.getPreviousMarkerAction());
1789 manager
.add(fTimeGraphViewer
.getNextMarkerAction());
1790 manager
.add(new Separator());
1791 manager
.add(fPreviousResourceAction
);
1792 manager
.add(fNextResourceAction
);
1793 manager
.add(fTimeGraphViewer
.getZoomInAction());
1794 manager
.add(fTimeGraphViewer
.getZoomOutAction());
1795 manager
.add(new Separator());
1799 * Add actions to local menu manager
1801 * @param manager the tool bar manager
1804 protected void fillLocalMenu(IMenuManager manager
) {
1805 manager
.add(fTimeGraphViewer
.getMarkersMenu());
1806 manager
.add(getMarkerSetMenu());
1813 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
1814 if (fTimeGraphViewer
== null) {
1817 return fTimeGraphViewer
.getTimeViewAlignmentInfo();
1824 public int getAvailableWidth(int requestedOffset
) {
1825 if (fTimeGraphViewer
== null) {
1828 return fTimeGraphViewer
.getAvailableWidth(requestedOffset
);
1835 public void performAlign(int offset
, int width
) {
1836 if (fTimeGraphViewer
!= null) {
1837 fTimeGraphViewer
.performAlign(offset
, width
);
1842 * Returns whether or not the time graph view is dirty. The time graph view
1843 * is considered dirty if it has yet to completely update its model.
1845 * This method is meant to be used by tests in order to know when it is safe
1848 * Note: If a trace is smaller than the initial window range (see
1849 * {@link ITmfTrace#getInitialRangeOffset}) this method will return true
1852 * @return true if the time graph view has yet to completely update its
1853 * model, false otherwise
1856 public boolean isDirty() {
1857 if (fTrace
== null) {
1861 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
1862 long startTime
= ctx
.getWindowRange().getStartTime().toNanos();
1863 long endTime
= ctx
.getWindowRange().getEndTime().toNanos();
1865 // If the time graph control hasn't updated all the way to the end of
1866 // the window range then it's dirty. A refresh should happen later.
1867 if (fTimeGraphViewer
.getTime0() != startTime
|| fTimeGraphViewer
.getTime1() != endTime
) {
1871 if (fZoomThread
== null) {
1872 // The zoom thread is null but we might be just about to create it (refresh called).
1873 return fDirty
.get() != 0;
1875 // Dirty if the zoom thread is not done or if it hasn't zoomed all the
1876 // way to the end of the window range. In the latter case, there should be
1877 // a subsequent zoom thread that will be triggered.
1878 return fDirty
.get() != 0 || fZoomThread
.getZoomStartTime() != startTime
|| fZoomThread
.getZoomEndTime() != endTime
;
1881 private void createColumnSelectionListener(Tree tree
) {
1882 for (int i
= 0; i
< fColumnComparators
.length
; i
++) {
1883 final int index
= i
;
1884 final Comparator
<ITimeGraphEntry
> comp
= fColumnComparators
[index
];
1885 final TreeColumn column
= tree
.getColumn(i
);
1888 column
.addSelectionListener(new SelectionAdapter() {
1890 public void widgetSelected(SelectionEvent e
) {
1891 TreeColumn prevSortcolumn
= tree
.getSortColumn();
1892 int direction
= tree
.getSortDirection();
1893 if (prevSortcolumn
== column
) {
1894 direction
= (direction
== SWT
.DOWN
) ? SWT
.UP
: SWT
.DOWN
;
1896 direction
= SWT
.DOWN
;
1898 tree
.setSortColumn(column
);
1899 tree
.setSortDirection(direction
);
1900 fSortDirection
= direction
;
1901 fCurrentSortColumn
= index
;
1902 Comparator
<ITimeGraphEntry
> comparator
= comp
;
1904 if (comparator
instanceof ITimeGraphEntryComparator
) {
1905 ((ITimeGraphEntryComparator
) comparator
).setDirection(direction
);
1907 if (direction
!= SWT
.DOWN
) {
1908 comparator
= checkNotNull(Collections
.reverseOrder(comparator
));
1910 setEntryComparator(comparator
);
1911 fIsRevealSelection
= true;
1912 fTimeGraphViewer
.getControl().setFocus();
1920 private void restoreViewContext() {
1921 ViewContext viewContext
= fViewContext
.get(fTrace
);
1922 if (fColumnComparators
!= null) {
1923 // restore sort settings
1924 fSortDirection
= SWT
.DOWN
;
1925 fCurrentSortColumn
= fInitialSortColumn
;
1926 if (viewContext
!= null) {
1927 fSortDirection
= viewContext
.getSortDirection();
1928 fCurrentSortColumn
= viewContext
.getSortColumn();
1930 if ((fCurrentSortColumn
< fColumnComparators
.length
) && (fColumnComparators
[fCurrentSortColumn
] != null)) {
1931 Comparator
<ITimeGraphEntry
> comparator
= fColumnComparators
[fCurrentSortColumn
];
1932 if (comparator
instanceof ITimeGraphEntryComparator
) {
1933 ((ITimeGraphEntryComparator
) comparator
).setDirection(fSortDirection
);
1935 if (fSortDirection
!= SWT
.DOWN
) {
1936 comparator
= checkNotNull(Collections
.reverseOrder(comparator
));
1938 setEntryComparator(comparator
);
1943 private void applyViewContext() {
1944 ViewContext viewContext
= fViewContext
.get(fTrace
);
1945 if (fColumnComparators
!= null) {
1946 final Tree tree
= fTimeGraphViewer
.getTree();
1947 final TreeColumn column
= tree
.getColumn(fCurrentSortColumn
);
1948 tree
.setSortDirection(fSortDirection
);
1949 tree
.setSortColumn(column
);
1951 fTimeGraphViewer
.getControl().setFocus();
1952 // restore and reveal selection
1953 if ((viewContext
!= null) && (viewContext
.getSelection() != null)) {
1954 fTimeGraphViewer
.setSelection(viewContext
.getSelection(), true);
1956 fViewContext
.remove(fTrace
);
1959 private static class ViewContext
{
1960 private int fSortColumnIndex
;
1961 private int fSortDirection
;
1962 private @Nullable ITimeGraphEntry fSelection
;
1964 ViewContext(int sortColunm
, int sortDirection
, ITimeGraphEntry selection
) {
1965 fSortColumnIndex
= sortColunm
;
1966 fSortDirection
= sortDirection
;
1967 fSelection
= selection
;
1970 * @return the sortColumn
1972 public int getSortColumn() {
1973 return fSortColumnIndex
;
1976 * @return the sortDirection
1978 public int getSortDirection() {
1979 return fSortDirection
;
1982 * @return the selection
1984 public ITimeGraphEntry
getSelection() {
1990 * Method to reset the view internal data for a given trace.
1992 * When overriding this method make sure to call the super
1996 * trace to reset the view for.
1999 protected void resetView(ITmfTrace viewTrace
) {
2000 if (viewTrace
== null) {
2003 synchronized (fBuildJobMap
) {
2004 for (ITmfTrace trace
: getTracesToBuild(viewTrace
)) {
2005 Job buildJob
= fBuildJobMap
.remove(trace
);
2006 if (buildJob
!= null) {
2011 synchronized (fEntryListMap
) {
2012 fEntryListMap
.remove(viewTrace
);
2014 fViewContext
.remove(viewTrace
);
2015 fFiltersMap
.remove(viewTrace
);
2016 fMarkerEventSourcesMap
.remove(viewTrace
);
2017 if (viewTrace
== fTrace
) {
2018 if (fZoomThread
!= null) {
2019 fZoomThread
.cancel();
2025 private void createContextMenu() {
2026 fEntryMenuManager
.setRemoveAllWhenShown(true);
2027 TimeGraphControl timeGraphControl
= getTimeGraphViewer().getTimeGraphControl();
2028 final Menu entryMenu
= fEntryMenuManager
.createContextMenu(timeGraphControl
);
2029 timeGraphControl
.addTimeGraphEntryMenuListener(new MenuDetectListener() {
2031 public void menuDetected(MenuDetectEvent event
) {
2032 Point p
= timeGraphControl
.toControl(event
.x
, event
.y
);
2034 * The TimeGraphControl will call the TimeGraphEntryMenuListener
2035 * before the TimeEventMenuListener. If the event is triggered
2036 * on the name space then show the menu else clear the menu.
2038 if (p
.x
< getTimeGraphViewer().getNameSpace()) {
2039 timeGraphControl
.setMenu(entryMenu
);
2041 timeGraphControl
.setMenu(null);
2046 fEntryMenuManager
.addMenuListener(new IMenuListener() {
2048 public void menuAboutToShow(IMenuManager manager
) {
2049 fillTimeGraphEntryContextMenu(fEntryMenuManager
);
2050 fEntryMenuManager
.add(new GroupMarker(IWorkbenchActionConstants
.MB_ADDITIONS
));
2053 getSite().registerContextMenu(fEntryMenuManager
, fTimeGraphViewer
.getSelectionProvider());
2059 * @param menuManager
2060 * a menuManager to fill
2063 protected void fillTimeGraphEntryContextMenu (@NonNull IMenuManager menuManager
) {
2067 * Inner classes used for searching
2070 public ITimeGraphEntry
getSelection() {
2071 return fTimeGraphViewer
.getSelection();
2074 public void selectAndReveal(@NonNull ITimeGraphEntry entry
) {
2075 fTimeGraphViewer
.selectAndReveal(entry
);
2078 public ITimeGraphEntry
[] getEntries() {
2079 TimeGraphViewer viewer
= getTimeGraphViewer();
2080 return viewer
.getTimeGraphContentProvider().getElements(viewer
.getInput());
2083 public Shell
getShell() {
2084 return getSite().getShell();
2088 class TimeGraphPartListener
implements IPartListener
{
2090 public void partActivated(IWorkbenchPart part
) {
2091 if (part
== AbstractTimeGraphView
.this) {
2092 synchronized (FIND_ACTION
) {
2093 if (fFindActionHandler
== null) {
2094 fFindActionHandler
= new ActionHandler(FIND_ACTION
);
2096 if (fFindHandlerActivation
== null) {
2097 final Object service
= PlatformUI
.getWorkbench().getService(IHandlerService
.class);
2098 fFindHandlerActivation
= ((IHandlerService
) service
).activateHandler(ActionFactory
.FIND
.getCommandId(), fFindActionHandler
);
2102 // Notify action for all parts
2103 FIND_ACTION
.partActivated(part
);
2106 public void partDeactivated(IWorkbenchPart part
) {
2107 if ((part
== AbstractTimeGraphView
.this) && (fFindHandlerActivation
!= null)) {
2108 final Object service
= PlatformUI
.getWorkbench().getService(IHandlerService
.class);
2109 ((IHandlerService
) service
).deactivateHandler(fFindHandlerActivation
);
2110 fFindHandlerActivation
= null;
2114 public void partBroughtToTop(IWorkbenchPart part
) {
2117 public void partClosed(IWorkbenchPart part
) {
2120 public void partOpened(IWorkbenchPart part
) {