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 ITmfTreeViewerEntry
updateElements(long start
, long end
, boolean selection
) {
164 if (getTrace() == null) {
168 ITmfTreeViewerEntry root
= getInput();
170 if ((!selection
) && (root
!= null)) {
175 * Build the entries if it is the first time or to show only modified
178 if (root
== null || fFilterStatus
) {
179 root
= buildEntries(start
);
180 } else if (root
instanceof TmfTreeViewerEntry
) {
182 * Update the values of the elements of the state systems at time
185 updateEntriesList(((TmfTreeViewerEntry
)root
).getChildren(), start
);
191 private ITmfTreeViewerEntry
buildEntries(long timestamp
) {
193 TmfTreeViewerEntry rootEntry
= new TmfTreeViewerEntry(""); //$NON-NLS-1$
195 List
<ITmfTreeViewerEntry
> children
= rootEntry
.getChildren();
196 for (final ITmfTrace currentTrace
: TmfTraceManager
.getTraceSet(getTrace())) {
197 if (currentTrace
== null) {
200 buildEntriesForTrace(currentTrace
, timestamp
, children
);
206 * Update the values of the entries. It will also create trace and state
207 * system entries if they do not exist yet.
209 private void updateEntriesList(List
<ITmfTreeViewerEntry
> entries
, long timestamp
) {
210 for (final ITmfTrace trace
: TmfTraceManager
.getTraceSet(getTrace())) {
214 ITmfTreeViewerEntry traceEntry
= null;
215 for (ITmfTreeViewerEntry entry
: entries
) {
216 if (entry
.getName().equals(trace
.getName())) {
220 if (traceEntry
== null) {
221 traceEntry
= buildEntriesForTrace(trace
, timestamp
, entries
);
224 /* Find the state system entries for this trace */
225 Iterable
<ITmfAnalysisModuleWithStateSystems
> modules
= trace
.getAnalysisModulesOfClass(ITmfAnalysisModuleWithStateSystems
.class);
226 for (ITmfAnalysisModuleWithStateSystems module
: modules
) {
228 for (ITmfStateSystem ss
: module
.getStateSystems()) {
232 ITmfTreeViewerEntry ssEntry
= null;
233 for (ITmfTreeViewerEntry entry
: traceEntry
.getChildren()) {
234 if (entry
.getName().equals(ss
.getSSID())) {
239 if (ssEntry
== null) {
240 /* The state system entry has not been built yet */
241 buildEntriesForStateSystem(ss
, timestamp
, (TmfTreeViewerEntry
) traceEntry
);
242 } else if (ssEntry
.hasChildren()) {
244 * Typical case at this point, update the data from the
247 updateEntriesForStateSystem(ss
, timestamp
, (TmfTreeViewerEntry
) ssEntry
);
250 * The state system existed but entries were not filled,
251 * that would occur if for instance the values were out
252 * of range at the first query.
254 fillEntriesForStateSystem(ss
, timestamp
, (TmfTreeViewerEntry
) ssEntry
);
262 private ITmfTreeViewerEntry
buildEntriesForTrace(@NonNull ITmfTrace trace
, long timestamp
, @NonNull List
<ITmfTreeViewerEntry
> rootEntries
) {
263 TmfTreeViewerEntry traceEntry
= new TmfTreeViewerEntry(trace
.getName());
264 rootEntries
.add(traceEntry
);
266 Iterable
<ITmfAnalysisModuleWithStateSystems
> modules
= trace
.getAnalysisModulesOfClass(ITmfAnalysisModuleWithStateSystems
.class);
267 for (ITmfAnalysisModuleWithStateSystems module
: modules
) {
268 /* Just schedule the module, the data will be filled when available */
270 for (ITmfStateSystem ss
: module
.getStateSystems()) {
274 buildEntriesForStateSystem(ss
, timestamp
, traceEntry
);
280 private void buildEntriesForStateSystem(ITmfStateSystem ss
, long timestamp
, TmfTreeViewerEntry traceEntry
) {
281 TmfTreeViewerEntry ssEntry
= new TmfTreeViewerEntry(ss
.getSSID());
282 traceEntry
.addChild(ssEntry
);
283 fillEntriesForStateSystem(ss
, timestamp
, ssEntry
);
286 private void fillEntriesForStateSystem(ITmfStateSystem ss
, long timestamp
, TmfTreeViewerEntry ssEntry
) {
288 addChildren(ss
, ss
.queryFullState(timestamp
), -1, ssEntry
, timestamp
);
289 } catch (StateSystemDisposedException
| TimeRangeException e
) {
295 * Add children node to an entry. It will create all necessary entries.
297 private void addChildren(ITmfStateSystem ss
, List
<ITmfStateInterval
> fullState
, int rootQuark
, TmfTreeViewerEntry root
, long timestamp
) {
299 for (int quark
: ss
.getSubAttributes(rootQuark
, false)) {
301 ITmfStateInterval interval
= fullState
.get(quark
);
303 StateSystemEntry entry
= new StateSystemEntry(ss
.getAttributeName(quark
), quark
, ss
.getFullAttributePath(quark
),
304 interval
.getStateValue(),
305 new TmfTimestamp(interval
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
306 new TmfTimestamp(interval
.getEndTime(), ITmfTimestamp
.NANOSECOND_SCALE
));
308 /* Add this node's children recursively */
309 addChildren(ss
, fullState
, quark
, entry
, timestamp
);
313 * Do not add this entry to root if
314 * 1- the filter status is ON
316 * 2- the entry has no children
318 * 3- the start time is not the current timestamp
321 if (!(fFilterStatus
&& !entry
.hasChildren() && (interval
.getStartTime() != timestamp
))) {
322 root
.addChild(entry
);
326 } catch (AttributeNotFoundException e
) {
327 /* Should not happen, we're iterating on known attributes */
328 throw new RuntimeException();
332 private void updateEntriesForStateSystem(ITmfStateSystem ss
, long timestamp
, TmfTreeViewerEntry ssEntry
) {
334 updateChildren(ss
, ss
.queryFullState(timestamp
), ssEntry
);
335 } catch (StateSystemDisposedException e
) {
336 } catch (TimeRangeException e
) {
337 /* Mark all entries out of range */
338 markOutOfRange(ssEntry
);
343 * Update the values of existing entries.
345 private void updateChildren(ITmfStateSystem ss
, List
<ITmfStateInterval
> fullState
, ITmfTreeViewerEntry root
) {
346 for (ITmfTreeViewerEntry entry
: root
.getChildren()) {
347 if (entry
instanceof StateSystemEntry
) {
349 * FIXME: if new sub attributes were added since the element was
350 * built, then then will not be added
352 StateSystemEntry ssEntry
= (StateSystemEntry
) entry
;
353 ITmfStateInterval interval
= fullState
.get(ssEntry
.getQuark());
354 if (interval
!= null) {
355 ssEntry
.update(interval
.getStateValue(), new TmfTimestamp(interval
.getStartTime(), ITmfTimestamp
.NANOSECOND_SCALE
),
356 new TmfTimestamp(interval
.getEndTime(), ITmfTimestamp
.NANOSECOND_SCALE
));
359 /* Update this node's children recursively */
360 updateChildren(ss
, fullState
, ssEntry
);
366 * Set the entries as out of range
368 private void markOutOfRange(ITmfTreeViewerEntry root
) {
369 for (ITmfTreeViewerEntry entry
: root
.getChildren()) {
370 if (entry
instanceof StateSystemEntry
) {
371 ((StateSystemEntry
) entry
).setOutOfRange();
373 /* Update this node's children recursively */
374 markOutOfRange(entry
);
380 * Set the filter status of the viewer. By default, all entries of all state
381 * system are present, and the values that changed since last refresh are
382 * shown in yellow. When the filter status is true, only the entries with
383 * values modified at current time are displayed.
385 public void changeFilterStatus() {
386 fFilterStatus
= !fFilterStatus
;
388 getTreeViewer().setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
390 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND
);
393 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
397 * Update the display to use the updated timestamp format
400 * the incoming signal
403 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal
) {
404 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
407 private class StateSystemEntry
extends TmfTreeViewerEntry
{
409 private final int fQuark
;
410 private final String fFullPath
;
411 private @NonNull TmfTimestamp fStart
;
412 private @NonNull TmfTimestamp fEnd
;
413 private ITmfStateValue fValue
;
414 private boolean fModified
= false;
415 private boolean fOutOfRange
= false;
417 public StateSystemEntry(String name
, int quark
, String fullPath
, ITmfStateValue value
, @NonNull TmfTimestamp start
, @NonNull TmfTimestamp end
) {
420 fFullPath
= fullPath
;
426 public int getQuark() {
430 public String
getFullPath() {
434 public String
getStartTime() {
438 return fStart
.toString();
441 public String
getEndTime() {
445 return fEnd
.toString();
448 public String
getValue() {
450 return Messages
.OutOfRangeMsg
;
452 switch (fValue
.getType()) {
457 return fValue
.toString();
464 public String
getType() {
468 switch (fValue
.getType()) {
470 return Messages
.TypeInteger
;
472 return Messages
.TypeLong
;
474 return Messages
.TypeDouble
;
476 return Messages
.TypeString
;
483 public boolean isModified() {
487 public void update(ITmfStateValue value
, @NonNull TmfTimestamp start
, @NonNull TmfTimestamp end
) {
490 if (!start
.equals(fStart
)) {
498 public void setOutOfRange() {