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