1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson, others
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 * Patrick Tasse - Initial API and implementation
11 * François Rajotte - Filter implementation
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
;
16 import java
.util
.ArrayList
;
17 import java
.util
.Arrays
;
18 import java
.util
.HashMap
;
19 import java
.util
.List
;
22 import org
.eclipse
.jface
.action
.Action
;
23 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
24 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
25 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
26 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
27 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
28 import org
.eclipse
.jface
.viewers
.ITreeViewerListener
;
29 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
30 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
31 import org
.eclipse
.jface
.viewers
.TreeExpansionEvent
;
32 import org
.eclipse
.jface
.viewers
.TreeViewer
;
33 import org
.eclipse
.jface
.viewers
.Viewer
;
34 import org
.eclipse
.jface
.viewers
.ViewerFilter
;
35 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
36 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.ITmfImageConstants
;
37 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Messages
;
38 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.dialogs
.TimeGraphFilterDialog
;
39 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
40 import org
.eclipse
.swt
.SWT
;
41 import org
.eclipse
.swt
.custom
.SashForm
;
42 import org
.eclipse
.swt
.events
.ControlAdapter
;
43 import org
.eclipse
.swt
.events
.ControlEvent
;
44 import org
.eclipse
.swt
.events
.MouseEvent
;
45 import org
.eclipse
.swt
.events
.MouseTrackAdapter
;
46 import org
.eclipse
.swt
.events
.MouseWheelListener
;
47 import org
.eclipse
.swt
.events
.PaintEvent
;
48 import org
.eclipse
.swt
.events
.PaintListener
;
49 import org
.eclipse
.swt
.events
.SelectionAdapter
;
50 import org
.eclipse
.swt
.events
.SelectionEvent
;
51 import org
.eclipse
.swt
.graphics
.Image
;
52 import org
.eclipse
.swt
.graphics
.Point
;
53 import org
.eclipse
.swt
.layout
.FillLayout
;
54 import org
.eclipse
.swt
.widgets
.Composite
;
55 import org
.eclipse
.swt
.widgets
.Display
;
56 import org
.eclipse
.swt
.widgets
.Event
;
57 import org
.eclipse
.swt
.widgets
.Listener
;
58 import org
.eclipse
.swt
.widgets
.Slider
;
59 import org
.eclipse
.swt
.widgets
.Tree
;
60 import org
.eclipse
.swt
.widgets
.TreeColumn
;
61 import org
.eclipse
.swt
.widgets
.TreeItem
;
64 * Time graph "combo" view (with the list/tree on the left and the gantt chart
68 * @author Patrick Tasse
70 public class TimeGraphCombo
extends Composite
{
72 // ------------------------------------------------------------------------
74 // ------------------------------------------------------------------------
76 private static final Object FILLER
= new Object();
78 // ------------------------------------------------------------------------
80 // ------------------------------------------------------------------------
82 /** The tree viewer */
83 private TreeViewer fTreeViewer
;
85 /** The time viewer */
86 private TimeGraphViewer fTimeGraphViewer
;
88 /** The top-level input (children excluded) */
89 private List
<?
extends ITimeGraphEntry
> fTopInput
;
91 /** The selection listener map */
92 private final Map
<ITimeGraphSelectionListener
, SelectionListenerWrapper
> fSelectionListenerMap
= new HashMap
<ITimeGraphSelectionListener
, SelectionListenerWrapper
>();
94 /** The map of viewer filters */
95 private final Map
<ViewerFilter
, ViewerFilter
> fViewerFilterMap
= new HashMap
<ViewerFilter
, ViewerFilter
>();
98 * Flag to block the tree selection changed listener when triggered by the
101 private boolean fInhibitTreeSelection
= false;
103 /** Number of filler rows used by the tree content provider */
104 private int fNumFillerRows
;
106 /** Calculated item height for Linux workaround */
107 private int fLinuxItemHeight
= 0;
109 /** The button that opens the filter dialog */
110 private Action showFilterAction
;
112 /** The filter dialog */
113 private TimeGraphFilterDialog fFilterDialog
;
115 /** The filter generated from the filter dialog */
116 private RawViewerFilter fFilter
;
118 /** Default weight of each part of the sash */
119 private static final int[] DEFAULT_WEIGHTS
= { 1, 1 };
121 // ------------------------------------------------------------------------
123 // ------------------------------------------------------------------------
126 * The TreeContentProviderWrapper is used to insert filler items after
127 * the elements of the tree's real content provider.
129 private class TreeContentProviderWrapper
implements ITreeContentProvider
{
130 private final ITreeContentProvider contentProvider
;
132 public TreeContentProviderWrapper(ITreeContentProvider contentProvider
) {
133 this.contentProvider
= contentProvider
;
137 public void dispose() {
138 contentProvider
.dispose();
142 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
143 contentProvider
.inputChanged(viewer
, oldInput
, newInput
);
147 public Object
[] getElements(Object inputElement
) {
148 Object
[] elements
= contentProvider
.getElements(inputElement
);
149 // add filler elements to ensure alignment with time analysis viewer
150 Object
[] oElements
= Arrays
.copyOf(elements
, elements
.length
+ fNumFillerRows
, Object
[].class);
151 for (int i
= 0; i
< fNumFillerRows
; i
++) {
152 oElements
[elements
.length
+ i
] = FILLER
;
158 public Object
[] getChildren(Object parentElement
) {
159 if (parentElement
instanceof ITimeGraphEntry
) {
160 return contentProvider
.getChildren(parentElement
);
162 return new Object
[0];
166 public Object
getParent(Object element
) {
167 if (element
instanceof ITimeGraphEntry
) {
168 return contentProvider
.getParent(element
);
174 public boolean hasChildren(Object element
) {
175 if (element
instanceof ITimeGraphEntry
) {
176 return contentProvider
.hasChildren(element
);
183 * The TreeLabelProviderWrapper is used to intercept the filler items
184 * from the calls to the tree's real label provider.
186 private class TreeLabelProviderWrapper
implements ITableLabelProvider
{
187 private final ITableLabelProvider labelProvider
;
189 public TreeLabelProviderWrapper(ITableLabelProvider labelProvider
) {
190 this.labelProvider
= labelProvider
;
194 public void addListener(ILabelProviderListener listener
) {
195 labelProvider
.addListener(listener
);
199 public void dispose() {
200 labelProvider
.dispose();
204 public boolean isLabelProperty(Object element
, String property
) {
205 if (element
instanceof ITimeGraphEntry
) {
206 return labelProvider
.isLabelProperty(element
, property
);
212 public void removeListener(ILabelProviderListener listener
) {
213 labelProvider
.removeListener(listener
);
217 public Image
getColumnImage(Object element
, int columnIndex
) {
218 if (element
instanceof ITimeGraphEntry
) {
219 return labelProvider
.getColumnImage(element
, columnIndex
);
225 public String
getColumnText(Object element
, int columnIndex
) {
226 if (element
instanceof ITimeGraphEntry
) {
227 return labelProvider
.getColumnText(element
, columnIndex
);
235 * The SelectionListenerWrapper is used to intercept the filler items from
236 * the time graph combo's real selection listener, and to prevent double
237 * notifications from being sent when selection changes in both tree and
238 * time graph at the same time.
240 private class SelectionListenerWrapper
implements ISelectionChangedListener
, ITimeGraphSelectionListener
{
241 private final ITimeGraphSelectionListener listener
;
242 private ITimeGraphEntry selection
= null;
244 public SelectionListenerWrapper(ITimeGraphSelectionListener listener
) {
245 this.listener
= listener
;
249 public void selectionChanged(SelectionChangedEvent event
) {
250 if (fInhibitTreeSelection
) {
253 Object element
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
254 if (element
instanceof ITimeGraphEntry
) {
255 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
256 if (entry
!= selection
) {
258 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
264 public void selectionChanged(TimeGraphSelectionEvent event
) {
265 ITimeGraphEntry entry
= event
.getSelection();
266 if (entry
!= selection
) {
268 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
274 * The ViewerFilterWrapper is used to intercept the filler items from
275 * the time graph combo's real ViewerFilters. These filler items should
278 private class ViewerFilterWrapper
extends ViewerFilter
{
280 private ViewerFilter fWrappedFilter
;
282 ViewerFilterWrapper(ViewerFilter filter
) {
284 this.fWrappedFilter
= filter
;
288 public boolean select(Viewer viewer
, Object parentElement
, Object element
) {
289 if (element
instanceof ITimeGraphEntry
) {
290 return fWrappedFilter
.select(viewer
, parentElement
, element
);
298 * This filter simply keeps a list of elements that should be filtered out.
299 * All the other elements will be shown.
300 * By default and when the list is set to null, all elements are shown.
302 private class RawViewerFilter
extends ViewerFilter
{
304 private List
<Object
> fFiltered
= null;
306 public void setFiltered(List
<Object
> objects
) {
310 public List
<Object
> getFiltered() {
315 public boolean select(Viewer viewer
, Object parentElement
, Object element
) {
316 if (fFiltered
== null) {
319 return !fFiltered
.contains(element
);
323 // ------------------------------------------------------------------------
325 // ------------------------------------------------------------------------
328 * Constructs a new instance of this class given its parent
329 * and a style value describing its behavior and appearance.
331 * @param parent a widget which will be the parent of the new instance (cannot be null)
332 * @param style the style of widget to construct
334 public TimeGraphCombo(Composite parent
, int style
) {
335 this(parent
, style
, DEFAULT_WEIGHTS
);
339 * Constructs a new instance of this class given its parent and a style
340 * value describing its behavior and appearance.
343 * a widget which will be the parent of the new instance (cannot
346 * the style of widget to construct
348 * The relative weights of each side of the sash form
351 public TimeGraphCombo(Composite parent
, int style
, int[] weights
) {
352 super(parent
, style
);
353 setLayout(new FillLayout());
355 final SashForm sash
= new SashForm(this, SWT
.NONE
);
357 fTreeViewer
= new TreeViewer(sash
, SWT
.FULL_SELECTION
| SWT
.H_SCROLL
);
358 final Tree tree
= fTreeViewer
.getTree();
359 tree
.setHeaderVisible(true);
360 tree
.setLinesVisible(true);
362 fTimeGraphViewer
= new TimeGraphViewer(sash
, SWT
.NONE
);
363 fTimeGraphViewer
.setItemHeight(getItemHeight(tree
));
364 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
365 fTimeGraphViewer
.setBorderWidth(tree
.getBorderWidth());
366 fTimeGraphViewer
.setNameWidthPref(0);
368 fFilter
= new RawViewerFilter();
371 fFilterDialog
= new TimeGraphFilterDialog(getShell());
373 // Feature in Windows. The tree vertical bar reappears when
374 // the control is resized so we need to hide it again.
375 // Bug in Linux. The tree header height is 0 in constructor,
376 // so we need to reset it later when the control is resized.
377 tree
.addControlListener(new ControlAdapter() {
378 private int depth
= 0;
380 public void controlResized(ControlEvent e
) {
383 tree
.getVerticalBar().setEnabled(false);
384 // this can trigger controlResized recursively
385 tree
.getVerticalBar().setVisible(false);
388 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
392 // ensure synchronization of expanded items between tree and time graph
393 fTreeViewer
.addTreeListener(new ITreeViewerListener() {
395 public void treeCollapsed(TreeExpansionEvent event
) {
396 fTimeGraphViewer
.setExpandedState((ITimeGraphEntry
) event
.getElement(), false);
397 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
398 if (treeItems
.size() == 0) {
401 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
402 tree
.setTopItem(treeItem
);
406 public void treeExpanded(TreeExpansionEvent event
) {
407 ITimeGraphEntry entry
= (ITimeGraphEntry
) event
.getElement();
408 fTimeGraphViewer
.setExpandedState(entry
, true);
409 for (ITimeGraphEntry child
: entry
.getChildren()) {
410 boolean expanded
= fTreeViewer
.getExpandedState(child
);
411 fTimeGraphViewer
.setExpandedState(child
, expanded
);
413 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
414 if (treeItems
.size() == 0) {
417 final TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
418 // queue the top item update because the tree can change its top item
419 // autonomously immediately after the listeners have been notified
420 getDisplay().asyncExec(new Runnable() {
423 tree
.setTopItem(treeItem
);
428 // ensure synchronization of expanded items between tree and time graph
429 fTimeGraphViewer
.addTreeListener(new ITimeGraphTreeListener() {
431 public void treeCollapsed(TimeGraphTreeExpansionEvent event
) {
432 fTreeViewer
.setExpandedState(event
.getEntry(), false);
436 public void treeExpanded(TimeGraphTreeExpansionEvent event
) {
437 ITimeGraphEntry entry
= event
.getEntry();
438 fTreeViewer
.setExpandedState(entry
, true);
439 for (ITimeGraphEntry child
: entry
.getChildren()) {
440 boolean expanded
= fTreeViewer
.getExpandedState(child
);
441 fTimeGraphViewer
.setExpandedState(child
, expanded
);
446 // prevent mouse button from selecting a filler tree item
447 tree
.addListener(SWT
.MouseDown
, new Listener() {
449 public void handleEvent(Event event
) {
450 TreeItem treeItem
= tree
.getItem(new Point(event
.x
, event
.y
));
451 if (treeItem
== null || treeItem
.getData() == FILLER
) {
453 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
454 if (treeItems
.size() == 0) {
455 fTreeViewer
.setSelection(new StructuredSelection());
456 fTimeGraphViewer
.setSelection(null);
459 // this prevents from scrolling up when selecting
460 // the partially visible tree item at the bottom
461 tree
.select(treeItems
.get(treeItems
.size() - 1));
462 fTreeViewer
.setSelection(new StructuredSelection());
463 fTimeGraphViewer
.setSelection(null);
468 // prevent mouse wheel from scrolling down into filler tree items
469 tree
.addListener(SWT
.MouseWheel
, new Listener() {
471 public void handleEvent(Event event
) {
473 Slider scrollBar
= fTimeGraphViewer
.getVerticalBar();
474 fTimeGraphViewer
.setTopIndex(scrollBar
.getSelection() - event
.count
);
475 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
476 if (treeItems
.size() == 0) {
479 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
480 tree
.setTopItem(treeItem
);
484 // prevent key stroke from selecting a filler tree item
485 tree
.addListener(SWT
.KeyDown
, new Listener() {
487 public void handleEvent(Event event
) {
488 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
489 if (treeItems
.size() == 0) {
490 fTreeViewer
.setSelection(new StructuredSelection());
494 if (event
.keyCode
== SWT
.ARROW_DOWN
) {
495 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + 1, treeItems
.size() - 1);
496 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
498 } else if (event
.keyCode
== SWT
.PAGE_DOWN
) {
499 int height
= tree
.getSize().y
- tree
.getHeaderHeight() - tree
.getHorizontalBar().getSize().y
;
500 int countPerPage
= height
/ getItemHeight(tree
);
501 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + countPerPage
- 1, treeItems
.size() - 1);
502 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
504 } else if (event
.keyCode
== SWT
.END
) {
505 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(treeItems
.size() - 1).getData());
508 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
509 tree
.setTopItem(treeItem
);
510 if (fTimeGraphViewer
.getSelectionIndex() >= 0) {
511 fTreeViewer
.setSelection(new StructuredSelection(fTimeGraphViewer
.getSelection()));
513 fTreeViewer
.setSelection(new StructuredSelection());
518 // ensure alignment of top item between tree and time graph
519 fTimeGraphViewer
.getTimeGraphControl().addControlListener(new ControlAdapter() {
521 public void controlResized(ControlEvent e
) {
522 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
523 if (treeItems
.size() == 0) {
526 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
527 tree
.setTopItem(treeItem
);
531 // ensure synchronization of selected item between tree and time graph
532 fTreeViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
534 public void selectionChanged(SelectionChangedEvent event
) {
535 if (fInhibitTreeSelection
) {
538 if (event
.getSelection() instanceof IStructuredSelection
) {
539 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
540 if (selection
instanceof ITimeGraphEntry
) {
541 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) selection
);
543 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
544 if (treeItems
.size() == 0) {
547 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
548 tree
.setTopItem(treeItem
);
553 // ensure synchronization of selected item between tree and time graph
554 fTimeGraphViewer
.addSelectionListener(new ITimeGraphSelectionListener() {
556 public void selectionChanged(TimeGraphSelectionEvent event
) {
557 ITimeGraphEntry entry
= fTimeGraphViewer
.getSelection();
558 fInhibitTreeSelection
= true; // block the tree selection changed listener
560 StructuredSelection selection
= new StructuredSelection(entry
);
561 fTreeViewer
.setSelection(selection
);
563 fTreeViewer
.setSelection(new StructuredSelection());
565 fInhibitTreeSelection
= false;
566 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
567 if (treeItems
.size() == 0) {
570 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
571 tree
.setTopItem(treeItem
);
575 // ensure alignment of top item between tree and time graph
576 fTimeGraphViewer
.getVerticalBar().addSelectionListener(new SelectionAdapter() {
578 public void widgetSelected(SelectionEvent e
) {
579 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
580 if (treeItems
.size() == 0) {
583 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
584 tree
.setTopItem(treeItem
);
588 // ensure alignment of top item between tree and time graph
589 fTimeGraphViewer
.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
591 public void mouseScrolled(MouseEvent e
) {
592 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
593 if (treeItems
.size() == 0) {
596 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
597 tree
.setTopItem(treeItem
);
601 // ensure the tree has focus control when mouse is over it if the time graph had control
602 fTreeViewer
.getControl().addMouseTrackListener(new MouseTrackAdapter() {
604 public void mouseEnter(MouseEvent e
) {
605 if (fTimeGraphViewer
.getTimeGraphControl().isFocusControl()) {
606 fTreeViewer
.getControl().setFocus();
611 // ensure the time graph has focus control when mouse is over it if the tree had control
612 fTimeGraphViewer
.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
614 public void mouseEnter(MouseEvent e
) {
615 if (fTreeViewer
.getControl().isFocusControl()) {
616 fTimeGraphViewer
.getTimeGraphControl().setFocus();
620 fTimeGraphViewer
.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
622 public void mouseEnter(MouseEvent e
) {
623 if (fTreeViewer
.getControl().isFocusControl()) {
624 fTimeGraphViewer
.getTimeGraphControl().setFocus();
629 // The filler rows are required to ensure alignment when the tree does not have a
630 // visible horizontal scroll bar. The tree does not allow its top item to be set
631 // to a value that would cause blank space to be drawn at the bottom of the tree.
632 fNumFillerRows
= Display
.getDefault().getBounds().height
/ getItemHeight(tree
);
634 sash
.setWeights(weights
);
637 // ------------------------------------------------------------------------
639 // ------------------------------------------------------------------------
642 * Returns this time graph combo's tree viewer.
644 * @return the tree viewer
646 public TreeViewer
getTreeViewer() {
651 * Returns this time graph combo's time graph viewer.
653 * @return the time graph viewer
655 public TimeGraphViewer
getTimeGraphViewer() {
656 return fTimeGraphViewer
;
660 * Callback for the show filter action
664 public void showFilterDialog() {
665 if(fTopInput
!= null) {
666 List
<?
extends ITimeGraphEntry
> allElements
= listAllInputs(fTopInput
);
667 fFilterDialog
.setInput(fTopInput
.toArray(new ITimeGraphEntry
[0]));
668 fFilterDialog
.setTitle(Messages
.TmfTimeFilterDialog_WINDOW_TITLE
);
669 fFilterDialog
.setMessage(Messages
.TmfTimeFilterDialog_MESSAGE
);
670 fFilterDialog
.setExpandedElements(allElements
.toArray());
671 if (fFilter
.getFiltered() != null) {
672 ArrayList
<?
extends ITimeGraphEntry
> nonFilteredElements
= new ArrayList
<ITimeGraphEntry
>(allElements
);
673 nonFilteredElements
.removeAll(fFilter
.getFiltered());
674 fFilterDialog
.setInitialElementSelections(nonFilteredElements
);
676 fFilterDialog
.setInitialElementSelections(allElements
);
678 fFilterDialog
.create();
679 fFilterDialog
.open();
680 // Process selected elements
681 if (fFilterDialog
.getResult() != null) {
682 fInhibitTreeSelection
= true;
683 if (fFilterDialog
.getResult().length
!= allElements
.size()) {
684 ArrayList
<Object
> filteredElements
= new ArrayList
<Object
>(allElements
);
685 filteredElements
.removeAll(Arrays
.asList(fFilterDialog
.getResult()));
686 fFilter
.setFiltered(filteredElements
);
688 fFilter
.setFiltered(null);
690 fTreeViewer
.refresh();
691 fTreeViewer
.expandAll();
692 fTimeGraphViewer
.refresh();
693 fInhibitTreeSelection
= false;
694 // Reset selection to first entry
695 if (fFilterDialog
.getResult().length
> 0) {
696 setSelection((ITimeGraphEntry
) fFilterDialog
.getResult()[0]);
703 * Get the show filter action.
705 * @return The Action object
708 public Action
getShowFilterAction() {
709 if (showFilterAction
== null) {
711 showFilterAction
= new Action() {
717 showFilterAction
.setText(Messages
.TmfTimeGraphCombo_FilterActionNameText
);
718 showFilterAction
.setToolTipText(Messages
.TmfTimeGraphCombo_FilterActionToolTipText
);
719 // TODO find a nice, distinctive icon
720 showFilterAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_FILTERS
));
723 return showFilterAction
;
726 // ------------------------------------------------------------------------
728 // ------------------------------------------------------------------------
731 public void redraw() {
732 fTimeGraphViewer
.getControl().redraw();
736 // ------------------------------------------------------------------------
738 // ------------------------------------------------------------------------
741 * Sets the tree content provider used by this time graph combo.
743 * @param contentProvider the tree content provider
745 public void setTreeContentProvider(ITreeContentProvider contentProvider
) {
746 fTreeViewer
.setContentProvider(new TreeContentProviderWrapper(contentProvider
));
750 * Sets the tree label provider used by this time graph combo.
752 * @param labelProvider the tree label provider
754 public void setTreeLabelProvider(ITableLabelProvider labelProvider
) {
755 fTreeViewer
.setLabelProvider(new TreeLabelProviderWrapper(labelProvider
));
759 * Sets the tree content provider used by the filter dialog
761 * @param contentProvider the tree content provider
764 public void setFilterContentProvider(ITreeContentProvider contentProvider
) {
765 fFilterDialog
.setContentProvider(contentProvider
);
769 * Sets the tree label provider used by the filter dialog
771 * @param labelProvider the tree label provider
774 public void setFilterLabelProvider(ITableLabelProvider labelProvider
) {
775 fFilterDialog
.setLabelProvider(labelProvider
);
779 * Sets the tree columns for this time graph combo.
781 * @param columnNames the tree column names
783 public void setTreeColumns(String
[] columnNames
) {
784 final Tree tree
= fTreeViewer
.getTree();
785 for (String columnName
: columnNames
) {
786 TreeColumn column
= new TreeColumn(tree
, SWT
.LEFT
);
787 column
.setText(columnName
);
793 * Sets the tree columns for this time graph combo's filter dialog.
795 * @param columnNames the tree column names
798 public void setFilterColumns(String
[] columnNames
) {
799 fFilterDialog
.setColumnNames(columnNames
);
803 * Sets the time graph provider used by this time graph combo.
805 * @param timeGraphProvider the time graph provider
807 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider
) {
808 fTimeGraphViewer
.setTimeGraphProvider(timeGraphProvider
);
812 * Sets or clears the input for this time graph combo.
813 * The input array should only contain top-level elements.
815 * @param input the input of this time graph combo, or <code>null</code> if none
817 public void setInput(ITimeGraphEntry
[] input
) {
818 fTopInput
= new ArrayList
<ITimeGraphEntry
>(Arrays
.asList(input
));
819 fFilter
.setFiltered(null);
820 fInhibitTreeSelection
= true;
821 fTreeViewer
.setInput(input
);
822 for (SelectionListenerWrapper listenerWrapper
: fSelectionListenerMap
.values()) {
823 listenerWrapper
.selection
= null;
825 fInhibitTreeSelection
= false;
826 fTreeViewer
.expandAll();
827 fTreeViewer
.getTree().getVerticalBar().setEnabled(false);
828 fTreeViewer
.getTree().getVerticalBar().setVisible(false);
829 fTimeGraphViewer
.setItemHeight(getItemHeight(fTreeViewer
.getTree()));
830 fTimeGraphViewer
.setInput(input
);
834 * @param filter The filter object to be attached to the view
837 public void addFilter(ViewerFilter filter
) {
838 ViewerFilter wrapper
= new ViewerFilterWrapper(filter
);
839 fTreeViewer
.addFilter(wrapper
);
840 fTimeGraphViewer
.addFilter(wrapper
);
841 fViewerFilterMap
.put(filter
, wrapper
);
845 * @param filter The filter object to be removed from the view
848 public void removeFilter(ViewerFilter filter
) {
849 ViewerFilter wrapper
= fViewerFilterMap
.get(filter
);
850 fTreeViewer
.removeFilter(wrapper
);
851 fTimeGraphViewer
.removeFilter(wrapper
);
852 fViewerFilterMap
.remove(filter
);
856 * Refreshes this time graph completely with information freshly obtained from its model.
858 public void refresh() {
859 fInhibitTreeSelection
= true;
860 fTreeViewer
.refresh();
861 fTimeGraphViewer
.refresh();
862 fInhibitTreeSelection
= false;
866 * Adds a listener for selection changes in this time graph combo.
868 * @param listener a selection listener
870 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
871 SelectionListenerWrapper listenerWrapper
= new SelectionListenerWrapper(listener
);
872 fTreeViewer
.addSelectionChangedListener(listenerWrapper
);
873 fSelectionListenerMap
.put(listener
, listenerWrapper
);
874 fTimeGraphViewer
.addSelectionListener(listenerWrapper
);
878 * Removes the given selection listener from this time graph combo.
880 * @param listener a selection changed listener
882 public void removeSelectionListener(ITimeGraphSelectionListener listener
) {
883 SelectionListenerWrapper listenerWrapper
= fSelectionListenerMap
.remove(listener
);
884 fTreeViewer
.removeSelectionChangedListener(listenerWrapper
);
885 fTimeGraphViewer
.removeSelectionListener(listenerWrapper
);
889 * Sets the current selection for this time graph combo.
891 * @param selection the new selection
893 public void setSelection(ITimeGraphEntry selection
) {
894 fTimeGraphViewer
.setSelection(selection
);
895 fInhibitTreeSelection
= true; // block the tree selection changed listener
896 if (selection
!= null) {
897 StructuredSelection structuredSelection
= new StructuredSelection(selection
);
898 fTreeViewer
.setSelection(structuredSelection
);
900 fTreeViewer
.setSelection(new StructuredSelection());
902 fInhibitTreeSelection
= false;
903 List
<TreeItem
> treeItems
= getVisibleExpandedItems(fTreeViewer
.getTree());
904 if (treeItems
.size() == 0) {
907 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
908 fTreeViewer
.getTree().setTopItem(treeItem
);
912 * Set the expanded state of an entry
915 * The entry to expand/collapse
917 * True for expanded, false for collapsed
921 public void setExpandedState(ITimeGraphEntry entry
, boolean expanded
) {
922 fTimeGraphViewer
.setExpandedState(entry
, expanded
);
923 fTreeViewer
.setExpandedState(entry
, expanded
);
927 * Collapses all nodes of the viewer's tree, starting with the root.
931 public void collapseAll() {
932 fTimeGraphViewer
.collapseAll();
933 fTreeViewer
.collapseAll();
937 * Expands all nodes of the viewer's tree, starting with the root.
941 public void expandAll() {
942 fTimeGraphViewer
.expandAll();
943 fTreeViewer
.expandAll();
946 // ------------------------------------------------------------------------
948 // ------------------------------------------------------------------------
950 private List
<TreeItem
> getVisibleExpandedItems(Tree tree
) {
951 ArrayList
<TreeItem
> items
= new ArrayList
<TreeItem
>();
952 for (TreeItem item
: tree
.getItems()) {
953 if (item
.getData() == FILLER
) {
957 if (item
.getExpanded()) {
958 items
.addAll(getVisibleExpandedItems(item
));
964 private List
<TreeItem
> getVisibleExpandedItems(TreeItem treeItem
) {
965 ArrayList
<TreeItem
> items
= new ArrayList
<TreeItem
>();
966 for (TreeItem item
: treeItem
.getItems()) {
968 if (item
.getExpanded()) {
969 items
.addAll(getVisibleExpandedItems(item
));
976 * Explores the list of top-level inputs and returns all the inputs
978 * @param inputs The top-level inputs
979 * @return All the inputs
981 private List
<?
extends ITimeGraphEntry
> listAllInputs(List
<?
extends ITimeGraphEntry
> inputs
) {
982 ArrayList
<ITimeGraphEntry
> items
= new ArrayList
<ITimeGraphEntry
>();
983 for (ITimeGraphEntry entry
: inputs
) {
985 if (entry
.hasChildren()) {
986 items
.addAll(listAllInputs(entry
.getChildren()));
992 private int getItemHeight(final Tree tree
) {
994 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
996 if (fLinuxItemHeight
>= 0 && System
.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
997 if (fLinuxItemHeight
!= 0) {
998 return fLinuxItemHeight
;
1000 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
1001 if (treeItems
.size() > 1) {
1002 final TreeItem treeItem0
= treeItems
.get(0);
1003 final TreeItem treeItem1
= treeItems
.get(1);
1004 PaintListener paintListener
= new PaintListener() {
1006 public void paintControl(PaintEvent e
) {
1007 tree
.removePaintListener(this);
1008 int y0
= treeItem0
.getBounds().y
;
1009 int y1
= treeItem1
.getBounds().y
;
1010 int itemHeight
= y1
- y0
;
1011 if (itemHeight
> 0) {
1012 fLinuxItemHeight
= itemHeight
;
1013 fTimeGraphViewer
.setItemHeight(itemHeight
);
1017 tree
.addPaintListener(paintListener
);
1020 fLinuxItemHeight
= -1; // Not Linux, don't perform os.name check anymore
1022 return tree
.getItemHeight();