47b9ef26eb32304dea094c6f26bffa3bef8ca0b1
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / widgets / timegraph / TimeGraphCombo.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 Ericsson, others
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 * François Rajotte - Filter implementation
12 * Geneviève Bastien - Add event links between entries
13 * Christian Mansky - Add check active / uncheck inactive buttons
14 *******************************************************************************/
15
16 package org.eclipse.tracecompass.tmf.ui.widgets.timegraph;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.jface.viewers.AbstractTreeViewer;
28 import org.eclipse.jface.viewers.ILabelProviderListener;
29 import org.eclipse.jface.viewers.ISelectionChangedListener;
30 import org.eclipse.jface.viewers.IStructuredSelection;
31 import org.eclipse.jface.viewers.ITableLabelProvider;
32 import org.eclipse.jface.viewers.ITreeContentProvider;
33 import org.eclipse.jface.viewers.ITreeViewerListener;
34 import org.eclipse.jface.viewers.SelectionChangedEvent;
35 import org.eclipse.jface.viewers.StructuredSelection;
36 import org.eclipse.jface.viewers.TreeExpansionEvent;
37 import org.eclipse.jface.viewers.TreeViewer;
38 import org.eclipse.jface.viewers.Viewer;
39 import org.eclipse.jface.viewers.ViewerFilter;
40 import org.eclipse.swt.SWT;
41 import org.eclipse.swt.custom.SashForm;
42 import org.eclipse.swt.events.ControlAdapter;
43 import org.eclipse.swt.events.ControlEvent;
44 import org.eclipse.swt.events.DisposeEvent;
45 import org.eclipse.swt.events.DisposeListener;
46 import org.eclipse.swt.events.MouseEvent;
47 import org.eclipse.swt.events.MouseTrackAdapter;
48 import org.eclipse.swt.events.MouseWheelListener;
49 import org.eclipse.swt.events.PaintEvent;
50 import org.eclipse.swt.events.PaintListener;
51 import org.eclipse.swt.events.SelectionAdapter;
52 import org.eclipse.swt.events.SelectionEvent;
53 import org.eclipse.swt.graphics.Font;
54 import org.eclipse.swt.graphics.FontData;
55 import org.eclipse.swt.graphics.Image;
56 import org.eclipse.swt.graphics.Point;
57 import org.eclipse.swt.graphics.Rectangle;
58 import org.eclipse.swt.layout.FillLayout;
59 import org.eclipse.swt.layout.GridLayout;
60 import org.eclipse.swt.widgets.Composite;
61 import org.eclipse.swt.widgets.Control;
62 import org.eclipse.swt.widgets.Display;
63 import org.eclipse.swt.widgets.Event;
64 import org.eclipse.swt.widgets.Listener;
65 import org.eclipse.swt.widgets.Sash;
66 import org.eclipse.swt.widgets.Slider;
67 import org.eclipse.swt.widgets.Tree;
68 import org.eclipse.swt.widgets.TreeColumn;
69 import org.eclipse.swt.widgets.TreeItem;
70 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
71 import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
72 import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentSignal;
73 import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
74 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.ITimeGraphEntryActiveProvider;
75 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.ShowFilterDialogAction;
76 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
77 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
78 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphColorScheme;
79 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
80
81 import com.google.common.collect.Iterables;
82
83 /**
84 * Time graph "combo" view (with the list/tree on the left and the gantt chart
85 * on the right)
86 *
87 * @author Patrick Tasse
88 */
89 public class TimeGraphCombo extends Composite {
90
91 // ------------------------------------------------------------------------
92 // Constants
93 // ------------------------------------------------------------------------
94
95 /** Constant indicating that all levels of the time graph should be expanded */
96 public static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
97
98 private static final Object FILLER = new Object();
99
100 // ------------------------------------------------------------------------
101 // Fields
102 // ------------------------------------------------------------------------
103
104 /** The tree viewer */
105 private TreeViewer fTreeViewer;
106
107 /** The time viewer */
108 private @NonNull TimeGraphViewer fTimeGraphViewer;
109
110 /** The selection listener map */
111 private final Map<ITimeGraphSelectionListener, SelectionListenerWrapper> fSelectionListenerMap = new HashMap<>();
112
113 /** The map of viewer filters to viewer filter wrappers */
114 private final Map<@NonNull ViewerFilter, @NonNull ViewerFilter> fViewerFilterMap = new HashMap<>();
115
116 /**
117 * Flag to block the tree selection changed listener when triggered by the
118 * time graph combo
119 */
120 private boolean fInhibitTreeSelection = false;
121
122 /** Number of filler rows used by the tree content provider */
123 private int fNumFillerRows;
124
125 /** Calculated item height for Linux workaround */
126 private int fLinuxItemHeight = 0;
127
128 /** The action that opens the filter dialog */
129 private ShowFilterDialogAction fShowFilterDialogAction;
130
131 /** Default weight of each part of the sash */
132 private static final int[] DEFAULT_WEIGHTS = { 1, 1 };
133
134 /** List of all expanded items whose parents are also expanded */
135 private List<TreeItem> fVisibleExpandedItems = null;
136
137 private Listener fSashDragListener;
138 private SashForm fSashForm;
139
140 private final boolean fScrollBarsInTreeWorkaround;
141
142 private Font fTreeFont;
143
144 // ------------------------------------------------------------------------
145 // Classes
146 // ------------------------------------------------------------------------
147
148 /**
149 * The TimeGraphViewerExtension is used to set appropriate values and to
150 * override methods that could be called directly by the user and that must
151 * be handled by the time graph combo.
152 */
153 private class TimeGraphViewerExtension extends TimeGraphViewer {
154
155 private TimeGraphViewerExtension(Composite parent, int style, Tree tree) {
156 super(parent, style);
157 setItemHeight(TimeGraphCombo.this.getItemHeight(tree, true));
158 setHeaderHeight(tree.getHeaderHeight());
159 setBorderWidth(tree.getBorderWidth());
160 setNameWidthPref(0);
161 }
162
163 @Override
164 public ShowFilterDialogAction getShowFilterDialogAction() {
165 return TimeGraphCombo.this.getShowFilterDialogAction();
166 }
167
168 @Override
169 protected TimeGraphControl createTimeGraphControl(Composite composite, TimeGraphColorScheme colors) {
170 return new TimeGraphControl(composite, colors) {
171 @Override
172 public void verticalZoom(boolean zoomIn, boolean adjustItems) {
173 boolean changed = TimeGraphCombo.this.verticalZoom(zoomIn);
174 if (changed) {
175 /*
176 * The time graph combo takes care of adjusting item
177 * heights, only adjust the font in the time graph
178 * control. Only do it if the time graph combo's tree
179 * font has actually changed.
180 */
181 super.verticalZoom(zoomIn, false);
182 }
183 }
184
185 @Override
186 public void resetVerticalZoom(boolean adjustItems) {
187 TimeGraphCombo.this.resetVerticalZoom();
188 /*
189 * The time graph combo takes care of resetting item
190 * heights, only reset the font in the time graph control.
191 */
192 super.resetVerticalZoom(false);
193 }
194 };
195 }
196 }
197
198 /**
199 * The TreeContentProviderWrapper is used to insert filler items after
200 * the elements of the tree's real content provider.
201 */
202 private class TreeContentProviderWrapper implements ITreeContentProvider {
203 private final ITreeContentProvider contentProvider;
204
205 public TreeContentProviderWrapper(ITreeContentProvider contentProvider) {
206 this.contentProvider = contentProvider;
207 }
208
209 @Override
210 public void dispose() {
211 contentProvider.dispose();
212 }
213
214 @Override
215 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
216 contentProvider.inputChanged(viewer, oldInput, newInput);
217 }
218
219 @Override
220 public Object[] getElements(Object inputElement) {
221 Object[] elements = contentProvider.getElements(inputElement);
222 // add filler elements to ensure alignment with time analysis viewer
223 Object[] oElements = Arrays.copyOf(elements, elements.length + fNumFillerRows, Object[].class);
224 for (int i = 0; i < fNumFillerRows; i++) {
225 oElements[elements.length + i] = FILLER;
226 }
227 return oElements;
228 }
229
230 @Override
231 public Object[] getChildren(Object parentElement) {
232 if (parentElement instanceof ITimeGraphEntry) {
233 return contentProvider.getChildren(parentElement);
234 }
235 return new Object[0];
236 }
237
238 @Override
239 public Object getParent(Object element) {
240 if (element instanceof ITimeGraphEntry) {
241 return contentProvider.getParent(element);
242 }
243 return null;
244 }
245
246 @Override
247 public boolean hasChildren(Object element) {
248 if (element instanceof ITimeGraphEntry) {
249 return contentProvider.hasChildren(element);
250 }
251 return false;
252 }
253 }
254
255 /**
256 * The TreeLabelProviderWrapper is used to intercept the filler items
257 * from the calls to the tree's real label provider.
258 */
259 private class TreeLabelProviderWrapper implements ITableLabelProvider {
260 private final ITableLabelProvider labelProvider;
261
262 public TreeLabelProviderWrapper(ITableLabelProvider labelProvider) {
263 this.labelProvider = labelProvider;
264 }
265
266 @Override
267 public void addListener(ILabelProviderListener listener) {
268 labelProvider.addListener(listener);
269 }
270
271 @Override
272 public void dispose() {
273 labelProvider.dispose();
274 }
275
276 @Override
277 public boolean isLabelProperty(Object element, String property) {
278 if (element instanceof ITimeGraphEntry) {
279 return labelProvider.isLabelProperty(element, property);
280 }
281 return false;
282 }
283
284 @Override
285 public void removeListener(ILabelProviderListener listener) {
286 labelProvider.removeListener(listener);
287 }
288
289 @Override
290 public Image getColumnImage(Object element, int columnIndex) {
291 if (element instanceof ITimeGraphEntry) {
292 return labelProvider.getColumnImage(element, columnIndex);
293 }
294 return null;
295 }
296
297 @Override
298 public String getColumnText(Object element, int columnIndex) {
299 if (element instanceof ITimeGraphEntry) {
300 return labelProvider.getColumnText(element, columnIndex);
301 }
302 return null;
303 }
304
305 }
306
307 /**
308 * The SelectionListenerWrapper is used to intercept the filler items from
309 * the time graph combo's real selection listener, and to prevent double
310 * notifications from being sent when selection changes in both tree and
311 * time graph at the same time.
312 */
313 private class SelectionListenerWrapper implements ISelectionChangedListener, ITimeGraphSelectionListener {
314 private final ITimeGraphSelectionListener listener;
315 private ITimeGraphEntry selection = null;
316
317 public SelectionListenerWrapper(ITimeGraphSelectionListener listener) {
318 this.listener = listener;
319 }
320
321 @Override
322 public void selectionChanged(SelectionChangedEvent event) {
323 if (fInhibitTreeSelection) {
324 return;
325 }
326 Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
327 if (element instanceof ITimeGraphEntry) {
328 ITimeGraphEntry entry = (ITimeGraphEntry) element;
329 if (entry != selection) {
330 selection = entry;
331 listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
332 }
333 }
334 }
335
336 @Override
337 public void selectionChanged(TimeGraphSelectionEvent event) {
338 ITimeGraphEntry entry = event.getSelection();
339 if (entry != selection) {
340 selection = entry;
341 listener.selectionChanged(new TimeGraphSelectionEvent(event.getSource(), selection));
342 }
343 }
344 }
345
346 /**
347 * The ViewerFilterWrapper is used to intercept the filler items from
348 * the time graph combo's real ViewerFilters. These filler items should
349 * always be visible.
350 */
351 private class ViewerFilterWrapper extends ViewerFilter {
352
353 private ViewerFilter fWrappedFilter;
354
355 ViewerFilterWrapper(ViewerFilter filter) {
356 super();
357 this.fWrappedFilter = filter;
358 }
359
360 @Override
361 public boolean select(Viewer viewer, Object parentElement, Object element) {
362 if (element instanceof ITimeGraphEntry) {
363 return fWrappedFilter.select(viewer, parentElement, element);
364 }
365 return true;
366 }
367
368 }
369
370 // ------------------------------------------------------------------------
371 // Constructors
372 // ------------------------------------------------------------------------
373
374 /**
375 * Constructs a new instance of this class given its parent
376 * and a style value describing its behavior and appearance.
377 *
378 * @param parent a widget which will be the parent of the new instance (cannot be null)
379 * @param style the style of widget to construct
380 */
381 public TimeGraphCombo(Composite parent, int style) {
382 this(parent, style, DEFAULT_WEIGHTS);
383 }
384
385 /**
386 * Constructs a new instance of this class given its parent and a style
387 * value describing its behavior and appearance.
388 *
389 * @param parent
390 * a widget which will be the parent of the new instance (cannot
391 * be null)
392 * @param style
393 * the style of widget to construct
394 * @param weights
395 * The array (length 2) of relative weights of each side of the sash form
396 */
397 public TimeGraphCombo(Composite parent, int style, int[] weights) {
398 super(parent, style);
399 setLayout(new FillLayout());
400
401 fSashForm = new SashForm(this, SWT.NONE);
402
403 /*
404 * In Windows, SWT.H_SCROLL | SWT.NO_SCROLL is not properly supported,
405 * both scroll bars are always created. See Tree.checkStyle: "Even when
406 * WS_HSCROLL or WS_VSCROLL is not specified, Windows creates trees and
407 * tables with scroll bars."
408 */
409 fScrollBarsInTreeWorkaround = "win32".equals(SWT.getPlatform()); //$NON-NLS-1$
410
411 int scrollBarStyle = fScrollBarsInTreeWorkaround ? SWT.H_SCROLL : SWT.H_SCROLL | SWT.NO_SCROLL;
412
413 fTreeViewer = new TreeViewer(fSashForm, SWT.FULL_SELECTION | scrollBarStyle);
414 fTreeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
415 final Tree tree = fTreeViewer.getTree();
416 tree.setHeaderVisible(true);
417 tree.setLinesVisible(true);
418
419 fTimeGraphViewer = new TimeGraphViewerExtension(fSashForm, SWT.NONE, tree);
420
421 if (fScrollBarsInTreeWorkaround) {
422 // Feature in Windows. The tree vertical bar reappears when
423 // the control is resized so we need to hide it again.
424 tree.addControlListener(new ControlAdapter() {
425 private int depth = 0;
426
427 @Override
428 public void controlResized(ControlEvent e) {
429 if (depth == 0) {
430 depth++;
431 tree.getVerticalBar().setEnabled(false);
432 // this can trigger controlResized recursively
433 tree.getVerticalBar().setVisible(false);
434 depth--;
435 }
436 }
437 });
438 }
439 // Bug in Linux. The tree header height is 0 in constructor,
440 // so we need to reset it later when the control is painted.
441 // This work around used to be done on control resized but the header
442 // height was not initialized on the initial resize on GTK3.
443 tree.addPaintListener(new PaintListener() {
444 @Override
445 public void paintControl(PaintEvent e) {
446 int headerHeight = tree.getHeaderHeight();
447 if (headerHeight > 0) {
448 fTimeGraphViewer.setHeaderHeight(headerHeight);
449 tree.removePaintListener(this);
450 }
451 }
452 });
453
454 tree.addDisposeListener(new DisposeListener() {
455 @Override
456 public void widgetDisposed(DisposeEvent e) {
457 if (fTreeFont != null) {
458 fTreeFont.dispose();
459 }
460 }
461 });
462
463 // ensure synchronization of expanded items between tree and time graph
464 fTreeViewer.addTreeListener(new ITreeViewerListener() {
465 @Override
466 public void treeCollapsed(TreeExpansionEvent event) {
467 fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), false);
468 // queue the alignment update because the tree items may only be
469 // actually collapsed after the listeners have been notified
470 fVisibleExpandedItems = null; // invalidate the cache
471 getDisplay().asyncExec(new Runnable() {
472 @Override
473 public void run() {
474 alignTreeItems(true);
475 }});
476 }
477
478 @Override
479 public void treeExpanded(TreeExpansionEvent event) {
480 ITimeGraphEntry entry = (ITimeGraphEntry) event.getElement();
481 fTimeGraphViewer.setExpandedState(entry, true);
482 Set<Object> expandedElements = new HashSet<>(Arrays.asList(fTreeViewer.getExpandedElements()));
483 for (ITimeGraphEntry child : entry.getChildren()) {
484 if (child.hasChildren()) {
485 boolean expanded = expandedElements.contains(child);
486 fTimeGraphViewer.setExpandedState(child, expanded);
487 }
488 }
489 // queue the alignment update because the tree items may only be
490 // actually expanded after the listeners have been notified
491 fVisibleExpandedItems = null; // invalidate the cache
492 getDisplay().asyncExec(new Runnable() {
493 @Override
494 public void run() {
495 alignTreeItems(true);
496 }});
497 }
498 });
499
500 // ensure synchronization of expanded items between tree and time graph
501 fTimeGraphViewer.addTreeListener(new ITimeGraphTreeListener() {
502 @Override
503 public void treeCollapsed(TimeGraphTreeExpansionEvent event) {
504 fTreeViewer.setExpandedState(event.getEntry(), false);
505 alignTreeItems(true);
506 }
507
508 @Override
509 public void treeExpanded(TimeGraphTreeExpansionEvent event) {
510 ITimeGraphEntry entry = event.getEntry();
511 fTreeViewer.setExpandedState(entry, true);
512 Set<Object> expandedElements = new HashSet<>(Arrays.asList(fTreeViewer.getExpandedElements()));
513 for (ITimeGraphEntry child : entry.getChildren()) {
514 if (child.hasChildren()) {
515 boolean expanded = expandedElements.contains(child);
516 fTimeGraphViewer.setExpandedState(child, expanded);
517 }
518 }
519 alignTreeItems(true);
520 }
521 });
522
523 // prevent mouse button from selecting a filler tree item
524 tree.addListener(SWT.MouseDown, new Listener() {
525 @Override
526 public void handleEvent(Event event) {
527 TreeItem treeItem = tree.getItem(new Point(event.x, event.y));
528 if (treeItem == null || treeItem.getData() == FILLER) {
529 event.doit = false;
530 List<TreeItem> treeItems = getVisibleExpandedItems(tree, false);
531 if (treeItems.size() == 0) {
532 fTreeViewer.setSelection(new StructuredSelection());
533 fTimeGraphViewer.setSelection(null);
534 return;
535 }
536 // this prevents from scrolling up when selecting
537 // the partially visible tree item at the bottom
538 tree.select(treeItems.get(treeItems.size() - 1));
539 fTreeViewer.setSelection(new StructuredSelection());
540 fTimeGraphViewer.setSelection(null);
541 }
542 }
543 });
544
545 // prevent mouse wheel from scrolling down into filler tree items
546 tree.addListener(SWT.MouseWheel, new Listener() {
547 @Override
548 public void handleEvent(Event event) {
549 event.doit = false;
550 Slider scrollBar = fTimeGraphViewer.getVerticalBar();
551 fTimeGraphViewer.setTopIndex(scrollBar.getSelection() - event.count);
552 alignTreeItems(false);
553 }
554 });
555
556 // prevent key stroke from selecting a filler tree item
557 tree.addListener(SWT.KeyDown, new Listener() {
558 @Override
559 public void handleEvent(Event event) {
560 List<TreeItem> treeItems = getVisibleExpandedItems(tree, false);
561 if (treeItems.size() == 0) {
562 fTreeViewer.setSelection(new StructuredSelection());
563 event.doit = false;
564 return;
565 }
566 if (event.keyCode == SWT.ARROW_DOWN) {
567 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + 1, treeItems.size() - 1);
568 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
569 event.doit = false;
570 } else if (event.keyCode == SWT.PAGE_DOWN) {
571 int height = tree.getSize().y - tree.getHeaderHeight() - tree.getHorizontalBar().getSize().y;
572 int countPerPage = height / getItemHeight(tree, false);
573 int index = Math.min(fTimeGraphViewer.getSelectionIndex() + countPerPage - 1, treeItems.size() - 1);
574 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(index).getData());
575 event.doit = false;
576 } else if (event.keyCode == SWT.END) {
577 fTimeGraphViewer.setSelection((ITimeGraphEntry) treeItems.get(treeItems.size() - 1).getData());
578 event.doit = false;
579 } else if ((event.character == '+' || event.character == '=') && ((event.stateMask & SWT.CTRL) != 0)) {
580 verticalZoom(true);
581 } else if (event.character == '-' && ((event.stateMask & SWT.CTRL) != 0)) {
582 verticalZoom(false);
583 } else if (event.character == '0' && ((event.stateMask & SWT.CTRL) != 0)) {
584 resetVerticalZoom();
585 } else {
586 return;
587 }
588 if (fTimeGraphViewer.getSelectionIndex() >= 0) {
589 fTreeViewer.setSelection(new StructuredSelection(fTimeGraphViewer.getSelection()));
590 } else {
591 fTreeViewer.setSelection(new StructuredSelection());
592 }
593 alignTreeItems(false);
594 }
595 });
596
597 // ensure alignment of top item between tree and time graph
598 fTimeGraphViewer.getTimeGraphControl().addControlListener(new ControlAdapter() {
599 @Override
600 public void controlResized(ControlEvent e) {
601 alignTreeItems(false);
602 }
603 });
604
605 // ensure synchronization of selected item between tree and time graph
606 fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
607 @Override
608 public void selectionChanged(SelectionChangedEvent event) {
609 if (fInhibitTreeSelection) {
610 return;
611 }
612 if (event.getSelection() instanceof IStructuredSelection) {
613 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
614 if (selection instanceof ITimeGraphEntry) {
615 fTimeGraphViewer.setSelection((ITimeGraphEntry) selection);
616 }
617 alignTreeItems(false);
618 }
619 }
620 });
621
622 // ensure synchronization of selected item between tree and time graph
623 fTimeGraphViewer.addSelectionListener(new ITimeGraphSelectionListener() {
624 @Override
625 public void selectionChanged(TimeGraphSelectionEvent event) {
626 ITimeGraphEntry entry = fTimeGraphViewer.getSelection();
627 fInhibitTreeSelection = true; // block the tree selection changed listener
628 if (entry != null) {
629 StructuredSelection selection = new StructuredSelection(entry);
630 fTreeViewer.setSelection(selection);
631 } else {
632 fTreeViewer.setSelection(new StructuredSelection());
633 }
634 fInhibitTreeSelection = false;
635 alignTreeItems(false);
636 }
637 });
638
639 // ensure alignment of top item between tree and time graph
640 fTimeGraphViewer.getVerticalBar().addSelectionListener(new SelectionAdapter() {
641 @Override
642 public void widgetSelected(SelectionEvent e) {
643 alignTreeItems(false);
644 }
645 });
646
647 // ensure alignment of top item between tree and time graph
648 fTimeGraphViewer.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
649 @Override
650 public void mouseScrolled(MouseEvent e) {
651 alignTreeItems(false);
652 }
653 });
654
655 // ensure the tree has focus control when mouse is over it if the time graph had control
656 fTreeViewer.getControl().addMouseTrackListener(new MouseTrackAdapter() {
657 @Override
658 public void mouseEnter(MouseEvent e) {
659 if (fTimeGraphViewer.getTimeGraphControl().isFocusControl()) {
660 fTreeViewer.getControl().setFocus();
661 }
662 }
663 });
664
665 // ensure the time graph has focus control when mouse is over it if the tree had control
666 fTimeGraphViewer.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
667 @Override
668 public void mouseEnter(MouseEvent e) {
669 if (fTreeViewer.getControl().isFocusControl()) {
670 fTimeGraphViewer.getTimeGraphControl().setFocus();
671 }
672 }
673 });
674 fTimeGraphViewer.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
675 @Override
676 public void mouseEnter(MouseEvent e) {
677 if (fTreeViewer.getControl().isFocusControl()) {
678 fTimeGraphViewer.getTimeGraphControl().setFocus();
679 }
680 }
681 });
682
683 // The filler rows are required to ensure alignment when the tree does not have a
684 // visible horizontal scroll bar. The tree does not allow its top item to be set
685 // to a value that would cause blank space to be drawn at the bottom of the tree.
686 fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree, false);
687
688 fSashForm.setWeights(weights);
689
690 fTimeGraphViewer.getTimeGraphControl().addPaintListener(new PaintListener() {
691 @Override
692 public void paintControl(PaintEvent e) {
693 // Sashes in a SashForm are being created on layout so add the
694 // drag listener here
695 if (fSashDragListener == null) {
696 for (Control control : fSashForm.getChildren()) {
697 if (control instanceof Sash) {
698 fSashDragListener = new Listener() {
699
700 @Override
701 public void handleEvent(Event event) {
702 sendTimeViewAlignmentChanged();
703
704 }
705 };
706 control.removePaintListener(this);
707 control.addListener(SWT.Selection, fSashDragListener);
708 // There should be only one sash
709 break;
710 }
711 }
712 }
713 }
714 });
715 }
716
717 private boolean verticalZoom(boolean zoomIn) {
718 Tree tree = fTreeViewer.getTree();
719 FontData fontData = tree.getFont().getFontData()[0];
720 int height = fontData.getHeight() + (zoomIn ? 1 : -1);
721 if (height <= 0) {
722 return false;
723 }
724 fontData.setHeight(height);
725 if (fTreeFont != null) {
726 fTreeFont.dispose();
727 }
728 fTreeFont = new Font(tree.getDisplay(), fontData);
729 tree.setFont(fTreeFont);
730 redraw();
731 update();
732 fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
733 fTimeGraphViewer.setItemHeight(getItemHeight(tree, true));
734 alignTreeItems(false);
735 return true;
736 }
737
738 private void resetVerticalZoom() {
739 Tree tree = fTreeViewer.getTree();
740 if (fTreeFont != null) {
741 fTreeFont.dispose();
742 fTreeFont = null;
743 }
744 tree.setFont(null);
745 redraw();
746 update();
747 fTimeGraphViewer.setHeaderHeight(tree.getHeaderHeight());
748 fTimeGraphViewer.setItemHeight(getItemHeight(tree, true));
749 alignTreeItems(false);
750 }
751
752 private void sendTimeViewAlignmentChanged() {
753 TmfSignalManager.dispatchSignal(new TmfTimeViewAlignmentSignal(fSashForm, getTimeViewAlignmentInfo()));
754 }
755
756 // ------------------------------------------------------------------------
757 // Accessors
758 // ------------------------------------------------------------------------
759
760 /**
761 * Returns this time graph combo's tree viewer.
762 *
763 * @return the tree viewer
764 */
765 public TreeViewer getTreeViewer() {
766 return fTreeViewer;
767 }
768
769 /**
770 * Returns this time graph combo's time graph viewer.
771 *
772 * @return the time graph viewer
773 */
774 public @NonNull TimeGraphViewer getTimeGraphViewer() {
775 return fTimeGraphViewer;
776 }
777
778 /**
779 * Get the show filter dialog action.
780 *
781 * @return The Action object
782 * @since 2.0
783 */
784 public ShowFilterDialogAction getShowFilterDialogAction() {
785 if (fShowFilterDialogAction == null) {
786 fShowFilterDialogAction = new ShowFilterDialogAction(fTimeGraphViewer) {
787 @Override
788 protected void addFilter(ViewerFilter filter) {
789 /* add filter to the combo instead of the viewer */
790 TimeGraphCombo.this.addFilter(filter);
791 }
792
793 @Override
794 protected void removeFilter(ViewerFilter filter) {
795 /* remove filter from the combo instead of the viewer */
796 TimeGraphCombo.this.removeFilter(filter);
797 }
798
799 @Override
800 protected void refresh() {
801 /* refresh the combo instead of the viewer */
802 TimeGraphCombo.this.refresh();
803 }
804 };
805 }
806 return fShowFilterDialogAction;
807 }
808
809 // ------------------------------------------------------------------------
810 // Control
811 // ------------------------------------------------------------------------
812
813 @Override
814 public void redraw() {
815 fTimeGraphViewer.getControl().redraw();
816 super.redraw();
817 }
818
819 @Override
820 public void update() {
821 fTimeGraphViewer.getControl().update();
822 super.update();
823 }
824
825 // ------------------------------------------------------------------------
826 // Operations
827 // ------------------------------------------------------------------------
828
829 /**
830 * Sets the tree content provider used by this time graph combo.
831 *
832 * @param contentProvider the tree content provider
833 */
834 public void setTreeContentProvider(ITreeContentProvider contentProvider) {
835 fTreeViewer.setContentProvider(new TreeContentProviderWrapper(contentProvider));
836 }
837
838 /**
839 * Sets the tree label provider used by this time graph combo.
840 *
841 * @param labelProvider the tree label provider
842 */
843 public void setTreeLabelProvider(ITableLabelProvider labelProvider) {
844 fTreeViewer.setLabelProvider(new TreeLabelProviderWrapper(labelProvider));
845 }
846
847 /**
848 * Sets the tree content provider used by the filter dialog
849 *
850 * @param contentProvider the tree content provider
851 */
852 public void setFilterContentProvider(ITreeContentProvider contentProvider) {
853 getShowFilterDialogAction().getFilterDialog().setContentProvider(contentProvider);
854 }
855
856 /**
857 * Sets the tree label provider used by the filter dialog
858 *
859 * @param labelProvider the tree label provider
860 */
861 public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
862 getShowFilterDialogAction().getFilterDialog().setLabelProvider(labelProvider);
863 }
864
865 /**
866 * Adds a "check active" button used by the filter dialog
867 *
868 * @param activeProvider
869 * Additional button info specific to a certain view.
870 * @since 1.0
871 */
872 public void addTimeGraphFilterCheckActiveButton(ITimeGraphEntryActiveProvider activeProvider) {
873 getShowFilterDialogAction().getFilterDialog().addTimeGraphFilterCheckActiveButton(activeProvider);
874 }
875
876 /**
877 * Adds an "uncheck inactive" button used by the filter dialog
878 *
879 * @param inactiveProvider
880 * Additional button info specific to a certain view.
881 * @since 1.0
882 */
883 public void addTimeGraphFilterUncheckInactiveButton(ITimeGraphEntryActiveProvider inactiveProvider) {
884 getShowFilterDialogAction().getFilterDialog().addTimeGraphFilterUncheckInactiveButton(inactiveProvider);
885 }
886
887 /**
888 * Sets the tree columns for this time graph combo.
889 *
890 * @param columnNames the tree column names
891 */
892 public void setTreeColumns(String[] columnNames) {
893 final Tree tree = fTreeViewer.getTree();
894 for (String columnName : columnNames) {
895 TreeColumn column = new TreeColumn(tree, SWT.LEFT);
896 column.setText(columnName);
897 column.pack();
898 }
899 }
900
901 /**
902 * Sets the tree columns for this time graph combo's filter dialog.
903 *
904 * @param columnNames the tree column names
905 */
906 public void setFilterColumns(String[] columnNames) {
907 getShowFilterDialogAction().getFilterDialog().setColumnNames(columnNames);
908 }
909
910 /**
911 * Sets the time graph content provider used by this time graph combo.
912 *
913 * @param timeGraphContentProvider
914 * the time graph content provider
915 */
916 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider) {
917 fTimeGraphViewer.setTimeGraphContentProvider(timeGraphContentProvider);
918 }
919
920 /**
921 * Sets the time graph presentation provider used by this time graph combo.
922 *
923 * @param timeGraphProvider the time graph provider
924 */
925 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
926 fTimeGraphViewer.setTimeGraphProvider(timeGraphProvider);
927 }
928
929 /**
930 * Sets or clears the input for this time graph combo.
931 *
932 * @param input the input of this time graph combo, or <code>null</code> if none
933 */
934 public void setInput(Object input) {
935 fInhibitTreeSelection = true;
936 fTreeViewer.setInput(input);
937 for (SelectionListenerWrapper listenerWrapper : fSelectionListenerMap.values()) {
938 listenerWrapper.selection = null;
939 }
940 fInhibitTreeSelection = false;
941 if (fScrollBarsInTreeWorkaround) {
942 fTreeViewer.getTree().getVerticalBar().setEnabled(false);
943 fTreeViewer.getTree().getVerticalBar().setVisible(false);
944 }
945 fTimeGraphViewer.setInput(input);
946 fTimeGraphViewer.setItemHeight(getItemHeight(fTreeViewer.getTree(), false));
947 // queue the alignment update because in Linux the item bounds are not
948 // set properly until the tree has been painted at least once
949 fVisibleExpandedItems = null; // invalidate the cache
950 getDisplay().asyncExec(new Runnable() {
951 @Override
952 public void run() {
953 alignTreeItems(true);
954 }});
955 }
956
957 /**
958 * Gets the input for this time graph combo.
959 *
960 * @return The input of this time graph combo, or <code>null</code> if none
961 */
962 public Object getInput() {
963 return fTreeViewer.getInput();
964 }
965
966 /**
967 * Sets or clears the list of links to display on this combo
968 *
969 * @param links the links to display in this time graph combo
970 */
971 public void setLinks(List<ILinkEvent> links) {
972 fTimeGraphViewer.setLinks(links);
973 }
974
975 /**
976 * @param filter The filter object to be attached to the view
977 */
978 public void addFilter(@NonNull ViewerFilter filter) {
979 fInhibitTreeSelection = true;
980 ViewerFilter wrapper = new ViewerFilterWrapper(filter);
981 fTreeViewer.addFilter(wrapper);
982 fTimeGraphViewer.addFilter(filter);
983 fViewerFilterMap.put(filter, wrapper);
984 alignTreeItems(true);
985 fInhibitTreeSelection = false;
986 }
987
988 /**
989 * @param filter The filter object to be removed from the view
990 */
991 public void removeFilter(@NonNull ViewerFilter filter) {
992 fInhibitTreeSelection = true;
993 ViewerFilter wrapper = fViewerFilterMap.get(filter);
994 fTreeViewer.removeFilter(wrapper);
995 fTimeGraphViewer.removeFilter(filter);
996 fViewerFilterMap.remove(filter);
997 alignTreeItems(true);
998 fInhibitTreeSelection = false;
999 }
1000
1001 /**
1002 * Returns this viewer's filters.
1003 *
1004 * @return an array of viewer filters
1005 * @since 2.0
1006 */
1007 public @NonNull ViewerFilter[] getFilters() {
1008 return fTimeGraphViewer.getFilters();
1009 }
1010
1011 /**
1012 * Sets the filters, replacing any previous filters, and triggers
1013 * refiltering of the elements.
1014 *
1015 * @param filters
1016 * an array of viewer filters, or null
1017 * @since 2.0
1018 */
1019 public void setFilters(@NonNull ViewerFilter[] filters) {
1020 fInhibitTreeSelection = true;
1021 fViewerFilterMap.clear();
1022 if (filters == null) {
1023 fTreeViewer.resetFilters();
1024 } else {
1025 for (ViewerFilter filter : filters) {
1026 ViewerFilter wrapper = new ViewerFilterWrapper(filter);
1027 fViewerFilterMap.put(filter, wrapper);
1028 }
1029 ViewerFilter[] wrappers = Iterables.toArray(fViewerFilterMap.values(), ViewerFilter.class);
1030 fTreeViewer.setFilters(wrappers);
1031 }
1032 fTimeGraphViewer.setFilters(filters);
1033 alignTreeItems(true);
1034 fInhibitTreeSelection = false;
1035 }
1036
1037 /**
1038 * Refreshes this time graph completely with information freshly obtained from its model.
1039 */
1040 public void refresh() {
1041 fInhibitTreeSelection = true;
1042 Tree tree = fTreeViewer.getTree();
1043 try {
1044 tree.setRedraw(false);
1045 fTreeViewer.refresh();
1046 } finally {
1047 tree.setRedraw(true);
1048 }
1049 fTimeGraphViewer.refresh();
1050 alignTreeItems(true);
1051 fInhibitTreeSelection = false;
1052 }
1053
1054 /**
1055 * Adds a listener for selection changes in this time graph combo.
1056 *
1057 * @param listener a selection listener
1058 */
1059 public void addSelectionListener(ITimeGraphSelectionListener listener) {
1060 SelectionListenerWrapper listenerWrapper = new SelectionListenerWrapper(listener);
1061 fTreeViewer.addSelectionChangedListener(listenerWrapper);
1062 fSelectionListenerMap.put(listener, listenerWrapper);
1063 fTimeGraphViewer.addSelectionListener(listenerWrapper);
1064 }
1065
1066 /**
1067 * Removes the given selection listener from this time graph combo.
1068 *
1069 * @param listener a selection changed listener
1070 */
1071 public void removeSelectionListener(ITimeGraphSelectionListener listener) {
1072 SelectionListenerWrapper listenerWrapper = fSelectionListenerMap.remove(listener);
1073 fTreeViewer.removeSelectionChangedListener(listenerWrapper);
1074 fTimeGraphViewer.removeSelectionListener(listenerWrapper);
1075 }
1076
1077 /**
1078 * Sets the current selection for this time graph combo.
1079 *
1080 * @param selection the new selection
1081 */
1082 public void setSelection(ITimeGraphEntry selection) {
1083 fTimeGraphViewer.setSelection(selection);
1084 fInhibitTreeSelection = true; // block the tree selection changed listener
1085 if (selection != null) {
1086 StructuredSelection structuredSelection = new StructuredSelection(selection);
1087 fTreeViewer.setSelection(structuredSelection);
1088 } else {
1089 fTreeViewer.setSelection(new StructuredSelection());
1090 }
1091 fInhibitTreeSelection = false;
1092 alignTreeItems(false);
1093 }
1094
1095 /**
1096 * Sets the auto-expand level to be used for new entries discovered when
1097 * calling {@link #setInput(Object)} or {@link #refresh()}. The value 0
1098 * means that there is no auto-expand; 1 means that top-level entries are
1099 * expanded, but not their children; 2 means that top-level entries are
1100 * expanded, and their children, but not grand-children; and so on.
1101 * <p>
1102 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
1103 * </p>
1104 *
1105 * @param level
1106 * non-negative level, or <code>ALL_LEVELS</code> to expand all
1107 * levels of the tree
1108 */
1109 public void setAutoExpandLevel(int level) {
1110 fTimeGraphViewer.setAutoExpandLevel(level);
1111 if (level <= 0) {
1112 fTreeViewer.setAutoExpandLevel(level);
1113 } else {
1114 fTreeViewer.setAutoExpandLevel(level + 1);
1115 }
1116 }
1117
1118 /**
1119 * Returns the auto-expand level.
1120 *
1121 * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of
1122 * the tree are expanded automatically
1123 * @see #setAutoExpandLevel
1124 */
1125 public int getAutoExpandLevel() {
1126 return fTimeGraphViewer.getAutoExpandLevel();
1127 }
1128
1129 /**
1130 * Set the expanded state of an entry
1131 *
1132 * @param entry
1133 * The entry to expand/collapse
1134 * @param expanded
1135 * True for expanded, false for collapsed
1136 */
1137 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
1138 fTimeGraphViewer.setExpandedState(entry, expanded);
1139 fTreeViewer.setExpandedState(entry, expanded);
1140 alignTreeItems(true);
1141 }
1142
1143 /**
1144 * Collapses all nodes of the viewer's tree, starting with the root.
1145 */
1146 public void collapseAll() {
1147 fTimeGraphViewer.collapseAll();
1148 fTreeViewer.collapseAll();
1149 alignTreeItems(true);
1150 }
1151
1152 /**
1153 * Expands all nodes of the viewer's tree, starting with the root.
1154 */
1155 public void expandAll() {
1156 fTimeGraphViewer.expandAll();
1157 fTreeViewer.expandAll();
1158 alignTreeItems(true);
1159 }
1160
1161 // ------------------------------------------------------------------------
1162 // Internal
1163 // ------------------------------------------------------------------------
1164
1165 private List<TreeItem> getVisibleExpandedItems(Tree tree, boolean refresh) {
1166 if (fVisibleExpandedItems == null || refresh) {
1167 List<TreeItem> visibleExpandedItems = new ArrayList<>();
1168 addVisibleExpandedItems(visibleExpandedItems, tree.getItems());
1169 fVisibleExpandedItems = visibleExpandedItems;
1170 }
1171 return fVisibleExpandedItems;
1172 }
1173
1174 private void addVisibleExpandedItems(List<TreeItem> visibleExpandedItems, TreeItem[] items) {
1175 for (TreeItem item : items) {
1176 Object data = item.getData();
1177 if (data == FILLER) {
1178 break;
1179 }
1180 visibleExpandedItems.add(item);
1181 boolean expandedState = fTimeGraphViewer.getExpandedState((ITimeGraphEntry) data);
1182 if (item.getExpanded() != expandedState) {
1183 /* synchronize the expanded state of both viewers */
1184 fTreeViewer.setExpandedState(data, expandedState);
1185 }
1186 if (expandedState) {
1187 addVisibleExpandedItems(visibleExpandedItems, item.getItems());
1188 }
1189 }
1190 }
1191
1192 private int getItemHeight(final Tree tree, boolean force) {
1193 /*
1194 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
1195 */
1196 if (fLinuxItemHeight >= 0 && System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
1197 if (fLinuxItemHeight != 0 && !force) {
1198 return fLinuxItemHeight;
1199 }
1200
1201 if (getVisibleExpandedItems(tree, true).size() > 1) {
1202 PaintListener paintListener = new PaintListener() {
1203 @Override
1204 public void paintControl(PaintEvent e) {
1205 // get the treeItems here to have all items
1206 List<TreeItem> treeItems = getVisibleExpandedItems(tree, true);
1207 if (treeItems.size() < 2) {
1208 return;
1209 }
1210 final TreeItem treeItem0 = treeItems.get(0);
1211 final TreeItem treeItem1 = treeItems.get(1);
1212 tree.removePaintListener(this);
1213 int y0 = treeItem0.getBounds().y;
1214 int y1 = treeItem1.getBounds().y;
1215 int itemHeight = y1 - y0;
1216 if (itemHeight > 0) {
1217 fLinuxItemHeight = itemHeight;
1218 fTimeGraphViewer.setItemHeight(itemHeight);
1219 }
1220 }
1221 };
1222 tree.addPaintListener(paintListener);
1223 }
1224 } else {
1225 fLinuxItemHeight = -1; // Not Linux, don't perform os.name check anymore
1226 }
1227 return tree.getItemHeight();
1228 }
1229
1230 private void alignTreeItems(boolean refreshExpandedItems) {
1231 // align the tree top item with the time graph top item
1232 Tree tree = fTreeViewer.getTree();
1233 List<TreeItem> treeItems = getVisibleExpandedItems(tree, refreshExpandedItems);
1234 int topIndex = fTimeGraphViewer.getTopIndex();
1235 if (topIndex >= treeItems.size()) {
1236 return;
1237 }
1238 TreeItem item = treeItems.get(topIndex);
1239 tree.setTopItem(item);
1240
1241 /*
1242 * In GTK3, the bounds of the tree items are only sure to be correct
1243 * after the tree has been painted.
1244 */
1245 tree.addPaintListener(new PaintListener() {
1246 @Override
1247 public void paintControl(PaintEvent e) {
1248 tree.removePaintListener(this);
1249 doAlignTreeItems();
1250 redraw();
1251 /*
1252 * Bug in GTK. Calling setTopItem() can scroll to the wrong item
1253 * when the 'tree view' is dirty. Set it again once it is clean.
1254 */
1255 if (SWT.getPlatform().equals("gtk")) { //$NON-NLS-1$
1256 TreeItem topItem = tree.getTopItem();
1257 tree.getDisplay().asyncExec(() -> {
1258 tree.setTopItem(topItem);
1259 });
1260 }
1261 }
1262 });
1263 /* Make sure the paint event is triggered. */
1264 tree.redraw();
1265 }
1266
1267 private void doAlignTreeItems() {
1268 Tree tree = fTreeViewer.getTree();
1269 List<TreeItem> treeItems = getVisibleExpandedItems(tree, false);
1270 int topIndex = fTimeGraphViewer.getTopIndex();
1271 if (topIndex >= treeItems.size()) {
1272 return;
1273 }
1274 TreeItem item = treeItems.get(topIndex);
1275
1276 // get the first filler item so we can calculate the last item's height
1277 TreeItem fillerItem = null;
1278 for (TreeItem treeItem : fTreeViewer.getTree().getItems()) {
1279 if (treeItem.getData() == FILLER) {
1280 fillerItem = treeItem;
1281 break;
1282 }
1283 }
1284
1285 // ensure the time graph item heights are equal to the tree item heights
1286 int treeHeight = fTreeViewer.getTree().getBounds().height;
1287 int index = topIndex;
1288 Rectangle bounds = item.getBounds();
1289 while (index < treeItems.size()) {
1290 if (bounds.y > treeHeight) {
1291 break;
1292 }
1293 TreeItem nextItem = (index + 1 == treeItems.size()) ? fillerItem : treeItems.get(index + 1);
1294 Rectangle nextBounds = alignTreeItem(item, bounds, nextItem);
1295 index++;
1296 item = nextItem;
1297 bounds = nextBounds;
1298 }
1299
1300 /*
1301 * When an item's height in the time graph changes, it is possible that
1302 * the time graph readjusts its top index to fill empty space at the
1303 * bottom of the viewer. Calling method setTopIndex() triggers this
1304 * adjustment, if needed. In that case, we need to make sure that the
1305 * newly visible items at the top of the viewer are also aligned.
1306 */
1307 fTimeGraphViewer.setTopIndex(topIndex);
1308 if (fTimeGraphViewer.getTopIndex() != topIndex) {
1309 alignTreeItems(false);
1310 }
1311 }
1312
1313 private Rectangle alignTreeItem(TreeItem item, Rectangle bounds, TreeItem nextItem) {
1314 /*
1315 * Bug in Linux. The method getBounds doesn't always return the correct height.
1316 * Use the difference of y position between items to calculate the height.
1317 */
1318 Rectangle nextBounds = nextItem.getBounds();
1319 Integer itemHeight = nextBounds.y - bounds.y;
1320 if (itemHeight > 0) {
1321 ITimeGraphEntry entry = (ITimeGraphEntry) item.getData();
1322 fTimeGraphViewer.getTimeGraphControl().setItemHeight(entry, itemHeight);
1323 }
1324 return nextBounds;
1325 }
1326
1327 /**
1328 * Return the time alignment information
1329 *
1330 * @return the time alignment information
1331 *
1332 * @see ITmfTimeAligned
1333 *
1334 * @since 1.0
1335 */
1336 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
1337 Point location = fSashForm.toDisplay(0, 0);
1338 int timeAxisOffset = fTreeViewer.getControl().getSize().x + fSashForm.getSashWidth();
1339 return new TmfTimeViewAlignmentInfo(fSashForm.getShell(), location, timeAxisOffset);
1340 }
1341
1342 /**
1343 * Return the available width for the time-axis.
1344 *
1345 * @see ITmfTimeAligned
1346 *
1347 * @param requestedOffset
1348 * the requested offset
1349 * @return the available width for the time-axis
1350 *
1351 * @since 1.0
1352 */
1353 public int getAvailableWidth(int requestedOffset) {
1354 int vBarWidth = ((fTimeGraphViewer.getVerticalBar() != null) && (fTimeGraphViewer.getVerticalBar().isVisible())) ? fTimeGraphViewer.getVerticalBar().getSize().x : 0;
1355 int totalWidth = fSashForm.getBounds().width;
1356 return Math.min(totalWidth, Math.max(0, totalWidth - requestedOffset - vBarWidth));
1357 }
1358
1359 /**
1360 * Perform the alignment operation.
1361 *
1362 * @param offset
1363 * the alignment offset
1364 * @param width
1365 * the alignment width
1366 *
1367 * @see ITmfTimeAligned
1368 *
1369 * @since 1.0
1370 */
1371 public void performAlign(int offset, int width) {
1372 int total = fSashForm.getBounds().width;
1373 int timeAxisOffset = Math.min(offset, total);
1374 int width1 = Math.max(0, timeAxisOffset - fSashForm.getSashWidth());
1375 int width2 = total - timeAxisOffset;
1376 if (width1 >= 0 && width2 > 0 || width1 > 0 && width2 >= 0) {
1377 fSashForm.setWeights(new int[] { width1, width2 });
1378 fSashForm.layout();
1379 }
1380
1381 Composite composite = fTimeGraphViewer.getTimeAlignedComposite();
1382 GridLayout layout = (GridLayout) composite.getLayout();
1383 int timeBasedControlsWidth = composite.getSize().x;
1384 int marginSize = timeBasedControlsWidth - width;
1385 layout.marginRight = Math.max(0, marginSize);
1386 composite.layout();
1387 }
1388 }
This page took 0.078717 seconds and 4 git commands to generate.