tmf: Move the trace statistics to the analysis framework
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / viewers / statistics / TmfStatisticsViewer.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson
3 *
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
8 *
9 * Contributors:
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 *******************************************************************************/
14
15 package org.eclipse.linuxtools.tmf.ui.viewers.statistics;
16
17 import java.util.List;
18 import java.util.Map;
19
20 import org.eclipse.jface.viewers.TreeViewer;
21 import org.eclipse.jface.viewers.TreeViewerColumn;
22 import org.eclipse.jface.viewers.Viewer;
23 import org.eclipse.jface.viewers.ViewerComparator;
24 import org.eclipse.linuxtools.tmf.core.component.TmfComponent;
25 import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
26 import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
27 import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
28 import org.eclipse.linuxtools.tmf.core.signal.TmfStatsUpdatedSignal;
29 import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
30 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceRangeUpdatedSignal;
31 import org.eclipse.linuxtools.tmf.core.statistics.ITmfStatistics;
32 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
33 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
34 import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
35 import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
36 import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
37 import org.eclipse.linuxtools.tmf.ui.viewers.TmfViewer;
38 import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.ITmfColumnDataProvider;
39 import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfBaseColumnData;
40 import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfBaseColumnDataProvider;
41 import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfStatisticsTree;
42 import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfStatisticsTreeManager;
43 import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfStatisticsTreeNode;
44 import org.eclipse.linuxtools.tmf.ui.viewers.statistics.model.TmfTreeContentProvider;
45 import org.eclipse.linuxtools.tmf.ui.views.statistics.TmfStatisticsModule;
46 import org.eclipse.swt.SWT;
47 import org.eclipse.swt.events.SelectionAdapter;
48 import org.eclipse.swt.events.SelectionEvent;
49 import org.eclipse.swt.graphics.Color;
50 import org.eclipse.swt.graphics.Cursor;
51 import org.eclipse.swt.widgets.Composite;
52 import org.eclipse.swt.widgets.Control;
53 import org.eclipse.swt.widgets.Display;
54 import org.eclipse.swt.widgets.Event;
55 import org.eclipse.swt.widgets.Listener;
56
57 /**
58 * A basic viewer to display statistics in the statistics view.
59 *
60 * It is linked to a single ITmfTrace until its disposal.
61 *
62 * @author Mathieu Denis
63 * @version 2.0
64 * @since 2.0
65 */
66 public class TmfStatisticsViewer extends TmfViewer {
67
68 /**
69 * Timestamp scale (nanosecond)
70 */
71 public static final byte TIME_SCALE = ITmfTimestamp.NANOSECOND_SCALE;
72
73 /**
74 * Default PAGE_SIZE for background requests.
75 */
76 protected static final int PAGE_SIZE = 50000;
77
78 /**
79 * Refresh frequency.
80 */
81 protected final Long STATS_INPUT_CHANGED_REFRESH = 5000L;
82
83 /**
84 * The actual tree viewer to display
85 */
86 protected TreeViewer fTreeViewer;
87
88 /**
89 * The statistics tree linked to this viewer
90 */
91 protected TmfStatisticsTree fStatisticsData;
92
93 /**
94 * Update synchronization parameter (used for streaming): Update busy
95 * indicator.
96 */
97 protected boolean fStatisticsUpdateBusy = false;
98
99 /**
100 * Update synchronization parameter (used for streaming): Update pending
101 * indicator.
102 */
103 protected boolean fStatisticsUpdatePending = false;
104
105 /**
106 * Update synchronization parameter (used for streaming): Pending Update
107 * time range.
108 */
109 protected TmfTimeRange fStatisticsUpdateRange = null;
110
111 /**
112 * Update synchronization object.
113 */
114 protected final Object fStatisticsUpdateSyncObj = new Object();
115
116 /**
117 * Update range synchronization object.
118 */
119 protected final Object fStatisticsRangeUpdateSyncObj = new Object();
120
121 /**
122 * The trace that is displayed by this viewer
123 */
124 protected ITmfTrace fTrace;
125
126 /**
127 * Stores the requested time range.
128 */
129 protected TmfTimeRange fRequestedTimerange;
130
131 /**
132 * Indicates to process all events
133 */
134 private boolean fProcessAll;
135
136 /**
137 * View instance counter (for multiple statistics views)
138 */
139 private static int fCountInstance = 0;
140
141 /**
142 * Number of this instance. Used as an instance ID.
143 */
144 private int fInstanceNb;
145
146 /**
147 * Object to store the cursor while waiting for the trace to load
148 */
149 private Cursor fWaitCursor = null;
150
151 /**
152 * Counts the number of times waitCursor() has been called. It avoids
153 * removing the waiting cursor, since there may be multiple requests running
154 * at the same time.
155 */
156 private int fWaitCursorCount = 0;
157
158 /**
159 * Tells to send a time range request when the trace gets updated.
160 */
161 private boolean fSendRangeRequest = true;
162
163 /** Reference to the trace manager */
164 private final TmfTraceManager fTraceManager;
165
166 /**
167 * Empty constructor. To be used in conjunction with
168 * {@link TmfStatisticsViewer#init(Composite, String, ITmfTrace)}
169 */
170 public TmfStatisticsViewer() {
171 super();
172 fTraceManager = TmfTraceManager.getInstance();
173 }
174
175 /**
176 * Create a basic statistics viewer. To be used in conjunction with
177 * {@link TmfStatisticsViewer#init(Composite, String, ITmfTrace)}
178 *
179 * @param parent
180 * The parent composite that will hold the viewer
181 * @param viewerName
182 * The name that will be assigned to this viewer
183 * @param trace
184 * The trace that is displayed by this viewer
185 * @see TmfComponent
186 */
187 public TmfStatisticsViewer(Composite parent, String viewerName, ITmfTrace trace) {
188 init(parent, viewerName, trace);
189 fTraceManager = TmfTraceManager.getInstance();
190 }
191
192 /**
193 * Initialize the statistics viewer.
194 *
195 * @param parent
196 * The parent component of the viewer.
197 * @param viewerName
198 * The name to give to the viewer.
199 * @param trace
200 * The trace that will be displayed by the viewer.
201 */
202 public void init(Composite parent, String viewerName, ITmfTrace trace) {
203 super.init(parent, viewerName);
204 // Increment a counter to make sure the tree ID is unique.
205 fCountInstance++;
206 fInstanceNb = fCountInstance;
207 fTrace = trace;
208
209 // The viewer will process all events if he is assigned to an experiment
210 fProcessAll = (trace instanceof TmfExperiment);
211
212 initContent(parent);
213 initInput();
214 }
215
216 @Override
217 public void dispose() {
218 super.dispose();
219 if (fWaitCursor != null) {
220 fWaitCursor.dispose();
221 }
222
223 // Clean the model for this viewer
224 TmfStatisticsTreeManager.removeStatTreeRoot(getTreeID());
225 }
226
227 // ------------------------------------------------------------------------
228 // Signal handlers
229 // ------------------------------------------------------------------------
230
231 /**
232 * Handles the signal about new trace range.
233 *
234 * @param signal
235 * The trace range updated signal
236 */
237 @TmfSignalHandler
238 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal) {
239 ITmfTrace trace = signal.getTrace();
240 // validate
241 if (!isListeningTo(trace)) {
242 return;
243 }
244
245 synchronized (fStatisticsRangeUpdateSyncObj) {
246 // Sends the time range request only once from this method.
247 if (fSendRangeRequest) {
248 fSendRangeRequest = false;
249 ITmfTimestamp begin = fTraceManager.getSelectionBeginTime();
250 ITmfTimestamp end = fTraceManager.getSelectionEndTime();
251 TmfTimeRange timeRange = new TmfTimeRange(begin, end);
252 requestTimeRangeData(trace, timeRange);
253 }
254 }
255 requestData(trace, signal.getRange());
256 }
257
258 /**
259 * Handles the time range updated signal. It updates the time range
260 * statistics.
261 *
262 * @param signal
263 * Contains the information about the new selected time range.
264 * @deprecated
265 * As of 2.1, use {@link #timeSynchUpdated(TmfTimeSynchSignal)}
266 */
267 @Deprecated
268 @TmfSignalHandler
269 public void timeRangeUpdated(TmfRangeSynchSignal signal) {
270 }
271
272 /**
273 * Handles the time synch updated signal. It updates the time range
274 * statistics.
275 *
276 * @param signal
277 * Contains the information about the new selected time range.
278 * @since 2.1
279 */
280 @TmfSignalHandler
281 public void timeSynchUpdated(TmfTimeSynchSignal signal) {
282 if (fTrace == null) {
283 return;
284 }
285 ITmfTimestamp begin = signal.getBeginTime();
286 ITmfTimestamp end = signal.getEndTime();
287 TmfTimeRange timeRange = new TmfTimeRange(begin, end);
288 requestTimeRangeData(fTrace, timeRange);
289 }
290
291 /**
292 * Whenever a trace's statistics back-end finishes computing the statistics
293 * for a given interval, it will send the StatsUpdated signal. This method
294 * will receive this signal and update the statistics view accordingly.
295 *
296 * @param sig
297 * The signal that is received
298 */
299 @TmfSignalHandler
300 public void statsUpdated(TmfStatsUpdatedSignal sig) {
301 /* Only handle this signal if it's about the trace we represent. */
302 if (!isListeningTo(sig.getTrace())) {
303 return;
304 }
305
306 final TmfStatisticsTree statsData = TmfStatisticsTreeManager.getStatTree(getTreeID());
307 Map<String, Long> map = sig.getEventsPerType();
308 String name = sig.getTrace().getName();
309 boolean isGlobal = sig.isGlobal();
310
311 /*
312 * "Global", "partial", "total", etc., it's all very confusing...
313 *
314 * The base view shows the total count for the trace and for
315 * each even types, organized in columns like this:
316 *
317 * | Global | Time range |
318 * trace name | A | B |
319 * Event Type | | |
320 * <event 1> | C | D |
321 * <event 2> | ... | ... |
322 * ... | | |
323 *
324 * Here, we called the cells like this:
325 * A : GlobalTotal
326 * B : TimeRangeTotal
327 * C : GlobalTypeCount(s)
328 * D : TimeRangeTypeCount(s)
329 */
330
331 /* Fill in an the event counts (either cells C or D) */
332 for (Map.Entry<String, Long> entry : map.entrySet()) {
333 statsData.setTypeCount(name, entry.getKey(), isGlobal, entry.getValue());
334 }
335
336 /*
337 * Calculate the totals (cell A or B, depending if isGlobal). We will
338 * use the results of the previous request instead of sending another
339 * one.
340 */
341 long globalTotal = 0;
342 for (long val : map.values()) {
343 globalTotal += val;
344 }
345 statsData.setTotal(name, isGlobal, globalTotal);
346
347 modelComplete(isGlobal);
348 }
349
350 // ------------------------------------------------------------------------
351 // Class methods
352 // ------------------------------------------------------------------------
353
354 /*
355 * Returns the primary control associated with this viewer.
356 *
357 * @return the SWT control which displays this viewer's content
358 */
359 @Override
360 public Control getControl() {
361 return fTreeViewer.getControl();
362 }
363
364 /**
365 * Get the input of the viewer.
366 *
367 * @return an object representing the input of the statistics viewer.
368 */
369 public Object getInput() {
370 return fTreeViewer.getInput();
371 }
372
373 /**
374 * Return the size of the request when performing background request.
375 *
376 * @return the block size for background request.
377 */
378 public int getPageSize() {
379 return PAGE_SIZE;
380 }
381
382 /**
383 * Return the number of events to receive before a refresh of the viewer is
384 * performed.
385 *
386 * @return the input refresh rate
387 */
388 public long getRefreshRate() {
389 return STATS_INPUT_CHANGED_REFRESH;
390 }
391
392 /**
393 * This method can be overridden to implement another way of representing
394 * the statistics data and to retrieve the information for display.
395 *
396 * @return a TmfStatisticsData object.
397 */
398 public TmfStatisticsTree getStatisticData() {
399 if (fStatisticsData == null) {
400 fStatisticsData = new TmfStatisticsTree();
401 }
402 return fStatisticsData;
403 }
404
405 /**
406 * Returns a unique ID based on name to be associated with the statistics
407 * tree for this viewer. For a same name, it will always return the same ID.
408 *
409 * @return a unique statistics tree ID.
410 */
411 public String getTreeID() {
412 return getName() + fInstanceNb;
413 }
414
415 @Override
416 public void refresh() {
417 final Control viewerControl = getControl();
418 // Ignore update if disposed
419 if (viewerControl.isDisposed()) {
420 return;
421 }
422
423 viewerControl.getDisplay().asyncExec(new Runnable() {
424 @Override
425 public void run() {
426 if (!viewerControl.isDisposed()) {
427 fTreeViewer.refresh();
428 }
429 }
430 });
431 }
432
433 /**
434 * Will force a request on the partial event count if one is needed.
435 */
436 public void sendPartialRequestOnNextUpdate() {
437 synchronized (fStatisticsRangeUpdateSyncObj) {
438 fSendRangeRequest = true;
439 }
440 }
441
442 /**
443 * Focus on the statistics tree of the viewer
444 */
445 public void setFocus() {
446 fTreeViewer.getTree().setFocus();
447 }
448
449 /**
450 * Cancels the request if it is not already completed
451 *
452 * @param request
453 * The request to be canceled
454 * @since 3.0
455 */
456 protected void cancelOngoingRequest(ITmfEventRequest request) {
457 if (request != null && !request.isCompleted()) {
458 request.cancel();
459 }
460 }
461
462 /**
463 * This method can be overridden to change the representation of the data in
464 * the columns.
465 *
466 * @return an object implementing ITmfBaseColumnDataProvider.
467 */
468 protected ITmfColumnDataProvider getColumnDataProvider() {
469 return new TmfBaseColumnDataProvider();
470 }
471
472 /**
473 * Initialize the content that will be drawn in this viewer
474 *
475 * @param parent
476 * The parent of the control to create
477 */
478 protected void initContent(Composite parent) {
479 final List<TmfBaseColumnData> columnDataList = getColumnDataProvider().getColumnData();
480
481 fTreeViewer = new TreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
482 fTreeViewer.setContentProvider(new TmfTreeContentProvider());
483 fTreeViewer.getTree().setHeaderVisible(true);
484 fTreeViewer.setUseHashlookup(true);
485
486 // Creates the columns defined by the column data provider
487 for (final TmfBaseColumnData columnData : columnDataList) {
488 final TreeViewerColumn treeColumn = new TreeViewerColumn(fTreeViewer, columnData.getAlignment());
489 treeColumn.getColumn().setText(columnData.getHeader());
490 treeColumn.getColumn().setWidth(columnData.getWidth());
491 treeColumn.getColumn().setToolTipText(columnData.getTooltip());
492
493 if (columnData.getComparator() != null) { // A comparator is defined.
494 // Adds a listener on the columns header for sorting purpose.
495 treeColumn.getColumn().addSelectionListener(new SelectionAdapter() {
496
497 private ViewerComparator reverseComparator;
498
499 @Override
500 public void widgetSelected(SelectionEvent e) {
501 // Initializes the reverse comparator once.
502 if (reverseComparator == null) {
503 reverseComparator = new ViewerComparator() {
504 @Override
505 public int compare(Viewer viewer, Object e1, Object e2) {
506 return -1 * columnData.getComparator().compare(viewer, e1, e2);
507 }
508 };
509 }
510
511 if (fTreeViewer.getTree().getSortDirection() == SWT.UP
512 || fTreeViewer.getTree().getSortColumn() != treeColumn.getColumn()) {
513 /*
514 * Puts the descendant order if the old order was
515 * up or if the selected column has changed.
516 */
517 fTreeViewer.setComparator(columnData.getComparator());
518 fTreeViewer.getTree().setSortDirection(SWT.DOWN);
519 } else {
520 /*
521 * Puts the ascendant ordering if the selected
522 * column hasn't changed.
523 */
524 fTreeViewer.setComparator(reverseComparator);
525 fTreeViewer.getTree().setSortDirection(SWT.UP);
526 }
527 fTreeViewer.getTree().setSortColumn(treeColumn.getColumn());
528 }
529 });
530 }
531 treeColumn.setLabelProvider(columnData.getLabelProvider());
532 }
533
534 // Handler that will draw the bar charts.
535 fTreeViewer.getTree().addListener(SWT.EraseItem, new Listener() {
536 @Override
537 public void handleEvent(Event event) {
538 if (columnDataList.get(event.index).getPercentageProvider() != null) {
539 TmfStatisticsTreeNode node = (TmfStatisticsTreeNode) event.item.getData();
540
541 double percentage = columnDataList.get(event.index).getPercentageProvider().getPercentage(node);
542 if (percentage == 0) { // No bar to draw
543 return;
544 }
545
546 if ((event.detail & SWT.SELECTED) > 0) { // The item is selected.
547 // Draws our own background to avoid overwritten the bar.
548 event.gc.fillRectangle(event.x, event.y, event.width, event.height);
549 event.detail &= ~SWT.SELECTED;
550 }
551
552 int barWidth = (int) ((fTreeViewer.getTree().getColumn(event.index).getWidth() - 8) * percentage);
553 int oldAlpha = event.gc.getAlpha();
554 Color oldForeground = event.gc.getForeground();
555 Color oldBackground = event.gc.getBackground();
556 /*
557 * Draws a transparent gradient rectangle from the color of
558 * foreground and background.
559 */
560 event.gc.setAlpha(64);
561 event.gc.setForeground(event.item.getDisplay().getSystemColor(SWT.COLOR_BLUE));
562 event.gc.setBackground(event.item.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
563 event.gc.fillGradientRectangle(event.x, event.y, barWidth, event.height, true);
564 event.gc.drawRectangle(event.x, event.y, barWidth, event.height);
565 // Restores old values
566 event.gc.setForeground(oldForeground);
567 event.gc.setBackground(oldBackground);
568 event.gc.setAlpha(oldAlpha);
569 event.detail &= ~SWT.BACKGROUND;
570 }
571 }
572 });
573
574 // Initializes the comparator parameters
575 fTreeViewer.setComparator(columnDataList.get(0).getComparator());
576 fTreeViewer.getTree().setSortColumn(fTreeViewer.getTree().getColumn(0));
577 fTreeViewer.getTree().setSortDirection(SWT.DOWN);
578 }
579
580 /**
581 * Initializes the input for the tree viewer.
582 */
583 protected void initInput() {
584 String treeID = getTreeID();
585 TmfStatisticsTreeNode statisticsTreeNode;
586 if (TmfStatisticsTreeManager.containsTreeRoot(treeID)) {
587 // The statistics root is already present
588 statisticsTreeNode = TmfStatisticsTreeManager.getStatTreeRoot(treeID);
589
590 // Checks if the trace is already in the statistics tree.
591 int numNodeTraces = statisticsTreeNode.getNbChildren();
592
593 ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
594 int numTraces = traces.length;
595
596 if (numTraces == numNodeTraces) {
597 boolean same = true;
598 /*
599 * Checks if the experiment contains the same traces as when
600 * previously selected.
601 */
602 for (int i = 0; i < numTraces; i++) {
603 String traceName = traces[i].getName();
604 if (!statisticsTreeNode.containsChild(traceName)) {
605 same = false;
606 break;
607 }
608 }
609
610 if (same) {
611 // No need to reload data, all traces are already loaded
612 fTreeViewer.setInput(statisticsTreeNode);
613 return;
614 }
615 // Clears the old content to start over
616 statisticsTreeNode.reset();
617 }
618 } else {
619 // Creates a new tree
620 statisticsTreeNode = TmfStatisticsTreeManager.addStatsTreeRoot(treeID, getStatisticData());
621 }
622
623 // Sets the input to a clean data model
624 fTreeViewer.setInput(statisticsTreeNode);
625 resetUpdateSynchronization();
626 }
627
628 /**
629 * Tells if the viewer is listening to a trace.
630 *
631 * @param trace
632 * The trace that the viewer may be listening
633 * @return true if the viewer is listening to the trace, false otherwise
634 */
635 protected boolean isListeningTo(ITmfTrace trace) {
636 if (fProcessAll || trace == fTrace) {
637 return true;
638 }
639 return false;
640 }
641
642 /**
643 * Called when an trace request has been completed successfully.
644 *
645 * @param global
646 * Tells if the request is a global or time range (partial)
647 * request.
648 */
649 protected void modelComplete(boolean global) {
650 refresh();
651 waitCursor(false);
652 if (global) {
653 sendPendingUpdate();
654 }
655 }
656
657 /**
658 * Called when an trace request has failed or has been cancelled.
659 *
660 * @param isGlobalRequest
661 * Tells if the request is a global or time range (partial)
662 * request.
663 */
664 protected void modelIncomplete(boolean isGlobalRequest) {
665 if (isGlobalRequest) { // Clean the global statistics
666 /*
667 * No need to reset the global number of events, since the index of
668 * the last requested event is known.
669 */
670 resetUpdateSynchronization();
671 sendPendingUpdate();
672 } else { // Clean the partial statistics
673 resetTimeRangeValue();
674 }
675 refresh();
676 waitCursor(false);
677 }
678
679 /**
680 * Sends the request to the trace for the whole trace
681 *
682 * @param trace
683 * The trace used to send the request
684 * @param timeRange
685 * The range to request to the trace
686 */
687 protected void requestData(final ITmfTrace trace, final TmfTimeRange timeRange) {
688 buildStatisticsTree(trace, timeRange, true);
689 }
690
691 /**
692 * Sends the time range request from the trace
693 *
694 * @param trace
695 * The trace used to send the request
696 * @param timeRange
697 * The range to request to the trace
698 */
699 protected void requestTimeRangeData(final ITmfTrace trace, final TmfTimeRange timeRange) {
700 fRequestedTimerange = timeRange;
701 buildStatisticsTree(trace, timeRange, false);
702 }
703
704 /**
705 * Requests all the data of the trace to the state system which
706 * contains information about the statistics.
707 *
708 * Since the viewer may be listening to multiple traces, it may receive
709 * an experiment rather than a single trace. The filtering is done with the
710 * method {@link #isListeningTo(String trace)}.
711 *
712 * @param trace
713 * The trace for which a request must be done
714 * @param timeRange
715 * The time range that will be requested to the state system
716 * @param isGlobal
717 * Tells if the request is for the global event count or the
718 * partial one.
719 */
720 private void buildStatisticsTree(final ITmfTrace trace, TmfTimeRange timeRange, boolean isGlobal) {
721 final TmfStatisticsTreeNode statTree = TmfStatisticsTreeManager.getStatTreeRoot(getTreeID());
722 final TmfStatisticsTree statsData = TmfStatisticsTreeManager.getStatTree(getTreeID());
723 if (statsData == null) {
724 return;
725 }
726
727 synchronized (statsData) {
728 if (isGlobal) {
729 statTree.resetGlobalValue();
730 } else {
731 statTree.resetTimeRangeValue();
732 }
733
734 for (final ITmfTrace aTrace : TmfTraceManager.getTraceSet(trace)) {
735 if (!isListeningTo(aTrace)) {
736 continue;
737 }
738
739 /* Retrieve the statistics object */
740 final TmfStatisticsModule statsMod = aTrace.getAnalysisModuleOfClass(TmfStatisticsModule.class, TmfStatisticsModule.ID);
741 if (statsMod == null) {
742 /* No statistics module available for this trace */
743 continue;
744 }
745 final ITmfStatistics stats = statsMod.getStatistics();
746 if (stats == null) {
747 /*
748 * The statistics provider for this trace is not accessible
749 * (yet?). Try the next one.
750 */
751 continue;
752 }
753
754 /* The generic statistics are stored in nanoseconds, so we must make
755 * sure the time range is scaled correctly. */
756 long start = timeRange.getStartTime().normalize(0, TIME_SCALE).getValue();
757 long end = timeRange.getEndTime().normalize(0, TIME_SCALE).getValue();
758
759 /*
760 * Send a request to update the statistics view. The result will
761 * be sent through a {@link TmfStatsUpdatedSignal}, and will be
762 * processed by the signal handler.
763 */
764 stats.updateStats(isGlobal, start, end);
765 }
766 }
767 }
768
769 /**
770 * Resets the number of events within the time range
771 */
772 protected void resetTimeRangeValue() {
773 TmfStatisticsTreeNode treeModelRoot = TmfStatisticsTreeManager.getStatTreeRoot(getTreeID());
774 if (treeModelRoot != null && treeModelRoot.hasChildren()) {
775 treeModelRoot.resetTimeRangeValue();
776 }
777 }
778
779 /**
780 * When the trace is loading the cursor will be different so the user
781 * knows that the processing is not finished yet.
782 *
783 * Calls to this method are stacked.
784 *
785 * @param waitRequested
786 * Indicates if we need to show the waiting cursor, or the
787 * default one.
788 */
789 protected void waitCursor(final boolean waitRequested) {
790 if ((fTreeViewer == null) || (fTreeViewer.getTree().isDisposed())) {
791 return;
792 }
793
794 boolean needsUpdate = false;
795 Display display = fTreeViewer.getControl().getDisplay();
796 if (waitRequested) {
797 fWaitCursorCount++;
798 if (fWaitCursor == null) { // The cursor hasn't been initialized yet
799 fWaitCursor = new Cursor(display, SWT.CURSOR_WAIT);
800 }
801 if (fWaitCursorCount == 1) { // The cursor is not in waiting mode
802 needsUpdate = true;
803 }
804 } else {
805 if (fWaitCursorCount > 0) { // The cursor is in waiting mode
806 fWaitCursorCount--;
807 if (fWaitCursorCount == 0) { // No more reason to wait
808 // Put back the default cursor
809 needsUpdate = true;
810 }
811 }
812 }
813
814 if (needsUpdate) {
815 // Performs the updates on the UI thread
816 display.asyncExec(new Runnable() {
817 @Override
818 public void run() {
819 if ((fTreeViewer != null)
820 && (!fTreeViewer.getTree().isDisposed())) {
821 Cursor cursor = null; // indicates default
822 if (waitRequested) {
823 cursor = fWaitCursor;
824 }
825 fTreeViewer.getControl().setCursor(cursor);
826 }
827 }
828 });
829 }
830 }
831
832 // ------------------------------------------------------------------------
833 // Methods reserved for the streaming functionality
834 // ------------------------------------------------------------------------
835
836 /**
837 * Resets update synchronization information
838 */
839 protected void resetUpdateSynchronization() {
840 synchronized (fStatisticsUpdateSyncObj) {
841 fStatisticsUpdateBusy = false;
842 fStatisticsUpdatePending = false;
843 fStatisticsUpdateRange = null;
844 }
845 }
846
847 /**
848 * Checks if statistics update is ongoing. If it is ongoing, the new time
849 * range is stored as pending
850 *
851 * @param timeRange
852 * - new time range
853 * @return true if statistic update is ongoing else false
854 */
855 protected boolean checkUpdateBusy(TmfTimeRange timeRange) {
856 synchronized (fStatisticsUpdateSyncObj) {
857 if (fStatisticsUpdateBusy) {
858 fStatisticsUpdatePending = true;
859 if (fStatisticsUpdateRange == null
860 || timeRange.getEndTime().compareTo(fStatisticsUpdateRange.getEndTime()) > 0) {
861 fStatisticsUpdateRange = timeRange;
862 }
863 return true;
864 }
865 fStatisticsUpdateBusy = true;
866 return false;
867 }
868 }
869
870 /**
871 * Sends pending request (if any)
872 */
873 protected void sendPendingUpdate() {
874 synchronized (fStatisticsUpdateSyncObj) {
875 fStatisticsUpdateBusy = false;
876 if (fStatisticsUpdatePending) {
877 fStatisticsUpdatePending = false;
878 requestData(fTrace, fStatisticsUpdateRange);
879 fStatisticsUpdateRange = null;
880 }
881 }
882 }
883 }
This page took 0.050261 seconds and 6 git commands to generate.