lttng: Add clear() call before add elements to list
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / widgets / timegraph / TimeGraphCombo.java
CommitLineData
837a2f8c 1/*******************************************************************************
c8422608 2 * Copyright (c) 2012, 2013 Ericsson
837a2f8c
PT
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
13package org.eclipse.linuxtools.tmf.ui.widgets.timegraph;
14
15import java.util.ArrayList;
16import java.util.Arrays;
17import java.util.HashMap;
6ac5a950
AM
18import java.util.List;
19import java.util.Map;
837a2f8c 20
6ac5a950 21import org.eclipse.jface.action.Action;
837a2f8c
PT
22import org.eclipse.jface.viewers.ILabelProviderListener;
23import org.eclipse.jface.viewers.ISelectionChangedListener;
24import org.eclipse.jface.viewers.IStructuredSelection;
25import org.eclipse.jface.viewers.ITableLabelProvider;
26import org.eclipse.jface.viewers.ITreeContentProvider;
27import org.eclipse.jface.viewers.ITreeViewerListener;
28import org.eclipse.jface.viewers.SelectionChangedEvent;
29import org.eclipse.jface.viewers.StructuredSelection;
30import org.eclipse.jface.viewers.TreeExpansionEvent;
31import org.eclipse.jface.viewers.TreeViewer;
32import org.eclipse.jface.viewers.Viewer;
6ac5a950
AM
33import org.eclipse.jface.viewers.ViewerFilter;
34import org.eclipse.linuxtools.internal.tmf.ui.Activator;
35import org.eclipse.linuxtools.internal.tmf.ui.ITmfImageConstants;
36import org.eclipse.linuxtools.internal.tmf.ui.Messages;
37import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.dialogs.TimeGraphFilterDialog;
837a2f8c
PT
38import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
39import org.eclipse.swt.SWT;
40import org.eclipse.swt.custom.SashForm;
41import org.eclipse.swt.events.ControlAdapter;
42import org.eclipse.swt.events.ControlEvent;
43import org.eclipse.swt.events.MouseEvent;
44import org.eclipse.swt.events.MouseTrackAdapter;
45import org.eclipse.swt.events.MouseWheelListener;
46import org.eclipse.swt.events.PaintEvent;
47import org.eclipse.swt.events.PaintListener;
48import org.eclipse.swt.events.SelectionAdapter;
49import org.eclipse.swt.events.SelectionEvent;
50import org.eclipse.swt.graphics.Image;
51import org.eclipse.swt.graphics.Point;
52import org.eclipse.swt.layout.FillLayout;
53import org.eclipse.swt.widgets.Composite;
54import org.eclipse.swt.widgets.Display;
55import org.eclipse.swt.widgets.Event;
56import org.eclipse.swt.widgets.Listener;
57import org.eclipse.swt.widgets.Slider;
58import org.eclipse.swt.widgets.Tree;
59import org.eclipse.swt.widgets.TreeColumn;
60import org.eclipse.swt.widgets.TreeItem;
61
62/**
63 * Time graph "combo" view (with the list/tree on the left and the gantt chart
64 * on the right)
65 *
66 * @version 1.0
67 * @author Patrick Tasse
68 */
69public class TimeGraphCombo extends Composite {
70
71 // ------------------------------------------------------------------------
72 // Constants
73 // ------------------------------------------------------------------------
74
75 private static final Object FILLER = new Object();
76
77 // ------------------------------------------------------------------------
78 // Fields
79 // ------------------------------------------------------------------------
80
81 // The tree viewer
82 private TreeViewer fTreeViewer;
83
84 // The time viewer
85 private TimeGraphViewer fTimeGraphViewer;
86
6ac5a950
AM
87 // The top-level input (children excluded)
88 private List<? extends ITimeGraphEntry> fTopInput;
89
90 // All the inputs (children included)
91 private List<? extends ITimeGraphEntry> fAllInput;
92
837a2f8c
PT
93 // The selection listener map
94 private final HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper> fSelectionListenerMap = new HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper>();
95
6ac5a950
AM
96 // The map of viewer filters
97 private final Map<ViewerFilter, ViewerFilter> fViewerFilterMap = new HashMap<ViewerFilter, ViewerFilter>();
98
837a2f8c
PT
99 // Flag to block the tree selection changed listener when triggered by the time graph combo
100 private boolean fInhibitTreeSelection = false;
101
102 // Number of filler rows used by the tree content provider
103 private int fNumFillerRows;
104
105 // Calculated item height for Linux workaround
106 private int fLinuxItemHeight = 0;
107
6ac5a950
AM
108 // The button that opens the filter dialog
109 private Action showFilterAction;
110
111 // The filter dialog
112 private TimeGraphFilterDialog fFilterDialog;
113
114 // The filter generated from the filter dialog
115 private RawViewerFilter fFilter;
116
837a2f8c
PT
117 // ------------------------------------------------------------------------
118 // Classes
119 // ------------------------------------------------------------------------
120
121 /**
122 * The TreeContentProviderWrapper is used to insert filler items after
123 * the elements of the tree's real content provider.
124 */
125 private class TreeContentProviderWrapper implements ITreeContentProvider {
126 private final ITreeContentProvider contentProvider;
127
128 public TreeContentProviderWrapper(ITreeContentProvider contentProvider) {
129 this.contentProvider = contentProvider;
130 }
131
132 @Override
133 public void dispose() {
134 contentProvider.dispose();
135 }
136
137 @Override
138 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
139 contentProvider.inputChanged(viewer, oldInput, newInput);
140 }
141
142 @Override
143 public Object[] getElements(Object inputElement) {
144 Object[] elements = contentProvider.getElements(inputElement);
145 // add filler elements to ensure alignment with time analysis viewer
146 Object[] oElements = Arrays.copyOf(elements, elements.length + fNumFillerRows, new Object[0].getClass());
147 for (int i = 0; i < fNumFillerRows; i++) {
148 oElements[elements.length + i] = FILLER;
149 }
150 return oElements;
151 }
152
153 @Override
154 public Object[] getChildren(Object parentElement) {
155 if (parentElement instanceof ITimeGraphEntry) {
156 return contentProvider.getChildren(parentElement);
157 }
158 return new Object[0];
159 }
160
161 @Override
162 public Object getParent(Object element) {
163 if (element instanceof ITimeGraphEntry) {
164 return contentProvider.getParent(element);
165 }
166 return null;
167 }
168
169 @Override
170 public boolean hasChildren(Object element) {
171 if (element instanceof ITimeGraphEntry) {
172 return contentProvider.hasChildren(element);
173 }
174 return false;
175 }
176 }
177
178 /**
179 * The TreeLabelProviderWrapper is used to intercept the filler items
180 * from the calls to the tree's real label provider.
181 */
182 private class TreeLabelProviderWrapper implements ITableLabelProvider {
183 private final ITableLabelProvider labelProvider;
184
185 public TreeLabelProviderWrapper(ITableLabelProvider labelProvider) {
186 this.labelProvider = labelProvider;
187 }
188
189 @Override
190 public void addListener(ILabelProviderListener listener) {
191 labelProvider.addListener(listener);
192 }
193
194 @Override
195 public void dispose() {
196 labelProvider.dispose();
197 }
198
199 @Override
200 public boolean isLabelProperty(Object element, String property) {
201 if (element instanceof ITimeGraphEntry) {
202 return labelProvider.isLabelProperty(element, property);
203 }
204 return false;
205 }
206
207 @Override
208 public void removeListener(ILabelProviderListener listener) {
209 labelProvider.removeListener(listener);
210 }
211
212 @Override
213 public Image getColumnImage(Object element, int columnIndex) {
214 if (element instanceof ITimeGraphEntry) {
215 return labelProvider.getColumnImage(element, columnIndex);
216 }
217 return null;
218 }
219
220 @Override
221 public String getColumnText(Object element, int columnIndex) {
222 if (element instanceof ITimeGraphEntry) {
223 return labelProvider.getColumnText(element, columnIndex);
224 }
225 return null;
226 }
227
228 }
229
230 /**
231 * The SelectionListenerWrapper is used to intercept the filler items from
232 * the time graph combo's real selection listener, and to prevent double
233 * notifications from being sent when selection changes in both tree and
234 * time graph at the same time.
235 */
236 private class SelectionListenerWrapper implements ISelectionChangedListener, ITimeGraphSelectionListener {
237 private final ITimeGraphSelectionListener listener;
238 private ITimeGraphEntry selection = null;
239
240 public SelectionListenerWrapper(ITimeGraphSelectionListener listener) {
241 this.listener = listener;
242 }
243
244 @Override
245 public void selectionChanged(SelectionChangedEvent event) {
246 if (fInhibitTreeSelection) {
247 return;
248 }
249 Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
250 if (element instanceof ITimeGraphEntry) {
251 ITimeGraphEntry entry = (ITimeGraphEntry) element;
252 if (entry != selection) {
253 selection = entry;
254 listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
255 }
256 }
257 }
258
259 @Override
260 public void selectionChanged(TimeGraphSelectionEvent event) {
261 ITimeGraphEntry entry = event.getSelection();
262 if (entry != selection) {
263 selection = entry;
264 listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
265 }
266 }
267 }
268
6ac5a950
AM
269 /**
270 * The ViewerFilterWrapper is used to intercept the filler items from
271 * the time graph combo's real ViewerFilters. These filler items should
272 * always be visible.
273 */
274 private class ViewerFilterWrapper extends ViewerFilter {
275
276 ViewerFilter fWrappedFilter;
277
278 ViewerFilterWrapper(ViewerFilter filter) {
279 super();
280 this.fWrappedFilter = filter;
281 }
282
283 @Override
284 public boolean select(Viewer viewer, Object parentElement, Object element) {
285 if (element instanceof ITimeGraphEntry) {
286 return fWrappedFilter.select(viewer, parentElement, element);
287 }
288 return true;
289 }
290
291 }
292
293 /**
294 * This filter simply keeps a list of elements that should be shown
295 * All the other elements will be filtered
296 */
297 private class RawViewerFilter extends ViewerFilter {
298
299 private List<Object> fNonFiltered = new ArrayList<Object>();
300
301 public void setNonFiltered(List<Object> objects) {
302 fNonFiltered = objects;
303 }
304
305 public List<Object> getNonFiltered() {
306 return fNonFiltered;
307 }
308
309 @Override
310 public boolean select(Viewer viewer, Object parentElement, Object element) {
311 return fNonFiltered.contains(element);
312 }
313 }
314
837a2f8c
PT
315 // ------------------------------------------------------------------------
316 // Constructors
317 // ------------------------------------------------------------------------
318
319 /**
320 * Constructs a new instance of this class given its parent
321 * and a style value describing its behavior and appearance.
322 *
323 * @param parent a widget which will be the parent of the new instance (cannot be null)
324 * @param style the style of widget to construct
325 */
326 public TimeGraphCombo(Composite parent, int style) {
327 super(parent, style);
328 setLayout(new FillLayout());
329
330 final SashForm sash = new SashForm(this, SWT.NONE);
331
332 fTreeViewer = new TreeViewer(sash, SWT.FULL_SELECTION | SWT.H_SCROLL);
333 final Tree tree = fTreeViewer.getTree();
334 tree.setHeaderVisible(true);
335 tree.setLinesVisible(true);
336
337 fTimeGraphViewer = new TimeGraphViewer(sash, SWT.NONE);
338 fTimeGraphViewer.setItemHeight(getItemHeight(tree));
339 fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
340 fTimeGraphViewer.setBorderWidth(tree.getBorderWidth());
341 fTimeGraphViewer.setNameWidthPref(0);
342
6ac5a950
AM
343 fFilter = new RawViewerFilter();
344 addFilter(fFilter);
345
346 fFilterDialog = new TimeGraphFilterDialog(getShell());
347
837a2f8c
PT
348 // Feature in Windows. The tree vertical bar reappears when
349 // the control is resized so we need to hide it again.
350 // Bug in Linux. The tree header height is 0 in constructor,
351 // so we need to reset it later when the control is resized.
352 tree.addControlListener(new ControlAdapter() {
353 int depth = 0;
354 @Override
355 public void controlResized(ControlEvent e) {
356 if (depth == 0) {
357 depth++;
358 tree.getVerticalBar().setEnabled(false);
359 // this can trigger controlResized recursively
360 tree.getVerticalBar().setVisible(false);
361 depth--;
362 }
363 fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
364 }
365 });
366
367 // ensure synchronization of expanded items between tree and time graph
368 fTreeViewer.addTreeListener(new ITreeViewerListener() {
369 @Override
370 public void treeCollapsed(TreeExpansionEvent event) {
371 fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), false);
372 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
373 if (treeItems.size() == 0) {
374 return;
375 }
376 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
377 tree.setTopItem(treeItem);
378 }
379
380 @Override
381 public void treeExpanded(TreeExpansionEvent event) {
382 fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), true);
383 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
384 if (treeItems.size() == 0) {
385 return;
386 }
387 final TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
388 // queue the top item update because the tree can change its top item
389 // autonomously immediately after the listeners have been notified
390 getDisplay().asyncExec(new Runnable() {
391 @Override
392 public void run() {
393 tree.setTopItem(treeItem);
394 }});
395 }
396 });
397
398 // ensure synchronization of expanded items between tree and time graph
399 fTimeGraphViewer.addTreeListener(new ITimeGraphTreeListener() {
400 @Override
401 public void treeCollapsed(TimeGraphTreeExpansionEvent event) {
402 fTreeViewer.setExpandedState(event.getEntry(), false);
403 }
404
405 @Override
406 public void treeExpanded(TimeGraphTreeExpansionEvent event) {
407 fTreeViewer.setExpandedState(event.getEntry(), true);
408 }
409 });
410
411 // prevent mouse button from selecting a filler tree item
412 tree.addListener(SWT.MouseDown, new Listener() {
413 @Override
414 public void handleEvent(Event event) {
415 TreeItem treeItem = tree.getItem(new Point(event.x, event.y));
416 if (treeItem == null || treeItem.getData() == FILLER) {
417 event.doit = false;
418 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
419 if (treeItems.size() == 0) {
420 fTreeViewer.setSelection(new StructuredSelection());
421 fTimeGraphViewer.setSelection(null);
422 return;
423 }
424 // this prevents from scrolling up when selecting
425 // the partially visible tree item at the bottom
426 tree.select(treeItems.get(treeItems.size() - 1));
427 fTreeViewer.setSelection(new StructuredSelection());
428 fTimeGraphViewer.setSelection(null);
429 }
430 }
431 });
432
433 // prevent mouse wheel from scrolling down into filler tree items
434 tree.addListener(SWT.MouseWheel, new Listener() {
435 @Override
436 public void handleEvent(Event event) {
437 event.doit = false;
438 Slider scrollBar = fTimeGraphViewer.getVerticalBar();
439 fTimeGraphViewer.setTopIndex(scrollBar.getSelection() - event.count);
440 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
441 if (treeItems.size() == 0) {
442 return;
443 }
444 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
445 tree.setTopItem(treeItem);
446 }
447 });
448
449 // prevent key stroke from selecting a filler tree item
450 tree.addListener(SWT.KeyDown, new Listener() {
451 @Override
452 public void handleEvent(Event event) {
453 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
454 if (treeItems.size() == 0) {
455 fTreeViewer.setSelection(new StructuredSelection());
456 event.doit = false;
457 return;
458 }
459 if (event.keyCode == SWT.ARROW_DOWN) {
460 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + 1, treeItems.size() - 1);
461 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
462 event.doit = false;
463 } else if (event.keyCode == SWT.PAGE_DOWN) {
464 int height = tree.getSize().y - tree.getHeaderHeight() - tree.getHorizontalBar().getSize().y;
465 int countPerPage = height / getItemHeight(tree);
466 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + countPerPage - 1, treeItems.size() - 1);
467 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
468 event.doit = false;
469 } else if (event.keyCode == SWT.END) {
470 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(treeItems.size() - 1).getData());
471 event.doit = false;
472 }
473 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
474 tree.setTopItem(treeItem);
475 if (fTimeGraphViewer.getSelectionIndex() >= 0) {
476 fTreeViewer.setSelection(new StructuredSelection(fTimeGraphViewer.getSelection()));
477 } else {
478 fTreeViewer.setSelection(new StructuredSelection());
479 }
480 }
481 });
482
483 // ensure alignment of top item between tree and time graph
484 fTimeGraphViewer.getTimeGraphControl().addControlListener(new ControlAdapter() {
485 @Override
486 public void controlResized(ControlEvent e) {
487 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
488 if (treeItems.size() == 0) {
489 return;
490 }
491 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
492 tree.setTopItem(treeItem);
493 }
494 });
495
496 // ensure synchronization of selected item between tree and time graph
497 fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
498 @Override
499 public void selectionChanged(SelectionChangedEvent event) {
500 if (fInhibitTreeSelection) {
501 return;
502 }
503 if (event.getSelection() instanceof IStructuredSelection) {
504 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
505 if (selection instanceof ITimeGraphEntry) {
506 fTimeGraphViewer.setSelection((ITimeGraphEntry) selection);
507 }
508 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
509 if (treeItems.size() == 0) {
510 return;
511 }
512 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
513 tree.setTopItem(treeItem);
514 }
515 }
516 });
517
518 // ensure synchronization of selected item between tree and time graph
519 fTimeGraphViewer.addSelectionListener(new ITimeGraphSelectionListener() {
520 @Override
521 public void selectionChanged(TimeGraphSelectionEvent event) {
522 ITimeGraphEntry entry = fTimeGraphViewer.getSelection();
523 fInhibitTreeSelection = true; // block the tree selection changed listener
524 if (entry != null) {
525 StructuredSelection selection = new StructuredSelection(entry);
526 fTreeViewer.setSelection(selection);
527 } else {
528 fTreeViewer.setSelection(new StructuredSelection());
529 }
530 fInhibitTreeSelection = false;
531 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
532 if (treeItems.size() == 0) {
533 return;
534 }
535 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
536 tree.setTopItem(treeItem);
537 }
538 });
539
540 // ensure alignment of top item between tree and time graph
541 fTimeGraphViewer.getVerticalBar().addSelectionListener(new SelectionAdapter() {
542 @Override
543 public void widgetSelected(SelectionEvent e) {
544 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
545 if (treeItems.size() == 0) {
546 return;
547 }
548 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
549 tree.setTopItem(treeItem);
550 }
551 });
552
553 // ensure alignment of top item between tree and time graph
554 fTimeGraphViewer.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
555 @Override
556 public void mouseScrolled(MouseEvent e) {
557 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
558 if (treeItems.size() == 0) {
559 return;
560 }
561 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
562 tree.setTopItem(treeItem);
563 }
564 });
565
566 // ensure the tree has focus control when mouse is over it if the time graph had control
567 fTreeViewer.getControl().addMouseTrackListener(new MouseTrackAdapter() {
568 @Override
569 public void mouseEnter(MouseEvent e) {
570 if (fTimeGraphViewer.getTimeGraphControl().isFocusControl()) {
571 fTreeViewer.getControl().setFocus();
572 }
573 }
574 });
575
576 // ensure the time graph has focus control when mouse is over it if the tree had control
577 fTimeGraphViewer.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
578 @Override
579 public void mouseEnter(MouseEvent e) {
580 if (fTreeViewer.getControl().isFocusControl()) {
581 fTimeGraphViewer.getTimeGraphControl().setFocus();
582 }
583 }
584 });
585 fTimeGraphViewer.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
586 @Override
587 public void mouseEnter(MouseEvent e) {
588 if (fTreeViewer.getControl().isFocusControl()) {
589 fTimeGraphViewer.getTimeGraphControl().setFocus();
590 }
591 }
592 });
593
594 // The filler rows are required to ensure alignment when the tree does not have a
595 // visible horizontal scroll bar. The tree does not allow its top item to be set
596 // to a value that would cause blank space to be drawn at the bottom of the tree.
597 fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree);
598
599 sash.setWeights(new int[] { 1, 1 });
600 }
601
602 // ------------------------------------------------------------------------
603 // Accessors
604 // ------------------------------------------------------------------------
605
606 /**
607 * Returns this time graph combo's tree viewer.
608 *
609 * @return the tree viewer
610 */
611 public TreeViewer getTreeViewer() {
612 return fTreeViewer;
613 }
614
615 /**
616 * Returns this time graph combo's time graph viewer.
617 *
618 * @return the time graph viewer
619 */
620 public TimeGraphViewer getTimeGraphViewer() {
621 return fTimeGraphViewer;
622 }
623
6ac5a950
AM
624 /**
625 * Callback for the show filter action
626 *
627 * @since 2.0
628 */
629 public void showFilterDialog() {
630 if(fTopInput != null) {
631 fFilterDialog.setInput(fTopInput.toArray(new ITimeGraphEntry[0]));
632 fFilterDialog.setTitle(Messages.TmfTimeFilterDialog_WINDOW_TITLE);
633 fFilterDialog.setMessage(Messages.TmfTimeFilterDialog_MESSAGE);
634 fFilterDialog.setInitialElementSelections(fFilter.getNonFiltered());
635 fFilterDialog.setExpandedElements(fAllInput.toArray());
636 fFilterDialog.create();
637 fFilterDialog.open();
638 // Process selected elements
639 if (fFilterDialog.getResult() != null) {
640 fInhibitTreeSelection = true;
641 fFilter.setNonFiltered(new ArrayList<Object>(Arrays.asList(fFilterDialog.getResult())));
642 fTreeViewer.refresh();
643 fTreeViewer.expandAll();
644 fTimeGraphViewer.refresh();
645 fInhibitTreeSelection = false;
646 // Reset selection to first entry
647 if (fFilterDialog.getResult().length > 0) {
648 setSelection((ITimeGraphEntry) fFilterDialog.getResult()[0]);
649 }
650 }
651 }
652 }
653
654 /**
655 * Get the show filter action.
656 *
657 * @return The Action object
658 * @since 2.0
659 */
660 public Action getShowFilterAction() {
661 if (showFilterAction == null) {
662 // showFilter
663 showFilterAction = new Action() {
664 @Override
665 public void run() {
666 showFilterDialog();
667 }
668 };
669 showFilterAction.setText(Messages.TmfTimeGraphCombo_FilterActionNameText);
670 showFilterAction.setToolTipText(Messages.TmfTimeGraphCombo_FilterActionToolTipText);
671 // TODO find a nice, distinctive icon
672 showFilterAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FILTERS));
673 }
674
675 return showFilterAction;
676 }
677
837a2f8c
PT
678 // ------------------------------------------------------------------------
679 // Control
680 // ------------------------------------------------------------------------
681
682 /* (non-Javadoc)
683 * @see org.eclipse.swt.widgets.Control#redraw()
684 */
685 @Override
686 public void redraw() {
687 fTimeGraphViewer.getControl().redraw();
688 super.redraw();
689 }
690
691 // ------------------------------------------------------------------------
692 // Operations
693 // ------------------------------------------------------------------------
694
695 /**
696 * Sets the tree content provider used by this time graph combo.
697 *
698 * @param contentProvider the tree content provider
699 */
700 public void setTreeContentProvider(ITreeContentProvider contentProvider) {
701 fTreeViewer.setContentProvider(new TreeContentProviderWrapper(contentProvider));
702 }
703
704 /**
705 * Sets the tree label provider used by this time graph combo.
706 *
707 * @param labelProvider the tree label provider
708 */
709 public void setTreeLabelProvider(ITableLabelProvider labelProvider) {
710 fTreeViewer.setLabelProvider(new TreeLabelProviderWrapper(labelProvider));
711 }
712
6ac5a950
AM
713 /**
714 * Sets the tree content provider used by the filter dialog
715 *
716 * @param contentProvider the tree content provider
717 * @since 2.0
718 */
719 public void setFilterContentProvider(ITreeContentProvider contentProvider) {
720 fFilterDialog.setContentProvider(contentProvider);
721 }
722
723 /**
724 * Sets the tree label provider used by the filter dialog
725 *
726 * @param labelProvider the tree label provider
727 * @since 2.0
728 */
729 public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
730 fFilterDialog.setLabelProvider(labelProvider);
731 }
732
837a2f8c
PT
733 /**
734 * Sets the tree columns for this time graph combo.
735 *
736 * @param columnNames the tree column names
737 */
738 public void setTreeColumns(String[] columnNames) {
739 final Tree tree = fTreeViewer.getTree();
740 for (String columnName : columnNames) {
741 TreeColumn column = new TreeColumn(tree, SWT.LEFT);
742 column.setText(columnName);
743 column.pack();
744 }
745 }
746
6ac5a950
AM
747 /**
748 * Sets the tree columns for this time graph combo's filter dialog.
749 *
750 * @param columnNames the tree column names
751 * @since 2.0
752 */
753 public void setFilterColumns(String[] columnNames) {
754 fFilterDialog.setColumnNames(columnNames);
755 }
756
837a2f8c
PT
757 /**
758 * Sets the time graph provider used by this time graph combo.
759 *
760 * @param timeGraphProvider the time graph provider
761 */
762 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
763 fTimeGraphViewer.setTimeGraphProvider(timeGraphProvider);
764 }
765
766 /**
767 * Sets or clears the input for this time graph combo.
768 * The input array should only contain top-level elements.
769 *
770 * @param input the input of this time graph combo, or <code>null</code> if none
771 */
772 public void setInput(ITimeGraphEntry[] input) {
6ac5a950
AM
773 fTopInput = new ArrayList<ITimeGraphEntry>(Arrays.asList(input));
774 fAllInput = listAllInputs(fTopInput);
775 fFilter.setNonFiltered(new ArrayList<Object>(fAllInput));
837a2f8c
PT
776 fInhibitTreeSelection = true;
777 fTreeViewer.setInput(input);
778 for (SelectionListenerWrapper listenerWrapper : fSelectionListenerMap.values()) {
779 listenerWrapper.selection = null;
780 }
781 fInhibitTreeSelection = false;
782 fTreeViewer.expandAll();
783 fTreeViewer.getTree().getVerticalBar().setEnabled(false);
784 fTreeViewer.getTree().getVerticalBar().setVisible(false);
785 fTimeGraphViewer.setItemHeight(getItemHeight(fTreeViewer.getTree()));
786 fTimeGraphViewer.setInput(input);
787 }
788
6ac5a950
AM
789 /**
790 * @param filter The filter object to be attached to the view
791 * @since 2.0
792 */
793 public void addFilter(ViewerFilter filter) {
794 ViewerFilter wrapper = new ViewerFilterWrapper(filter);
795 fTreeViewer.addFilter(wrapper);
796 fTimeGraphViewer.addFilter(wrapper);
797 fViewerFilterMap.put(filter, wrapper);
798 }
799
800 /**
801 * @param filter The filter object to be removed from the view
802 * @since 2.0
803 */
804 public void removeFilter(ViewerFilter filter) {
805 ViewerFilter wrapper = fViewerFilterMap.get(filter);
806 fTreeViewer.removeFilter(wrapper);
807 fTimeGraphViewer.removeFilter(wrapper);
808 fViewerFilterMap.remove(filter);
809 }
810
837a2f8c
PT
811 /**
812 * Refreshes this time graph completely with information freshly obtained from its model.
813 */
814 public void refresh() {
815 fInhibitTreeSelection = true;
816 fTreeViewer.refresh();
817 fTimeGraphViewer.refresh();
818 fInhibitTreeSelection = false;
819 }
820
821 /**
822 * Adds a listener for selection changes in this time graph combo.
823 *
824 * @param listener a selection listener
825 */
826 public void addSelectionListener(ITimeGraphSelectionListener listener) {
827 SelectionListenerWrapper listenerWrapper = new SelectionListenerWrapper(listener);
828 fTreeViewer.addSelectionChangedListener(listenerWrapper);
829 fSelectionListenerMap.put(listener, listenerWrapper);
830 fTimeGraphViewer.addSelectionListener(listenerWrapper);
831 }
832
833 /**
834 * Removes the given selection listener from this time graph combo.
835 *
836 * @param listener a selection changed listener
837 */
838 public void removeSelectionListener(ITimeGraphSelectionListener listener) {
839 SelectionListenerWrapper listenerWrapper = fSelectionListenerMap.remove(listener);
840 fTreeViewer.removeSelectionChangedListener(listenerWrapper);
841 fTimeGraphViewer.removeSelectionListener(listenerWrapper);
842 }
843
844 /**
845 * Sets the current selection for this time graph combo.
846 *
847 * @param selection the new selection
848 */
849 public void setSelection(ITimeGraphEntry selection) {
850 fTimeGraphViewer.setSelection(selection);
851 fInhibitTreeSelection = true; // block the tree selection changed listener
852 if (selection != null) {
853 StructuredSelection structuredSelection = new StructuredSelection(selection);
854 fTreeViewer.setSelection(structuredSelection);
855 } else {
856 fTreeViewer.setSelection(new StructuredSelection());
857 }
858 fInhibitTreeSelection = false;
859 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(fTreeViewer.getTree());
860 if (treeItems.size() == 0) {
861 return;
862 }
863 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
864 fTreeViewer.getTree().setTopItem(treeItem);
865 }
866
867 /**
868 * Set the expanded state of an entry
869 *
870 * @param entry
871 * The entry to expand/collapse
872 * @param expanded
873 * True for expanded, false for collapsed
874 *
875 * @since 2.0
876 */
877 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
878 fTimeGraphViewer.setExpandedState(entry, expanded);
879 fTreeViewer.setExpandedState(entry, expanded);
880 }
881
882 /**
883 * Collapses all nodes of the viewer's tree, starting with the root.
884 *
885 * @since 2.0
886 */
887 public void collapseAll() {
888 fTimeGraphViewer.collapseAll();
889 fTreeViewer.collapseAll();
890 }
891
892 /**
893 * Expands all nodes of the viewer's tree, starting with the root.
894 *
895 * @since 2.0
896 */
897 public void expandAll() {
898 fTimeGraphViewer.expandAll();
899 fTreeViewer.expandAll();
900 }
901
902 // ------------------------------------------------------------------------
903 // Internal
904 // ------------------------------------------------------------------------
905
906 private ArrayList<TreeItem> getVisibleExpandedItems(Tree tree) {
907 ArrayList<TreeItem> items = new ArrayList<TreeItem>();
908 for (TreeItem item : tree.getItems()) {
909 if (item.getData() == FILLER) {
910 break;
911 }
912 items.add(item);
913 if (item.getExpanded()) {
914 items.addAll(getVisibleExpandedItems(item));
915 }
916 }
917 return items;
918 }
919
920 private ArrayList<TreeItem> getVisibleExpandedItems(TreeItem treeItem) {
921 ArrayList<TreeItem> items = new ArrayList<TreeItem>();
922 for (TreeItem item : treeItem.getItems()) {
923 items.add(item);
924 if (item.getExpanded()) {
925 items.addAll(getVisibleExpandedItems(item));
926 }
927 }
928 return items;
929 }
930
6ac5a950
AM
931 /**
932 * Explores the list of top-level inputs and returns all the inputs
933 *
934 * @param inputs The top-level inputs
935 * @return All the inputs
936 */
937 private List<? extends ITimeGraphEntry> listAllInputs(List<? extends ITimeGraphEntry> inputs) {
938 ArrayList<ITimeGraphEntry> items = new ArrayList<ITimeGraphEntry>();
939 for (ITimeGraphEntry entry : inputs) {
940 items.add(entry);
941 if (entry.hasChildren()) {
942 items.addAll(listAllInputs(entry.getChildren()));
943 }
944 }
945 return items;
946 }
947
837a2f8c
PT
948 private int getItemHeight(final Tree tree) {
949 /*
950 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
951 */
952 if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
953 if (fLinuxItemHeight != 0) {
954 return fLinuxItemHeight;
955 }
956 ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
957 if (treeItems.size() > 1) {
958 final TreeItem treeItem0 = treeItems.get(0);
959 final TreeItem treeItem1 = treeItems.get(1);
960 PaintListener paintListener = new PaintListener() {
961 @Override
962 public void paintControl(PaintEvent e) {
963 tree.removePaintListener(this);
964 int y0 = treeItem0.getBounds().y;
965 int y1 = treeItem1.getBounds().y;
966 int itemHeight = y1 - y0;
967 if (itemHeight > 0) {
968 fLinuxItemHeight = itemHeight;
969 fTimeGraphViewer.setItemHeight(itemHeight);
970 }
971 }
972 };
973 tree.addPaintListener(paintListener);
974 }
975 } else {
976 fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore
977 }
978 return tree.getItemHeight();
979 }
980
981}
This page took 0.093884 seconds and 5 git commands to generate.