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
.IAction
;
49 import org
.eclipse
.jface
.action
.IMenuManager
;
50 import org
.eclipse
.jface
.action
.IStatusLineManager
;
51 import org
.eclipse
.jface
.action
.IToolBarManager
;
52 import org
.eclipse
.jface
.action
.Separator
;
53 import org
.eclipse
.jface
.viewers
.AbstractTreeViewer
;
54 import org
.eclipse
.jface
.viewers
.ILabelProvider
;
55 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
56 import org
.eclipse
.jface
.viewers
.ISelectionProvider
;
57 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
58 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
59 import org
.eclipse
.jface
.viewers
.TreeViewer
;
60 import org
.eclipse
.jface
.viewers
.ViewerFilter
;
61 import org
.eclipse
.osgi
.util
.NLS
;
62 import org
.eclipse
.swt
.SWT
;
63 import org
.eclipse
.swt
.events
.SelectionAdapter
;
64 import org
.eclipse
.swt
.events
.SelectionEvent
;
65 import org
.eclipse
.swt
.graphics
.Image
;
66 import org
.eclipse
.swt
.graphics
.RGBA
;
67 import org
.eclipse
.swt
.widgets
.Composite
;
68 import org
.eclipse
.swt
.widgets
.Display
;
69 import org
.eclipse
.swt
.widgets
.Tree
;
70 import org
.eclipse
.swt
.widgets
.TreeColumn
;
71 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
72 import org
.eclipse
.tracecompass
.tmf
.core
.resources
.ITmfMarker
;
73 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSelectionRangeUpdatedSignal
;
74 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
75 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTimestampFormatUpdateSignal
;
76 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
77 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
78 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
79 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfWindowRangeUpdatedSignal
;
80 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
81 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfNanoTimestamp
;
82 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
83 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
84 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceAdapterManager
;
85 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceContext
;
86 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
87 import org
.eclipse
.tracecompass
.tmf
.ui
.TmfUiRefreshHandler
;
88 import org
.eclipse
.tracecompass
.tmf
.ui
.signal
.TmfTimeViewAlignmentInfo
;
89 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.ITmfTimeAligned
;
90 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
91 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphBookmarkListener
;
92 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphContentProvider
;
93 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphPresentationProvider2
;
94 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphRangeListener
;
95 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphSelectionListener
;
96 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
97 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphBookmarkEvent
;
98 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
99 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphContentProvider
;
100 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphPresentationProvider
;
101 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphRangeUpdateEvent
;
102 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
103 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphViewer
;
104 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ILinkEvent
;
105 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.IMarkerEvent
;
106 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.IMarkerEventSource
;
107 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
108 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
109 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.MarkerEvent
;
110 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
111 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
112 import org
.eclipse
.ui
.IActionBars
;
115 * An abstract view all time graph views can inherit
117 * This view contains either a time graph viewer, or a time graph combo which is
118 * divided between a tree viewer on the left and a time graph viewer on the right.
120 public abstract class AbstractTimeGraphView
extends TmfView
implements ITmfTimeAligned
, IResourceChangeListener
{
122 /** Constant indicating that all levels of the time graph should be expanded */
123 protected static final int ALL_LEVELS
= AbstractTreeViewer
.ALL_LEVELS
;
125 private static final Pattern RGBA_PATTERN
= Pattern
.compile("RGBA \\{(\\d+), (\\d+), (\\d+), (\\d+)\\}"); //$NON-NLS-1$
134 // ------------------------------------------------------------------------
136 // ------------------------------------------------------------------------
138 /** The timegraph wrapper */
139 private ITimeGraphWrapper fTimeGraphWrapper
;
141 private AtomicInteger fDirty
= new AtomicInteger();
143 /** The selected trace */
144 private ITmfTrace fTrace
;
146 /** The selected trace editor file*/
147 private IFile fEditorFile
;
149 /** The timegraph entry list */
150 private List
<TimeGraphEntry
> fEntryList
;
152 /** The trace to entry list hash map */
153 private final Map
<ITmfTrace
, List
<TimeGraphEntry
>> fEntryListMap
= new HashMap
<>();
155 /** The trace to filters hash map */
156 private final Map
<ITmfTrace
, @NonNull ViewerFilter
[]> fFiltersMap
= new HashMap
<>();
158 /** The trace to view context hash map */
159 private final Map
<ITmfTrace
, ViewContext
> fViewContext
= new HashMap
<>();
161 /** The trace to marker event sources hash map */
162 private final Map
<ITmfTrace
, List
<IMarkerEventSource
>> fMarkerEventSourcesMap
= new HashMap
<>();
164 /** The trace to build thread hash map */
165 private final Map
<ITmfTrace
, BuildThread
> fBuildThreadMap
= new HashMap
<>();
167 /** The start time */
168 private long fStartTime
= SWT
.DEFAULT
;
171 private long fEndTime
= SWT
.DEFAULT
;
173 /** The display width */
174 private final int fDisplayWidth
;
176 /** The zoom thread */
177 private ZoomThread fZoomThread
;
179 /** The next resource action */
180 private Action fNextResourceAction
;
182 /** The previous resource action */
183 private Action fPreviousResourceAction
;
185 /** A comparator class */
186 private Comparator
<ITimeGraphEntry
> fEntryComparator
= null;
188 /** The redraw state used to prevent unnecessary queuing of display runnables */
189 private State fRedrawState
= State
.IDLE
;
191 /** The redraw synchronization object */
192 private final Object fSyncObj
= new Object();
194 /** The presentation provider for this view */
195 private final TimeGraphPresentationProvider fPresentation
;
197 /** The tree column label array, or null if combo is not used */
198 private String
[] fColumns
;
200 private Comparator
<ITimeGraphEntry
>[] fColumnComparators
;
202 /** The tree label provider, or null if combo is not used */
203 private TreeLabelProvider fLabelProvider
= null;
205 /** The time graph content provider */
206 private @NonNull ITimeGraphContentProvider fTimeGraphContentProvider
= new TimeGraphContentProvider();
208 /** The relative weight of the sash, ignored if combo is not used */
209 private int[] fWeight
= { 1, 3 };
211 /** The filter column label array, or null if filter is not used */
212 private String
[] fFilterColumns
;
214 /** The pack done flag */
215 private boolean fPackDone
= false;
217 /** The filter content provider, or null if filter is not used */
218 private ITreeContentProvider fFilterContentProvider
;
220 /** The filter label provider, or null if filter is not used */
221 private TreeLabelProvider fFilterLabelProvider
;
223 private int fAutoExpandLevel
= ALL_LEVELS
;
225 /** The default column index for sorting */
226 private int fInitialSortColumn
= 0;
228 /** The default column index for sorting */
229 private int fCurrentSortColumn
= 0;
231 /** The current sort direction */
232 private int fSortDirection
= SWT
.DOWN
;
234 /** Flag to indicate to reveal selection */
235 private volatile boolean fIsRevealSelection
= false;
237 // ------------------------------------------------------------------------
239 // ------------------------------------------------------------------------
241 private interface ITimeGraphWrapper
{
243 void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider
);
245 void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider
);
247 TimeGraphViewer
getTimeGraphViewer();
249 void addSelectionListener(ITimeGraphSelectionListener listener
);
251 ISelectionProvider
getSelectionProvider();
255 boolean isDisposed();
259 void setInput(Object input
);
263 void setFilters(@NonNull ViewerFilter
[] filters
);
265 @NonNull ViewerFilter
[] getFilters();
271 void setAutoExpandLevel(int level
);
273 void setFilterColumns(String
[] columnNames
);
275 void setFilterContentProvider(ITreeContentProvider contentProvider
);
277 void setFilterLabelProvider(ITableLabelProvider labelProvider
);
279 IAction
getShowFilterDialogAction();
281 void performAlign(int offset
, int width
);
283 TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo();
285 int getAvailableWidth(int requestedOffset
);
287 ITimeGraphEntry
getSelection();
289 void setSelection(ITimeGraphEntry selection
);
292 private class TimeGraphViewerWrapper
implements ITimeGraphWrapper
{
293 private TimeGraphViewer viewer
;
295 private TimeGraphViewerWrapper(Composite parent
, int style
) {
296 viewer
= new TimeGraphViewer(parent
, style
);
300 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider
) {
301 viewer
.setTimeGraphContentProvider(timeGraphContentProvider
);
305 public void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider
) {
306 viewer
.setTimeGraphProvider(timeGraphPresentationProvider
);
310 public TimeGraphViewer
getTimeGraphViewer() {
315 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
316 viewer
.addSelectionListener(listener
);
320 public ISelectionProvider
getSelectionProvider() {
321 return viewer
.getSelectionProvider();
325 public void setFocus() {
330 public boolean isDisposed() {
331 return viewer
.getControl().isDisposed();
335 public void setInput(Object input
) {
336 viewer
.setInput(input
);
340 public Object
getInput() {
341 return viewer
.getInput();
345 public void setFilterColumns(String
[] columnNames
) {
346 viewer
.setFilterColumns(columnNames
);
350 public void setFilterContentProvider(ITreeContentProvider contentProvider
) {
351 viewer
.setFilterContentProvider(contentProvider
);
355 public void setFilterLabelProvider(ITableLabelProvider labelProvider
) {
356 viewer
.setFilterLabelProvider(labelProvider
);
360 public void setFilters(@NonNull ViewerFilter
[] filters
) {
361 viewer
.setFilters(filters
);
365 public @NonNull ViewerFilter
[] getFilters() {
366 return viewer
.getFilters();
370 public IAction
getShowFilterDialogAction() {
371 return viewer
.getShowFilterDialogAction();
375 public void refresh() {
380 public void redraw() {
381 viewer
.getControl().redraw();
385 public void update() {
386 viewer
.getControl().update();
390 public void setAutoExpandLevel(int level
) {
391 viewer
.setAutoExpandLevel(level
);
395 public void performAlign(int offset
, int width
) {
396 viewer
.performAlign(offset
, width
);
400 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
401 return viewer
.getTimeViewAlignmentInfo();
405 public int getAvailableWidth(int requestedOffset
) {
406 return viewer
.getAvailableWidth(requestedOffset
);
410 public ITimeGraphEntry
getSelection() {
411 return viewer
.getSelection();
415 public void setSelection(ITimeGraphEntry selection
) {
416 viewer
.setSelection(selection
);
420 private class TimeGraphComboWrapper
implements ITimeGraphWrapper
{
421 private TimeGraphCombo combo
;
423 private TimeGraphComboWrapper(Composite parent
, int style
) {
424 combo
= new TimeGraphCombo(parent
, style
, fWeight
);
428 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider
) {
429 combo
.setTimeGraphContentProvider(timeGraphContentProvider
);
433 public void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider
) {
434 combo
.setTimeGraphProvider(timeGraphPresentationProvider
);
438 public TimeGraphViewer
getTimeGraphViewer() {
439 return combo
.getTimeGraphViewer();
443 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
444 combo
.addSelectionListener(listener
);
448 public ISelectionProvider
getSelectionProvider() {
449 return combo
.getTreeViewer();
453 public void setFocus() {
458 public boolean isDisposed() {
459 return combo
.isDisposed();
463 public void setInput(Object input
) {
464 combo
.setInput(input
);
468 public Object
getInput() {
469 return combo
.getInput();
473 public void setFilterColumns(String
[] columnNames
) {
474 combo
.setFilterColumns(columnNames
);
478 public void setFilterContentProvider(ITreeContentProvider contentProvider
) {
479 combo
.setFilterContentProvider(contentProvider
);
483 public void setFilterLabelProvider(ITableLabelProvider labelProvider
) {
484 combo
.setFilterLabelProvider(labelProvider
);
488 public void setFilters(@NonNull ViewerFilter
[] filters
) {
489 combo
.setFilters(filters
);
493 public @NonNull ViewerFilter
[] getFilters() {
494 return combo
.getFilters();
498 public IAction
getShowFilterDialogAction() {
499 return combo
.getShowFilterDialogAction();
503 public void refresh() {
508 public void redraw() {
513 public void update() {
518 public void setAutoExpandLevel(int level
) {
519 combo
.setAutoExpandLevel(level
);
522 TimeGraphCombo
getTimeGraphCombo() {
526 TreeViewer
getTreeViewer() {
527 return combo
.getTreeViewer();
531 public void performAlign(int offset
, int width
) {
532 combo
.performAlign(offset
, width
);
536 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
537 return combo
.getTimeViewAlignmentInfo();
541 public int getAvailableWidth(int requestedOffset
) {
542 return combo
.getAvailableWidth(requestedOffset
);
546 public ITimeGraphEntry
getSelection() {
547 return combo
.getTimeGraphViewer().getSelection();
551 public void setSelection(ITimeGraphEntry selection
) {
552 combo
.setSelection(selection
);
557 * Base class to provide the labels for the tree viewer. Views extending
558 * this class typically need to override the getColumnText method if they
559 * have more than one column to display
561 protected static class TreeLabelProvider
implements ITableLabelProvider
, ILabelProvider
{
564 public void addListener(ILabelProviderListener listener
) {
568 public void dispose() {
572 public boolean isLabelProperty(Object element
, String property
) {
577 public void removeListener(ILabelProviderListener listener
) {
581 public Image
getColumnImage(Object element
, int columnIndex
) {
586 public String
getColumnText(Object element
, int columnIndex
) {
587 TimeGraphEntry entry
= (TimeGraphEntry
) element
;
588 if (columnIndex
== 0) {
589 return entry
.getName();
595 public Image
getImage(Object element
) {
600 public String
getText(Object element
) {
601 TimeGraphEntry entry
= (TimeGraphEntry
) element
;
602 return entry
.getName();
607 private class BuildThread
extends Thread
{
608 private final @NonNull ITmfTrace fBuildTrace
;
609 private final @NonNull ITmfTrace fParentTrace
;
610 private final @NonNull IProgressMonitor fMonitor
;
612 public BuildThread(final @NonNull ITmfTrace trace
, final @NonNull ITmfTrace parentTrace
, final String name
) {
613 super(name
+ " build"); //$NON-NLS-1$
615 fParentTrace
= parentTrace
;
616 fMonitor
= new NullProgressMonitor();
621 buildEventList(fBuildTrace
, fParentTrace
, fMonitor
);
622 synchronized (fBuildThreadMap
) {
623 fBuildThreadMap
.remove(fBuildTrace
);
627 public void cancel() {
628 fMonitor
.setCanceled(true);
636 protected abstract class ZoomThread
extends Thread
{
637 private final long fZoomStartTime
;
638 private final long fZoomEndTime
;
639 private final long fResolution
;
640 private final @NonNull IProgressMonitor fMonitor
;
652 public ZoomThread(long startTime
, long endTime
, long resolution
) {
653 super(AbstractTimeGraphView
.this.getName() + " zoom"); //$NON-NLS-1$
654 fZoomStartTime
= startTime
;
655 fZoomEndTime
= endTime
;
656 fResolution
= resolution
;
657 fMonitor
= new NullProgressMonitor();
661 * @return the zoom start time
663 public long getZoomStartTime() {
664 return fZoomStartTime
;
668 * @return the zoom end time
670 public long getZoomEndTime() {
675 * @return the resolution
677 public long getResolution() {
682 * @return the monitor
684 public @NonNull IProgressMonitor
getMonitor() {
689 * Cancel the zoom thread
691 public void cancel() {
692 fMonitor
.setCanceled(true);
696 public final void run() {
698 fDirty
.decrementAndGet();
702 * Run the zoom operation.
705 public abstract void doRun();
708 private class ZoomThreadByEntry
extends ZoomThread
{
709 private final @NonNull List
<TimeGraphEntry
> fZoomEntryList
;
711 public ZoomThreadByEntry(@NonNull List
<TimeGraphEntry
> entryList
, long startTime
, long endTime
, long resolution
) {
712 super(startTime
, endTime
, resolution
);
713 fZoomEntryList
= entryList
;
717 public void doRun() {
718 for (TimeGraphEntry entry
: fZoomEntryList
) {
719 if (getMonitor().isCanceled()) {
725 zoom(entry
, getMonitor());
727 /* Refresh the arrows when zooming */
728 List
<ILinkEvent
> events
= getLinkList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
729 if (events
!= null) {
730 fTimeGraphWrapper
.getTimeGraphViewer().setLinks(events
);
733 /* Refresh the view-specific markers when zooming */
734 List
<IMarkerEvent
> markers
= new ArrayList
<>(getViewMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
735 /* Refresh the trace-specific markers when zooming */
736 markers
.addAll(getTraceMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
737 fTimeGraphWrapper
.getTimeGraphViewer().setMarkers(markers
);
741 private void zoom(@NonNull TimeGraphEntry entry
, @NonNull IProgressMonitor monitor
) {
742 if (getZoomStartTime() <= fStartTime
&& getZoomEndTime() >= fEndTime
) {
743 entry
.setZoomedEventList(null);
745 List
<ITimeEvent
> zoomedEventList
= getEventList(entry
, getZoomStartTime(), getZoomEndTime(), getResolution(), monitor
);
746 if (zoomedEventList
!= null) {
747 entry
.setZoomedEventList(zoomedEventList
);
751 for (ITimeGraphEntry child
: entry
.getChildren()) {
752 if (monitor
.isCanceled()) {
755 if (child
instanceof TimeGraphEntry
) {
756 zoom((TimeGraphEntry
) child
, monitor
);
763 // ------------------------------------------------------------------------
765 // ------------------------------------------------------------------------
768 * Constructs a time graph view that contains either a time graph viewer or
769 * a time graph combo.
771 * By default, the view uses a time graph viewer. To use a time graph combo,
772 * the subclass constructor must call {@link #setTreeColumns(String[])} and
773 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
778 * The presentation provider
780 public AbstractTimeGraphView(String id
, TimeGraphPresentationProvider pres
) {
782 fPresentation
= pres
;
783 fDisplayWidth
= Display
.getDefault().getBounds().width
;
786 // ------------------------------------------------------------------------
787 // Getters and setters
788 // ------------------------------------------------------------------------
791 * Getter for the time graph combo
793 * @return The time graph combo, or null if combo is not used
795 protected TimeGraphCombo
getTimeGraphCombo() {
796 if (fTimeGraphWrapper
instanceof TimeGraphComboWrapper
) {
797 return ((TimeGraphComboWrapper
) fTimeGraphWrapper
).getTimeGraphCombo();
803 * Getter for the time graph viewer
805 * @return The time graph viewer
807 protected TimeGraphViewer
getTimeGraphViewer() {
808 return fTimeGraphWrapper
.getTimeGraphViewer();
812 * Getter for the presentation provider
814 * @return The time graph presentation provider
816 protected ITimeGraphPresentationProvider2
getPresentationProvider() {
817 return fPresentation
;
821 * Sets the tree column labels.
823 * This should be called from the constructor.
826 * The array of tree column labels
828 protected void setTreeColumns(final String
[] columns
) {
829 setTreeColumns(columns
, null, 0);
833 * Sets the tree column labels.
835 * This should be called from the constructor.
838 * The array of tree column labels
840 * An array of column comparators for sorting of columns when
841 * clicking on column header
842 * @param initialSortColumn
843 * Index of column to sort initially
846 protected void setTreeColumns(final String
[] columns
, final Comparator
<ITimeGraphEntry
>[] comparators
, int initialSortColumn
) {
847 checkPartNotCreated();
849 fColumnComparators
= comparators
;
850 fInitialSortColumn
= initialSortColumn
;
854 * Sets the tree label provider.
856 * This should be called from the constructor.
859 * The tree label provider
861 protected void setTreeLabelProvider(final TreeLabelProvider tlp
) {
862 checkPartNotCreated();
863 fLabelProvider
= tlp
;
867 * Sets the time graph content provider.
869 * This should be called from the constructor.
872 * The time graph content provider
875 protected void setTimeGraphContentProvider(final @NonNull ITimeGraphContentProvider tgcp
) {
876 checkPartNotCreated();
877 fTimeGraphContentProvider
= tgcp
;
881 * Sets the relative weight of each part of the time graph combo.
883 * This should be called from the constructor.
886 * The array (length 2) of relative weights of each part of the combo
888 protected void setWeight(final int[] weights
) {
889 checkPartNotCreated();
894 * Sets the filter column labels.
896 * This should be called from the constructor.
898 * @param filterColumns
899 * The array of filter column labels
901 protected void setFilterColumns(final String
[] filterColumns
) {
902 checkPartNotCreated();
903 fFilterColumns
= filterColumns
;
907 * Sets the filter content provider.
909 * This should be called from the constructor.
911 * @param contentProvider
912 * The filter content provider
915 protected void setFilterContentProvider(final ITreeContentProvider contentProvider
) {
916 checkPartNotCreated();
917 fFilterContentProvider
= contentProvider
;
921 * Sets the filter label provider.
923 * This should be called from the constructor.
925 * @param labelProvider
926 * The filter label provider
928 protected void setFilterLabelProvider(final TreeLabelProvider labelProvider
) {
929 checkPartNotCreated();
930 fFilterLabelProvider
= labelProvider
;
933 private void checkPartNotCreated() {
934 if (getParentComposite() != null) {
935 throw new IllegalStateException("This method must be called before createPartControl."); //$NON-NLS-1$
940 * Gets the display width
942 * @return the display width
944 protected int getDisplayWidth() {
945 return fDisplayWidth
;
949 * Gets the comparator for the entries
951 * @return The entry comparator
953 protected Comparator
<ITimeGraphEntry
> getEntryComparator() {
954 return fEntryComparator
;
958 * Sets the comparator class for the entries.
960 * This comparator will apply recursively to entries that implement
961 * {@link TimeGraphEntry#sortChildren(Comparator)}.
964 * A comparator object
966 protected void setEntryComparator(final Comparator
<ITimeGraphEntry
> comparator
) {
967 fEntryComparator
= comparator
;
971 * Gets the trace displayed in the view
975 protected ITmfTrace
getTrace() {
980 * Gets the start time
982 * @return The start time
984 protected long getStartTime() {
989 * Sets the start time
994 protected void setStartTime(long time
) {
1001 * @return The end time
1003 protected long getEndTime() {
1013 protected void setEndTime(long time
) {
1018 * Sets the auto-expand level to be used for the input of the view. The
1019 * value 0 means that there is no auto-expand; 1 means that top-level
1020 * elements are expanded, but not their children; 2 means that top-level
1021 * elements are expanded, and their children, but not grand-children; and so
1024 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
1028 * non-negative level, or <code>ALL_LEVELS</code> to expand all
1029 * levels of the tree
1031 protected void setAutoExpandLevel(int level
) {
1032 fAutoExpandLevel
= level
;
1033 ITimeGraphWrapper tgWrapper
= fTimeGraphWrapper
;
1034 if (tgWrapper
!= null) {
1035 tgWrapper
.setAutoExpandLevel(level
);
1040 * Gets the entry list for a trace
1045 * @return the entry list map
1047 protected List
<TimeGraphEntry
> getEntryList(ITmfTrace trace
) {
1048 synchronized (fEntryListMap
) {
1049 return fEntryListMap
.get(trace
);
1054 * Adds a trace entry list to the entry list map
1059 * the list of time graph entries
1061 protected void putEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
1062 synchronized (fEntryListMap
) {
1063 fEntryListMap
.put(trace
, new CopyOnWriteArrayList
<>(list
));
1068 * Adds a list of entries to a trace's entry list
1073 * the list of time graph entries to add
1075 protected void addToEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
1076 synchronized (fEntryListMap
) {
1077 List
<TimeGraphEntry
> entryList
= fEntryListMap
.get(trace
);
1078 if (entryList
== null) {
1079 fEntryListMap
.put(trace
, new CopyOnWriteArrayList
<>(list
));
1081 entryList
.addAll(list
);
1087 * Removes a list of entries from a trace's entry list
1092 * the list of time graph entries to remove
1094 protected void removeFromEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
1095 synchronized (fEntryListMap
) {
1096 List
<TimeGraphEntry
> entryList
= fEntryListMap
.get(trace
);
1097 if (entryList
!= null) {
1098 entryList
.removeAll(list
);
1104 * Text for the "next" button
1106 * @return The "next" button text
1108 protected String
getNextText() {
1109 return Messages
.AbstractTimeGraphtView_NextText
;
1113 * Tooltip for the "next" button
1115 * @return Tooltip for the "next" button
1117 protected String
getNextTooltip() {
1118 return Messages
.AbstractTimeGraphView_NextTooltip
;
1122 * Text for the "Previous" button
1124 * @return The "Previous" button text
1126 protected String
getPrevText() {
1127 return Messages
.AbstractTimeGraphView_PreviousText
;
1131 * Tooltip for the "previous" button
1133 * @return Tooltip for the "previous" button
1135 protected String
getPrevTooltip() {
1136 return Messages
.AbstractTimeGraphView_PreviousTooltip
;
1139 // ------------------------------------------------------------------------
1141 // ------------------------------------------------------------------------
1144 public void createPartControl(Composite parent
) {
1145 super.createPartControl(parent
);
1146 if (fColumns
== null || fLabelProvider
== null) {
1147 fTimeGraphWrapper
= new TimeGraphViewerWrapper(parent
, SWT
.NONE
);
1149 TimeGraphComboWrapper wrapper
= new TimeGraphComboWrapper(parent
, SWT
.NONE
);
1150 fTimeGraphWrapper
= wrapper
;
1151 TimeGraphCombo combo
= wrapper
.getTimeGraphCombo();
1152 combo
.setTreeContentProvider(fTimeGraphContentProvider
);
1153 combo
.setTreeLabelProvider(fLabelProvider
);
1154 combo
.setTreeColumns(fColumns
);
1155 if (fColumnComparators
!= null) {
1156 createColumnSelectionListener(combo
.getTreeViewer());
1159 fTimeGraphWrapper
.setTimeGraphContentProvider(fTimeGraphContentProvider
);
1160 fTimeGraphWrapper
.setFilterContentProvider(fFilterContentProvider
!= null ? fFilterContentProvider
: fTimeGraphContentProvider
);
1161 fTimeGraphWrapper
.setFilterLabelProvider(fFilterLabelProvider
);
1162 fTimeGraphWrapper
.setFilterColumns(fFilterColumns
);
1164 fTimeGraphWrapper
.setTimeGraphPresentationProvider(fPresentation
);
1165 fTimeGraphWrapper
.setAutoExpandLevel(fAutoExpandLevel
);
1167 fTimeGraphWrapper
.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
1169 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event
) {
1170 final long startTime
= event
.getStartTime();
1171 final long endTime
= event
.getEndTime();
1172 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
1173 broadcast(new TmfWindowRangeUpdatedSignal(AbstractTimeGraphView
.this, range
));
1174 startZoomThread(startTime
, endTime
);
1178 fTimeGraphWrapper
.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
1180 public void timeSelected(TimeGraphTimeEvent event
) {
1181 TmfNanoTimestamp startTime
= new TmfNanoTimestamp(event
.getBeginTime());
1182 TmfNanoTimestamp endTime
= new TmfNanoTimestamp(event
.getEndTime());
1183 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractTimeGraphView
.this, startTime
, endTime
));
1187 fTimeGraphWrapper
.getTimeGraphViewer().addBookmarkListener(new ITimeGraphBookmarkListener() {
1189 public void bookmarkAdded(final TimeGraphBookmarkEvent event
) {
1191 ResourcesPlugin
.getWorkspace().run(new IWorkspaceRunnable() {
1193 public void run(IProgressMonitor monitor
) throws CoreException
{
1194 IMarkerEvent bookmark
= event
.getBookmark();
1195 IMarker marker
= fEditorFile
.createMarker(IMarker
.BOOKMARK
);
1196 marker
.setAttribute(IMarker
.MESSAGE
, bookmark
.getLabel());
1197 marker
.setAttribute(ITmfMarker
.MARKER_TIME
, Long
.toString(bookmark
.getTime()));
1198 if (bookmark
.getDuration() > 0) {
1199 marker
.setAttribute(ITmfMarker
.MARKER_DURATION
, Long
.toString(bookmark
.getDuration()));
1200 marker
.setAttribute(IMarker
.LOCATION
,
1201 NLS
.bind(org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Messages
.TmfMarker_LocationTimeRange
,
1202 new TmfNanoTimestamp(bookmark
.getTime()),
1203 new TmfNanoTimestamp(bookmark
.getTime() + bookmark
.getDuration())));
1205 marker
.setAttribute(IMarker
.LOCATION
,
1206 NLS
.bind(org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Messages
.TmfMarker_LocationTime
,
1207 new TmfNanoTimestamp(bookmark
.getTime())));
1209 marker
.setAttribute(ITmfMarker
.MARKER_COLOR
, bookmark
.getColor().toString());
1212 } catch (CoreException e
) {
1213 Activator
.getDefault().logError(e
.getMessage());
1218 public void bookmarkRemoved(TimeGraphBookmarkEvent event
) {
1220 IMarkerEvent bookmark
= event
.getBookmark();
1221 IMarker
[] markers
= fEditorFile
.findMarkers(IMarker
.BOOKMARK
, false, IResource
.DEPTH_ZERO
);
1222 for (IMarker marker
: markers
) {
1223 if (bookmark
.getLabel().equals(marker
.getAttribute(IMarker
.MESSAGE
)) &&
1224 Long
.toString(bookmark
.getTime()).equals(marker
.getAttribute(ITmfMarker
.MARKER_TIME
, (String
) null)) &&
1225 Long
.toString(bookmark
.getDuration()).equals(marker
.getAttribute(ITmfMarker
.MARKER_DURATION
, Long
.toString(0))) &&
1226 bookmark
.getColor().toString().equals(marker
.getAttribute(ITmfMarker
.MARKER_COLOR
))) {
1231 } catch (CoreException e
) {
1232 Activator
.getDefault().logError(e
.getMessage());
1237 fTimeGraphWrapper
.getTimeGraphViewer().setTimeFormat(TimeFormat
.CALENDAR
);
1239 IStatusLineManager statusLineManager
= getViewSite().getActionBars().getStatusLineManager();
1240 fTimeGraphWrapper
.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager
);
1242 // View Action Handling
1244 contributeToActionBars();
1246 ITmfTrace trace
= TmfTraceManager
.getInstance().getActiveTrace();
1247 if (trace
!= null) {
1248 traceSelected(new TmfTraceSelectedSignal(this, trace
));
1251 // make selection available to other views
1252 getSite().setSelectionProvider(fTimeGraphWrapper
.getSelectionProvider());
1254 ResourcesPlugin
.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent
.POST_CHANGE
);
1258 public void setFocus() {
1259 fTimeGraphWrapper
.setFocus();
1263 public void dispose() {
1265 ResourcesPlugin
.getWorkspace().removeResourceChangeListener(this);
1272 public void resourceChanged(final IResourceChangeEvent event
) {
1273 for (final IMarkerDelta delta
: event
.findMarkerDeltas(IMarker
.BOOKMARK
, false)) {
1274 if (delta
.getResource().equals(fEditorFile
)) {
1275 fTimeGraphWrapper
.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile
));
1282 private static List
<IMarkerEvent
> refreshBookmarks(final IFile editorFile
) {
1283 List
<IMarkerEvent
> bookmarks
= new ArrayList
<>();
1284 if (editorFile
== null || !editorFile
.exists()) {
1288 IMarker
[] markers
= editorFile
.findMarkers(IMarker
.BOOKMARK
, false, IResource
.DEPTH_ZERO
);
1289 for (IMarker marker
: markers
) {
1290 String label
= marker
.getAttribute(IMarker
.MESSAGE
, (String
) null);
1291 String time
= marker
.getAttribute(ITmfMarker
.MARKER_TIME
, (String
) null);
1292 String duration
= marker
.getAttribute(ITmfMarker
.MARKER_DURATION
, Long
.toString(0));
1293 String rgba
= marker
.getAttribute(ITmfMarker
.MARKER_COLOR
, (String
) null);
1294 if (label
!= null && time
!= null && rgba
!= null) {
1295 Matcher matcher
= RGBA_PATTERN
.matcher(rgba
);
1296 if (matcher
.matches()) {
1298 int red
= Integer
.valueOf(matcher
.group(1));
1299 int green
= Integer
.valueOf(matcher
.group(2));
1300 int blue
= Integer
.valueOf(matcher
.group(3));
1301 int alpha
= Integer
.valueOf(matcher
.group(4));
1302 RGBA color
= new RGBA(red
, green
, blue
, alpha
);
1303 bookmarks
.add(new MarkerEvent(null, Long
.valueOf(time
), Long
.valueOf(duration
), IMarkerEvent
.BOOKMARKS
, color
, label
, true));
1304 } catch (NumberFormatException e
) {
1305 Activator
.getDefault().logError(e
.getMessage());
1310 } catch (CoreException e
) {
1311 Activator
.getDefault().logError(e
.getMessage());
1318 // ------------------------------------------------------------------------
1320 // ------------------------------------------------------------------------
1323 * Handler for the trace opened signal.
1326 * The incoming signal
1329 public void traceOpened(TmfTraceOpenedSignal signal
) {
1330 loadTrace(signal
.getTrace());
1334 * Handler for the trace selected signal
1337 * The incoming signal
1340 public void traceSelected(final TmfTraceSelectedSignal signal
) {
1341 if (signal
.getTrace() == fTrace
) {
1344 loadTrace(signal
.getTrace());
1348 * Trace is closed: clear the data structures and the view
1351 * the signal received
1354 public void traceClosed(final TmfTraceClosedSignal signal
) {
1355 synchronized (fBuildThreadMap
) {
1356 for (ITmfTrace trace
: getTracesToBuild(signal
.getTrace())) {
1357 BuildThread buildThread
= fBuildThreadMap
.remove(trace
);
1358 if (buildThread
!= null) {
1359 buildThread
.cancel();
1363 fMarkerEventSourcesMap
.remove(signal
.getTrace());
1364 synchronized (fEntryListMap
) {
1365 fEntryListMap
.remove(signal
.getTrace());
1367 fFiltersMap
.remove(signal
.getTrace());
1368 fViewContext
.remove(signal
.getTrace());
1369 if (signal
.getTrace() == fTrace
) {
1372 fStartTime
= SWT
.DEFAULT
;
1373 fEndTime
= SWT
.DEFAULT
;
1374 if (fZoomThread
!= null) {
1375 fZoomThread
.cancel();
1383 * Handler for the selection range signal.
1386 * The signal that's received
1390 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal
) {
1391 if (signal
.getSource() == this || fTrace
== null) {
1394 final long beginTime
= signal
.getBeginTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1395 final long endTime
= signal
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1397 Display
.getDefault().asyncExec(new Runnable() {
1400 if (fTimeGraphWrapper
.isDisposed()) {
1403 if (beginTime
== endTime
) {
1404 fTimeGraphWrapper
.getTimeGraphViewer().setSelectedTime(beginTime
, true);
1406 fTimeGraphWrapper
.getTimeGraphViewer().setSelectionRange(beginTime
, endTime
, true);
1408 synchingToTime(fTimeGraphWrapper
.getTimeGraphViewer().getSelectionBegin());
1414 * Handler for the window range signal.
1417 * The signal that's received
1421 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal
) {
1422 if (signal
.getSource() == this || fTrace
== null) {
1425 if (signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange()) == null) {
1428 final long startTime
= signal
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1429 final long endTime
= signal
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1430 Display
.getDefault().asyncExec(new Runnable() {
1433 if (fTimeGraphWrapper
.isDisposed()) {
1436 fTimeGraphWrapper
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
1437 startZoomThread(startTime
, endTime
);
1443 * @param signal the format of the timestamps was updated.
1446 public void updateTimeFormat( final TmfTimestampFormatUpdateSignal signal
){
1447 fTimeGraphWrapper
.refresh();
1450 // ------------------------------------------------------------------------
1452 // ------------------------------------------------------------------------
1454 private void loadTrace(final ITmfTrace trace
) {
1455 if (fZoomThread
!= null) {
1456 fZoomThread
.cancel();
1459 if (fTrace
!= null) {
1460 /* save the filters of the previous trace */
1461 fFiltersMap
.put(fTrace
, fTimeGraphWrapper
.getFilters());
1462 fViewContext
.put(fTrace
, new ViewContext(fCurrentSortColumn
, fSortDirection
, fTimeGraphWrapper
.getSelection()));
1465 restoreViewContext();
1466 fEditorFile
= TmfTraceManager
.getInstance().getTraceEditorFile(trace
);
1467 synchronized (fEntryListMap
) {
1468 fEntryList
= fEntryListMap
.get(fTrace
);
1469 if (fEntryList
== null) {
1472 fStartTime
= fTrace
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1473 fEndTime
= fTrace
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1480 * Forces a rebuild of the entries list, even if entries already exist for this trace
1482 protected void rebuild() {
1483 setStartTime(Long
.MAX_VALUE
);
1484 setEndTime(Long
.MIN_VALUE
);
1486 ITmfTrace viewTrace
= fTrace
;
1487 if (viewTrace
== null) {
1490 List
<IMarkerEventSource
> markerEventSources
= new ArrayList
<>();
1491 synchronized (fBuildThreadMap
) {
1492 for (ITmfTrace trace
: getTracesToBuild(viewTrace
)) {
1493 if (trace
== null) {
1496 markerEventSources
.addAll(TmfTraceAdapterManager
.getAdapters(trace
, IMarkerEventSource
.class));
1497 BuildThread buildThread
= new BuildThread(trace
, viewTrace
, getName());
1498 fBuildThreadMap
.put(trace
, buildThread
);
1499 buildThread
.start();
1502 fMarkerEventSourcesMap
.put(viewTrace
, markerEventSources
);
1506 * Method called when synching to a given timestamp. Inheriting classes can
1507 * perform actions here to update the view at the given timestamp.
1510 * The currently selected time
1512 protected void synchingToTime(long time
) {
1517 * Return the list of traces whose data or analysis results will be used to
1518 * populate the view. By default, if the trace is an experiment, the traces
1519 * under it will be returned, otherwise, the trace itself is returned.
1521 * A build thread will be started for each trace returned by this method,
1522 * some of which may receive events in live streaming mode.
1525 * The trace associated with this view
1526 * @return List of traces with data to display
1528 protected @NonNull Iterable
<ITmfTrace
> getTracesToBuild(@NonNull ITmfTrace trace
) {
1529 return TmfTraceManager
.getTraceSet(trace
);
1533 * Build the entries list to show in this time graph
1535 * Called from the BuildThread
1538 * The trace being built
1539 * @param parentTrace
1540 * The parent of the trace set, or the trace itself
1542 * The progress monitor object
1544 protected abstract void buildEventList(@NonNull ITmfTrace trace
, @NonNull ITmfTrace parentTrace
, @NonNull IProgressMonitor monitor
);
1547 * Gets the list of event for an entry in a given timerange
1550 * The entry to get events for
1552 * Start of the time range
1554 * End of the time range
1558 * The progress monitor object
1559 * @return The list of events for the entry
1561 protected abstract @Nullable List
<@NonNull ITimeEvent
> getEventList(@NonNull TimeGraphEntry entry
,
1562 long startTime
, long endTime
, long resolution
,
1563 @NonNull IProgressMonitor monitor
);
1566 * Gets the list of links (displayed as arrows) for a trace in a given
1567 * timerange. Default implementation returns an empty list.
1570 * Start of the time range
1572 * End of the time range
1576 * The progress monitor object
1577 * @return The list of link events
1579 protected @Nullable List
<@NonNull ILinkEvent
> getLinkList(long startTime
, long endTime
,
1580 long resolution
, @NonNull IProgressMonitor monitor
) {
1581 return new ArrayList
<>();
1585 * Gets the list of view-specific marker categories. Default implementation
1586 * returns an empty list.
1588 * @return The list of marker categories
1591 protected @NonNull List
<String
> getViewMarkerCategories() {
1592 return new ArrayList
<>();
1596 * Gets the list of view-specific markers for a trace in a given time range.
1597 * Default implementation returns an empty list.
1600 * Start of the time range
1602 * End of the time range
1606 * The progress monitor object
1607 * @return The list of marker events
1610 protected @NonNull List
<IMarkerEvent
> getViewMarkerList(long startTime
, long endTime
,
1611 long resolution
, @NonNull IProgressMonitor monitor
) {
1612 return new ArrayList
<>();
1616 * Gets the list of trace-specific markers for a trace in a given time range.
1619 * Start of the time range
1621 * End of the time range
1625 * The progress monitor object
1626 * @return The list of marker events
1629 protected @NonNull List
<IMarkerEvent
> getTraceMarkerList(long startTime
, long endTime
,
1630 long resolution
, @NonNull IProgressMonitor monitor
) {
1631 List
<IMarkerEvent
> markers
= new ArrayList
<>();
1632 for (IMarkerEventSource markerEventSource
: getMarkerEventSources(fTrace
)) {
1633 for (String category
: markerEventSource
.getMarkerCategories()) {
1634 if (monitor
.isCanceled()) {
1637 markers
.addAll(markerEventSource
.getMarkerList(checkNotNull(category
), startTime
, endTime
, resolution
, monitor
));
1644 * Get the list of current marker categories.
1646 * @return The list of marker categories
1649 private @NonNull List
<String
> getMarkerCategories() {
1650 Set
<String
> categories
= new LinkedHashSet
<>(getViewMarkerCategories());
1651 for (IMarkerEventSource markerEventSource
: getMarkerEventSources(fTrace
)) {
1652 categories
.addAll(markerEventSource
.getMarkerCategories());
1654 return new ArrayList
<>(categories
);
1658 * Gets the list of marker event sources for a given trace.
1662 * @return The list of marker event sources
1665 private @NonNull List
<IMarkerEventSource
> getMarkerEventSources(ITmfTrace trace
) {
1666 List
<IMarkerEventSource
> markerEventSources
= fMarkerEventSourcesMap
.get(trace
);
1667 if (markerEventSources
== null) {
1668 markerEventSources
= checkNotNull(Collections
.<IMarkerEventSource
>emptyList());
1670 return markerEventSources
;
1674 * Refresh the display
1676 protected void refresh() {
1677 final boolean zoomThread
= Thread
.currentThread() instanceof ZoomThread
;
1678 TmfUiRefreshHandler
.getInstance().queueUpdate(this, new Runnable() {
1681 if (fTimeGraphWrapper
.isDisposed()) {
1684 boolean hasEntries
= false;
1685 synchronized (fEntryListMap
) {
1686 fEntryList
= fEntryListMap
.get(fTrace
);
1687 if (fEntryList
== null) {
1688 fEntryList
= new CopyOnWriteArrayList
<>();
1689 } else if (fEntryComparator
!= null) {
1690 List
<TimeGraphEntry
> list
= new ArrayList
<>(fEntryList
);
1691 Collections
.sort(list
, fEntryComparator
);
1692 for (ITimeGraphEntry entry
: list
) {
1693 sortChildren(entry
, fEntryComparator
);
1696 fEntryList
.addAll(list
);
1698 hasEntries
= !fEntryList
.isEmpty();
1700 boolean inputChanged
= fEntryList
!= fTimeGraphWrapper
.getInput();
1701 TimeGraphCombo combo
= getTimeGraphCombo();
1703 // Set redraw to false to only draw once
1704 if (combo
!= null) {
1705 combo
.getTreeViewer().getTree().setRedraw(false);
1707 getTimeGraphViewer().getTimeGraphControl().setRedraw(false);
1709 fTimeGraphWrapper
.setInput(fEntryList
);
1710 /* restore the previously saved filters, if any */
1711 fTimeGraphWrapper
.setFilters(fFiltersMap
.get(fTrace
));
1712 fTimeGraphWrapper
.getTimeGraphViewer().setLinks(null);
1713 fTimeGraphWrapper
.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile
));
1714 fTimeGraphWrapper
.getTimeGraphViewer().setMarkerCategories(getMarkerCategories());
1715 fTimeGraphWrapper
.getTimeGraphViewer().setMarkers(null);
1718 fTimeGraphWrapper
.refresh();
1721 if (fIsRevealSelection
) {
1722 fIsRevealSelection
= false;
1723 ITimeGraphEntry entry1
= fTimeGraphWrapper
.getSelection();
1724 fTimeGraphWrapper
.setSelection(entry1
);
1727 if (combo
!= null) {
1728 combo
.getTreeViewer().getTree().setRedraw(true);
1730 getTimeGraphViewer().getTimeGraphControl().setRedraw(true);
1732 long startBound
= (fStartTime
== Long
.MAX_VALUE ? SWT
.DEFAULT
: fStartTime
);
1733 long endBound
= (fEndTime
== Long
.MIN_VALUE ? SWT
.DEFAULT
: fEndTime
);
1734 fTimeGraphWrapper
.getTimeGraphViewer().setTimeBounds(startBound
, endBound
);
1736 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
1737 long selectionBeginTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1738 long selectionEndTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getSelectionRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1739 long startTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getWindowRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1740 long endTime
= fTrace
== null ? SWT
.DEFAULT
: ctx
.getWindowRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1741 startTime
= (fStartTime
== Long
.MAX_VALUE ? SWT
.DEFAULT
: Math
.max(startTime
, fStartTime
));
1742 endTime
= (fEndTime
== Long
.MIN_VALUE ? SWT
.DEFAULT
: Math
.min(endTime
, fEndTime
));
1743 fTimeGraphWrapper
.getTimeGraphViewer().setSelectionRange(selectionBeginTime
, selectionEndTime
, false);
1744 fTimeGraphWrapper
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
1746 if (inputChanged
&& selectionBeginTime
!= SWT
.DEFAULT
) {
1747 synchingToTime(selectionBeginTime
);
1750 if (fTimeGraphWrapper
instanceof TimeGraphComboWrapper
&& !fPackDone
) {
1751 for (TreeColumn column
: ((TimeGraphComboWrapper
) fTimeGraphWrapper
).getTreeViewer().getTree().getColumns()) {
1760 startZoomThread(startTime
, endTime
);
1770 protected void redraw() {
1771 synchronized (fSyncObj
) {
1772 if (fRedrawState
== State
.IDLE
) {
1773 fRedrawState
= State
.BUSY
;
1775 fRedrawState
= State
.PENDING
;
1779 Display
.getDefault().asyncExec(new Runnable() {
1782 if (fTimeGraphWrapper
.isDisposed()) {
1785 fTimeGraphWrapper
.redraw();
1786 fTimeGraphWrapper
.update();
1787 synchronized (fSyncObj
) {
1788 if (fRedrawState
== State
.PENDING
) {
1789 fRedrawState
= State
.IDLE
;
1792 fRedrawState
= State
.IDLE
;
1799 private void sortChildren(ITimeGraphEntry entry
, Comparator
<ITimeGraphEntry
> comparator
) {
1800 if (entry
instanceof TimeGraphEntry
) {
1801 ((TimeGraphEntry
) entry
).sortChildren(comparator
);
1803 for (ITimeGraphEntry child
: entry
.getChildren()) {
1804 sortChildren(child
, comparator
);
1809 * Start or restart the zoom thread.
1812 * the zoom start time
1817 protected final void startZoomThread(long startTime
, long endTime
) {
1818 fDirty
.incrementAndGet();
1819 boolean restart
= false;
1820 if (fZoomThread
!= null) {
1821 fZoomThread
.cancel();
1822 if (fZoomThread
.fZoomStartTime
== startTime
&& fZoomThread
.fZoomEndTime
== endTime
) {
1826 long resolution
= Math
.max(1, (endTime
- startTime
) / fDisplayWidth
);
1827 fZoomThread
= createZoomThread(startTime
, endTime
, resolution
, restart
);
1828 if (fZoomThread
!= null) {
1829 fZoomThread
.start();
1831 fDirty
.decrementAndGet();
1836 * Create a zoom thread.
1839 * the zoom start time
1845 * true if restarting zoom for the same time range
1846 * @return a zoom thread
1849 protected @Nullable ZoomThread
createZoomThread(long startTime
, long endTime
, long resolution
, boolean restart
) {
1850 final List
<TimeGraphEntry
> entryList
= fEntryList
;
1851 if (entryList
== null) {
1854 return new ZoomThreadByEntry(entryList
, startTime
, endTime
, resolution
);
1857 private void makeActions() {
1858 fPreviousResourceAction
= fTimeGraphWrapper
.getTimeGraphViewer().getPreviousItemAction();
1859 fPreviousResourceAction
.setText(getPrevText());
1860 fPreviousResourceAction
.setToolTipText(getPrevTooltip());
1861 fNextResourceAction
= fTimeGraphWrapper
.getTimeGraphViewer().getNextItemAction();
1862 fNextResourceAction
.setText(getNextText());
1863 fNextResourceAction
.setToolTipText(getNextTooltip());
1866 private void contributeToActionBars() {
1867 IActionBars bars
= getViewSite().getActionBars();
1868 fillLocalToolBar(bars
.getToolBarManager());
1869 fillLocalMenu(bars
.getMenuManager());
1873 * Add actions to local tool bar manager
1875 * @param manager the tool bar manager
1877 protected void fillLocalToolBar(IToolBarManager manager
) {
1878 if (fFilterColumns
!= null && fFilterLabelProvider
!= null && fFilterColumns
.length
> 0) {
1879 manager
.add(fTimeGraphWrapper
.getShowFilterDialogAction());
1881 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getShowLegendAction());
1882 manager
.add(new Separator());
1883 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getResetScaleAction());
1884 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getPreviousEventAction());
1885 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getNextEventAction());
1886 manager
.add(new Separator());
1887 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getToggleBookmarkAction());
1888 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getPreviousMarkerAction());
1889 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getNextMarkerAction());
1890 manager
.add(new Separator());
1891 manager
.add(fPreviousResourceAction
);
1892 manager
.add(fNextResourceAction
);
1893 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getZoomInAction());
1894 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getZoomOutAction());
1895 manager
.add(new Separator());
1899 * Add actions to local menu manager
1901 * @param manager the tool bar manager
1904 protected void fillLocalMenu(IMenuManager manager
) {
1905 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getMarkersMenu());
1912 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
1913 if (fTimeGraphWrapper
== null) {
1916 return fTimeGraphWrapper
.getTimeViewAlignmentInfo();
1923 public int getAvailableWidth(int requestedOffset
) {
1924 if (fTimeGraphWrapper
== null) {
1927 return fTimeGraphWrapper
.getAvailableWidth(requestedOffset
);
1934 public void performAlign(int offset
, int width
) {
1935 if (fTimeGraphWrapper
!= null) {
1936 fTimeGraphWrapper
.performAlign(offset
, width
);
1941 * Returns whether or not the time graph view is dirty. The time graph view
1942 * is considered dirty if it has yet to completely update its model.
1944 * @return true if the time graph view has yet to completely update its
1945 * model, false otherwise
1948 public boolean isDirty() {
1949 if (fZoomThread
== null) {
1952 return fDirty
.get() != 0 || fZoomThread
.getZoomStartTime() != fTimeGraphWrapper
.getTimeGraphViewer().getTime0() || fZoomThread
.getZoomEndTime() != fTimeGraphWrapper
.getTimeGraphViewer().getTime1();
1955 private void createColumnSelectionListener(TreeViewer treeViewer
) {
1956 for (int i
= 0; i
< fColumnComparators
.length
; i
++) {
1957 final int index
= i
;
1958 final Comparator
<ITimeGraphEntry
> comp
= fColumnComparators
[index
];
1959 final Tree tree
= treeViewer
.getTree();
1960 final TreeColumn column
= tree
.getColumn(i
);
1963 column
.addSelectionListener(new SelectionAdapter() {
1965 public void widgetSelected(SelectionEvent e
) {
1966 TreeColumn prevSortcolumn
= tree
.getSortColumn();
1967 int direction
= tree
.getSortDirection();
1968 if (prevSortcolumn
== column
) {
1969 direction
= (direction
== SWT
.DOWN
) ? SWT
.UP
: SWT
.DOWN
;
1971 direction
= SWT
.DOWN
;
1973 tree
.setSortColumn(column
);
1974 tree
.setSortDirection(direction
);
1975 fSortDirection
= direction
;
1976 fCurrentSortColumn
= index
;
1977 Comparator
<ITimeGraphEntry
> comparator
= comp
;
1979 if (comparator
instanceof ITimeGraphEntryComparator
) {
1980 ((ITimeGraphEntryComparator
) comparator
).setDirection(direction
);
1982 if (direction
!= SWT
.DOWN
) {
1983 comparator
= checkNotNull(Collections
.reverseOrder(comparator
));
1985 setEntryComparator(comparator
);
1986 fIsRevealSelection
= true;
1987 if (fTimeGraphWrapper
instanceof TimeGraphComboWrapper
) {
1988 ((TimeGraphComboWrapper
) fTimeGraphWrapper
).getTreeViewer().getControl().setFocus();
1997 private void restoreViewContext() {
1998 TimeGraphCombo combo
= getTimeGraphCombo();
1999 ViewContext viewContext
= fViewContext
.get(fTrace
);
2000 if (combo
!= null) {
2001 if (fColumnComparators
!= null) {
2002 // restore sort settings
2003 fSortDirection
= SWT
.DOWN
;
2004 fCurrentSortColumn
= fInitialSortColumn
;
2005 if (viewContext
!= null) {
2006 fSortDirection
= viewContext
.getSortDirection();
2007 fCurrentSortColumn
= viewContext
.getSortColumn();
2009 if ((fCurrentSortColumn
< fColumnComparators
.length
) && (fColumnComparators
[fCurrentSortColumn
] != null)) {
2010 Comparator
<ITimeGraphEntry
> comparator
= fColumnComparators
[fCurrentSortColumn
];
2011 if (comparator
instanceof ITimeGraphEntryComparator
) {
2012 ((ITimeGraphEntryComparator
) comparator
).setDirection(fSortDirection
);
2014 if (fSortDirection
!= SWT
.DOWN
) {
2015 comparator
= checkNotNull(Collections
.reverseOrder(comparator
));
2017 setEntryComparator(comparator
);
2023 private void applyViewContext() {
2024 TimeGraphCombo combo
= getTimeGraphCombo();
2025 ViewContext viewContext
= fViewContext
.get(fTrace
);
2026 if (combo
!= null) {
2027 TreeViewer treeViewer
= combo
.getTreeViewer();
2028 final Tree tree
= treeViewer
.getTree();
2029 final TreeColumn column
= tree
.getColumn(fCurrentSortColumn
);
2030 tree
.setSortDirection(fSortDirection
);
2031 tree
.setSortColumn(column
);
2032 combo
.getTreeViewer().getControl().setFocus();
2034 // restore and reveal selection
2035 if ((viewContext
!= null) && (viewContext
.getSelection() != null)) {
2036 fTimeGraphWrapper
.setSelection(viewContext
.getSelection());
2038 fViewContext
.remove(fTrace
);
2041 private static class ViewContext
{
2042 private int fSortColumnIndex
;
2043 private int fSortDirection
;
2044 private @Nullable ITimeGraphEntry fSelection
;
2046 ViewContext(int sortColunm
, int sortDirection
, ITimeGraphEntry selection
) {
2047 fSortColumnIndex
= sortColunm
;
2048 fSortDirection
= sortDirection
;
2049 fSelection
= selection
;
2052 * @return the sortColumn
2054 public int getSortColumn() {
2055 return fSortColumnIndex
;
2058 * @return the sortDirection
2060 public int getSortDirection() {
2061 return fSortDirection
;
2064 * @return the selection
2066 public ITimeGraphEntry
getSelection() {