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