1 /*******************************************************************************
2 * Copyright (c) 2012, 2016 Ericsson, others
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
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 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
;
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
;
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
.KeyEvent
;
45 import org
.eclipse
.swt
.events
.MouseAdapter
;
46 import org
.eclipse
.swt
.events
.MouseEvent
;
47 import org
.eclipse
.swt
.events
.MouseTrackAdapter
;
48 import org
.eclipse
.swt
.events
.PaintEvent
;
49 import org
.eclipse
.swt
.events
.PaintListener
;
50 import org
.eclipse
.swt
.events
.SelectionAdapter
;
51 import org
.eclipse
.swt
.events
.SelectionEvent
;
52 import org
.eclipse
.swt
.graphics
.Font
;
53 import org
.eclipse
.swt
.graphics
.FontData
;
54 import org
.eclipse
.swt
.graphics
.GC
;
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
.ITimeDataProvider
;
79 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphColorScheme
;
80 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphControl
;
81 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphMarkerAxis
;
83 import com
.google
.common
.collect
.Iterables
;
86 * Time graph "combo" view (with the list/tree on the left and the gantt chart
89 * @author Patrick Tasse
91 public class TimeGraphCombo
extends Composite
{
93 // ------------------------------------------------------------------------
95 // ------------------------------------------------------------------------
98 * Constant indicating that all levels of the time graph should be expanded
100 public static final int ALL_LEVELS
= AbstractTreeViewer
.ALL_LEVELS
;
102 private static final Object FILLER
= new Object();
104 // ------------------------------------------------------------------------
106 // ------------------------------------------------------------------------
108 /** The tree viewer */
109 private TreeViewer fTreeViewer
;
111 /** The time viewer */
112 private @NonNull TimeGraphViewer fTimeGraphViewer
;
114 /** The selection listener map */
115 private final Map
<ITimeGraphSelectionListener
, SelectionListenerWrapper
> fSelectionListenerMap
= new HashMap
<>();
117 /** The map of viewer filters to viewer filter wrappers */
118 private final Map
<@NonNull ViewerFilter
, @NonNull ViewerFilter
> fViewerFilterMap
= new HashMap
<>();
121 * Flag to block the tree selection changed listener when triggered by the
124 private boolean fInhibitTreeSelection
= false;
126 /** Number of filler rows used by the tree content provider */
127 private int fNumFillerRows
;
129 /** Calculated item height for Linux workaround */
130 private int fLinuxItemHeight
= 0;
132 /** The action that opens the filter dialog */
133 private ShowFilterDialogAction fShowFilterDialogAction
;
135 /** Default weight of each part of the sash */
136 private static final int[] DEFAULT_WEIGHTS
= { 1, 1 };
138 /** List of all expanded items whose parents are also expanded */
139 private List
<TreeItem
> fVisibleExpandedItems
= null;
141 private Listener fSashDragListener
;
142 private SashForm fSashForm
;
144 private final boolean fScrollBarsInTreeWorkaround
;
146 private Font fTreeFont
;
148 // ------------------------------------------------------------------------
150 // ------------------------------------------------------------------------
153 * The TimeGraphViewerExtension is used to set appropriate values and to
154 * override methods that could be called directly by the user and that must
155 * be handled by the time graph combo.
157 private class TimeGraphViewerExtension
extends TimeGraphViewer
{
159 private TimeGraphViewerExtension(Composite parent
, int style
, Tree tree
) {
160 super(parent
, style
);
161 setItemHeight(TimeGraphCombo
.this.getItemHeight(tree
, true));
162 setHeaderHeight(tree
.getHeaderHeight());
163 setBorderWidth(tree
.getBorderWidth());
168 public ShowFilterDialogAction
getShowFilterDialogAction() {
169 return TimeGraphCombo
.this.getShowFilterDialogAction();
173 protected TimeGraphControl
createTimeGraphControl(Composite composite
, TimeGraphColorScheme colors
) {
174 return new TimeGraphControl(composite
, colors
) {
176 public void verticalZoom(boolean zoomIn
) {
177 TimeGraphCombo
.this.verticalZoom(zoomIn
);
181 public void resetVerticalZoom() {
182 TimeGraphCombo
.this.resetVerticalZoom();
186 public void setElementPosition(ITimeGraphEntry entry
, int y
) {
188 * Queue the update to make sure the time graph combo has
189 * finished updating the item heights.
191 getDisplay().asyncExec(() -> {
195 super.setElementPosition(entry
, y
);
196 alignTreeItems(false);
202 private class TimeGraphMarkerAxisExtension
extends TimeGraphMarkerAxis
{
203 private int fMargin
= 0;
205 public TimeGraphMarkerAxisExtension(Composite parent
, @NonNull TimeGraphColorScheme colorScheme
, @NonNull ITimeDataProvider timeProvider
) {
206 super(parent
, colorScheme
, timeProvider
);
210 public Point
computeSize(int wHint
, int hHint
, boolean changed
) {
211 Point size
= super.computeSize(wHint
, hHint
, changed
);
219 public void redraw() {
221 fTreeViewer
.getControl().redraw();
225 protected void drawMarkerAxis(Rectangle bounds
, int nameSpace
, GC gc
) {
226 super.drawMarkerAxis(bounds
, nameSpace
, gc
);
229 private Rectangle
getAxisBounds() {
230 Tree tree
= fTreeViewer
.getTree();
231 Rectangle axisBounds
= getBounds();
232 Rectangle treeClientArea
= tree
.getClientArea();
233 if (axisBounds
.isEmpty()) {
234 treeClientArea
.y
+= treeClientArea
.height
;
235 treeClientArea
.height
= 0;
236 return treeClientArea
;
238 Composite axisParent
= getParent();
239 Point axisDisplayCoordinates
= axisParent
.toDisplay(axisBounds
.x
, axisBounds
.y
);
240 Point axisTreeCoordinates
= tree
.toControl(axisDisplayCoordinates
);
241 int height
= treeClientArea
.y
+ treeClientArea
.height
- axisTreeCoordinates
.y
;
242 int margin
= Math
.max(0, axisBounds
.height
- height
);
243 if (fMargin
!= margin
) {
245 getParent().layout();
247 axisTreeCoordinates
.y
-= margin
;
250 return new Rectangle(treeClientArea
.x
, axisTreeCoordinates
.y
, treeClientArea
.width
, height
);
255 protected TimeGraphMarkerAxis
createTimeGraphMarkerAxis(Composite parent
, @NonNull TimeGraphColorScheme colorScheme
, @NonNull ITimeDataProvider timeProvider
) {
256 TimeGraphMarkerAxisExtension timeGraphMarkerAxis
= new TimeGraphMarkerAxisExtension(parent
, colorScheme
, timeProvider
);
257 Tree tree
= fTreeViewer
.getTree();
258 tree
.addPaintListener(e
-> {
260 * Draw the marker axis over the tree. Only the name area will
261 * be drawn, since the time area has zero width.
263 Rectangle bounds
= timeGraphMarkerAxis
.getAxisBounds();
264 e
.gc
.setBackground(timeGraphMarkerAxis
.getBackground());
265 timeGraphMarkerAxis
.drawMarkerAxis(bounds
, bounds
.width
, e
.gc
);
267 tree
.addMouseListener(new MouseAdapter() {
269 public void mouseDown(MouseEvent e
) {
270 Rectangle bounds
= timeGraphMarkerAxis
.getAxisBounds();
271 if (bounds
.contains(e
.x
, e
.y
)) {
272 timeGraphMarkerAxis
.mouseDown(e
, bounds
, bounds
.width
);
276 tree
.getHorizontalBar().addSelectionListener(new SelectionAdapter() {
278 public void widgetSelected(SelectionEvent e
) {
282 return timeGraphMarkerAxis
;
287 * The TreeContentProviderWrapper is used to insert filler items after the
288 * elements of the tree's real content provider.
290 private class TreeContentProviderWrapper
implements ITreeContentProvider
{
291 private final ITreeContentProvider contentProvider
;
293 public TreeContentProviderWrapper(ITreeContentProvider contentProvider
) {
294 this.contentProvider
= contentProvider
;
298 public void dispose() {
299 contentProvider
.dispose();
303 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
304 contentProvider
.inputChanged(viewer
, oldInput
, newInput
);
308 public Object
[] getElements(Object inputElement
) {
309 Object
[] elements
= contentProvider
.getElements(inputElement
);
310 // add filler elements to ensure alignment with time analysis viewer
311 Object
[] oElements
= Arrays
.copyOf(elements
, elements
.length
+ fNumFillerRows
, Object
[].class);
312 for (int i
= 0; i
< fNumFillerRows
; i
++) {
313 oElements
[elements
.length
+ i
] = FILLER
;
319 public Object
[] getChildren(Object parentElement
) {
320 if (parentElement
instanceof ITimeGraphEntry
) {
321 return contentProvider
.getChildren(parentElement
);
323 return new Object
[0];
327 public Object
getParent(Object element
) {
328 if (element
instanceof ITimeGraphEntry
) {
329 return contentProvider
.getParent(element
);
335 public boolean hasChildren(Object element
) {
336 if (element
instanceof ITimeGraphEntry
) {
337 return contentProvider
.hasChildren(element
);
344 * The TreeLabelProviderWrapper is used to intercept the filler items from
345 * the calls to the tree's real label provider.
347 private static class TreeLabelProviderWrapper
implements ITableLabelProvider
{
348 private final ITableLabelProvider labelProvider
;
350 public TreeLabelProviderWrapper(ITableLabelProvider labelProvider
) {
351 this.labelProvider
= labelProvider
;
355 public void addListener(ILabelProviderListener listener
) {
356 labelProvider
.addListener(listener
);
360 public void dispose() {
361 labelProvider
.dispose();
365 public boolean isLabelProperty(Object element
, String property
) {
366 if (element
instanceof ITimeGraphEntry
) {
367 return labelProvider
.isLabelProperty(element
, property
);
373 public void removeListener(ILabelProviderListener listener
) {
374 labelProvider
.removeListener(listener
);
378 public Image
getColumnImage(Object element
, int columnIndex
) {
379 if (element
instanceof ITimeGraphEntry
) {
380 return labelProvider
.getColumnImage(element
, columnIndex
);
386 public String
getColumnText(Object element
, int columnIndex
) {
387 if (element
instanceof ITimeGraphEntry
) {
388 return labelProvider
.getColumnText(element
, columnIndex
);
396 * The SelectionListenerWrapper is used to intercept the filler items from
397 * the time graph combo's real selection listener, and to prevent double
398 * notifications from being sent when selection changes in both tree and
399 * time graph at the same time.
401 private class SelectionListenerWrapper
implements ISelectionChangedListener
, ITimeGraphSelectionListener
{
402 private final ITimeGraphSelectionListener listener
;
403 private ITimeGraphEntry selection
= null;
405 public SelectionListenerWrapper(ITimeGraphSelectionListener listener
) {
406 this.listener
= listener
;
410 public void selectionChanged(SelectionChangedEvent event
) {
411 if (fInhibitTreeSelection
) {
414 Object element
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
415 if (element
instanceof ITimeGraphEntry
) {
416 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
417 if (entry
!= selection
) {
419 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
425 public void selectionChanged(TimeGraphSelectionEvent event
) {
426 ITimeGraphEntry entry
= event
.getSelection();
427 if (entry
!= selection
) {
429 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
435 * The ViewerFilterWrapper is used to intercept the filler items from the
436 * time graph combo's real ViewerFilters. These filler items should always
439 private static class ViewerFilterWrapper
extends ViewerFilter
{
441 private ViewerFilter fWrappedFilter
;
443 ViewerFilterWrapper(ViewerFilter filter
) {
445 this.fWrappedFilter
= filter
;
449 public boolean select(Viewer viewer
, Object parentElement
, Object element
) {
450 if (element
instanceof ITimeGraphEntry
) {
451 return fWrappedFilter
.select(viewer
, parentElement
, element
);
458 // ------------------------------------------------------------------------
460 // ------------------------------------------------------------------------
463 * Constructs a new instance of this class given its parent and a style
464 * value describing its behavior and appearance.
467 * a widget which will be the parent of the new instance (cannot
470 * the style of widget to construct
472 public TimeGraphCombo(Composite parent
, int style
) {
473 this(parent
, style
, DEFAULT_WEIGHTS
);
477 * Constructs a new instance of this class given its parent and a style
478 * value describing its behavior and appearance.
481 * a widget which will be the parent of the new instance (cannot
484 * the style of widget to construct
486 * The array (length 2) of relative weights of each side of the sash form
488 public TimeGraphCombo(Composite parent
, int style
, int[] weights
) {
489 super(parent
, style
);
490 setLayout(new FillLayout());
492 fSashForm
= new SashForm(this, SWT
.NONE
);
495 * In Windows, SWT.H_SCROLL | SWT.NO_SCROLL is not properly supported,
496 * both scroll bars are always created. See Tree.checkStyle: "Even when
497 * WS_HSCROLL or WS_VSCROLL is not specified, Windows creates trees and
498 * tables with scroll bars."
500 fScrollBarsInTreeWorkaround
= "win32".equals(SWT
.getPlatform()); //$NON-NLS-1$
502 int scrollBarStyle
= fScrollBarsInTreeWorkaround ? SWT
.H_SCROLL
: SWT
.H_SCROLL
| SWT
.NO_SCROLL
;
504 fTreeViewer
= new TreeViewer(fSashForm
, SWT
.FULL_SELECTION
| scrollBarStyle
);
505 fTreeViewer
.setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
506 final Tree tree
= fTreeViewer
.getTree();
507 tree
.setHeaderVisible(true);
508 tree
.setLinesVisible(true);
510 fTimeGraphViewer
= new TimeGraphViewerExtension(fSashForm
, SWT
.NONE
, tree
);
512 if (fScrollBarsInTreeWorkaround
) {
513 // Feature in Windows. The tree vertical bar reappears when
514 // the control is resized so we need to hide it again.
515 tree
.addControlListener(new ControlAdapter() {
516 private int depth
= 0;
519 public void controlResized(ControlEvent e
) {
522 tree
.getVerticalBar().setEnabled(false);
523 // this can trigger controlResized recursively
524 tree
.getVerticalBar().setVisible(false);
530 // Bug in Linux. The tree header height is 0 in constructor,
531 // so we need to reset it later when the control is painted.
532 // This work around used to be done on control resized but the header
533 // height was not initialized on the initial resize on GTK3.
534 tree
.addPaintListener(new PaintListener() {
537 public void paintControl(PaintEvent e
) {
538 int headerHeight
= tree
.getHeaderHeight();
539 if (headerHeight
> 0) {
540 fTimeGraphViewer
.setHeaderHeight(headerHeight
);
541 tree
.removePaintListener(this);
546 tree
.addDisposeListener(e
-> {
547 if (fTreeFont
!= null) {
552 // ensure synchronization of expanded items between tree and time graph
553 fTreeViewer
.addTreeListener(new ITreeViewerListener() {
555 public void treeCollapsed(TreeExpansionEvent event
) {
556 fTimeGraphViewer
.setExpandedState((ITimeGraphEntry
) event
.getElement(), false);
557 // queue the alignment update because the tree items may only be
558 // actually collapsed after the listeners have been notified
559 fVisibleExpandedItems
= null; // invalidate the cache
560 getDisplay().asyncExec(new Runnable() {
563 alignTreeItems(true);
568 public void treeExpanded(TreeExpansionEvent event
) {
569 ITimeGraphEntry entry
= (ITimeGraphEntry
) event
.getElement();
570 fTimeGraphViewer
.setExpandedState(entry
, true);
571 Set
<Object
> expandedElements
= new HashSet
<>(Arrays
.asList(fTreeViewer
.getExpandedElements()));
572 for (ITimeGraphEntry child
: entry
.getChildren()) {
573 if (child
.hasChildren()) {
574 boolean expanded
= expandedElements
.contains(child
);
575 fTimeGraphViewer
.setExpandedState(child
, expanded
);
578 // queue the alignment update because the tree items may only be
579 // actually expanded after the listeners have been notified
580 fVisibleExpandedItems
= null; // invalidate the cache
581 getDisplay().asyncExec(new Runnable() {
584 alignTreeItems(true);
589 // ensure synchronization of expanded items between tree and time graph
590 fTimeGraphViewer
.addTreeListener(new ITimeGraphTreeListener() {
592 public void treeCollapsed(TimeGraphTreeExpansionEvent event
) {
593 fTreeViewer
.setExpandedState(event
.getEntry(), false);
594 alignTreeItems(true);
598 public void treeExpanded(TimeGraphTreeExpansionEvent event
) {
599 ITimeGraphEntry entry
= event
.getEntry();
600 fTreeViewer
.setExpandedState(entry
, true);
601 Set
<Object
> expandedElements
= new HashSet
<>(Arrays
.asList(fTreeViewer
.getExpandedElements()));
602 for (ITimeGraphEntry child
: entry
.getChildren()) {
603 if (child
.hasChildren()) {
604 boolean expanded
= expandedElements
.contains(child
);
605 fTimeGraphViewer
.setExpandedState(child
, expanded
);
608 alignTreeItems(true);
612 // prevent mouse button from selecting a filler tree item
613 tree
.addListener(SWT
.MouseDown
, event
-> {
614 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, false);
615 if (treeItems
.isEmpty()) {
617 fTreeViewer
.setSelection(new StructuredSelection());
618 fTimeGraphViewer
.setSelection(null);
621 TreeItem lastTreeItem
= treeItems
.get(treeItems
.size() - 1);
622 if (event
.y
>= lastTreeItem
.getBounds().y
+ lastTreeItem
.getBounds().height
) {
624 // this prevents from scrolling up when selecting
625 // the partially visible tree item at the bottom
626 tree
.select(treeItems
.get(treeItems
.size() - 1));
627 fTreeViewer
.setSelection(new StructuredSelection());
628 fTimeGraphViewer
.setSelection(null);
632 // prevent mouse wheel from scrolling down into filler tree items
633 tree
.addListener(SWT
.MouseWheel
, event
-> {
635 if (event
.count
== 0) {
638 Slider scrollBar
= fTimeGraphViewer
.getVerticalBar();
639 fTimeGraphViewer
.setTopIndex(scrollBar
.getSelection() - event
.count
);
640 alignTreeItems(false);
643 // prevent key stroke from selecting a filler tree item
644 tree
.addListener(SWT
.KeyDown
, event
-> {
645 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, false);
646 if (treeItems
.size() == 0) {
647 fTreeViewer
.setSelection(new StructuredSelection());
651 if (event
.keyCode
== SWT
.ARROW_DOWN
) {
652 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + 1, treeItems
.size() - 1);
653 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
655 } else if (event
.keyCode
== SWT
.PAGE_DOWN
) {
656 int height
= tree
.getSize().y
- tree
.getHeaderHeight() - tree
.getHorizontalBar().getSize().y
;
657 int countPerPage
= height
/ getItemHeight(tree
, false);
658 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + countPerPage
- 1, treeItems
.size() - 1);
659 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
661 } else if (event
.keyCode
== SWT
.END
) {
662 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(treeItems
.size() - 1).getData());
664 } else if ((event
.character
== '+' || event
.character
== '=') && ((event
.stateMask
& SWT
.CTRL
) != 0)) {
665 fTimeGraphViewer
.getTimeGraphControl().keyPressed(new KeyEvent(event
));
667 } else if (event
.character
== '-' && ((event
.stateMask
& SWT
.CTRL
) != 0)) {
668 fTimeGraphViewer
.getTimeGraphControl().keyPressed(new KeyEvent(event
));
670 } else if (event
.character
== '0' && ((event
.stateMask
& SWT
.CTRL
) != 0)) {
671 fTimeGraphViewer
.getTimeGraphControl().keyPressed(new KeyEvent(event
));
676 if (fTimeGraphViewer
.getSelectionIndex() >= 0) {
677 fTreeViewer
.setSelection(new StructuredSelection(fTimeGraphViewer
.getSelection()));
679 fTreeViewer
.setSelection(new StructuredSelection());
681 alignTreeItems(false);
684 // ensure alignment of top item between tree and time graph
685 fTimeGraphViewer
.getTimeGraphControl().addControlListener(new ControlAdapter() {
687 public void controlResized(ControlEvent e
) {
688 alignTreeItems(false);
692 // ensure synchronization of selected item between tree and time graph
693 fTreeViewer
.addSelectionChangedListener(event
-> {
694 if (fInhibitTreeSelection
) {
697 if (event
.getSelection() instanceof IStructuredSelection
) {
698 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
699 if (selection
instanceof ITimeGraphEntry
) {
700 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) selection
);
702 alignTreeItems(false);
706 // ensure synchronization of selected item between tree and time graph
707 fTimeGraphViewer
.addSelectionListener(event
-> {
708 ITimeGraphEntry entry
= fTimeGraphViewer
.getSelection();
709 setSelectionInTree(entry
);
712 // ensure alignment of top item between tree and time graph
713 fTimeGraphViewer
.getVerticalBar().addSelectionListener(new SelectionAdapter() {
716 public void widgetSelected(SelectionEvent e
) {
717 alignTreeItems(false);
721 // ensure alignment of top item between tree and time graph
722 fTimeGraphViewer
.getTimeGraphControl().addMouseWheelListener(e
-> {
726 alignTreeItems(false);
729 // ensure the tree has focus control when mouse is over it if the time graph had control
730 fTreeViewer
.getControl().addMouseTrackListener(new MouseTrackAdapter() {
732 public void mouseEnter(MouseEvent e
) {
733 if (fTimeGraphViewer
.getTimeGraphControl().isFocusControl()) {
734 fTreeViewer
.getControl().setFocus();
739 // ensure the time graph has focus control when mouse is over it if the tree had control
740 fTimeGraphViewer
.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
742 public void mouseEnter(MouseEvent e
) {
743 if (fTreeViewer
.getControl().isFocusControl()) {
744 fTimeGraphViewer
.getTimeGraphControl().setFocus();
748 fTimeGraphViewer
.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
750 public void mouseEnter(MouseEvent e
) {
751 if (fTreeViewer
.getControl().isFocusControl()) {
752 fTimeGraphViewer
.getTimeGraphControl().setFocus();
757 // The filler rows are required to ensure alignment when the tree does not have a
758 // visible horizontal scroll bar. The tree does not allow its top item to be set
759 // to a value that would cause blank space to be drawn at the bottom of the tree.
760 fNumFillerRows
= Display
.getDefault().getBounds().height
/ getItemHeight(tree
, false);
762 fSashForm
.setWeights(weights
);
764 fTimeGraphViewer
.getTimeGraphControl().addPaintListener(new PaintListener() {
766 public void paintControl(PaintEvent e
) {
767 // Sashes in a SashForm are being created on layout so add the
768 // drag listener here
769 if (fSashDragListener
== null) {
770 for (Control control
: fSashForm
.getChildren()) {
771 if (control
instanceof Sash
) {
772 fSashDragListener
= new Listener() {
775 public void handleEvent(Event event
) {
776 sendTimeViewAlignmentChanged();
780 control
.removePaintListener(this);
781 control
.addListener(SWT
.Selection
, fSashDragListener
);
782 // There should be only one sash
791 private void verticalZoom(boolean zoomIn
) {
792 Tree tree
= fTreeViewer
.getTree();
793 FontData fontData
= tree
.getFont().getFontData()[0];
794 int height
= fontData
.getHeight() + (zoomIn ?
1 : -1);
798 fontData
.setHeight(height
);
799 if (fTreeFont
!= null) {
802 fTreeFont
= new Font(tree
.getDisplay(), fontData
);
803 tree
.setFont(fTreeFont
);
806 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
807 fTimeGraphViewer
.setItemHeight(getItemHeight(tree
, true));
808 alignTreeItems(false);
811 private void resetVerticalZoom() {
812 Tree tree
= fTreeViewer
.getTree();
813 if (fTreeFont
!= null) {
820 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
821 fTimeGraphViewer
.setItemHeight(getItemHeight(tree
, true));
822 alignTreeItems(false);
825 private void sendTimeViewAlignmentChanged() {
826 TmfSignalManager
.dispatchSignal(new TmfTimeViewAlignmentSignal(fSashForm
, getTimeViewAlignmentInfo()));
829 // ------------------------------------------------------------------------
831 // ------------------------------------------------------------------------
834 * Returns this time graph combo's tree viewer.
836 * @return the tree viewer
838 public TreeViewer
getTreeViewer() {
843 * Returns this time graph combo's time graph viewer.
845 * @return the time graph viewer
847 public @NonNull TimeGraphViewer
getTimeGraphViewer() {
848 return fTimeGraphViewer
;
852 * Get the show filter dialog action.
854 * @return The Action object
857 public ShowFilterDialogAction
getShowFilterDialogAction() {
858 if (fShowFilterDialogAction
== null) {
859 fShowFilterDialogAction
= new ShowFilterDialogAction(fTimeGraphViewer
) {
861 protected void addFilter(ViewerFilter filter
) {
862 /* add filter to the combo instead of the viewer */
863 TimeGraphCombo
.this.addFilter(filter
);
867 protected void removeFilter(ViewerFilter filter
) {
868 /* remove filter from the combo instead of the viewer */
869 TimeGraphCombo
.this.removeFilter(filter
);
873 protected void refresh() {
874 /* refresh the combo instead of the viewer */
875 TimeGraphCombo
.this.refresh();
879 return fShowFilterDialogAction
;
882 // ------------------------------------------------------------------------
884 // ------------------------------------------------------------------------
887 public void redraw() {
888 fTimeGraphViewer
.getControl().redraw();
893 public void update() {
894 fTimeGraphViewer
.getControl().update();
898 // ------------------------------------------------------------------------
900 // ------------------------------------------------------------------------
903 * Sets the tree content provider used by this time graph combo.
905 * @param contentProvider
906 * the tree content provider
908 public void setTreeContentProvider(ITreeContentProvider contentProvider
) {
909 fTreeViewer
.setContentProvider(new TreeContentProviderWrapper(contentProvider
));
913 * Sets the tree label provider used by this time graph combo.
915 * @param labelProvider
916 * the tree label provider
918 public void setTreeLabelProvider(ITableLabelProvider labelProvider
) {
919 fTreeViewer
.setLabelProvider(new TreeLabelProviderWrapper(labelProvider
));
923 * Sets the tree content provider used by the filter dialog
925 * @param contentProvider
926 * the tree content provider
928 public void setFilterContentProvider(ITreeContentProvider contentProvider
) {
929 getShowFilterDialogAction().getFilterDialog().setContentProvider(contentProvider
);
933 * Sets the tree label provider used by the filter dialog
935 * @param labelProvider
936 * the tree label provider
938 public void setFilterLabelProvider(ITableLabelProvider labelProvider
) {
939 getShowFilterDialogAction().getFilterDialog().setLabelProvider(labelProvider
);
943 * Adds a "check active" button used by the filter dialog
945 * @param activeProvider
946 * Additional button info specific to a certain view.
949 public void addTimeGraphFilterCheckActiveButton(ITimeGraphEntryActiveProvider activeProvider
) {
950 getShowFilterDialogAction().getFilterDialog().addTimeGraphFilterCheckActiveButton(activeProvider
);
954 * Adds an "uncheck inactive" button used by the filter dialog
956 * @param inactiveProvider
957 * Additional button info specific to a certain view.
960 public void addTimeGraphFilterUncheckInactiveButton(ITimeGraphEntryActiveProvider inactiveProvider
) {
961 getShowFilterDialogAction().getFilterDialog().addTimeGraphFilterUncheckInactiveButton(inactiveProvider
);
965 * Sets the tree columns for this time graph combo.
968 * the tree column names
970 public void setTreeColumns(String
[] columnNames
) {
971 final Tree tree
= fTreeViewer
.getTree();
972 for (String columnName
: columnNames
) {
973 TreeColumn column
= new TreeColumn(tree
, SWT
.LEFT
);
974 column
.setMoveable(true);
975 column
.setText(columnName
);
981 * Sets the tree columns for this time graph combo's filter dialog.
984 * the tree column names
986 public void setFilterColumns(String
[] columnNames
) {
987 getShowFilterDialogAction().getFilterDialog().setColumnNames(columnNames
);
991 * Sets the time graph content provider used by this time graph combo.
993 * @param timeGraphContentProvider
994 * the time graph content provider
996 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider
) {
997 fTimeGraphViewer
.setTimeGraphContentProvider(timeGraphContentProvider
);
1001 * Sets the time graph presentation provider used by this time graph combo.
1003 * @param timeGraphProvider
1004 * the time graph provider
1006 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider
) {
1007 fTimeGraphViewer
.setTimeGraphProvider(timeGraphProvider
);
1011 * Sets or clears the input for this time graph combo.
1014 * the input of this time graph combo, or <code>null</code> if
1017 public void setInput(Object input
) {
1018 fInhibitTreeSelection
= true;
1019 fTreeViewer
.setInput(input
);
1020 for (SelectionListenerWrapper listenerWrapper
: fSelectionListenerMap
.values()) {
1021 listenerWrapper
.selection
= null;
1023 fInhibitTreeSelection
= false;
1024 if (fScrollBarsInTreeWorkaround
) {
1025 fTreeViewer
.getTree().getVerticalBar().setEnabled(false);
1026 fTreeViewer
.getTree().getVerticalBar().setVisible(false);
1028 fTimeGraphViewer
.setInput(input
);
1029 fTimeGraphViewer
.setItemHeight(getItemHeight(fTreeViewer
.getTree(), false));
1030 // queue the alignment update because in Linux the item bounds are not
1031 // set properly until the tree has been painted at least once
1032 fVisibleExpandedItems
= null; // invalidate the cache
1033 getDisplay().asyncExec(new Runnable() {
1039 alignTreeItems(true);
1045 * Gets the input for this time graph combo.
1047 * @return The input of this time graph combo, or <code>null</code> if none
1049 public Object
getInput() {
1050 return fTreeViewer
.getInput();
1054 * Sets or clears the list of links to display on this combo
1057 * the links to display in this time graph combo
1059 public void setLinks(List
<ILinkEvent
> links
) {
1060 fTimeGraphViewer
.setLinks(links
);
1065 * The filter object to be attached to the view
1067 public void addFilter(@NonNull ViewerFilter filter
) {
1068 fInhibitTreeSelection
= true;
1069 ViewerFilter wrapper
= new ViewerFilterWrapper(filter
);
1070 fTreeViewer
.addFilter(wrapper
);
1071 fTimeGraphViewer
.addFilter(filter
);
1072 fViewerFilterMap
.put(filter
, wrapper
);
1073 alignTreeItems(true);
1074 fInhibitTreeSelection
= false;
1079 * The filter object to be removed from the view
1081 public void removeFilter(@NonNull ViewerFilter filter
) {
1082 fInhibitTreeSelection
= true;
1083 ViewerFilter wrapper
= fViewerFilterMap
.get(filter
);
1084 fTreeViewer
.removeFilter(wrapper
);
1085 fTimeGraphViewer
.removeFilter(filter
);
1086 fViewerFilterMap
.remove(filter
);
1087 alignTreeItems(true);
1088 fInhibitTreeSelection
= false;
1092 * Returns this viewer's filters.
1094 * @return an array of viewer filters
1097 public @NonNull ViewerFilter
[] getFilters() {
1098 return fTimeGraphViewer
.getFilters();
1102 * Sets the filters, replacing any previous filters, and triggers
1103 * refiltering of the elements.
1106 * an array of viewer filters, or null
1109 public void setFilters(@NonNull ViewerFilter
[] filters
) {
1110 fInhibitTreeSelection
= true;
1111 fViewerFilterMap
.clear();
1112 if (filters
== null) {
1113 fTreeViewer
.resetFilters();
1115 for (ViewerFilter filter
: filters
) {
1116 ViewerFilter wrapper
= new ViewerFilterWrapper(filter
);
1117 fViewerFilterMap
.put(filter
, wrapper
);
1119 ViewerFilter
[] wrappers
= Iterables
.toArray(fViewerFilterMap
.values(), ViewerFilter
.class);
1120 fTreeViewer
.setFilters(wrappers
);
1122 fTimeGraphViewer
.setFilters(filters
);
1123 alignTreeItems(true);
1124 fInhibitTreeSelection
= false;
1128 * Refreshes this time graph completely with information freshly obtained
1131 public void refresh() {
1132 fInhibitTreeSelection
= true;
1133 Tree tree
= fTreeViewer
.getTree();
1135 tree
.setRedraw(false);
1136 fTreeViewer
.refresh();
1138 tree
.setRedraw(true);
1140 fTimeGraphViewer
.refresh();
1141 alignTreeItems(true);
1142 fInhibitTreeSelection
= false;
1146 * Adds a listener for selection changes in this time graph combo.
1149 * a selection listener
1151 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
1152 SelectionListenerWrapper listenerWrapper
= new SelectionListenerWrapper(listener
);
1153 fTreeViewer
.addSelectionChangedListener(listenerWrapper
);
1154 fSelectionListenerMap
.put(listener
, listenerWrapper
);
1155 fTimeGraphViewer
.addSelectionListener(listenerWrapper
);
1159 * Removes the given selection listener from this time graph combo.
1162 * a selection changed listener
1164 public void removeSelectionListener(ITimeGraphSelectionListener listener
) {
1165 SelectionListenerWrapper listenerWrapper
= fSelectionListenerMap
.remove(listener
);
1166 fTreeViewer
.removeSelectionChangedListener(listenerWrapper
);
1167 fTimeGraphViewer
.removeSelectionListener(listenerWrapper
);
1171 * Sets the current selection for this time graph combo.
1176 public void setSelection(ITimeGraphEntry selection
) {
1177 fTimeGraphViewer
.setSelection(selection
);
1178 setSelectionInTree(selection
);
1182 * Sets the current selection for this time graph combo and reveal it if
1189 public void selectAndReveal(@NonNull ITimeGraphEntry selection
) {
1190 fTimeGraphViewer
.selectAndReveal(selection
);
1191 setSelectionInTree(selection
);
1195 * Select the entry in the tree structure
1200 private void setSelectionInTree(ITimeGraphEntry selection
) {
1201 fInhibitTreeSelection
= true; // block the tree selection changed
1203 if (selection
!= null) {
1204 StructuredSelection structuredSelection
= new StructuredSelection(selection
);
1205 fTreeViewer
.setSelection(structuredSelection
);
1207 fTreeViewer
.setSelection(new StructuredSelection());
1209 fInhibitTreeSelection
= false;
1210 alignTreeItems(false);
1214 * Sets the auto-expand level to be used for new entries discovered when
1215 * calling {@link #setInput(Object)} or {@link #refresh()}. The value 0
1216 * means that there is no auto-expand; 1 means that top-level entries are
1217 * expanded, but not their children; 2 means that top-level entries are
1218 * expanded, and their children, but not grand-children; and so on.
1220 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
1224 * non-negative level, or <code>ALL_LEVELS</code> to expand all
1225 * levels of the tree
1227 public void setAutoExpandLevel(int level
) {
1228 fTimeGraphViewer
.setAutoExpandLevel(level
);
1230 fTreeViewer
.setAutoExpandLevel(level
);
1232 fTreeViewer
.setAutoExpandLevel(level
+ 1);
1237 * Returns the auto-expand level.
1239 * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of
1240 * the tree are expanded automatically
1241 * @see #setAutoExpandLevel
1243 public int getAutoExpandLevel() {
1244 return fTimeGraphViewer
.getAutoExpandLevel();
1248 * Get the expanded state of an entry.
1252 * @return true if the entry is expanded, false if collapsed
1255 public boolean getExpandedState(ITimeGraphEntry entry
) {
1256 return fTimeGraphViewer
.getExpandedState(entry
);
1260 * Set the expanded state of an entry
1263 * The entry to expand/collapse
1265 * True for expanded, false for collapsed
1267 public void setExpandedState(ITimeGraphEntry entry
, boolean expanded
) {
1268 fTimeGraphViewer
.setExpandedState(entry
, expanded
);
1269 fTreeViewer
.setExpandedState(entry
, expanded
);
1270 alignTreeItems(true);
1274 * Collapses all nodes of the viewer's tree, starting with the root.
1276 public void collapseAll() {
1277 fTimeGraphViewer
.collapseAll();
1278 fTreeViewer
.collapseAll();
1279 alignTreeItems(true);
1283 * Expands all nodes of the viewer's tree, starting with the root.
1285 public void expandAll() {
1286 fTimeGraphViewer
.expandAll();
1287 fTreeViewer
.expandAll();
1288 alignTreeItems(true);
1291 // ------------------------------------------------------------------------
1293 // ------------------------------------------------------------------------
1295 private List
<TreeItem
> getVisibleExpandedItems(Tree tree
, boolean refresh
) {
1296 if (fVisibleExpandedItems
== null || refresh
) {
1297 List
<TreeItem
> visibleExpandedItems
= new ArrayList
<>();
1298 addVisibleExpandedItems(visibleExpandedItems
, tree
.getItems());
1299 fVisibleExpandedItems
= visibleExpandedItems
;
1301 return fVisibleExpandedItems
;
1304 private void addVisibleExpandedItems(List
<TreeItem
> visibleExpandedItems
, TreeItem
[] items
) {
1305 for (TreeItem item
: items
) {
1306 Object data
= item
.getData();
1307 if (data
== FILLER
) {
1310 visibleExpandedItems
.add(item
);
1311 boolean expandedState
= fTimeGraphViewer
.getExpandedState((ITimeGraphEntry
) data
);
1312 if (item
.getExpanded() != expandedState
) {
1313 /* synchronize the expanded state of both viewers */
1314 fTreeViewer
.setExpandedState(data
, expandedState
);
1316 if (expandedState
) {
1317 addVisibleExpandedItems(visibleExpandedItems
, item
.getItems());
1322 private int getItemHeight(final Tree tree
, boolean force
) {
1324 * Bug in Linux. The method getItemHeight doesn't always return the
1327 if (fLinuxItemHeight
>= 0 && System
.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
1328 if (fLinuxItemHeight
!= 0 && !force
) {
1329 return fLinuxItemHeight
;
1332 if (getVisibleExpandedItems(tree
, true).size() > 1) {
1333 PaintListener paintListener
= new PaintListener() {
1335 public void paintControl(PaintEvent e
) {
1336 // get the treeItems here to have all items
1337 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, true);
1338 if (treeItems
.size() < 2) {
1341 final TreeItem treeItem0
= treeItems
.get(0);
1342 final TreeItem treeItem1
= treeItems
.get(1);
1343 tree
.removePaintListener(this);
1344 int y0
= treeItem0
.getBounds().y
;
1345 int y1
= treeItem1
.getBounds().y
;
1346 int itemHeight
= y1
- y0
;
1347 if (itemHeight
> 0) {
1348 fLinuxItemHeight
= itemHeight
;
1349 fTimeGraphViewer
.setItemHeight(itemHeight
);
1353 tree
.addPaintListener(paintListener
);
1356 fLinuxItemHeight
= -1; // Not Linux, don't perform os.name check
1359 return tree
.getItemHeight();
1362 private void alignTreeItems(boolean refreshExpandedItems
) {
1364 // align the tree top item with the time graph top item
1365 Tree tree
= fTreeViewer
.getTree();
1366 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, refreshExpandedItems
);
1367 int topIndex
= fTimeGraphViewer
.getTopIndex();
1368 if (topIndex
>= treeItems
.size()) {
1371 TreeItem item
= treeItems
.get(topIndex
);
1372 tree
.setTopItem(item
);
1374 * In GTK3, the bounds of the tree items are only sure to be correct
1375 * after the tree has been painted.
1377 tree
.addPaintListener(new PaintListener() {
1379 public void paintControl(PaintEvent e
) {
1380 tree
.removePaintListener(this);
1384 * Bug in GTK. Calling setTopItem() can scroll to the wrong item
1385 * when the 'tree view' is dirty. Set it again once it is clean.
1387 if (SWT
.getPlatform().equals("gtk")) { //$NON-NLS-1$
1388 tree
.getDisplay().asyncExec(() -> {
1389 TreeItem topItem
= tree
.getTopItem();
1390 if (!tree
.isDisposed() && topItem
!= null && !topItem
.isDisposed()) {
1391 tree
.setTopItem(topItem
);
1397 /* Make sure the paint event is triggered. */
1401 private void doAlignTreeItems() {
1402 Tree tree
= fTreeViewer
.getTree();
1403 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, false);
1404 int topIndex
= fTimeGraphViewer
.getTopIndex();
1405 if (topIndex
>= treeItems
.size()) {
1408 TreeItem item
= treeItems
.get(topIndex
);
1410 // get the first filler item so we can calculate the last item's height
1411 TreeItem fillerItem
= null;
1412 for (TreeItem treeItem
: fTreeViewer
.getTree().getItems()) {
1413 if (treeItem
.getData() == FILLER
) {
1414 fillerItem
= treeItem
;
1419 // ensure the time graph item heights are equal to the tree item heights
1420 int treeHeight
= fTreeViewer
.getTree().getBounds().height
;
1421 int index
= topIndex
;
1422 Rectangle bounds
= item
.getBounds();
1423 while (index
< treeItems
.size()) {
1424 if (bounds
.y
> treeHeight
) {
1427 TreeItem nextItem
= (index
+ 1 == treeItems
.size()) ? fillerItem
: treeItems
.get(index
+ 1);
1428 Rectangle nextBounds
= alignTreeItem(item
, bounds
, nextItem
);
1431 bounds
= nextBounds
;
1435 * When an item's height in the time graph changes, it is possible that
1436 * the time graph readjusts its top index to fill empty space at the
1437 * bottom of the viewer. Calling method setTopIndex() triggers this
1438 * adjustment, if needed. In that case, we need to make sure that the
1439 * newly visible items at the top of the viewer are also aligned.
1441 fTimeGraphViewer
.setTopIndex(topIndex
);
1442 if (fTimeGraphViewer
.getTopIndex() != topIndex
) {
1443 alignTreeItems(false);
1447 private Rectangle
alignTreeItem(TreeItem item
, Rectangle bounds
, TreeItem nextItem
) {
1449 * Bug in Linux. The method getBounds doesn't always return the correct
1450 * height. Use the difference of y position between items to calculate
1453 Rectangle nextBounds
= nextItem
.getBounds();
1454 Integer itemHeight
= nextBounds
.y
- bounds
.y
;
1455 if (itemHeight
> 0) {
1456 ITimeGraphEntry entry
= (ITimeGraphEntry
) item
.getData();
1457 fTimeGraphViewer
.getTimeGraphControl().setItemHeight(entry
, itemHeight
);
1463 * Return the time alignment information
1465 * @return the time alignment information
1467 * @see ITmfTimeAligned
1471 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
1472 Point location
= fSashForm
.toDisplay(0, 0);
1473 int timeAxisOffset
= fTreeViewer
.getControl().getSize().x
+ fSashForm
.getSashWidth();
1474 return new TmfTimeViewAlignmentInfo(fSashForm
.getShell(), location
, timeAxisOffset
);
1478 * Return the available width for the time-axis.
1480 * @see ITmfTimeAligned
1482 * @param requestedOffset
1483 * the requested offset
1484 * @return the available width for the time-axis
1488 public int getAvailableWidth(int requestedOffset
) {
1489 int vBarWidth
= ((fTimeGraphViewer
.getVerticalBar() != null) && (fTimeGraphViewer
.getVerticalBar().isVisible())) ? fTimeGraphViewer
.getVerticalBar().getSize().x
: 0;
1490 int totalWidth
= fSashForm
.getBounds().width
;
1491 return Math
.min(totalWidth
, Math
.max(0, totalWidth
- requestedOffset
- vBarWidth
));
1495 * Perform the alignment operation.
1498 * the alignment offset
1500 * the alignment width
1502 * @see ITmfTimeAligned
1506 public void performAlign(int offset
, int width
) {
1507 int total
= fSashForm
.getBounds().width
;
1508 int timeAxisOffset
= Math
.min(offset
, total
);
1509 int width1
= Math
.max(0, timeAxisOffset
- fSashForm
.getSashWidth());
1510 int width2
= total
- timeAxisOffset
;
1511 if (width1
>= 0 && width2
> 0 || width1
> 0 && width2
>= 0) {
1512 fSashForm
.setWeights(new int[] { width1
, width2
});
1516 Composite composite
= fTimeGraphViewer
.getTimeAlignedComposite();
1517 GridLayout layout
= (GridLayout
) composite
.getLayout();
1518 int timeBasedControlsWidth
= composite
.getSize().x
;
1519 int marginSize
= timeBasedControlsWidth
- width
;
1520 layout
.marginRight
= Math
.max(0, marginSize
);