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