1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson
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 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Arrays
;
17 import java
.util
.HashMap
;
18 import java
.util
.List
;
21 import org
.eclipse
.jface
.action
.Action
;
22 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
23 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
24 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
25 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
26 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
27 import org
.eclipse
.jface
.viewers
.ITreeViewerListener
;
28 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
29 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
30 import org
.eclipse
.jface
.viewers
.TreeExpansionEvent
;
31 import org
.eclipse
.jface
.viewers
.TreeViewer
;
32 import org
.eclipse
.jface
.viewers
.Viewer
;
33 import org
.eclipse
.jface
.viewers
.ViewerFilter
;
34 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Activator
;
35 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.ITmfImageConstants
;
36 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Messages
;
37 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.dialogs
.TimeGraphFilterDialog
;
38 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
39 import org
.eclipse
.swt
.SWT
;
40 import org
.eclipse
.swt
.custom
.SashForm
;
41 import org
.eclipse
.swt
.events
.ControlAdapter
;
42 import org
.eclipse
.swt
.events
.ControlEvent
;
43 import org
.eclipse
.swt
.events
.MouseEvent
;
44 import org
.eclipse
.swt
.events
.MouseTrackAdapter
;
45 import org
.eclipse
.swt
.events
.MouseWheelListener
;
46 import org
.eclipse
.swt
.events
.PaintEvent
;
47 import org
.eclipse
.swt
.events
.PaintListener
;
48 import org
.eclipse
.swt
.events
.SelectionAdapter
;
49 import org
.eclipse
.swt
.events
.SelectionEvent
;
50 import org
.eclipse
.swt
.graphics
.Image
;
51 import org
.eclipse
.swt
.graphics
.Point
;
52 import org
.eclipse
.swt
.layout
.FillLayout
;
53 import org
.eclipse
.swt
.widgets
.Composite
;
54 import org
.eclipse
.swt
.widgets
.Display
;
55 import org
.eclipse
.swt
.widgets
.Event
;
56 import org
.eclipse
.swt
.widgets
.Listener
;
57 import org
.eclipse
.swt
.widgets
.Slider
;
58 import org
.eclipse
.swt
.widgets
.Tree
;
59 import org
.eclipse
.swt
.widgets
.TreeColumn
;
60 import org
.eclipse
.swt
.widgets
.TreeItem
;
63 * Time graph "combo" view (with the list/tree on the left and the gantt chart
67 * @author Patrick Tasse
69 public class TimeGraphCombo
extends Composite
{
71 // ------------------------------------------------------------------------
73 // ------------------------------------------------------------------------
75 private static final Object FILLER
= new Object();
77 // ------------------------------------------------------------------------
79 // ------------------------------------------------------------------------
82 private TreeViewer fTreeViewer
;
85 private TimeGraphViewer fTimeGraphViewer
;
87 // The top-level input (children excluded)
88 private List
<?
extends ITimeGraphEntry
> fTopInput
;
90 // The selection listener map
91 private final HashMap
<ITimeGraphSelectionListener
, SelectionListenerWrapper
> fSelectionListenerMap
= new HashMap
<ITimeGraphSelectionListener
, SelectionListenerWrapper
>();
93 // The map of viewer filters
94 private final Map
<ViewerFilter
, ViewerFilter
> fViewerFilterMap
= new HashMap
<ViewerFilter
, ViewerFilter
>();
96 // Flag to block the tree selection changed listener when triggered by the time graph combo
97 private boolean fInhibitTreeSelection
= false;
99 // Number of filler rows used by the tree content provider
100 private int fNumFillerRows
;
102 // Calculated item height for Linux workaround
103 private int fLinuxItemHeight
= 0;
105 // The button that opens the filter dialog
106 private Action showFilterAction
;
109 private TimeGraphFilterDialog fFilterDialog
;
111 // The filter generated from the filter dialog
112 private RawViewerFilter fFilter
;
114 // ------------------------------------------------------------------------
116 // ------------------------------------------------------------------------
119 * The TreeContentProviderWrapper is used to insert filler items after
120 * the elements of the tree's real content provider.
122 private class TreeContentProviderWrapper
implements ITreeContentProvider
{
123 private final ITreeContentProvider contentProvider
;
125 public TreeContentProviderWrapper(ITreeContentProvider contentProvider
) {
126 this.contentProvider
= contentProvider
;
130 public void dispose() {
131 contentProvider
.dispose();
135 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
136 contentProvider
.inputChanged(viewer
, oldInput
, newInput
);
140 public Object
[] getElements(Object inputElement
) {
141 Object
[] elements
= contentProvider
.getElements(inputElement
);
142 // add filler elements to ensure alignment with time analysis viewer
143 Object
[] oElements
= Arrays
.copyOf(elements
, elements
.length
+ fNumFillerRows
, new Object
[0].getClass());
144 for (int i
= 0; i
< fNumFillerRows
; i
++) {
145 oElements
[elements
.length
+ i
] = FILLER
;
151 public Object
[] getChildren(Object parentElement
) {
152 if (parentElement
instanceof ITimeGraphEntry
) {
153 return contentProvider
.getChildren(parentElement
);
155 return new Object
[0];
159 public Object
getParent(Object element
) {
160 if (element
instanceof ITimeGraphEntry
) {
161 return contentProvider
.getParent(element
);
167 public boolean hasChildren(Object element
) {
168 if (element
instanceof ITimeGraphEntry
) {
169 return contentProvider
.hasChildren(element
);
176 * The TreeLabelProviderWrapper is used to intercept the filler items
177 * from the calls to the tree's real label provider.
179 private class TreeLabelProviderWrapper
implements ITableLabelProvider
{
180 private final ITableLabelProvider labelProvider
;
182 public TreeLabelProviderWrapper(ITableLabelProvider labelProvider
) {
183 this.labelProvider
= labelProvider
;
187 public void addListener(ILabelProviderListener listener
) {
188 labelProvider
.addListener(listener
);
192 public void dispose() {
193 labelProvider
.dispose();
197 public boolean isLabelProperty(Object element
, String property
) {
198 if (element
instanceof ITimeGraphEntry
) {
199 return labelProvider
.isLabelProperty(element
, property
);
205 public void removeListener(ILabelProviderListener listener
) {
206 labelProvider
.removeListener(listener
);
210 public Image
getColumnImage(Object element
, int columnIndex
) {
211 if (element
instanceof ITimeGraphEntry
) {
212 return labelProvider
.getColumnImage(element
, columnIndex
);
218 public String
getColumnText(Object element
, int columnIndex
) {
219 if (element
instanceof ITimeGraphEntry
) {
220 return labelProvider
.getColumnText(element
, columnIndex
);
228 * The SelectionListenerWrapper is used to intercept the filler items from
229 * the time graph combo's real selection listener, and to prevent double
230 * notifications from being sent when selection changes in both tree and
231 * time graph at the same time.
233 private class SelectionListenerWrapper
implements ISelectionChangedListener
, ITimeGraphSelectionListener
{
234 private final ITimeGraphSelectionListener listener
;
235 private ITimeGraphEntry selection
= null;
237 public SelectionListenerWrapper(ITimeGraphSelectionListener listener
) {
238 this.listener
= listener
;
242 public void selectionChanged(SelectionChangedEvent event
) {
243 if (fInhibitTreeSelection
) {
246 Object element
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
247 if (element
instanceof ITimeGraphEntry
) {
248 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
249 if (entry
!= selection
) {
251 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
257 public void selectionChanged(TimeGraphSelectionEvent event
) {
258 ITimeGraphEntry entry
= event
.getSelection();
259 if (entry
!= selection
) {
261 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
267 * The ViewerFilterWrapper is used to intercept the filler items from
268 * the time graph combo's real ViewerFilters. These filler items should
271 private class ViewerFilterWrapper
extends ViewerFilter
{
273 ViewerFilter fWrappedFilter
;
275 ViewerFilterWrapper(ViewerFilter filter
) {
277 this.fWrappedFilter
= filter
;
281 public boolean select(Viewer viewer
, Object parentElement
, Object element
) {
282 if (element
instanceof ITimeGraphEntry
) {
283 return fWrappedFilter
.select(viewer
, parentElement
, element
);
291 * This filter simply keeps a list of elements that should be shown.
292 * All the other elements will be filtered.
293 * By default and when the list is set to null, all elements are shown.
295 private class RawViewerFilter
extends ViewerFilter
{
297 private List
<Object
> fNonFiltered
= null;
299 public void setNonFiltered(List
<Object
> objects
) {
300 fNonFiltered
= objects
;
303 public List
<Object
> getNonFiltered() {
308 public boolean select(Viewer viewer
, Object parentElement
, Object element
) {
309 if (fNonFiltered
== null) {
312 return fNonFiltered
.contains(element
);
316 // ------------------------------------------------------------------------
318 // ------------------------------------------------------------------------
321 * Constructs a new instance of this class given its parent
322 * and a style value describing its behavior and appearance.
324 * @param parent a widget which will be the parent of the new instance (cannot be null)
325 * @param style the style of widget to construct
327 public TimeGraphCombo(Composite parent
, int style
) {
328 super(parent
, style
);
329 setLayout(new FillLayout());
331 final SashForm sash
= new SashForm(this, SWT
.NONE
);
333 fTreeViewer
= new TreeViewer(sash
, SWT
.FULL_SELECTION
| SWT
.H_SCROLL
);
334 final Tree tree
= fTreeViewer
.getTree();
335 tree
.setHeaderVisible(true);
336 tree
.setLinesVisible(true);
338 fTimeGraphViewer
= new TimeGraphViewer(sash
, SWT
.NONE
);
339 fTimeGraphViewer
.setItemHeight(getItemHeight(tree
));
340 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
341 fTimeGraphViewer
.setBorderWidth(tree
.getBorderWidth());
342 fTimeGraphViewer
.setNameWidthPref(0);
344 fFilter
= new RawViewerFilter();
347 fFilterDialog
= new TimeGraphFilterDialog(getShell());
349 // Feature in Windows. The tree vertical bar reappears when
350 // the control is resized so we need to hide it again.
351 // Bug in Linux. The tree header height is 0 in constructor,
352 // so we need to reset it later when the control is resized.
353 tree
.addControlListener(new ControlAdapter() {
356 public void controlResized(ControlEvent e
) {
359 tree
.getVerticalBar().setEnabled(false);
360 // this can trigger controlResized recursively
361 tree
.getVerticalBar().setVisible(false);
364 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
368 // ensure synchronization of expanded items between tree and time graph
369 fTreeViewer
.addTreeListener(new ITreeViewerListener() {
371 public void treeCollapsed(TreeExpansionEvent event
) {
372 fTimeGraphViewer
.setExpandedState((ITimeGraphEntry
) event
.getElement(), false);
373 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
374 if (treeItems
.size() == 0) {
377 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
378 tree
.setTopItem(treeItem
);
382 public void treeExpanded(TreeExpansionEvent event
) {
383 fTimeGraphViewer
.setExpandedState((ITimeGraphEntry
) event
.getElement(), true);
384 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
385 if (treeItems
.size() == 0) {
388 final TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
389 // queue the top item update because the tree can change its top item
390 // autonomously immediately after the listeners have been notified
391 getDisplay().asyncExec(new Runnable() {
394 tree
.setTopItem(treeItem
);
399 // ensure synchronization of expanded items between tree and time graph
400 fTimeGraphViewer
.addTreeListener(new ITimeGraphTreeListener() {
402 public void treeCollapsed(TimeGraphTreeExpansionEvent event
) {
403 fTreeViewer
.setExpandedState(event
.getEntry(), false);
407 public void treeExpanded(TimeGraphTreeExpansionEvent event
) {
408 fTreeViewer
.setExpandedState(event
.getEntry(), true);
412 // prevent mouse button from selecting a filler tree item
413 tree
.addListener(SWT
.MouseDown
, new Listener() {
415 public void handleEvent(Event event
) {
416 TreeItem treeItem
= tree
.getItem(new Point(event
.x
, event
.y
));
417 if (treeItem
== null || treeItem
.getData() == FILLER
) {
419 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
420 if (treeItems
.size() == 0) {
421 fTreeViewer
.setSelection(new StructuredSelection());
422 fTimeGraphViewer
.setSelection(null);
425 // this prevents from scrolling up when selecting
426 // the partially visible tree item at the bottom
427 tree
.select(treeItems
.get(treeItems
.size() - 1));
428 fTreeViewer
.setSelection(new StructuredSelection());
429 fTimeGraphViewer
.setSelection(null);
434 // prevent mouse wheel from scrolling down into filler tree items
435 tree
.addListener(SWT
.MouseWheel
, new Listener() {
437 public void handleEvent(Event event
) {
439 Slider scrollBar
= fTimeGraphViewer
.getVerticalBar();
440 fTimeGraphViewer
.setTopIndex(scrollBar
.getSelection() - event
.count
);
441 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
442 if (treeItems
.size() == 0) {
445 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
446 tree
.setTopItem(treeItem
);
450 // prevent key stroke from selecting a filler tree item
451 tree
.addListener(SWT
.KeyDown
, new Listener() {
453 public void handleEvent(Event event
) {
454 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
455 if (treeItems
.size() == 0) {
456 fTreeViewer
.setSelection(new StructuredSelection());
460 if (event
.keyCode
== SWT
.ARROW_DOWN
) {
461 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + 1, treeItems
.size() - 1);
462 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
464 } else if (event
.keyCode
== SWT
.PAGE_DOWN
) {
465 int height
= tree
.getSize().y
- tree
.getHeaderHeight() - tree
.getHorizontalBar().getSize().y
;
466 int countPerPage
= height
/ getItemHeight(tree
);
467 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + countPerPage
- 1, treeItems
.size() - 1);
468 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
470 } else if (event
.keyCode
== SWT
.END
) {
471 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(treeItems
.size() - 1).getData());
474 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
475 tree
.setTopItem(treeItem
);
476 if (fTimeGraphViewer
.getSelectionIndex() >= 0) {
477 fTreeViewer
.setSelection(new StructuredSelection(fTimeGraphViewer
.getSelection()));
479 fTreeViewer
.setSelection(new StructuredSelection());
484 // ensure alignment of top item between tree and time graph
485 fTimeGraphViewer
.getTimeGraphControl().addControlListener(new ControlAdapter() {
487 public void controlResized(ControlEvent e
) {
488 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
489 if (treeItems
.size() == 0) {
492 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
493 tree
.setTopItem(treeItem
);
497 // ensure synchronization of selected item between tree and time graph
498 fTreeViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
500 public void selectionChanged(SelectionChangedEvent event
) {
501 if (fInhibitTreeSelection
) {
504 if (event
.getSelection() instanceof IStructuredSelection
) {
505 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
506 if (selection
instanceof ITimeGraphEntry
) {
507 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) selection
);
509 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
510 if (treeItems
.size() == 0) {
513 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
514 tree
.setTopItem(treeItem
);
519 // ensure synchronization of selected item between tree and time graph
520 fTimeGraphViewer
.addSelectionListener(new ITimeGraphSelectionListener() {
522 public void selectionChanged(TimeGraphSelectionEvent event
) {
523 ITimeGraphEntry entry
= fTimeGraphViewer
.getSelection();
524 fInhibitTreeSelection
= true; // block the tree selection changed listener
526 StructuredSelection selection
= new StructuredSelection(entry
);
527 fTreeViewer
.setSelection(selection
);
529 fTreeViewer
.setSelection(new StructuredSelection());
531 fInhibitTreeSelection
= false;
532 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
533 if (treeItems
.size() == 0) {
536 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
537 tree
.setTopItem(treeItem
);
541 // ensure alignment of top item between tree and time graph
542 fTimeGraphViewer
.getVerticalBar().addSelectionListener(new SelectionAdapter() {
544 public void widgetSelected(SelectionEvent e
) {
545 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
546 if (treeItems
.size() == 0) {
549 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
550 tree
.setTopItem(treeItem
);
554 // ensure alignment of top item between tree and time graph
555 fTimeGraphViewer
.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
557 public void mouseScrolled(MouseEvent e
) {
558 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
559 if (treeItems
.size() == 0) {
562 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
563 tree
.setTopItem(treeItem
);
567 // ensure the tree has focus control when mouse is over it if the time graph had control
568 fTreeViewer
.getControl().addMouseTrackListener(new MouseTrackAdapter() {
570 public void mouseEnter(MouseEvent e
) {
571 if (fTimeGraphViewer
.getTimeGraphControl().isFocusControl()) {
572 fTreeViewer
.getControl().setFocus();
577 // ensure the time graph has focus control when mouse is over it if the tree had control
578 fTimeGraphViewer
.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
580 public void mouseEnter(MouseEvent e
) {
581 if (fTreeViewer
.getControl().isFocusControl()) {
582 fTimeGraphViewer
.getTimeGraphControl().setFocus();
586 fTimeGraphViewer
.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
588 public void mouseEnter(MouseEvent e
) {
589 if (fTreeViewer
.getControl().isFocusControl()) {
590 fTimeGraphViewer
.getTimeGraphControl().setFocus();
595 // The filler rows are required to ensure alignment when the tree does not have a
596 // visible horizontal scroll bar. The tree does not allow its top item to be set
597 // to a value that would cause blank space to be drawn at the bottom of the tree.
598 fNumFillerRows
= Display
.getDefault().getBounds().height
/ getItemHeight(tree
);
600 sash
.setWeights(new int[] { 1, 1 });
603 // ------------------------------------------------------------------------
605 // ------------------------------------------------------------------------
608 * Returns this time graph combo's tree viewer.
610 * @return the tree viewer
612 public TreeViewer
getTreeViewer() {
617 * Returns this time graph combo's time graph viewer.
619 * @return the time graph viewer
621 public TimeGraphViewer
getTimeGraphViewer() {
622 return fTimeGraphViewer
;
626 * Callback for the show filter action
630 public void showFilterDialog() {
631 if(fTopInput
!= null) {
632 List
<?
extends ITimeGraphEntry
> allElements
= listAllInputs(fTopInput
);
633 fFilterDialog
.setInput(fTopInput
.toArray(new ITimeGraphEntry
[0]));
634 fFilterDialog
.setTitle(Messages
.TmfTimeFilterDialog_WINDOW_TITLE
);
635 fFilterDialog
.setMessage(Messages
.TmfTimeFilterDialog_MESSAGE
);
636 fFilterDialog
.setExpandedElements(allElements
.toArray());
637 if (fFilter
.getNonFiltered() != null) {
638 fFilterDialog
.setInitialElementSelections(fFilter
.getNonFiltered());
640 fFilterDialog
.setInitialElementSelections(allElements
);
642 fFilterDialog
.create();
643 fFilterDialog
.open();
644 // Process selected elements
645 if (fFilterDialog
.getResult() != null) {
646 fInhibitTreeSelection
= true;
647 if (fFilterDialog
.getResult().length
!= allElements
.size()) {
648 fFilter
.setNonFiltered(new ArrayList
<Object
>(Arrays
.asList(fFilterDialog
.getResult())));
650 fFilter
.setNonFiltered(null);
652 fTreeViewer
.refresh();
653 fTreeViewer
.expandAll();
654 fTimeGraphViewer
.refresh();
655 fInhibitTreeSelection
= false;
656 // Reset selection to first entry
657 if (fFilterDialog
.getResult().length
> 0) {
658 setSelection((ITimeGraphEntry
) fFilterDialog
.getResult()[0]);
665 * Get the show filter action.
667 * @return The Action object
670 public Action
getShowFilterAction() {
671 if (showFilterAction
== null) {
673 showFilterAction
= new Action() {
679 showFilterAction
.setText(Messages
.TmfTimeGraphCombo_FilterActionNameText
);
680 showFilterAction
.setToolTipText(Messages
.TmfTimeGraphCombo_FilterActionToolTipText
);
681 // TODO find a nice, distinctive icon
682 showFilterAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_FILTERS
));
685 return showFilterAction
;
688 // ------------------------------------------------------------------------
690 // ------------------------------------------------------------------------
693 * @see org.eclipse.swt.widgets.Control#redraw()
696 public void redraw() {
697 fTimeGraphViewer
.getControl().redraw();
701 // ------------------------------------------------------------------------
703 // ------------------------------------------------------------------------
706 * Sets the tree content provider used by this time graph combo.
708 * @param contentProvider the tree content provider
710 public void setTreeContentProvider(ITreeContentProvider contentProvider
) {
711 fTreeViewer
.setContentProvider(new TreeContentProviderWrapper(contentProvider
));
715 * Sets the tree label provider used by this time graph combo.
717 * @param labelProvider the tree label provider
719 public void setTreeLabelProvider(ITableLabelProvider labelProvider
) {
720 fTreeViewer
.setLabelProvider(new TreeLabelProviderWrapper(labelProvider
));
724 * Sets the tree content provider used by the filter dialog
726 * @param contentProvider the tree content provider
729 public void setFilterContentProvider(ITreeContentProvider contentProvider
) {
730 fFilterDialog
.setContentProvider(contentProvider
);
734 * Sets the tree label provider used by the filter dialog
736 * @param labelProvider the tree label provider
739 public void setFilterLabelProvider(ITableLabelProvider labelProvider
) {
740 fFilterDialog
.setLabelProvider(labelProvider
);
744 * Sets the tree columns for this time graph combo.
746 * @param columnNames the tree column names
748 public void setTreeColumns(String
[] columnNames
) {
749 final Tree tree
= fTreeViewer
.getTree();
750 for (String columnName
: columnNames
) {
751 TreeColumn column
= new TreeColumn(tree
, SWT
.LEFT
);
752 column
.setText(columnName
);
758 * Sets the tree columns for this time graph combo's filter dialog.
760 * @param columnNames the tree column names
763 public void setFilterColumns(String
[] columnNames
) {
764 fFilterDialog
.setColumnNames(columnNames
);
768 * Sets the time graph provider used by this time graph combo.
770 * @param timeGraphProvider the time graph provider
772 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider
) {
773 fTimeGraphViewer
.setTimeGraphProvider(timeGraphProvider
);
777 * Sets or clears the input for this time graph combo.
778 * The input array should only contain top-level elements.
780 * @param input the input of this time graph combo, or <code>null</code> if none
782 public void setInput(ITimeGraphEntry
[] input
) {
783 fTopInput
= new ArrayList
<ITimeGraphEntry
>(Arrays
.asList(input
));
784 fFilter
.setNonFiltered(null);
785 fInhibitTreeSelection
= true;
786 fTreeViewer
.setInput(input
);
787 for (SelectionListenerWrapper listenerWrapper
: fSelectionListenerMap
.values()) {
788 listenerWrapper
.selection
= null;
790 fInhibitTreeSelection
= false;
791 fTreeViewer
.expandAll();
792 fTreeViewer
.getTree().getVerticalBar().setEnabled(false);
793 fTreeViewer
.getTree().getVerticalBar().setVisible(false);
794 fTimeGraphViewer
.setItemHeight(getItemHeight(fTreeViewer
.getTree()));
795 fTimeGraphViewer
.setInput(input
);
799 * @param filter The filter object to be attached to the view
802 public void addFilter(ViewerFilter filter
) {
803 ViewerFilter wrapper
= new ViewerFilterWrapper(filter
);
804 fTreeViewer
.addFilter(wrapper
);
805 fTimeGraphViewer
.addFilter(wrapper
);
806 fViewerFilterMap
.put(filter
, wrapper
);
810 * @param filter The filter object to be removed from the view
813 public void removeFilter(ViewerFilter filter
) {
814 ViewerFilter wrapper
= fViewerFilterMap
.get(filter
);
815 fTreeViewer
.removeFilter(wrapper
);
816 fTimeGraphViewer
.removeFilter(wrapper
);
817 fViewerFilterMap
.remove(filter
);
821 * Refreshes this time graph completely with information freshly obtained from its model.
823 public void refresh() {
824 fInhibitTreeSelection
= true;
825 fTreeViewer
.refresh();
826 fTimeGraphViewer
.refresh();
827 fInhibitTreeSelection
= false;
831 * Adds a listener for selection changes in this time graph combo.
833 * @param listener a selection listener
835 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
836 SelectionListenerWrapper listenerWrapper
= new SelectionListenerWrapper(listener
);
837 fTreeViewer
.addSelectionChangedListener(listenerWrapper
);
838 fSelectionListenerMap
.put(listener
, listenerWrapper
);
839 fTimeGraphViewer
.addSelectionListener(listenerWrapper
);
843 * Removes the given selection listener from this time graph combo.
845 * @param listener a selection changed listener
847 public void removeSelectionListener(ITimeGraphSelectionListener listener
) {
848 SelectionListenerWrapper listenerWrapper
= fSelectionListenerMap
.remove(listener
);
849 fTreeViewer
.removeSelectionChangedListener(listenerWrapper
);
850 fTimeGraphViewer
.removeSelectionListener(listenerWrapper
);
854 * Sets the current selection for this time graph combo.
856 * @param selection the new selection
858 public void setSelection(ITimeGraphEntry selection
) {
859 fTimeGraphViewer
.setSelection(selection
);
860 fInhibitTreeSelection
= true; // block the tree selection changed listener
861 if (selection
!= null) {
862 StructuredSelection structuredSelection
= new StructuredSelection(selection
);
863 fTreeViewer
.setSelection(structuredSelection
);
865 fTreeViewer
.setSelection(new StructuredSelection());
867 fInhibitTreeSelection
= false;
868 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(fTreeViewer
.getTree());
869 if (treeItems
.size() == 0) {
872 TreeItem treeItem
= treeItems
.get(fTimeGraphViewer
.getTopIndex());
873 fTreeViewer
.getTree().setTopItem(treeItem
);
877 * Set the expanded state of an entry
880 * The entry to expand/collapse
882 * True for expanded, false for collapsed
886 public void setExpandedState(ITimeGraphEntry entry
, boolean expanded
) {
887 fTimeGraphViewer
.setExpandedState(entry
, expanded
);
888 fTreeViewer
.setExpandedState(entry
, expanded
);
892 * Collapses all nodes of the viewer's tree, starting with the root.
896 public void collapseAll() {
897 fTimeGraphViewer
.collapseAll();
898 fTreeViewer
.collapseAll();
902 * Expands all nodes of the viewer's tree, starting with the root.
906 public void expandAll() {
907 fTimeGraphViewer
.expandAll();
908 fTreeViewer
.expandAll();
911 // ------------------------------------------------------------------------
913 // ------------------------------------------------------------------------
915 private ArrayList
<TreeItem
> getVisibleExpandedItems(Tree tree
) {
916 ArrayList
<TreeItem
> items
= new ArrayList
<TreeItem
>();
917 for (TreeItem item
: tree
.getItems()) {
918 if (item
.getData() == FILLER
) {
922 if (item
.getExpanded()) {
923 items
.addAll(getVisibleExpandedItems(item
));
929 private ArrayList
<TreeItem
> getVisibleExpandedItems(TreeItem treeItem
) {
930 ArrayList
<TreeItem
> items
= new ArrayList
<TreeItem
>();
931 for (TreeItem item
: treeItem
.getItems()) {
933 if (item
.getExpanded()) {
934 items
.addAll(getVisibleExpandedItems(item
));
941 * Explores the list of top-level inputs and returns all the inputs
943 * @param inputs The top-level inputs
944 * @return All the inputs
946 private List
<?
extends ITimeGraphEntry
> listAllInputs(List
<?
extends ITimeGraphEntry
> inputs
) {
947 ArrayList
<ITimeGraphEntry
> items
= new ArrayList
<ITimeGraphEntry
>();
948 for (ITimeGraphEntry entry
: inputs
) {
950 if (entry
.hasChildren()) {
951 items
.addAll(listAllInputs(entry
.getChildren()));
957 private int getItemHeight(final Tree tree
) {
959 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
961 if (fLinuxItemHeight
>= 0 && System
.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
962 if (fLinuxItemHeight
!= 0) {
963 return fLinuxItemHeight
;
965 ArrayList
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
);
966 if (treeItems
.size() > 1) {
967 final TreeItem treeItem0
= treeItems
.get(0);
968 final TreeItem treeItem1
= treeItems
.get(1);
969 PaintListener paintListener
= new PaintListener() {
971 public void paintControl(PaintEvent e
) {
972 tree
.removePaintListener(this);
973 int y0
= treeItem0
.getBounds().y
;
974 int y1
= treeItem1
.getBounds().y
;
975 int itemHeight
= y1
- y0
;
976 if (itemHeight
> 0) {
977 fLinuxItemHeight
= itemHeight
;
978 fTimeGraphViewer
.setItemHeight(itemHeight
);
982 tree
.addPaintListener(paintListener
);
985 fLinuxItemHeight
= -1; // Not Linux, don't perform os.name check anymore
987 return tree
.getItemHeight();