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
.analysis
.IAnalysisModule
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
39 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTimestampFormatUpdateSignal
;
40 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.ITmfAnalysisModuleWithStateSystems
;
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
.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
<IAnalysisModule
> modules
= trace
.getAnalysisModules();
211 for (IAnalysisModule module
: modules
) {
212 if (module
instanceof ITmfAnalysisModuleWithStateSystems
) {
213 ITmfAnalysisModuleWithStateSystems moduleWithStateSystem
= (ITmfAnalysisModuleWithStateSystems
) module
;
215 * Just schedule the module, the data will be filled when
218 moduleWithStateSystem
.schedule();
219 if (!moduleWithStateSystem
.waitForInitialization()) {
222 for (ITmfStateSystem ss
: moduleWithStateSystem
.getStateSystems()) {
223 traceEntry
.addChild(new StateSystemEntry(ss
));
230 private static void clearStateSystemEntries(ITmfTreeViewerEntry root
) {
231 for (ITmfTreeViewerEntry traceEntry
: root
.getChildren()) {
232 for (ITmfTreeViewerEntry ssEntry
: traceEntry
.getChildren()) {
233 ssEntry
.getChildren().clear();
238 private boolean updateStateSystemEntries(ITmfTreeViewerEntry root
, long timestamp
) {
239 boolean changed
= false;
240 for (ITmfTreeViewerEntry traceEntry
: root
.getChildren()) {
241 for (ITmfTreeViewerEntry ssEntry
: traceEntry
.getChildren()) {
242 StateSystemEntry stateSystemEntry
= (StateSystemEntry
) ssEntry
;
243 ITmfStateSystem ss
= stateSystemEntry
.getSS();
245 List
<ITmfStateInterval
> fullState
= ss
.queryFullState(timestamp
);
246 changed
|= updateStateEntries(ss
, fullState
, stateSystemEntry
, -1, timestamp
);
247 } catch (TimeRangeException e
) {
248 markOutOfRange(stateSystemEntry
);
250 } catch (StateSystemDisposedException e
) {
258 private boolean updateStateEntries(ITmfStateSystem ss
, List
<ITmfStateInterval
> fullState
, TmfTreeViewerEntry parent
, int parentQuark
, long timestamp
) {
259 boolean changed
= false;
261 for (int quark
: ss
.getSubAttributes(parentQuark
, false)) {
262 if (quark
>= fullState
.size()) {
263 // attribute was created after the full state query
266 ITmfStateInterval interval
= fullState
.get(quark
);
267 StateEntry stateEntry
= findStateEntry(parent
, quark
);
268 if (stateEntry
== null) {
269 boolean modified
= fFilterStatus ?
270 interval
.getStartTime() == timestamp
:
271 !interval
.getStateValue().isNull();
272 stateEntry
= new StateEntry(ss
.getAttributeName(quark
), quark
, ss
.getFullAttributePath(quark
),
273 interval
.getStateValue(),
274 TmfTimestamp
.fromNanos(interval
.getStartTime()),
275 TmfTimestamp
.fromNanos(interval
.getEndTime()),
278 // update children first to know if parent is really needed
279 updateStateEntries(ss
, fullState
, stateEntry
, quark
, timestamp
);
282 * Add this entry to parent if filtering is off, or
283 * if the entry has children to display, or
284 * if there is a state change at the current timestamp
286 if (!fFilterStatus
|| stateEntry
.hasChildren() || interval
.getStartTime() == timestamp
) {
287 parent
.addChild(stateEntry
);
291 stateEntry
.update(interval
.getStateValue(),
292 TmfTimestamp
.fromNanos(interval
.getStartTime()),
293 TmfTimestamp
.fromNanos(interval
.getEndTime()));
295 // update children recursively
296 updateStateEntries(ss
, fullState
, stateEntry
, quark
, timestamp
);
300 } catch (AttributeNotFoundException e
) {
301 /* Should not happen, we're iterating on known attributes */
306 private static StateEntry
findStateEntry(TmfTreeViewerEntry parent
, int quark
) {
307 for (ITmfTreeViewerEntry child
: parent
.getChildren()) {
308 StateEntry stateEntry
= (StateEntry
) child
;
309 if (stateEntry
.getQuark() == quark
) {
316 * Set the entries as out of range
318 private static void markOutOfRange(ITmfTreeViewerEntry parent
) {
319 for (ITmfTreeViewerEntry entry
: parent
.getChildren()) {
320 if (entry
instanceof StateEntry
) {
321 ((StateEntry
) entry
).setOutOfRange();
323 /* Update this node's children recursively */
324 markOutOfRange(entry
);
330 * Set the filter status of the viewer. By default, all entries of all state
331 * system are present, and the values that changed since last refresh are
332 * shown in yellow. When the filter status is true, only the entries with
333 * values modified at current time are displayed.
335 public void changeFilterStatus() {
336 fFilterStatus
= !fFilterStatus
;
338 getTreeViewer().setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
340 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
343 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
347 * Update the display to use the updated timestamp format
350 * the incoming signal
353 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal
) {
354 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
357 private static class StateSystemEntry
extends TmfTreeViewerEntry
{
358 private final @NonNull ITmfStateSystem fSS
;
360 public StateSystemEntry(@NonNull ITmfStateSystem ss
) {
365 public @NonNull ITmfStateSystem
getSS() {
370 private class StateEntry
extends TmfTreeViewerEntry
{
372 private final int fQuark
;
373 private final String fFullPath
;
374 private @NonNull ITmfTimestamp fStart
;
375 private @NonNull ITmfTimestamp fEnd
;
376 private ITmfStateValue fValue
;
377 private boolean fModified
;
378 private boolean fOutOfRange
= false;
380 public StateEntry(String name
, int quark
, String fullPath
, ITmfStateValue value
, @NonNull ITmfTimestamp start
, @NonNull ITmfTimestamp end
, boolean modified
) {
383 fFullPath
= fullPath
;
387 fModified
= modified
;
390 public int getQuark() {
394 public String
getFullPath() {
398 public String
getStartTime() {
402 return fStart
.toString();
405 public String
getEndTime() {
409 return fEnd
.toString();
412 public String
getValue() {
414 return Messages
.OutOfRangeMsg
;
416 switch (fValue
.getType()) {
422 return fValue
.toString();
429 public String
getType() {
433 switch (fValue
.getType()) {
435 return Messages
.TypeInteger
;
437 return Messages
.TypeLong
;
439 return Messages
.TypeDouble
;
441 return Messages
.TypeString
;
443 return Messages
.TypeCustom
;
450 public boolean isModified() {
454 public void update(ITmfStateValue value
, @NonNull ITmfTimestamp start
, @NonNull ITmfTimestamp end
) {
457 if (!start
.equals(fStart
)) {
465 public void setOutOfRange() {