TMF: Changed the state system explorer to use an abstract tree viewer
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / statesystem / TmfStateSystemViewer.java
CommitLineData
17c73d10
GB
1/*******************************************************************************
2 * Copyright (c) 2014 École Polytechnique de Montréal
3 *
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
8 *
9 * Contributors:
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 *******************************************************************************/
16
17package org.eclipse.linuxtools.tmf.ui.views.statesystem;
18
19import java.util.ArrayList;
20import java.util.List;
21
22import org.eclipse.jdt.annotation.NonNull;
23import org.eclipse.jface.viewers.AbstractTreeViewer;
24import org.eclipse.jface.viewers.Viewer;
25import org.eclipse.jface.viewers.ViewerComparator;
26import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
27import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
28import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
29import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
30import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
31import org.eclipse.linuxtools.tmf.core.signal.TmfTimestampFormatUpdateSignal;
32import org.eclipse.linuxtools.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems;
33import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
34import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
35import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
36import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
37import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
38import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
39import org.eclipse.linuxtools.tmf.ui.viewers.tree.AbstractTmfTreeViewer;
40import org.eclipse.linuxtools.tmf.ui.viewers.tree.ITmfTreeColumnDataProvider;
41import org.eclipse.linuxtools.tmf.ui.viewers.tree.ITmfTreeViewerEntry;
42import org.eclipse.linuxtools.tmf.ui.viewers.tree.TmfTreeColumnData;
43import org.eclipse.linuxtools.tmf.ui.viewers.tree.TmfTreeViewerEntry;
44import org.eclipse.swt.SWT;
45import org.eclipse.swt.graphics.Color;
46import org.eclipse.swt.widgets.Composite;
47import org.eclipse.swt.widgets.Display;
48
49/**
50 * Displays the content of the state systems at the current time
51 *
52 * @author Florian Wininger
53 * @author Alexandre Montplaisir
54 * @author Geneviève Bastien
55 * @since 3.0
56 */
57public class TmfStateSystemViewer extends AbstractTmfTreeViewer {
58
59 private static final String EMPTY_STRING = ""; //$NON-NLS-1$
60 private boolean fFilterStatus = false;
61 private static final int DEFAULT_AUTOEXPAND = 2;
62
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;
71
72 /**
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
76 */
77 protected static class StateSystemTreeLabelProvider extends TreeLabelProvider {
78
79 @Override
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();
86 case QUARK_COL:
87 return String.valueOf(entry.getQuark());
88 case VALUE_COL:
89 return entry.getValue();
90 case TYPE_COL:
91 return entry.getType();
92 case START_TIME_COL:
93 return entry.getStartTime();
94 case END_TIME_COL:
95 return entry.getEndTime();
96 case ATTRIBUTE_FULLPATH_COL:
97 return entry.getFullPath();
98 default:
99 return EMPTY_STRING;
100 }
101 }
102 return super.getColumnText(element, columnIndex);
103 }
104
105 @Override
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);
110 }
111 }
112 return super.getBackground(element, columnIndex);
113 }
114 }
115
116 /**
117 * Constructor
118 *
119 * @param parent
120 * The parent containing this viewer
121 */
122 public TmfStateSystemViewer(Composite parent) {
123 super(parent, false);
124 this.setLabelProvider(new StateSystemTreeLabelProvider());
125 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND);
126 }
127
128 @Override
129 protected ITmfTreeColumnDataProvider getColumnDataProvider() {
130 return new ITmfTreeColumnDataProvider() {
131
132 @Override
133 public List<TmfTreeColumnData> getColumnData() {
134 List<TmfTreeColumnData> columns = new ArrayList<>();
135 TmfTreeColumnData column = new TmfTreeColumnData(Messages.TreeNodeColumnLabel);
136 columns.add(column);
137 column.setComparator(new ViewerComparator() {
138 @Override
139 public int compare(Viewer viewer, Object e1, Object e2) {
140 TmfTreeViewerEntry n1 = (TmfTreeViewerEntry) e1;
141 TmfTreeViewerEntry n2 = (TmfTreeViewerEntry) e2;
142
143 return n1.getName().compareTo(n2.getName());
144 }
145 });
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));
152 return columns;
153 }
154
155 };
156 }
157
158 // ------------------------------------------------------------------------
159 // Operations
160 // ------------------------------------------------------------------------
161
162 @Override
163 protected List<ITmfTreeViewerEntry> updateElements(long start, long end, boolean selection) {
164 if (getTrace() == null) {
165 return null;
166 }
167
168 List<ITmfTreeViewerEntry> entries = (List<ITmfTreeViewerEntry>) getInput();
169
170 if ((!selection) && (entries != null)) {
171 return null;
172 }
173
174 /*
175 * Build the entries if it is the first time or to show only modified
176 * values
177 */
178 if (entries == null || fFilterStatus) {
179 entries = buildEntriesList(start);
180 } else {
181 /*
182 * Update the values of the elements of the state systems at time
183 * 'start'
184 */
185 entries = updateEntriesList(entries, start);
186 }
187
188 return entries;
189 }
190
191 private List<ITmfTreeViewerEntry> buildEntriesList(long timestamp) {
192 List<ITmfTreeViewerEntry> rootEntries = new ArrayList<>();
193 for (final ITmfTrace currentTrace : TmfTraceManager.getTraceSet(getTrace())) {
194 if (currentTrace == null) {
195 continue;
196 }
197 buildEntriesForTrace(currentTrace, timestamp, rootEntries);
198 }
199 return rootEntries;
200 }
201
202 /*
203 * Update the values of the entries. It will also create trace and state
204 * system entries if they do not exist yet.
205 */
206 private List<ITmfTreeViewerEntry> updateEntriesList(List<ITmfTreeViewerEntry> entries, long timestamp) {
207 for (final ITmfTrace trace : TmfTraceManager.getTraceSet(getTrace())) {
208 if (trace == null) {
209 continue;
210 }
211 ITmfTreeViewerEntry traceEntry = null;
212 for (ITmfTreeViewerEntry entry : entries) {
213 if (entry.getName().equals(trace.getName())) {
214 traceEntry = entry;
215 }
216 }
217 if (traceEntry == null) {
218 traceEntry = buildEntriesForTrace(trace, timestamp, entries);
219 }
220
221 /* Find the state system entries for this trace */
222 Iterable<ITmfAnalysisModuleWithStateSystems> modules = trace.getAnalysisModulesOfClass(ITmfAnalysisModuleWithStateSystems.class);
223 for (ITmfAnalysisModuleWithStateSystems module : modules) {
224 module.schedule();
225 for (ITmfStateSystem ss : module.getStateSystems()) {
226 if (ss == null) {
227 continue;
228 }
229 ITmfTreeViewerEntry ssEntry = null;
230 for (ITmfTreeViewerEntry entry : traceEntry.getChildren()) {
231 if (entry.getName().equals(ss.getSSID())) {
232 ssEntry = entry;
233 }
234 }
235
236 if (ssEntry == null) {
237 /* The state system entry has not been built yet */
238 buildEntriesForStateSystem(ss, timestamp, (TmfTreeViewerEntry) traceEntry);
239 } else if (ssEntry.hasChildren()) {
240 /*
241 * Typical case at this point, update the data from the
242 * state system
243 */
244 updateEntriesForStateSystem(ss, timestamp, (TmfTreeViewerEntry) ssEntry);
245 } else {
246 /*
247 * The state system existed but entries were not filled,
248 * that would occur if for instance the values were out
249 * of range at the first query.
250 */
251 fillEntriesForStateSystem(ss, timestamp, (TmfTreeViewerEntry) ssEntry);
252 }
253 }
254 }
255 }
256 return entries;
257 }
258
259 @NonNull
260 private ITmfTreeViewerEntry buildEntriesForTrace(@NonNull ITmfTrace trace, long timestamp, @NonNull List<ITmfTreeViewerEntry> rootEntries) {
261 TmfTreeViewerEntry traceEntry = new TmfTreeViewerEntry(trace.getName());
262 rootEntries.add(traceEntry);
263
264 Iterable<ITmfAnalysisModuleWithStateSystems> modules = trace.getAnalysisModulesOfClass(ITmfAnalysisModuleWithStateSystems.class);
265 for (ITmfAnalysisModuleWithStateSystems module : modules) {
266 /* Just schedule the module, the data will be filled when available */
267 module.schedule();
268 for (ITmfStateSystem ss : module.getStateSystems()) {
269 if (ss == null) {
270 continue;
271 }
272 buildEntriesForStateSystem(ss, timestamp, traceEntry);
273 }
274 }
275 return traceEntry;
276 }
277
278 private void buildEntriesForStateSystem(ITmfStateSystem ss, long timestamp, TmfTreeViewerEntry traceEntry) {
279 TmfTreeViewerEntry ssEntry = new TmfTreeViewerEntry(ss.getSSID());
280 traceEntry.addChild(ssEntry);
281 fillEntriesForStateSystem(ss, timestamp, ssEntry);
282 }
283
284 private void fillEntriesForStateSystem(ITmfStateSystem ss, long timestamp, TmfTreeViewerEntry ssEntry) {
285 try {
286 addChildren(ss, ss.queryFullState(timestamp), -1, ssEntry, timestamp);
287 } catch (StateSystemDisposedException | TimeRangeException e) {
288 /* Nothing to do */
289 }
290 }
291
292 /**
293 * Add children node to an entry. It will create all necessary entries.
294 */
295 private void addChildren(ITmfStateSystem ss, List<ITmfStateInterval> fullState, int rootQuark, TmfTreeViewerEntry root, long timestamp) {
296 try {
297 for (int quark : ss.getSubAttributes(rootQuark, false)) {
298
299 ITmfStateInterval interval = fullState.get(quark);
300
301 StateSystemEntry entry = new StateSystemEntry(ss.getAttributeName(quark), quark, ss.getFullAttributePath(quark),
302 interval.getStateValue(),
303 new TmfTimestamp(interval.getStartTime(), ITmfTimestamp.NANOSECOND_SCALE),
304 new TmfTimestamp(interval.getEndTime(), ITmfTimestamp.NANOSECOND_SCALE));
305
306 /* Add this node's children recursively */
307 addChildren(ss, fullState, quark, entry, timestamp);
308
309 /**
310 * <pre>
311 * Do not add this entry to root if
312 * 1- the filter status is ON
313 * AND
314 * 2- the entry has no children
315 * AND
316 * 3- the start time is not the current timestamp
317 * </pre>
318 */
319 if (!(fFilterStatus && !entry.hasChildren() && (interval.getStartTime() != timestamp))) {
320 root.addChild(entry);
321 }
322 }
323
324 } catch (AttributeNotFoundException e) {
325 /* Should not happen, we're iterating on known attributes */
326 throw new RuntimeException();
327 }
328 }
329
330 private void updateEntriesForStateSystem(ITmfStateSystem ss, long timestamp, TmfTreeViewerEntry ssEntry) {
331 try {
332 updateChildren(ss, ss.queryFullState(timestamp), ssEntry);
333 } catch (StateSystemDisposedException e) {
334 } catch (TimeRangeException e) {
335 /* Mark all entries out of range */
336 markOutOfRange(ssEntry);
337 }
338 }
339
340 /**
341 * Update the values of existing entries.
342 */
343 private void updateChildren(ITmfStateSystem ss, List<ITmfStateInterval> fullState, ITmfTreeViewerEntry root) {
344 for (ITmfTreeViewerEntry entry : root.getChildren()) {
345 if (entry instanceof StateSystemEntry) {
346 /*
347 * FIXME: if new sub attributes were added since the element was
348 * built, then then will not be added
349 */
350 StateSystemEntry ssEntry = (StateSystemEntry) entry;
351 ITmfStateInterval interval = fullState.get(ssEntry.getQuark());
352 if (interval != null) {
353 ssEntry.update(interval.getStateValue(), new TmfTimestamp(interval.getStartTime(), ITmfTimestamp.NANOSECOND_SCALE),
354 new TmfTimestamp(interval.getEndTime(), ITmfTimestamp.NANOSECOND_SCALE));
355 }
356
357 /* Update this node's children recursively */
358 updateChildren(ss, fullState, ssEntry);
359 }
360 }
361 }
362
363 /**
364 * Set the entries as out of range
365 */
366 private void markOutOfRange(ITmfTreeViewerEntry root) {
367 for (ITmfTreeViewerEntry entry : root.getChildren()) {
368 if (entry instanceof StateSystemEntry) {
369 ((StateSystemEntry) entry).setOutOfRange();
370
371 /* Update this node's children recursively */
372 markOutOfRange(entry);
373 }
374 }
375 }
376
377 /**
378 * Set the filter status of the viewer. By default, all entries of all state
379 * system are present, and the values that changed since last refresh are
380 * shown in yellow. When the filter status is true, only the entries with
381 * values modified at current time are displayed.
382 */
383 public void changeFilterStatus() {
384 fFilterStatus = !fFilterStatus;
385 if (fFilterStatus) {
386 getTreeViewer().setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
387 } else {
388 getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND);
389 clearContent();
390 }
391 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
392 }
393
394 /**
395 * Update the display to use the updated timestamp format
396 *
397 * @param signal
398 * the incoming signal
399 */
400 @TmfSignalHandler
401 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
402 updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
403 }
404
405 private class StateSystemEntry extends TmfTreeViewerEntry {
406
407 private final int fQuark;
408 private final String fFullPath;
409 private @NonNull TmfTimestamp fStart;
410 private @NonNull TmfTimestamp fEnd;
411 private ITmfStateValue fValue;
412 private boolean fModified = false;
413 private boolean fOutOfRange = false;
414
415 public StateSystemEntry(String name, int quark, String fullPath, ITmfStateValue value, @NonNull TmfTimestamp start, @NonNull TmfTimestamp end) {
416 super(name);
417 fQuark = quark;
418 fFullPath = fullPath;
419 fStart = start;
420 fEnd = end;
421 fValue = value;
422 }
423
424 public int getQuark() {
425 return fQuark;
426 }
427
428 public String getFullPath() {
429 return fFullPath;
430 }
431
432 public String getStartTime() {
433 if (fOutOfRange) {
434 return EMPTY_STRING;
435 }
436 return fStart.toString();
437 }
438
439 public String getEndTime() {
440 if (fOutOfRange) {
441 return EMPTY_STRING;
442 }
443 return fEnd.toString();
444 }
445
446 public String getValue() {
447 if (fOutOfRange) {
448 return Messages.OutOfRangeMsg;
449 }
450 switch (fValue.getType()) {
451 case INTEGER:
452 case LONG:
453 case DOUBLE:
454 case STRING:
455 return fValue.toString();
456 case NULL:
457 default:
458 return EMPTY_STRING;
459 }
460 }
461
462 public String getType() {
463 if (fOutOfRange) {
464 return EMPTY_STRING;
465 }
466 switch (fValue.getType()) {
467 case INTEGER:
468 return Messages.TypeInteger;
469 case LONG:
470 return Messages.TypeLong;
471 case DOUBLE:
472 return Messages.TypeDouble;
473 case STRING:
474 return Messages.TypeString;
475 case NULL:
476 default:
477 return EMPTY_STRING;
478 }
479 }
480
481 public boolean isModified() {
482 return fModified;
483 }
484
485 public void update(ITmfStateValue value, @NonNull TmfTimestamp start, @NonNull TmfTimestamp end) {
486 fModified = false;
487 fOutOfRange = false;
488 if (!start.equals(fStart)) {
489 fModified = true;
490 fStart = start;
491 fEnd = end;
492 fValue = value;
493 }
494 }
495
496 public void setOutOfRange() {
497 fModified = false;
498 fOutOfRange = true;
499 }
500 }
501}
This page took 0.059805 seconds and 5 git commands to generate.