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
CommitLineData
cfd22ad0 1/*******************************************************************************
87f83123 2 * Copyright (c) 2012, 2014 Ericsson
cfd22ad0
MD
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
0fcf3b09 12 * Patrick Tasse - Support selection range
cfd22ad0
MD
13 *******************************************************************************/
14
2bdf0193 15package org.eclipse.tracecompass.tmf.ui.viewers.statistics;
cfd22ad0 16
de83d1ab 17import java.util.HashMap;
cfd22ad0 18import java.util.List;
89c06060 19import java.util.Map;
cfd22ad0 20
de83d1ab
MAL
21import org.eclipse.core.runtime.IProgressMonitor;
22import org.eclipse.core.runtime.IStatus;
23import org.eclipse.core.runtime.Status;
24import org.eclipse.core.runtime.jobs.Job;
cfd22ad0
MD
25import org.eclipse.jface.viewers.TreeViewer;
26import org.eclipse.jface.viewers.TreeViewerColumn;
27import org.eclipse.jface.viewers.Viewer;
28import org.eclipse.jface.viewers.ViewerComparator;
cfd22ad0
MD
29import org.eclipse.swt.SWT;
30import org.eclipse.swt.events.SelectionAdapter;
31import org.eclipse.swt.events.SelectionEvent;
32import org.eclipse.swt.graphics.Color;
33import org.eclipse.swt.graphics.Cursor;
cfd22ad0
MD
34import org.eclipse.swt.widgets.Composite;
35import org.eclipse.swt.widgets.Control;
36import org.eclipse.swt.widgets.Display;
37import org.eclipse.swt.widgets.Event;
38import org.eclipse.swt.widgets.Listener;
e894a508 39import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
2bdf0193
AM
40import org.eclipse.tracecompass.tmf.core.component.TmfComponent;
41import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
42import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
43import org.eclipse.tracecompass.tmf.core.signal.TmfTimeSynchSignal;
44import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
45import org.eclipse.tracecompass.tmf.core.statistics.ITmfStatistics;
46import org.eclipse.tracecompass.tmf.core.statistics.TmfStatisticsEventTypesModule;
47import org.eclipse.tracecompass.tmf.core.statistics.TmfStatisticsModule;
48import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
49import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
50import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
2bdf0193 51import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
b8585c7c 52import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
5c5fa260 53import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
2bdf0193
AM
54import org.eclipse.tracecompass.tmf.ui.TmfUiRefreshHandler;
55import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer;
56import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfBaseColumnData;
57import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfBaseColumnDataProvider;
58import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfStatisticsFormatter;
59import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfStatisticsTree;
60import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfStatisticsTreeManager;
61import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfStatisticsTreeNode;
62import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfTreeContentProvider;
cfd22ad0
MD
63
64/**
65 * A basic viewer to display statistics in the statistics view.
66 *
8b60cb37
MD
67 * It is linked to a single ITmfTrace until its disposal.
68 *
cfd22ad0 69 * @author Mathieu Denis
cfd22ad0
MD
70 * @since 2.0
71 */
05627bda 72public class TmfStatisticsViewer extends TmfViewer {
cfd22ad0 73
87f83123
AM
74 /** Timestamp scale used for all statistics (nanosecond) */
75 private static final byte TIME_SCALE = ITmfTimestamp.NANOSECOND_SCALE;
05627bda 76
aae89862
PT
77 /** The delay (in ms) between each update in live-reading mode */
78 private static final long LIVE_UPDATE_DELAY = 1000;
79
87f83123
AM
80 /** The actual tree viewer to display */
81 private TreeViewer fTreeViewer;
05627bda 82
87f83123
AM
83 /** The statistics tree linked to this viewer */
84 private TmfStatisticsTree fStatisticsData;
3c934968 85
87f83123
AM
86 /** Update range synchronization object */
87 private final Object fStatisticsRangeUpdateSyncObj = new Object();
73fbf6be 88
87f83123
AM
89 /** The trace that is displayed by this viewer */
90 private ITmfTrace fTrace;
89c06060 91
87f83123 92 /** Indicates to process all events */
05627bda
MD
93 private boolean fProcessAll;
94
87f83123 95 /** View instance counter (for multiple statistics views) */
cfd22ad0
MD
96 private static int fCountInstance = 0;
97
87f83123 98 /** Number of this instance. Used as an instance ID. */
cfd22ad0
MD
99 private int fInstanceNb;
100
87f83123 101 /** Object to store the cursor while waiting for the trace to load */
cfd22ad0
MD
102 private Cursor fWaitCursor = null;
103
104 /**
05627bda
MD
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
87f83123 111 /** Tells to send a time range request when the trace gets updated. */
05627bda
MD
112 private boolean fSendRangeRequest = true;
113
f0c0d2c2
AM
114 /** Reference to the trace manager */
115 private final TmfTraceManager fTraceManager;
116
de83d1ab
MAL
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
05627bda
MD
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);
f0c0d2c2 138 fTraceManager = TmfTraceManager.getInstance();
05627bda
MD
139 }
140
141 /**
142 * Initialize the statistics viewer.
cfd22ad0
MD
143 *
144 * @param parent
05627bda
MD
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.
cfd22ad0 150 */
05627bda
MD
151 public void init(Composite parent, String viewerName, ITmfTrace trace) {
152 super.init(parent, viewerName);
cfd22ad0
MD
153 // Increment a counter to make sure the tree ID is unique.
154 fCountInstance++;
155 fInstanceNb = fCountInstance;
05627bda
MD
156 fTrace = trace;
157
faa38350 158 // The viewer will process all events if he is assigned to an experiment
05627bda
MD
159 fProcessAll = (trace instanceof TmfExperiment);
160
161 initContent(parent);
8b60cb37 162 initInput();
05627bda
MD
163 }
164
05627bda
MD
165 @Override
166 public void dispose() {
167 super.dispose();
168 if (fWaitCursor != null) {
169 fWaitCursor.dispose();
170 }
8b60cb37 171
de83d1ab
MAL
172 for (Job j : fUpdateJobsGlobal.values()) {
173 j.cancel();
174 }
175
176 for (Job j : fUpdateJobsPartial.values()) {
177 j.cancel();
178 }
179
66792052 180 // Clean the model for this viewer
36033ff0 181 TmfStatisticsTreeManager.removeStatTreeRoot(getTreeID());
05627bda
MD
182 }
183
1c0de632
AM
184 // ------------------------------------------------------------------------
185 // Signal handlers
186 // ------------------------------------------------------------------------
89c06060 187
05627bda 188 /**
faa38350 189 * Handles the signal about new trace range.
05627bda
MD
190 *
191 * @param signal
faa38350 192 * The trace range updated signal
05627bda
MD
193 */
194 @TmfSignalHandler
faa38350
PT
195 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal) {
196 ITmfTrace trace = signal.getTrace();
05627bda 197 // validate
faa38350 198 if (!isListeningTo(trace)) {
05627bda
MD
199 return;
200 }
201
3c934968
MD
202 synchronized (fStatisticsRangeUpdateSyncObj) {
203 // Sends the time range request only once from this method.
204 if (fSendRangeRequest) {
205 fSendRangeRequest = false;
0fcf3b09
PT
206 ITmfTimestamp begin = fTraceManager.getSelectionBeginTime();
207 ITmfTimestamp end = fTraceManager.getSelectionEndTime();
208 TmfTimeRange timeRange = new TmfTimeRange(begin, end);
209 requestTimeRangeData(trace, timeRange);
3c934968 210 }
05627bda 211 }
faa38350 212 requestData(trace, signal.getRange());
05627bda
MD
213 }
214
0fcf3b09
PT
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.
4b121c48 221 * @since 2.1
0fcf3b09
PT
222 */
223 @TmfSignalHandler
224 public void timeSynchUpdated(TmfTimeSynchSignal signal) {
faa38350
PT
225 if (fTrace == null) {
226 return;
227 }
0fcf3b09
PT
228 ITmfTimestamp begin = signal.getBeginTime();
229 ITmfTimestamp end = signal.getEndTime();
230 TmfTimeRange timeRange = new TmfTimeRange(begin, end);
231 requestTimeRangeData(fTrace, timeRange);
05627bda
MD
232 }
233
1c0de632
AM
234 // ------------------------------------------------------------------------
235 // Class methods
236 // ------------------------------------------------------------------------
237
05627bda
MD
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
05627bda
MD
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 */
36033ff0 263 public TmfStatisticsTree getStatisticData() {
05627bda 264 if (fStatisticsData == null) {
36033ff0 265 fStatisticsData = new TmfStatisticsTree();
05627bda
MD
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
65fc212e 288 TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
05627bda
MD
289 @Override
290 public void run() {
291 if (!viewerControl.isDisposed()) {
292 fTreeViewer.refresh();
293 }
294 }
295 });
296 }
297
3c934968
MD
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
05627bda
MD
307 /**
308 * Focus on the statistics tree of the viewer
309 */
310 public void setFocus() {
311 fTreeViewer.getTree().setFocus();
312 }
313
05627bda
MD
314 /**
315 * Cancels the request if it is not already completed
316 *
317 * @param request
318 * The request to be canceled
c4767854 319 * @since 3.0
05627bda 320 */
fd3f1eff 321 protected void cancelOngoingRequest(ITmfEventRequest request) {
05627bda
MD
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 *
b3a26928
AM
331 * @return An object of type {@link TmfBaseColumnDataProvider}.
332 * @since 3.0
05627bda 333 */
b3a26928 334 protected TmfBaseColumnDataProvider getColumnDataProvider() {
05627bda
MD
335 return new TmfBaseColumnDataProvider();
336 }
cfd22ad0 337
05627bda
MD
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) {
cfd22ad0 345 final List<TmfBaseColumnData> columnDataList = getColumnDataProvider().getColumnData();
cfd22ad0
MD
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
df2b3dbb
VP
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) {
cfd22ad0
MD
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 /*
df2b3dbb
VP
386 * Puts the descendant order if the old order was up
387 * or if the selected column has changed.
cfd22ad0
MD
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
df2b3dbb 406 // Handler that will draw the percentages and the bar charts.
cfd22ad0
MD
407 fTreeViewer.getTree().addListener(SWT.EraseItem, new Listener() {
408 @Override
409 public void handleEvent(Event event) {
410 if (columnDataList.get(event.index).getPercentageProvider() != null) {
df2b3dbb 411
cfd22ad0
MD
412 TmfStatisticsTreeNode node = (TmfStatisticsTreeNode) event.item.getData();
413
df2b3dbb
VP
414 // If node is hidden, exit immediately.
415 if (TmfBaseColumnDataProvider.HIDDEN_FOLDER_LEVELS.contains(node.getName())) {
cfd22ad0
MD
416 return;
417 }
418
df2b3dbb
VP
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.
cfd22ad0
MD
425 event.gc.fillRectangle(event.x, event.y, event.width, event.height);
426 event.detail &= ~SWT.SELECTED;
427 }
428
df2b3dbb
VP
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 }
cfd22ad0
MD
481 }
482 }
df2b3dbb 483
cfd22ad0
MD
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
8b60cb37
MD
492 /**
493 * Initializes the input for the tree viewer.
8b60cb37
MD
494 */
495 protected void initInput() {
496 String treeID = getTreeID();
faa38350 497 TmfStatisticsTreeNode statisticsTreeNode;
36033ff0 498 if (TmfStatisticsTreeManager.containsTreeRoot(treeID)) {
faa38350
PT
499 // The statistics root is already present
500 statisticsTreeNode = TmfStatisticsTreeManager.getStatTreeRoot(treeID);
8b60cb37
MD
501
502 // Checks if the trace is already in the statistics tree.
faa38350 503 int numNodeTraces = statisticsTreeNode.getNbChildren();
8b60cb37 504
b9a5bf8f 505 ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
fe0c44c4 506 int numTraces = traces.length;
8b60cb37
MD
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++) {
fe0c44c4 515 String traceName = traces[i].getName();
faa38350 516 if (!statisticsTreeNode.containsChild(traceName)) {
8b60cb37
MD
517 same = false;
518 break;
519 }
520 }
521
522 if (same) {
523 // No need to reload data, all traces are already loaded
faa38350 524 fTreeViewer.setInput(statisticsTreeNode);
8b60cb37
MD
525 return;
526 }
527 // Clears the old content to start over
faa38350 528 statisticsTreeNode.reset();
8b60cb37
MD
529 }
530 } else {
531 // Creates a new tree
faa38350 532 statisticsTreeNode = TmfStatisticsTreeManager.addStatsTreeRoot(treeID, getStatisticData());
8b60cb37
MD
533 }
534
535 // Sets the input to a clean data model
faa38350 536 fTreeViewer.setInput(statisticsTreeNode);
8b60cb37
MD
537 }
538
cfd22ad0 539 /**
faa38350 540 * Tells if the viewer is listening to a trace.
cfd22ad0 541 *
1c0de632 542 * @param trace
05627bda
MD
543 * The trace that the viewer may be listening
544 * @return true if the viewer is listening to the trace, false otherwise
cfd22ad0 545 */
1c0de632
AM
546 protected boolean isListeningTo(ITmfTrace trace) {
547 if (fProcessAll || trace == fTrace) {
05627bda 548 return true;
cfd22ad0 549 }
05627bda 550 return false;
cfd22ad0
MD
551 }
552
553 /**
faa38350 554 * Called when an trace request has been completed successfully.
cfd22ad0 555 *
05627bda
MD
556 * @param global
557 * Tells if the request is a global or time range (partial)
558 * request.
cfd22ad0 559 */
05627bda
MD
560 protected void modelComplete(boolean global) {
561 refresh();
562 waitCursor(false);
cfd22ad0
MD
563 }
564
565 /**
faa38350 566 * Called when an trace request has failed or has been cancelled.
cfd22ad0 567 *
05627bda
MD
568 * @param isGlobalRequest
569 * Tells if the request is a global or time range (partial)
570 * request.
cfd22ad0 571 */
05627bda 572 protected void modelIncomplete(boolean isGlobalRequest) {
df2b3dbb 573 if (isGlobalRequest) { // Clean the global statistics
05627bda 574 /*
763f4972
MD
575 * No need to reset the global number of events, since the index of
576 * the last requested event is known.
05627bda 577 */
df2b3dbb 578 } else { // Clean the partial statistics
05627bda
MD
579 resetTimeRangeValue();
580 }
581 refresh();
582 waitCursor(false);
cfd22ad0
MD
583 }
584
585 /**
faa38350 586 * Sends the request to the trace for the whole trace
cfd22ad0 587 *
faa38350
PT
588 * @param trace
589 * The trace used to send the request
8b260d9f 590 * @param timeRange
faa38350 591 * The range to request to the trace
cfd22ad0 592 */
faa38350
PT
593 protected void requestData(final ITmfTrace trace, final TmfTimeRange timeRange) {
594 buildStatisticsTree(trace, timeRange, true);
cfd22ad0
MD
595 }
596
597 /**
faa38350 598 * Sends the time range request from the trace
cfd22ad0 599 *
faa38350
PT
600 * @param trace
601 * The trace used to send the request
8b260d9f 602 * @param timeRange
faa38350 603 * The range to request to the trace
cfd22ad0 604 */
faa38350 605 protected void requestTimeRangeData(final ITmfTrace trace, final TmfTimeRange timeRange) {
faa38350 606 buildStatisticsTree(trace, timeRange, false);
89c06060
AM
607 }
608
609 /**
df2b3dbb
VP
610 * Requests all the data of the trace to the state system which contains
611 * information about the statistics.
89c06060 612 *
df2b3dbb
VP
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
89c06060
AM
615 * method {@link #isListeningTo(String trace)}.
616 *
faa38350
PT
617 * @param trace
618 * The trace for which a request must be done
89c06060
AM
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 */
d6b46913 625 private void buildStatisticsTree(final ITmfTrace trace, final TmfTimeRange timeRange, final boolean isGlobal) {
36033ff0 626 final TmfStatisticsTree statsData = TmfStatisticsTreeManager.getStatTree(getTreeID());
89c06060
AM
627 if (statsData == null) {
628 return;
629 }
630
de83d1ab
MAL
631 Map<ITmfTrace, Job> updateJobs;
632 if (isGlobal) {
633 updateJobs = fUpdateJobsGlobal;
634 fTimeRange = timeRange;
635 } else {
636 updateJobs = fUpdateJobsPartial;
637 fTimeRangePartial = timeRange;
638 }
89c06060 639
de83d1ab
MAL
640 for (final ITmfTrace aTrace : TmfTraceManager.getTraceSet(trace)) {
641 if (!isListeningTo(aTrace)) {
642 continue;
643 }
d6b46913 644
de83d1ab 645 /* Retrieve the statistics object */
b8585c7c 646 final TmfStatisticsModule statsMod = TmfTraceUtils.getAnalysisModuleOfClass(aTrace, TmfStatisticsModule.class, TmfStatisticsModule.ID);
de83d1ab
MAL
647 if (statsMod == null) {
648 /* No statistics module available for this trace */
649 continue;
650 }
55954069 651
de83d1ab
MAL
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();
89c06060 658 }
89c06060 659 }
cfd22ad0
MD
660 }
661
de83d1ab 662 private class UpdateJob extends Job {
d6b46913 663
de83d1ab
MAL
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;
55954069
AM
673 }
674
de83d1ab
MAL
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 }
d6b46913 696
df2b3dbb 697
de83d1ab
MAL
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);
d6b46913 727
de83d1ab 728 return Status.OK_STATUS;
d6b46913
AM
729 }
730
731 /*
de83d1ab 732 * Update statistics for a given trace
d6b46913 733 */
de83d1ab
MAL
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 */
d6b46913 765
de83d1ab
MAL
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 }
d6b46913
AM
784 }
785
cfd22ad0 786 /**
05627bda 787 * Resets the number of events within the time range
cfd22ad0 788 */
05627bda 789 protected void resetTimeRangeValue() {
36033ff0 790 TmfStatisticsTreeNode treeModelRoot = TmfStatisticsTreeManager.getStatTreeRoot(getTreeID());
05627bda
MD
791 if (treeModelRoot != null && treeModelRoot.hasChildren()) {
792 treeModelRoot.resetTimeRangeValue();
793 }
cfd22ad0
MD
794 }
795
796 /**
df2b3dbb
VP
797 * When the trace is loading the cursor will be different so the user knows
798 * that the processing is not finished yet.
05627bda
MD
799 *
800 * Calls to this method are stacked.
cfd22ad0 801 *
05627bda 802 * @param waitRequested
cfd22ad0 803 * Indicates if we need to show the waiting cursor, or the
05627bda 804 * default one.
cfd22ad0 805 */
05627bda 806 protected void waitCursor(final boolean waitRequested) {
cfd22ad0
MD
807 if ((fTreeViewer == null) || (fTreeViewer.getTree().isDisposed())) {
808 return;
809 }
810
05627bda 811 boolean needsUpdate = false;
cfd22ad0 812 Display display = fTreeViewer.getControl().getDisplay();
05627bda
MD
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 }
cfd22ad0
MD
829 }
830
05627bda
MD
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);
cfd22ad0 843 }
cfd22ad0 844 }
05627bda
MD
845 });
846 }
cfd22ad0 847 }
cfd22ad0 848}
This page took 0.109653 seconds and 5 git commands to generate.