1 /*******************************************************************************
2 * Copyright (c) 2012, 2016 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
.regex
.Matcher
;
32 import java
.util
.regex
.Pattern
;
34 import org
.eclipse
.core
.resources
.IFile
;
35 import org
.eclipse
.core
.resources
.IMarker
;
36 import org
.eclipse
.core
.resources
.IMarkerDelta
;
37 import org
.eclipse
.core
.resources
.IResource
;
38 import org
.eclipse
.core
.resources
.IResourceChangeEvent
;
39 import org
.eclipse
.core
.resources
.IResourceChangeListener
;
40 import org
.eclipse
.core
.resources
.IWorkspaceRunnable
;
41 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
42 import org
.eclipse
.core
.runtime
.CoreException
;
43 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
44 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
45 import org
.eclipse
.jdt
.annotation
.NonNull
;
46 import org
.eclipse
.jdt
.annotation
.Nullable
;
47 import org
.eclipse
.jface
.action
.Action
;
48 import org
.eclipse
.jface
.action
.GroupMarker
;
49 import org
.eclipse
.jface
.action
.IAction
;
50 import org
.eclipse
.jface
.action
.IMenuListener
;
51 import org
.eclipse
.jface
.action
.IMenuManager
;
52 import org
.eclipse
.jface
.action
.IStatusLineManager
;
53 import org
.eclipse
.jface
.action
.IToolBarManager
;
54 import org
.eclipse
.jface
.action
.MenuManager
;
55 import org
.eclipse
.jface
.action
.Separator
;
56 import org
.eclipse
.jface
.viewers
.AbstractTreeViewer
;
57 import org
.eclipse
.jface
.viewers
.ILabelProvider
;
58 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
59 import org
.eclipse
.jface
.viewers
.ISelectionProvider
;
60 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
61 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
62 import org
.eclipse
.jface
.viewers
.TreeSelection
;
63 import org
.eclipse
.jface
.viewers
.TreeViewer
;
64 import org
.eclipse
.jface
.viewers
.ViewerFilter
;
65 import org
.eclipse
.osgi
.util
.NLS
;
66 import org
.eclipse
.swt
.SWT
;
67 import org
.eclipse
.swt
.events
.MenuDetectEvent
;
68 import org
.eclipse
.swt
.events
.MenuDetectListener
;
69 import org
.eclipse
.swt
.events
.SelectionAdapter
;
70 import org
.eclipse
.swt
.events
.SelectionEvent
;
71 import org
.eclipse
.swt
.graphics
.Image
;
72 import org
.eclipse
.swt
.graphics
.Point
;
73 import org
.eclipse
.swt
.graphics
.RGBA
;
74 import org
.eclipse
.swt
.widgets
.Composite
;
75 import org
.eclipse
.swt
.widgets
.Display
;
76 import org
.eclipse
.swt
.widgets
.Menu
;
77 import org
.eclipse
.swt
.widgets
.Tree
;
78 import org
.eclipse
.swt
.widgets
.TreeColumn
;
79 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
80 import org
.eclipse
.tracecompass
.tmf
.core
.resources
.ITmfMarker
;
81 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSelectionRangeUpdatedSignal
;
82 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
83 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTimestampFormatUpdateSignal
;
84 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
85 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
86 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
87 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfWindowRangeUpdatedSignal
;
88 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfNanoTimestamp
;
89 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
90 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
91 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceAdapterManager
;
92 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceContext
;
93 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
94 import org
.eclipse
.tracecompass
.tmf
.ui
.TmfUiRefreshHandler
;
95 import org
.eclipse
.tracecompass
.tmf
.ui
.signal
.TmfTimeViewAlignmentInfo
;
96 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.ITmfTimeAligned
;
97 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
98 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphBookmarkListener
;
99 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphContentProvider
;
100 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphPresentationProvider2
;
101 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphRangeListener
;
102 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphSelectionListener
;
103 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
104 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphBookmarkEvent
;
105 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
106 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphContentProvider
;
107 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphPresentationProvider
;
108 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphRangeUpdateEvent
;
109 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
110 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphViewer
;
111 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ILinkEvent
;
112 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.IMarkerEvent
;
113 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.IMarkerEventSource
;
114 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
115 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
116 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.MarkerEvent
;
117 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
118 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphControl
;
119 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
120 import org
.eclipse
.ui
.IActionBars
;
121 import org
.eclipse
.ui
.IWorkbenchActionConstants
;
124 * An abstract view all time graph views can inherit
126 * This view contains either a time graph viewer, or a time graph combo which is
127 * divided between a tree viewer on the left and a time graph viewer on the right.
129 public abstract class AbstractTimeGraphView
extends TmfView
implements ITmfTimeAligned
, IResourceChangeListener
{
131 /** Constant indicating that all levels of the time graph should be expanded */
132 protected static final int ALL_LEVELS
= AbstractTreeViewer
.ALL_LEVELS
;
134 private static final Pattern RGBA_PATTERN
= Pattern
.compile("RGBA \\{(\\d+), (\\d+), (\\d+), (\\d+)\\}"); //$NON-NLS-1$
143 // ------------------------------------------------------------------------
145 // ------------------------------------------------------------------------
147 /** The timegraph wrapper */
148 private ITimeGraphWrapper fTimeGraphWrapper
;
150 private AtomicInteger fDirty
= new AtomicInteger();
152 /** The selected trace */
153 private ITmfTrace fTrace
;
155 /** The selected trace editor file*/
156 private IFile fEditorFile
;
158 /** The timegraph entry list */
159 private List
<TimeGraphEntry
> fEntryList
;
161 /** The trace to entry list hash map */
162 private final Map
<ITmfTrace
, List
<TimeGraphEntry
>> fEntryListMap
= new HashMap
<>();
164 /** The trace to filters hash map */
165 private final Map
<ITmfTrace
, @NonNull ViewerFilter
[]> fFiltersMap
= new HashMap
<>();
167 /** The trace to view context hash map */
168 private final Map
<ITmfTrace
, ViewContext
> fViewContext
= new HashMap
<>();
170 /** The trace to marker event sources hash map */
171 private final Map
<ITmfTrace
, List
<IMarkerEventSource
>> fMarkerEventSourcesMap
= new HashMap
<>();
173 /** The trace to build thread hash map */
174 private final Map
<ITmfTrace
, BuildThread
> fBuildThreadMap
= new HashMap
<>();
176 /** The start time */
177 private long fStartTime
= SWT
.DEFAULT
;
180 private long fEndTime
= SWT
.DEFAULT
;
182 /** The display width */
183 private final int fDisplayWidth
;
185 /** The zoom thread */
186 private ZoomThread fZoomThread
;
188 /** The next resource action */
189 private Action fNextResourceAction
;
191 /** The previous resource action */
192 private Action fPreviousResourceAction
;
194 /** A comparator class */
195 private Comparator
<ITimeGraphEntry
> fEntryComparator
= null;
197 /** The redraw state used to prevent unnecessary queuing of display runnables */
198 private State fRedrawState
= State
.IDLE
;
200 /** The redraw synchronization object */
201 private final Object fSyncObj
= new Object();
203 /** The presentation provider for this view */
204 private final TimeGraphPresentationProvider fPresentation
;
206 /** The tree column label array, or null if combo is not used */
207 private String
[] fColumns
;
209 private Comparator
<ITimeGraphEntry
>[] fColumnComparators
;
211 /** The tree label provider, or null if combo is not used */
212 private TreeLabelProvider fLabelProvider
= null;
214 /** The time graph content provider */
215 private @NonNull ITimeGraphContentProvider fTimeGraphContentProvider
= new TimeGraphContentProvider();
217 /** The relative weight of the sash, ignored if combo is not used */
218 private int[] fWeight
= { 1, 3 };
220 /** The filter column label array, or null if filter is not used */
221 private String
[] fFilterColumns
;
223 /** The pack done flag */
224 private boolean fPackDone
= false;
226 /** The filter content provider, or null if filter is not used */
227 private ITreeContentProvider fFilterContentProvider
;
229 /** The filter label provider, or null if filter is not used */
230 private TreeLabelProvider fFilterLabelProvider
;
232 private int fAutoExpandLevel
= ALL_LEVELS
;
234 /** The default column index for sorting */
235 private int fInitialSortColumn
= 0;
237 /** The default column index for sorting */
238 private int fCurrentSortColumn
= 0;
240 /** The current sort direction */
241 private int fSortDirection
= SWT
.DOWN
;
243 /** Flag to indicate to reveal selection */
244 private volatile boolean fIsRevealSelection
= false;
247 * Menu Manager for context-sensitive menu for time graph entries.
248 * This will be used on the tree viewer in case of the time graph combo
249 * or the on the namespace in case of a single time graph viewer.
251 private final @NonNull MenuManager fEntryMenuManager
= new MenuManager();
253 // ------------------------------------------------------------------------
255 // ------------------------------------------------------------------------
257 private interface ITimeGraphWrapper
{
259 void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider
);
261 void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider
);
263 TimeGraphViewer
getTimeGraphViewer();
265 void addSelectionListener(ITimeGraphSelectionListener listener
);
267 ISelectionProvider
getSelectionProvider();
271 boolean isDisposed();
275 void setInput(Object input
);
279 void setFilters(@NonNull ViewerFilter
[] filters
);
281 @NonNull ViewerFilter
[] getFilters();
287 void setAutoExpandLevel(int level
);
289 boolean getExpandedState(ITimeGraphEntry entry
);
291 void setExpandedState(ITimeGraphEntry entry
, boolean expanded
);
293 void setFilterColumns(String
[] columnNames
);
295 void setFilterContentProvider(ITreeContentProvider contentProvider
);
297 void setFilterLabelProvider(ITableLabelProvider labelProvider
);
299 IAction
getShowFilterDialogAction();
301 void performAlign(int offset
, int width
);
303 TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo();
305 int getAvailableWidth(int requestedOffset
);
307 ITimeGraphEntry
getSelection();
309 void setSelection(ITimeGraphEntry selection
);
312 private class TimeGraphViewerWrapper
implements ITimeGraphWrapper
{
313 private TimeGraphViewer viewer
;
315 private TimeGraphViewerWrapper(Composite parent
, int style
) {
316 viewer
= new TimeGraphViewer(parent
, style
);
320 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider
) {
321 viewer
.setTimeGraphContentProvider(timeGraphContentProvider
);
325 public void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider
) {
326 viewer
.setTimeGraphProvider(timeGraphPresentationProvider
);
330 public TimeGraphViewer
getTimeGraphViewer() {
335 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
336 viewer
.addSelectionListener(listener
);
340 public ISelectionProvider
getSelectionProvider() {
341 return viewer
.getSelectionProvider();
345 public void setFocus() {
350 public boolean isDisposed() {
351 return viewer
.getControl().isDisposed();
355 public void setInput(Object input
) {
356 viewer
.setInput(input
);
360 public Object
getInput() {
361 return viewer
.getInput();
365 public void setFilterColumns(String
[] columnNames
) {
366 viewer
.setFilterColumns(columnNames
);
370 public void setFilterContentProvider(ITreeContentProvider contentProvider
) {
371 viewer
.setFilterContentProvider(contentProvider
);
375 public void setFilterLabelProvider(ITableLabelProvider labelProvider
) {
376 viewer
.setFilterLabelProvider(labelProvider
);
380 public void setFilters(@NonNull ViewerFilter
[] filters
) {
381 viewer
.setFilters(filters
);
385 public @NonNull ViewerFilter
[] getFilters() {
386 return viewer
.getFilters();
390 public IAction
getShowFilterDialogAction() {
391 return viewer
.getShowFilterDialogAction();
395 public void refresh() {
400 public void redraw() {
401 viewer
.getControl().redraw();
405 public void update() {
406 viewer
.getControl().update();
410 public void setAutoExpandLevel(int level
) {
411 viewer
.setAutoExpandLevel(level
);
415 public boolean getExpandedState(ITimeGraphEntry entry
) {
416 return viewer
.getExpandedState(entry
);
420 public void setExpandedState(ITimeGraphEntry entry
, boolean expanded
) {
421 viewer
.setExpandedState(entry
, expanded
);
425 public void performAlign(int offset
, int width
) {
426 viewer
.performAlign(offset
, width
);
430 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
431 return viewer
.getTimeViewAlignmentInfo();
435 public int getAvailableWidth(int requestedOffset
) {
436 return viewer
.getAvailableWidth(requestedOffset
);
440 public ITimeGraphEntry
getSelection() {
441 return viewer
.getSelection();
445 public void setSelection(ITimeGraphEntry selection
) {
446 viewer
.setSelection(selection
);
450 private class TimeGraphComboWrapper
implements ITimeGraphWrapper
{
451 private TimeGraphCombo combo
;
453 private TimeGraphComboWrapper(Composite parent
, int style
) {
454 combo
= new TimeGraphCombo(parent
, style
, fWeight
);
458 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider
) {
459 combo
.setTimeGraphContentProvider(timeGraphContentProvider
);
463 public void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider
) {
464 combo
.setTimeGraphProvider(timeGraphPresentationProvider
);
468 public TimeGraphViewer
getTimeGraphViewer() {
469 return combo
.getTimeGraphViewer();
473 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
474 combo
.addSelectionListener(listener
);
478 public ISelectionProvider
getSelectionProvider() {
479 return combo
.getTreeViewer();
483 public void setFocus() {
488 public boolean isDisposed() {
489 return combo
.isDisposed();
493 public void setInput(Object input
) {
494 combo
.setInput(input
);
498 public Object
getInput() {
499 return combo
.getInput();
503 public void setFilterColumns(String
[] columnNames
) {
504 combo
.setFilterColumns(columnNames
);
508 public void setFilterContentProvider(ITreeContentProvider contentProvider
) {
509 combo
.setFilterContentProvider(contentProvider
);
513 public void setFilterLabelProvider(ITableLabelProvider labelProvider
) {
514 combo
.setFilterLabelProvider(labelProvider
);
518 public void setFilters(@NonNull ViewerFilter
[] filters
) {
519 combo
.setFilters(filters
);
523 public @NonNull ViewerFilter
[] getFilters() {
524 return combo
.getFilters();
528 public IAction
getShowFilterDialogAction() {
529 return combo
.getShowFilterDialogAction();
533 public void refresh() {
538 public void redraw() {
543 public void update() {
548 public void setAutoExpandLevel(int level
) {
549 combo
.setAutoExpandLevel(level
);
553 public boolean getExpandedState(ITimeGraphEntry entry
) {
554 return combo
.getExpandedState(entry
);
558 public void setExpandedState(ITimeGraphEntry entry
, boolean expanded
) {
559 combo
.setExpandedState(entry
, expanded
);
562 TimeGraphCombo
getTimeGraphCombo() {
566 TreeViewer
getTreeViewer() {
567 return combo
.getTreeViewer();
571 public void performAlign(int offset
, int width
) {
572 combo
.performAlign(offset
, width
);
576 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
577 return combo
.getTimeViewAlignmentInfo();
581 public int getAvailableWidth(int requestedOffset
) {
582 return combo
.getAvailableWidth(requestedOffset
);
586 public ITimeGraphEntry
getSelection() {
587 return combo
.getTimeGraphViewer().getSelection();
591 public void setSelection(ITimeGraphEntry selection
) {
592 combo
.setSelection(selection
);
597 * Base class to provide the labels for the tree viewer. Views extending
598 * this class typically need to override the getColumnText method if they
599 * have more than one column to display
601 protected static class TreeLabelProvider
implements ITableLabelProvider
, ILabelProvider
{
604 public void addListener(ILabelProviderListener listener
) {
608 public void dispose() {
612 public boolean isLabelProperty(Object element
, String property
) {
617 public void removeListener(ILabelProviderListener listener
) {
621 public Image
getColumnImage(Object element
, int columnIndex
) {
626 public String
getColumnText(Object element
, int columnIndex
) {
627 TimeGraphEntry entry
= (TimeGraphEntry
) element
;
628 if (columnIndex
== 0) {
629 return entry
.getName();
635 public Image
getImage(Object element
) {
640 public String
getText(Object element
) {
641 TimeGraphEntry entry
= (TimeGraphEntry
) element
;
642 return entry
.getName();
647 private class BuildThread
extends Thread
{
648 private final @NonNull ITmfTrace fBuildTrace
;
649 private final @NonNull ITmfTrace fParentTrace
;
650 private final @NonNull IProgressMonitor fMonitor
;
652 public BuildThread(final @NonNull ITmfTrace trace
, final @NonNull ITmfTrace parentTrace
, final String name
) {
653 super(name
+ " build"); //$NON-NLS-1$
655 fParentTrace
= parentTrace
;
656 fMonitor
= new NullProgressMonitor();
661 buildEventList(fBuildTrace
, fParentTrace
, fMonitor
);
662 synchronized (fBuildThreadMap
) {
663 fBuildThreadMap
.remove(fBuildTrace
);
667 public void cancel() {
668 fMonitor
.setCanceled(true);
676 protected abstract class ZoomThread
extends Thread
{
677 private final long fZoomStartTime
;
678 private final long fZoomEndTime
;
679 private final long fResolution
;
680 private final @NonNull IProgressMonitor fMonitor
;
692 public ZoomThread(long startTime
, long endTime
, long resolution
) {
693 super(AbstractTimeGraphView
.this.getName() + " zoom"); //$NON-NLS-1$
694 fZoomStartTime
= startTime
;
695 fZoomEndTime
= endTime
;
696 fResolution
= resolution
;
697 fMonitor
= new NullProgressMonitor();
701 * @return the zoom start time
703 public long getZoomStartTime() {
704 return fZoomStartTime
;
708 * @return the zoom end time
710 public long getZoomEndTime() {
715 * @return the resolution
717 public long getResolution() {
722 * @return the monitor
724 public @NonNull IProgressMonitor
getMonitor() {
729 * Cancel the zoom thread
731 public void cancel() {
732 fMonitor
.setCanceled(true);
736 public final void run() {
738 fDirty
.decrementAndGet();
742 * Run the zoom operation.
745 public abstract void doRun();
748 private class ZoomThreadByEntry
extends ZoomThread
{
749 private final @NonNull List
<TimeGraphEntry
> fZoomEntryList
;
751 public ZoomThreadByEntry(@NonNull List
<TimeGraphEntry
> entryList
, long startTime
, long endTime
, long resolution
) {
752 super(startTime
, endTime
, resolution
);
753 fZoomEntryList
= entryList
;
757 public void doRun() {
758 for (TimeGraphEntry entry
: fZoomEntryList
) {
759 if (getMonitor().isCanceled()) {
765 zoom(entry
, getMonitor());
767 /* Refresh the arrows when zooming */
768 List
<ILinkEvent
> events
= getLinkList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
769 if (events
!= null) {
770 fTimeGraphWrapper
.getTimeGraphViewer().setLinks(events
);
773 /* Refresh the view-specific markers when zooming */
774 List
<IMarkerEvent
> markers
= new ArrayList
<>(getViewMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
775 /* Refresh the trace-specific markers when zooming */
776 markers
.addAll(getTraceMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
777 fTimeGraphWrapper
.getTimeGraphViewer().setMarkers(markers
);
781 private void zoom(@NonNull TimeGraphEntry entry
, @NonNull IProgressMonitor monitor
) {
782 if (getZoomStartTime() <= fStartTime
&& getZoomEndTime() >= fEndTime
) {
783 entry
.setZoomedEventList(null);
785 List
<ITimeEvent
> zoomedEventList
= getEventList(entry
, getZoomStartTime(), getZoomEndTime(), getResolution(), monitor
);
786 if (zoomedEventList
!= null) {
787 entry
.setZoomedEventList(zoomedEventList
);
791 for (ITimeGraphEntry child
: entry
.getChildren()) {
792 if (monitor
.isCanceled()) {
795 if (child
instanceof TimeGraphEntry
) {
796 zoom((TimeGraphEntry
) child
, monitor
);
803 // ------------------------------------------------------------------------
805 // ------------------------------------------------------------------------
808 * Constructs a time graph view that contains either a time graph viewer or
809 * a time graph combo.
811 * By default, the view uses a time graph viewer. To use a time graph combo,
812 * the subclass constructor must call {@link #setTreeColumns(String[])} and
813 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
818 * The presentation provider
820 public AbstractTimeGraphView(String id
, TimeGraphPresentationProvider pres
) {
822 fPresentation
= pres
;
823 fDisplayWidth
= Display
.getDefault().getBounds().width
;
826 // ------------------------------------------------------------------------
827 // Getters and setters
828 // ------------------------------------------------------------------------
831 * Getter for the time graph combo
833 * @return The time graph combo, or null if combo is not used
835 protected TimeGraphCombo
getTimeGraphCombo() {
836 if (fTimeGraphWrapper
instanceof TimeGraphComboWrapper
) {
837 return ((TimeGraphComboWrapper
) fTimeGraphWrapper
).getTimeGraphCombo();
843 * Getter for the time graph viewer
845 * @return The time graph viewer
847 protected TimeGraphViewer
getTimeGraphViewer() {
848 return fTimeGraphWrapper
.getTimeGraphViewer();
852 * Getter for the presentation provider
854 * @return The time graph presentation provider
856 protected ITimeGraphPresentationProvider2
getPresentationProvider() {
857 return fPresentation
;
861 * Sets the tree column labels.
863 * This should be called from the constructor.
866 * The array of tree column labels
868 protected void setTreeColumns(final String
[] columns
) {
869 setTreeColumns(columns
, null, 0);
873 * Sets the tree column labels.
875 * This should be called from the constructor.
878 * The array of tree column labels
880 * An array of column comparators for sorting of columns when
881 * clicking on column header
882 * @param initialSortColumn
883 * Index of column to sort initially
886 protected void setTreeColumns(final String
[] columns
, final Comparator
<ITimeGraphEntry
>[] comparators
, int initialSortColumn
) {
887 checkPartNotCreated();
889 fColumnComparators
= comparators
;
890 fInitialSortColumn
= initialSortColumn
;
894 * Sets the tree label provider.
896 * This should be called from the constructor.
899 * The tree label provider
901 protected void setTreeLabelProvider(final TreeLabelProvider tlp
) {
902 checkPartNotCreated();
903 fLabelProvider
= tlp
;
907 * Sets the time graph content provider.
909 * This should be called from the constructor.
912 * The time graph content provider
915 protected void setTimeGraphContentProvider(final @NonNull ITimeGraphContentProvider tgcp
) {
916 checkPartNotCreated();
917 fTimeGraphContentProvider
= tgcp
;
921 * Sets the relative weight of each part of the time graph combo.
923 * This should be called from the constructor.
926 * The array (length 2) of relative weights of each part of the combo
928 protected void setWeight(final int[] weights
) {
929 checkPartNotCreated();
934 * Sets the filter column labels.
936 * This should be called from the constructor.
938 * @param filterColumns
939 * The array of filter column labels
941 protected void setFilterColumns(final String
[] filterColumns
) {
942 checkPartNotCreated();
943 fFilterColumns
= filterColumns
;
947 * Sets the filter content provider.
949 * This should be called from the constructor.
951 * @param contentProvider
952 * The filter content provider
955 protected void setFilterContentProvider(final ITreeContentProvider contentProvider
) {
956 checkPartNotCreated();
957 fFilterContentProvider
= contentProvider
;
961 * Sets the filter label provider.
963 * This should be called from the constructor.
965 * @param labelProvider
966 * The filter label provider
968 protected void setFilterLabelProvider(final TreeLabelProvider labelProvider
) {
969 checkPartNotCreated();
970 fFilterLabelProvider
= labelProvider
;
973 private void checkPartNotCreated() {
974 if (getParentComposite() != null) {
975 throw new IllegalStateException("This method must be called before createPartControl."); //$NON-NLS-1$
980 * Gets the display width
982 * @return the display width
984 protected int getDisplayWidth() {
985 return fDisplayWidth
;
989 * Gets the comparator for the entries
991 * @return The entry comparator
993 protected Comparator
<ITimeGraphEntry
> getEntryComparator() {
994 return fEntryComparator
;
998 * Sets the comparator class for the entries.
1000 * This comparator will apply recursively to entries that implement
1001 * {@link TimeGraphEntry#sortChildren(Comparator)}.
1004 * A comparator object
1006 protected void setEntryComparator(final Comparator
<ITimeGraphEntry
> comparator
) {
1007 fEntryComparator
= comparator
;
1011 * Gets the trace displayed in the view
1015 protected ITmfTrace
getTrace() {
1020 * Gets the start time
1022 * @return The start time
1024 protected long getStartTime() {
1029 * Sets the start time
1034 protected void setStartTime(long time
) {
1041 * @return The end time
1043 protected long getEndTime() {
1053 protected void setEndTime(long time
) {
1058 * Sets the auto-expand level to be used for the input of the view. The
1059 * value 0 means that there is no auto-expand; 1 means that top-level
1060 * elements are expanded, but not their children; 2 means that top-level
1061 * elements are expanded, and their children, but not grand-children; and so
1064 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
1068 * non-negative level, or <code>ALL_LEVELS</code> to expand all
1069 * levels of the tree
1071 protected void setAutoExpandLevel(int level
) {
1072 fAutoExpandLevel
= level
;
1073 ITimeGraphWrapper tgWrapper
= fTimeGraphWrapper
;
1074 if (tgWrapper
!= null) {
1075 tgWrapper
.setAutoExpandLevel(level
);
1080 * Gets the entry list for a trace
1085 * @return the entry list map
1087 protected List
<TimeGraphEntry
> getEntryList(ITmfTrace trace
) {
1088 synchronized (fEntryListMap
) {
1089 return fEntryListMap
.get(trace
);
1094 * Adds a trace entry list to the entry list map
1099 * the list of time graph entries
1101 protected void putEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
1102 synchronized (fEntryListMap
) {
1103 fEntryListMap
.put(trace
, new CopyOnWriteArrayList
<>(list
));
1108 * Adds a list of entries to a trace's entry list
1113 * the list of time graph entries to add
1115 protected void addToEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
1116 synchronized (fEntryListMap
) {
1117 List
<TimeGraphEntry
> entryList
= fEntryListMap
.get(trace
);
1118 if (entryList
== null) {
1119 fEntryListMap
.put(trace
, new CopyOnWriteArrayList
<>(list
));
1121 entryList
.addAll(list
);
1127 * Removes a list of entries from a trace's entry list
1132 * the list of time graph entries to remove
1134 protected void removeFromEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
1135 synchronized (fEntryListMap
) {
1136 List
<TimeGraphEntry
> entryList
= fEntryListMap
.get(trace
);
1137 if (entryList
!= null) {
1138 entryList
.removeAll(list
);
1144 * Text for the "next" button
1146 * @return The "next" button text
1148 protected String
getNextText() {
1149 return Messages
.AbstractTimeGraphtView_NextText
;
1153 * Tooltip for the "next" button
1155 * @return Tooltip for the "next" button
1157 protected String
getNextTooltip() {
1158 return Messages
.AbstractTimeGraphView_NextTooltip
;
1162 * Text for the "Previous" button
1164 * @return The "Previous" button text
1166 protected String
getPrevText() {
1167 return Messages
.AbstractTimeGraphView_PreviousText
;
1171 * Tooltip for the "previous" button
1173 * @return Tooltip for the "previous" button
1175 protected String
getPrevTooltip() {
1176 return Messages
.AbstractTimeGraphView_PreviousTooltip
;
1179 // ------------------------------------------------------------------------
1181 // ------------------------------------------------------------------------
1184 public void createPartControl(Composite parent
) {
1185 super.createPartControl(parent
);
1186 if (fColumns
== null || fLabelProvider
== null) {
1187 fTimeGraphWrapper
= new TimeGraphViewerWrapper(parent
, SWT
.NONE
);
1189 TimeGraphComboWrapper wrapper
= new TimeGraphComboWrapper(parent
, SWT
.NONE
);
1190 fTimeGraphWrapper
= wrapper
;
1191 TimeGraphCombo combo
= wrapper
.getTimeGraphCombo();
1192 combo
.setTreeContentProvider(fTimeGraphContentProvider
);
1193 combo
.setTreeLabelProvider(fLabelProvider
);
1194 combo
.setTreeColumns(fColumns
);
1195 if (fColumnComparators
!= null) {
1196 createColumnSelectionListener(combo
.getTreeViewer());
1198 // Add double click listener to tree viewer
1199 createDoubleClickListener(combo
.getTreeViewer());
1201 fTimeGraphWrapper
.setTimeGraphContentProvider(fTimeGraphContentProvider
);
1202 fTimeGraphWrapper
.setFilterContentProvider(fFilterContentProvider
!= null ? fFilterContentProvider
: fTimeGraphContentProvider
);
1203 fTimeGraphWrapper
.setFilterLabelProvider(fFilterLabelProvider
);
1204 fTimeGraphWrapper
.setFilterColumns(fFilterColumns
);
1206 fTimeGraphWrapper
.setTimeGraphPresentationProvider(fPresentation
);
1207 fTimeGraphWrapper
.setAutoExpandLevel(fAutoExpandLevel
);
1209 fTimeGraphWrapper
.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
1211 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event
) {
1212 final long startTime
= event
.getStartTime();
1213 final long endTime
= event
.getEndTime();
1214 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
1215 broadcast(new TmfWindowRangeUpdatedSignal(AbstractTimeGraphView
.this, range
));
1216 startZoomThread(startTime
, endTime
);
1220 fTimeGraphWrapper
.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
1222 public void timeSelected(TimeGraphTimeEvent event
) {
1223 TmfNanoTimestamp startTime
= new TmfNanoTimestamp(event
.getBeginTime());
1224 TmfNanoTimestamp endTime
= new TmfNanoTimestamp(event
.getEndTime());
1225 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractTimeGraphView
.this, startTime
, endTime
));
1229 fTimeGraphWrapper
.getTimeGraphViewer().addBookmarkListener(new ITimeGraphBookmarkListener() {
1231 public void bookmarkAdded(final TimeGraphBookmarkEvent event
) {
1233 ResourcesPlugin
.getWorkspace().run(new IWorkspaceRunnable() {
1235 public void run(IProgressMonitor monitor
) throws CoreException
{
1236 IMarkerEvent bookmark
= event
.getBookmark();
1237 IMarker marker
= fEditorFile
.createMarker(IMarker
.BOOKMARK
);
1238 marker
.setAttribute(IMarker
.MESSAGE
, bookmark
.getLabel());
1239 marker
.setAttribute(ITmfMarker
.MARKER_TIME
, Long
.toString(bookmark
.getTime()));
1240 if (bookmark
.getDuration() > 0) {
1241 marker
.setAttribute(ITmfMarker
.MARKER_DURATION
, Long
.toString(bookmark
.getDuration()));
1242 marker
.setAttribute(IMarker
.LOCATION
,
1243 NLS
.bind(org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Messages
.TmfMarker_LocationTimeRange
,
1244 new TmfNanoTimestamp(bookmark
.getTime()),
1245 new TmfNanoTimestamp(bookmark
.getTime() + bookmark
.getDuration())));
1247 marker
.setAttribute(IMarker
.LOCATION
,
1248 NLS
.bind(org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Messages
.TmfMarker_LocationTime
,
1249 new TmfNanoTimestamp(bookmark
.getTime())));
1251 marker
.setAttribute(ITmfMarker
.MARKER_COLOR
, bookmark
.getColor().toString());
1254 } catch (CoreException e
) {
1255 Activator
.getDefault().logError(e
.getMessage());
1260 public void bookmarkRemoved(TimeGraphBookmarkEvent event
) {
1262 IMarkerEvent bookmark
= event
.getBookmark();
1263 IMarker
[] markers
= fEditorFile
.findMarkers(IMarker
.BOOKMARK
, false, IResource
.DEPTH_ZERO
);
1264 for (IMarker marker
: markers
) {
1265 if (bookmark
.getLabel().equals(marker
.getAttribute(IMarker
.MESSAGE
)) &&
1266 Long
.toString(bookmark
.getTime()).equals(marker
.getAttribute(ITmfMarker
.MARKER_TIME
, (String
) null)) &&
1267 Long
.toString(bookmark
.getDuration()).equals(marker
.getAttribute(ITmfMarker
.MARKER_DURATION
, Long
.toString(0))) &&
1268 bookmark
.getColor().toString().equals(marker
.getAttribute(ITmfMarker
.MARKER_COLOR
))) {
1273 } catch (CoreException e
) {
1274 Activator
.getDefault().logError(e
.getMessage());
1279 fTimeGraphWrapper
.getTimeGraphViewer().setTimeFormat(TimeFormat
.CALENDAR
);
1281 IStatusLineManager statusLineManager
= getViewSite().getActionBars().getStatusLineManager();
1282 fTimeGraphWrapper
.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager
);
1284 // View Action Handling
1286 contributeToActionBars();
1288 ITmfTrace trace
= TmfTraceManager
.getInstance().getActiveTrace();
1289 if (trace
!= null) {
1290 traceSelected(new TmfTraceSelectedSignal(this, trace
));
1293 // make selection available to other views
1294 getSite().setSelectionProvider(fTimeGraphWrapper
.getSelectionProvider());
1296 ResourcesPlugin
.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent
.POST_CHANGE
);
1298 createContextMenu();
1302 public void setFocus() {
1303 fTimeGraphWrapper
.setFocus();
1307 public void dispose() {
1309 ResourcesPlugin
.getWorkspace().removeResourceChangeListener(this);
1316 public void resourceChanged(final IResourceChangeEvent event
) {
1317 for (final IMarkerDelta delta
: event
.findMarkerDeltas(IMarker
.BOOKMARK
, false)) {
1318 if (delta
.getResource().equals(fEditorFile
)) {
1319 fTimeGraphWrapper
.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile
));
1326 private static List
<IMarkerEvent
> refreshBookmarks(final IFile editorFile
) {
1327 List
<IMarkerEvent
> bookmarks
= new ArrayList
<>();
1328 if (editorFile
== null || !editorFile
.exists()) {
1332 IMarker
[] markers
= editorFile
.findMarkers(IMarker
.BOOKMARK
, false, IResource
.DEPTH_ZERO
);
1333 for (IMarker marker
: markers
) {
1334 String label
= marker
.getAttribute(IMarker
.MESSAGE
, (String
) null);
1335 String time
= marker
.getAttribute(ITmfMarker
.MARKER_TIME
, (String
) null);
1336 String duration
= marker
.getAttribute(ITmfMarker
.MARKER_DURATION
, Long
.toString(0));
1337 String rgba
= marker
.getAttribute(ITmfMarker
.MARKER_COLOR
, (String
) null);
1338 if (label
!= null && time
!= null && rgba
!= null) {
1339 Matcher matcher
= RGBA_PATTERN
.matcher(rgba
);
1340 if (matcher
.matches()) {
1342 int red
= Integer
.valueOf(matcher
.group(1));
1343 int green
= Integer
.valueOf(matcher
.group(2));
1344 int blue
= Integer
.valueOf(matcher
.group(3));
1345 int alpha
= Integer
.valueOf(matcher
.group(4));
1346 RGBA color
= new RGBA(red
, green
, blue
, alpha
);
1347 bookmarks
.add(new MarkerEvent(null, Long
.valueOf(time
), Long
.valueOf(duration
), IMarkerEvent
.BOOKMARKS
, color
, label
, true));
1348 } catch (NumberFormatException e
) {
1349 Activator
.getDefault().logError(e
.getMessage());
1354 } catch (CoreException e
) {
1355 Activator
.getDefault().logError(e
.getMessage());
1362 // ------------------------------------------------------------------------
1364 // ------------------------------------------------------------------------
1367 * Handler for the trace opened signal.
1370 * The incoming signal
1373 public void traceOpened(TmfTraceOpenedSignal signal
) {
1374 loadTrace(signal
.getTrace());
1378 * Handler for the trace selected signal
1381 * The incoming signal
1384 public void traceSelected(final TmfTraceSelectedSignal signal
) {
1385 if (signal
.getTrace() == fTrace
) {
1388 loadTrace(signal
.getTrace());
1392 * Trace is closed: clear the data structures and the view
1395 * the signal received
1398 public void traceClosed(final TmfTraceClosedSignal signal
) {
1399 synchronized (fBuildThreadMap
) {
1400 for (ITmfTrace trace
: getTracesToBuild(signal
.getTrace())) {
1401 BuildThread buildThread
= fBuildThreadMap
.remove(trace
);
1402 if (buildThread
!= null) {
1403 buildThread
.cancel();
1407 fMarkerEventSourcesMap
.remove(signal
.getTrace());
1408 synchronized (fEntryListMap
) {
1409 fEntryListMap
.remove(signal
.getTrace());
1411 fFiltersMap
.remove(signal
.getTrace());
1412 fViewContext
.remove(signal
.getTrace());
1413 if (signal
.getTrace() == fTrace
) {
1416 fStartTime
= SWT
.DEFAULT
;
1417 fEndTime
= SWT
.DEFAULT
;
1418 if (fZoomThread
!= null) {
1419 fZoomThread
.cancel();
1427 * Handler for the selection range signal.
1430 * The signal that's received
1434 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal
) {
1435 if (signal
.getSource() == this || fTrace
== null) {
1438 final long beginTime
= signal
.getBeginTime().toNanos();
1439 final long endTime
= signal
.getEndTime().toNanos();
1441 Display
.getDefault().asyncExec(new Runnable() {
1444 if (fTimeGraphWrapper
.isDisposed()) {
1447 if (beginTime
== endTime
) {
1448 fTimeGraphWrapper
.getTimeGraphViewer().setSelectedTime(beginTime
, true);
1450 fTimeGraphWrapper
.getTimeGraphViewer().setSelectionRange(beginTime
, endTime
, true);
1452 synchingToTime(fTimeGraphWrapper
.getTimeGraphViewer().getSelectionBegin());
1458 * Handler for the window range signal.
1461 * The signal that's received
1465 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal
) {
1466 if (signal
.getSource() == this || fTrace
== null) {
1469 if (signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange()) == null) {
1472 final long startTime
= signal
.getCurrentRange().getStartTime().toNanos();
1473 final long endTime
= signal
.getCurrentRange().getEndTime().toNanos();
1474 Display
.getDefault().asyncExec(new Runnable() {
1477 if (fTimeGraphWrapper
.isDisposed()) {
1480 fTimeGraphWrapper
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
1481 startZoomThread(startTime
, endTime
);
1487 * @param signal the format of the timestamps was updated.
1490 public void updateTimeFormat( final TmfTimestampFormatUpdateSignal signal
){
1491 fTimeGraphWrapper
.refresh();
1494 // ------------------------------------------------------------------------
1496 // ------------------------------------------------------------------------
1498 private void loadTrace(final ITmfTrace trace
) {
1499 if (fZoomThread
!= null) {
1500 fZoomThread
.cancel();
1503 if (fTrace
!= null) {
1504 /* save the filters of the previous trace */
1505 fFiltersMap
.put(fTrace
, fTimeGraphWrapper
.getFilters());
1506 fViewContext
.put(fTrace
, new ViewContext(fCurrentSortColumn
, fSortDirection
, fTimeGraphWrapper
.getSelection()));
1509 restoreViewContext();
1510 fEditorFile
= TmfTraceManager
.getInstance().getTraceEditorFile(trace
);
1511 synchronized (fEntryListMap
) {
1512 fEntryList
= fEntryListMap
.get(fTrace
);
1513 if (fEntryList
== null) {
1516 fStartTime
= fTrace
.getStartTime().toNanos();
1517 fEndTime
= fTrace
.getEndTime().toNanos();
1524 * Forces a rebuild of the entries list, even if entries already exist for this trace
1526 protected void rebuild() {
1527 setStartTime(Long
.MAX_VALUE
);
1528 setEndTime(Long
.MIN_VALUE
);
1530 ITmfTrace viewTrace
= fTrace
;
1531 if (viewTrace
== null) {
1534 List
<IMarkerEventSource
> markerEventSources
= new ArrayList
<>();
1535 synchronized (fBuildThreadMap
) {
1536 for (ITmfTrace trace
: getTracesToBuild(viewTrace
)) {
1537 if (trace
== null) {
1540 markerEventSources
.addAll(TmfTraceAdapterManager
.getAdapters(trace
, IMarkerEventSource
.class));
1541 BuildThread buildThread
= new BuildThread(trace
, viewTrace
, getName());
1542 fBuildThreadMap
.put(trace
, buildThread
);
1543 buildThread
.start();
1546 fMarkerEventSourcesMap
.put(viewTrace
, markerEventSources
);
1550 * Method called when synching to a given timestamp. Inheriting classes can
1551 * perform actions here to update the view at the given timestamp.
1554 * The currently selected time
1556 protected void synchingToTime(long time
) {
1561 * Return the list of traces whose data or analysis results will be used to
1562 * populate the view. By default, if the trace is an experiment, the traces
1563 * under it will be returned, otherwise, the trace itself is returned.
1565 * A build thread will be started for each trace returned by this method,
1566 * some of which may receive events in live streaming mode.
1569 * The trace associated with this view
1570 * @return List of traces with data to display
1572 protected @NonNull Iterable
<ITmfTrace
> getTracesToBuild(@NonNull ITmfTrace trace
) {
1573 return TmfTraceManager
.getTraceSet(trace
);
1577 * Build the entries list to show in this time graph
1579 * Called from the BuildThread
1582 * The trace being built
1583 * @param parentTrace
1584 * The parent of the trace set, or the trace itself
1586 * The progress monitor object
1588 protected abstract void buildEventList(@NonNull ITmfTrace trace
, @NonNull ITmfTrace parentTrace
, @NonNull IProgressMonitor monitor
);
1591 * Gets the list of event for an entry in a given timerange
1594 * The entry to get events for
1596 * Start of the time range
1598 * End of the time range
1602 * The progress monitor object
1603 * @return The list of events for the entry
1605 protected abstract @Nullable List
<@NonNull ITimeEvent
> getEventList(@NonNull TimeGraphEntry entry
,
1606 long startTime
, long endTime
, long resolution
,
1607 @NonNull IProgressMonitor monitor
);
1610 * Gets the list of links (displayed as arrows) for a trace in a given
1611 * timerange. Default implementation returns an empty list.
1614 * Start of the time range
1616 * End of the time range
1620 * The progress monitor object
1621 * @return The list of link events
1623 protected @Nullable List
<@NonNull ILinkEvent
> getLinkList(long startTime
, long endTime
,
1624 long resolution
, @NonNull IProgressMonitor monitor
) {
1625 return new ArrayList
<>();
1629 * Gets the list of view-specific marker categories. Default implementation
1630 * returns an empty list.
1632 * @return The list of marker categories
1635 protected @NonNull List
<String
> getViewMarkerCategories() {
1636 return new ArrayList
<>();
1640 * Gets the list of view-specific markers for a trace in a given time range.
1641 * Default implementation returns an empty list.
1644 * Start of the time range
1646 * End of the time range
1650 * The progress monitor object
1651 * @return The list of marker events
1654 protected @NonNull List
<IMarkerEvent
> getViewMarkerList(long startTime
, long endTime
,
1655 long resolution
, @NonNull IProgressMonitor monitor
) {
1656 return new ArrayList
<>();
1660 * Gets the list of trace-specific markers for a trace in a given time range.
1663 * Start of the time range
1665 * End of the time range
1669 * The progress monitor object
1670 * @return The list of marker events
1673 protected @NonNull List
<IMarkerEvent
> getTraceMarkerList(long startTime
, long endTime
,
1674 long resolution
, @NonNull IProgressMonitor monitor
) {
1675 List
<IMarkerEvent
> markers
= new ArrayList
<>();
1676 for (IMarkerEventSource markerEventSource
: getMarkerEventSources(fTrace
)) {
1677 for (String category
: markerEventSource
.getMarkerCategories()) {
1678 if (monitor
.isCanceled()) {
1681 markers
.addAll(markerEventSource
.getMarkerList(category
, startTime
, endTime
, resolution
, monitor
));
1688 * Get the list of current marker categories.
1690 * @return The list of marker categories
1693 private @NonNull List
<String
> getMarkerCategories() {
1694 Set
<String
> categories
= new LinkedHashSet
<>(getViewMarkerCategories());
1695 for (IMarkerEventSource markerEventSource
: getMarkerEventSources(fTrace
)) {
1696 categories
.addAll(markerEventSource
.getMarkerCategories());
1698 return new ArrayList
<>(categories
);
1702 * Gets the list of marker event sources for a given trace.
1706 * @return The list of marker event sources
1709 private @NonNull List
<IMarkerEventSource
> getMarkerEventSources(ITmfTrace trace
) {
1710 List
<IMarkerEventSource
> markerEventSources
= fMarkerEventSourcesMap
.get(trace
);
1711 if (markerEventSources
== null) {
1712 markerEventSources
= Collections
.emptyList();
1714 return markerEventSources
;
1718 * Refresh the display
1720 protected void refresh() {
1721 final boolean zoomThread
= Thread
.currentThread() instanceof ZoomThread
;
1722 TmfUiRefreshHandler
.getInstance().queueUpdate(this, new Runnable() {
1725 if (fTimeGraphWrapper
.isDisposed()) {
1728 fDirty
.incrementAndGet();
1730 boolean hasEntries
= false;
1731 synchronized (fEntryListMap
) {
1732 fEntryList
= fEntryListMap
.get(fTrace
);
1733 if (fEntryList
== null) {
1734 fEntryList
= new CopyOnWriteArrayList
<>();
1735 } else if (fEntryComparator
!= null) {
1736 List
<TimeGraphEntry
> list
= new ArrayList
<>(fEntryList
);
1737 Collections
.sort(list
, fEntryComparator
);
1738 for (ITimeGraphEntry entry
: list
) {
1739 sortChildren(entry
, fEntryComparator
);
1742 fEntryList
.addAll(list
);
1744 hasEntries
= !fEntryList
.isEmpty();
1746 boolean inputChanged
= fEntryList
!= fTimeGraphWrapper
.getInput();
1747 TimeGraphCombo combo
= getTimeGraphCombo();
1749 // Set redraw to false to only draw once
1750 if (combo
!= null) {
1751 combo
.getTreeViewer().getTree().setRedraw(false);
1753 getTimeGraphViewer().getTimeGraphControl().setRedraw(false);
1755 fTimeGraphWrapper
.setInput(fEntryList
);
1756 /* restore the previously saved filters, if any */
1757 fTimeGraphWrapper
.setFilters(fFiltersMap
.get(fTrace
));
1758 fTimeGraphWrapper
.getTimeGraphViewer().setLinks(null);
1759 fTimeGraphWrapper
.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile
));
1760 fTimeGraphWrapper
.getTimeGraphViewer().setMarkerCategories(getMarkerCategories());
1761 fTimeGraphWrapper
.getTimeGraphViewer().setMarkers(null);
1764 fTimeGraphWrapper
.refresh();
1767 if (fIsRevealSelection
) {
1768 fIsRevealSelection
= false;
1769 ITimeGraphEntry entry1
= fTimeGraphWrapper
.getSelection();
1770 fTimeGraphWrapper
.setSelection(entry1
);
1773 if (combo
!= null) {
1774 combo
.getTreeViewer().getTree().setRedraw(true);
1776 getTimeGraphViewer().getTimeGraphControl().setRedraw(true);
1778 long startBound
= (fStartTime
== Long
.MAX_VALUE ? SWT
.DEFAULT
: fStartTime
);
1779 long endBound
= (fEndTime
== Long
.MIN_VALUE ? SWT
.DEFAULT
: fEndTime
);
1780 fTimeGraphWrapper
.getTimeGraphViewer().setTimeBounds(startBound
, endBound
);
1782 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
1783 long selectionBeginTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getSelectionRange().getStartTime().toNanos();
1784 long selectionEndTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getSelectionRange().getEndTime().toNanos();
1785 long startTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getWindowRange().getStartTime().toNanos();
1786 long endTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getWindowRange().getEndTime().toNanos();
1787 startTime
= (fStartTime
== Long
.MAX_VALUE ? SWT
.DEFAULT
: Math
.max(startTime
, fStartTime
));
1788 endTime
= (fEndTime
== Long
.MIN_VALUE ? SWT
.DEFAULT
: Math
.min(endTime
, fEndTime
));
1789 fTimeGraphWrapper
.getTimeGraphViewer().setSelectionRange(selectionBeginTime
, selectionEndTime
, false);
1790 fTimeGraphWrapper
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
1792 if (inputChanged
&& selectionBeginTime
!= SWT
.DEFAULT
) {
1793 synchingToTime(selectionBeginTime
);
1796 if (fTimeGraphWrapper
instanceof TimeGraphComboWrapper
&& !fPackDone
) {
1797 for (TreeColumn column
: ((TimeGraphComboWrapper
) fTimeGraphWrapper
).getTreeViewer().getTree().getColumns()) {
1806 startZoomThread(startTime
, endTime
);
1808 fDirty
.decrementAndGet();
1816 protected void redraw() {
1817 synchronized (fSyncObj
) {
1818 if (fRedrawState
== State
.IDLE
) {
1819 fRedrawState
= State
.BUSY
;
1821 fRedrawState
= State
.PENDING
;
1825 Display
.getDefault().asyncExec(new Runnable() {
1828 if (fTimeGraphWrapper
.isDisposed()) {
1831 fTimeGraphWrapper
.redraw();
1832 fTimeGraphWrapper
.update();
1833 synchronized (fSyncObj
) {
1834 if (fRedrawState
== State
.PENDING
) {
1835 fRedrawState
= State
.IDLE
;
1838 fRedrawState
= State
.IDLE
;
1845 private void sortChildren(ITimeGraphEntry entry
, Comparator
<ITimeGraphEntry
> comparator
) {
1846 if (entry
instanceof TimeGraphEntry
) {
1847 ((TimeGraphEntry
) entry
).sortChildren(comparator
);
1849 for (ITimeGraphEntry child
: entry
.getChildren()) {
1850 sortChildren(child
, comparator
);
1855 * Start or restart the zoom thread.
1858 * the zoom start time
1863 protected final void startZoomThread(long startTime
, long endTime
) {
1864 long clampedStartTime
= Math
.min(Math
.max(startTime
, fStartTime
), fEndTime
);
1865 long clampedEndTime
= Math
.max(Math
.min(endTime
, fEndTime
), fStartTime
);
1866 fDirty
.incrementAndGet();
1867 boolean restart
= false;
1868 if (fZoomThread
!= null) {
1869 fZoomThread
.cancel();
1870 if (fZoomThread
.fZoomStartTime
== clampedStartTime
&& fZoomThread
.fZoomEndTime
== clampedEndTime
) {
1874 long resolution
= Math
.max(1, (clampedEndTime
- clampedStartTime
) / fDisplayWidth
);
1875 fZoomThread
= createZoomThread(clampedStartTime
, clampedEndTime
, resolution
, restart
);
1876 if (fZoomThread
!= null) {
1877 fZoomThread
.start();
1879 fDirty
.decrementAndGet();
1884 * Create a zoom thread.
1887 * the zoom start time
1893 * true if restarting zoom for the same time range
1894 * @return a zoom thread
1897 protected @Nullable ZoomThread
createZoomThread(long startTime
, long endTime
, long resolution
, boolean restart
) {
1898 final List
<TimeGraphEntry
> entryList
= fEntryList
;
1899 if (entryList
== null) {
1902 return new ZoomThreadByEntry(entryList
, startTime
, endTime
, resolution
);
1905 private void makeActions() {
1906 fPreviousResourceAction
= fTimeGraphWrapper
.getTimeGraphViewer().getPreviousItemAction();
1907 fPreviousResourceAction
.setText(getPrevText());
1908 fPreviousResourceAction
.setToolTipText(getPrevTooltip());
1909 fNextResourceAction
= fTimeGraphWrapper
.getTimeGraphViewer().getNextItemAction();
1910 fNextResourceAction
.setText(getNextText());
1911 fNextResourceAction
.setToolTipText(getNextTooltip());
1914 private void contributeToActionBars() {
1915 IActionBars bars
= getViewSite().getActionBars();
1916 fillLocalToolBar(bars
.getToolBarManager());
1917 fillLocalMenu(bars
.getMenuManager());
1921 * Add actions to local tool bar manager
1923 * @param manager the tool bar manager
1925 protected void fillLocalToolBar(IToolBarManager manager
) {
1926 if (fFilterColumns
!= null && fFilterLabelProvider
!= null && fFilterColumns
.length
> 0) {
1927 manager
.add(fTimeGraphWrapper
.getShowFilterDialogAction());
1929 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getShowLegendAction());
1930 manager
.add(new Separator());
1931 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getResetScaleAction());
1932 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getPreviousEventAction());
1933 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getNextEventAction());
1934 manager
.add(new Separator());
1935 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getToggleBookmarkAction());
1936 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getPreviousMarkerAction());
1937 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getNextMarkerAction());
1938 manager
.add(new Separator());
1939 manager
.add(fPreviousResourceAction
);
1940 manager
.add(fNextResourceAction
);
1941 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getZoomInAction());
1942 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getZoomOutAction());
1943 manager
.add(new Separator());
1947 * Add actions to local menu manager
1949 * @param manager the tool bar manager
1952 protected void fillLocalMenu(IMenuManager manager
) {
1953 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getMarkersMenu());
1960 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
1961 if (fTimeGraphWrapper
== null) {
1964 return fTimeGraphWrapper
.getTimeViewAlignmentInfo();
1971 public int getAvailableWidth(int requestedOffset
) {
1972 if (fTimeGraphWrapper
== null) {
1975 return fTimeGraphWrapper
.getAvailableWidth(requestedOffset
);
1982 public void performAlign(int offset
, int width
) {
1983 if (fTimeGraphWrapper
!= null) {
1984 fTimeGraphWrapper
.performAlign(offset
, width
);
1989 * Returns whether or not the time graph view is dirty. The time graph view
1990 * is considered dirty if it has yet to completely update its model.
1992 * This method is meant to be used by tests in order to know when it is safe
1995 * Note: If a trace is smaller than the initial window range (see
1996 * {@link ITmfTrace#getInitialRangeOffset}) this method will return true
1999 * @return true if the time graph view has yet to completely update its
2000 * model, false otherwise
2003 public boolean isDirty() {
2004 if (fTrace
== null) {
2008 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
2009 long startTime
= ctx
.getWindowRange().getStartTime().toNanos();
2010 long endTime
= ctx
.getWindowRange().getEndTime().toNanos();
2012 // If the time graph control hasn't updated all the way to the end of
2013 // the window range then it's dirty. A refresh should happen later.
2014 if (fTimeGraphWrapper
.getTimeGraphViewer().getTime0() != startTime
|| fTimeGraphWrapper
.getTimeGraphViewer().getTime1() != endTime
) {
2018 if (fZoomThread
== null) {
2019 // The zoom thread is null but we might be just about to create it (refresh called).
2020 return fDirty
.get() != 0;
2022 // Dirty if the zoom thread is not done or if it hasn't zoomed all the
2023 // way to the end of the window range. In the latter case, there should be
2024 // a subsequent zoom thread that will be triggered.
2025 return fDirty
.get() != 0 || fZoomThread
.getZoomStartTime() != startTime
|| fZoomThread
.getZoomEndTime() != endTime
;
2028 private void createColumnSelectionListener(TreeViewer treeViewer
) {
2029 for (int i
= 0; i
< fColumnComparators
.length
; i
++) {
2030 final int index
= i
;
2031 final Comparator
<ITimeGraphEntry
> comp
= fColumnComparators
[index
];
2032 final Tree tree
= treeViewer
.getTree();
2033 final TreeColumn column
= tree
.getColumn(i
);
2036 column
.addSelectionListener(new SelectionAdapter() {
2038 public void widgetSelected(SelectionEvent e
) {
2039 TreeColumn prevSortcolumn
= tree
.getSortColumn();
2040 int direction
= tree
.getSortDirection();
2041 if (prevSortcolumn
== column
) {
2042 direction
= (direction
== SWT
.DOWN
) ? SWT
.UP
: SWT
.DOWN
;
2044 direction
= SWT
.DOWN
;
2046 tree
.setSortColumn(column
);
2047 tree
.setSortDirection(direction
);
2048 fSortDirection
= direction
;
2049 fCurrentSortColumn
= index
;
2050 Comparator
<ITimeGraphEntry
> comparator
= comp
;
2052 if (comparator
instanceof ITimeGraphEntryComparator
) {
2053 ((ITimeGraphEntryComparator
) comparator
).setDirection(direction
);
2055 if (direction
!= SWT
.DOWN
) {
2056 comparator
= checkNotNull(Collections
.reverseOrder(comparator
));
2058 setEntryComparator(comparator
);
2059 fIsRevealSelection
= true;
2060 if (fTimeGraphWrapper
instanceof TimeGraphComboWrapper
) {
2061 ((TimeGraphComboWrapper
) fTimeGraphWrapper
).getTreeViewer().getControl().setFocus();
2070 private void createDoubleClickListener(TreeViewer treeViewer
) {
2071 treeViewer
.addDoubleClickListener(event
-> {
2072 if (event
.getSelection() instanceof TreeSelection
) {
2073 TreeSelection selection
= (TreeSelection
) event
.getSelection();
2074 if (selection
.getFirstElement() instanceof ITimeGraphEntry
) {
2075 ITimeGraphEntry entry
= (ITimeGraphEntry
) selection
.getFirstElement();
2076 if (entry
.hasChildren()) {
2077 fTimeGraphWrapper
.setExpandedState(entry
, !fTimeGraphWrapper
.getExpandedState(entry
));
2085 private void restoreViewContext() {
2086 TimeGraphCombo combo
= getTimeGraphCombo();
2087 ViewContext viewContext
= fViewContext
.get(fTrace
);
2088 if (combo
!= null) {
2089 if (fColumnComparators
!= null) {
2090 // restore sort settings
2091 fSortDirection
= SWT
.DOWN
;
2092 fCurrentSortColumn
= fInitialSortColumn
;
2093 if (viewContext
!= null) {
2094 fSortDirection
= viewContext
.getSortDirection();
2095 fCurrentSortColumn
= viewContext
.getSortColumn();
2097 if ((fCurrentSortColumn
< fColumnComparators
.length
) && (fColumnComparators
[fCurrentSortColumn
] != null)) {
2098 Comparator
<ITimeGraphEntry
> comparator
= fColumnComparators
[fCurrentSortColumn
];
2099 if (comparator
instanceof ITimeGraphEntryComparator
) {
2100 ((ITimeGraphEntryComparator
) comparator
).setDirection(fSortDirection
);
2102 if (fSortDirection
!= SWT
.DOWN
) {
2103 comparator
= checkNotNull(Collections
.reverseOrder(comparator
));
2105 setEntryComparator(comparator
);
2111 private void applyViewContext() {
2112 TimeGraphCombo combo
= getTimeGraphCombo();
2113 ViewContext viewContext
= fViewContext
.get(fTrace
);
2114 if (combo
!= null) {
2115 TreeViewer treeViewer
= combo
.getTreeViewer();
2116 final Tree tree
= treeViewer
.getTree();
2117 final TreeColumn column
= tree
.getColumn(fCurrentSortColumn
);
2118 tree
.setSortDirection(fSortDirection
);
2119 tree
.setSortColumn(column
);
2120 combo
.getTreeViewer().getControl().setFocus();
2122 // restore and reveal selection
2123 if ((viewContext
!= null) && (viewContext
.getSelection() != null)) {
2124 fTimeGraphWrapper
.setSelection(viewContext
.getSelection());
2126 fViewContext
.remove(fTrace
);
2129 private static class ViewContext
{
2130 private int fSortColumnIndex
;
2131 private int fSortDirection
;
2132 private @Nullable ITimeGraphEntry fSelection
;
2134 ViewContext(int sortColunm
, int sortDirection
, ITimeGraphEntry selection
) {
2135 fSortColumnIndex
= sortColunm
;
2136 fSortDirection
= sortDirection
;
2137 fSelection
= selection
;
2140 * @return the sortColumn
2142 public int getSortColumn() {
2143 return fSortColumnIndex
;
2146 * @return the sortDirection
2148 public int getSortDirection() {
2149 return fSortDirection
;
2152 * @return the selection
2154 public ITimeGraphEntry
getSelection() {
2159 private void createContextMenu() {
2160 TimeGraphCombo combo
= getTimeGraphCombo();
2161 fEntryMenuManager
.setRemoveAllWhenShown(true);
2162 if (combo
!= null) {
2163 TreeViewer treeViewer
= combo
.getTreeViewer();
2164 Tree tree
= treeViewer
.getTree();
2165 Menu menu
= fEntryMenuManager
.createContextMenu(tree
);
2168 TimeGraphControl timeGraphControl
= getTimeGraphViewer().getTimeGraphControl();
2169 final Menu entryMenu
= fEntryMenuManager
.createContextMenu(timeGraphControl
);
2170 timeGraphControl
.addTimeGraphEntryMenuListener(new MenuDetectListener() {
2172 public void menuDetected(MenuDetectEvent event
) {
2173 Point p
= timeGraphControl
.toControl(event
.x
, event
.y
);
2175 * The TimeGraphControl will call the TimeGraphEntryMenuListener
2176 * before the TimeEventMenuListener. If the event is
2177 * triggered on the namespace then show the menu else
2180 if (p
.x
< getTimeGraphViewer().getNameSpace()) {
2181 timeGraphControl
.setMenu(entryMenu
);
2183 timeGraphControl
.setMenu(null);
2189 fEntryMenuManager
.addMenuListener(new IMenuListener() {
2191 public void menuAboutToShow(IMenuManager manager
) {
2192 fillTimeGraphEntryContextMenu(fEntryMenuManager
);
2193 fEntryMenuManager
.add(new GroupMarker(IWorkbenchActionConstants
.MB_ADDITIONS
));
2196 getSite().registerContextMenu(fEntryMenuManager
, fTimeGraphWrapper
.getSelectionProvider());
2202 * @param menuManager
2203 * a menuManager to fill
2206 protected void fillTimeGraphEntryContextMenu (@NonNull IMenuManager menuManager
) {