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 // ------------------------------------------------------------------------
83 private TreeViewer fTreeViewer
;
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 HashMap
<ITimeGraphSelectionListener
, SelectionListenerWrapper
> fSelectionListenerMap
= new HashMap
<ITimeGraphSelectionListener
, SelectionListenerWrapper
>();
94 // The map of viewer filters
95 private final Map
<ViewerFilter
, ViewerFilter
> fViewerFilterMap
= new HashMap
<ViewerFilter
, ViewerFilter
>();
97 // Flag to block the tree selection changed listener when triggered by the time graph combo
98 private boolean fInhibitTreeSelection
= false;
100 // Number of filler rows used by the tree content provider
101 private int fNumFillerRows
;
103 // Calculated item height for Linux workaround
104 private int fLinuxItemHeight
= 0;
106 // The button that opens the filter dialog
107 private Action showFilterAction
;
110 private TimeGraphFilterDialog fFilterDialog
;
112 // The filter generated from the filter dialog
113 private RawViewerFilter fFilter
;
115 // ------------------------------------------------------------------------
117 // ------------------------------------------------------------------------
120 * The TreeContentProviderWrapper is used to insert filler items after
121 * the elements of the tree's real content provider.
123 private class TreeContentProviderWrapper
implements ITreeContentProvider
{
124 private final ITreeContentProvider contentProvider
;
126 public TreeContentProviderWrapper(ITreeContentProvider contentProvider
) {
127 this.contentProvider
= contentProvider
;
131 public void dispose() {
132 contentProvider
.dispose();
136 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
137 contentProvider
.inputChanged(viewer
, oldInput
, newInput
);
141 public Object
[] getElements(Object inputElement
) {
142 Object
[] elements
= contentProvider
.getElements(inputElement
);
143 // add filler elements to ensure alignment with time analysis viewer
144 Object
[] oElements
= Arrays
.copyOf(elements
, elements
.length
+ fNumFillerRows
, new Object
[0].getClass());
145 for (int i
= 0; i
< fNumFillerRows
; i
++) {
146 oElements
[elements
.length
+ i
] = FILLER
;
152 public Object
[] getChildren(Object parentElement
) {
153 if (parentElement
instanceof ITimeGraphEntry
) {
154 return contentProvider
.getChildren(parentElement
);
156 return new Object
[0];
160 public Object
getParent(Object element
) {
161 if (element
instanceof ITimeGraphEntry
) {
162 return contentProvider
.getParent(element
);
168 public boolean hasChildren(Object element
) {
169 if (element
instanceof ITimeGraphEntry
) {
170 return contentProvider
.hasChildren(element
);
177 * The TreeLabelProviderWrapper is used to intercept the filler items
178 * from the calls to the tree's real label provider.
180 private class TreeLabelProviderWrapper
implements ITableLabelProvider
{
181 private final ITableLabelProvider labelProvider
;
183 public TreeLabelProviderWrapper(ITableLabelProvider labelProvider
) {
184 this.labelProvider
= labelProvider
;
188 public void addListener(ILabelProviderListener listener
) {
189 labelProvider
.addListener(listener
);
193 public void dispose() {
194 labelProvider
.dispose();
198 public boolean isLabelProperty(Object element
, String property
) {
199 if (element
instanceof ITimeGraphEntry
) {
200 return labelProvider
.isLabelProperty(element
, property
);
206 public void removeListener(ILabelProviderListener listener
) {
207 labelProvider
.removeListener(listener
);
211 public Image
getColumnImage(Object element
, int columnIndex
) {
212 if (element
instanceof ITimeGraphEntry
) {
213 return labelProvider
.getColumnImage(element
, columnIndex
);
219 public String
getColumnText(Object element
, int columnIndex
) {
220 if (element
instanceof ITimeGraphEntry
) {
221 return labelProvider
.getColumnText(element
, columnIndex
);
229 * The SelectionListenerWrapper is used to intercept the filler items from
230 * the time graph combo's real selection listener, and to prevent double
231 * notifications from being sent when selection changes in both tree and
232 * time graph at the same time.
234 private class SelectionListenerWrapper
implements ISelectionChangedListener
, ITimeGraphSelectionListener
{
235 private final ITimeGraphSelectionListener listener
;
236 private ITimeGraphEntry selection
= null;
238 public SelectionListenerWrapper(ITimeGraphSelectionListener listener
) {
239 this.listener
= listener
;
243 public void selectionChanged(SelectionChangedEvent event
) {
244 if (fInhibitTreeSelection
) {
247 Object element
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
248 if (element
instanceof ITimeGraphEntry
) {
249 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
250 if (entry
!= selection
) {
252 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
258 public void selectionChanged(TimeGraphSelectionEvent event
) {
259 ITimeGraphEntry entry
= event
.getSelection();
260 if (entry
!= selection
) {
262 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
268 * The ViewerFilterWrapper is used to intercept the filler items from
269 * the time graph combo's real ViewerFilters. These filler items should
272 private class ViewerFilterWrapper
extends ViewerFilter
{
274 ViewerFilter fWrappedFilter
;
276 ViewerFilterWrapper(ViewerFilter filter
) {
278 this.fWrappedFilter
= filter
;
282 public boolean select(Viewer viewer
, Object parentElement
, Object element
) {
283 if (element
instanceof ITimeGraphEntry
) {
284 return fWrappedFilter
.select(viewer
, parentElement
, element
);
292 * This filter simply keeps a list of elements that should be filtered out.
293 * All the other elements will be shown.
294 * By default and when the list is set to null, all elements are shown.
296 private class RawViewerFilter
extends ViewerFilter
{
298 private List
<Object
> fFiltered
= null;
300 public void setFiltered(List
<Object
> objects
) {
304 public List
<Object
> getFiltered() {
309 public boolean select(Viewer viewer
, Object parentElement
, Object element
) {
310 if (fFiltered
== null) {
313 return !fFiltered
.contains(element
);
317 // ------------------------------------------------------------------------
319 // ------------------------------------------------------------------------
322 * Constructs a new instance of this class given its parent
323 * and a style value describing its behavior and appearance.
325 * @param parent a widget which will be the parent of the new instance (cannot be null)
326 * @param style the style of widget to construct
328 public TimeGraphCombo(Composite parent
, int style
) {
329 super(parent
, style
);
330 setLayout(new FillLayout());
332 final SashForm sash
= new SashForm(this, SWT
.NONE
);
334 fTreeViewer
= new TreeViewer(sash
, SWT
.FULL_SELECTION
| SWT
.H_SCROLL
);
335 final Tree tree
= fTreeViewer
.getTree();
336 tree
.setHeaderVisible(true);
337 tree
.setLinesVisible(true);
339 fTimeGraphViewer
= new TimeGraphViewer(sash
, SWT
.NONE
);
340 fTimeGraphViewer
.setItemHeight(getItemHeight(tree
));
341 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
342 fTimeGraphViewer
.setBorderWidth(tree
.getBorderWidth());
343 fTimeGraphViewer
.setNameWidthPref(0);
345 fFilter
= new RawViewerFilter();
348 fFilterDialog
= new TimeGraphFilterDialog(getShell());
350 // Feature in Windows. The tree vertical bar reappears when
351 // the control is resized so we need to hide it again.
352 // Bug in Linux. The tree header height is 0 in constructor,
353 // so we need to reset it later when the control is resized.
354 tree
.addControlListener(new ControlAdapter() {
357 public void controlResized(ControlEvent e
) {
360 tree
.getVerticalBar().setEnabled(false);
361 // this can trigger controlResized recursively
362 tree
.getVerticalBar().setVisible(false);
365 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
369 // ensure synchronization of expanded items between tree and time graph
370 fTreeViewer
.addTreeListener(new ITreeViewerListener() {
372 public void treeCollapsed(TreeExpansionEvent event
) {
373 fTimeGraphViewer
.setExpandedState((ITimeGraphEntry
) event
.getElement(), false);
374 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
375 if (treeItems
.size() == 0) {
378 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
379 tree
.setTopItem(treeItem
);
383 public void treeExpanded(TreeExpansionEvent event
) {
384 fTimeGraphViewer
.setExpandedState((ITimeGraphEntry
) event
.getElement(), true);
385 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
386 if (treeItems
.size() == 0) {
389 final TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
390 // queue the top item update because the tree can change its top item
391 // autonomously immediately after the listeners have been notified
392 getDisplay().asyncExec(new Runnable() {
395 tree
.setTopItem(treeItem
);
400 // ensure synchronization of expanded items between tree and time graph
401 fTimeGraphViewer
.addTreeListener(new ITimeGraphTreeListener() {
403 public void treeCollapsed(TimeGraphTreeExpansionEvent event
) {
404 fTreeViewer
.setExpandedState(event
.getEntry(), false);
408 public void treeExpanded(TimeGraphTreeExpansionEvent event
) {
409 fTreeViewer
.setExpandedState(event
.getEntry(), true);
413 // prevent mouse button from selecting a filler tree item
414 tree
.addListener(SWT
.MouseDown
, new Listener() {
416 public void handleEvent(Event event
) {
417 TreeItem treeItem
= tree
.getItem(new Point(event
.x
, event
.y
));
418 if (treeItem
== null || treeItem
.getData() == FILLER
) {
420 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
421 if (treeItems
.size() == 0) {
422 fTreeViewer
.setSelection(new StructuredSelection());
423 fTimeGraphViewer
.setSelection(null);
426 // this prevents from scrolling up when selecting
427 // the partially visible tree item at the bottom
428 tree
.select(treeItems
.get(treeItems
.size() - 1));
429 fTreeViewer
.setSelection(new StructuredSelection());
430 fTimeGraphViewer
.setSelection(null);
435 // prevent mouse wheel from scrolling down into filler tree items
436 tree
.addListener(SWT
.MouseWheel
, new Listener() {
438 public void handleEvent(Event event
) {
440 Slider scrollBar
= fTimeGraphViewer
.getVerticalBar();
441 fTimeGraphViewer
.setTopIndex(scrollBar
.getSelection() - event
.count
);
442 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
443 if (treeItems
.size() == 0) {
446 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
447 tree
.setTopItem(treeItem
);
451 // prevent key stroke from selecting a filler tree item
452 tree
.addListener(SWT
.KeyDown
, new Listener() {
454 public void handleEvent(Event event
) {
455 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
456 if (treeItems
.size() == 0) {
457 fTreeViewer
.setSelection(new StructuredSelection());
461 if (event
.keyCode
== SWT
.ARROW_DOWN
) {
462 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + 1, treeItems
.size() - 1);
463 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
465 } else if (event
.keyCode
== SWT
.PAGE_DOWN
) {
466 int height
= tree
.getSize().y
- tree
.getHeaderHeight() - tree
.getHorizontalBar().getSize().y
;
467 int countPerPage
= height
/ getItemHeight(tree
);
468 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + countPerPage
- 1, treeItems
.size() - 1);
469 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
471 } else if (event
.keyCode
== SWT
.END
) {
472 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(treeItems
.size() - 1).getData());
475 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
476 tree
.setTopItem(treeItem
);
477 if (fTimeGraphViewer
.getSelectionIndex() >= 0) {
478 fTreeViewer
.setSelection(new StructuredSelection(fTimeGraphViewer
.getSelection()));
480 fTreeViewer
.setSelection(new StructuredSelection());
485 // ensure alignment of top item between tree and time graph
486 fTimeGraphViewer
.getTimeGraphControl().addControlListener(new ControlAdapter() {
488 public void controlResized(ControlEvent e
) {
489 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
490 if (treeItems
.size() == 0) {
493 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
494 tree
.setTopItem(treeItem
);
498 // ensure synchronization of selected item between tree and time graph
499 fTreeViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
501 public void selectionChanged(SelectionChangedEvent event
) {
502 if (fInhibitTreeSelection
) {
505 if (event
.getSelection() instanceof IStructuredSelection
) {
506 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
507 if (selection
instanceof ITimeGraphEntry
) {
508 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) selection
);
510 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
511 if (treeItems
.size() == 0) {
514 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
515 tree
.setTopItem(treeItem
);
520 // ensure synchronization of selected item between tree and time graph
521 fTimeGraphViewer
.addSelectionListener(new ITimeGraphSelectionListener() {
523 public void selectionChanged(TimeGraphSelectionEvent event
) {
524 ITimeGraphEntry entry
= fTimeGraphViewer
.getSelection();
525 fInhibitTreeSelection
= true; // block the tree selection changed listener
527 StructuredSelection selection
= new StructuredSelection(entry
);
528 fTreeViewer
.setSelection(selection
);
530 fTreeViewer
.setSelection(new StructuredSelection());
532 fInhibitTreeSelection
= false;
533 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
534 if (treeItems
.size() == 0) {
537 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
538 tree
.setTopItem(treeItem
);
542 // ensure alignment of top item between tree and time graph
543 fTimeGraphViewer
.getVerticalBar().addSelectionListener(new SelectionAdapter() {
545 public void widgetSelected(SelectionEvent e
) {
546 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
547 if (treeItems
.size() == 0) {
550 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
551 tree
.setTopItem(treeItem
);
555 // ensure alignment of top item between tree and time graph
556 fTimeGraphViewer
.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
558 public void mouseScrolled(MouseEvent e
) {
559 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
560 if (treeItems
.size() == 0) {
563 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
564 tree
.setTopItem(treeItem
);
568 // ensure the tree has focus control when mouse is over it if the time graph had control
569 fTreeViewer
.getControl().addMouseTrackListener(new MouseTrackAdapter() {
571 public void mouseEnter(MouseEvent e
) {
572 if (fTimeGraphViewer
.getTimeGraphControl().isFocusControl()) {
573 fTreeViewer
.getControl().setFocus();
578 // ensure the time graph has focus control when mouse is over it if the tree had control
579 fTimeGraphViewer
.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
581 public void mouseEnter(MouseEvent e
) {
582 if (fTreeViewer
.getControl().isFocusControl()) {
583 fTimeGraphViewer
.getTimeGraphControl().setFocus();
587 fTimeGraphViewer
.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
589 public void mouseEnter(MouseEvent e
) {
590 if (fTreeViewer
.getControl().isFocusControl()) {
591 fTimeGraphViewer
.getTimeGraphControl().setFocus();
596 // The filler rows are required to ensure alignment when the tree does not have a
597 // visible horizontal scroll bar. The tree does not allow its top item to be set
598 // to a value that would cause blank space to be drawn at the bottom of the tree.
599 fNumFillerRows
= Display
.getDefault().getBounds().height
/ getItemHeight(tree
);
601 sash
.setWeights(new int[] { 1, 1 });
604 // ------------------------------------------------------------------------
606 // ------------------------------------------------------------------------
609 * Returns this time graph combo's tree viewer.
611 * @return the tree viewer
613 public TreeViewer
getTreeViewer() {
618 * Returns this time graph combo's time graph viewer.
620 * @return the time graph viewer
622 public TimeGraphViewer
getTimeGraphViewer() {
623 return fTimeGraphViewer
;
627 * Callback for the show filter action
631 public void showFilterDialog() {
632 if(fTopInput
!= null) {
633 List
<?
extends ITimeGraphEntry
> allElements
= listAllInputs(fTopInput
);
634 fFilterDialog
.setInput(fTopInput
.toArray(new ITimeGraphEntry
[0]));
635 fFilterDialog
.setTitle(Messages
.TmfTimeFilterDialog_WINDOW_TITLE
);
636 fFilterDialog
.setMessage(Messages
.TmfTimeFilterDialog_MESSAGE
);
637 fFilterDialog
.setExpandedElements(allElements
.toArray());
638 if (fFilter
.getFiltered() != null) {
639 ArrayList
<?
extends ITimeGraphEntry
> nonFilteredElements
= new ArrayList
<ITimeGraphEntry
>(allElements
);
640 nonFilteredElements
.removeAll(fFilter
.getFiltered());
641 fFilterDialog
.setInitialElementSelections(nonFilteredElements
);
643 fFilterDialog
.setInitialElementSelections(allElements
);
645 fFilterDialog
.create();
646 fFilterDialog
.open();
647 // Process selected elements
648 if (fFilterDialog
.getResult() != null) {
649 fInhibitTreeSelection
= true;
650 if (fFilterDialog
.getResult().length
!= allElements
.size()) {
651 ArrayList
<Object
> filteredElements
= new ArrayList
<Object
>(allElements
);
652 filteredElements
.removeAll(Arrays
.asList(fFilterDialog
.getResult()));
653 fFilter
.setFiltered(filteredElements
);
655 fFilter
.setFiltered(null);
657 fTreeViewer
.refresh();
658 fTreeViewer
.expandAll();
659 fTimeGraphViewer
.refresh();
660 fInhibitTreeSelection
= false;
661 // Reset selection to first entry
662 if (fFilterDialog
.getResult().length
> 0) {
663 setSelection((ITimeGraphEntry
) fFilterDialog
.getResult()[0]);
670 * Get the show filter action.
672 * @return The Action object
675 public Action
getShowFilterAction() {
676 if (showFilterAction
== null) {
678 showFilterAction
= new Action() {
684 showFilterAction
.setText(Messages
.TmfTimeGraphCombo_FilterActionNameText
);
685 showFilterAction
.setToolTipText(Messages
.TmfTimeGraphCombo_FilterActionToolTipText
);
686 // TODO find a nice, distinctive icon
687 showFilterAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_FILTERS
));
690 return showFilterAction
;
693 // ------------------------------------------------------------------------
695 // ------------------------------------------------------------------------
698 public void redraw() {
699 fTimeGraphViewer
.getControl().redraw();
703 // ------------------------------------------------------------------------
705 // ------------------------------------------------------------------------
708 * Sets the tree content provider used by this time graph combo.
710 * @param contentProvider the tree content provider
712 public void setTreeContentProvider(ITreeContentProvider contentProvider
) {
713 fTreeViewer
.setContentProvider(new TreeContentProviderWrapper(contentProvider
));
717 * Sets the tree label provider used by this time graph combo.
719 * @param labelProvider the tree label provider
721 public void setTreeLabelProvider(ITableLabelProvider labelProvider
) {
722 fTreeViewer
.setLabelProvider(new TreeLabelProviderWrapper(labelProvider
));
726 * Sets the tree content provider used by the filter dialog
728 * @param contentProvider the tree content provider
731 public void setFilterContentProvider(ITreeContentProvider contentProvider
) {
732 fFilterDialog
.setContentProvider(contentProvider
);
736 * Sets the tree label provider used by the filter dialog
738 * @param labelProvider the tree label provider
741 public void setFilterLabelProvider(ITableLabelProvider labelProvider
) {
742 fFilterDialog
.setLabelProvider(labelProvider
);
746 * Sets the tree columns for this time graph combo.
748 * @param columnNames the tree column names
750 public void setTreeColumns(String
[] columnNames
) {
751 final Tree tree
= fTreeViewer
.getTree();
752 for (String columnName
: columnNames
) {
753 TreeColumn column
= new TreeColumn(tree
, SWT
.LEFT
);
754 column
.setText(columnName
);
760 * Sets the tree columns for this time graph combo's filter dialog.
762 * @param columnNames the tree column names
765 public void setFilterColumns(String
[] columnNames
) {
766 fFilterDialog
.setColumnNames(columnNames
);
770 * Sets the time graph provider used by this time graph combo.
772 * @param timeGraphProvider the time graph provider
774 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider
) {
775 fTimeGraphViewer
.setTimeGraphProvider(timeGraphProvider
);
779 * Sets or clears the input for this time graph combo.
780 * The input array should only contain top-level elements.
782 * @param input the input of this time graph combo, or <code>null</code> if none
784 public void setInput(ITimeGraphEntry
[] input
) {
785 fTopInput
= new ArrayList
<ITimeGraphEntry
>(Arrays
.asList(input
));
786 fFilter
.setFiltered(null);
787 fInhibitTreeSelection
= true;
788 fTreeViewer
.setInput(input
);
789 for (SelectionListenerWrapper listenerWrapper
: fSelectionListenerMap
.values()) {
790 listenerWrapper
.selection
= null;
792 fInhibitTreeSelection
= false;
793 fTreeViewer
.expandAll();
794 fTreeViewer
.getTree().getVerticalBar().setEnabled(false);
795 fTreeViewer
.getTree().getVerticalBar().setVisible(false);
796 fTimeGraphViewer
.setItemHeight(getItemHeight(fTreeViewer
.getTree()));
797 fTimeGraphViewer
.setInput(input
);
801 * @param filter The filter object to be attached to the view
804 public void addFilter(ViewerFilter filter
) {
805 ViewerFilter wrapper
= new ViewerFilterWrapper(filter
);
806 fTreeViewer
.addFilter(wrapper
);
807 fTimeGraphViewer
.addFilter(wrapper
);
808 fViewerFilterMap
.put(filter
, wrapper
);
812 * @param filter The filter object to be removed from the view
815 public void removeFilter(ViewerFilter filter
) {
816 ViewerFilter wrapper
= fViewerFilterMap
.get(filter
);
817 fTreeViewer
.removeFilter(wrapper
);
818 fTimeGraphViewer
.removeFilter(wrapper
);
819 fViewerFilterMap
.remove(filter
);
823 * Refreshes this time graph completely with information freshly obtained from its model.
825 public void refresh() {
826 fInhibitTreeSelection
= true;
827 fTreeViewer
.refresh();
828 fTimeGraphViewer
.refresh();
829 fInhibitTreeSelection
= false;
833 * Adds a listener for selection changes in this time graph combo.
835 * @param listener a selection listener
837 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
838 SelectionListenerWrapper listenerWrapper
= new SelectionListenerWrapper(listener
);
839 fTreeViewer
.addSelectionChangedListener(listenerWrapper
);
840 fSelectionListenerMap
.put(listener
, listenerWrapper
);
841 fTimeGraphViewer
.addSelectionListener(listenerWrapper
);
845 * Removes the given selection listener from this time graph combo.
847 * @param listener a selection changed listener
849 public void removeSelectionListener(ITimeGraphSelectionListener listener
) {
850 SelectionListenerWrapper listenerWrapper
= fSelectionListenerMap
.remove(listener
);
851 fTreeViewer
.removeSelectionChangedListener(listenerWrapper
);
852 fTimeGraphViewer
.removeSelectionListener(listenerWrapper
);
856 * Sets the current selection for this time graph combo.
858 * @param selection the new selection
860 public void setSelection(ITimeGraphEntry selection
) {
861 fTimeGraphViewer
.setSelection(selection
);
862 fInhibitTreeSelection
= true; // block the tree selection changed listener
863 if (selection
!= null) {
864 StructuredSelection structuredSelection
= new StructuredSelection(selection
);
865 fTreeViewer
.setSelection(structuredSelection
);
867 fTreeViewer
.setSelection(new StructuredSelection());
869 fInhibitTreeSelection
= false;
870 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(fTreeViewer
.getTree());
871 if (treeItems
.size() == 0) {
874 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
875 fTreeViewer
.getTree().setTopItem(treeItem
);
879 * Set the expanded state of an entry
882 * The entry to expand/collapse
884 * True for expanded, false for collapsed
888 public void setExpandedState(ITimeGraphEntry entry
, boolean expanded
) {
889 fTimeGraphViewer
.setExpandedState(entry
, expanded
);
890 fTreeViewer
.setExpandedState(entry
, expanded
);
894 * Collapses all nodes of the viewer's tree, starting with the root.
898 public void collapseAll() {
899 fTimeGraphViewer
.collapseAll();
900 fTreeViewer
.collapseAll();
904 * Expands all nodes of the viewer's tree, starting with the root.
908 public void expandAll() {
909 fTimeGraphViewer
.expandAll();
910 fTreeViewer
.expandAll();
913 // ------------------------------------------------------------------------
915 // ------------------------------------------------------------------------
917 private ArrayList
<TreeItem
> getVisibleExpandedItems(Tree tree
) {
918 ArrayList
<TreeItem
> items
= new ArrayList
<TreeItem
>();
919 for (TreeItem item
: tree
.getItems()) {
920 if (item
.getData() == FILLER
) {
924 if (item
.getExpanded()) {
925 items
.addAll(getVisibleExpandedItems(item
));
931 private ArrayList
<TreeItem
> getVisibleExpandedItems(TreeItem treeItem
) {
932 ArrayList
<TreeItem
> items
= new ArrayList
<TreeItem
>();
933 for (TreeItem item
: treeItem
.getItems()) {
935 if (item
.getExpanded()) {
936 items
.addAll(getVisibleExpandedItems(item
));
943 * Explores the list of top-level inputs and returns all the inputs
945 * @param inputs The top-level inputs
946 * @return All the inputs
948 private List
<?
extends ITimeGraphEntry
> listAllInputs(List
<?
extends ITimeGraphEntry
> inputs
) {
949 ArrayList
<ITimeGraphEntry
> items
= new ArrayList
<ITimeGraphEntry
>();
950 for (ITimeGraphEntry entry
: inputs
) {
952 if (entry
.hasChildren()) {
953 items
.addAll(listAllInputs(entry
.getChildren()));
959 private int getItemHeight(final Tree tree
) {
961 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
963 if (fLinuxItemHeight
>= 0 && System
.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
964 if (fLinuxItemHeight
!= 0) {
965 return fLinuxItemHeight
;
967 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
968 if (treeItems
.size() > 1) {
969 final TreeItem treeItem0
= treeItems
.get(0);
970 final TreeItem treeItem1
= treeItems
.get(1);
971 PaintListener paintListener
= new PaintListener() {
973 public void paintControl(PaintEvent e
) {
974 tree
.removePaintListener(this);
975 int y0
= treeItem0
.getBounds().y
;
976 int y1
= treeItem1
.getBounds().y
;
977 int itemHeight
= y1
- y0
;
978 if (itemHeight
> 0) {
979 fLinuxItemHeight
= itemHeight
;
980 fTimeGraphViewer
.setItemHeight(itemHeight
);
984 tree
.addPaintListener(paintListener
);
987 fLinuxItemHeight
= -1; // Not Linux, don't perform os.name check anymore
989 return tree
.getItemHeight();