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