Build using a target definition file
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / viewers / tree / AbstractTmfTreeViewer.java
CommitLineData
c0188b25
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 * Geneviève Bastien - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.linuxtools.tmf.ui.viewers.tree;
14
15import java.util.List;
16
17import org.eclipse.jface.viewers.AbstractTreeViewer;
18import org.eclipse.jface.viewers.IBaseLabelProvider;
19import org.eclipse.jface.viewers.ILabelProviderListener;
20import org.eclipse.jface.viewers.ISelectionChangedListener;
21import org.eclipse.jface.viewers.ITableColorProvider;
22import org.eclipse.jface.viewers.ITableFontProvider;
23import org.eclipse.jface.viewers.ITableLabelProvider;
24import org.eclipse.jface.viewers.ITreeContentProvider;
25import org.eclipse.jface.viewers.TreeViewer;
26import org.eclipse.jface.viewers.Viewer;
27import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
28import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
29import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
30import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
31import org.eclipse.linuxtools.tmf.ui.viewers.TmfTimeViewer;
32import org.eclipse.swt.SWT;
33import org.eclipse.swt.graphics.Color;
34import org.eclipse.swt.graphics.Font;
35import org.eclipse.swt.graphics.Image;
36import org.eclipse.swt.widgets.Composite;
37import org.eclipse.swt.widgets.Control;
38import org.eclipse.swt.widgets.Display;
39import org.eclipse.swt.widgets.Event;
40import org.eclipse.swt.widgets.Listener;
41import org.eclipse.swt.widgets.Tree;
42import org.eclipse.swt.widgets.TreeColumn;
43
44/**
45 * Abstract class for viewers who will display data using a TreeViewer. It
46 * automatically synchronizes with time information of the UI. It also
47 * implements some common functionalities for all tree viewer, such as managing
48 * the column data, content initialization and update. The viewer implementing
49 * this does not have to worry about whether some code runs in the UI thread or
50 * not.
51 *
52 * @author Geneviève Bastien
53 * @since 3.0
54 */
55public abstract class AbstractTmfTreeViewer extends TmfTimeViewer {
56
57 private final TreeViewer fTreeViewer;
58
59 // ------------------------------------------------------------------------
60 // Internal classes
61 // ------------------------------------------------------------------------
62
63 /* The elements of the tree viewer are of type ITmfTreeViewerEntry */
64 private class TreeContentProvider implements ITreeContentProvider {
65
66 @Override
67 public void dispose() {
68 }
69
70 @Override
71 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
72 }
73
74 @Override
75 public Object[] getElements(Object inputElement) {
59c8ff34
MAL
76 if (inputElement instanceof ITmfTreeViewerEntry) {
77 return ((ITmfTreeViewerEntry) inputElement).getChildren().toArray(new ITmfTreeViewerEntry[0]);
c0188b25
GB
78 }
79 return new ITmfTreeViewerEntry[0];
80 }
81
82 @Override
83 public Object[] getChildren(Object parentElement) {
84 ITmfTreeViewerEntry entry = (ITmfTreeViewerEntry) parentElement;
85 List<? extends ITmfTreeViewerEntry> children = entry.getChildren();
86 return children.toArray(new ITmfTreeViewerEntry[children.size()]);
87 }
88
89 @Override
90 public Object getParent(Object element) {
91 ITmfTreeViewerEntry entry = (ITmfTreeViewerEntry) element;
92 return entry.getParent();
93 }
94
95 @Override
96 public boolean hasChildren(Object element) {
97 ITmfTreeViewerEntry entry = (ITmfTreeViewerEntry) element;
98 return entry.hasChildren();
99 }
100
101 }
102
103 /**
104 * Base class to provide the labels for the tree viewer. Views extending
105 * this class typically need to override the getColumnText method if they
106 * have more than one column to display. It also allows to change the font
107 * and colors of the cells.
108 */
109 protected static class TreeLabelProvider implements ITableLabelProvider, ITableFontProvider, ITableColorProvider {
110
111 @Override
112 public void addListener(ILabelProviderListener listener) {
113 }
114
115 @Override
116 public void dispose() {
117 }
118
119 @Override
120 public boolean isLabelProperty(Object element, String property) {
121 return false;
122 }
123
124 @Override
125 public void removeListener(ILabelProviderListener listener) {
126 }
127
128 @Override
129 public Image getColumnImage(Object element, int columnIndex) {
130 return null;
131 }
132
133 @Override
134 public String getColumnText(Object element, int columnIndex) {
135 if ((element instanceof ITmfTreeViewerEntry) && (columnIndex == 0)) {
136 ITmfTreeViewerEntry entry = (ITmfTreeViewerEntry) element;
137 return entry.getName();
138 }
139 return new String();
140 }
141
142 @Override
143 public Color getForeground(Object element, int columnIndex) {
144 return Display.getCurrent().getSystemColor(SWT.COLOR_LIST_FOREGROUND);
145 }
146
147 @Override
148 public Color getBackground(Object element, int columnIndex) {
149 return Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
150 }
151
152 @Override
153 public Font getFont(Object element, int columnIndex) {
154 return null;
155 }
156
157 }
158
159 // ------------------------------------------------------------------------
160 // Constructors and initialization methods
161 // ------------------------------------------------------------------------
162
163 /**
164 * Constructor
165 *
166 * @param parent
167 * The parent composite that holds this viewer
168 * @param allowMultiSelect
169 * Whether multiple selections are allowed
170 */
171 public AbstractTmfTreeViewer(Composite parent, boolean allowMultiSelect) {
172 super(parent);
173
174 int flags = SWT.FULL_SELECTION | SWT.H_SCROLL;
175 if (allowMultiSelect) {
176 flags |= SWT.MULTI;
177 }
178
179 /* Build the tree viewer part of the view */
180 fTreeViewer = new TreeViewer(parent, flags);
181 fTreeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
182 final Tree tree = fTreeViewer.getTree();
183 tree.setHeaderVisible(true);
184 tree.setLinesVisible(true);
185 fTreeViewer.setContentProvider(new TreeContentProvider());
186 fTreeViewer.setLabelProvider(new TreeLabelProvider());
187 List<TmfTreeColumnData> columns = getColumnDataProvider().getColumnData();
188 this.setTreeColumns(columns);
189 }
190
191 /**
192 * Get the column data provider that will contain the list of columns to be
193 * part of this viewer. It is called once during the constructor.
194 *
195 * @return The tree column data provider for this viewer.
196 */
197 protected abstract ITmfTreeColumnDataProvider getColumnDataProvider();
198
199 /**
200 * Sets the tree columns for this tree viewer
201 *
202 * @param columns
203 * The tree column data
204 */
205 public void setTreeColumns(final List<TmfTreeColumnData> columns) {
206 boolean hasPercentProvider = false;
207 for (final TmfTreeColumnData columnData : columns) {
208 columnData.createColumn(fTreeViewer);
209 hasPercentProvider |= (columnData.getPercentageProvider() != null);
210 }
211
212 if (hasPercentProvider) {
213 /*
214 * Handler that will draw bar charts in the cell using a percentage
215 * value.
216 */
217 fTreeViewer.getTree().addListener(SWT.EraseItem, new Listener() {
218 @Override
219 public void handleEvent(Event event) {
220 if (columns.get(event.index).getPercentageProvider() != null) {
221
222 double percentage = columns.get(event.index).getPercentageProvider().getPercentage(event.item.getData());
223 if (percentage == 0) { // No bar to draw
224 return;
225 }
226
227 if ((event.detail & SWT.SELECTED) > 0) {
228 /*
229 * The item is selected. Draw our own background to
230 * avoid overwriting the bar.
231 */
232 event.gc.fillRectangle(event.x, event.y, event.width, event.height);
233 event.detail &= ~SWT.SELECTED;
234 }
235
236 int barWidth = (int) ((fTreeViewer.getTree().getColumn(event.index).getWidth() - 8) * percentage);
237 int oldAlpha = event.gc.getAlpha();
238 Color oldForeground = event.gc.getForeground();
239 Color oldBackground = event.gc.getBackground();
240 /*
241 * Draws a transparent gradient rectangle from the color
242 * of foreground and background.
243 */
244 event.gc.setAlpha(64);
245 event.gc.setForeground(event.item.getDisplay().getSystemColor(SWT.COLOR_BLUE));
246 event.gc.setBackground(event.item.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
247 event.gc.fillGradientRectangle(event.x, event.y, barWidth, event.height, true);
248 event.gc.drawRectangle(event.x, event.y, barWidth, event.height);
249 /* Restores old values */
250 event.gc.setForeground(oldForeground);
251 event.gc.setBackground(oldBackground);
252 event.gc.setAlpha(oldAlpha);
253 event.detail &= ~SWT.BACKGROUND;
254 }
255 }
256 });
257 }
258 }
259
260 /**
261 * Set the label provider that will fill the columns of the tree viewer
262 *
263 * @param labelProvider
264 * The label provider to fill the columns
265 */
266 protected void setLabelProvider(IBaseLabelProvider labelProvider) {
267 fTreeViewer.setLabelProvider(labelProvider);
268 }
269
270 /**
271 * Get the tree viewer object
272 *
273 * @return The tree viewer object displayed by this viewer
274 */
275 protected TreeViewer getTreeViewer() {
276 return fTreeViewer;
277 }
278
279 // ------------------------------------------------------------------------
280 // ITmfViewer
281 // ------------------------------------------------------------------------
282
283 @Override
284 public Control getControl() {
285 return fTreeViewer.getControl();
286 }
287
288 @Override
289 public void refresh() {
290 Tree tree = fTreeViewer.getTree();
291 tree.setRedraw(false);
292 fTreeViewer.refresh();
293 fTreeViewer.expandAll();
294 tree.setRedraw(true);
295 }
296
297 @Override
298 public void loadTrace(ITmfTrace trace) {
299 super.loadTrace(trace);
300 Thread thread = new Thread() {
301 @Override
302 public void run() {
303 initializeDataSource();
304 Display.getDefault().asyncExec(new Runnable() {
305 @Override
306 public void run() {
307 clearContent();
308 updateContent(getWindowStartTime(), getWindowEndTime(), false);
309 }
310 });
311 }
312 };
313 thread.start();
314 }
315
316 // ------------------------------------------------------------------------
317 // Operations
318 // ------------------------------------------------------------------------
319
320 /**
321 * Add a selection listener to the tree viewer. This will be called when the
322 * selection changes and contain all the selected items.
323 *
324 * The selection change listener can be used like this:
325 *
326 * <pre>
327 * getTreeViewer().addSelectionChangeListener(new ISelectionChangedListener() {
328 * &#064;Override
329 * public void selectionChanged(SelectionChangedEvent event) {
330 * if (event.getSelection() instanceof IStructuredSelection) {
331 * Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
332 * if (selection instanceof ITmfTreeViewerEntry) {
333 * // Do something
334 * }
335 * }
336 * }
337 * });
338 * </pre>
339 *
340 * @param listener
341 * The {@link ISelectionChangedListener}
342 */
343 public void addSelectionChangeListener(ISelectionChangedListener listener) {
344 fTreeViewer.addSelectionChangedListener(listener);
345 }
346
347 /**
348 * Method called when the trace is loaded, to initialize any data once the
349 * trace has been set, but before the first call to update the content of
350 * the viewer.
351 */
352 protected void initializeDataSource() {
353
354 }
355
356 /**
357 * Clears the current content of the viewer.
358 */
359 protected void clearContent() {
360 fTreeViewer.setInput(null);
361 }
362
363 /**
364 * Requests an update of the viewer's content in a given time range or
365 * selection time range. An extra parameter defines whether these times
366 * correspond to the selection or the visible range, as the viewer may
367 * update differently in those cases.
368 *
369 * @param start
370 * The start time of the requested content
371 * @param end
372 * The end time of the requested content
373 * @param isSelection
374 * <code>true</code> if this time range is for a selection,
375 * <code>false</code> for the visible time range
376 */
377 protected void updateContent(final long start, final long end, final boolean isSelection) {
378 Thread thread = new Thread() {
379 @Override
380 public void run() {
59c8ff34 381 final ITmfTreeViewerEntry rootEntry = updateElements(start, end, isSelection);
c0188b25 382 /* Set the input in main thread only if it didn't change */
59c8ff34 383 if (rootEntry != null) {
c0188b25
GB
384 Display.getDefault().asyncExec(new Runnable() {
385 @Override
386 public void run() {
59c8ff34
MAL
387 if (rootEntry != fTreeViewer.getInput()) {
388 fTreeViewer.setInput(rootEntry);
c0188b25
GB
389 } else {
390 fTreeViewer.refresh();
391 }
392 // FIXME should add a bit of padding
393 for (TreeColumn column : fTreeViewer.getTree().getColumns()) {
394 column.pack();
395 }
396 }
397 });
398 }
399 }
400 };
401 thread.start();
402 }
403
404 /**
405 * Update the entries to the given start/end time. An extra parameter
406 * defines whether these times correspond to the selection or the visible
59c8ff34
MAL
407 * range, as the viewer may update differently in those cases. This methods
408 * returns a root node that is not meant to be visible. The children of this
409 * 'fake' root node are the first level of entries that will appear in the
410 * tree. If no update is necessary, the method should return
411 * <code>null</code>. To empty the tree, a root node containing an empty
412 * list of children should be returned.
c0188b25
GB
413 *
414 * This method is not called in the UI thread when using the default viewer
415 * content update. Resource-intensive calculations here should not block the
416 * UI.
417 *
418 * @param start
419 * The start time of the requested content
420 * @param end
421 * The end time of the requested content
422 * @param isSelection
423 * <code>true</code> if this time range is for a selection,
424 * <code>false</code> for the visible time range
59c8ff34
MAL
425 * @return The root entry of the list of entries to display or
426 * <code>null</code> if no update necessary
c0188b25 427 */
59c8ff34 428 protected abstract ITmfTreeViewerEntry updateElements(long start, long end, boolean isSelection);
c0188b25
GB
429
430 /**
431 * Get the current input displayed by the viewer
432 *
59c8ff34 433 * @return The input of the tree viewer, the root entry
c0188b25 434 */
59c8ff34
MAL
435 protected ITmfTreeViewerEntry getInput() {
436 return (ITmfTreeViewerEntry) fTreeViewer.getInput();
c0188b25
GB
437 }
438
439 // ------------------------------------------------------------------------
440 // Signal Handler
441 // ------------------------------------------------------------------------
442
443 /**
444 * Signal handler for handling of the time synch signal. The times
445 * correspond to the selection by the user, not the visible time range.
446 *
447 * @param signal
448 * The time synch signal {@link TmfTimeSynchSignal}
449 */
450 @Override
451 @TmfSignalHandler
452 public void selectionRangeUpdated(TmfTimeSynchSignal signal) {
453 super.selectionRangeUpdated(signal);
454 if ((signal.getSource() != this) && (getTrace() != null)) {
455 updateContent(this.getSelectionBeginTime(), this.getSelectionEndTime(), true);
456 }
457 }
458
459 /**
460 * Signal handler for handling of the time range synch signal. This time
461 * range is the visible zone of the view.
462 *
463 * @param signal
464 * The time range synch signal {@link TmfRangeSynchSignal}
465 */
466 @Override
467 @TmfSignalHandler
468 public void timeRangeUpdated(TmfRangeSynchSignal signal) {
469 super.timeRangeUpdated(signal);
470 updateContent(this.getWindowStartTime(), this.getWindowEndTime(), false);
471 }
472
d8adbbe6
BH
473 @Override
474 public void reset() {
475 super.reset();
476 clearContent();
477 }
478
c0188b25 479}
This page took 0.097344 seconds and 5 git commands to generate.