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