Merge branch 'master' into lttng-kepler
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / statistics / TmfStatisticsView.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 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> - Generalized version based on LTTng
11 * Bernd Hufmann - Updated to use trace reference in TmfEvent and streaming
12 * Mathieu Denis - New request added to update the statistics from the selected time range
13 *
14 *******************************************************************************/
15
16 package org.eclipse.linuxtools.tmf.ui.views.statistics;
17
18 import java.util.List;
19
20 import org.eclipse.jface.viewers.TreeViewer;
21 import org.eclipse.jface.viewers.TreeViewerColumn;
22 import org.eclipse.jface.viewers.Viewer;
23 import org.eclipse.jface.viewers.ViewerComparator;
24 import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
25 import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
26 import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType;
27 import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
28 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentDisposedSignal;
29 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;
30 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;
31 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentUpdatedSignal;
32 import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
33 import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
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.views.TmfView;
37 import org.eclipse.linuxtools.tmf.ui.views.statistics.model.AbsTmfStatisticsTree;
38 import org.eclipse.linuxtools.tmf.ui.views.statistics.model.ITmfColumnDataProvider;
39 import org.eclipse.linuxtools.tmf.ui.views.statistics.model.TmfBaseColumnData;
40 import org.eclipse.linuxtools.tmf.ui.views.statistics.model.TmfBaseColumnDataProvider;
41 import org.eclipse.linuxtools.tmf.ui.views.statistics.model.TmfBaseStatisticsTree;
42 import org.eclipse.linuxtools.tmf.ui.views.statistics.model.TmfStatisticsTreeNode;
43 import org.eclipse.linuxtools.tmf.ui.views.statistics.model.TmfStatisticsTreeRootFactory;
44 import org.eclipse.linuxtools.tmf.ui.views.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.layout.FillLayout;
51 import org.eclipse.swt.widgets.Composite;
52 import org.eclipse.swt.widgets.Display;
53 import org.eclipse.swt.widgets.Event;
54 import org.eclipse.swt.widgets.Listener;
55
56 /**
57 * The generic Statistics View displays statistics for any kind of traces.
58 *
59 * It is implemented according to the MVC pattern. - The model is a
60 * TmfStatisticsTreeNode built by the State Manager. - The view is built with a
61 * TreeViewer. - The controller that keeps model and view synchronized is an
62 * observer of the model.
63 *
64 * @version 2.0
65 * @author Mathieu Denis
66 */
67 public class TmfStatisticsView extends TmfView {
68
69 /**
70 * The ID correspond to the package in which this class is embedded
71 */
72 public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.statistics"; //$NON-NLS-1$
73
74 /**
75 * The view name.
76 */
77 public static final String TMF_STATISTICS_VIEW = "StatisticsView"; //$NON-NLS-1$
78
79 /**
80 * Refresh frequency
81 */
82 protected static final Long STATS_INPUT_CHANGED_REFRESH = 5000L;
83
84 /**
85 * Default PAGE_SIZE for background requests
86 */
87 protected static final int PAGE_SIZE = 50000;
88
89 /**
90 * The initial window span (in nanoseconds)
91 *
92 * @since 2.0
93 */
94 public static final long INITIAL_WINDOW_SPAN = (1L * 100 * 1000 * 1000); // .1sec
95
96 /**
97 * Timestamp scale (nanosecond)
98 *
99 * @since 2.0
100 */
101 public static final byte TIME_SCALE = -9;
102
103 /**
104 * The actual tree viewer to display
105 */
106 protected TreeViewer fTreeViewer;
107
108 /**
109 * Stores the global request to the experiment
110 */
111 protected ITmfEventRequest fRequest = null;
112
113 /**
114 * Stores the ranged request to the experiment
115 * @since 2.0
116 */
117 protected ITmfEventRequest fRequestRange = null;
118
119 /**
120 * Update synchronization parameter (used for streaming): Update busy
121 * indicator
122 */
123 protected boolean fStatisticsUpdateBusy = false;
124
125 /**
126 * Update synchronization parameter (used for streaming): Update pending
127 * indicator
128 */
129 protected boolean fStatisticsUpdatePending = false;
130
131 /**
132 * Update synchronization parameter (used for streaming): Pending Update
133 * time range
134 */
135 protected TmfTimeRange fStatisticsUpdateRange = null;
136
137 /**
138 * Update synchronization object.
139 */
140 protected final Object fStatisticsUpdateSyncObj = new Object();
141
142 /**
143 * Flag to force request the data from trace
144 */
145 protected boolean fRequestData = false;
146
147 /**
148 * Object to store the cursor while waiting for the experiment to load
149 */
150 private Cursor fWaitCursor = null;
151
152 /**
153 * View instance counter (for multiple statistic views)
154 */
155 private static int fCountInstance = 0;
156
157 /**
158 * Number of this instance. Used as an instance ID.
159 */
160 private final int fInstanceNb;
161
162 /**
163 * Constructor of a statistics view.
164 *
165 * @param viewName
166 * The name to give to the view.
167 */
168 public TmfStatisticsView(String viewName) {
169 super(viewName);
170 fCountInstance++;
171 fInstanceNb = fCountInstance;
172 }
173
174 /**
175 * Default constructor.
176 */
177 public TmfStatisticsView() {
178 this(TMF_STATISTICS_VIEW);
179 }
180
181 /*
182 * (non-Javadoc)
183 *
184 * @see
185 * org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
186 */
187 @Override
188 public void createPartControl(Composite parent) {
189 final List<TmfBaseColumnData> columnDataList = getColumnDataProvider().getColumnData();
190 parent.setLayout(new FillLayout());
191
192 fTreeViewer = new TreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
193 fTreeViewer.setContentProvider(new TmfTreeContentProvider());
194 fTreeViewer.getTree().setHeaderVisible(true);
195 fTreeViewer.setUseHashlookup(true);
196
197 for (final TmfBaseColumnData columnData : columnDataList) {
198 final TreeViewerColumn treeColumn = new TreeViewerColumn(fTreeViewer, columnData.getAlignment());
199 treeColumn.getColumn().setText(columnData.getHeader());
200 treeColumn.getColumn().setWidth(columnData.getWidth());
201 treeColumn.getColumn().setToolTipText(columnData.getTooltip());
202
203 if (columnData.getComparator() != null) {
204 treeColumn.getColumn().addSelectionListener(new SelectionAdapter() {
205 @Override
206 public void widgetSelected(SelectionEvent e) {
207 if (fTreeViewer.getTree().getSortDirection() == SWT.UP || fTreeViewer.getTree().getSortColumn() != treeColumn.getColumn()) {
208 fTreeViewer.setComparator(columnData.getComparator());
209 fTreeViewer.getTree().setSortDirection(SWT.DOWN);
210 } else {
211 fTreeViewer.setComparator(new ViewerComparator() {
212 @Override
213 public int compare(Viewer viewer, Object e1, Object e2) {
214 return -1 * columnData.getComparator().compare(viewer, e1, e2);
215 }
216 });
217 fTreeViewer.getTree().setSortDirection(SWT.UP);
218 }
219 fTreeViewer.getTree().setSortColumn(treeColumn.getColumn());
220 }
221 });
222 }
223 treeColumn.setLabelProvider(columnData.getLabelProvider());
224 }
225
226 // Handler that will draw the bar charts.
227 fTreeViewer.getTree().addListener(SWT.EraseItem, new Listener() {
228 @Override
229 public void handleEvent(Event event) {
230 if (columnDataList.get(event.index).getPercentageProvider() != null) {
231 TmfStatisticsTreeNode node = (TmfStatisticsTreeNode) event.item.getData();
232
233 double percentage = columnDataList.get(event.index).getPercentageProvider().getPercentage(node);
234 if (percentage == 0) {
235 return;
236 }
237
238 if ((event.detail & SWT.SELECTED) > 0) {
239 Color oldForeground = event.gc.getForeground();
240 event.gc.setForeground(event.item.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION));
241 event.gc.fillRectangle(event.x, event.y, event.width, event.height);
242 event.gc.setForeground(oldForeground);
243 event.detail &= ~SWT.SELECTED;
244 }
245
246 int barWidth = (int) ((fTreeViewer.getTree().getColumn(event.index).getWidth() - 8) * percentage);
247 int oldAlpha = event.gc.getAlpha();
248 Color oldForeground = event.gc.getForeground();
249 Color oldBackground = event.gc.getBackground();
250 event.gc.setAlpha(64);
251 event.gc.setForeground(event.item.getDisplay().getSystemColor(SWT.COLOR_BLUE));
252 event.gc.setBackground(event.item.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
253 event.gc.fillGradientRectangle(event.x, event.y, barWidth, event.height, true);
254 event.gc.drawRectangle(event.x, event.y, barWidth, event.height);
255 event.gc.setForeground(oldForeground);
256 event.gc.setBackground(oldBackground);
257 event.gc.setAlpha(oldAlpha);
258 event.detail &= ~SWT.BACKGROUND;
259 }
260 }
261 });
262
263 fTreeViewer.setComparator(columnDataList.get(0).getComparator());
264 fTreeViewer.getTree().setSortColumn(fTreeViewer.getTree().getColumn(0));
265 fTreeViewer.getTree().setSortDirection(SWT.DOWN);
266
267 // Read current data if any available
268 TmfExperiment experiment = TmfExperiment.getCurrentExperiment();
269 if (experiment != null) {
270 fRequestData = true;
271 // Insert the statistics data into the tree
272 TmfExperimentSelectedSignal signal = new TmfExperimentSelectedSignal(this, experiment);
273 experimentSelected(signal);
274 }
275 }
276
277 /*
278 * (non-Javadoc)
279 *
280 * @see org.eclipse.linuxtools.tmf.ui.views.TmfView#dispose()
281 */
282 @Override
283 public void dispose() {
284 super.dispose();
285 if (fWaitCursor != null) {
286 fWaitCursor.dispose();
287 }
288
289 /*
290 * Make sure there is no request running before removing the statistics
291 * tree
292 */
293 cancelOngoingRequest(fRequestRange);
294 cancelOngoingRequest(fRequest);
295 // clean the model
296 TmfStatisticsTreeRootFactory.removeAll();
297 }
298
299 /*
300 * (non-Javadoc)
301 *
302 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
303 */
304 @Override
305 public void setFocus() {
306 fTreeViewer.getTree().setFocus();
307 }
308
309 /**
310 * Refresh the view.
311 *
312 * @param complete
313 * Should a pending update be sent afterwards or not
314 */
315 public void modelInputChanged(boolean complete) {
316 // Ignore update if disposed
317 if (fTreeViewer.getTree().isDisposed()) {
318 return;
319 }
320
321 fTreeViewer.getTree().getDisplay().asyncExec(new Runnable() {
322 @Override
323 public void run() {
324 if (!fTreeViewer.getTree().isDisposed()) {
325 fTreeViewer.refresh();
326 }
327 }
328 });
329
330 if (complete) {
331 sendPendingUpdate();
332 }
333 }
334
335 /**
336 * Called when an experiment request has failed or has been cancelled.
337 * Remove the data retrieved from the experiment from the statistics tree.
338 *
339 * @param name
340 * The experiment name
341 */
342 public void modelIncomplete(String name) {
343 Object input = fTreeViewer.getInput();
344 if (input != null && input instanceof TmfStatisticsTreeNode) {
345 /*
346 * The data from this experiment is invalid and shall be removed to
347 * refresh upon next selection
348 */
349 TmfStatisticsTreeRootFactory.removeStatTreeRoot(getTreeID(name));
350
351 // Reset synchronization information
352 resetUpdateSynchronization();
353 modelInputChanged(false);
354 }
355 waitCursor(false);
356 }
357
358 /**
359 * Handles the signal about disposal of the current experiment.
360 *
361 * @param signal
362 * The disposed signal
363 */
364 @TmfSignalHandler
365 public void experimentDisposed(TmfExperimentDisposedSignal signal) {
366 if (signal.getExperiment() != TmfExperiment.getCurrentExperiment()) {
367 return;
368 }
369 /*
370 * The range request must be cancelled first, since the global one removes
371 * the statistics tree
372 */
373 cancelOngoingRequest(fRequestRange);
374 cancelOngoingRequest(fRequest);
375 resetTimeRangeValue();
376 }
377
378 /**
379 * Handler called when an experiment is selected. Checks if the experiment
380 * has changed and requests the selected experiment if it has not yet been
381 * cached.
382 *
383 * @param signal
384 * Contains the information about the selection.
385 */
386 @TmfSignalHandler
387 public void experimentSelected(TmfExperimentSelectedSignal signal) {
388 if (signal != null) {
389 TmfExperiment experiment = signal.getExperiment();
390 String experimentName = experiment.getName();
391
392 if (TmfStatisticsTreeRootFactory.containsTreeRoot(getTreeID(experimentName))) {
393 // The experiment root is already present
394 String treeID = getTreeID(experimentName);
395 TmfStatisticsTreeNode experimentTreeNode = TmfStatisticsTreeRootFactory.getStatTreeRoot(treeID);
396
397 ITmfTrace[] traces = experiment.getTraces();
398
399 // check if there is partial data loaded in the experiment
400 int numTraces = experiment.getTraces().length;
401 int numNodeTraces = experimentTreeNode.getNbChildren();
402
403 if (numTraces == numNodeTraces) {
404 boolean same = true;
405 /*
406 * Detect if the experiment contains the same traces as when
407 * previously selected
408 */
409 for (int i = 0; i < numTraces; i++) {
410 String traceName = traces[i].getName();
411 if (!experimentTreeNode.containsChild(traceName)) {
412 same = false;
413 break;
414 }
415 }
416
417 if (same) {
418 // no need to reload data, all traces are already loaded
419 fTreeViewer.setInput(experimentTreeNode);
420
421 resetUpdateSynchronization();
422
423 return;
424 }
425 experimentTreeNode.reset();
426 }
427 } else {
428 TmfStatisticsTreeRootFactory.addStatsTreeRoot(getTreeID(experimentName), getStatisticData());
429 }
430
431 resetUpdateSynchronization();
432
433 TmfStatisticsTreeNode treeModelRoot = TmfStatisticsTreeRootFactory.getStatTreeRoot(getTreeID(experiment.getName()));
434
435 // if the model has contents, clear to start over
436 if (treeModelRoot.hasChildren()) {
437 treeModelRoot.reset();
438 }
439
440 // set input to a clean data model
441 fTreeViewer.setInput(treeModelRoot);
442
443 if (fRequestData) {
444 requestData(experiment, experiment.getTimeRange());
445 fRequestData = false;
446 }
447 }
448 }
449
450 /**
451 * Handles the signal about new experiment range.
452 *
453 * @param signal
454 * The experiment range updated signal
455 */
456 @TmfSignalHandler
457 public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal) {
458 TmfExperiment experiment = signal.getExperiment();
459 // validate
460 if (!experiment.equals(TmfExperiment.getCurrentExperiment())) {
461 return;
462 }
463
464 // Calculate the selected timerange for the request
465 long startTime = signal.getRange().getStartTime().normalize(0, TIME_SCALE).getValue();
466 TmfTimestamp startTS = new TmfTimestamp(startTime, TIME_SCALE);
467 TmfTimestamp endTS = new TmfTimestamp(startTime + INITIAL_WINDOW_SPAN, TIME_SCALE);
468 TmfTimeRange timeRange = new TmfTimeRange(startTS, endTS);
469
470 requestTimeRangeData(experiment, timeRange);
471 requestData(experiment, signal.getRange());
472 }
473
474 /**
475 * Handles the experiment updated signal. This will detect new events in
476 * case the indexing is not coalesced with a statistics request.
477 *
478 * @param signal
479 * The experiment updated signal
480 *
481 * @since 1.1
482 */
483 @TmfSignalHandler
484 public void experimentUpdated(TmfExperimentUpdatedSignal signal) {
485 TmfExperiment experiment = signal.getExperiment();
486 if (!experiment.equals(TmfExperiment.getCurrentExperiment())) {
487 return;
488 }
489
490 int nbEvents = 0;
491 for (TmfStatisticsTreeNode node : ((TmfStatisticsTreeNode) fTreeViewer.getInput()).getChildren()) {
492 nbEvents += (int) node.getValue().getTotal();
493 }
494
495 /*
496 * In the normal case, the statistics request is coalesced with indexing
497 * and the number of events are the same, there is nothing to do. But if
498 * it's not the case, trigger a new request to count the new events.
499 */
500 if (nbEvents < experiment.getNbEvents()) {
501 requestData(experiment, experiment.getTimeRange());
502 }
503 }
504
505 /**
506 * Handles the time range updated signal. It updates the time range
507 * statistics.
508 *
509 * @param signal
510 * Contains the information about the new selected time range.
511 * @since 2.0
512 */
513 @TmfSignalHandler
514 public void timeRangeUpdated(TmfRangeSynchSignal signal) {
515 /*
516 * It is possible that the time range changes while a request is
517 * processing
518 */
519 cancelOngoingRequest(fRequestRange);
520 resetTimeRangeValue();
521
522 requestTimeRangeData(TmfExperiment.getCurrentExperiment(), signal.getCurrentRange());
523 }
524
525 /**
526 * Return the size of the request when performing background request.
527 *
528 * @return the block size for background request.
529 */
530 protected int getIndexPageSize() {
531 return PAGE_SIZE;
532 }
533
534 /**
535 * Returns the quantity of data to retrieve before a refresh of the view is
536 * performed
537 *
538 * @return the quantity of data to retrieve before a refresh of the view is
539 * performed.
540 */
541 protected long getInputChangedRefresh() {
542 return STATS_INPUT_CHANGED_REFRESH;
543 }
544
545 /**
546 * This method can be overridden to implement another way to represent the
547 * statistics data and to retrieve the information for display.
548 *
549 * @return a TmfStatisticsData object.
550 */
551 protected AbsTmfStatisticsTree getStatisticData() {
552 return new TmfBaseStatisticsTree();
553 }
554
555 /**
556 * This method can be overridden to change the representation of the data in
557 * the columns.
558 *
559 * @return an object implementing ITmfBaseColumnDataProvider.
560 */
561 protected ITmfColumnDataProvider getColumnDataProvider() {
562 return new TmfBaseColumnDataProvider();
563 }
564
565 /**
566 * Constructs the ID based on the experiment name and
567 * <code>fInstanceNb</code>
568 *
569 * @param experimentName
570 * the name of the trace name to show in the view
571 * @return a view ID
572 */
573 protected String getTreeID(String experimentName) {
574 return experimentName + fInstanceNb;
575 }
576
577 /**
578 * When the experiment is loading the cursor will be different so the user
579 * knows the processing is not finished yet.
580 *
581 * @param waitInd
582 * Indicates if we need to show the waiting cursor, or the
583 * default one
584 */
585 protected void waitCursor(final boolean waitInd) {
586 if ((fTreeViewer == null) || (fTreeViewer.getTree().isDisposed())) {
587 return;
588 }
589
590 Display display = fTreeViewer.getControl().getDisplay();
591 if (fWaitCursor == null) {
592 fWaitCursor = new Cursor(display, SWT.CURSOR_WAIT);
593 }
594
595 // Perform the updates on the UI thread
596 display.asyncExec(new Runnable() {
597 @Override
598 public void run() {
599 if ((fTreeViewer != null)
600 && (!fTreeViewer.getTree().isDisposed())) {
601 Cursor cursor = null; /* indicates default */
602 if (waitInd) {
603 cursor = fWaitCursor;
604 }
605 fTreeViewer.getControl().setCursor(cursor);
606 }
607 }
608 });
609 }
610
611 /**
612 * Performs the request for an experiment and populates the statistics tree
613 * with events.
614 *
615 * @param experiment
616 * Experiment for which we need the statistics data.
617 * @param timeRange
618 * to request
619 */
620 protected void requestData(final TmfExperiment experiment, TmfTimeRange timeRange) {
621 if (experiment != null) {
622
623 // Check if an update is already ongoing
624 if (checkUpdateBusy(timeRange)) {
625 return;
626 }
627
628 int index = 0;
629 for (TmfStatisticsTreeNode node : ((TmfStatisticsTreeNode) fTreeViewer.getInput()).getChildren()) {
630 index += (int) node.getValue().getTotal();
631 }
632
633 // Prepare the global event request
634 fRequest = new TmfStatisticsRequest(this, experiment, timeRange, index, ExecutionType.BACKGROUND, true);
635
636 experiment.sendRequest(fRequest);
637 waitCursor(true);
638 }
639 }
640
641 /**
642 * Performs the time range request for an experiment and populates the
643 * statistics tree with events.
644 *
645 * @param experiment
646 * Experiment for which we need the statistics data.
647 * @param timeRange
648 * To request
649 * @since 2.0
650 */
651 protected void requestTimeRangeData(final TmfExperiment experiment, TmfTimeRange timeRange) {
652 if (experiment != null) {
653
654 // Prepare the partial event request
655 fRequestRange = new TmfStatisticsRequest(this, experiment, timeRange, 0, ExecutionType.FOREGROUND, false);
656 experiment.sendRequest(fRequestRange);
657 }
658 }
659
660 /**
661 * Reset the number of events within the time range
662 *
663 * @since 2.0
664 */
665 protected void resetTimeRangeValue() {
666 // Reset the number of events in the time range
667 String treeID = getTreeID(TmfExperiment.getCurrentExperiment().getName());
668 TmfStatisticsTreeNode treeModelRoot = TmfStatisticsTreeRootFactory.getStatTreeRoot(treeID);
669 if (treeModelRoot.hasChildren()) {
670 treeModelRoot.resetTimeRangeValue();
671 }
672 }
673
674 /**
675 * Cancels the current ongoing request
676 *
677 * @param request
678 * The request to be canceled
679 * @since 2.0
680 */
681 protected void cancelOngoingRequest(ITmfEventRequest request) {
682 if (request != null && !request.isCompleted()) {
683 request.cancel();
684 }
685 }
686
687 /**
688 * Reset update synchronization information
689 */
690 protected void resetUpdateSynchronization() {
691 synchronized (fStatisticsUpdateSyncObj) {
692 fStatisticsUpdateBusy = false;
693 fStatisticsUpdatePending = false;
694 fStatisticsUpdateRange = null;
695 }
696 }
697
698 /**
699 * Checks if statistic update is ongoing. If it is ongoing the new time
700 * range is stored as pending
701 *
702 * @param timeRange
703 * - new time range
704 * @return true if statistic update is ongoing else false
705 */
706 protected boolean checkUpdateBusy(TmfTimeRange timeRange) {
707 synchronized (fStatisticsUpdateSyncObj) {
708 if (fStatisticsUpdateBusy) {
709 fStatisticsUpdatePending = true;
710 if (fStatisticsUpdateRange == null
711 || timeRange.getEndTime().compareTo(fStatisticsUpdateRange.getEndTime()) > 0) {
712 fStatisticsUpdateRange = timeRange;
713 }
714 return true;
715 }
716 fStatisticsUpdateBusy = true;
717 return false;
718 }
719 }
720
721 /**
722 * Sends pending request (if any)
723 */
724 protected void sendPendingUpdate() {
725 synchronized (fStatisticsUpdateSyncObj) {
726 fStatisticsUpdateBusy = false;
727 if (fStatisticsUpdatePending) {
728 fStatisticsUpdatePending = false;
729 requestData(TmfExperiment.getCurrentExperiment(), fStatisticsUpdateRange);
730 fStatisticsUpdateRange = null;
731 }
732 }
733 }
734
735 }
This page took 0.082346 seconds and 6 git commands to generate.