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
.statesystem
.TmfStateSystemAnalysisModule
;
41 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
42 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceContext
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
47 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.AbstractTmfTreeViewer
;
48 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.ITmfTreeColumnDataProvider
;
49 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.ITmfTreeViewerEntry
;
50 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.TmfTreeColumnData
;
51 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.tree
.TmfTreeViewerEntry
;
54 * Displays the content of the state systems at the current time
56 * @author Florian Wininger
57 * @author Alexandre Montplaisir
58 * @author Geneviève Bastien
60 public class TmfStateSystemViewer
extends AbstractTmfTreeViewer
{
62 private static final String EMPTY_STRING
= ""; //$NON-NLS-1$
63 private static final int DEFAULT_AUTOEXPAND
= 2;
64 private boolean fFilterStatus
= false;
65 private long fSelection
= 0;
67 /* Order of columns */
68 private static final int ATTRIBUTE_NAME_COL
= 0;
69 private static final int QUARK_COL
= 1;
70 private static final int VALUE_COL
= 2;
71 private static final int TYPE_COL
= 3;
72 private static final int START_TIME_COL
= 4;
73 private static final int END_TIME_COL
= 5;
74 private static final int ATTRIBUTE_FULLPATH_COL
= 6;
77 * Base class to provide the labels for the tree viewer. Views extending
78 * this class typically need to override the getColumnText method if they
79 * have more than one column to display
81 protected static class StateSystemTreeLabelProvider
extends TreeLabelProvider
{
84 public String
getColumnText(Object element
, int columnIndex
) {
85 if (element
instanceof StateEntry
) {
86 StateEntry entry
= (StateEntry
) element
;
87 switch (columnIndex
) {
88 case ATTRIBUTE_NAME_COL
:
89 return entry
.getName();
91 return String
.valueOf(entry
.getQuark());
93 return entry
.getValue();
95 return entry
.getType();
97 return entry
.getStartTime();
99 return entry
.getEndTime();
100 case ATTRIBUTE_FULLPATH_COL
:
101 return entry
.getFullPath();
106 return super.getColumnText(element
, columnIndex
);
110 public Color
getBackground(Object element
, int columnIndex
) {
111 if (element
instanceof StateEntry
) {
112 if (((StateEntry
) element
).isModified()) {
113 return Display
.getCurrent().getSystemColor(SWT
.COLOR_YELLOW
);
116 return super.getBackground(element
, columnIndex
);
124 * The parent containing this viewer
126 public TmfStateSystemViewer(Composite parent
) {
127 super(parent
, false);
128 this.setLabelProvider(new StateSystemTreeLabelProvider());
129 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
133 protected ITmfTreeColumnDataProvider
getColumnDataProvider() {
134 return new ITmfTreeColumnDataProvider() {
137 public List
<TmfTreeColumnData
> getColumnData() {
138 List
<TmfTreeColumnData
> columns
= new ArrayList
<>();
139 TmfTreeColumnData column
= new TmfTreeColumnData(Messages
.TreeNodeColumnLabel
);
141 column
.setComparator(new ViewerComparator() {
143 public int compare(Viewer viewer
, Object e1
, Object e2
) {
144 TmfTreeViewerEntry n1
= (TmfTreeViewerEntry
) e1
;
145 TmfTreeViewerEntry n2
= (TmfTreeViewerEntry
) e2
;
147 return n1
.getName().compareTo(n2
.getName());
150 columns
.add(new TmfTreeColumnData(Messages
.QuarkColumnLabel
));
151 columns
.add(new TmfTreeColumnData(Messages
.ValueColumnLabel
));
152 columns
.add(new TmfTreeColumnData(Messages
.TypeColumnLabel
));
153 columns
.add(new TmfTreeColumnData(Messages
.StartTimeColumLabel
));
154 columns
.add(new TmfTreeColumnData(Messages
.EndTimeColumLabel
));
155 columns
.add(new TmfTreeColumnData(Messages
.AttributePathColumnLabel
));
162 // ------------------------------------------------------------------------
164 // ------------------------------------------------------------------------
167 protected ITmfTreeViewerEntry
updateElements(long start
, long end
, boolean selection
) {
172 TmfTraceContext ctx
= TmfTraceManager
.getInstance().getCurrentTraceContext();
173 fSelection
= ctx
.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
176 if (getTrace() == null) {
180 ITmfTreeViewerEntry root
= getInput();
184 } else if (fFilterStatus
) {
185 clearStateSystemEntries(root
);
189 * Update the values of the elements of the state systems at the
190 * selection start time
192 boolean changed
= updateStateSystemEntries(root
, fSelection
);
194 return selection
|| changed ? root
: null;
197 private ITmfTreeViewerEntry
createRoot() {
199 TmfTreeViewerEntry rootEntry
= new TmfTreeViewerEntry("root"); //$NON-NLS-1$
201 for (final ITmfTrace trace
: TmfTraceManager
.getTraceSetWithExperiment(getTrace())) {
203 rootEntry
.addChild(createTraceEntry(trace
));
209 private static TmfTreeViewerEntry
createTraceEntry(ITmfTrace trace
) {
210 TmfTreeViewerEntry traceEntry
= new TmfTreeViewerEntry(trace
.getName());
211 Iterable
<ITmfAnalysisModuleWithStateSystems
> modules
= TmfTraceUtils
.getAnalysisModulesOfClass(trace
, ITmfAnalysisModuleWithStateSystems
.class);
212 for (ITmfAnalysisModuleWithStateSystems module
: modules
) {
213 /* Just schedule the module, the data will be filled when available */
215 if (module
instanceof TmfStateSystemAnalysisModule
) {
216 // TODO: add this method to ITmfAnalysisModuleWithStateSystems
217 ((TmfStateSystemAnalysisModule
) module
).waitForInitialization();
219 for (ITmfStateSystem ss
: module
.getStateSystems()) {
221 traceEntry
.addChild(new StateSystemEntry(ss
));
228 private static void clearStateSystemEntries(ITmfTreeViewerEntry root
) {
229 for (ITmfTreeViewerEntry traceEntry
: root
.getChildren()) {
230 for (ITmfTreeViewerEntry ssEntry
: traceEntry
.getChildren()) {
231 ssEntry
.getChildren().clear();
236 private boolean updateStateSystemEntries(ITmfTreeViewerEntry root
, long timestamp
) {
237 boolean changed
= false;
238 for (ITmfTreeViewerEntry traceEntry
: root
.getChildren()) {
239 for (ITmfTreeViewerEntry ssEntry
: traceEntry
.getChildren()) {
240 StateSystemEntry stateSystemEntry
= (StateSystemEntry
) ssEntry
;
241 ITmfStateSystem ss
= stateSystemEntry
.getSS();
243 List
<ITmfStateInterval
> fullState
= ss
.queryFullState(timestamp
);
244 changed
|= updateStateEntries(ss
, fullState
, stateSystemEntry
, -1, timestamp
);
245 } catch (TimeRangeException e
) {
246 markOutOfRange(stateSystemEntry
);
248 } catch (StateSystemDisposedException e
) {
256 private boolean updateStateEntries(ITmfStateSystem ss
, List
<ITmfStateInterval
> fullState
, TmfTreeViewerEntry parent
, int parentQuark
, long timestamp
) {
257 boolean changed
= false;
259 for (int quark
: ss
.getSubAttributes(parentQuark
, false)) {
260 if (quark
>= fullState
.size()) {
261 // attribute was created after the full state query
264 ITmfStateInterval interval
= fullState
.get(quark
);
265 StateEntry stateEntry
= findStateEntry(parent
, quark
);
266 if (stateEntry
== null) {
267 boolean modified
= fFilterStatus ?
268 interval
.getStartTime() == timestamp
:
269 !interval
.getStateValue().isNull();
270 stateEntry
= new StateEntry(ss
.getAttributeName(quark
), quark
, ss
.getFullAttributePath(quark
),
271 interval
.getStateValue(),
272 new TmfTimestamp(interval
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
273 new TmfTimestamp(interval
.getEndTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
276 // update children first to know if parent is really needed
277 updateStateEntries(ss
, fullState
, stateEntry
, quark
, timestamp
);
280 * Add this entry to parent if filtering is off, or
281 * if the entry has children to display, or
282 * if there is a state change at the current timestamp
284 if (!fFilterStatus
|| stateEntry
.hasChildren() || interval
.getStartTime() == timestamp
) {
285 parent
.addChild(stateEntry
);
289 stateEntry
.update(interval
.getStateValue(),
290 new TmfTimestamp(interval
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
291 new TmfTimestamp(interval
.getEndTime(), ITmfTimestamp
.NANOSECOND_SCALE
));
293 // update children recursively
294 updateStateEntries(ss
, fullState
, stateEntry
, quark
, timestamp
);
298 } catch (AttributeNotFoundException e
) {
299 /* Should not happen, we're iterating on known attributes */
304 private static StateEntry
findStateEntry(TmfTreeViewerEntry parent
, int quark
) {
305 for (ITmfTreeViewerEntry child
: parent
.getChildren()) {
306 StateEntry stateEntry
= (StateEntry
) child
;
307 if (stateEntry
.getQuark() == quark
) {
314 * Set the entries as out of range
316 private static void markOutOfRange(ITmfTreeViewerEntry parent
) {
317 for (ITmfTreeViewerEntry entry
: parent
.getChildren()) {
318 if (entry
instanceof StateEntry
) {
319 ((StateEntry
) entry
).setOutOfRange();
321 /* Update this node's children recursively */
322 markOutOfRange(entry
);
328 * Set the filter status of the viewer. By default, all entries of all state
329 * system are present, and the values that changed since last refresh are
330 * shown in yellow. When the filter status is true, only the entries with
331 * values modified at current time are displayed.
333 public void changeFilterStatus() {
334 fFilterStatus
= !fFilterStatus
;
336 getTreeViewer().setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
338 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
341 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
345 * Update the display to use the updated timestamp format
348 * the incoming signal
351 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal
) {
352 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
355 private static class StateSystemEntry
extends TmfTreeViewerEntry
{
356 private final @NonNull ITmfStateSystem fSS
;
358 public StateSystemEntry(@NonNull ITmfStateSystem ss
) {
363 public @NonNull ITmfStateSystem
getSS() {
368 private class StateEntry
extends TmfTreeViewerEntry
{
370 private final int fQuark
;
371 private final String fFullPath
;
372 private @NonNull TmfTimestamp fStart
;
373 private @NonNull TmfTimestamp fEnd
;
374 private ITmfStateValue fValue
;
375 private boolean fModified
;
376 private boolean fOutOfRange
= false;
378 public StateEntry(String name
, int quark
, String fullPath
, ITmfStateValue value
, @NonNull TmfTimestamp start
, @NonNull TmfTimestamp end
, boolean modified
) {
381 fFullPath
= fullPath
;
385 fModified
= modified
;
388 public int getQuark() {
392 public String
getFullPath() {
396 public String
getStartTime() {
400 return fStart
.toString();
403 public String
getEndTime() {
407 return fEnd
.toString();
410 public String
getValue() {
412 return Messages
.OutOfRangeMsg
;
414 switch (fValue
.getType()) {
419 return fValue
.toString();
426 public String
getType() {
430 switch (fValue
.getType()) {
432 return Messages
.TypeInteger
;
434 return Messages
.TypeLong
;
436 return Messages
.TypeDouble
;
438 return Messages
.TypeString
;
445 public boolean isModified() {
449 public void update(ITmfStateValue value
, @NonNull TmfTimestamp start
, @NonNull TmfTimestamp end
) {
452 if (!start
.equals(fStart
)) {
460 public void setOutOfRange() {