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