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 * Patrick Tasse - Refactoring
16 *******************************************************************************/
18 package org
.eclipse
.tracecompass
.tmf
.ui
.views
.statesystem
;
20 import java
.util
.ArrayList
;
21 import java
.util
.List
;
23 import org
.eclipse
.jdt
.annotation
.NonNull
;
24 import org
.eclipse
.jface
.viewers
.AbstractTreeViewer
;
25 import org
.eclipse
.jface
.viewers
.Viewer
;
26 import org
.eclipse
.jface
.viewers
.ViewerComparator
;
27 import org
.eclipse
.swt
.SWT
;
28 import org
.eclipse
.swt
.graphics
.Color
;
29 import org
.eclipse
.swt
.widgets
.Composite
;
30 import org
.eclipse
.swt
.widgets
.Display
;
31 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
32 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
33 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
34 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
35 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
36 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
37 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTimestampFormatUpdateSignal
;
39 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.ITmfAnalysisModuleWithStateSystems
;
40 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
41 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
42 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceContext
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
46 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.AbstractTmfTreeViewer
;
47 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.ITmfTreeColumnDataProvider
;
48 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.ITmfTreeViewerEntry
;
49 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.TmfTreeColumnData
;
50 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.TmfTreeViewerEntry
;
53 * Displays the content of the state systems at the current time
55 * @author Florian Wininger
56 * @author Alexandre Montplaisir
57 * @author Geneviève Bastien
59 public class TmfStateSystemViewer
extends AbstractTmfTreeViewer
{
61 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
62 private static final int DEFAULT_AUTOEXPAND
= 2;
63 private boolean fFilterStatus
= false;
64 private long fSelection
= 0;
66 /* Order of columns */
67 private static final int ATTRIBUTE_NAME_COL
= 0;
68 private static final int QUARK_COL
= 1;
69 private static final int VALUE_COL
= 2;
70 private static final int TYPE_COL
= 3;
71 private static final int START_TIME_COL
= 4;
72 private static final int END_TIME_COL
= 5;
73 private static final int ATTRIBUTE_FULLPATH_COL
= 6;
76 * Base class to provide the labels for the tree viewer. Views extending
77 * this class typically need to override the getColumnText method if they
78 * have more than one column to display
80 protected static class StateSystemTreeLabelProvider
extends TreeLabelProvider
{
83 public String
getColumnText(Object element
, int columnIndex
) {
84 if (element
instanceof StateEntry
) {
85 StateEntry entry
= (StateEntry
) element
;
86 switch (columnIndex
) {
87 case ATTRIBUTE_NAME_COL
:
88 return entry
.getName();
90 return String
.valueOf(entry
.getQuark());
92 return entry
.getValue();
94 return entry
.getType();
96 return entry
.getStartTime();
98 return entry
.getEndTime();
99 case ATTRIBUTE_FULLPATH_COL
:
100 return entry
.getFullPath();
105 return super.getColumnText(element
, columnIndex
);
109 public Color
getBackground(Object element
, int columnIndex
) {
110 if (element
instanceof StateEntry
) {
111 if (((StateEntry
) element
).isModified()) {
112 return Display
.getCurrent().getSystemColor(SWT
.COLOR_YELLOW
);
115 return super.getBackground(element
, columnIndex
);
123 * The parent containing this viewer
125 public TmfStateSystemViewer(Composite parent
) {
126 super(parent
, false);
127 this.setLabelProvider(new StateSystemTreeLabelProvider());
128 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
132 protected ITmfTreeColumnDataProvider
getColumnDataProvider() {
133 return new ITmfTreeColumnDataProvider() {
136 public List
<TmfTreeColumnData
> getColumnData() {
137 List
<TmfTreeColumnData
> columns
= new ArrayList
<>();
138 TmfTreeColumnData column
= new TmfTreeColumnData(Messages
.TreeNodeColumnLabel
);
140 column
.setComparator(new ViewerComparator() {
142 public int compare(Viewer viewer
, Object e1
, Object e2
) {
143 TmfTreeViewerEntry n1
= (TmfTreeViewerEntry
) e1
;
144 TmfTreeViewerEntry n2
= (TmfTreeViewerEntry
) e2
;
146 return n1
.getName().compareTo(n2
.getName());
149 columns
.add(new TmfTreeColumnData(Messages
.QuarkColumnLabel
));
150 columns
.add(new TmfTreeColumnData(Messages
.ValueColumnLabel
));
151 columns
.add(new TmfTreeColumnData(Messages
.TypeColumnLabel
));
152 columns
.add(new TmfTreeColumnData(Messages
.StartTimeColumLabel
));
153 columns
.add(new TmfTreeColumnData(Messages
.EndTimeColumLabel
));
154 columns
.add(new TmfTreeColumnData(Messages
.AttributePathColumnLabel
));
161 // ------------------------------------------------------------------------
163 // ------------------------------------------------------------------------
166 protected ITmfTreeViewerEntry
updateElements(long start
, long end
, boolean selection
) {
171 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
172 fSelection
= ctx
.getSelectionRange().getStartTime().toNanos();
175 if (getTrace() == null) {
179 ITmfTreeViewerEntry root
= getInput();
183 } else if (fFilterStatus
) {
184 clearStateSystemEntries(root
);
188 * Update the values of the elements of the state systems at the
189 * selection start time
191 boolean changed
= updateStateSystemEntries(root
, fSelection
);
193 return selection
|| changed ? root
: null;
196 private ITmfTreeViewerEntry
createRoot() {
198 TmfTreeViewerEntry rootEntry
= new TmfTreeViewerEntry("root"); //$NON-NLS-1$
200 for (final ITmfTrace trace
: TmfTraceManager
.getTraceSetWithExperiment(getTrace())) {
202 rootEntry
.addChild(createTraceEntry(trace
));
208 private static TmfTreeViewerEntry
createTraceEntry(ITmfTrace trace
) {
209 TmfTreeViewerEntry traceEntry
= new TmfTreeViewerEntry(trace
.getName());
210 Iterable
<ITmfAnalysisModuleWithStateSystems
> modules
= TmfTraceUtils
.getAnalysisModulesOfClass(trace
, ITmfAnalysisModuleWithStateSystems
.class);
211 for (ITmfAnalysisModuleWithStateSystems module
: modules
) {
212 /* Just schedule the module, the data will be filled when available */
214 module
.waitForInitialization();
215 for (ITmfStateSystem ss
: module
.getStateSystems()) {
216 traceEntry
.addChild(new StateSystemEntry(ss
));
222 private static void clearStateSystemEntries(ITmfTreeViewerEntry root
) {
223 for (ITmfTreeViewerEntry traceEntry
: root
.getChildren()) {
224 for (ITmfTreeViewerEntry ssEntry
: traceEntry
.getChildren()) {
225 ssEntry
.getChildren().clear();
230 private boolean updateStateSystemEntries(ITmfTreeViewerEntry root
, long timestamp
) {
231 boolean changed
= false;
232 for (ITmfTreeViewerEntry traceEntry
: root
.getChildren()) {
233 for (ITmfTreeViewerEntry ssEntry
: traceEntry
.getChildren()) {
234 StateSystemEntry stateSystemEntry
= (StateSystemEntry
) ssEntry
;
235 ITmfStateSystem ss
= stateSystemEntry
.getSS();
237 List
<ITmfStateInterval
> fullState
= ss
.queryFullState(timestamp
);
238 changed
|= updateStateEntries(ss
, fullState
, stateSystemEntry
, -1, timestamp
);
239 } catch (TimeRangeException e
) {
240 markOutOfRange(stateSystemEntry
);
242 } catch (StateSystemDisposedException e
) {
250 private boolean updateStateEntries(ITmfStateSystem ss
, List
<ITmfStateInterval
> fullState
, TmfTreeViewerEntry parent
, int parentQuark
, long timestamp
) {
251 boolean changed
= false;
253 for (int quark
: ss
.getSubAttributes(parentQuark
, false)) {
254 if (quark
>= fullState
.size()) {
255 // attribute was created after the full state query
258 ITmfStateInterval interval
= fullState
.get(quark
);
259 StateEntry stateEntry
= findStateEntry(parent
, quark
);
260 if (stateEntry
== null) {
261 boolean modified
= fFilterStatus ?
262 interval
.getStartTime() == timestamp
:
263 !interval
.getStateValue().isNull();
264 stateEntry
= new StateEntry(ss
.getAttributeName(quark
), quark
, ss
.getFullAttributePath(quark
),
265 interval
.getStateValue(),
266 new TmfTimestamp(interval
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
267 new TmfTimestamp(interval
.getEndTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
270 // update children first to know if parent is really needed
271 updateStateEntries(ss
, fullState
, stateEntry
, quark
, timestamp
);
274 * Add this entry to parent if filtering is off, or
275 * if the entry has children to display, or
276 * if there is a state change at the current timestamp
278 if (!fFilterStatus
|| stateEntry
.hasChildren() || interval
.getStartTime() == timestamp
) {
279 parent
.addChild(stateEntry
);
283 stateEntry
.update(interval
.getStateValue(),
284 new TmfTimestamp(interval
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
285 new TmfTimestamp(interval
.getEndTime(), ITmfTimestamp
.NANOSECOND_SCALE
));
287 // update children recursively
288 updateStateEntries(ss
, fullState
, stateEntry
, quark
, timestamp
);
292 } catch (AttributeNotFoundException e
) {
293 /* Should not happen, we're iterating on known attributes */
298 private static StateEntry
findStateEntry(TmfTreeViewerEntry parent
, int quark
) {
299 for (ITmfTreeViewerEntry child
: parent
.getChildren()) {
300 StateEntry stateEntry
= (StateEntry
) child
;
301 if (stateEntry
.getQuark() == quark
) {
308 * Set the entries as out of range
310 private static void markOutOfRange(ITmfTreeViewerEntry parent
) {
311 for (ITmfTreeViewerEntry entry
: parent
.getChildren()) {
312 if (entry
instanceof StateEntry
) {
313 ((StateEntry
) entry
).setOutOfRange();
315 /* Update this node's children recursively */
316 markOutOfRange(entry
);
322 * Set the filter status of the viewer. By default, all entries of all state
323 * system are present, and the values that changed since last refresh are
324 * shown in yellow. When the filter status is true, only the entries with
325 * values modified at current time are displayed.
327 public void changeFilterStatus() {
328 fFilterStatus
= !fFilterStatus
;
330 getTreeViewer().setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
332 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
335 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
339 * Update the display to use the updated timestamp format
342 * the incoming signal
345 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal
) {
346 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
349 private static class StateSystemEntry
extends TmfTreeViewerEntry
{
350 private final @NonNull ITmfStateSystem fSS
;
352 public StateSystemEntry(@NonNull ITmfStateSystem ss
) {
357 public @NonNull ITmfStateSystem
getSS() {
362 private class StateEntry
extends TmfTreeViewerEntry
{
364 private final int fQuark
;
365 private final String fFullPath
;
366 private @NonNull TmfTimestamp fStart
;
367 private @NonNull TmfTimestamp fEnd
;
368 private ITmfStateValue fValue
;
369 private boolean fModified
;
370 private boolean fOutOfRange
= false;
372 public StateEntry(String name
, int quark
, String fullPath
, ITmfStateValue value
, @NonNull TmfTimestamp start
, @NonNull TmfTimestamp end
, boolean modified
) {
375 fFullPath
= fullPath
;
379 fModified
= modified
;
382 public int getQuark() {
386 public String
getFullPath() {
390 public String
getStartTime() {
394 return fStart
.toString();
397 public String
getEndTime() {
401 return fEnd
.toString();
404 public String
getValue() {
406 return Messages
.OutOfRangeMsg
;
408 switch (fValue
.getType()) {
413 return fValue
.toString();
420 public String
getType() {
424 switch (fValue
.getType()) {
426 return Messages
.TypeInteger
;
428 return Messages
.TypeLong
;
430 return Messages
.TypeDouble
;
432 return Messages
.TypeString
;
439 public boolean isModified() {
443 public void update(ITmfStateValue value
, @NonNull TmfTimestamp start
, @NonNull TmfTimestamp end
) {
446 if (!start
.equals(fStart
)) {
454 public void setOutOfRange() {