1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 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 java
.util
.ArrayList
;
20 import java
.util
.Collections
;
21 import java
.util
.Comparator
;
22 import java
.util
.HashMap
;
23 import java
.util
.List
;
25 import java
.util
.concurrent
.CopyOnWriteArrayList
;
27 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
28 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
29 import org
.eclipse
.jdt
.annotation
.NonNull
;
30 import org
.eclipse
.jdt
.annotation
.Nullable
;
31 import org
.eclipse
.jface
.action
.Action
;
32 import org
.eclipse
.jface
.action
.IAction
;
33 import org
.eclipse
.jface
.action
.IStatusLineManager
;
34 import org
.eclipse
.jface
.action
.IToolBarManager
;
35 import org
.eclipse
.jface
.action
.Separator
;
36 import org
.eclipse
.jface
.viewers
.AbstractTreeViewer
;
37 import org
.eclipse
.jface
.viewers
.ILabelProvider
;
38 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
39 import org
.eclipse
.jface
.viewers
.ISelectionProvider
;
40 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
41 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
42 import org
.eclipse
.jface
.viewers
.TreeViewer
;
43 import org
.eclipse
.jface
.viewers
.Viewer
;
44 import org
.eclipse
.swt
.SWT
;
45 import org
.eclipse
.swt
.graphics
.Image
;
46 import org
.eclipse
.swt
.widgets
.Composite
;
47 import org
.eclipse
.swt
.widgets
.Display
;
48 import org
.eclipse
.swt
.widgets
.TreeColumn
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfRangeSynchSignal
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTimeSynchSignal
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTimestampFormatUpdateSignal
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
56 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
57 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfNanoTimestamp
;
58 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
59 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
60 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceContext
;
61 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
62 import org
.eclipse
.tracecompass
.tmf
.ui
.TmfUiRefreshHandler
;
63 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.TmfView
;
64 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphContentProvider
;
65 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphPresentationProvider2
;
66 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphRangeListener
;
67 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphSelectionListener
;
68 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
69 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
70 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphPresentationProvider
;
71 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphRangeUpdateEvent
;
72 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
73 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphViewer
;
74 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ILinkEvent
;
75 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
76 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
77 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
78 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
79 import org
.eclipse
.ui
.IActionBars
;
82 * An abstract view all time graph views can inherit
84 * This view contains either a time graph viewer, or a time graph combo which is
85 * divided between a tree viewer on the left and a time graph viewer on the right.
87 public abstract class AbstractTimeGraphView
extends TmfView
{
89 /** Constant indicating that all levels of the time graph should be expanded */
90 protected static final int ALL_LEVELS
= AbstractTreeViewer
.ALL_LEVELS
;
99 // ------------------------------------------------------------------------
101 // ------------------------------------------------------------------------
103 /** The timegraph wrapper */
104 private ITimeGraphWrapper fTimeGraphWrapper
;
106 /** The selected trace */
107 private ITmfTrace fTrace
;
109 /** The timegraph entry list */
110 private List
<TimeGraphEntry
> fEntryList
;
112 /** The trace to entry list hash map */
113 private final Map
<ITmfTrace
, List
<TimeGraphEntry
>> fEntryListMap
= new HashMap
<>();
115 /** The trace to build thread hash map */
116 private final Map
<ITmfTrace
, BuildThread
> fBuildThreadMap
= new HashMap
<>();
118 /** The start time */
119 private long fStartTime
;
122 private long fEndTime
;
124 /** The display width */
125 private final int fDisplayWidth
;
127 /** The zoom thread */
128 private ZoomThread fZoomThread
;
130 /** The next resource action */
131 private Action fNextResourceAction
;
133 /** The previous resource action */
134 private Action fPreviousResourceAction
;
136 /** A comparator class */
137 private Comparator
<ITimeGraphEntry
> fEntryComparator
= null;
139 /** The redraw state used to prevent unnecessary queuing of display runnables */
140 private State fRedrawState
= State
.IDLE
;
142 /** The redraw synchronization object */
143 private final Object fSyncObj
= new Object();
145 /** The presentation provider for this view */
146 private final TimeGraphPresentationProvider fPresentation
;
148 /** The tree column label array, or null if combo is not used */
149 private String
[] fColumns
;
151 /** The tree label provider, or null if combo is not used */
152 private TreeLabelProvider fLabelProvider
= null;
154 /** The relative weight of the sash, ignored if combo is not used */
155 private int[] fWeight
= { 1, 1 };
157 /** The filter column label array, or null if filter is not used */
158 private String
[] fFilterColumns
;
160 /** The pack done flag */
161 private boolean fPackDone
= false;
163 /** The filter label provider, or null if filter is not used */
164 private TreeLabelProvider fFilterLabelProvider
;
166 private int fAutoExpandLevel
= ALL_LEVELS
;
168 // ------------------------------------------------------------------------
170 // ------------------------------------------------------------------------
172 private interface ITimeGraphWrapper
{
174 void setTimeGraphProvider(TimeGraphPresentationProvider fPresentation
);
176 TimeGraphViewer
getTimeGraphViewer();
178 void addSelectionListener(ITimeGraphSelectionListener iTimeGraphSelectionListener
);
180 ISelectionProvider
getSelectionProvider();
184 boolean isDisposed();
188 void setInput(Object input
);
196 void setAutoExpandLevel(int level
);
200 private class TimeGraphViewerWrapper
implements ITimeGraphWrapper
{
201 private TimeGraphViewer viewer
;
203 private TimeGraphViewerWrapper(Composite parent
, int style
) {
204 viewer
= new TimeGraphViewer(parent
, style
);
208 public void setTimeGraphProvider(TimeGraphPresentationProvider timeGraphProvider
) {
209 viewer
.setTimeGraphProvider(timeGraphProvider
);
213 public TimeGraphViewer
getTimeGraphViewer() {
218 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
219 viewer
.addSelectionListener(listener
);
223 public ISelectionProvider
getSelectionProvider() {
224 return viewer
.getSelectionProvider();
228 public void setFocus() {
233 public boolean isDisposed() {
234 return viewer
.getControl().isDisposed();
238 public void setInput(Object input
) {
239 viewer
.setInput(input
);
243 public Object
getInput() {
244 return viewer
.getInput();
248 public void refresh() {
253 public void redraw() {
254 viewer
.getControl().redraw();
258 public void update() {
259 viewer
.getControl().update();
263 public void setAutoExpandLevel(int level
) {
264 viewer
.setAutoExpandLevel(level
);
268 private class TimeGraphComboWrapper
implements ITimeGraphWrapper
{
269 private TimeGraphCombo combo
;
271 private TimeGraphComboWrapper(Composite parent
, int style
) {
272 combo
= new TimeGraphCombo(parent
, style
, fWeight
);
276 public void setTimeGraphProvider(TimeGraphPresentationProvider timeGraphProvider
) {
277 combo
.setTimeGraphProvider(timeGraphProvider
);
281 public TimeGraphViewer
getTimeGraphViewer() {
282 return combo
.getTimeGraphViewer();
286 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
287 combo
.addSelectionListener(listener
);
291 public ISelectionProvider
getSelectionProvider() {
292 return combo
.getTreeViewer();
296 public void setFocus() {
301 public boolean isDisposed() {
302 return combo
.isDisposed();
306 public void setInput(Object input
) {
307 combo
.setInput(input
);
311 public Object
getInput() {
312 return combo
.getInput();
316 public void refresh() {
321 public void redraw() {
326 public void update() {
331 public void setAutoExpandLevel(int level
) {
332 combo
.setAutoExpandLevel(level
);
335 TimeGraphCombo
getTimeGraphCombo() {
339 TreeViewer
getTreeViewer() {
340 return combo
.getTreeViewer();
343 IAction
getShowFilterAction() {
344 return combo
.getShowFilterAction();
348 private class TreeContentProvider
implements ITreeContentProvider
{
351 public void dispose() {
355 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
359 public ITimeGraphEntry
[] getElements(Object inputElement
) {
360 if (inputElement
!= null) {
362 return ((List
<?
>) inputElement
).toArray(new ITimeGraphEntry
[0]);
363 } catch (ClassCastException e
) {
366 return new ITimeGraphEntry
[0];
370 public Object
[] getChildren(Object parentElement
) {
371 ITimeGraphEntry entry
= (ITimeGraphEntry
) parentElement
;
372 List
<?
extends ITimeGraphEntry
> children
= entry
.getChildren();
373 return children
.toArray(new ITimeGraphEntry
[children
.size()]);
377 public Object
getParent(Object element
) {
378 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
379 return entry
.getParent();
383 public boolean hasChildren(Object element
) {
384 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
385 return entry
.hasChildren();
390 private class TimeGraphContentProvider
implements ITimeGraphContentProvider
{
393 public ITimeGraphEntry
[] getElements(Object inputElement
) {
394 if (inputElement
!= null) {
396 return ((List
<?
>) inputElement
).toArray(new ITimeGraphEntry
[0]);
397 } catch (ClassCastException e
) {
400 return new ITimeGraphEntry
[0];
406 * Base class to provide the labels for the tree viewer. Views extending
407 * this class typically need to override the getColumnText method if they
408 * have more than one column to display
410 protected static class TreeLabelProvider
implements ITableLabelProvider
, ILabelProvider
{
413 public void addListener(ILabelProviderListener listener
) {
417 public void dispose() {
421 public boolean isLabelProperty(Object element
, String property
) {
426 public void removeListener(ILabelProviderListener listener
) {
430 public Image
getColumnImage(Object element
, int columnIndex
) {
435 public String
getColumnText(Object element
, int columnIndex
) {
436 TimeGraphEntry entry
= (TimeGraphEntry
) element
;
437 if (columnIndex
== 0) {
438 return entry
.getName();
444 public Image
getImage(Object element
) {
449 public String
getText(Object element
) {
450 TimeGraphEntry entry
= (TimeGraphEntry
) element
;
451 return entry
.getName();
456 private class BuildThread
extends Thread
{
457 private final @NonNull ITmfTrace fBuildTrace
;
458 private final @NonNull ITmfTrace fParentTrace
;
459 private final @NonNull IProgressMonitor fMonitor
;
461 public BuildThread(final @NonNull ITmfTrace trace
, final @NonNull ITmfTrace parentTrace
, final String name
) {
462 super(name
+ " build"); //$NON-NLS-1$
464 fParentTrace
= parentTrace
;
465 fMonitor
= new NullProgressMonitor();
470 buildEventList(fBuildTrace
, fParentTrace
, fMonitor
);
471 synchronized (fBuildThreadMap
) {
472 fBuildThreadMap
.remove(fBuildTrace
);
476 public void cancel() {
477 fMonitor
.setCanceled(true);
481 private class ZoomThread
extends Thread
{
482 private final @NonNull List
<TimeGraphEntry
> fZoomEntryList
;
483 private final long fZoomStartTime
;
484 private final long fZoomEndTime
;
485 private final long fResolution
;
486 private final @NonNull IProgressMonitor fMonitor
;
488 public ZoomThread(@NonNull List
<TimeGraphEntry
> entryList
, long startTime
, long endTime
, String name
) {
489 super(name
+ " zoom"); //$NON-NLS-1$
490 fZoomEntryList
= entryList
;
491 fZoomStartTime
= startTime
;
492 fZoomEndTime
= endTime
;
493 fResolution
= Math
.max(1, (fZoomEndTime
- fZoomStartTime
) / fDisplayWidth
);
494 fMonitor
= new NullProgressMonitor();
499 for (TimeGraphEntry entry
: fZoomEntryList
) {
500 if (fMonitor
.isCanceled()) {
506 zoom(entry
, fMonitor
);
508 /* Refresh the arrows when zooming */
509 List
<ILinkEvent
> events
= getLinkList(fZoomStartTime
, fZoomEndTime
, fResolution
, fMonitor
);
510 if (events
!= null) {
511 fTimeGraphWrapper
.getTimeGraphViewer().setLinks(events
);
516 private void zoom(@NonNull TimeGraphEntry entry
, @NonNull IProgressMonitor monitor
) {
517 if (fZoomStartTime
<= fStartTime
&& fZoomEndTime
>= fEndTime
) {
518 entry
.setZoomedEventList(null);
520 List
<ITimeEvent
> zoomedEventList
= getEventList(entry
, fZoomStartTime
, fZoomEndTime
, fResolution
, monitor
);
521 if (zoomedEventList
!= null) {
522 entry
.setZoomedEventList(zoomedEventList
);
526 for (ITimeGraphEntry child
: entry
.getChildren()) {
527 if (fMonitor
.isCanceled()) {
530 if (child
instanceof TimeGraphEntry
) {
531 zoom((TimeGraphEntry
) child
, monitor
);
536 public void cancel() {
537 fMonitor
.setCanceled(true);
541 // ------------------------------------------------------------------------
543 // ------------------------------------------------------------------------
546 * Constructs a time graph view that contains either a time graph viewer or
547 * a time graph combo.
549 * By default, the view uses a time graph viewer. To use a time graph combo,
550 * the subclass constructor must call {@link #setTreeColumns(String[])} and
551 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
556 * The presentation provider
558 public AbstractTimeGraphView(String id
, TimeGraphPresentationProvider pres
) {
560 fPresentation
= pres
;
561 fDisplayWidth
= Display
.getDefault().getBounds().width
;
564 // ------------------------------------------------------------------------
565 // Getters and setters
566 // ------------------------------------------------------------------------
569 * Getter for the time graph combo
571 * @return The time graph combo, or null if combo is not used
573 protected TimeGraphCombo
getTimeGraphCombo() {
574 if (fTimeGraphWrapper
instanceof TimeGraphComboWrapper
) {
575 return ((TimeGraphComboWrapper
) fTimeGraphWrapper
).getTimeGraphCombo();
581 * Getter for the time graph viewer
583 * @return The time graph viewer
585 protected TimeGraphViewer
getTimeGraphViewer() {
586 return fTimeGraphWrapper
.getTimeGraphViewer();
590 * Getter for the presentation provider
592 * @return The time graph presentation provider
594 protected ITimeGraphPresentationProvider2
getPresentationProvider() {
595 return fPresentation
;
599 * Sets the tree column labels.
600 * This should be called from the constructor.
603 * The array of tree column labels
605 protected void setTreeColumns(final String
[] columns
) {
610 * Sets the tree label provider.
611 * This should be called from the constructor.
614 * The tree label provider
616 protected void setTreeLabelProvider(final TreeLabelProvider tlp
) {
617 fLabelProvider
= tlp
;
621 * Sets the relative weight of each part of the time graph combo.
622 * This should be called from the constructor.
625 * The array (length 2) of relative weights of each part of the combo
627 protected void setWeight(final int[] weights
) {
632 * Sets the filter column labels.
633 * This should be called from the constructor.
635 * @param filterColumns
636 * The array of filter column labels
638 protected void setFilterColumns(final String
[] filterColumns
) {
639 fFilterColumns
= filterColumns
;
643 * Sets the filter label provider.
644 * This should be called from the constructor.
646 * @param labelProvider
647 * The filter label provider
649 protected void setFilterLabelProvider(final TreeLabelProvider labelProvider
) {
650 fFilterLabelProvider
= labelProvider
;
654 * Gets the display width
656 * @return the display width
658 protected int getDisplayWidth() {
659 return fDisplayWidth
;
663 * Gets the comparator for the entries
665 * @return The entry comparator
667 protected Comparator
<ITimeGraphEntry
> getEntryComparator() {
668 return fEntryComparator
;
672 * Sets the comparator class for the entries
675 * A comparator object
677 protected void setEntryComparator(final Comparator
<ITimeGraphEntry
> comparator
) {
678 fEntryComparator
= comparator
;
682 * Gets the trace displayed in the view
686 protected ITmfTrace
getTrace() {
691 * Gets the start time
693 * @return The start time
695 protected long getStartTime() {
700 * Sets the start time
705 protected void setStartTime(long time
) {
712 * @return The end time
714 protected long getEndTime() {
724 protected void setEndTime(long time
) {
729 * Sets the auto-expand level to be used for the input of the view. The
730 * value 0 means that there is no auto-expand; 1 means that top-level
731 * elements are expanded, but not their children; 2 means that top-level
732 * elements are expanded, and their children, but not grand-children; and so
735 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
739 * non-negative level, or <code>ALL_LEVELS</code> to expand all
742 protected void setAutoExpandLevel(int level
) {
743 fAutoExpandLevel
= level
;
744 ITimeGraphWrapper tgWrapper
= fTimeGraphWrapper
;
745 if (tgWrapper
!= null) {
746 tgWrapper
.setAutoExpandLevel(level
);
751 * Gets the entry list for a trace
756 * @return the entry list map
758 protected List
<TimeGraphEntry
> getEntryList(ITmfTrace trace
) {
759 synchronized (fEntryListMap
) {
760 return fEntryListMap
.get(trace
);
765 * Adds a trace entry list to the entry list map
770 * the list of time graph entries
772 protected void putEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
773 synchronized (fEntryListMap
) {
774 fEntryListMap
.put(trace
, new CopyOnWriteArrayList
<>(list
));
779 * Adds a list of entries to a trace's entry list
784 * the list of time graph entries to add
786 protected void addToEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
787 synchronized (fEntryListMap
) {
788 List
<TimeGraphEntry
> entryList
= fEntryListMap
.get(trace
);
789 if (entryList
== null) {
790 fEntryListMap
.put(trace
, new CopyOnWriteArrayList
<>(list
));
792 entryList
.addAll(list
);
798 * Removes a list of entries from a trace's entry list
803 * the list of time graph entries to remove
805 protected void removeFromEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
806 synchronized (fEntryListMap
) {
807 List
<TimeGraphEntry
> entryList
= fEntryListMap
.get(trace
);
808 if (entryList
!= null) {
809 entryList
.removeAll(list
);
815 * Text for the "next" button
817 * @return The "next" button text
819 protected String
getNextText() {
820 return Messages
.AbstractTimeGraphtView_NextText
;
824 * Tooltip for the "next" button
826 * @return Tooltip for the "next" button
828 protected String
getNextTooltip() {
829 return Messages
.AbstractTimeGraphView_NextTooltip
;
833 * Text for the "Previous" button
835 * @return The "Previous" button text
837 protected String
getPrevText() {
838 return Messages
.AbstractTimeGraphView_PreviousText
;
842 * Tooltip for the "previous" button
844 * @return Tooltip for the "previous" button
846 protected String
getPrevTooltip() {
847 return Messages
.AbstractTimeGraphView_PreviousTooltip
;
850 // ------------------------------------------------------------------------
852 // ------------------------------------------------------------------------
855 public void createPartControl(Composite parent
) {
856 if (fColumns
== null || fLabelProvider
== null) {
857 fTimeGraphWrapper
= new TimeGraphViewerWrapper(parent
, SWT
.NONE
);
858 TimeGraphViewer viewer
= fTimeGraphWrapper
.getTimeGraphViewer();
859 viewer
.setTimeGraphContentProvider(new TimeGraphContentProvider());
861 TimeGraphComboWrapper wrapper
= new TimeGraphComboWrapper(parent
, SWT
.NONE
);
862 fTimeGraphWrapper
= wrapper
;
863 TimeGraphCombo combo
= wrapper
.getTimeGraphCombo();
864 combo
.setTreeContentProvider(new TreeContentProvider());
865 combo
.setTreeLabelProvider(fLabelProvider
);
866 combo
.setTreeColumns(fColumns
);
867 combo
.setFilterContentProvider(new TreeContentProvider());
868 combo
.setFilterLabelProvider(fFilterLabelProvider
);
869 combo
.setFilterColumns(fFilterColumns
);
870 combo
.setTimeGraphContentProvider(new TimeGraphContentProvider());
873 fTimeGraphWrapper
.setTimeGraphProvider(fPresentation
);
874 fTimeGraphWrapper
.setAutoExpandLevel(fAutoExpandLevel
);
876 fTimeGraphWrapper
.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
878 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event
) {
879 final long startTime
= event
.getStartTime();
880 final long endTime
= event
.getEndTime();
881 TmfTimeRange range
= new TmfTimeRange(new TmfNanoTimestamp(startTime
), new TmfNanoTimestamp(endTime
));
882 broadcast(new TmfRangeSynchSignal(AbstractTimeGraphView
.this, range
));
883 startZoomThread(startTime
, endTime
);
887 fTimeGraphWrapper
.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
889 public void timeSelected(TimeGraphTimeEvent event
) {
890 TmfNanoTimestamp startTime
= new TmfNanoTimestamp(event
.getBeginTime());
891 TmfNanoTimestamp endTime
= new TmfNanoTimestamp(event
.getEndTime());
892 broadcast(new TmfTimeSynchSignal(AbstractTimeGraphView
.this, startTime
, endTime
));
896 fTimeGraphWrapper
.getTimeGraphViewer().setTimeFormat(TimeFormat
.CALENDAR
);
898 IStatusLineManager statusLineManager
= getViewSite().getActionBars().getStatusLineManager();
899 fTimeGraphWrapper
.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager
);
901 // View Action Handling
903 contributeToActionBars();
905 ITmfTrace trace
= TmfTraceManager
.getInstance().getActiveTrace();
907 traceSelected(new TmfTraceSelectedSignal(this, trace
));
910 // make selection available to other views
911 getSite().setSelectionProvider(fTimeGraphWrapper
.getSelectionProvider());
915 public void setFocus() {
916 fTimeGraphWrapper
.setFocus();
919 // ------------------------------------------------------------------------
921 // ------------------------------------------------------------------------
924 * Handler for the trace opened signal.
927 * The incoming signal
930 public void traceOpened(TmfTraceOpenedSignal signal
) {
931 fTrace
= signal
.getTrace();
936 * Handler for the trace selected signal
939 * The incoming signal
942 public void traceSelected(final TmfTraceSelectedSignal signal
) {
943 if (signal
.getTrace() == fTrace
) {
946 fTrace
= signal
.getTrace();
952 * Trace is closed: clear the data structures and the view
955 * the signal received
958 public void traceClosed(final TmfTraceClosedSignal signal
) {
959 synchronized (fBuildThreadMap
) {
960 for (ITmfTrace trace
: getTracesToBuild(signal
.getTrace())) {
961 BuildThread buildThread
= fBuildThreadMap
.remove(trace
);
962 if (buildThread
!= null) {
963 buildThread
.cancel();
967 synchronized (fEntryListMap
) {
968 fEntryListMap
.remove(signal
.getTrace());
970 if (signal
.getTrace() == fTrace
) {
974 if (fZoomThread
!= null) {
975 fZoomThread
.cancel();
982 * Handler for the time synch signal
985 * The signal that's received
988 public void synchToTime(final TmfTimeSynchSignal signal
) {
989 if (signal
.getSource() == this || fTrace
== null) {
992 final long beginTime
= signal
.getBeginTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
993 final long endTime
= signal
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
995 Display
.getDefault().asyncExec(new Runnable() {
998 if (fTimeGraphWrapper
.isDisposed()) {
1001 if (beginTime
== endTime
) {
1002 fTimeGraphWrapper
.getTimeGraphViewer().setSelectedTime(beginTime
, true);
1004 fTimeGraphWrapper
.getTimeGraphViewer().setSelectionRange(beginTime
, endTime
);
1006 startZoomThread(fTimeGraphWrapper
.getTimeGraphViewer().getTime0(), fTimeGraphWrapper
.getTimeGraphViewer().getTime1());
1008 synchingToTime(beginTime
);
1014 * Handler for the range synch signal
1017 * The signal that's received
1020 public void synchToRange(final TmfRangeSynchSignal signal
) {
1021 if (signal
.getSource() == this || fTrace
== null) {
1024 if (signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange()) == null) {
1027 final long startTime
= signal
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1028 final long endTime
= signal
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1029 Display
.getDefault().asyncExec(new Runnable() {
1032 if (fTimeGraphWrapper
.isDisposed()) {
1035 fTimeGraphWrapper
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
1036 startZoomThread(startTime
, endTime
);
1042 * @param signal the format of the timestamps was updated.
1045 public void updateTimeFormat( final TmfTimestampFormatUpdateSignal signal
){
1046 fTimeGraphWrapper
.refresh();
1049 // ------------------------------------------------------------------------
1051 // ------------------------------------------------------------------------
1053 private void loadTrace() {
1054 synchronized (fEntryListMap
) {
1055 fEntryList
= fEntryListMap
.get(fTrace
);
1056 if (fEntryList
== null) {
1059 fStartTime
= fTrace
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1060 fEndTime
= fTrace
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1067 * Forces a rebuild of the entries list, even if entries already exist for this trace
1069 protected void rebuild() {
1070 setStartTime(Long
.MAX_VALUE
);
1071 setEndTime(Long
.MIN_VALUE
);
1073 ITmfTrace viewTrace
= fTrace
;
1074 if (viewTrace
== null) {
1077 synchronized (fBuildThreadMap
) {
1078 for (ITmfTrace trace
: getTracesToBuild(viewTrace
)) {
1079 if (trace
== null) {
1082 BuildThread buildThread
= new BuildThread(trace
, viewTrace
, getName());
1083 fBuildThreadMap
.put(trace
, buildThread
);
1084 buildThread
.start();
1090 * Method called when synching to a given timestamp. Inheriting classes can
1091 * perform actions here to update the view at the given timestamp.
1094 * The currently selected time
1096 protected void synchingToTime(long time
) {
1101 * Return the list of traces whose data or analysis results will be used to
1102 * populate the view. By default, if the trace is an experiment, the traces
1103 * under it will be returned, otherwise, the trace itself is returned.
1105 * A build thread will be started for each trace returned by this method,
1106 * some of which may receive events in live streaming mode.
1109 * The trace associated with this view
1110 * @return List of traces with data to display
1112 protected @NonNull Iterable
<ITmfTrace
> getTracesToBuild(@NonNull ITmfTrace trace
) {
1113 return TmfTraceManager
.getTraceSet(trace
);
1117 * Build the entries list to show in this time graph
1119 * Called from the BuildThread
1122 * The trace being built
1123 * @param parentTrace
1124 * The parent of the trace set, or the trace itself
1126 * The progress monitor object
1128 protected abstract void buildEventList(@NonNull ITmfTrace trace
, @NonNull ITmfTrace parentTrace
, @NonNull IProgressMonitor monitor
);
1131 * Gets the list of event for an entry in a given timerange
1134 * The entry to get events for
1136 * Start of the time range
1138 * End of the time range
1142 * The progress monitor object
1143 * @return The list of events for the entry
1145 protected abstract @Nullable List
<ITimeEvent
> getEventList(@NonNull TimeGraphEntry entry
,
1146 long startTime
, long endTime
, long resolution
,
1147 @NonNull IProgressMonitor monitor
);
1150 * Gets the list of links (displayed as arrows) for a trace in a given
1151 * timerange. Default implementation returns an empty list.
1154 * Start of the time range
1156 * End of the time range
1160 * The progress monitor object
1161 * @return The list of link events
1163 protected @Nullable List
<ILinkEvent
> getLinkList(long startTime
, long endTime
,
1164 long resolution
, @NonNull IProgressMonitor monitor
) {
1165 return new ArrayList
<>();
1170 * Refresh the display
1172 protected void refresh() {
1173 TmfUiRefreshHandler
.getInstance().queueUpdate(this, new Runnable() {
1176 if (fTimeGraphWrapper
.isDisposed()) {
1179 boolean hasEntries
= false;
1180 synchronized (fEntryListMap
) {
1181 fEntryList
= fEntryListMap
.get(fTrace
);
1182 if (fEntryList
== null) {
1183 fEntryList
= new CopyOnWriteArrayList
<>();
1184 } else if (fEntryComparator
!= null) {
1185 List
<TimeGraphEntry
> list
= new ArrayList
<>(fEntryList
);
1186 Collections
.sort(list
, fEntryComparator
);
1188 fEntryList
.addAll(list
);
1190 hasEntries
= fEntryList
.size() != 0;
1192 if (fEntryList
!= fTimeGraphWrapper
.getInput()) {
1193 fTimeGraphWrapper
.setInput(fEntryList
);
1195 fTimeGraphWrapper
.refresh();
1197 fTimeGraphWrapper
.getTimeGraphViewer().setTimeBounds(fStartTime
, fEndTime
);
1199 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
1200 long selectionBeginTime
= fTrace
== null ?
0 : ctx
.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1201 long selectionEndTime
= fTrace
== null ?
0 : ctx
.getSelectionRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1202 long startTime
= fTrace
== null ?
0 : ctx
.getWindowRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1203 long endTime
= fTrace
== null ?
0 : ctx
.getWindowRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
1204 startTime
= Math
.max(startTime
, fStartTime
);
1205 endTime
= Math
.min(endTime
, fEndTime
);
1206 fTimeGraphWrapper
.getTimeGraphViewer().setSelectionRange(selectionBeginTime
, selectionEndTime
);
1207 fTimeGraphWrapper
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
1209 if (fTimeGraphWrapper
instanceof TimeGraphComboWrapper
&& !fPackDone
) {
1210 for (TreeColumn column
: ((TimeGraphComboWrapper
) fTimeGraphWrapper
).getTreeViewer().getTree().getColumns()) {
1218 startZoomThread(startTime
, endTime
);
1226 protected void redraw() {
1227 synchronized (fSyncObj
) {
1228 if (fRedrawState
== State
.IDLE
) {
1229 fRedrawState
= State
.BUSY
;
1231 fRedrawState
= State
.PENDING
;
1235 Display
.getDefault().asyncExec(new Runnable() {
1238 if (fTimeGraphWrapper
.isDisposed()) {
1241 fTimeGraphWrapper
.redraw();
1242 fTimeGraphWrapper
.update();
1243 synchronized (fSyncObj
) {
1244 if (fRedrawState
== State
.PENDING
) {
1245 fRedrawState
= State
.IDLE
;
1248 fRedrawState
= State
.IDLE
;
1255 private void startZoomThread(long startTime
, long endTime
) {
1256 if (fZoomThread
!= null) {
1257 fZoomThread
.cancel();
1259 final List
<TimeGraphEntry
> entryList
= fEntryList
;
1260 if (entryList
== null) {
1263 fZoomThread
= new ZoomThread(entryList
, startTime
, endTime
, getName());
1264 fZoomThread
.start();
1267 private void makeActions() {
1268 fPreviousResourceAction
= fTimeGraphWrapper
.getTimeGraphViewer().getPreviousItemAction();
1269 fPreviousResourceAction
.setText(getPrevText());
1270 fPreviousResourceAction
.setToolTipText(getPrevTooltip());
1271 fNextResourceAction
= fTimeGraphWrapper
.getTimeGraphViewer().getNextItemAction();
1272 fNextResourceAction
.setText(getNextText());
1273 fNextResourceAction
.setToolTipText(getNextTooltip());
1276 private void contributeToActionBars() {
1277 IActionBars bars
= getViewSite().getActionBars();
1278 fillLocalToolBar(bars
.getToolBarManager());
1282 * Add actions to local tool bar manager
1284 * @param manager the tool bar manager
1286 protected void fillLocalToolBar(IToolBarManager manager
) {
1287 if (fTimeGraphWrapper
instanceof TimeGraphComboWrapper
) {
1288 if (fFilterColumns
!= null && fFilterLabelProvider
!= null && fFilterColumns
.length
> 0) {
1289 manager
.add(((TimeGraphComboWrapper
) fTimeGraphWrapper
).getShowFilterAction());
1292 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getShowLegendAction());
1293 manager
.add(new Separator());
1294 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getResetScaleAction());
1295 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getPreviousEventAction());
1296 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getNextEventAction());
1297 manager
.add(fPreviousResourceAction
);
1298 manager
.add(fNextResourceAction
);
1299 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getZoomInAction());
1300 manager
.add(fTimeGraphWrapper
.getTimeGraphViewer().getZoomOutAction());
1301 manager
.add(new Separator());