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 @Override
276 public void controlResized(ControlEvent e) {
277 fTreeViewer.getTree().getVerticalBar().setEnabled(false);
278 fTreeViewer.getTree().getVerticalBar().setVisible(false);
279 fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
280 }
281 });
282
283 // ensure synchronization of expanded items between tree and time graph
284 fTreeViewer.addTreeListener(new ITreeViewerListener() {
285 @Override
286 public void treeCollapsed(TreeExpansionEvent event) {
287 fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), false);
288 }
289
290 @Override
291 public void treeExpanded(TreeExpansionEvent event) {
292 fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), true);
293 }
294 });
295
296 // ensure synchronization of expanded items between tree and time graph
297 fTimeGraphViewer.addTreeListener(new ITimeGraphTreeListener() {
298 @Override
299 public void treeCollapsed(TimeGraphTreeExpansionEvent event) {
300 fTreeViewer.setExpandedState(event.getEntry(), false);
301 }
302
303 @Override
304 public void treeExpanded(TimeGraphTreeExpansionEvent event) {
305 fTreeViewer.setExpandedState(event.getEntry(), true);
306 }
307 });
308
309 // prevent mouse button from selecting a filler tree item
310 tree.addListener(SWT.MouseDown, new Listener() {
311 @Override
312 public void handleEvent(Event event) {
313 TreeItem treeItem = tree.getItem(new Point(event.x, event.y));
314 if (treeItem == null || treeItem.getData() == FILLER) {
315 event.doit = false;
316 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
317 if (treeItems.size() == 0) {
318 fTreeViewer.setSelection(new StructuredSelection());
319 fTimeGraphViewer.setSelection(null);
320 return;
321 }
322 // this prevents from scrolling up when selecting
323 // the partially visible tree item at the bottom
324 tree.select(treeItems.get(treeItems.size() - 1));
325 fTreeViewer.setSelection(new StructuredSelection());
326 fTimeGraphViewer.setSelection(null);
327 }
328 }
329 });
330
331 // prevent mouse wheel from scrolling down into filler tree items
332 tree.addListener(SWT.MouseWheel, new Listener() {
333 @Override
334 public void handleEvent(Event event) {
335 event.doit = false;
336 Slider scrollBar = fTimeGraphViewer.getVerticalBar();
337 fTimeGraphViewer.setTopIndex(scrollBar.getSelection() - event.count);
338 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
339 if (treeItems.size() == 0) {
340 return;
341 }
342 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
343 tree.setTopItem(treeItem);
344 }
345 });
346
347 // prevent key stroke from selecting a filler tree item
348 tree.addListener(SWT.KeyDown, new Listener() {
349 @Override
350 public void handleEvent(Event event) {
351 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
352 if (treeItems.size() == 0) {
353 fTreeViewer.setSelection(new StructuredSelection());
354 event.doit = false;
355 return;
356 }
357 if (event.keyCode == SWT.ARROW_DOWN) {
358 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + 1, treeItems.size() - 1);
359 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
360 event.doit = false;
361 } else if (event.keyCode == SWT.PAGE_DOWN) {
362 int height = tree.getSize().y - tree.getHeaderHeight() - tree.getHorizontalBar().getSize().y;
363 int countPerPage = height / getItemHeight(tree);
364 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + countPerPage - 1, treeItems.size() - 1);
365 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
366 event.doit = false;
367 } else if (event.keyCode == SWT.END) {
368 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(treeItems.size() - 1).getData());
369 event.doit = false;
370 }
371 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
372 tree.setTopItem(treeItem);
373 if (fTimeGraphViewer.getSelectionIndex() >= 0) {
374 fTreeViewer.setSelection(new StructuredSelection(fTimeGraphViewer.getSelection()));
375 } else {
376 fTreeViewer.setSelection(new StructuredSelection());
377 }
378 }
379 });
380
381 // ensure alignment of top item between tree and time graph
382 fTimeGraphViewer.getTimeGraphControl().addControlListener(new ControlAdapter() {
383 @Override
384 public void controlResized(ControlEvent e) {
385 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
386 if (treeItems.size() == 0) {
387 return;
388 }
389 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
390 tree.setTopItem(treeItem);
391 }
392 });
393
394 // ensure synchronization of selected item between tree and time graph
395 fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
396 @Override
397 public void selectionChanged(SelectionChangedEvent event) {
398 if (fInhibitTreeSelection) {
399 return;
400 }
401 if (event.getSelection() instanceof IStructuredSelection) {
402 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
403 if (selection instanceof ITimeGraphEntry) {
404 fTimeGraphViewer.setSelection((ITimeGraphEntry) selection);
405 }
406 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
407 if (treeItems.size() == 0) {
408 return;
409 }
410 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
411 tree.setTopItem(treeItem);
412 }
413 }
414 });
415
416 // ensure synchronization of selected item between tree and time graph
417 fTimeGraphViewer.addSelectionListener(new ITimeGraphSelectionListener() {
418 @Override
419 public void selectionChanged(TimeGraphSelectionEvent event) {
420 ITimeGraphEntry entry = fTimeGraphViewer.getSelection();
421 fInhibitTreeSelection = true; // block the tree selection changed listener
422 if (entry != null) {
423 StructuredSelection selection = new StructuredSelection(entry);
424 fTreeViewer.setSelection(selection);
425 } else {
426 fTreeViewer.setSelection(new StructuredSelection());
427 }
428 fInhibitTreeSelection = false;
429 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
430 if (treeItems.size() == 0) {
431 return;
432 }
433 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
434 tree.setTopItem(treeItem);
435 }
436 });
437
438 // ensure alignment of top item between tree and time graph
439 fTimeGraphViewer.getVerticalBar().addSelectionListener(new SelectionAdapter() {
440 @Override
441 public void widgetSelected(SelectionEvent e) {
442 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
443 if (treeItems.size() == 0) {
444 return;
445 }
446 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
447 tree.setTopItem(treeItem);
448 }
449 });
450
451 // ensure alignment of top item between tree and time graph
452 fTimeGraphViewer.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
453 @Override
454 public void mouseScrolled(MouseEvent e) {
455 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
456 if (treeItems.size() == 0) {
457 return;
458 }
459 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
460 tree.setTopItem(treeItem);
461 }
462 });
463
464 // ensure the tree has focus control when mouse is over it if the time graph had control
465 fTreeViewer.getControl().addMouseTrackListener(new MouseTrackAdapter() {
466 @Override
467 public void mouseEnter(MouseEvent e) {
468 if (fTimeGraphViewer.getTimeGraphControl().isFocusControl()) {
469 fTreeViewer.getControl().setFocus();
470 }
471 }
472 });
473
474 // ensure the time graph has focus control when mouse is over it if the tree had control
475 fTimeGraphViewer.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
476 @Override
477 public void mouseEnter(MouseEvent e) {
478 if (fTreeViewer.getControl().isFocusControl()) {
479 fTimeGraphViewer.getTimeGraphControl().setFocus();
480 }
481 }
482 });
483 fTimeGraphViewer.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
484 @Override
485 public void mouseEnter(MouseEvent e) {
486 if (fTreeViewer.getControl().isFocusControl()) {
487 fTimeGraphViewer.getTimeGraphControl().setFocus();
488 }
489 }
490 });
491
492 // The filler rows are required to ensure alignment when the tree does not have a
493 // visible horizontal scroll bar. The tree does not allow its top item to be set
494 // to a value that would cause blank space to be drawn at the bottom of the tree.
495 fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree);
496
497 sash.setWeights(new int[] { 1, 1 });
498 }
499
500 // ------------------------------------------------------------------------
501 // Accessors
502 // ------------------------------------------------------------------------
503
504 /**
505 * Returns this time graph combo's tree viewer.
506 *
507 * @return the tree viewer
508 */
509 public TreeViewer getTreeViewer() {
510 return fTreeViewer;
511 }
512
513 /**
514 * Returns this time graph combo's time graph viewer.
515 *
516 * @return the time graph viewer
517 */
518 public TimeGraphViewer getTimeGraphViewer() {
519 return fTimeGraphViewer;
520 }
521
522 // ------------------------------------------------------------------------
523 // Control
524 // ------------------------------------------------------------------------
525
526 /* (non-Javadoc)
527 * @see org.eclipse.swt.widgets.Control#redraw()
528 */
529 @Override
530 public void redraw() {
531 fTimeGraphViewer.getControl().redraw();
532 super.redraw();
533 }
534
535 // ------------------------------------------------------------------------
536 // Operations
537 // ------------------------------------------------------------------------
538
539 /**
540 * Sets the tree content provider used by this time graph combo.
541 *
542 * @param contentProvider the tree content provider
543 */
544 public void setTreeContentProvider(ITreeContentProvider contentProvider) {
545 fTreeViewer.setContentProvider(new TreeContentProviderWrapper(contentProvider));
546 }
547
548 /**
549 * Sets the tree label provider used by this time graph combo.
550 *
551 * @param treeLabelProvider the tree label provider
552 */
553 public void setTreeLabelProvider(ITableLabelProvider labelProvider) {
554 fTreeViewer.setLabelProvider(new TreeLabelProviderWrapper(labelProvider));
555 }
556
557 /**
558 * Sets the tree columns for this time graph combo.
559 *
560 * @param columnNames the tree column names
561 */
562 public void setTreeColumns(String[] columnNames) {
563 final Tree tree = fTreeViewer.getTree();
564 for (String columnName : columnNames) {
565 TreeColumn column = new TreeColumn(tree, SWT.LEFT);
566 column.setText(columnName);
567 column.pack();
568 }
569 }
570
571
572 /**
573 * Sets the time graph provider used by this time graph combo.
574 *
575 * @param timeGraphProvider the time graph provider
576 */
577 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
578 fTimeGraphViewer.setTimeGraphProvider(timeGraphProvider);
579 }
580
581 /**
582 * Sets or clears the input for this time graph combo.
583 * The input array should only contain top-level elements.
584 *
585 * @param input the input of this time graph combo, or <code>null</code> if none
586 */
587 public void setInput(ITimeGraphEntry[] input) {
588 fInhibitTreeSelection = true;
589 fTreeViewer.setInput(input);
590 fInhibitTreeSelection = false;
591 fTreeViewer.expandAll();
592 fTreeViewer.getTree().getVerticalBar().setEnabled(false);
593 fTreeViewer.getTree().getVerticalBar().setVisible(false);
594 fTimeGraphViewer.setItemHeight(getItemHeight(fTreeViewer.getTree()));
595 fTimeGraphViewer.setInput(input);
596 }
597
598 /**
599 * Refreshes this time graph completely with information freshly obtained from its model.
600 */
601 public void refresh() {
602 fTreeViewer.refresh();
603 fTimeGraphViewer.refresh();
604 }
605
606 /**
607 * Adds a listener for selection changes in this time graph combo.
608 *
609 * @param listener a selection listener
610 */
611 public void addSelectionListener(ITimeGraphSelectionListener listener) {
612 SelectionListenerWrapper listenerWrapper = new SelectionListenerWrapper(listener);
613 fTreeViewer.addSelectionChangedListener(listenerWrapper);
614 fSelectionListenerMap.put(listener, listenerWrapper);
615 fTimeGraphViewer.addSelectionListener(listenerWrapper);
616 }
617
618 /**
619 * Removes the given selection listener from this time graph combo.
620 *
621 * @param listener a selection changed listener
622 */
623 public void removeSelectionListener(ITimeGraphSelectionListener listener) {
624 SelectionListenerWrapper listenerWrapper = fSelectionListenerMap.remove(listener);
625 fTreeViewer.removeSelectionChangedListener(listenerWrapper);
626 fTimeGraphViewer.removeSelectionListener(listenerWrapper);
627 }
628
629 /**
630 * Sets the current selection for this time graph combo.
631 *
632 * @param selection the new selection
633 */
634 public void setSelection(ITimeGraphEntry selection) {
635 fTimeGraphViewer.setSelection(selection);
636 fInhibitTreeSelection = true; // block the tree selection changed listener
637 if (selection != null) {
638 StructuredSelection structuredSelection = new StructuredSelection(selection);
639 fTreeViewer.setSelection(structuredSelection);
640 } else {
641 fTreeViewer.setSelection(new StructuredSelection());
642 }
643 fInhibitTreeSelection = false;
644 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(fTreeViewer.getTree());
645 if (treeItems.size() == 0) {
646 return;
647 }
648 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
649 fTreeViewer.getTree().setTopItem(treeItem);
650 }
651
652 // ------------------------------------------------------------------------
653 // Internal
654 // ------------------------------------------------------------------------
655
656 private ArrayList<TreeItem> getVisibleExpandedItems(Tree tree) {
657 ArrayList<TreeItem> items = new ArrayList<TreeItem>();
658 for (TreeItem item : tree.getItems()) {
659 if (item.getData() == FILLER) {
660 break;
661 }
662 items.add(item);
663 if (item.getExpanded()) {
664 items.addAll(getVisibleExpandedItems(item));
665 }
666 }
667 return items;
668 }
669
670 private ArrayList<TreeItem> getVisibleExpandedItems(TreeItem treeItem) {
671 ArrayList<TreeItem> items = new ArrayList<TreeItem>();
672 for (TreeItem item : treeItem.getItems()) {
673 items.add(item);
674 if (item.getExpanded()) {
675 items.addAll(getVisibleExpandedItems(item));
676 }
677 }
678 return items;
679 }
680
681 private int getItemHeight(final Tree tree) {
682 /*
683 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
684 */
685 if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
686 if (fLinuxItemHeight != 0) {
687 return fLinuxItemHeight;
688 }
689 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
690 if (treeItems.size() > 1) {
691 final TreeItem treeItem0 = treeItems.get(0);
692 final TreeItem treeItem1 = treeItems.get(1);
693 PaintListener paintListener = new PaintListener() {
694 @Override
695 public void paintControl(PaintEvent e) {
696 tree.removePaintListener(this);
697 int y0 = treeItem0.getBounds().y;
698 int y1 = treeItem1.getBounds().y;
699 int itemHeight = y1 - y0;
700 if (itemHeight > 0) {
701 fLinuxItemHeight = itemHeight;
702 fTimeGraphViewer.setItemHeight(itemHeight);
703 }
704 }
705 };
706 tree.addPaintListener(paintListener);
707 }
708 } else {
709 fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore
710 }
711 return tree.getItemHeight();
712 }
713
714 }
This page took 0.046722 seconds and 6 git commands to generate.