1 /*******************************************************************************
2 * Copyright (c) 2015, 2016 Ericsson
4 * All rights reserved. This program and the accompanying materials are made
5 * 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
10 * Bernd Hufmann - Initial API and implementation
11 *******************************************************************************/
12 package org
.eclipse
.tracecompass
.analysis
.timing
.ui
.views
.segmentstore
.statistics
;
14 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
16 import java
.text
.Format
;
17 import java
.util
.ArrayList
;
18 import java
.util
.List
;
20 import java
.util
.Map
.Entry
;
22 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
23 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
24 import org
.eclipse
.jdt
.annotation
.NonNull
;
25 import org
.eclipse
.jdt
.annotation
.Nullable
;
26 import org
.eclipse
.jface
.action
.Action
;
27 import org
.eclipse
.jface
.action
.IAction
;
28 import org
.eclipse
.jface
.action
.IMenuManager
;
29 import org
.eclipse
.jface
.action
.MenuManager
;
30 import org
.eclipse
.jface
.viewers
.ISelection
;
31 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
32 import org
.eclipse
.jface
.viewers
.TreeViewer
;
33 import org
.eclipse
.jface
.viewers
.Viewer
;
34 import org
.eclipse
.jface
.viewers
.ViewerComparator
;
35 import org
.eclipse
.swt
.SWT
;
36 import org
.eclipse
.swt
.widgets
.Composite
;
37 import org
.eclipse
.swt
.widgets
.Menu
;
38 import org
.eclipse
.tracecompass
.analysis
.timing
.core
.segmentstore
.statistics
.AbstractSegmentStatisticsAnalysis
;
39 import org
.eclipse
.tracecompass
.analysis
.timing
.core
.segmentstore
.statistics
.SegmentStoreStatistics
;
40 import org
.eclipse
.tracecompass
.analysis
.timing
.ui
.views
.segmentstore
.SubSecondTimeWithUnitFormat
;
41 import org
.eclipse
.tracecompass
.internal
.analysis
.timing
.ui
.Activator
;
42 import org
.eclipse
.tracecompass
.internal
.analysis
.timing
.ui
.views
.segmentstore
.statistics
.Messages
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.analysis
.TmfAbstractAnalysisModule
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.exceptions
.TmfAnalysisException
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSelectionRangeUpdatedSignal
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfWindowRangeUpdatedSignal
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
50 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.AbstractTmfTreeViewer
;
51 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.ITmfTreeColumnDataProvider
;
52 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.ITmfTreeViewerEntry
;
53 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.TmfTreeColumnData
;
54 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.TmfTreeViewerEntry
;
57 * An abstract tree viewer implementation for displaying segment store
60 * @author Bernd Hufmann
63 public abstract class AbstractSegmentStoreStatisticsViewer
extends AbstractTmfTreeViewer
{
65 private static final Format FORMATTER
= new SubSecondTimeWithUnitFormat();
67 private @Nullable TmfAbstractAnalysisModule fModule
;
68 private MenuManager fTablePopupMenuManager
;
70 private static final String
[] COLUMN_NAMES
= new String
[] {
71 checkNotNull(Messages
.SegmentStoreStatistics_LevelLabel
),
72 checkNotNull(Messages
.SegmentStoreStatistics_Statistics_MinLabel
),
73 checkNotNull(Messages
.SegmentStoreStatistics_MaxLabel
),
74 checkNotNull(Messages
.SegmentStoreStatistics_AverageLabel
),
75 checkNotNull(Messages
.SegmentStoreStatisticsViewer_StandardDeviation
),
76 checkNotNull(Messages
.SegmentStoreStatisticsViewer_Count
),
77 checkNotNull(Messages
.SegmentStoreStatisticsViewer_Total
)
84 * the parent composite
86 public AbstractSegmentStoreStatisticsViewer(Composite parent
) {
88 setLabelProvider(new SegmentStoreStatisticsLabelProvider());
89 fTablePopupMenuManager
= new MenuManager();
90 fTablePopupMenuManager
.setRemoveAllWhenShown(true);
91 fTablePopupMenuManager
.addMenuListener(manager
-> {
92 TreeViewer viewer
= getTreeViewer();
93 ISelection selection
= viewer
.getSelection();
94 if (selection
instanceof IStructuredSelection
) {
95 IStructuredSelection sel
= (IStructuredSelection
) selection
;
96 if (manager
!= null) {
97 appendToTablePopupMenu(manager
, sel
);
101 Menu tablePopup
= fTablePopupMenuManager
.createContextMenu(getTreeViewer().getTree());
102 getTreeViewer().getTree().setMenu(tablePopup
);
105 /** Provides label for the Segment Store tree viewer cells */
106 protected static class SegmentStoreStatisticsLabelProvider
extends TreeLabelProvider
{
109 public String
getColumnText(@Nullable Object element
, int columnIndex
) {
110 String value
= ""; //$NON-NLS-1$
111 if (element
instanceof HiddenTreeViewerEntry
) {
112 if (columnIndex
== 0) {
113 value
= ((HiddenTreeViewerEntry
) element
).getName();
115 } else if (element
instanceof SegmentStoreStatisticsEntry
) {
116 SegmentStoreStatisticsEntry entry
= (SegmentStoreStatisticsEntry
) element
;
117 if (columnIndex
== 0) {
118 return String
.valueOf(entry
.getName());
120 if (entry
.getEntry().getNbSegments() > 0) {
121 if (columnIndex
== 1) {
122 value
= toFormattedString(entry
.getEntry().getMin());
123 } else if (columnIndex
== 2) {
124 value
= String
.valueOf(toFormattedString(entry
.getEntry().getMax()));
125 } else if (columnIndex
== 3) {
126 value
= String
.valueOf(toFormattedString(entry
.getEntry().getAverage()));
127 } else if (columnIndex
== 4) {
128 value
= String
.valueOf(toFormattedString(entry
.getEntry().getStdDev()));
129 } else if (columnIndex
== 5) {
130 value
= String
.valueOf(entry
.getEntry().getNbSegments());
131 } else if (columnIndex
== 6) {
132 value
= String
.valueOf(toFormattedString(entry
.getEntry().getTotal()));
136 return checkNotNull(value
);
141 * Creates the statistics analysis module
143 * @return the statistics analysis module
146 protected abstract TmfAbstractAnalysisModule
createStatisticsAnalysiModule();
149 * Gets the statistics analysis module
151 * @return the statistics analysis module
154 public TmfAbstractAnalysisModule
getStatisticsAnalysisModule() {
159 protected ITmfTreeColumnDataProvider
getColumnDataProvider() {
160 return new ITmfTreeColumnDataProvider() {
163 public List
<@Nullable TmfTreeColumnData
> getColumnData() {
164 /* All columns are sortable */
165 List
<@Nullable TmfTreeColumnData
> columns
= new ArrayList
<>();
166 TmfTreeColumnData column
= new TmfTreeColumnData(COLUMN_NAMES
[0]);
167 column
.setAlignment(SWT
.RIGHT
);
168 column
.setComparator(new ViewerComparator() {
170 public int compare(@Nullable Viewer viewer
, @Nullable Object e1
, @Nullable Object e2
) {
171 if ((e1
== null) || (e2
== null)) {
175 SegmentStoreStatisticsEntry n1
= (SegmentStoreStatisticsEntry
) e1
;
176 SegmentStoreStatisticsEntry n2
= (SegmentStoreStatisticsEntry
) e2
;
178 return n1
.getName().compareTo(n2
.getName());
183 column
= new TmfTreeColumnData(COLUMN_NAMES
[1]);
184 column
.setAlignment(SWT
.RIGHT
);
185 column
.setComparator(new ViewerComparator() {
187 public int compare(@Nullable Viewer viewer
, @Nullable Object e1
, @Nullable Object e2
) {
188 if ((e1
== null) || (e2
== null)) {
192 SegmentStoreStatisticsEntry n1
= (SegmentStoreStatisticsEntry
) e1
;
193 SegmentStoreStatisticsEntry n2
= (SegmentStoreStatisticsEntry
) e2
;
195 return Long
.compare(n1
.getEntry().getMin(), n2
.getEntry().getMin());
200 column
= new TmfTreeColumnData(COLUMN_NAMES
[2]);
201 column
.setAlignment(SWT
.RIGHT
);
202 column
.setComparator(new ViewerComparator() {
204 public int compare(@Nullable Viewer viewer
, @Nullable Object e1
, @Nullable Object e2
) {
205 if ((e1
== null) || (e2
== null)) {
209 SegmentStoreStatisticsEntry n1
= (SegmentStoreStatisticsEntry
) e1
;
210 SegmentStoreStatisticsEntry n2
= (SegmentStoreStatisticsEntry
) e2
;
212 return Long
.compare(n1
.getEntry().getMax(), n2
.getEntry().getMax());
217 column
= new TmfTreeColumnData(COLUMN_NAMES
[3]);
218 column
.setAlignment(SWT
.RIGHT
);
219 column
.setComparator(new ViewerComparator() {
221 public int compare(@Nullable Viewer viewer
, @Nullable Object e1
, @Nullable Object e2
) {
222 if ((e1
== null) || (e2
== null)) {
226 SegmentStoreStatisticsEntry n1
= (SegmentStoreStatisticsEntry
) e1
;
227 SegmentStoreStatisticsEntry n2
= (SegmentStoreStatisticsEntry
) e2
;
229 return Double
.compare(n1
.getEntry().getAverage(), n2
.getEntry().getAverage());
234 column
= new TmfTreeColumnData(COLUMN_NAMES
[4]);
235 column
.setAlignment(SWT
.RIGHT
);
236 column
.setComparator(new ViewerComparator() {
238 public int compare(@Nullable Viewer viewer
, @Nullable Object e1
, @Nullable Object e2
) {
239 if ((e1
== null) || (e2
== null)) {
243 SegmentStoreStatisticsEntry n1
= (SegmentStoreStatisticsEntry
) e1
;
244 SegmentStoreStatisticsEntry n2
= (SegmentStoreStatisticsEntry
) e2
;
246 return Double
.compare(n1
.getEntry().getStdDev(), n2
.getEntry().getStdDev());
251 column
= new TmfTreeColumnData(COLUMN_NAMES
[5]);
252 column
.setAlignment(SWT
.RIGHT
);
253 column
.setComparator(new ViewerComparator() {
255 public int compare(@Nullable Viewer viewer
, @Nullable Object e1
, @Nullable Object e2
) {
256 if ((e1
== null) || (e2
== null)) {
260 SegmentStoreStatisticsEntry n1
= (SegmentStoreStatisticsEntry
) e1
;
261 SegmentStoreStatisticsEntry n2
= (SegmentStoreStatisticsEntry
) e2
;
263 return Long
.compare(n1
.getEntry().getNbSegments(), n2
.getEntry().getNbSegments());
268 column
= new TmfTreeColumnData(COLUMN_NAMES
[6]);
269 column
.setAlignment(SWT
.RIGHT
);
270 column
.setComparator(new ViewerComparator() {
272 public int compare(@Nullable Viewer viewer
, @Nullable Object e1
, @Nullable Object e2
) {
273 if ((e1
== null) || (e2
== null)) {
277 SegmentStoreStatisticsEntry n1
= (SegmentStoreStatisticsEntry
) e1
;
278 SegmentStoreStatisticsEntry n2
= (SegmentStoreStatisticsEntry
) e2
;
280 return Double
.compare(n1
.getEntry().getTotal(), n2
.getEntry().getTotal());
285 column
= new TmfTreeColumnData(""); //$NON-NLS-1$
294 public void initializeDataSource() {
295 ITmfTrace trace
= getTrace();
297 TmfAbstractAnalysisModule module
= createStatisticsAnalysiModule();
298 if (module
== null) {
302 module
.setTrace(trace
);
305 } catch (TmfAnalysisException e
) {
306 Activator
.getDefault().logError("Error initializing statistics analysis module", e
); //$NON-NLS-1$
312 * Method to add commands to the context sensitive menu.
317 * the current selection
319 protected void appendToTablePopupMenu(IMenuManager manager
, IStructuredSelection sel
) {
320 Object element
= sel
.getFirstElement();
321 if ((element
instanceof SegmentStoreStatisticsEntry
) && !(element
instanceof HiddenTreeViewerEntry
)) {
322 final SegmentStoreStatisticsEntry segment
= (SegmentStoreStatisticsEntry
) element
;
323 IAction gotoStartTime
= new Action(Messages
.SegmentStoreStatisticsViewer_GotoMinAction
) {
326 long start
= segment
.getEntry().getMinSegment().getStart();
327 long end
= segment
.getEntry().getMinSegment().getEnd();
328 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreStatisticsViewer
.this, TmfTimestamp
.fromNanos(start
), TmfTimestamp
.fromNanos(end
)));
329 updateContent(start
, end
, true);
333 IAction gotoEndTime
= new Action(Messages
.SegmentStoreStatisticsViewer_GotoMaxAction
) {
336 long start
= segment
.getEntry().getMaxSegment().getStart();
337 long end
= segment
.getEntry().getMaxSegment().getEnd();
338 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractSegmentStoreStatisticsViewer
.this, TmfTimestamp
.fromNanos(start
), TmfTimestamp
.fromNanos(end
)));
339 updateContent(start
, end
, true);
343 manager
.add(gotoStartTime
);
344 manager
.add(gotoEndTime
);
349 * Formats a double value string
353 * @return formatted value
355 protected static String
toFormattedString(double value
) {
356 // The cast to long is needed because the formatter cannot truncate the
358 String percentageString
= String
.format("%s", FORMATTER
.format(value
)); //$NON-NLS-1$
359 return percentageString
;
363 * Class for defining an entry in the statistics tree.
365 protected class SegmentStoreStatisticsEntry
extends TmfTreeViewerEntry
{
367 private final SegmentStoreStatistics fEntry
;
376 * segment store statistics object
378 public SegmentStoreStatisticsEntry(String name
, SegmentStoreStatistics entry
) {
384 * Gets the statistics object
386 * @return statistics object
388 public SegmentStoreStatistics
getEntry() {
395 protected @Nullable ITmfTreeViewerEntry
updateElements(long start
, long end
, boolean isSelection
) {
397 TmfAbstractAnalysisModule analysisModule
= getStatisticsAnalysisModule();
399 if (getTrace() == null || !(analysisModule
instanceof AbstractSegmentStatisticsAnalysis
)) {
403 AbstractSegmentStatisticsAnalysis module
= (AbstractSegmentStatisticsAnalysis
) analysisModule
;
405 module
.waitForCompletion();
407 TmfTreeViewerEntry root
= new TmfTreeViewerEntry(""); //$NON-NLS-1$
408 List
<ITmfTreeViewerEntry
> entryList
= root
.getChildren();
411 setStats(start
, end
, entryList
, module
, true, new NullProgressMonitor());
413 setStats(start
, end
, entryList
, module
, false, new NullProgressMonitor());
417 private void setStats(long start
, long end
, List
<ITmfTreeViewerEntry
> entryList
, AbstractSegmentStatisticsAnalysis module
, boolean isSelection
, IProgressMonitor monitor
) {
418 String label
= isSelection ?
getSelectionLabel() : getTotalLabel();
419 final SegmentStoreStatistics entry
= isSelection ? module
.getTotalStatsForRange(start
, end
, monitor
) : module
.getTotalStats();
422 if (entry
.getNbSegments() == 0) {
425 TmfTreeViewerEntry child
= new SegmentStoreStatisticsEntry(checkNotNull(label
), entry
);
426 entryList
.add(child
);
428 final Map
<@NonNull String
, @NonNull SegmentStoreStatistics
> perTypeStats
= isSelection? module
.getPerSegmentTypeStatsForRange(start
, end
, monitor
) : module
.getPerSegmentTypeStats();
429 if (perTypeStats
!= null) {
430 for (Entry
<@NonNull String
, @NonNull SegmentStoreStatistics
> statsEntry
: perTypeStats
.entrySet()) {
431 child
.addChild(new SegmentStoreStatisticsEntry(statsEntry
.getKey(), statsEntry
.getValue()));
439 public void windowRangeUpdated(@Nullable TmfWindowRangeUpdatedSignal signal
) {
440 // Do nothing. We do not want to update the view and lose the selection
441 // if the window range is updated with current selection outside of this
451 protected String
getTypeLabel() {
452 return checkNotNull(Messages
.AbstractSegmentStoreStatisticsViewer_types
);
456 * Get the total column label
458 * @return the totals column label
461 protected String
getTotalLabel() {
462 return checkNotNull(Messages
.AbstractSegmentStoreStatisticsViewer_total
);
466 * Get the selection column label
468 * @return The selection column label
471 protected String
getSelectionLabel() {
472 return checkNotNull(Messages
.AbstractSegmentStoreStatisticsViewer_selection
);
476 * Class to define a level in the tree that doesn't have any values.
478 protected class HiddenTreeViewerEntry
extends SegmentStoreStatisticsEntry
{
483 * the name of the level
485 public HiddenTreeViewerEntry(String name
) {
486 super(name
, new SegmentStoreStatistics());