tmf : Fix binary search end time in InMemoryBackend
[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 91 // The selection listener map
f1fae91f 92 private final Map<ITimeGraphSelectionListener, SelectionListenerWrapper> fSelectionListenerMap = new HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper>();
837a2f8c 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
f1fae91f 144 Object[] oElements = Arrays.copyOf(elements, elements.length + fNumFillerRows, Object[].class);
837a2f8c
PT
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
f1fae91f 274 private ViewerFilter fWrappedFilter;
6ac5a950
AM
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() {
f1fae91f 355 private int depth = 0;
837a2f8c
PT
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);
f1fae91f 374 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
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) {
e7708b02
PT
384 ITimeGraphEntry entry = (ITimeGraphEntry) event.getElement();
385 fTimeGraphViewer.setExpandedState(entry, true);
386 for (ITimeGraphEntry child : entry.getChildren()) {
387 boolean expanded = fTreeViewer.getExpandedState(child);
388 fTimeGraphViewer.setExpandedState(child, expanded);
389 }
f1fae91f 390 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
391 if (treeItems.size() == 0) {
392 return;
393 }
394 final TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
395 // queue the top item update because the tree can change its top item
396 // autonomously immediately after the listeners have been notified
397 getDisplay().asyncExec(new Runnable() {
398 @Override
399 public void run() {
400 tree.setTopItem(treeItem);
401 }});
402 }
403 });
404
405 // ensure synchronization of expanded items between tree and time graph
406 fTimeGraphViewer.addTreeListener(new ITimeGraphTreeListener() {
407 @Override
408 public void treeCollapsed(TimeGraphTreeExpansionEvent event) {
409 fTreeViewer.setExpandedState(event.getEntry(), false);
410 }
411
412 @Override
413 public void treeExpanded(TimeGraphTreeExpansionEvent event) {
e7708b02
PT
414 ITimeGraphEntry entry = event.getEntry();
415 fTreeViewer.setExpandedState(entry, true);
416 for (ITimeGraphEntry child : entry.getChildren()) {
417 boolean expanded = fTreeViewer.getExpandedState(child);
418 fTimeGraphViewer.setExpandedState(child, expanded);
419 }
837a2f8c
PT
420 }
421 });
422
423 // prevent mouse button from selecting a filler tree item
424 tree.addListener(SWT.MouseDown, new Listener() {
425 @Override
426 public void handleEvent(Event event) {
427 TreeItem treeItem = tree.getItem(new Point(event.x, event.y));
428 if (treeItem == null || treeItem.getData() == FILLER) {
429 event.doit = false;
f1fae91f 430 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
431 if (treeItems.size() == 0) {
432 fTreeViewer.setSelection(new StructuredSelection());
433 fTimeGraphViewer.setSelection(null);
434 return;
435 }
436 // this prevents from scrolling up when selecting
437 // the partially visible tree item at the bottom
438 tree.select(treeItems.get(treeItems.size() - 1));
439 fTreeViewer.setSelection(new StructuredSelection());
440 fTimeGraphViewer.setSelection(null);
441 }
442 }
443 });
444
445 // prevent mouse wheel from scrolling down into filler tree items
446 tree.addListener(SWT.MouseWheel, new Listener() {
447 @Override
448 public void handleEvent(Event event) {
449 event.doit = false;
450 Slider scrollBar = fTimeGraphViewer.getVerticalBar();
451 fTimeGraphViewer.setTopIndex(scrollBar.getSelection() - event.count);
f1fae91f 452 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
453 if (treeItems.size() == 0) {
454 return;
455 }
456 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
457 tree.setTopItem(treeItem);
458 }
459 });
460
461 // prevent key stroke from selecting a filler tree item
462 tree.addListener(SWT.KeyDown, new Listener() {
463 @Override
464 public void handleEvent(Event event) {
f1fae91f 465 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
466 if (treeItems.size() == 0) {
467 fTreeViewer.setSelection(new StructuredSelection());
468 event.doit = false;
469 return;
470 }
471 if (event.keyCode == SWT.ARROW_DOWN) {
472 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + 1, treeItems.size() - 1);
473 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
474 event.doit = false;
475 } else if (event.keyCode == SWT.PAGE_DOWN) {
476 int height = tree.getSize().y - tree.getHeaderHeight() - tree.getHorizontalBar().getSize().y;
477 int countPerPage = height / getItemHeight(tree);
478 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + countPerPage - 1, treeItems.size() - 1);
479 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
480 event.doit = false;
481 } else if (event.keyCode == SWT.END) {
482 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(treeItems.size() - 1).getData());
483 event.doit = false;
484 }
485 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
486 tree.setTopItem(treeItem);
487 if (fTimeGraphViewer.getSelectionIndex() >= 0) {
488 fTreeViewer.setSelection(new StructuredSelection(fTimeGraphViewer.getSelection()));
489 } else {
490 fTreeViewer.setSelection(new StructuredSelection());
491 }
492 }
493 });
494
495 // ensure alignment of top item between tree and time graph
496 fTimeGraphViewer.getTimeGraphControl().addControlListener(new ControlAdapter() {
497 @Override
498 public void controlResized(ControlEvent e) {
f1fae91f 499 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
500 if (treeItems.size() == 0) {
501 return;
502 }
503 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
504 tree.setTopItem(treeItem);
505 }
506 });
507
508 // ensure synchronization of selected item between tree and time graph
509 fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
510 @Override
511 public void selectionChanged(SelectionChangedEvent event) {
512 if (fInhibitTreeSelection) {
513 return;
514 }
515 if (event.getSelection() instanceof IStructuredSelection) {
516 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
517 if (selection instanceof ITimeGraphEntry) {
518 fTimeGraphViewer.setSelection((ITimeGraphEntry) selection);
519 }
f1fae91f 520 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
521 if (treeItems.size() == 0) {
522 return;
523 }
524 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
525 tree.setTopItem(treeItem);
526 }
527 }
528 });
529
530 // ensure synchronization of selected item between tree and time graph
531 fTimeGraphViewer.addSelectionListener(new ITimeGraphSelectionListener() {
532 @Override
533 public void selectionChanged(TimeGraphSelectionEvent event) {
534 ITimeGraphEntry entry = fTimeGraphViewer.getSelection();
535 fInhibitTreeSelection = true; // block the tree selection changed listener
536 if (entry != null) {
537 StructuredSelection selection = new StructuredSelection(entry);
538 fTreeViewer.setSelection(selection);
539 } else {
540 fTreeViewer.setSelection(new StructuredSelection());
541 }
542 fInhibitTreeSelection = false;
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 // ensure alignment of top item between tree and time graph
553 fTimeGraphViewer.getVerticalBar().addSelectionListener(new SelectionAdapter() {
554 @Override
555 public void widgetSelected(SelectionEvent e) {
f1fae91f 556 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
557 if (treeItems.size() == 0) {
558 return;
559 }
560 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
561 tree.setTopItem(treeItem);
562 }
563 });
564
565 // ensure alignment of top item between tree and time graph
566 fTimeGraphViewer.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
567 @Override
568 public void mouseScrolled(MouseEvent e) {
f1fae91f 569 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
570 if (treeItems.size() == 0) {
571 return;
572 }
573 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
574 tree.setTopItem(treeItem);
575 }
576 });
577
578 // ensure the tree has focus control when mouse is over it if the time graph had control
579 fTreeViewer.getControl().addMouseTrackListener(new MouseTrackAdapter() {
580 @Override
581 public void mouseEnter(MouseEvent e) {
582 if (fTimeGraphViewer.getTimeGraphControl().isFocusControl()) {
583 fTreeViewer.getControl().setFocus();
584 }
585 }
586 });
587
588 // ensure the time graph has focus control when mouse is over it if the tree had control
589 fTimeGraphViewer.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
590 @Override
591 public void mouseEnter(MouseEvent e) {
592 if (fTreeViewer.getControl().isFocusControl()) {
593 fTimeGraphViewer.getTimeGraphControl().setFocus();
594 }
595 }
596 });
597 fTimeGraphViewer.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
598 @Override
599 public void mouseEnter(MouseEvent e) {
600 if (fTreeViewer.getControl().isFocusControl()) {
601 fTimeGraphViewer.getTimeGraphControl().setFocus();
602 }
603 }
604 });
605
606 // The filler rows are required to ensure alignment when the tree does not have a
607 // visible horizontal scroll bar. The tree does not allow its top item to be set
608 // to a value that would cause blank space to be drawn at the bottom of the tree.
609 fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree);
610
611 sash.setWeights(new int[] { 1, 1 });
612 }
613
614 // ------------------------------------------------------------------------
615 // Accessors
616 // ------------------------------------------------------------------------
617
618 /**
619 * Returns this time graph combo's tree viewer.
620 *
621 * @return the tree viewer
622 */
623 public TreeViewer getTreeViewer() {
624 return fTreeViewer;
625 }
626
627 /**
628 * Returns this time graph combo's time graph viewer.
629 *
630 * @return the time graph viewer
631 */
632 public TimeGraphViewer getTimeGraphViewer() {
633 return fTimeGraphViewer;
634 }
635
6ac5a950
AM
636 /**
637 * Callback for the show filter action
638 *
639 * @since 2.0
640 */
641 public void showFilterDialog() {
642 if(fTopInput != null) {
8f28f9d8 643 List<? extends ITimeGraphEntry> allElements = listAllInputs(fTopInput);
6ac5a950
AM
644 fFilterDialog.setInput(fTopInput.toArray(new ITimeGraphEntry[0]));
645 fFilterDialog.setTitle(Messages.TmfTimeFilterDialog_WINDOW_TITLE);
646 fFilterDialog.setMessage(Messages.TmfTimeFilterDialog_MESSAGE);
8f28f9d8 647 fFilterDialog.setExpandedElements(allElements.toArray());
f8840316
FR
648 if (fFilter.getFiltered() != null) {
649 ArrayList<? extends ITimeGraphEntry> nonFilteredElements = new ArrayList<ITimeGraphEntry>(allElements);
650 nonFilteredElements.removeAll(fFilter.getFiltered());
651 fFilterDialog.setInitialElementSelections(nonFilteredElements);
8f28f9d8
PT
652 } else {
653 fFilterDialog.setInitialElementSelections(allElements);
654 }
6ac5a950
AM
655 fFilterDialog.create();
656 fFilterDialog.open();
657 // Process selected elements
658 if (fFilterDialog.getResult() != null) {
659 fInhibitTreeSelection = true;
8f28f9d8 660 if (fFilterDialog.getResult().length != allElements.size()) {
f8840316
FR
661 ArrayList<Object> filteredElements = new ArrayList<Object>(allElements);
662 filteredElements.removeAll(Arrays.asList(fFilterDialog.getResult()));
663 fFilter.setFiltered(filteredElements);
8f28f9d8 664 } else {
f8840316 665 fFilter.setFiltered(null);
8f28f9d8 666 }
6ac5a950
AM
667 fTreeViewer.refresh();
668 fTreeViewer.expandAll();
669 fTimeGraphViewer.refresh();
670 fInhibitTreeSelection = false;
671 // Reset selection to first entry
672 if (fFilterDialog.getResult().length > 0) {
673 setSelection((ITimeGraphEntry) fFilterDialog.getResult()[0]);
674 }
675 }
676 }
677 }
678
679 /**
680 * Get the show filter action.
681 *
682 * @return The Action object
683 * @since 2.0
684 */
685 public Action getShowFilterAction() {
686 if (showFilterAction == null) {
687 // showFilter
688 showFilterAction = new Action() {
689 @Override
690 public void run() {
691 showFilterDialog();
692 }
693 };
694 showFilterAction.setText(Messages.TmfTimeGraphCombo_FilterActionNameText);
695 showFilterAction.setToolTipText(Messages.TmfTimeGraphCombo_FilterActionToolTipText);
696 // TODO find a nice, distinctive icon
697 showFilterAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FILTERS));
698 }
699
700 return showFilterAction;
701 }
702
837a2f8c
PT
703 // ------------------------------------------------------------------------
704 // Control
705 // ------------------------------------------------------------------------
706
837a2f8c
PT
707 @Override
708 public void redraw() {
709 fTimeGraphViewer.getControl().redraw();
710 super.redraw();
711 }
712
713 // ------------------------------------------------------------------------
714 // Operations
715 // ------------------------------------------------------------------------
716
717 /**
718 * Sets the tree content provider used by this time graph combo.
719 *
720 * @param contentProvider the tree content provider
721 */
722 public void setTreeContentProvider(ITreeContentProvider contentProvider) {
723 fTreeViewer.setContentProvider(new TreeContentProviderWrapper(contentProvider));
724 }
725
726 /**
727 * Sets the tree label provider used by this time graph combo.
728 *
729 * @param labelProvider the tree label provider
730 */
731 public void setTreeLabelProvider(ITableLabelProvider labelProvider) {
732 fTreeViewer.setLabelProvider(new TreeLabelProviderWrapper(labelProvider));
733 }
734
6ac5a950
AM
735 /**
736 * Sets the tree content provider used by the filter dialog
737 *
738 * @param contentProvider the tree content provider
739 * @since 2.0
740 */
741 public void setFilterContentProvider(ITreeContentProvider contentProvider) {
742 fFilterDialog.setContentProvider(contentProvider);
743 }
744
745 /**
746 * Sets the tree label provider used by the filter dialog
747 *
748 * @param labelProvider the tree label provider
749 * @since 2.0
750 */
751 public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
752 fFilterDialog.setLabelProvider(labelProvider);
753 }
754
837a2f8c
PT
755 /**
756 * Sets the tree columns for this time graph combo.
757 *
758 * @param columnNames the tree column names
759 */
760 public void setTreeColumns(String[] columnNames) {
761 final Tree tree = fTreeViewer.getTree();
762 for (String columnName : columnNames) {
763 TreeColumn column = new TreeColumn(tree, SWT.LEFT);
764 column.setText(columnName);
765 column.pack();
766 }
767 }
768
6ac5a950
AM
769 /**
770 * Sets the tree columns for this time graph combo's filter dialog.
771 *
772 * @param columnNames the tree column names
773 * @since 2.0
774 */
775 public void setFilterColumns(String[] columnNames) {
776 fFilterDialog.setColumnNames(columnNames);
777 }
778
837a2f8c
PT
779 /**
780 * Sets the time graph provider used by this time graph combo.
781 *
782 * @param timeGraphProvider the time graph provider
783 */
784 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
785 fTimeGraphViewer.setTimeGraphProvider(timeGraphProvider);
786 }
787
788 /**
789 * Sets or clears the input for this time graph combo.
790 * The input array should only contain top-level elements.
791 *
792 * @param input the input of this time graph combo, or <code>null</code> if none
793 */
794 public void setInput(ITimeGraphEntry[] input) {
6ac5a950 795 fTopInput = new ArrayList<ITimeGraphEntry>(Arrays.asList(input));
f8840316 796 fFilter.setFiltered(null);
837a2f8c
PT
797 fInhibitTreeSelection = true;
798 fTreeViewer.setInput(input);
799 for (SelectionListenerWrapper listenerWrapper : fSelectionListenerMap.values()) {
800 listenerWrapper.selection = null;
801 }
802 fInhibitTreeSelection = false;
803 fTreeViewer.expandAll();
804 fTreeViewer.getTree().getVerticalBar().setEnabled(false);
805 fTreeViewer.getTree().getVerticalBar().setVisible(false);
806 fTimeGraphViewer.setItemHeight(getItemHeight(fTreeViewer.getTree()));
807 fTimeGraphViewer.setInput(input);
808 }
809
6ac5a950
AM
810 /**
811 * @param filter The filter object to be attached to the view
812 * @since 2.0
813 */
814 public void addFilter(ViewerFilter filter) {
815 ViewerFilter wrapper = new ViewerFilterWrapper(filter);
816 fTreeViewer.addFilter(wrapper);
817 fTimeGraphViewer.addFilter(wrapper);
818 fViewerFilterMap.put(filter, wrapper);
819 }
820
821 /**
822 * @param filter The filter object to be removed from the view
823 * @since 2.0
824 */
825 public void removeFilter(ViewerFilter filter) {
826 ViewerFilter wrapper = fViewerFilterMap.get(filter);
827 fTreeViewer.removeFilter(wrapper);
828 fTimeGraphViewer.removeFilter(wrapper);
829 fViewerFilterMap.remove(filter);
830 }
831
837a2f8c
PT
832 /**
833 * Refreshes this time graph completely with information freshly obtained from its model.
834 */
835 public void refresh() {
836 fInhibitTreeSelection = true;
837 fTreeViewer.refresh();
838 fTimeGraphViewer.refresh();
839 fInhibitTreeSelection = false;
840 }
841
842 /**
843 * Adds a listener for selection changes in this time graph combo.
844 *
845 * @param listener a selection listener
846 */
847 public void addSelectionListener(ITimeGraphSelectionListener listener) {
848 SelectionListenerWrapper listenerWrapper = new SelectionListenerWrapper(listener);
849 fTreeViewer.addSelectionChangedListener(listenerWrapper);
850 fSelectionListenerMap.put(listener, listenerWrapper);
851 fTimeGraphViewer.addSelectionListener(listenerWrapper);
852 }
853
854 /**
855 * Removes the given selection listener from this time graph combo.
856 *
857 * @param listener a selection changed listener
858 */
859 public void removeSelectionListener(ITimeGraphSelectionListener listener) {
860 SelectionListenerWrapper listenerWrapper = fSelectionListenerMap.remove(listener);
861 fTreeViewer.removeSelectionChangedListener(listenerWrapper);
862 fTimeGraphViewer.removeSelectionListener(listenerWrapper);
863 }
864
865 /**
866 * Sets the current selection for this time graph combo.
867 *
868 * @param selection the new selection
869 */
870 public void setSelection(ITimeGraphEntry selection) {
871 fTimeGraphViewer.setSelection(selection);
872 fInhibitTreeSelection = true; // block the tree selection changed listener
873 if (selection != null) {
874 StructuredSelection structuredSelection = new StructuredSelection(selection);
875 fTreeViewer.setSelection(structuredSelection);
876 } else {
877 fTreeViewer.setSelection(new StructuredSelection());
878 }
879 fInhibitTreeSelection = false;
f1fae91f 880 List<TreeItem> treeItems = getVisibleExpandedItems(fTreeViewer.getTree());
837a2f8c
PT
881 if (treeItems.size() == 0) {
882 return;
883 }
884 TreeItem treeItem = treeItems.get(fTimeGraphViewer.getTopIndex());
885 fTreeViewer.getTree().setTopItem(treeItem);
886 }
887
888 /**
889 * Set the expanded state of an entry
890 *
891 * @param entry
892 * The entry to expand/collapse
893 * @param expanded
894 * True for expanded, false for collapsed
895 *
896 * @since 2.0
897 */
898 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
899 fTimeGraphViewer.setExpandedState(entry, expanded);
900 fTreeViewer.setExpandedState(entry, expanded);
901 }
902
903 /**
904 * Collapses all nodes of the viewer's tree, starting with the root.
905 *
906 * @since 2.0
907 */
908 public void collapseAll() {
909 fTimeGraphViewer.collapseAll();
910 fTreeViewer.collapseAll();
911 }
912
913 /**
914 * Expands all nodes of the viewer's tree, starting with the root.
915 *
916 * @since 2.0
917 */
918 public void expandAll() {
919 fTimeGraphViewer.expandAll();
920 fTreeViewer.expandAll();
921 }
922
923 // ------------------------------------------------------------------------
924 // Internal
925 // ------------------------------------------------------------------------
926
f1fae91f 927 private List<TreeItem> getVisibleExpandedItems(Tree tree) {
837a2f8c
PT
928 ArrayList<TreeItem> items = new ArrayList<TreeItem>();
929 for (TreeItem item : tree.getItems()) {
930 if (item.getData() == FILLER) {
931 break;
932 }
933 items.add(item);
934 if (item.getExpanded()) {
935 items.addAll(getVisibleExpandedItems(item));
936 }
937 }
938 return items;
939 }
940
f1fae91f 941 private List<TreeItem> getVisibleExpandedItems(TreeItem treeItem) {
837a2f8c
PT
942 ArrayList<TreeItem> items = new ArrayList<TreeItem>();
943 for (TreeItem item : treeItem.getItems()) {
944 items.add(item);
945 if (item.getExpanded()) {
946 items.addAll(getVisibleExpandedItems(item));
947 }
948 }
949 return items;
950 }
951
6ac5a950
AM
952 /**
953 * Explores the list of top-level inputs and returns all the inputs
954 *
955 * @param inputs The top-level inputs
956 * @return All the inputs
957 */
958 private List<? extends ITimeGraphEntry> listAllInputs(List<? extends ITimeGraphEntry> inputs) {
959 ArrayList<ITimeGraphEntry> items = new ArrayList<ITimeGraphEntry>();
960 for (ITimeGraphEntry entry : inputs) {
961 items.add(entry);
962 if (entry.hasChildren()) {
963 items.addAll(listAllInputs(entry.getChildren()));
964 }
965 }
966 return items;
967 }
968
837a2f8c
PT
969 private int getItemHeight(final Tree tree) {
970 /*
971 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
972 */
973 if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
974 if (fLinuxItemHeight != 0) {
975 return fLinuxItemHeight;
976 }
f1fae91f 977 List<TreeItem> treeItems = getVisibleExpandedItems(tree);
837a2f8c
PT
978 if (treeItems.size() > 1) {
979 final TreeItem treeItem0 = treeItems.get(0);
980 final TreeItem treeItem1 = treeItems.get(1);
981 PaintListener paintListener = new PaintListener() {
982 @Override
983 public void paintControl(PaintEvent e) {
984 tree.removePaintListener(this);
985 int y0 = treeItem0.getBounds().y;
986 int y1 = treeItem1.getBounds().y;
987 int itemHeight = y1 - y0;
988 if (itemHeight > 0) {
989 fLinuxItemHeight = itemHeight;
990 fTimeGraphViewer.setItemHeight(itemHeight);
991 }
992 }
993 };
994 tree.addPaintListener(paintListener);
995 }
996 } else {
997 fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore
998 }
999 return tree.getItemHeight();
1000 }
1001
1002}
This page took 0.076958 seconds and 5 git commands to generate.