control: Fix dead store sonar warning in destroy session handler
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / widgets / timegraph / TimeGraphCombo.java
CommitLineData
837a2f8c 1/*******************************************************************************
d2e4afa7 2 * Copyright (c) 2012, 2015 Ericsson, others
837a2f8c
PT
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 * Patrick Tasse - Initial API and implementation
f8840316 11 * François Rajotte - Filter implementation
bec1f1ac 12 * Geneviève Bastien - Add event links between entries
b97d61f0 13 * Christian Mansky - Add check active / uncheck inactive buttons
837a2f8c
PT
14 *******************************************************************************/
15
2bdf0193 16package org.eclipse.tracecompass.tmf.ui.widgets.timegraph;
837a2f8c
PT
17
18import java.util.ArrayList;
19import java.util.Arrays;
20import java.util.HashMap;
70e10acc 21import java.util.HashSet;
6ac5a950
AM
22import java.util.List;
23import java.util.Map;
70e10acc 24import java.util.Set;
837a2f8c 25
dfa0ef96 26import org.eclipse.jdt.annotation.NonNull;
4c9c0c87 27import org.eclipse.jface.viewers.AbstractTreeViewer;
837a2f8c
PT
28import org.eclipse.jface.viewers.ILabelProviderListener;
29import org.eclipse.jface.viewers.ISelectionChangedListener;
30import org.eclipse.jface.viewers.IStructuredSelection;
31import org.eclipse.jface.viewers.ITableLabelProvider;
32import org.eclipse.jface.viewers.ITreeContentProvider;
33import org.eclipse.jface.viewers.ITreeViewerListener;
34import org.eclipse.jface.viewers.SelectionChangedEvent;
35import org.eclipse.jface.viewers.StructuredSelection;
36import org.eclipse.jface.viewers.TreeExpansionEvent;
37import org.eclipse.jface.viewers.TreeViewer;
38import org.eclipse.jface.viewers.Viewer;
6ac5a950 39import org.eclipse.jface.viewers.ViewerFilter;
837a2f8c
PT
40import org.eclipse.swt.SWT;
41import org.eclipse.swt.custom.SashForm;
42import org.eclipse.swt.events.ControlAdapter;
43import org.eclipse.swt.events.ControlEvent;
44import org.eclipse.swt.events.MouseEvent;
45import org.eclipse.swt.events.MouseTrackAdapter;
46import org.eclipse.swt.events.MouseWheelListener;
47import org.eclipse.swt.events.PaintEvent;
48import org.eclipse.swt.events.PaintListener;
49import org.eclipse.swt.events.SelectionAdapter;
50import org.eclipse.swt.events.SelectionEvent;
51import org.eclipse.swt.graphics.Image;
52import org.eclipse.swt.graphics.Point;
588dff10 53import org.eclipse.swt.graphics.Rectangle;
837a2f8c 54import org.eclipse.swt.layout.FillLayout;
d2e4afa7 55import org.eclipse.swt.layout.GridLayout;
837a2f8c 56import org.eclipse.swt.widgets.Composite;
d2e4afa7 57import org.eclipse.swt.widgets.Control;
837a2f8c
PT
58import org.eclipse.swt.widgets.Display;
59import org.eclipse.swt.widgets.Event;
60import org.eclipse.swt.widgets.Listener;
d2e4afa7 61import org.eclipse.swt.widgets.Sash;
837a2f8c
PT
62import org.eclipse.swt.widgets.Slider;
63import org.eclipse.swt.widgets.Tree;
64import org.eclipse.swt.widgets.TreeColumn;
65import org.eclipse.swt.widgets.TreeItem;
d2e4afa7
MAL
66import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
67import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
68import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentSignal;
69import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
b97d61f0 70import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.ITimeGraphEntryActiveProvider;
cfcfd964 71import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.ShowFilterDialogAction;
2bdf0193
AM
72import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
73import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
837a2f8c 74
4923d7b9
PT
75import com.google.common.collect.Iterables;
76
837a2f8c
PT
77/**
78 * Time graph "combo" view (with the list/tree on the left and the gantt chart
79 * on the right)
80 *
837a2f8c
PT
81 * @author Patrick Tasse
82 */
83public class TimeGraphCombo extends Composite {
84
85 // ------------------------------------------------------------------------
86 // Constants
87 // ------------------------------------------------------------------------
88
ae09c4ad 89 /** Constant indicating that all levels of the time graph should be expanded */
f4617471
PT
90 public static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
91
837a2f8c
PT
92 private static final Object FILLER = new Object();
93
94 // ------------------------------------------------------------------------
95 // Fields
96 // ------------------------------------------------------------------------
97
4999a196 98 /** The tree viewer */
837a2f8c
PT
99 private TreeViewer fTreeViewer;
100
4999a196 101 /** The time viewer */
dfa0ef96 102 private @NonNull TimeGraphViewer fTimeGraphViewer;
837a2f8c 103
4999a196 104 /** The selection listener map */
507b1336 105 private final Map<ITimeGraphSelectionListener, SelectionListenerWrapper> fSelectionListenerMap = new HashMap<>();
837a2f8c 106
4923d7b9 107 /** The map of viewer filters to viewer filter wrappers */
507b1336 108 private final Map<ViewerFilter, ViewerFilter> fViewerFilterMap = new HashMap<>();
6ac5a950 109
4999a196
GB
110 /**
111 * Flag to block the tree selection changed listener when triggered by the
112 * time graph combo
113 */
837a2f8c
PT
114 private boolean fInhibitTreeSelection = false;
115
4999a196 116 /** Number of filler rows used by the tree content provider */
837a2f8c
PT
117 private int fNumFillerRows;
118
4999a196 119 /** Calculated item height for Linux workaround */
837a2f8c
PT
120 private int fLinuxItemHeight = 0;
121
cfcfd964
PT
122 /** The action that opens the filter dialog */
123 private ShowFilterDialogAction fShowFilterDialogAction;
6ac5a950 124
4999a196
GB
125 /** Default weight of each part of the sash */
126 private static final int[] DEFAULT_WEIGHTS = { 1, 1 };
127
588dff10
PT
128 /** List of all expanded items whose parents are also expanded */
129 private List<TreeItem> fVisibleExpandedItems = null;
130
d2e4afa7
MAL
131 private Listener fSashDragListener;
132 private SashForm fSashForm;
133
837a2f8c
PT
134 // ------------------------------------------------------------------------
135 // Classes
136 // ------------------------------------------------------------------------
137
138 /**
139 * The TreeContentProviderWrapper is used to insert filler items after
140 * the elements of the tree's real content provider.
141 */
142 private class TreeContentProviderWrapper implements ITreeContentProvider {
143 private final ITreeContentProvider contentProvider;
144
145 public TreeContentProviderWrapper(ITreeContentProvider contentProvider) {
146 this.contentProvider = contentProvider;
147 }
148
149 @Override
150 public void dispose() {
151 contentProvider.dispose();
152 }
153
154 @Override
155 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
156 contentProvider.inputChanged(viewer, oldInput, newInput);
157 }
158
159 @Override
160 public Object[] getElements(Object inputElement) {
161 Object[] elements = contentProvider.getElements(inputElement);
162 // add filler elements to ensure alignment with time analysis viewer
f1fae91f 163 Object[] oElements = Arrays.copyOf(elements, elements.length + fNumFillerRows, Object[].class);
837a2f8c
PT
164 for (int i = 0; i < fNumFillerRows; i++) {
165 oElements[elements.length + i] = FILLER;
166 }
167 return oElements;
168 }
169
170 @Override
171 public Object[] getChildren(Object parentElement) {
172 if (parentElement instanceof ITimeGraphEntry) {
173 return contentProvider.getChildren(parentElement);
174 }
175 return new Object[0];
176 }
177
178 @Override
179 public Object getParent(Object element) {
180 if (element instanceof ITimeGraphEntry) {
181 return contentProvider.getParent(element);
182 }
183 return null;
184 }
185
186 @Override
187 public boolean hasChildren(Object element) {
188 if (element instanceof ITimeGraphEntry) {
189 return contentProvider.hasChildren(element);
190 }
191 return false;
192 }
193 }
194
195 /**
196 * The TreeLabelProviderWrapper is used to intercept the filler items
197 * from the calls to the tree's real label provider.
198 */
199 private class TreeLabelProviderWrapper implements ITableLabelProvider {
200 private final ITableLabelProvider labelProvider;
201
202 public TreeLabelProviderWrapper(ITableLabelProvider labelProvider) {
203 this.labelProvider = labelProvider;
204 }
205
206 @Override
207 public void addListener(ILabelProviderListener listener) {
208 labelProvider.addListener(listener);
209 }
210
211 @Override
212 public void dispose() {
213 labelProvider.dispose();
214 }
215
216 @Override
217 public boolean isLabelProperty(Object element, String property) {
218 if (element instanceof ITimeGraphEntry) {
219 return labelProvider.isLabelProperty(element, property);
220 }
221 return false;
222 }
223
224 @Override
225 public void removeListener(ILabelProviderListener listener) {
226 labelProvider.removeListener(listener);
227 }
228
229 @Override
230 public Image getColumnImage(Object element, int columnIndex) {
231 if (element instanceof ITimeGraphEntry) {
232 return labelProvider.getColumnImage(element, columnIndex);
233 }
234 return null;
235 }
236
237 @Override
238 public String getColumnText(Object element, int columnIndex) {
239 if (element instanceof ITimeGraphEntry) {
240 return labelProvider.getColumnText(element, columnIndex);
241 }
242 return null;
243 }
244
245 }
246
247 /**
248 * The SelectionListenerWrapper is used to intercept the filler items from
249 * the time graph combo's real selection listener, and to prevent double
250 * notifications from being sent when selection changes in both tree and
251 * time graph at the same time.
252 */
253 private class SelectionListenerWrapper implements ISelectionChangedListener, ITimeGraphSelectionListener {
254 private final ITimeGraphSelectionListener listener;
255 private ITimeGraphEntry selection = null;
256
257 public SelectionListenerWrapper(ITimeGraphSelectionListener listener) {
258 this.listener = listener;
259 }
260
261 @Override
262 public void selectionChanged(SelectionChangedEvent event) {
263 if (fInhibitTreeSelection) {
264 return;
265 }
266 Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
267 if (element instanceof ITimeGraphEntry) {
268 ITimeGraphEntry entry = (ITimeGraphEntry) element;
269 if (entry != selection) {
270 selection = entry;
271 listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
272 }
273 }
274 }
275
276 @Override
277 public void selectionChanged(TimeGraphSelectionEvent event) {
278 ITimeGraphEntry entry = event.getSelection();
279 if (entry != selection) {
280 selection = entry;
281 listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
282 }
283 }
284 }
285
6ac5a950
AM
286 /**
287 * The ViewerFilterWrapper is used to intercept the filler items from
288 * the time graph combo's real ViewerFilters. These filler items should
289 * always be visible.
290 */
291 private class ViewerFilterWrapper extends ViewerFilter {
292
f1fae91f 293 private ViewerFilter fWrappedFilter;
6ac5a950
AM
294
295 ViewerFilterWrapper(ViewerFilter filter) {
296 super();
297 this.fWrappedFilter = filter;
298 }
299
300 @Override
301 public boolean select(Viewer viewer, Object parentElement, Object element) {
302 if (element instanceof ITimeGraphEntry) {
303 return fWrappedFilter.select(viewer, parentElement, element);
304 }
305 return true;
306 }
307
308 }
309
837a2f8c
PT
310 // ------------------------------------------------------------------------
311 // Constructors
312 // ------------------------------------------------------------------------
313
314 /**
315 * Constructs a new instance of this class given its parent
316 * and a style value describing its behavior and appearance.
317 *
318 * @param parent a widget which will be the parent of the new instance (cannot be null)
319 * @param style the style of widget to construct
320 */
321 public TimeGraphCombo(Composite parent, int style) {
4999a196
GB
322 this(parent, style, DEFAULT_WEIGHTS);
323 }
324
325 /**
326 * Constructs a new instance of this class given its parent and a style
327 * value describing its behavior and appearance.
328 *
329 * @param parent
330 * a widget which will be the parent of the new instance (cannot
331 * be null)
332 * @param style
333 * the style of widget to construct
334 * @param weights
d2e4afa7 335 * The array (length 2) of relative weights of each side of the sash form
4999a196
GB
336 */
337 public TimeGraphCombo(Composite parent, int style, int[] weights) {
837a2f8c
PT
338 super(parent, style);
339 setLayout(new FillLayout());
340
d2e4afa7 341 fSashForm = new SashForm(this, SWT.NONE);
837a2f8c 342
d2e4afa7 343 fTreeViewer = new TreeViewer(fSashForm, SWT.FULL_SELECTION | SWT.H_SCROLL);
4c9c0c87 344 fTreeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
837a2f8c
PT
345 final Tree tree = fTreeViewer.getTree();
346 tree.setHeaderVisible(true);
347 tree.setLinesVisible(true);
348
d2e4afa7 349 fTimeGraphViewer = new TimeGraphViewer(fSashForm, SWT.NONE);
837a2f8c
PT
350 fTimeGraphViewer.setItemHeight(getItemHeight(tree));
351 fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
352 fTimeGraphViewer.setBorderWidth(tree.getBorderWidth());
353 fTimeGraphViewer.setNameWidthPref(0);
354
355 // Feature in Windows. The tree vertical bar reappears when
356 // the control is resized so we need to hide it again.
837a2f8c 357 tree.addControlListener(new ControlAdapter() {
f1fae91f 358 private int depth = 0;
837a2f8c
PT
359 @Override
360 public void controlResized(ControlEvent e) {
361 if (depth == 0) {
362 depth++;
363 tree.getVerticalBar().setEnabled(false);
364 // this can trigger controlResized recursively
365 tree.getVerticalBar().setVisible(false);
366 depth--;
367 }
3573a01c
MAL
368 }
369 });
370 // Bug in Linux. The tree header height is 0 in constructor,
371 // so we need to reset it later when the control is painted.
372 // This work around used to be done on control resized but the header
373 // height was not initialized on the initial resize on GTK3.
374 tree.addPaintListener(new PaintListener() {
375 @Override
376 public void paintControl(PaintEvent e) {
377 int headerHeight = tree.getHeaderHeight();
378 if (headerHeight > 0) {
379 fTimeGraphViewer.setHeaderHeight(headerHeight);
380 tree.removePaintListener(this);
381 }
837a2f8c
PT
382 }
383 });
384
385 // ensure synchronization of expanded items between tree and time graph
386 fTreeViewer.addTreeListener(new ITreeViewerListener() {
387 @Override
388 public void treeCollapsed(TreeExpansionEvent event) {
389 fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), false);
588dff10
PT
390 // queue the alignment update because the tree items may only be
391 // actually collapsed after the listeners have been notified
392 fVisibleExpandedItems = null; // invalidate the cache
393 getDisplay().asyncExec(new Runnable() {
394 @Override
395 public void run() {
396 alignTreeItems(true);
397 }});
837a2f8c
PT
398 }
399
400 @Override
401 public void treeExpanded(TreeExpansionEvent event) {
e7708b02
PT
402 ITimeGraphEntry entry = (ITimeGraphEntry) event.getElement();
403 fTimeGraphViewer.setExpandedState(entry, true);
70e10acc 404 Set<Object> expandedElements = new HashSet<>(Arrays.asList(fTreeViewer.getExpandedElements()));
e7708b02 405 for (ITimeGraphEntry child : entry.getChildren()) {
70e10acc
PT
406 if (child.hasChildren()) {
407 boolean expanded = expandedElements.contains(child);
408 fTimeGraphViewer.setExpandedState(child, expanded);
409 }
e7708b02 410 }
588dff10
PT
411 // queue the alignment update because the tree items may only be
412 // actually expanded after the listeners have been notified
413 fVisibleExpandedItems = null; // invalidate the cache
837a2f8c
PT
414 getDisplay().asyncExec(new Runnable() {
415 @Override
416 public void run() {
588dff10 417 alignTreeItems(true);
837a2f8c
PT
418 }});
419 }
420 });
421
422 // ensure synchronization of expanded items between tree and time graph
423 fTimeGraphViewer.addTreeListener(new ITimeGraphTreeListener() {
424 @Override
425 public void treeCollapsed(TimeGraphTreeExpansionEvent event) {
426 fTreeViewer.setExpandedState(event.getEntry(), false);
588dff10 427 alignTreeItems(true);
837a2f8c
PT
428 }
429
430 @Override
431 public void treeExpanded(TimeGraphTreeExpansionEvent event) {
e7708b02
PT
432 ITimeGraphEntry entry = event.getEntry();
433 fTreeViewer.setExpandedState(entry, true);
70e10acc 434 Set<Object> expandedElements = new HashSet<>(Arrays.asList(fTreeViewer.getExpandedElements()));
e7708b02 435 for (ITimeGraphEntry child : entry.getChildren()) {
70e10acc
PT
436 if (child.hasChildren()) {
437 boolean expanded = expandedElements.contains(child);
438 fTimeGraphViewer.setExpandedState(child, expanded);
439 }
e7708b02 440 }
588dff10 441 alignTreeItems(true);
837a2f8c
PT
442 }
443 });
444
445 // prevent mouse button from selecting a filler tree item
446 tree.addListener(SWT.MouseDown, new Listener() {
447 @Override
448 public void handleEvent(Event event) {
449 TreeItem treeItem = tree.getItem(new Point(event.x, event.y));
450 if (treeItem == null || treeItem.getData() == FILLER) {
451 event.doit = false;
588dff10 452 List<TreeItem> treeItems = getVisibleExpandedItems(tree, false);
837a2f8c
PT
453 if (treeItems.size() == 0) {
454 fTreeViewer.setSelection(new StructuredSelection());
455 fTimeGraphViewer.setSelection(null);
456 return;
457 }
458 // this prevents from scrolling up when selecting
459 // the partially visible tree item at the bottom
460 tree.select(treeItems.get(treeItems.size() - 1));
461 fTreeViewer.setSelection(new StructuredSelection());
462 fTimeGraphViewer.setSelection(null);
463 }
464 }
465 });
466
467 // prevent mouse wheel from scrolling down into filler tree items
468 tree.addListener(SWT.MouseWheel, new Listener() {
469 @Override
470 public void handleEvent(Event event) {
471 event.doit = false;
472 Slider scrollBar = fTimeGraphViewer.getVerticalBar();
473 fTimeGraphViewer.setTopIndex(scrollBar.getSelection() - event.count);
588dff10 474 alignTreeItems(false);
837a2f8c
PT
475 }
476 });
477
478 // prevent key stroke from selecting a filler tree item
479 tree.addListener(SWT.KeyDown, new Listener() {
480 @Override
481 public void handleEvent(Event event) {
588dff10 482 List<TreeItem> treeItems = getVisibleExpandedItems(tree, false);
837a2f8c
PT
483 if (treeItems.size() == 0) {
484 fTreeViewer.setSelection(new StructuredSelection());
485 event.doit = false;
486 return;
487 }
488 if (event.keyCode == SWT.ARROW_DOWN) {
489 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + 1, treeItems.size() - 1);
490 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
491 event.doit = false;
492 } else if (event.keyCode == SWT.PAGE_DOWN) {
493 int height = tree.getSize().y - tree.getHeaderHeight() - tree.getHorizontalBar().getSize().y;
494 int countPerPage = height / getItemHeight(tree);
495 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + countPerPage - 1, treeItems.size() - 1);
496 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
497 event.doit = false;
498 } else if (event.keyCode == SWT.END) {
499 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(treeItems.size() - 1).getData());
500 event.doit = false;
501 }
837a2f8c
PT
502 if (fTimeGraphViewer.getSelectionIndex() >= 0) {
503 fTreeViewer.setSelection(new StructuredSelection(fTimeGraphViewer.getSelection()));
504 } else {
505 fTreeViewer.setSelection(new StructuredSelection());
506 }
588dff10 507 alignTreeItems(false);
837a2f8c
PT
508 }
509 });
510
511 // ensure alignment of top item between tree and time graph
512 fTimeGraphViewer.getTimeGraphControl().addControlListener(new ControlAdapter() {
513 @Override
514 public void controlResized(ControlEvent e) {
588dff10 515 alignTreeItems(false);
837a2f8c
PT
516 }
517 });
518
519 // ensure synchronization of selected item between tree and time graph
520 fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
521 @Override
522 public void selectionChanged(SelectionChangedEvent event) {
523 if (fInhibitTreeSelection) {
524 return;
525 }
526 if (event.getSelection() instanceof IStructuredSelection) {
527 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
528 if (selection instanceof ITimeGraphEntry) {
529 fTimeGraphViewer.setSelection((ITimeGraphEntry) selection);
530 }
588dff10 531 alignTreeItems(false);
837a2f8c
PT
532 }
533 }
534 });
535
536 // ensure synchronization of selected item between tree and time graph
537 fTimeGraphViewer.addSelectionListener(new ITimeGraphSelectionListener() {
538 @Override
539 public void selectionChanged(TimeGraphSelectionEvent event) {
540 ITimeGraphEntry entry = fTimeGraphViewer.getSelection();
541 fInhibitTreeSelection = true; // block the tree selection changed listener
542 if (entry != null) {
543 StructuredSelection selection = new StructuredSelection(entry);
544 fTreeViewer.setSelection(selection);
545 } else {
546 fTreeViewer.setSelection(new StructuredSelection());
547 }
548 fInhibitTreeSelection = false;
588dff10 549 alignTreeItems(false);
837a2f8c
PT
550 }
551 });
552
553 // ensure alignment of top item between tree and time graph
554 fTimeGraphViewer.getVerticalBar().addSelectionListener(new SelectionAdapter() {
555 @Override
556 public void widgetSelected(SelectionEvent e) {
588dff10 557 alignTreeItems(false);
837a2f8c
PT
558 }
559 });
560
561 // ensure alignment of top item between tree and time graph
562 fTimeGraphViewer.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
563 @Override
564 public void mouseScrolled(MouseEvent e) {
588dff10 565 alignTreeItems(false);
837a2f8c
PT
566 }
567 });
568
569 // ensure the tree has focus control when mouse is over it if the time graph had control
570 fTreeViewer.getControl().addMouseTrackListener(new MouseTrackAdapter() {
571 @Override
572 public void mouseEnter(MouseEvent e) {
573 if (fTimeGraphViewer.getTimeGraphControl().isFocusControl()) {
574 fTreeViewer.getControl().setFocus();
575 }
576 }
577 });
578
579 // ensure the time graph has focus control when mouse is over it if the tree had control
580 fTimeGraphViewer.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
581 @Override
582 public void mouseEnter(MouseEvent e) {
583 if (fTreeViewer.getControl().isFocusControl()) {
584 fTimeGraphViewer.getTimeGraphControl().setFocus();
585 }
586 }
587 });
588 fTimeGraphViewer.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
589 @Override
590 public void mouseEnter(MouseEvent e) {
591 if (fTreeViewer.getControl().isFocusControl()) {
592 fTimeGraphViewer.getTimeGraphControl().setFocus();
593 }
594 }
595 });
596
597 // The filler rows are required to ensure alignment when the tree does not have a
598 // visible horizontal scroll bar. The tree does not allow its top item to be set
599 // to a value that would cause blank space to be drawn at the bottom of the tree.
600 fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree);
601
d2e4afa7
MAL
602 fSashForm.setWeights(weights);
603
604 fTimeGraphViewer.getTimeGraphControl().addPaintListener(new PaintListener() {
605 @Override
606 public void paintControl(PaintEvent e) {
607 // Sashes in a SashForm are being created on layout so add the
608 // drag listener here
609 if (fSashDragListener == null) {
610 for (Control control : fSashForm.getChildren()) {
611 if (control instanceof Sash) {
612 fSashDragListener = new Listener() {
613
614 @Override
615 public void handleEvent(Event event) {
616 sendTimeViewAlignmentChanged();
617
618 }
619 };
620 control.removePaintListener(this);
621 control.addListener(SWT.Selection, fSashDragListener);
622 // There should be only one sash
623 break;
624 }
625 }
626 }
627 }
628 });
629 }
630
631 private void sendTimeViewAlignmentChanged() {
632 TmfSignalManager.dispatchSignal(new TmfTimeViewAlignmentSignal(fSashForm, getTimeViewAlignmentInfo()));
837a2f8c
PT
633 }
634
635 // ------------------------------------------------------------------------
636 // Accessors
637 // ------------------------------------------------------------------------
638
639 /**
640 * Returns this time graph combo's tree viewer.
641 *
642 * @return the tree viewer
643 */
644 public TreeViewer getTreeViewer() {
645 return fTreeViewer;
646 }
647
648 /**
649 * Returns this time graph combo's time graph viewer.
650 *
651 * @return the time graph viewer
652 */
dfa0ef96 653 public @NonNull TimeGraphViewer getTimeGraphViewer() {
837a2f8c
PT
654 return fTimeGraphViewer;
655 }
656
6ac5a950 657 /**
cfcfd964
PT
658 * Get the show filter dialog action.
659 *
660 * @return The Action object
661 * @since 2.0
6ac5a950 662 */
cfcfd964
PT
663 public ShowFilterDialogAction getShowFilterDialogAction() {
664 if (fShowFilterDialogAction == null) {
665 fShowFilterDialogAction = new ShowFilterDialogAction(fTimeGraphViewer) {
666 @Override
667 protected void addFilter(ViewerFilter filter) {
668 /* add filter to the combo instead of the viewer */
669 TimeGraphCombo.this.addFilter(filter);
8f28f9d8 670 }
cfcfd964
PT
671
672 @Override
673 protected void removeFilter(ViewerFilter filter) {
674 /* remove filter from the combo instead of the viewer */
675 TimeGraphCombo.this.removeFilter(filter);
6ac5a950 676 }
6ac5a950 677
6ac5a950 678 @Override
cfcfd964
PT
679 protected void refresh() {
680 /* refresh the combo instead of the viewer */
681 TimeGraphCombo.this.refresh();
6ac5a950
AM
682 }
683 };
6ac5a950 684 }
cfcfd964 685 return fShowFilterDialogAction;
6ac5a950
AM
686 }
687
837a2f8c
PT
688 // ------------------------------------------------------------------------
689 // Control
690 // ------------------------------------------------------------------------
691
837a2f8c
PT
692 @Override
693 public void redraw() {
694 fTimeGraphViewer.getControl().redraw();
695 super.redraw();
696 }
697
698 // ------------------------------------------------------------------------
699 // Operations
700 // ------------------------------------------------------------------------
701
702 /**
703 * Sets the tree content provider used by this time graph combo.
704 *
705 * @param contentProvider the tree content provider
706 */
707 public void setTreeContentProvider(ITreeContentProvider contentProvider) {
708 fTreeViewer.setContentProvider(new TreeContentProviderWrapper(contentProvider));
709 }
710
711 /**
712 * Sets the tree label provider used by this time graph combo.
713 *
714 * @param labelProvider the tree label provider
715 */
716 public void setTreeLabelProvider(ITableLabelProvider labelProvider) {
717 fTreeViewer.setLabelProvider(new TreeLabelProviderWrapper(labelProvider));
718 }
719
6ac5a950
AM
720 /**
721 * Sets the tree content provider used by the filter dialog
722 *
723 * @param contentProvider the tree content provider
6ac5a950
AM
724 */
725 public void setFilterContentProvider(ITreeContentProvider contentProvider) {
cfcfd964 726 getShowFilterDialogAction().getFilterDialog().setContentProvider(contentProvider);
6ac5a950
AM
727 }
728
729 /**
730 * Sets the tree label provider used by the filter dialog
731 *
732 * @param labelProvider the tree label provider
6ac5a950
AM
733 */
734 public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
cfcfd964 735 getShowFilterDialogAction().getFilterDialog().setLabelProvider(labelProvider);
6ac5a950
AM
736 }
737
b97d61f0
CM
738 /**
739 * Adds a "check active" button used by the filter dialog
740 *
741 * @param activeProvider
742 * Additional button info specific to a certain view.
743 * @since 1.0
744 */
745 public void addTimeGraphFilterCheckActiveButton(ITimeGraphEntryActiveProvider activeProvider) {
cfcfd964 746 getShowFilterDialogAction().getFilterDialog().addTimeGraphFilterCheckActiveButton(activeProvider);
b97d61f0
CM
747 }
748
749 /**
750 * Adds an "uncheck inactive" button used by the filter dialog
751 *
752 * @param inactiveProvider
753 * Additional button info specific to a certain view.
754 * @since 1.0
755 */
756 public void addTimeGraphFilterUncheckInactiveButton(ITimeGraphEntryActiveProvider inactiveProvider) {
cfcfd964 757 getShowFilterDialogAction().getFilterDialog().addTimeGraphFilterUncheckInactiveButton(inactiveProvider);
b97d61f0
CM
758 }
759
837a2f8c
PT
760 /**
761 * Sets the tree columns for this time graph combo.
762 *
763 * @param columnNames the tree column names
764 */
765 public void setTreeColumns(String[] columnNames) {
766 final Tree tree = fTreeViewer.getTree();
767 for (String columnName : columnNames) {
768 TreeColumn column = new TreeColumn(tree, SWT.LEFT);
769 column.setText(columnName);
770 column.pack();
771 }
772 }
773
6ac5a950
AM
774 /**
775 * Sets the tree columns for this time graph combo's filter dialog.
776 *
777 * @param columnNames the tree column names
6ac5a950
AM
778 */
779 public void setFilterColumns(String[] columnNames) {
cfcfd964 780 getShowFilterDialogAction().getFilterDialog().setColumnNames(columnNames);
6ac5a950
AM
781 }
782
837a2f8c 783 /**
4c9c0c87
PT
784 * Sets the time graph content provider used by this time graph combo.
785 *
786 * @param timeGraphContentProvider
787 * the time graph content provider
4c9c0c87
PT
788 */
789 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider) {
790 fTimeGraphViewer.setTimeGraphContentProvider(timeGraphContentProvider);
791 }
792
793 /**
794 * Sets the time graph presentation provider used by this time graph combo.
837a2f8c
PT
795 *
796 * @param timeGraphProvider the time graph provider
797 */
798 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
799 fTimeGraphViewer.setTimeGraphProvider(timeGraphProvider);
800 }
801
802 /**
803 * Sets or clears the input for this time graph combo.
837a2f8c
PT
804 *
805 * @param input the input of this time graph combo, or <code>null</code> if none
806 */
4c9c0c87 807 public void setInput(Object input) {
837a2f8c
PT
808 fInhibitTreeSelection = true;
809 fTreeViewer.setInput(input);
810 for (SelectionListenerWrapper listenerWrapper : fSelectionListenerMap.values()) {
811 listenerWrapper.selection = null;
812 }
813 fInhibitTreeSelection = false;
837a2f8c
PT
814 fTreeViewer.getTree().getVerticalBar().setEnabled(false);
815 fTreeViewer.getTree().getVerticalBar().setVisible(false);
837a2f8c 816 fTimeGraphViewer.setInput(input);
63b93cd6 817 fTimeGraphViewer.setItemHeight(getItemHeight(fTreeViewer.getTree()));
588dff10
PT
818 // queue the alignment update because in Linux the item bounds are not
819 // set properly until the tree has been painted at least once
820 fVisibleExpandedItems = null; // invalidate the cache
821 getDisplay().asyncExec(new Runnable() {
822 @Override
823 public void run() {
824 alignTreeItems(true);
825 }});
837a2f8c
PT
826 }
827
4c9c0c87
PT
828 /**
829 * Gets the input for this time graph combo.
830 *
831 * @return The input of this time graph combo, or <code>null</code> if none
4c9c0c87
PT
832 */
833 public Object getInput() {
834 return fTreeViewer.getInput();
835 }
836
bec1f1ac
GB
837 /**
838 * Sets or clears the list of links to display on this combo
839 *
840 * @param links the links to display in this time graph combo
bec1f1ac
GB
841 */
842 public void setLinks(List<ILinkEvent> links) {
843 fTimeGraphViewer.setLinks(links);
844 }
845
6ac5a950
AM
846 /**
847 * @param filter The filter object to be attached to the view
6ac5a950
AM
848 */
849 public void addFilter(ViewerFilter filter) {
cfcfd964 850 fInhibitTreeSelection = true;
6ac5a950
AM
851 ViewerFilter wrapper = new ViewerFilterWrapper(filter);
852 fTreeViewer.addFilter(wrapper);
4923d7b9 853 fTimeGraphViewer.addFilter(filter);
6ac5a950 854 fViewerFilterMap.put(filter, wrapper);
588dff10 855 alignTreeItems(true);
cfcfd964 856 fInhibitTreeSelection = false;
6ac5a950
AM
857 }
858
859 /**
860 * @param filter The filter object to be removed from the view
6ac5a950
AM
861 */
862 public void removeFilter(ViewerFilter filter) {
cfcfd964 863 fInhibitTreeSelection = true;
6ac5a950
AM
864 ViewerFilter wrapper = fViewerFilterMap.get(filter);
865 fTreeViewer.removeFilter(wrapper);
4923d7b9 866 fTimeGraphViewer.removeFilter(filter);
6ac5a950 867 fViewerFilterMap.remove(filter);
588dff10 868 alignTreeItems(true);
cfcfd964 869 fInhibitTreeSelection = false;
6ac5a950
AM
870 }
871
4923d7b9
PT
872 /**
873 * Returns this viewer's filters.
874 *
875 * @return an array of viewer filters
876 * @since 2.0
877 */
878 public ViewerFilter[] getFilters() {
879 return fTimeGraphViewer.getFilters();
880 }
881
882 /**
883 * Sets the filters, replacing any previous filters, and triggers
884 * refiltering of the elements.
885 *
886 * @param filters
887 * an array of viewer filters, or null
888 * @since 2.0
889 */
890 public void setFilters(ViewerFilter[] filters) {
cfcfd964 891 fInhibitTreeSelection = true;
4923d7b9
PT
892 fViewerFilterMap.clear();
893 if (filters == null) {
894 fTreeViewer.resetFilters();
895 } else {
896 for (ViewerFilter filter : filters) {
897 ViewerFilter wrapper = new ViewerFilterWrapper(filter);
898 fViewerFilterMap.put(filter, wrapper);
899 }
900 ViewerFilter[] wrappers = Iterables.toArray(fViewerFilterMap.values(), ViewerFilter.class);
901 fTreeViewer.setFilters(wrappers);
902 }
903 fTimeGraphViewer.setFilters(filters);
904 alignTreeItems(true);
cfcfd964 905 fInhibitTreeSelection = false;
4923d7b9
PT
906 }
907
837a2f8c
PT
908 /**
909 * Refreshes this time graph completely with information freshly obtained from its model.
910 */
911 public void refresh() {
912 fInhibitTreeSelection = true;
4c9c0c87 913 Tree tree = fTreeViewer.getTree();
ece2fc5f
PT
914 try {
915 tree.setRedraw(false);
916 fTreeViewer.refresh();
ece2fc5f
PT
917 } finally {
918 tree.setRedraw(true);
919 }
837a2f8c 920 fTimeGraphViewer.refresh();
588dff10 921 alignTreeItems(true);
837a2f8c
PT
922 fInhibitTreeSelection = false;
923 }
924
925 /**
926 * Adds a listener for selection changes in this time graph combo.
927 *
928 * @param listener a selection listener
929 */
930 public void addSelectionListener(ITimeGraphSelectionListener listener) {
931 SelectionListenerWrapper listenerWrapper = new SelectionListenerWrapper(listener);
932 fTreeViewer.addSelectionChangedListener(listenerWrapper);
933 fSelectionListenerMap.put(listener, listenerWrapper);
934 fTimeGraphViewer.addSelectionListener(listenerWrapper);
935 }
936
937 /**
938 * Removes the given selection listener from this time graph combo.
939 *
940 * @param listener a selection changed listener
941 */
942 public void removeSelectionListener(ITimeGraphSelectionListener listener) {
943 SelectionListenerWrapper listenerWrapper = fSelectionListenerMap.remove(listener);
944 fTreeViewer.removeSelectionChangedListener(listenerWrapper);
945 fTimeGraphViewer.removeSelectionListener(listenerWrapper);
946 }
947
948 /**
949 * Sets the current selection for this time graph combo.
950 *
951 * @param selection the new selection
952 */
953 public void setSelection(ITimeGraphEntry selection) {
954 fTimeGraphViewer.setSelection(selection);
955 fInhibitTreeSelection = true; // block the tree selection changed listener
956 if (selection != null) {
957 StructuredSelection structuredSelection = new StructuredSelection(selection);
958 fTreeViewer.setSelection(structuredSelection);
959 } else {
960 fTreeViewer.setSelection(new StructuredSelection());
961 }
962 fInhibitTreeSelection = false;
588dff10 963 alignTreeItems(false);
837a2f8c
PT
964 }
965
f4617471 966 /**
df0e3d5f
PT
967 * Sets the auto-expand level to be used for new entries discovered when
968 * calling {@link #setInput(Object)} or {@link #refresh()}. The value 0
969 * means that there is no auto-expand; 1 means that top-level entries are
970 * expanded, but not their children; 2 means that top-level entries are
971 * expanded, and their children, but not grand-children; and so on.
f4617471
PT
972 * <p>
973 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
974 * </p>
df0e3d5f 975 *
f4617471
PT
976 * @param level
977 * non-negative level, or <code>ALL_LEVELS</code> to expand all
978 * levels of the tree
f4617471
PT
979 */
980 public void setAutoExpandLevel(int level) {
981 fTimeGraphViewer.setAutoExpandLevel(level);
982 if (level <= 0) {
983 fTreeViewer.setAutoExpandLevel(level);
984 } else {
985 fTreeViewer.setAutoExpandLevel(level + 1);
986 }
987 }
988
989 /**
990 * Returns the auto-expand level.
991 *
992 * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of
993 * the tree are expanded automatically
994 * @see #setAutoExpandLevel
f4617471
PT
995 */
996 public int getAutoExpandLevel() {
997 return fTimeGraphViewer.getAutoExpandLevel();
998 }
999
837a2f8c
PT
1000 /**
1001 * Set the expanded state of an entry
1002 *
1003 * @param entry
1004 * The entry to expand/collapse
1005 * @param expanded
1006 * True for expanded, false for collapsed
837a2f8c
PT
1007 */
1008 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
1009 fTimeGraphViewer.setExpandedState(entry, expanded);
1010 fTreeViewer.setExpandedState(entry, expanded);
588dff10 1011 alignTreeItems(true);
837a2f8c
PT
1012 }
1013
1014 /**
1015 * Collapses all nodes of the viewer's tree, starting with the root.
837a2f8c
PT
1016 */
1017 public void collapseAll() {
1018 fTimeGraphViewer.collapseAll();
1019 fTreeViewer.collapseAll();
588dff10 1020 alignTreeItems(true);
837a2f8c
PT
1021 }
1022
1023 /**
1024 * Expands all nodes of the viewer's tree, starting with the root.
837a2f8c
PT
1025 */
1026 public void expandAll() {
1027 fTimeGraphViewer.expandAll();
1028 fTreeViewer.expandAll();
588dff10 1029 alignTreeItems(true);
837a2f8c
PT
1030 }
1031
1032 // ------------------------------------------------------------------------
1033 // Internal
1034 // ------------------------------------------------------------------------
1035
588dff10
PT
1036 private List<TreeItem> getVisibleExpandedItems(Tree tree, boolean refresh) {
1037 if (fVisibleExpandedItems == null || refresh) {
df0e3d5f
PT
1038 List<TreeItem> visibleExpandedItems = new ArrayList<>();
1039 addVisibleExpandedItems(visibleExpandedItems, tree.getItems());
1040 fVisibleExpandedItems = visibleExpandedItems;
837a2f8c 1041 }
588dff10 1042 return fVisibleExpandedItems;
837a2f8c
PT
1043 }
1044
df0e3d5f
PT
1045 private void addVisibleExpandedItems(List<TreeItem> visibleExpandedItems, TreeItem[] items) {
1046 for (TreeItem item : items) {
1047 Object data = item.getData();
1048 if (data == FILLER) {
1049 break;
1050 }
1051 visibleExpandedItems.add(item);
1052 boolean expandedState = fTimeGraphViewer.getExpandedState((ITimeGraphEntry) data);
1053 if (item.getExpanded() != expandedState) {
1054 /* synchronize the expanded state of both viewers */
1055 fTreeViewer.setExpandedState(data, expandedState);
1056 }
1057 if (expandedState) {
1058 addVisibleExpandedItems(visibleExpandedItems, item.getItems());
837a2f8c
PT
1059 }
1060 }
837a2f8c
PT
1061 }
1062
1063 private int getItemHeight(final Tree tree) {
1064 /*
1065 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
1066 */
1067 if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
1068 if (fLinuxItemHeight != 0) {
1069 return fLinuxItemHeight;
1070 }
ff2990ed
BH
1071
1072 if (getVisibleExpandedItems(tree, true).size() > 1) {
837a2f8c
PT
1073 PaintListener paintListener = new PaintListener() {
1074 @Override
1075 public void paintControl(PaintEvent e) {
ff2990ed
BH
1076 // get the treeItems here to have all items
1077 List<TreeItem> treeItems = getVisibleExpandedItems(tree, true);
1078 if (treeItems.size() < 2) {
1079 return;
1080 }
1081 final TreeItem treeItem0 = treeItems.get(0);
1082 final TreeItem treeItem1 = treeItems.get(1);
837a2f8c
PT
1083 tree.removePaintListener(this);
1084 int y0 = treeItem0.getBounds().y;
1085 int y1 = treeItem1.getBounds().y;
1086 int itemHeight = y1 - y0;
1087 if (itemHeight > 0) {
1088 fLinuxItemHeight = itemHeight;
1089 fTimeGraphViewer.setItemHeight(itemHeight);
1090 }
1091 }
1092 };
1093 tree.addPaintListener(paintListener);
1094 }
1095 } else {
1096 fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore
1097 }
1098 return tree.getItemHeight();
1099 }
1100
588dff10
PT
1101 private void alignTreeItems(boolean refreshExpandedItems) {
1102 // align the tree top item with the time graph top item
1103 Tree tree = fTreeViewer.getTree();
1104 List<TreeItem> treeItems = getVisibleExpandedItems(tree, refreshExpandedItems);
1105 int topIndex = fTimeGraphViewer.getTopIndex();
1106 if (topIndex >= treeItems.size()) {
1107 return;
1108 }
1109 TreeItem item = treeItems.get(topIndex);
1110 tree.setTopItem(item);
1111
1112 // ensure the time graph item heights are equal to the tree item heights
1113 int treeHeight = fTreeViewer.getTree().getBounds().height;
1114 int index = topIndex;
1115 Rectangle bounds = item.getBounds();
1116 while (index < treeItems.size() - 1) {
1117 if (bounds.y > treeHeight) {
1118 break;
1119 }
1120 /*
1121 * Bug in Linux. The method getBounds doesn't always return the correct height.
1122 * Use the difference of y position between items to calculate the height.
1123 */
1124 TreeItem nextItem = treeItems.get(index + 1);
1125 Rectangle nextBounds = nextItem.getBounds();
1126 Integer itemHeight = nextBounds.y - bounds.y;
63b93cd6 1127 if (itemHeight > 0) {
588dff10 1128 ITimeGraphEntry entry = (ITimeGraphEntry) item.getData();
63b93cd6 1129 fTimeGraphViewer.getTimeGraphControl().setItemHeight(entry, itemHeight);
588dff10
PT
1130 }
1131 index++;
1132 item = nextItem;
1133 bounds = nextBounds;
1134 }
1135 }
1136
d2e4afa7
MAL
1137 /**
1138 * Return the time alignment information
1139 *
1140 * @return the time alignment information
1141 *
1142 * @see ITmfTimeAligned
1143 *
1144 * @since 1.0
1145 */
1146 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
d2e4afa7 1147 Point location = fSashForm.toDisplay(0, 0);
2e23a015
PT
1148 int timeAxisOffset = fTreeViewer.getControl().getSize().x + fSashForm.getSashWidth();
1149 return new TmfTimeViewAlignmentInfo(fSashForm.getShell(), location, timeAxisOffset);
d2e4afa7
MAL
1150 }
1151
1152 /**
1153 * Return the available width for the time-axis.
1154 *
1155 * @see ITmfTimeAligned
1156 *
1157 * @param requestedOffset
1158 * the requested offset
1159 * @return the available width for the time-axis
1160 *
1161 * @since 1.0
1162 */
1163 public int getAvailableWidth(int requestedOffset) {
89316ebe 1164 int vBarWidth = ((fTimeGraphViewer.getVerticalBar() != null) && (fTimeGraphViewer.getVerticalBar().isVisible())) ? fTimeGraphViewer.getVerticalBar().getSize().x : 0;
d2e4afa7 1165 int totalWidth = fSashForm.getBounds().width;
89316ebe 1166 return Math.min(totalWidth, Math.max(0, totalWidth - requestedOffset - vBarWidth));
d2e4afa7
MAL
1167 }
1168
1169 /**
1170 * Perform the alignment operation.
1171 *
1172 * @param offset
1173 * the alignment offset
1174 * @param width
1175 * the alignment width
1176 *
1177 * @see ITmfTimeAligned
1178 *
1179 * @since 1.0
1180 */
1181 public void performAlign(int offset, int width) {
1182 int total = fSashForm.getBounds().width;
1183 int timeAxisOffset = Math.min(offset, total);
c34ab48a
PT
1184 int width1 = Math.max(0, timeAxisOffset - fSashForm.getSashWidth());
1185 int width2 = total - timeAxisOffset;
1186 fSashForm.setWeights(new int[] { width1, width2 });
d2e4afa7
MAL
1187 fSashForm.layout();
1188
1189 Composite composite = fTimeGraphViewer.getTimeAlignedComposite();
1190 GridLayout layout = (GridLayout) composite.getLayout();
1191 int timeBasedControlsWidth = composite.getSize().x;
1192 int marginSize = timeBasedControlsWidth - width;
1193 layout.marginRight = Math.max(0, marginSize);
1194 composite.layout();
1195 }
837a2f8c 1196}
This page took 0.141212 seconds and 5 git commands to generate.