1 /*******************************************************************************
2 * Copyright (c) 2014, 2016 École Polytechnique de Montréal and others.
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
.StateSystemDisposedException
;
33 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
34 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
35 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
36 import org
.eclipse
.tracecompass
.tmf
.core
.analysis
.IAnalysisModule
;
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
.ui
.viewers
.tree
.AbstractTmfTreeViewer
;
46 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.ITmfTreeColumnDataProvider
;
47 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.ITmfTreeViewerEntry
;
48 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.TmfTreeColumnData
;
49 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.TmfTreeViewerEntry
;
52 * Displays the content of the state systems at the current time
54 * @author Florian Wininger
55 * @author Alexandre Montplaisir
56 * @author Geneviève Bastien
58 public class TmfStateSystemViewer
extends AbstractTmfTreeViewer
{
60 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
61 private static final int DEFAULT_AUTOEXPAND
= 2;
62 private boolean fFilterStatus
= false;
63 private long fSelection
= 0;
65 /* Order of columns */
66 private static final int ATTRIBUTE_NAME_COL
= 0;
67 private static final int QUARK_COL
= 1;
68 private static final int VALUE_COL
= 2;
69 private static final int TYPE_COL
= 3;
70 private static final int START_TIME_COL
= 4;
71 private static final int END_TIME_COL
= 5;
72 private static final int ATTRIBUTE_FULLPATH_COL
= 6;
75 * Base class to provide the labels for the tree viewer. Views extending
76 * this class typically need to override the getColumnText method if they
77 * have more than one column to display
79 protected static class StateSystemTreeLabelProvider
extends TreeLabelProvider
{
82 public String
getColumnText(Object element
, int columnIndex
) {
83 if (element
instanceof StateEntry
) {
84 StateEntry entry
= (StateEntry
) element
;
85 switch (columnIndex
) {
86 case ATTRIBUTE_NAME_COL
:
87 return entry
.getName();
89 return String
.valueOf(entry
.getQuark());
91 return entry
.getValue();
93 return entry
.getType();
95 return entry
.getStartTime();
97 return entry
.getEndTime();
98 case ATTRIBUTE_FULLPATH_COL
:
99 return entry
.getFullPath();
104 return super.getColumnText(element
, columnIndex
);
108 public Color
getBackground(Object element
, int columnIndex
) {
109 if (element
instanceof StateEntry
) {
110 if (((StateEntry
) element
).isModified()) {
111 return Display
.getCurrent().getSystemColor(SWT
.COLOR_YELLOW
);
114 return super.getBackground(element
, columnIndex
);
122 * The parent containing this viewer
124 public TmfStateSystemViewer(Composite parent
) {
125 super(parent
, false);
126 this.setLabelProvider(new StateSystemTreeLabelProvider());
127 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
131 protected ITmfTreeColumnDataProvider
getColumnDataProvider() {
132 return new ITmfTreeColumnDataProvider() {
135 public List
<TmfTreeColumnData
> getColumnData() {
136 List
<TmfTreeColumnData
> columns
= new ArrayList
<>();
137 TmfTreeColumnData column
= new TmfTreeColumnData(Messages
.TreeNodeColumnLabel
);
139 column
.setComparator(new ViewerComparator() {
141 public int compare(Viewer viewer
, Object e1
, Object e2
) {
142 TmfTreeViewerEntry n1
= (TmfTreeViewerEntry
) e1
;
143 TmfTreeViewerEntry n2
= (TmfTreeViewerEntry
) e2
;
145 return n1
.getName().compareTo(n2
.getName());
148 columns
.add(new TmfTreeColumnData(Messages
.QuarkColumnLabel
));
149 columns
.add(new TmfTreeColumnData(Messages
.ValueColumnLabel
));
150 columns
.add(new TmfTreeColumnData(Messages
.TypeColumnLabel
));
151 columns
.add(new TmfTreeColumnData(Messages
.StartTimeColumLabel
));
152 columns
.add(new TmfTreeColumnData(Messages
.EndTimeColumLabel
));
153 columns
.add(new TmfTreeColumnData(Messages
.AttributePathColumnLabel
));
160 // ------------------------------------------------------------------------
162 // ------------------------------------------------------------------------
165 protected ITmfTreeViewerEntry
updateElements(long start
, long end
, boolean selection
) {
170 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
171 fSelection
= ctx
.getSelectionRange().getStartTime().toNanos();
174 if (getTrace() == null) {
178 ITmfTreeViewerEntry root
= getInput();
182 } else if (fFilterStatus
) {
183 clearStateSystemEntries(root
);
187 * Update the values of the elements of the state systems at the
188 * selection start time
190 boolean changed
= updateStateSystemEntries(root
, fSelection
);
192 return selection
|| changed ? root
: null;
195 private ITmfTreeViewerEntry
createRoot() {
197 TmfTreeViewerEntry rootEntry
= new TmfTreeViewerEntry("root"); //$NON-NLS-1$
199 for (final ITmfTrace trace
: TmfTraceManager
.getTraceSetWithExperiment(getTrace())) {
200 rootEntry
.addChild(createTraceEntry(trace
));
205 private static TmfTreeViewerEntry
createTraceEntry(ITmfTrace trace
) {
206 TmfTreeViewerEntry traceEntry
= new TmfTreeViewerEntry(trace
.getName());
207 Iterable
<IAnalysisModule
> modules
= trace
.getAnalysisModules();
208 for (IAnalysisModule module
: modules
) {
209 if (module
instanceof ITmfAnalysisModuleWithStateSystems
) {
210 ITmfAnalysisModuleWithStateSystems moduleWithStateSystem
= (ITmfAnalysisModuleWithStateSystems
) module
;
212 * Just schedule the module, the data will be filled when
215 moduleWithStateSystem
.schedule();
216 if (!moduleWithStateSystem
.waitForInitialization()) {
219 for (ITmfStateSystem ss
: moduleWithStateSystem
.getStateSystems()) {
220 traceEntry
.addChild(new StateSystemEntry(ss
));
227 private static void clearStateSystemEntries(ITmfTreeViewerEntry root
) {
228 for (ITmfTreeViewerEntry traceEntry
: root
.getChildren()) {
229 for (ITmfTreeViewerEntry ssEntry
: traceEntry
.getChildren()) {
230 ssEntry
.getChildren().clear();
235 private boolean updateStateSystemEntries(ITmfTreeViewerEntry root
, long timestamp
) {
236 boolean changed
= false;
237 for (ITmfTreeViewerEntry traceEntry
: root
.getChildren()) {
238 for (ITmfTreeViewerEntry ssEntry
: traceEntry
.getChildren()) {
239 StateSystemEntry stateSystemEntry
= (StateSystemEntry
) ssEntry
;
240 ITmfStateSystem ss
= stateSystemEntry
.getSS();
242 List
<ITmfStateInterval
> fullState
= ss
.queryFullState(timestamp
);
243 changed
|= updateStateEntries(ss
, fullState
, stateSystemEntry
, -1, timestamp
);
244 } catch (TimeRangeException e
) {
245 markOutOfRange(stateSystemEntry
);
247 } catch (StateSystemDisposedException e
) {
255 private boolean updateStateEntries(ITmfStateSystem ss
, List
<ITmfStateInterval
> fullState
, TmfTreeViewerEntry parent
, int parentQuark
, long timestamp
) {
256 boolean changed
= false;
257 for (int quark
: ss
.getSubAttributes(parentQuark
, false)) {
258 if (quark
>= fullState
.size()) {
259 // attribute was created after the full state query
262 ITmfStateInterval interval
= fullState
.get(quark
);
263 StateEntry stateEntry
= findStateEntry(parent
, quark
);
264 if (stateEntry
== null) {
265 boolean modified
= fFilterStatus ?
266 interval
.getStartTime() == timestamp
:
267 !interval
.getStateValue().isNull();
268 stateEntry
= new StateEntry(ss
.getAttributeName(quark
), quark
, ss
.getFullAttributePath(quark
),
269 interval
.getStateValue(),
270 TmfTimestamp
.fromNanos(interval
.getStartTime()),
271 TmfTimestamp
.fromNanos(interval
.getEndTime()),
274 // update children first to know if parent is really needed
275 updateStateEntries(ss
, fullState
, stateEntry
, quark
, timestamp
);
278 * Add this entry to parent if filtering is off, or
279 * if the entry has children to display, or
280 * if there is a state change at the current timestamp
282 if (!fFilterStatus
|| stateEntry
.hasChildren() || interval
.getStartTime() == timestamp
) {
283 parent
.addChild(stateEntry
);
287 stateEntry
.update(interval
.getStateValue(),
288 TmfTimestamp
.fromNanos(interval
.getStartTime()),
289 TmfTimestamp
.fromNanos(interval
.getEndTime()));
291 // update children recursively
292 updateStateEntries(ss
, fullState
, stateEntry
, quark
, timestamp
);
299 private static StateEntry
findStateEntry(TmfTreeViewerEntry parent
, int quark
) {
300 for (ITmfTreeViewerEntry child
: parent
.getChildren()) {
301 StateEntry stateEntry
= (StateEntry
) child
;
302 if (stateEntry
.getQuark() == quark
) {
309 * Set the entries as out of range
311 private static void markOutOfRange(ITmfTreeViewerEntry parent
) {
312 for (ITmfTreeViewerEntry entry
: parent
.getChildren()) {
313 if (entry
instanceof StateEntry
) {
314 ((StateEntry
) entry
).setOutOfRange();
316 /* Update this node's children recursively */
317 markOutOfRange(entry
);
323 * Set the filter status of the viewer. By default, all entries of all state
324 * system are present, and the values that changed since last refresh are
325 * shown in yellow. When the filter status is true, only the entries with
326 * values modified at current time are displayed.
328 public void changeFilterStatus() {
329 fFilterStatus
= !fFilterStatus
;
331 getTreeViewer().setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
333 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
336 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
340 * Update the display to use the updated timestamp format
343 * the incoming signal
346 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal
) {
347 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
350 private static class StateSystemEntry
extends TmfTreeViewerEntry
{
351 private final @NonNull ITmfStateSystem fSS
;
353 public StateSystemEntry(@NonNull ITmfStateSystem ss
) {
358 public @NonNull ITmfStateSystem
getSS() {
363 private class StateEntry
extends TmfTreeViewerEntry
{
365 private final int fQuark
;
366 private final String fFullPath
;
367 private @NonNull ITmfTimestamp fStart
;
368 private @NonNull ITmfTimestamp fEnd
;
369 private ITmfStateValue fValue
;
370 private boolean fModified
;
371 private boolean fOutOfRange
= false;
373 public StateEntry(String name
, int quark
, String fullPath
, ITmfStateValue value
, @NonNull ITmfTimestamp start
, @NonNull ITmfTimestamp end
, boolean modified
) {
376 fFullPath
= fullPath
;
380 fModified
= modified
;
383 public int getQuark() {
387 public String
getFullPath() {
391 public String
getStartTime() {
395 return fStart
.toString();
398 public String
getEndTime() {
402 return fEnd
.toString();
405 public String
getValue() {
407 return Messages
.OutOfRangeMsg
;
409 switch (fValue
.getType()) {
415 return fValue
.toString();
422 public String
getType() {
426 switch (fValue
.getType()) {
428 return Messages
.TypeInteger
;
430 return Messages
.TypeLong
;
432 return Messages
.TypeDouble
;
434 return Messages
.TypeString
;
436 return Messages
.TypeCustom
;
443 public boolean isModified() {
447 public void update(ITmfStateValue value
, @NonNull ITmfTimestamp start
, @NonNull ITmfTimestamp end
) {
450 if (!start
.equals(fStart
)) {
458 public void setOutOfRange() {