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