Merge branch 'master' into lttng-kepler
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / widgets / timegraph / TimeGraphCombo.java
1 /*******************************************************************************
2 * Copyright (c) 2012 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.ui.widgets.timegraph;
14
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.HashMap;
18
19 import org.eclipse.jface.viewers.ILabelProviderListener;
20 import org.eclipse.jface.viewers.ISelectionChangedListener;
21 import org.eclipse.jface.viewers.IStructuredSelection;
22 import org.eclipse.jface.viewers.ITableLabelProvider;
23 import org.eclipse.jface.viewers.ITreeContentProvider;
24 import org.eclipse.jface.viewers.ITreeViewerListener;
25 import org.eclipse.jface.viewers.SelectionChangedEvent;
26 import org.eclipse.jface.viewers.StructuredSelection;
27 import org.eclipse.jface.viewers.TreeExpansionEvent;
28 import org.eclipse.jface.viewers.TreeViewer;
29 import org.eclipse.jface.viewers.Viewer;
30 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
31 import org.eclipse.swt.SWT;
32 import org.eclipse.swt.custom.SashForm;
33 import org.eclipse.swt.events.ControlAdapter;
34 import org.eclipse.swt.events.ControlEvent;
35 import org.eclipse.swt.events.MouseEvent;
36 import org.eclipse.swt.events.MouseTrackAdapter;
37 import org.eclipse.swt.events.MouseWheelListener;
38 import org.eclipse.swt.events.PaintEvent;
39 import org.eclipse.swt.events.PaintListener;
40 import org.eclipse.swt.events.SelectionAdapter;
41 import org.eclipse.swt.events.SelectionEvent;
42 import org.eclipse.swt.graphics.Image;
43 import org.eclipse.swt.graphics.Point;
44 import org.eclipse.swt.layout.FillLayout;
45 import org.eclipse.swt.widgets.Composite;
46 import org.eclipse.swt.widgets.Display;
47 import org.eclipse.swt.widgets.Event;
48 import org.eclipse.swt.widgets.Listener;
49 import org.eclipse.swt.widgets.Slider;
50 import org.eclipse.swt.widgets.Tree;
51 import org.eclipse.swt.widgets.TreeColumn;
52 import org.eclipse.swt.widgets.TreeItem;
53
54 /**
55 * Time graph "combo" view (with the list/tree on the left and the gantt chart
56 * on the right)
57 *
58 * @version 1.0
59 * @author Patrick Tasse
60 */
61 public class TimeGraphCombo extends Composite {
62
63 // ------------------------------------------------------------------------
64 // Constants
65 // ------------------------------------------------------------------------
66
67 private static final Object FILLER = new Object();
68
69 // ------------------------------------------------------------------------
70 // Fields
71 // ------------------------------------------------------------------------
72
73 // The tree viewer
74 private TreeViewer fTreeViewer;
75
76 // The time viewer
77 private TimeGraphViewer fTimeGraphViewer;
78
79 // The selection listener map
80 private final HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper> fSelectionListenerMap = new HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper>();
81
82 // Flag to block the tree selection changed listener when triggered by the time graph combo
83 private boolean fInhibitTreeSelection = false;
84
85 // Number of filler rows used by the tree content provider
86 private int fNumFillerRows;
87
88 // Calculated item height for Linux workaround
89 private int fLinuxItemHeight = 0;
90
91 // ------------------------------------------------------------------------
92 // Classes
93 // ------------------------------------------------------------------------
94
95 /**
96 * The TreeContentProviderWrapper is used to insert filler items after
97 * the elements of the tree's real content provider.
98 */
99 private class TreeContentProviderWrapper implements ITreeContentProvider {
100 private final ITreeContentProvider contentProvider;
101
102 public TreeContentProviderWrapper(ITreeContentProvider contentProvider) {
103 this.contentProvider = contentProvider;
104 }
105
106 @Override
107 public void dispose() {
108 contentProvider.dispose();
109 }
110
111 @Override
112 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
113 contentProvider.inputChanged(viewer, oldInput, newInput);
114 }
115
116 @Override
117 public Object[] getElements(Object inputElement) {
118 Object[] elements = contentProvider.getElements(inputElement);
119 // add filler elements to ensure alignment with time analysis viewer
120 Object[] oElements = Arrays.copyOf(elements, elements.length + fNumFillerRows, new Object[0].getClass());
121 for (int i = 0; i < fNumFillerRows; i++) {
122 oElements[elements.length + i] = FILLER;
123 }
124 return oElements;
125 }
126
127 @Override
128 public Object[] getChildren(Object parentElement) {
129 if (parentElement instanceof ITimeGraphEntry) {
130 return contentProvider.getChildren(parentElement);
131 }
132 return new Object[0];
133 }
134
135 @Override
136 public Object getParent(Object element) {
137 if (element instanceof ITimeGraphEntry) {
138 return contentProvider.getParent(element);
139 }
140 return null;
141 }
142
143 @Override
144 public boolean hasChildren(Object element) {
145 if (element instanceof ITimeGraphEntry) {
146 return contentProvider.hasChildren(element);
147 }
148 return false;
149 }
150 }
151
152 /**
153 * The TreeLabelProviderWrapper is used to intercept the filler items
154 * from the calls to the tree's real label provider.
155 */
156 private class TreeLabelProviderWrapper implements ITableLabelProvider {
157 private final ITableLabelProvider labelProvider;
158
159 public TreeLabelProviderWrapper(ITableLabelProvider labelProvider) {
160 this.labelProvider = labelProvider;
161 }
162
163 @Override
164 public void addListener(ILabelProviderListener listener) {
165 labelProvider.addListener(listener);
166 }
167
168 @Override
169 public void dispose() {
170 labelProvider.dispose();
171 }
172
173 @Override
174 public boolean isLabelProperty(Object element, String property) {
175 if (element instanceof ITimeGraphEntry) {
176 return labelProvider.isLabelProperty(element, property);
177 }
178 return false;
179 }
180
181 @Override
182 public void removeListener(ILabelProviderListener listener) {
183 labelProvider.removeListener(listener);
184 }
185
186 @Override
187 public Image getColumnImage(Object element, int columnIndex) {
188 if (element instanceof ITimeGraphEntry) {
189 return labelProvider.getColumnImage(element, columnIndex);
190 }
191 return null;
192 }
193
194 @Override
195 public String getColumnText(Object element, int columnIndex) {
196 if (element instanceof ITimeGraphEntry) {
197 return labelProvider.getColumnText(element, columnIndex);
198 }
199 return null;
200 }
201
202 }
203
204 /**
205 * The SelectionListenerWrapper is used to intercept the filler items from
206 * the time graph combo's real selection listener, and to prevent double
207 * notifications from being sent when selection changes in both tree and
208 * time graph at the same time.
209 */
210 private class SelectionListenerWrapper implements ISelectionChangedListener, ITimeGraphSelectionListener {
211 private final ITimeGraphSelectionListener listener;
212 private ITimeGraphEntry selection = null;
213
214 public SelectionListenerWrapper(ITimeGraphSelectionListener listener) {
215 this.listener = listener;
216 }
217
218 @Override
219 public void selectionChanged(SelectionChangedEvent event) {
220 if (fInhibitTreeSelection) {
221 return;
222 }
223 Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
224 if (element instanceof ITimeGraphEntry) {
225 ITimeGraphEntry entry = (ITimeGraphEntry) element;
226 if (entry != selection) {
227 selection = entry;
228 listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
229 }
230 }
231 }
232
233 @Override
234 public void selectionChanged(TimeGraphSelectionEvent event) {
235 ITimeGraphEntry entry = event.getSelection();
236 if (entry != selection) {
237 selection = entry;
238 listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
239 }
240 }
241 }
242
243 // ------------------------------------------------------------------------
244 // Constructors
245 // ------------------------------------------------------------------------
246
247 /**
248 * Constructs a new instance of this class given its parent
249 * and a style value describing its behavior and appearance.
250 *
251 * @param parent a widget which will be the parent of the new instance (cannot be null)
252 * @param style the style of widget to construct
253 */
254 public TimeGraphCombo(Composite parent, int style) {
255 super(parent, style);
256 setLayout(new FillLayout());
257
258 final SashForm sash = new SashForm(this, SWT.NONE);
259
260 fTreeViewer = new TreeViewer(sash, SWT.FULL_SELECTION | SWT.H_SCROLL);
261 final Tree tree = fTreeViewer.getTree();
262 tree.setHeaderVisible(true);
263 tree.setLinesVisible(true);
264
265 fTimeGraphViewer = new TimeGraphViewer(sash, SWT.NONE);
266 fTimeGraphViewer.setItemHeight(getItemHeight(tree));
267 fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
268 fTimeGraphViewer.setBorderWidth(tree.getBorderWidth());
269 fTimeGraphViewer.setNameWidthPref(0);
270
271 // Feature in Windows. The tree vertical bar reappears when
272 // the control is resized so we need to hide it again.
273 // Bug in Linux. The tree header height is 0 in constructor,
274 // so we need to reset it later when the control is resized.
275 tree.addControlListener(new ControlAdapter() {
276 int depth = 0;
277 @Override
278 public void controlResized(ControlEvent e) {
279 if (depth == 0) {
280 depth++;
281 tree.getVerticalBar().setEnabled(false);
282 // this can trigger controlResized recursively
283 tree.getVerticalBar().setVisible(false);
284 depth--;
285 }
286 fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
287 }
288 });
289
290 // ensure synchronization of expanded items between tree and time graph
291 fTreeViewer.addTreeListener(new ITreeViewerListener() {
292 @Override
293 public void treeCollapsed(TreeExpansionEvent event) {
294 fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), false);
295 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
296 if (treeItems.size() == 0) {
297 return;
298 }
299 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
300 tree.setTopItem(treeItem);
301 }
302
303 @Override
304 public void treeExpanded(TreeExpansionEvent event) {
305 fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), true);
306 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
307 if (treeItems.size() == 0) {
308 return;
309 }
310 final TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
311 // queue the top item update because the tree can change its top item
312 // autonomously immediately after the listeners have been notified
313 getDisplay().asyncExec(new Runnable() {
314 @Override
315 public void run() {
316 tree.setTopItem(treeItem);
317 }});
318 }
319 });
320
321 // ensure synchronization of expanded items between tree and time graph
322 fTimeGraphViewer.addTreeListener(new ITimeGraphTreeListener() {
323 @Override
324 public void treeCollapsed(TimeGraphTreeExpansionEvent event) {
325 fTreeViewer.setExpandedState(event.getEntry(), false);
326 }
327
328 @Override
329 public void treeExpanded(TimeGraphTreeExpansionEvent event) {
330 fTreeViewer.setExpandedState(event.getEntry(), true);
331 }
332 });
333
334 // prevent mouse button from selecting a filler tree item
335 tree.addListener(SWT.MouseDown, new Listener() {
336 @Override
337 public void handleEvent(Event event) {
338 TreeItem treeItem = tree.getItem(new Point(event.x, event.y));
339 if (treeItem == null || treeItem.getData() == FILLER) {
340 event.doit = false;
341 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
342 if (treeItems.size() == 0) {
343 fTreeViewer.setSelection(new StructuredSelection());
344 fTimeGraphViewer.setSelection(null);
345 return;
346 }
347 // this prevents from scrolling up when selecting
348 // the partially visible tree item at the bottom
349 tree.select(treeItems.get(treeItems.size() - 1));
350 fTreeViewer.setSelection(new StructuredSelection());
351 fTimeGraphViewer.setSelection(null);
352 }
353 }
354 });
355
356 // prevent mouse wheel from scrolling down into filler tree items
357 tree.addListener(SWT.MouseWheel, new Listener() {
358 @Override
359 public void handleEvent(Event event) {
360 event.doit = false;
361 Slider scrollBar = fTimeGraphViewer.getVerticalBar();
362 fTimeGraphViewer.setTopIndex(scrollBar.getSelection() - event.count);
363 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
364 if (treeItems.size() == 0) {
365 return;
366 }
367 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
368 tree.setTopItem(treeItem);
369 }
370 });
371
372 // prevent key stroke from selecting a filler tree item
373 tree.addListener(SWT.KeyDown, new Listener() {
374 @Override
375 public void handleEvent(Event event) {
376 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
377 if (treeItems.size() == 0) {
378 fTreeViewer.setSelection(new StructuredSelection());
379 event.doit = false;
380 return;
381 }
382 if (event.keyCode == SWT.ARROW_DOWN) {
383 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + 1, treeItems.size() - 1);
384 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
385 event.doit = false;
386 } else if (event.keyCode == SWT.PAGE_DOWN) {
387 int height = tree.getSize().y - tree.getHeaderHeight() - tree.getHorizontalBar().getSize().y;
388 int countPerPage = height / getItemHeight(tree);
389 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + countPerPage - 1, treeItems.size() - 1);
390 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
391 event.doit = false;
392 } else if (event.keyCode == SWT.END) {
393 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(treeItems.size() - 1).getData());
394 event.doit = false;
395 }
396 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
397 tree.setTopItem(treeItem);
398 if (fTimeGraphViewer.getSelectionIndex() >= 0) {
399 fTreeViewer.setSelection(new StructuredSelection(fTimeGraphViewer.getSelection()));
400 } else {
401 fTreeViewer.setSelection(new StructuredSelection());
402 }
403 }
404 });
405
406 // ensure alignment of top item between tree and time graph
407 fTimeGraphViewer.getTimeGraphControl().addControlListener(new ControlAdapter() {
408 @Override
409 public void controlResized(ControlEvent e) {
410 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
411 if (treeItems.size() == 0) {
412 return;
413 }
414 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
415 tree.setTopItem(treeItem);
416 }
417 });
418
419 // ensure synchronization of selected item between tree and time graph
420 fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
421 @Override
422 public void selectionChanged(SelectionChangedEvent event) {
423 if (fInhibitTreeSelection) {
424 return;
425 }
426 if (event.getSelection() instanceof IStructuredSelection) {
427 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
428 if (selection instanceof ITimeGraphEntry) {
429 fTimeGraphViewer.setSelection((ITimeGraphEntry) selection);
430 }
431 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
432 if (treeItems.size() == 0) {
433 return;
434 }
435 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
436 tree.setTopItem(treeItem);
437 }
438 }
439 });
440
441 // ensure synchronization of selected item between tree and time graph
442 fTimeGraphViewer.addSelectionListener(new ITimeGraphSelectionListener() {
443 @Override
444 public void selectionChanged(TimeGraphSelectionEvent event) {
445 ITimeGraphEntry entry = fTimeGraphViewer.getSelection();
446 fInhibitTreeSelection = true; // block the tree selection changed listener
447 if (entry != null) {
448 StructuredSelection selection = new StructuredSelection(entry);
449 fTreeViewer.setSelection(selection);
450 } else {
451 fTreeViewer.setSelection(new StructuredSelection());
452 }
453 fInhibitTreeSelection = false;
454 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
455 if (treeItems.size() == 0) {
456 return;
457 }
458 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
459 tree.setTopItem(treeItem);
460 }
461 });
462
463 // ensure alignment of top item between tree and time graph
464 fTimeGraphViewer.getVerticalBar().addSelectionListener(new SelectionAdapter() {
465 @Override
466 public void widgetSelected(SelectionEvent e) {
467 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
468 if (treeItems.size() == 0) {
469 return;
470 }
471 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
472 tree.setTopItem(treeItem);
473 }
474 });
475
476 // ensure alignment of top item between tree and time graph
477 fTimeGraphViewer.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
478 @Override
479 public void mouseScrolled(MouseEvent e) {
480 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
481 if (treeItems.size() == 0) {
482 return;
483 }
484 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
485 tree.setTopItem(treeItem);
486 }
487 });
488
489 // ensure the tree has focus control when mouse is over it if the time graph had control
490 fTreeViewer.getControl().addMouseTrackListener(new MouseTrackAdapter() {
491 @Override
492 public void mouseEnter(MouseEvent e) {
493 if (fTimeGraphViewer.getTimeGraphControl().isFocusControl()) {
494 fTreeViewer.getControl().setFocus();
495 }
496 }
497 });
498
499 // ensure the time graph has focus control when mouse is over it if the tree had control
500 fTimeGraphViewer.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
501 @Override
502 public void mouseEnter(MouseEvent e) {
503 if (fTreeViewer.getControl().isFocusControl()) {
504 fTimeGraphViewer.getTimeGraphControl().setFocus();
505 }
506 }
507 });
508 fTimeGraphViewer.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
509 @Override
510 public void mouseEnter(MouseEvent e) {
511 if (fTreeViewer.getControl().isFocusControl()) {
512 fTimeGraphViewer.getTimeGraphControl().setFocus();
513 }
514 }
515 });
516
517 // The filler rows are required to ensure alignment when the tree does not have a
518 // visible horizontal scroll bar. The tree does not allow its top item to be set
519 // to a value that would cause blank space to be drawn at the bottom of the tree.
520 fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree);
521
522 sash.setWeights(new int[] { 1, 1 });
523 }
524
525 // ------------------------------------------------------------------------
526 // Accessors
527 // ------------------------------------------------------------------------
528
529 /**
530 * Returns this time graph combo's tree viewer.
531 *
532 * @return the tree viewer
533 */
534 public TreeViewer getTreeViewer() {
535 return fTreeViewer;
536 }
537
538 /**
539 * Returns this time graph combo's time graph viewer.
540 *
541 * @return the time graph viewer
542 */
543 public TimeGraphViewer getTimeGraphViewer() {
544 return fTimeGraphViewer;
545 }
546
547 // ------------------------------------------------------------------------
548 // Control
549 // ------------------------------------------------------------------------
550
551 /* (non-Javadoc)
552 * @see org.eclipse.swt.widgets.Control#redraw()
553 */
554 @Override
555 public void redraw() {
556 fTimeGraphViewer.getControl().redraw();
557 super.redraw();
558 }
559
560 // ------------------------------------------------------------------------
561 // Operations
562 // ------------------------------------------------------------------------
563
564 /**
565 * Sets the tree content provider used by this time graph combo.
566 *
567 * @param contentProvider the tree content provider
568 */
569 public void setTreeContentProvider(ITreeContentProvider contentProvider) {
570 fTreeViewer.setContentProvider(new TreeContentProviderWrapper(contentProvider));
571 }
572
573 /**
574 * Sets the tree label provider used by this time graph combo.
575 *
576 * @param labelProvider the tree label provider
577 */
578 public void setTreeLabelProvider(ITableLabelProvider labelProvider) {
579 fTreeViewer.setLabelProvider(new TreeLabelProviderWrapper(labelProvider));
580 }
581
582 /**
583 * Sets the tree columns for this time graph combo.
584 *
585 * @param columnNames the tree column names
586 */
587 public void setTreeColumns(String[] columnNames) {
588 final Tree tree = fTreeViewer.getTree();
589 for (String columnName : columnNames) {
590 TreeColumn column = new TreeColumn(tree, SWT.LEFT);
591 column.setText(columnName);
592 column.pack();
593 }
594 }
595
596 /**
597 * Sets the time graph provider used by this time graph combo.
598 *
599 * @param timeGraphProvider the time graph provider
600 */
601 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
602 fTimeGraphViewer.setTimeGraphProvider(timeGraphProvider);
603 }
604
605 /**
606 * Sets or clears the input for this time graph combo.
607 * The input array should only contain top-level elements.
608 *
609 * @param input the input of this time graph combo, or <code>null</code> if none
610 */
611 public void setInput(ITimeGraphEntry[] input) {
612 fInhibitTreeSelection = true;
613 fTreeViewer.setInput(input);
614 for (SelectionListenerWrapper listenerWrapper : fSelectionListenerMap.values()) {
615 listenerWrapper.selection = null;
616 }
617 fInhibitTreeSelection = false;
618 fTreeViewer.expandAll();
619 fTreeViewer.getTree().getVerticalBar().setEnabled(false);
620 fTreeViewer.getTree().getVerticalBar().setVisible(false);
621 fTimeGraphViewer.setItemHeight(getItemHeight(fTreeViewer.getTree()));
622 fTimeGraphViewer.setInput(input);
623 }
624
625 /**
626 * Refreshes this time graph completely with information freshly obtained from its model.
627 */
628 public void refresh() {
629 fInhibitTreeSelection = true;
630 fTreeViewer.refresh();
631 fTimeGraphViewer.refresh();
632 fInhibitTreeSelection = false;
633 }
634
635 /**
636 * Adds a listener for selection changes in this time graph combo.
637 *
638 * @param listener a selection listener
639 */
640 public void addSelectionListener(ITimeGraphSelectionListener listener) {
641 SelectionListenerWrapper listenerWrapper = new SelectionListenerWrapper(listener);
642 fTreeViewer.addSelectionChangedListener(listenerWrapper);
643 fSelectionListenerMap.put(listener, listenerWrapper);
644 fTimeGraphViewer.addSelectionListener(listenerWrapper);
645 }
646
647 /**
648 * Removes the given selection listener from this time graph combo.
649 *
650 * @param listener a selection changed listener
651 */
652 public void removeSelectionListener(ITimeGraphSelectionListener listener) {
653 SelectionListenerWrapper listenerWrapper = fSelectionListenerMap.remove(listener);
654 fTreeViewer.removeSelectionChangedListener(listenerWrapper);
655 fTimeGraphViewer.removeSelectionListener(listenerWrapper);
656 }
657
658 /**
659 * Sets the current selection for this time graph combo.
660 *
661 * @param selection the new selection
662 */
663 public void setSelection(ITimeGraphEntry selection) {
664 fTimeGraphViewer.setSelection(selection);
665 fInhibitTreeSelection = true; // block the tree selection changed listener
666 if (selection != null) {
667 StructuredSelection structuredSelection = new StructuredSelection(selection);
668 fTreeViewer.setSelection(structuredSelection);
669 } else {
670 fTreeViewer.setSelection(new StructuredSelection());
671 }
672 fInhibitTreeSelection = false;
673 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(fTreeViewer.getTree());
674 if (treeItems.size() == 0) {
675 return;
676 }
677 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
678 fTreeViewer.getTree().setTopItem(treeItem);
679 }
680
681 /**
682 * Set the expanded state of an entry
683 *
684 * @param entry
685 * The entry to expand/collapse
686 * @param expanded
687 * True for expanded, false for collapsed
688 *
689 * @since 2.0
690 */
691 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
692 fTimeGraphViewer.setExpandedState(entry, expanded);
693 fTreeViewer.setExpandedState(entry, expanded);
694 }
695
696 /**
697 * Collapses all nodes of the viewer's tree, starting with the root.
698 *
699 * @since 2.0
700 */
701 public void collapseAll() {
702 fTimeGraphViewer.collapseAll();
703 fTreeViewer.collapseAll();
704 }
705
706 /**
707 * Expands all nodes of the viewer's tree, starting with the root.
708 *
709 * @since 2.0
710 */
711 public void expandAll() {
712 fTimeGraphViewer.expandAll();
713 fTreeViewer.expandAll();
714 }
715
716 // ------------------------------------------------------------------------
717 // Internal
718 // ------------------------------------------------------------------------
719
720 private ArrayList<TreeItem> getVisibleExpandedItems(Tree tree) {
721 ArrayList<TreeItem> items = new ArrayList<TreeItem>();
722 for (TreeItem item : tree.getItems()) {
723 if (item.getData() == FILLER) {
724 break;
725 }
726 items.add(item);
727 if (item.getExpanded()) {
728 items.addAll(getVisibleExpandedItems(item));
729 }
730 }
731 return items;
732 }
733
734 private ArrayList<TreeItem> getVisibleExpandedItems(TreeItem treeItem) {
735 ArrayList<TreeItem> items = new ArrayList<TreeItem>();
736 for (TreeItem item : treeItem.getItems()) {
737 items.add(item);
738 if (item.getExpanded()) {
739 items.addAll(getVisibleExpandedItems(item));
740 }
741 }
742 return items;
743 }
744
745 private int getItemHeight(final Tree tree) {
746 /*
747 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
748 */
749 if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
750 if (fLinuxItemHeight != 0) {
751 return fLinuxItemHeight;
752 }
753 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
754 if (treeItems.size() > 1) {
755 final TreeItem treeItem0 = treeItems.get(0);
756 final TreeItem treeItem1 = treeItems.get(1);
757 PaintListener paintListener = new PaintListener() {
758 @Override
759 public void paintControl(PaintEvent e) {
760 tree.removePaintListener(this);
761 int y0 = treeItem0.getBounds().y;
762 int y1 = treeItem1.getBounds().y;
763 int itemHeight = y1 - y0;
764 if (itemHeight > 0) {
765 fLinuxItemHeight = itemHeight;
766 fTimeGraphViewer.setItemHeight(itemHeight);
767 }
768 }
769 };
770 tree.addPaintListener(paintListener);
771 }
772 } else {
773 fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore
774 }
775 return tree.getItemHeight();
776 }
777
778 }
This page took 0.048244 seconds and 6 git commands to generate.