1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 Ericsson
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 * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial API and implementation
11 * Alexandre Montplaisir - Port to ITmfStatistics provider
12 * Patrick Tasse - Support selection range
13 * Bernd Hufmann - Fix range selection updates
14 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.statistics
;
18 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
20 import java
.util
.Collection
;
21 import java
.util
.HashMap
;
22 import java
.util
.List
;
25 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
26 import org
.eclipse
.core
.runtime
.IStatus
;
27 import org
.eclipse
.core
.runtime
.Status
;
28 import org
.eclipse
.core
.runtime
.jobs
.Job
;
29 import org
.eclipse
.jface
.viewers
.TreeViewer
;
30 import org
.eclipse
.jface
.viewers
.TreeViewerColumn
;
31 import org
.eclipse
.jface
.viewers
.Viewer
;
32 import org
.eclipse
.jface
.viewers
.ViewerComparator
;
33 import org
.eclipse
.swt
.SWT
;
34 import org
.eclipse
.swt
.events
.SelectionAdapter
;
35 import org
.eclipse
.swt
.events
.SelectionEvent
;
36 import org
.eclipse
.swt
.graphics
.Color
;
37 import org
.eclipse
.swt
.graphics
.Cursor
;
38 import org
.eclipse
.swt
.widgets
.Composite
;
39 import org
.eclipse
.swt
.widgets
.Control
;
40 import org
.eclipse
.swt
.widgets
.Display
;
41 import org
.eclipse
.swt
.widgets
.Event
;
42 import org
.eclipse
.swt
.widgets
.Listener
;
43 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.component
.TmfComponent
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.request
.ITmfEventRequest
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTimeSynchSignal
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.statistics
.ITmfStatistics
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.statistics
.TmfStatisticsEventTypesModule
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.statistics
.TmfStatisticsModule
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceContext
;
56 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
57 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
58 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.experiment
.TmfExperiment
;
59 import org
.eclipse
.tracecompass
.tmf
.ui
.TmfUiRefreshHandler
;
60 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.TmfViewer
;
61 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.statistics
.model
.TmfBaseColumnData
;
62 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.statistics
.model
.TmfBaseColumnDataProvider
;
63 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.statistics
.model
.TmfStatisticsFormatter
;
64 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.statistics
.model
.TmfStatisticsTree
;
65 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.statistics
.model
.TmfStatisticsTreeManager
;
66 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.statistics
.model
.TmfStatisticsTreeNode
;
67 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.statistics
.model
.TmfTreeContentProvider
;
70 * A basic viewer to display statistics in the statistics view.
72 * It is linked to a single ITmfTrace until its disposal.
74 * @author Mathieu Denis
76 public class TmfStatisticsViewer
extends TmfViewer
{
78 /** Timestamp scale used for all statistics (nanosecond) */
79 private static final byte TIME_SCALE
= ITmfTimestamp
.NANOSECOND_SCALE
;
81 /** The delay (in ms) between each update in live-reading mode */
82 private static final long LIVE_UPDATE_DELAY
= 1000;
84 /** The actual tree viewer to display */
85 private TreeViewer fTreeViewer
;
87 /** The statistics tree linked to this viewer */
88 private TmfStatisticsTree fStatisticsData
;
90 /** Update range synchronization object */
91 private final Object fStatisticsRangeUpdateSyncObj
= new Object();
93 /** The trace that is displayed by this viewer */
94 private ITmfTrace fTrace
;
96 /** Indicates to process all events */
97 private boolean fProcessAll
;
99 /** View instance counter (for multiple statistics views) */
100 private static int fCountInstance
= 0;
102 /** Number of this instance. Used as an instance ID. */
103 private int fInstanceNb
;
105 /** Object to store the cursor while waiting for the trace to load */
106 private Cursor fWaitCursor
= null;
109 * Counts the number of times waitCursor() has been called. It avoids
110 * removing the waiting cursor, since there may be multiple requests running
113 private int fWaitCursorCount
= 0;
115 /** Tells to send a time range request when the trace gets updated. */
116 private boolean fSendRangeRequest
= true;
118 private final Map
<ITmfTrace
, Job
> fUpdateJobsPartial
= new HashMap
<>();
119 private final Map
<ITmfTrace
, Job
> fUpdateJobsGlobal
= new HashMap
<>();
121 private TmfTimeRange fTimeRange
;
123 private TmfTimeRange fTimeRangePartial
;
126 * Create a basic statistics viewer. To be used in conjunction with
127 * {@link TmfStatisticsViewer#init(Composite, String, ITmfTrace)}
130 * The parent composite that will hold the viewer
132 * The name that will be assigned to this viewer
134 * The trace that is displayed by this viewer
137 public TmfStatisticsViewer(Composite parent
, String viewerName
, ITmfTrace trace
) {
138 init(parent
, viewerName
, trace
);
142 * Initialize the statistics viewer.
145 * The parent component of the viewer.
147 * The name to give to the viewer.
149 * The trace that will be displayed by the viewer.
151 public void init(Composite parent
, String viewerName
, ITmfTrace trace
) {
152 super.init(parent
, viewerName
);
153 // Increment a counter to make sure the tree ID is unique.
155 fInstanceNb
= fCountInstance
;
158 // The viewer will process all events if he is assigned to an experiment
159 fProcessAll
= (trace
instanceof TmfExperiment
);
166 public void dispose() {
168 if (fWaitCursor
!= null) {
169 fWaitCursor
.dispose();
172 for (Job j
: fUpdateJobsGlobal
.values()) {
176 for (Job j
: fUpdateJobsPartial
.values()) {
180 // Clean the model for this viewer
181 TmfStatisticsTreeManager
.removeStatTreeRoot(getTreeID());
184 // ------------------------------------------------------------------------
186 // ------------------------------------------------------------------------
189 * Handles the signal about new trace range.
192 * The trace range updated signal
195 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal
) {
196 ITmfTrace trace
= signal
.getTrace();
198 if (!isListeningTo(trace
)) {
202 synchronized (fStatisticsRangeUpdateSyncObj
) {
203 // Sends the time range request only once from this method.
204 if (fSendRangeRequest
) {
205 fSendRangeRequest
= false;
207 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
208 TmfTimeRange timeRange
= ctx
.getSelectionRange();
209 requestTimeRangeData(trace
, timeRange
);
212 requestData(trace
, signal
.getRange());
216 * Handles the time synch updated signal. It updates the time range
220 * Contains the information about the new selected time range.
223 public void timeSynchUpdated(TmfTimeSynchSignal signal
) {
224 if (fTrace
== null) {
227 ITmfTimestamp begin
= signal
.getBeginTime();
228 ITmfTimestamp end
= signal
.getEndTime();
229 TmfTimeRange timeRange
= new TmfTimeRange(begin
, end
);
230 requestTimeRangeData(fTrace
, timeRange
);
233 // ------------------------------------------------------------------------
235 // ------------------------------------------------------------------------
238 * Returns the primary control associated with this viewer.
240 * @return the SWT control which displays this viewer's content
243 public Control
getControl() {
244 return fTreeViewer
.getControl();
248 * Get the input of the viewer.
250 * @return an object representing the input of the statistics viewer.
252 public Object
getInput() {
253 return fTreeViewer
.getInput();
257 * This method can be overridden to implement another way of representing
258 * the statistics data and to retrieve the information for display.
260 * @return a TmfStatisticsData object.
262 public TmfStatisticsTree
getStatisticData() {
263 if (fStatisticsData
== null) {
264 fStatisticsData
= new TmfStatisticsTree();
266 return fStatisticsData
;
270 * Returns a unique ID based on name to be associated with the statistics
271 * tree for this viewer. For a same name, it will always return the same ID.
273 * @return a unique statistics tree ID.
275 public String
getTreeID() {
276 return getName() + fInstanceNb
;
280 public void refresh() {
281 final Control viewerControl
= getControl();
282 // Ignore update if disposed
283 if (viewerControl
.isDisposed()) {
287 TmfUiRefreshHandler
.getInstance().queueUpdate(this, new Runnable() {
290 if (!viewerControl
.isDisposed()) {
291 fTreeViewer
.refresh();
298 * Will force a request on the partial event count if one is needed.
300 public void sendPartialRequestOnNextUpdate() {
301 synchronized (fStatisticsRangeUpdateSyncObj
) {
302 fSendRangeRequest
= true;
307 * Focus on the statistics tree of the viewer
309 public void setFocus() {
310 fTreeViewer
.getTree().setFocus();
314 * Cancels the request if it is not already completed
317 * The request to be canceled
319 protected void cancelOngoingRequest(ITmfEventRequest request
) {
320 if (request
!= null && !request
.isCompleted()) {
326 * This method can be overridden to change the representation of the data in
329 * @return An object of type {@link TmfBaseColumnDataProvider}.
331 protected TmfBaseColumnDataProvider
getColumnDataProvider() {
332 return new TmfBaseColumnDataProvider();
336 * Initialize the content that will be drawn in this viewer
339 * The parent of the control to create
341 protected void initContent(Composite parent
) {
342 final List
<TmfBaseColumnData
> columnDataList
= getColumnDataProvider().getColumnData();
344 fTreeViewer
= new TreeViewer(parent
, SWT
.BORDER
| SWT
.H_SCROLL
| SWT
.V_SCROLL
);
345 fTreeViewer
.setContentProvider(new TmfTreeContentProvider());
346 fTreeViewer
.getTree().setHeaderVisible(true);
347 fTreeViewer
.setUseHashlookup(true);
349 // Creates the columns defined by the column data provider
350 for (final TmfBaseColumnData columnData
: columnDataList
) {
351 final TreeViewerColumn treeColumn
= new TreeViewerColumn(fTreeViewer
, columnData
.getAlignment());
352 treeColumn
.getColumn().setText(columnData
.getHeader());
353 treeColumn
.getColumn().setWidth(columnData
.getWidth());
354 treeColumn
.getColumn().setToolTipText(columnData
.getTooltip());
356 // If is dummy column
357 if (columnData
== columnDataList
.get(TmfBaseColumnDataProvider
.StatsColumn
.DUMMY
.getIndex())) {
358 treeColumn
.getColumn().setResizable(false);
361 // A comparator is defined.
362 if (columnData
.getComparator() != null) {
363 // Adds a listener on the columns header for sorting purpose.
364 treeColumn
.getColumn().addSelectionListener(new SelectionAdapter() {
366 private ViewerComparator reverseComparator
;
369 public void widgetSelected(SelectionEvent e
) {
370 // Initializes the reverse comparator once.
371 if (reverseComparator
== null) {
372 reverseComparator
= new ViewerComparator() {
374 public int compare(Viewer viewer
, Object e1
, Object e2
) {
375 return -1 * columnData
.getComparator().compare(viewer
, e1
, e2
);
380 if (fTreeViewer
.getTree().getSortDirection() == SWT
.UP
381 || fTreeViewer
.getTree().getSortColumn() != treeColumn
.getColumn()) {
383 * Puts the descendant order if the old order was up
384 * or if the selected column has changed.
386 fTreeViewer
.setComparator(columnData
.getComparator());
387 fTreeViewer
.getTree().setSortDirection(SWT
.DOWN
);
390 * Puts the ascendant ordering if the selected
391 * column hasn't changed.
393 fTreeViewer
.setComparator(reverseComparator
);
394 fTreeViewer
.getTree().setSortDirection(SWT
.UP
);
396 fTreeViewer
.getTree().setSortColumn(treeColumn
.getColumn());
400 treeColumn
.setLabelProvider(columnData
.getLabelProvider());
403 // Handler that will draw the percentages and the bar charts.
404 fTreeViewer
.getTree().addListener(SWT
.EraseItem
, new Listener() {
406 public void handleEvent(Event event
) {
407 if (columnDataList
.get(event
.index
).getPercentageProvider() != null) {
409 TmfStatisticsTreeNode node
= (TmfStatisticsTreeNode
) event
.item
.getData();
411 // If node is hidden, exit immediately.
412 if (TmfBaseColumnDataProvider
.HIDDEN_FOLDER_LEVELS
.contains(node
.getName())) {
416 // Otherwise, get percentage and draw bar and text if applicable.
417 double percentage
= columnDataList
.get(event
.index
).getPercentageProvider().getPercentage(node
);
419 // The item is selected.
420 if ((event
.detail
& SWT
.SELECTED
) > 0) {
421 // Draws our own background to avoid overwriting the bar.
422 event
.gc
.fillRectangle(event
.x
, event
.y
, event
.width
, event
.height
);
423 event
.detail
&= ~SWT
.SELECTED
;
426 // Drawing the percentage text
427 // if events are present in top node
428 // and the current node is not the top node
429 // and if is total or partial events column.
430 // If not, exit the method.
431 if (!((event
.index
== TmfBaseColumnDataProvider
.StatsColumn
.TOTAL
.getIndex() || event
.index
== TmfBaseColumnDataProvider
.StatsColumn
.PARTIAL
.getIndex())
432 && node
!= node
.getTop())) {
436 long eventValue
= event
.index
== TmfBaseColumnDataProvider
.StatsColumn
.TOTAL
.getIndex() ?
437 node
.getTop().getValues().getTotal() : node
.getTop().getValues().getPartial();
439 if (eventValue
!= 0) {
441 int oldAlpha
= event
.gc
.getAlpha();
442 Color oldForeground
= event
.gc
.getForeground();
443 Color oldBackground
= event
.gc
.getBackground();
446 if (percentage
!= 0) {
448 * Draws a transparent gradient rectangle from the
449 * color of foreground and background.
451 int barWidth
= (int) ((fTreeViewer
.getTree().getColumn(event
.index
).getWidth() - 8) * percentage
);
452 event
.gc
.setAlpha(64);
453 event
.gc
.setForeground(event
.item
.getDisplay().getSystemColor(SWT
.COLOR_BLUE
));
454 event
.gc
.setBackground(event
.item
.getDisplay().getSystemColor(SWT
.COLOR_LIST_BACKGROUND
));
455 event
.gc
.fillGradientRectangle(event
.x
, event
.y
, barWidth
, event
.height
, true);
456 event
.gc
.drawRectangle(event
.x
, event
.y
, barWidth
, event
.height
);
458 // Restore old values
459 event
.gc
.setBackground(oldBackground
);
460 event
.gc
.setAlpha(oldAlpha
);
461 event
.detail
&= ~SWT
.BACKGROUND
;
465 String percentageText
= TmfStatisticsFormatter
.toPercentageText(percentage
);
466 String absoluteNumberText
= TmfStatisticsFormatter
.toColumnData(node
, TmfBaseColumnDataProvider
.StatsColumn
.getColumn(event
.index
));
468 if (event
.width
> event
.gc
.stringExtent(percentageText
).x
+ event
.gc
.stringExtent(absoluteNumberText
).x
) {
469 int textHeight
= event
.gc
.stringExtent(percentageText
).y
;
470 event
.gc
.setForeground(event
.item
.getDisplay().getSystemColor(SWT
.COLOR_DARK_GRAY
));
471 event
.gc
.drawText(percentageText
, event
.x
, event
.y
+ (event
.height
- textHeight
) / 2, true);
474 // Restores old values
475 event
.gc
.setForeground(oldForeground
);
483 // Initializes the comparator parameters
484 fTreeViewer
.setComparator(columnDataList
.get(0).getComparator());
485 fTreeViewer
.getTree().setSortColumn(fTreeViewer
.getTree().getColumn(0));
486 fTreeViewer
.getTree().setSortDirection(SWT
.DOWN
);
490 * Initializes the input for the tree viewer.
492 protected void initInput() {
493 String treeID
= getTreeID();
494 TmfStatisticsTreeNode statisticsTreeNode
;
495 if (TmfStatisticsTreeManager
.containsTreeRoot(treeID
)) {
496 // The statistics root is already present
497 statisticsTreeNode
= TmfStatisticsTreeManager
.getStatTreeRoot(treeID
);
499 // Checks if the trace is already in the statistics tree.
500 int numNodeTraces
= statisticsTreeNode
.getNbChildren();
502 Collection
<ITmfTrace
> traces
= TmfTraceManager
.getTraceSet(fTrace
);
503 int numTraces
= traces
.size();
505 if (numTraces
== numNodeTraces
) {
508 * Checks if the experiment contains the same traces as when
509 * previously selected.
511 for (ITmfTrace trace
: traces
) {
512 String traceName
= trace
.getName();
513 if (!statisticsTreeNode
.containsChild(traceName
)) {
520 // No need to reload data, all traces are already loaded
521 fTreeViewer
.setInput(statisticsTreeNode
);
524 // Clears the old content to start over
525 statisticsTreeNode
.reset();
528 // Creates a new tree
529 statisticsTreeNode
= TmfStatisticsTreeManager
.addStatsTreeRoot(treeID
, getStatisticData());
532 // Sets the input to a clean data model
533 fTreeViewer
.setInput(statisticsTreeNode
);
537 * Tells if the viewer is listening to a trace.
540 * The trace that the viewer may be listening
541 * @return true if the viewer is listening to the trace, false otherwise
543 protected boolean isListeningTo(ITmfTrace trace
) {
544 if (fProcessAll
|| trace
== fTrace
) {
551 * Called when an trace request has been completed successfully.
554 * Tells if the request is a global or time range (partial)
557 protected void modelComplete(boolean global
) {
563 * Called when an trace request has failed or has been cancelled.
565 * @param isGlobalRequest
566 * Tells if the request is a global or time range (partial)
569 protected void modelIncomplete(boolean isGlobalRequest
) {
570 if (isGlobalRequest
) { // Clean the global statistics
572 * No need to reset the global number of events, since the index of
573 * the last requested event is known.
575 } else { // Clean the partial statistics
576 resetTimeRangeValue();
583 * Sends the request to the trace for the whole trace
586 * The trace used to send the request
588 * The range to request to the trace
590 protected void requestData(final ITmfTrace trace
, final TmfTimeRange timeRange
) {
591 buildStatisticsTree(trace
, timeRange
, true);
595 * Sends the time range request from the trace
598 * The trace used to send the request
600 * The range to request to the trace
602 protected void requestTimeRangeData(final ITmfTrace trace
, final TmfTimeRange timeRange
) {
603 buildStatisticsTree(trace
, timeRange
, false);
607 * Requests all the data of the trace to the state system which contains
608 * information about the statistics.
610 * Since the viewer may be listening to multiple traces, it may receive an
611 * experiment rather than a single trace. The filtering is done with the
612 * method {@link #isListeningTo(String trace)}.
615 * The trace for which a request must be done
617 * The time range that will be requested to the state system
619 * Tells if the request is for the global event count or the
622 private void buildStatisticsTree(final ITmfTrace trace
, final TmfTimeRange timeRange
, final boolean isGlobal
) {
623 final TmfStatisticsTree statsData
= TmfStatisticsTreeManager
.getStatTree(getTreeID());
624 if (statsData
== null) {
628 Map
<ITmfTrace
, Job
> updateJobs
;
630 updateJobs
= fUpdateJobsGlobal
;
631 fTimeRange
= timeRange
;
633 updateJobs
= fUpdateJobsPartial
;
634 fTimeRangePartial
= timeRange
;
637 for (ITmfTrace aTrace
: TmfTraceManager
.getTraceSet(trace
)) {
638 aTrace
= checkNotNull(aTrace
);
639 if (!isListeningTo(aTrace
)) {
643 /* Retrieve the statistics object */
644 final TmfStatisticsModule statsMod
= TmfTraceUtils
.getAnalysisModuleOfClass(aTrace
, TmfStatisticsModule
.class, TmfStatisticsModule
.ID
);
645 if (statsMod
== null) {
646 /* No statistics module available for this trace */
650 Job job
= updateJobs
.get(aTrace
);
652 job
= new UpdateJob("Statistics update", aTrace
, isGlobal
, statsMod
); //$NON-NLS-1$
653 updateJobs
.put(aTrace
, job
);
660 private class UpdateJob
extends Job
{
662 private final ITmfTrace fJobTrace
;
663 private final boolean fIsGlobal
;
664 private final TmfStatisticsModule fStatsMod
;
666 private UpdateJob(String name
, ITmfTrace trace
, boolean isGlobal
, TmfStatisticsModule statsMod
) {
669 fIsGlobal
= isGlobal
;
670 fStatsMod
= statsMod
;
674 protected IStatus
run(IProgressMonitor monitor
) {
676 /* Wait until the analysis is ready to be queried */
677 fStatsMod
.waitForInitialization();
678 ITmfStatistics stats
= fStatsMod
.getStatistics();
680 /* It should have worked, but didn't */
681 throw new IllegalStateException();
685 * TODO Eventually this could be exposed through the
686 * TmfStateSystemAnalysisModule directly.
688 ITmfStateSystem ss
= fStatsMod
.getStateSystem(TmfStatisticsEventTypesModule
.ID
);
690 /* It should be instantiated after the
691 * statsMod.waitForInitialization() above. */
692 throw new IllegalStateException();
697 * Periodically update the statistics while they are
698 * being built (or, if the back-end is already completely
699 * built, it will skip over the while() immediately.
703 boolean finished
= false;
705 if (monitor
.isCanceled()) {
706 return Status
.CANCEL_STATUS
;
708 finished
= ss
.waitUntilBuilt(LIVE_UPDATE_DELAY
);
710 TmfTimeRange localtimeRange
= fIsGlobal ? fTimeRange
: fTimeRangePartial
;
712 * The generic statistics are stored in nanoseconds, so
713 * we must make sure the time range is scaled correctly.
715 start
= localtimeRange
.getStartTime().normalize(0, TIME_SCALE
).getValue();
716 end
= localtimeRange
.getEndTime().normalize(0, TIME_SCALE
).getValue();
718 Map
<String
, Long
> map
= stats
.getEventTypesInRange(start
, end
);
722 /* Query one last time for the final values */
723 Map
<String
, Long
> map
= stats
.getEventTypesInRange(start
, end
);
727 * Remove job from map so that new range selection updates can
730 Map
<ITmfTrace
, Job
> updateJobs
;
732 updateJobs
= fUpdateJobsGlobal
;
734 updateJobs
= fUpdateJobsPartial
;
736 updateJobs
.remove(fJobTrace
);
737 return Status
.OK_STATUS
;
741 * Update statistics for a given trace
743 private void updateStats(Map
<String
, Long
> eventsPerType
) {
745 final TmfStatisticsTree statsData
= TmfStatisticsTreeManager
.getStatTree(getTreeID());
746 if (statsData
== null) {
747 /* The stat tree has been disposed, abort mission. */
751 Map
<String
, Long
> map
= eventsPerType
;
752 String name
= fJobTrace
.getName();
756 * "Global", "partial", "total", etc., it's all very confusing...
758 * The base view shows the total count for the trace and for
759 * each even types, organized in columns like this:
761 * | Global | Time range |
762 * trace name | A | B |
764 * <event 1> | C | D |
765 * <event 2> | ... | ... |
768 * Here, we called the cells like this:
771 * C : GlobalTypeCount(s)
772 * D : TimeRangeTypeCount(s)
775 /* Fill in an the event counts (either cells C or D) */
776 for (Map
.Entry
<String
, Long
> entry
: map
.entrySet()) {
777 statsData
.setTypeCount(name
, entry
.getKey(), fIsGlobal
, entry
.getValue());
781 * Calculate the totals (cell A or B, depending if isGlobal). We will
782 * use the results of the previous request instead of sending another
785 long globalTotal
= 0;
786 for (long val
: map
.values()) {
789 statsData
.setTotal(name
, fIsGlobal
, globalTotal
);
791 modelComplete(fIsGlobal
);
796 * Resets the number of events within the time range
798 protected void resetTimeRangeValue() {
799 TmfStatisticsTreeNode treeModelRoot
= TmfStatisticsTreeManager
.getStatTreeRoot(getTreeID());
800 if (treeModelRoot
!= null && treeModelRoot
.hasChildren()) {
801 treeModelRoot
.resetTimeRangeValue();
806 * When the trace is loading the cursor will be different so the user knows
807 * that the processing is not finished yet.
809 * Calls to this method are stacked.
811 * @param waitRequested
812 * Indicates if we need to show the waiting cursor, or the
815 protected void waitCursor(final boolean waitRequested
) {
816 if ((fTreeViewer
== null) || (fTreeViewer
.getTree().isDisposed())) {
820 boolean needsUpdate
= false;
821 Display display
= fTreeViewer
.getControl().getDisplay();
824 if (fWaitCursor
== null) { // The cursor hasn't been initialized yet
825 fWaitCursor
= new Cursor(display
, SWT
.CURSOR_WAIT
);
827 if (fWaitCursorCount
== 1) { // The cursor is not in waiting mode
831 if (fWaitCursorCount
> 0) { // The cursor is in waiting mode
833 if (fWaitCursorCount
== 0) { // No more reason to wait
834 // Put back the default cursor
841 // Performs the updates on the UI thread
842 display
.asyncExec(new Runnable() {
845 if ((fTreeViewer
!= null)
846 && (!fTreeViewer
.getTree().isDisposed())) {
847 Cursor cursor
= null; // indicates default
849 cursor
= fWaitCursor
;
851 fTreeViewer
.getControl().setCursor(cursor
);