1 /*******************************************************************************
2 * Copyright (c) 2014 École Polytechnique de Montréal
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
10 * Florian Wininger - Initial API and implementation
11 * Alexandre Montplaisir - Refactoring, performance tweaks
12 * Bernd Hufmann - Updated signal handling
13 * Marc-Andre Laperle - Add time zone preference
14 * Geneviève Bastien - Moved state system explorer to use the abstract tree viewer
15 *******************************************************************************/
17 package org
.eclipse
.linuxtools
.tmf
.ui
.views
.statesystem
;
19 import java
.util
.ArrayList
;
20 import java
.util
.List
;
22 import org
.eclipse
.jdt
.annotation
.NonNull
;
23 import org
.eclipse
.jface
.viewers
.AbstractTreeViewer
;
24 import org
.eclipse
.jface
.viewers
.Viewer
;
25 import org
.eclipse
.jface
.viewers
.ViewerComparator
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.AttributeNotFoundException
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateSystemDisposedException
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimestampFormatUpdateSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.ITmfAnalysisModuleWithStateSystems
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.ITmfStateSystem
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTraceManager
;
39 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.tree
.AbstractTmfTreeViewer
;
40 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.tree
.ITmfTreeColumnDataProvider
;
41 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.tree
.ITmfTreeViewerEntry
;
42 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.tree
.TmfTreeColumnData
;
43 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.tree
.TmfTreeViewerEntry
;
44 import org
.eclipse
.swt
.SWT
;
45 import org
.eclipse
.swt
.graphics
.Color
;
46 import org
.eclipse
.swt
.widgets
.Composite
;
47 import org
.eclipse
.swt
.widgets
.Display
;
50 * Displays the content of the state systems at the current time
52 * @author Florian Wininger
53 * @author Alexandre Montplaisir
54 * @author Geneviève Bastien
57 public class TmfStateSystemViewer
extends AbstractTmfTreeViewer
{
59 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
60 private boolean fFilterStatus
= false;
61 private static final int DEFAULT_AUTOEXPAND
= 2;
63 /* Order of columns */
64 private static final int ATTRIBUTE_NAME_COL
= 0;
65 private static final int QUARK_COL
= 1;
66 private static final int VALUE_COL
= 2;
67 private static final int TYPE_COL
= 3;
68 private static final int START_TIME_COL
= 4;
69 private static final int END_TIME_COL
= 5;
70 private static final int ATTRIBUTE_FULLPATH_COL
= 6;
73 * Base class to provide the labels for the tree viewer. Views extending
74 * this class typically need to override the getColumnText method if they
75 * have more than one column to display
77 protected static class StateSystemTreeLabelProvider
extends TreeLabelProvider
{
80 public String
getColumnText(Object element
, int columnIndex
) {
81 if (element
instanceof StateSystemEntry
) {
82 StateSystemEntry entry
= (StateSystemEntry
) element
;
83 switch (columnIndex
) {
84 case ATTRIBUTE_NAME_COL
:
85 return entry
.getName();
87 return String
.valueOf(entry
.getQuark());
89 return entry
.getValue();
91 return entry
.getType();
93 return entry
.getStartTime();
95 return entry
.getEndTime();
96 case ATTRIBUTE_FULLPATH_COL
:
97 return entry
.getFullPath();
102 return super.getColumnText(element
, columnIndex
);
106 public Color
getBackground(Object element
, int columnIndex
) {
107 if (element
instanceof StateSystemEntry
) {
108 if (((StateSystemEntry
) element
).isModified()) {
109 return Display
.getCurrent().getSystemColor(SWT
.COLOR_YELLOW
);
112 return super.getBackground(element
, columnIndex
);
120 * The parent containing this viewer
122 public TmfStateSystemViewer(Composite parent
) {
123 super(parent
, false);
124 this.setLabelProvider(new StateSystemTreeLabelProvider());
125 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
129 protected ITmfTreeColumnDataProvider
getColumnDataProvider() {
130 return new ITmfTreeColumnDataProvider() {
133 public List
<TmfTreeColumnData
> getColumnData() {
134 List
<TmfTreeColumnData
> columns
= new ArrayList
<>();
135 TmfTreeColumnData column
= new TmfTreeColumnData(Messages
.TreeNodeColumnLabel
);
137 column
.setComparator(new ViewerComparator() {
139 public int compare(Viewer viewer
, Object e1
, Object e2
) {
140 TmfTreeViewerEntry n1
= (TmfTreeViewerEntry
) e1
;
141 TmfTreeViewerEntry n2
= (TmfTreeViewerEntry
) e2
;
143 return n1
.getName().compareTo(n2
.getName());
146 columns
.add(new TmfTreeColumnData(Messages
.QuarkColumnLabel
));
147 columns
.add(new TmfTreeColumnData(Messages
.ValueColumnLabel
));
148 columns
.add(new TmfTreeColumnData(Messages
.TypeColumnLabel
));
149 columns
.add(new TmfTreeColumnData(Messages
.StartTimeColumLabel
));
150 columns
.add(new TmfTreeColumnData(Messages
.EndTimeColumLabel
));
151 columns
.add(new TmfTreeColumnData(Messages
.AttributePathColumnLabel
));
158 // ------------------------------------------------------------------------
160 // ------------------------------------------------------------------------
163 protected List
<ITmfTreeViewerEntry
> updateElements(long start
, long end
, boolean selection
) {
164 if (getTrace() == null) {
168 List
<ITmfTreeViewerEntry
> entries
= (List
<ITmfTreeViewerEntry
>) getInput();
170 if ((!selection
) && (entries
!= null)) {
175 * Build the entries if it is the first time or to show only modified
178 if (entries
== null || fFilterStatus
) {
179 entries
= buildEntriesList(start
);
182 * Update the values of the elements of the state systems at time
185 entries
= updateEntriesList(entries
, start
);
191 private List
<ITmfTreeViewerEntry
> buildEntriesList(long timestamp
) {
192 List
<ITmfTreeViewerEntry
> rootEntries
= new ArrayList
<>();
193 for (final ITmfTrace currentTrace
: TmfTraceManager
.getTraceSet(getTrace())) {
194 if (currentTrace
== null) {
197 buildEntriesForTrace(currentTrace
, timestamp
, rootEntries
);
203 * Update the values of the entries. It will also create trace and state
204 * system entries if they do not exist yet.
206 private List
<ITmfTreeViewerEntry
> updateEntriesList(List
<ITmfTreeViewerEntry
> entries
, long timestamp
) {
207 for (final ITmfTrace trace
: TmfTraceManager
.getTraceSet(getTrace())) {
211 ITmfTreeViewerEntry traceEntry
= null;
212 for (ITmfTreeViewerEntry entry
: entries
) {
213 if (entry
.getName().equals(trace
.getName())) {
217 if (traceEntry
== null) {
218 traceEntry
= buildEntriesForTrace(trace
, timestamp
, entries
);
221 /* Find the state system entries for this trace */
222 Iterable
<ITmfAnalysisModuleWithStateSystems
> modules
= trace
.getAnalysisModulesOfClass(ITmfAnalysisModuleWithStateSystems
.class);
223 for (ITmfAnalysisModuleWithStateSystems module
: modules
) {
225 for (ITmfStateSystem ss
: module
.getStateSystems()) {
229 ITmfTreeViewerEntry ssEntry
= null;
230 for (ITmfTreeViewerEntry entry
: traceEntry
.getChildren()) {
231 if (entry
.getName().equals(ss
.getSSID())) {
236 if (ssEntry
== null) {
237 /* The state system entry has not been built yet */
238 buildEntriesForStateSystem(ss
, timestamp
, (TmfTreeViewerEntry
) traceEntry
);
239 } else if (ssEntry
.hasChildren()) {
241 * Typical case at this point, update the data from the
244 updateEntriesForStateSystem(ss
, timestamp
, (TmfTreeViewerEntry
) ssEntry
);
247 * The state system existed but entries were not filled,
248 * that would occur if for instance the values were out
249 * of range at the first query.
251 fillEntriesForStateSystem(ss
, timestamp
, (TmfTreeViewerEntry
) ssEntry
);
260 private ITmfTreeViewerEntry
buildEntriesForTrace(@NonNull ITmfTrace trace
, long timestamp
, @NonNull List
<ITmfTreeViewerEntry
> rootEntries
) {
261 TmfTreeViewerEntry traceEntry
= new TmfTreeViewerEntry(trace
.getName());
262 rootEntries
.add(traceEntry
);
264 Iterable
<ITmfAnalysisModuleWithStateSystems
> modules
= trace
.getAnalysisModulesOfClass(ITmfAnalysisModuleWithStateSystems
.class);
265 for (ITmfAnalysisModuleWithStateSystems module
: modules
) {
266 /* Just schedule the module, the data will be filled when available */
268 for (ITmfStateSystem ss
: module
.getStateSystems()) {
272 buildEntriesForStateSystem(ss
, timestamp
, traceEntry
);
278 private void buildEntriesForStateSystem(ITmfStateSystem ss
, long timestamp
, TmfTreeViewerEntry traceEntry
) {
279 TmfTreeViewerEntry ssEntry
= new TmfTreeViewerEntry(ss
.getSSID());
280 traceEntry
.addChild(ssEntry
);
281 fillEntriesForStateSystem(ss
, timestamp
, ssEntry
);
284 private void fillEntriesForStateSystem(ITmfStateSystem ss
, long timestamp
, TmfTreeViewerEntry ssEntry
) {
286 addChildren(ss
, ss
.queryFullState(timestamp
), -1, ssEntry
, timestamp
);
287 } catch (StateSystemDisposedException
| TimeRangeException e
) {
293 * Add children node to an entry. It will create all necessary entries.
295 private void addChildren(ITmfStateSystem ss
, List
<ITmfStateInterval
> fullState
, int rootQuark
, TmfTreeViewerEntry root
, long timestamp
) {
297 for (int quark
: ss
.getSubAttributes(rootQuark
, false)) {
299 ITmfStateInterval interval
= fullState
.get(quark
);
301 StateSystemEntry entry
= new StateSystemEntry(ss
.getAttributeName(quark
), quark
, ss
.getFullAttributePath(quark
),
302 interval
.getStateValue(),
303 new TmfTimestamp(interval
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
304 new TmfTimestamp(interval
.getEndTime(), ITmfTimestamp
.NANOSECOND_SCALE
));
306 /* Add this node's children recursively */
307 addChildren(ss
, fullState
, quark
, entry
, timestamp
);
311 * Do not add this entry to root if
312 * 1- the filter status is ON
314 * 2- the entry has no children
316 * 3- the start time is not the current timestamp
319 if (!(fFilterStatus
&& !entry
.hasChildren() && (interval
.getStartTime() != timestamp
))) {
320 root
.addChild(entry
);
324 } catch (AttributeNotFoundException e
) {
325 /* Should not happen, we're iterating on known attributes */
326 throw new RuntimeException();
330 private void updateEntriesForStateSystem(ITmfStateSystem ss
, long timestamp
, TmfTreeViewerEntry ssEntry
) {
332 updateChildren(ss
, ss
.queryFullState(timestamp
), ssEntry
);
333 } catch (StateSystemDisposedException e
) {
334 } catch (TimeRangeException e
) {
335 /* Mark all entries out of range */
336 markOutOfRange(ssEntry
);
341 * Update the values of existing entries.
343 private void updateChildren(ITmfStateSystem ss
, List
<ITmfStateInterval
> fullState
, ITmfTreeViewerEntry root
) {
344 for (ITmfTreeViewerEntry entry
: root
.getChildren()) {
345 if (entry
instanceof StateSystemEntry
) {
347 * FIXME: if new sub attributes were added since the element was
348 * built, then then will not be added
350 StateSystemEntry ssEntry
= (StateSystemEntry
) entry
;
351 ITmfStateInterval interval
= fullState
.get(ssEntry
.getQuark());
352 if (interval
!= null) {
353 ssEntry
.update(interval
.getStateValue(), new TmfTimestamp(interval
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
354 new TmfTimestamp(interval
.getEndTime(), ITmfTimestamp
.NANOSECOND_SCALE
));
357 /* Update this node's children recursively */
358 updateChildren(ss
, fullState
, ssEntry
);
364 * Set the entries as out of range
366 private void markOutOfRange(ITmfTreeViewerEntry root
) {
367 for (ITmfTreeViewerEntry entry
: root
.getChildren()) {
368 if (entry
instanceof StateSystemEntry
) {
369 ((StateSystemEntry
) entry
).setOutOfRange();
371 /* Update this node's children recursively */
372 markOutOfRange(entry
);
378 * Set the filter status of the viewer. By default, all entries of all state
379 * system are present, and the values that changed since last refresh are
380 * shown in yellow. When the filter status is true, only the entries with
381 * values modified at current time are displayed.
383 public void changeFilterStatus() {
384 fFilterStatus
= !fFilterStatus
;
386 getTreeViewer().setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
388 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
391 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
395 * Update the display to use the updated timestamp format
398 * the incoming signal
401 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal
) {
402 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
405 private class StateSystemEntry
extends TmfTreeViewerEntry
{
407 private final int fQuark
;
408 private final String fFullPath
;
409 private @NonNull TmfTimestamp fStart
;
410 private @NonNull TmfTimestamp fEnd
;
411 private ITmfStateValue fValue
;
412 private boolean fModified
= false;
413 private boolean fOutOfRange
= false;
415 public StateSystemEntry(String name
, int quark
, String fullPath
, ITmfStateValue value
, @NonNull TmfTimestamp start
, @NonNull TmfTimestamp end
) {
418 fFullPath
= fullPath
;
424 public int getQuark() {
428 public String
getFullPath() {
432 public String
getStartTime() {
436 return fStart
.toString();
439 public String
getEndTime() {
443 return fEnd
.toString();
446 public String
getValue() {
448 return Messages
.OutOfRangeMsg
;
450 switch (fValue
.getType()) {
455 return fValue
.toString();
462 public String
getType() {
466 switch (fValue
.getType()) {
468 return Messages
.TypeInteger
;
470 return Messages
.TypeLong
;
472 return Messages
.TypeDouble
;
474 return Messages
.TypeString
;
481 public boolean isModified() {
485 public void update(ITmfStateValue value
, @NonNull TmfTimestamp start
, @NonNull TmfTimestamp end
) {
488 if (!start
.equals(fStart
)) {
496 public void setOutOfRange() {