1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 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 // ------------------------------------------------------------------------
97 /** Constant indicating that all levels of the time graph should be expanded */
98 public static final int ALL_LEVELS
= AbstractTreeViewer
.ALL_LEVELS
;
100 private static final Object FILLER
= new Object();
102 // ------------------------------------------------------------------------
104 // ------------------------------------------------------------------------
106 /** The tree viewer */
107 private TreeViewer fTreeViewer
;
109 /** The time viewer */
110 private @NonNull TimeGraphViewer fTimeGraphViewer
;
112 /** The selection listener map */
113 private final Map
<ITimeGraphSelectionListener
, SelectionListenerWrapper
> fSelectionListenerMap
= new HashMap
<>();
115 /** The map of viewer filters to viewer filter wrappers */
116 private final Map
<@NonNull ViewerFilter
, @NonNull ViewerFilter
> fViewerFilterMap
= new HashMap
<>();
119 * Flag to block the tree selection changed listener when triggered by the
122 private boolean fInhibitTreeSelection
= false;
124 /** Number of filler rows used by the tree content provider */
125 private int fNumFillerRows
;
127 /** Calculated item height for Linux workaround */
128 private int fLinuxItemHeight
= 0;
130 /** The action that opens the filter dialog */
131 private ShowFilterDialogAction fShowFilterDialogAction
;
133 /** Default weight of each part of the sash */
134 private static final int[] DEFAULT_WEIGHTS
= { 1, 1 };
136 /** List of all expanded items whose parents are also expanded */
137 private List
<TreeItem
> fVisibleExpandedItems
= null;
139 private Listener fSashDragListener
;
140 private SashForm fSashForm
;
142 private final boolean fScrollBarsInTreeWorkaround
;
144 private Font fTreeFont
;
146 // ------------------------------------------------------------------------
148 // ------------------------------------------------------------------------
151 * The TimeGraphViewerExtension is used to set appropriate values and to
152 * override methods that could be called directly by the user and that must
153 * be handled by the time graph combo.
155 private class TimeGraphViewerExtension
extends TimeGraphViewer
{
157 private TimeGraphViewerExtension(Composite parent
, int style
, Tree tree
) {
158 super(parent
, style
);
159 setItemHeight(TimeGraphCombo
.this.getItemHeight(tree
, true));
160 setHeaderHeight(tree
.getHeaderHeight());
161 setBorderWidth(tree
.getBorderWidth());
166 public ShowFilterDialogAction
getShowFilterDialogAction() {
167 return TimeGraphCombo
.this.getShowFilterDialogAction();
171 protected TimeGraphControl
createTimeGraphControl(Composite composite
, TimeGraphColorScheme colors
) {
172 return new TimeGraphControl(composite
, colors
) {
174 public void verticalZoom(boolean zoomIn
) {
175 TimeGraphCombo
.this.verticalZoom(zoomIn
);
179 public void resetVerticalZoom() {
180 TimeGraphCombo
.this.resetVerticalZoom();
184 public void setElementPosition(ITimeGraphEntry entry
, int y
) {
186 * Queue the update to make sure the time graph combo has finished
187 * updating the item heights.
189 getDisplay().asyncExec(() -> {
190 super.setElementPosition(entry
, y
);
191 alignTreeItems(false);
197 private class TimeGraphMarkerAxisExtension
extends TimeGraphMarkerAxis
{
198 private int fMargin
= 0;
200 public TimeGraphMarkerAxisExtension(Composite parent
, @NonNull TimeGraphColorScheme colorScheme
, @NonNull ITimeDataProvider timeProvider
) {
201 super(parent
, colorScheme
, timeProvider
);
205 public Point
computeSize(int wHint
, int hHint
, boolean changed
) {
206 Point size
= super.computeSize(wHint
, hHint
, changed
);
214 public void redraw() {
216 fTreeViewer
.getControl().redraw();
220 protected void drawMarkerAxis(Rectangle bounds
, int nameSpace
, GC gc
) {
221 super.drawMarkerAxis(bounds
, nameSpace
, gc
);
224 private Rectangle
getAxisBounds() {
225 Tree tree
= fTreeViewer
.getTree();
226 Rectangle axisBounds
= getBounds();
227 Rectangle treeClientArea
= tree
.getClientArea();
228 if (axisBounds
.isEmpty()) {
229 treeClientArea
.y
+= treeClientArea
.height
;
230 treeClientArea
.height
= 0;
231 return treeClientArea
;
233 Composite axisParent
= getParent();
234 Point axisDisplayCoordinates
= axisParent
.toDisplay(axisBounds
.x
, axisBounds
.y
);
235 Point axisTreeCoordinates
= tree
.toControl(axisDisplayCoordinates
);
236 int height
= treeClientArea
.y
+ treeClientArea
.height
- axisTreeCoordinates
.y
;
237 int margin
= Math
.max(0, axisBounds
.height
- height
);
238 if (fMargin
!= margin
) {
240 getParent().layout();
242 axisTreeCoordinates
.y
-= margin
;
245 return new Rectangle(treeClientArea
.x
, axisTreeCoordinates
.y
, treeClientArea
.width
, height
);
250 protected TimeGraphMarkerAxis
createTimeGraphMarkerAxis(Composite parent
, @NonNull TimeGraphColorScheme colorScheme
, @NonNull ITimeDataProvider timeProvider
) {
251 TimeGraphMarkerAxisExtension timeGraphMarkerAxis
= new TimeGraphMarkerAxisExtension(parent
, colorScheme
, timeProvider
);
252 Tree tree
= fTreeViewer
.getTree();
253 tree
.addPaintListener(e
-> {
255 * Draw the marker axis over the tree. Only the name area
256 * will be drawn, since the time area has zero width.
258 Rectangle bounds
= timeGraphMarkerAxis
.getAxisBounds();
259 e
.gc
.setBackground(timeGraphMarkerAxis
.getBackground());
260 timeGraphMarkerAxis
.drawMarkerAxis(bounds
, bounds
.width
, e
.gc
);
262 tree
.addMouseListener(new MouseAdapter() {
264 public void mouseDown(MouseEvent e
) {
265 Rectangle bounds
= timeGraphMarkerAxis
.getAxisBounds();
266 if (bounds
.contains(e
.x
, e
.y
)) {
267 timeGraphMarkerAxis
.mouseDown(e
, bounds
, bounds
.width
);
271 tree
.getHorizontalBar().addSelectionListener(new SelectionAdapter() {
273 public void widgetSelected(SelectionEvent e
) {
277 return timeGraphMarkerAxis
;
282 * The TreeContentProviderWrapper is used to insert filler items after
283 * the elements of the tree's real content provider.
285 private class TreeContentProviderWrapper
implements ITreeContentProvider
{
286 private final ITreeContentProvider contentProvider
;
288 public TreeContentProviderWrapper(ITreeContentProvider contentProvider
) {
289 this.contentProvider
= contentProvider
;
293 public void dispose() {
294 contentProvider
.dispose();
298 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
299 contentProvider
.inputChanged(viewer
, oldInput
, newInput
);
303 public Object
[] getElements(Object inputElement
) {
304 Object
[] elements
= contentProvider
.getElements(inputElement
);
305 // add filler elements to ensure alignment with time analysis viewer
306 Object
[] oElements
= Arrays
.copyOf(elements
, elements
.length
+ fNumFillerRows
, Object
[].class);
307 for (int i
= 0; i
< fNumFillerRows
; i
++) {
308 oElements
[elements
.length
+ i
] = FILLER
;
314 public Object
[] getChildren(Object parentElement
) {
315 if (parentElement
instanceof ITimeGraphEntry
) {
316 return contentProvider
.getChildren(parentElement
);
318 return new Object
[0];
322 public Object
getParent(Object element
) {
323 if (element
instanceof ITimeGraphEntry
) {
324 return contentProvider
.getParent(element
);
330 public boolean hasChildren(Object element
) {
331 if (element
instanceof ITimeGraphEntry
) {
332 return contentProvider
.hasChildren(element
);
339 * The TreeLabelProviderWrapper is used to intercept the filler items
340 * from the calls to the tree's real label provider.
342 private static class TreeLabelProviderWrapper
implements ITableLabelProvider
{
343 private final ITableLabelProvider labelProvider
;
345 public TreeLabelProviderWrapper(ITableLabelProvider labelProvider
) {
346 this.labelProvider
= labelProvider
;
350 public void addListener(ILabelProviderListener listener
) {
351 labelProvider
.addListener(listener
);
355 public void dispose() {
356 labelProvider
.dispose();
360 public boolean isLabelProperty(Object element
, String property
) {
361 if (element
instanceof ITimeGraphEntry
) {
362 return labelProvider
.isLabelProperty(element
, property
);
368 public void removeListener(ILabelProviderListener listener
) {
369 labelProvider
.removeListener(listener
);
373 public Image
getColumnImage(Object element
, int columnIndex
) {
374 if (element
instanceof ITimeGraphEntry
) {
375 return labelProvider
.getColumnImage(element
, columnIndex
);
381 public String
getColumnText(Object element
, int columnIndex
) {
382 if (element
instanceof ITimeGraphEntry
) {
383 return labelProvider
.getColumnText(element
, columnIndex
);
391 * The SelectionListenerWrapper is used to intercept the filler items from
392 * the time graph combo's real selection listener, and to prevent double
393 * notifications from being sent when selection changes in both tree and
394 * time graph at the same time.
396 private class SelectionListenerWrapper
implements ISelectionChangedListener
, ITimeGraphSelectionListener
{
397 private final ITimeGraphSelectionListener listener
;
398 private ITimeGraphEntry selection
= null;
400 public SelectionListenerWrapper(ITimeGraphSelectionListener listener
) {
401 this.listener
= listener
;
405 public void selectionChanged(SelectionChangedEvent event
) {
406 if (fInhibitTreeSelection
) {
409 Object element
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
410 if (element
instanceof ITimeGraphEntry
) {
411 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
412 if (entry
!= selection
) {
414 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
420 public void selectionChanged(TimeGraphSelectionEvent event
) {
421 ITimeGraphEntry entry
= event
.getSelection();
422 if (entry
!= selection
) {
424 listener
.selectionChanged(new TimeGraphSelectionEvent(event
.getSource(), selection
));
430 * The ViewerFilterWrapper is used to intercept the filler items from
431 * the time graph combo's real ViewerFilters. These filler items should
434 private static class ViewerFilterWrapper
extends ViewerFilter
{
436 private ViewerFilter fWrappedFilter
;
438 ViewerFilterWrapper(ViewerFilter filter
) {
440 this.fWrappedFilter
= filter
;
444 public boolean select(Viewer viewer
, Object parentElement
, Object element
) {
445 if (element
instanceof ITimeGraphEntry
) {
446 return fWrappedFilter
.select(viewer
, parentElement
, element
);
453 // ------------------------------------------------------------------------
455 // ------------------------------------------------------------------------
458 * Constructs a new instance of this class given its parent
459 * and a style value describing its behavior and appearance.
461 * @param parent a widget which will be the parent of the new instance (cannot be null)
462 * @param style the style of widget to construct
464 public TimeGraphCombo(Composite parent
, int style
) {
465 this(parent
, style
, DEFAULT_WEIGHTS
);
469 * Constructs a new instance of this class given its parent and a style
470 * value describing its behavior and appearance.
473 * a widget which will be the parent of the new instance (cannot
476 * the style of widget to construct
478 * The array (length 2) of relative weights of each side of the sash form
480 public TimeGraphCombo(Composite parent
, int style
, int[] weights
) {
481 super(parent
, style
);
482 setLayout(new FillLayout());
484 fSashForm
= new SashForm(this, SWT
.NONE
);
487 * In Windows, SWT.H_SCROLL | SWT.NO_SCROLL is not properly supported,
488 * both scroll bars are always created. See Tree.checkStyle: "Even when
489 * WS_HSCROLL or WS_VSCROLL is not specified, Windows creates trees and
490 * tables with scroll bars."
492 fScrollBarsInTreeWorkaround
= "win32".equals(SWT
.getPlatform()); //$NON-NLS-1$
494 int scrollBarStyle
= fScrollBarsInTreeWorkaround ? SWT
.H_SCROLL
: SWT
.H_SCROLL
| SWT
.NO_SCROLL
;
496 fTreeViewer
= new TreeViewer(fSashForm
, SWT
.FULL_SELECTION
| scrollBarStyle
);
497 fTreeViewer
.setAutoExpandLevel(AbstractTreeViewer
.ALL_LEVELS
);
498 final Tree tree
= fTreeViewer
.getTree();
499 tree
.setHeaderVisible(true);
500 tree
.setLinesVisible(true);
502 fTimeGraphViewer
= new TimeGraphViewerExtension(fSashForm
, SWT
.NONE
, tree
);
504 if (fScrollBarsInTreeWorkaround
) {
505 // Feature in Windows. The tree vertical bar reappears when
506 // the control is resized so we need to hide it again.
507 tree
.addControlListener(new ControlAdapter() {
508 private int depth
= 0;
511 public void controlResized(ControlEvent e
) {
514 tree
.getVerticalBar().setEnabled(false);
515 // this can trigger controlResized recursively
516 tree
.getVerticalBar().setVisible(false);
522 // Bug in Linux. The tree header height is 0 in constructor,
523 // so we need to reset it later when the control is painted.
524 // This work around used to be done on control resized but the header
525 // height was not initialized on the initial resize on GTK3.
526 tree
.addPaintListener(new PaintListener() {
528 public void paintControl(PaintEvent e
) {
529 int headerHeight
= tree
.getHeaderHeight();
530 if (headerHeight
> 0) {
531 fTimeGraphViewer
.setHeaderHeight(headerHeight
);
532 tree
.removePaintListener(this);
537 tree
.addDisposeListener(e
-> {
538 if (fTreeFont
!= null) {
543 // ensure synchronization of expanded items between tree and time graph
544 fTreeViewer
.addTreeListener(new ITreeViewerListener() {
546 public void treeCollapsed(TreeExpansionEvent event
) {
547 fTimeGraphViewer
.setExpandedState((ITimeGraphEntry
) event
.getElement(), false);
548 // queue the alignment update because the tree items may only be
549 // actually collapsed after the listeners have been notified
550 fVisibleExpandedItems
= null; // invalidate the cache
551 getDisplay().asyncExec(new Runnable() {
554 alignTreeItems(true);
559 public void treeExpanded(TreeExpansionEvent event
) {
560 ITimeGraphEntry entry
= (ITimeGraphEntry
) event
.getElement();
561 fTimeGraphViewer
.setExpandedState(entry
, true);
562 Set
<Object
> expandedElements
= new HashSet
<>(Arrays
.asList(fTreeViewer
.getExpandedElements()));
563 for (ITimeGraphEntry child
: entry
.getChildren()) {
564 if (child
.hasChildren()) {
565 boolean expanded
= expandedElements
.contains(child
);
566 fTimeGraphViewer
.setExpandedState(child
, expanded
);
569 // queue the alignment update because the tree items may only be
570 // actually expanded after the listeners have been notified
571 fVisibleExpandedItems
= null; // invalidate the cache
572 getDisplay().asyncExec(new Runnable() {
575 alignTreeItems(true);
580 // ensure synchronization of expanded items between tree and time graph
581 fTimeGraphViewer
.addTreeListener(new ITimeGraphTreeListener() {
583 public void treeCollapsed(TimeGraphTreeExpansionEvent event
) {
584 fTreeViewer
.setExpandedState(event
.getEntry(), false);
585 alignTreeItems(true);
589 public void treeExpanded(TimeGraphTreeExpansionEvent event
) {
590 ITimeGraphEntry entry
= event
.getEntry();
591 fTreeViewer
.setExpandedState(entry
, true);
592 Set
<Object
> expandedElements
= new HashSet
<>(Arrays
.asList(fTreeViewer
.getExpandedElements()));
593 for (ITimeGraphEntry child
: entry
.getChildren()) {
594 if (child
.hasChildren()) {
595 boolean expanded
= expandedElements
.contains(child
);
596 fTimeGraphViewer
.setExpandedState(child
, expanded
);
599 alignTreeItems(true);
603 // prevent mouse button from selecting a filler tree item
604 tree
.addListener(SWT
.MouseDown
, event
-> {
605 TreeItem treeItem
= tree
.getItem(new Point(event
.x
, event
.y
));
606 if (treeItem
== null || treeItem
.getData() == FILLER
) {
608 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, false);
609 if (treeItems
.size() == 0) {
610 fTreeViewer
.setSelection(new StructuredSelection());
611 fTimeGraphViewer
.setSelection(null);
614 // this prevents from scrolling up when selecting
615 // the partially visible tree item at the bottom
616 tree
.select(treeItems
.get(treeItems
.size() - 1));
617 fTreeViewer
.setSelection(new StructuredSelection());
618 fTimeGraphViewer
.setSelection(null);
622 // prevent mouse wheel from scrolling down into filler tree items
623 tree
.addListener(SWT
.MouseWheel
, event
-> {
625 if (event
.count
== 0) {
628 Slider scrollBar
= fTimeGraphViewer
.getVerticalBar();
629 fTimeGraphViewer
.setTopIndex(scrollBar
.getSelection() - event
.count
);
630 alignTreeItems(false);
633 // prevent key stroke from selecting a filler tree item
634 tree
.addListener(SWT
.KeyDown
, event
-> {
635 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, false);
636 if (treeItems
.size() == 0) {
637 fTreeViewer
.setSelection(new StructuredSelection());
641 if (event
.keyCode
== SWT
.ARROW_DOWN
) {
642 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + 1, treeItems
.size() - 1);
643 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
645 } else if (event
.keyCode
== SWT
.PAGE_DOWN
) {
646 int height
= tree
.getSize().y
- tree
.getHeaderHeight() - tree
.getHorizontalBar().getSize().y
;
647 int countPerPage
= height
/ getItemHeight(tree
, false);
648 int index
= Math
.min(fTimeGraphViewer
.getSelectionIndex() + countPerPage
- 1, treeItems
.size() - 1);
649 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(index
).getData());
651 } else if (event
.keyCode
== SWT
.END
) {
652 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) treeItems
.get(treeItems
.size() - 1).getData());
654 } else if ((event
.character
== '+' || event
.character
== '=') && ((event
.stateMask
& SWT
.CTRL
) != 0)) {
655 fTimeGraphViewer
.getTimeGraphControl().keyPressed(new KeyEvent(event
));
657 } else if (event
.character
== '-' && ((event
.stateMask
& SWT
.CTRL
) != 0)) {
658 fTimeGraphViewer
.getTimeGraphControl().keyPressed(new KeyEvent(event
));
660 } else if (event
.character
== '0' && ((event
.stateMask
& SWT
.CTRL
) != 0)) {
661 fTimeGraphViewer
.getTimeGraphControl().keyPressed(new KeyEvent(event
));
666 if (fTimeGraphViewer
.getSelectionIndex() >= 0) {
667 fTreeViewer
.setSelection(new StructuredSelection(fTimeGraphViewer
.getSelection()));
669 fTreeViewer
.setSelection(new StructuredSelection());
671 alignTreeItems(false);
674 // ensure alignment of top item between tree and time graph
675 fTimeGraphViewer
.getTimeGraphControl().addControlListener(new ControlAdapter() {
677 public void controlResized(ControlEvent e
) {
678 alignTreeItems(false);
682 // ensure synchronization of selected item between tree and time graph
683 fTreeViewer
.addSelectionChangedListener(event
-> {
684 if (fInhibitTreeSelection
) {
687 if (event
.getSelection() instanceof IStructuredSelection
) {
688 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
689 if (selection
instanceof ITimeGraphEntry
) {
690 fTimeGraphViewer
.setSelection((ITimeGraphEntry
) selection
);
692 alignTreeItems(false);
696 // ensure synchronization of selected item between tree and time graph
697 fTimeGraphViewer
.addSelectionListener(event
-> {
698 ITimeGraphEntry entry
= fTimeGraphViewer
.getSelection();
699 fInhibitTreeSelection
= true; // block the tree selection changed listener
701 StructuredSelection selection
= new StructuredSelection(entry
);
702 fTreeViewer
.setSelection(selection
);
704 fTreeViewer
.setSelection(new StructuredSelection());
706 fInhibitTreeSelection
= false;
707 alignTreeItems(false);
710 // ensure alignment of top item between tree and time graph
711 fTimeGraphViewer
.getVerticalBar().addSelectionListener(new SelectionAdapter() {
713 public void widgetSelected(SelectionEvent e
) {
714 alignTreeItems(false);
718 // ensure alignment of top item between tree and time graph
719 fTimeGraphViewer
.getTimeGraphControl().addMouseWheelListener(e
-> {
723 alignTreeItems(false);
726 // ensure the tree has focus control when mouse is over it if the time graph had control
727 fTreeViewer
.getControl().addMouseTrackListener(new MouseTrackAdapter() {
729 public void mouseEnter(MouseEvent e
) {
730 if (fTimeGraphViewer
.getTimeGraphControl().isFocusControl()) {
731 fTreeViewer
.getControl().setFocus();
736 // ensure the time graph has focus control when mouse is over it if the tree had control
737 fTimeGraphViewer
.getTimeGraphControl().addMouseTrackListener(new MouseTrackAdapter() {
739 public void mouseEnter(MouseEvent e
) {
740 if (fTreeViewer
.getControl().isFocusControl()) {
741 fTimeGraphViewer
.getTimeGraphControl().setFocus();
745 fTimeGraphViewer
.getTimeGraphScale().addMouseTrackListener(new MouseTrackAdapter() {
747 public void mouseEnter(MouseEvent e
) {
748 if (fTreeViewer
.getControl().isFocusControl()) {
749 fTimeGraphViewer
.getTimeGraphControl().setFocus();
754 // The filler rows are required to ensure alignment when the tree does not have a
755 // visible horizontal scroll bar. The tree does not allow its top item to be set
756 // to a value that would cause blank space to be drawn at the bottom of the tree.
757 fNumFillerRows
= Display
.getDefault().getBounds().height
/ getItemHeight(tree
, false);
759 fSashForm
.setWeights(weights
);
761 fTimeGraphViewer
.getTimeGraphControl().addPaintListener(new PaintListener() {
763 public void paintControl(PaintEvent e
) {
764 // Sashes in a SashForm are being created on layout so add the
765 // drag listener here
766 if (fSashDragListener
== null) {
767 for (Control control
: fSashForm
.getChildren()) {
768 if (control
instanceof Sash
) {
769 fSashDragListener
= new Listener() {
772 public void handleEvent(Event event
) {
773 sendTimeViewAlignmentChanged();
777 control
.removePaintListener(this);
778 control
.addListener(SWT
.Selection
, fSashDragListener
);
779 // There should be only one sash
788 private void verticalZoom(boolean zoomIn
) {
789 Tree tree
= fTreeViewer
.getTree();
790 FontData fontData
= tree
.getFont().getFontData()[0];
791 int height
= fontData
.getHeight() + (zoomIn ?
1 : -1);
795 fontData
.setHeight(height
);
796 if (fTreeFont
!= null) {
799 fTreeFont
= new Font(tree
.getDisplay(), fontData
);
800 tree
.setFont(fTreeFont
);
803 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
804 fTimeGraphViewer
.setItemHeight(getItemHeight(tree
, true));
805 alignTreeItems(false);
808 private void resetVerticalZoom() {
809 Tree tree
= fTreeViewer
.getTree();
810 if (fTreeFont
!= null) {
817 fTimeGraphViewer
.setHeaderHeight(tree
.getHeaderHeight());
818 fTimeGraphViewer
.setItemHeight(getItemHeight(tree
, true));
819 alignTreeItems(false);
822 private void sendTimeViewAlignmentChanged() {
823 TmfSignalManager
.dispatchSignal(new TmfTimeViewAlignmentSignal(fSashForm
, getTimeViewAlignmentInfo()));
826 // ------------------------------------------------------------------------
828 // ------------------------------------------------------------------------
831 * Returns this time graph combo's tree viewer.
833 * @return the tree viewer
835 public TreeViewer
getTreeViewer() {
840 * Returns this time graph combo's time graph viewer.
842 * @return the time graph viewer
844 public @NonNull TimeGraphViewer
getTimeGraphViewer() {
845 return fTimeGraphViewer
;
849 * Get the show filter dialog action.
851 * @return The Action object
854 public ShowFilterDialogAction
getShowFilterDialogAction() {
855 if (fShowFilterDialogAction
== null) {
856 fShowFilterDialogAction
= new ShowFilterDialogAction(fTimeGraphViewer
) {
858 protected void addFilter(ViewerFilter filter
) {
859 /* add filter to the combo instead of the viewer */
860 TimeGraphCombo
.this.addFilter(filter
);
864 protected void removeFilter(ViewerFilter filter
) {
865 /* remove filter from the combo instead of the viewer */
866 TimeGraphCombo
.this.removeFilter(filter
);
870 protected void refresh() {
871 /* refresh the combo instead of the viewer */
872 TimeGraphCombo
.this.refresh();
876 return fShowFilterDialogAction
;
879 // ------------------------------------------------------------------------
881 // ------------------------------------------------------------------------
884 public void redraw() {
885 fTimeGraphViewer
.getControl().redraw();
890 public void update() {
891 fTimeGraphViewer
.getControl().update();
895 // ------------------------------------------------------------------------
897 // ------------------------------------------------------------------------
900 * Sets the tree content provider used by this time graph combo.
902 * @param contentProvider the tree content provider
904 public void setTreeContentProvider(ITreeContentProvider contentProvider
) {
905 fTreeViewer
.setContentProvider(new TreeContentProviderWrapper(contentProvider
));
909 * Sets the tree label provider used by this time graph combo.
911 * @param labelProvider the tree label provider
913 public void setTreeLabelProvider(ITableLabelProvider labelProvider
) {
914 fTreeViewer
.setLabelProvider(new TreeLabelProviderWrapper(labelProvider
));
918 * Sets the tree content provider used by the filter dialog
920 * @param contentProvider the tree content provider
922 public void setFilterContentProvider(ITreeContentProvider contentProvider
) {
923 getShowFilterDialogAction().getFilterDialog().setContentProvider(contentProvider
);
927 * Sets the tree label provider used by the filter dialog
929 * @param labelProvider the tree label provider
931 public void setFilterLabelProvider(ITableLabelProvider labelProvider
) {
932 getShowFilterDialogAction().getFilterDialog().setLabelProvider(labelProvider
);
936 * Adds a "check active" button used by the filter dialog
938 * @param activeProvider
939 * Additional button info specific to a certain view.
942 public void addTimeGraphFilterCheckActiveButton(ITimeGraphEntryActiveProvider activeProvider
) {
943 getShowFilterDialogAction().getFilterDialog().addTimeGraphFilterCheckActiveButton(activeProvider
);
947 * Adds an "uncheck inactive" button used by the filter dialog
949 * @param inactiveProvider
950 * Additional button info specific to a certain view.
953 public void addTimeGraphFilterUncheckInactiveButton(ITimeGraphEntryActiveProvider inactiveProvider
) {
954 getShowFilterDialogAction().getFilterDialog().addTimeGraphFilterUncheckInactiveButton(inactiveProvider
);
958 * Sets the tree columns for this time graph combo.
960 * @param columnNames the tree column names
962 public void setTreeColumns(String
[] columnNames
) {
963 final Tree tree
= fTreeViewer
.getTree();
964 for (String columnName
: columnNames
) {
965 TreeColumn column
= new TreeColumn(tree
, SWT
.LEFT
);
966 column
.setMoveable(true);
967 column
.setText(columnName
);
973 * Sets the tree columns for this time graph combo's filter dialog.
975 * @param columnNames the tree column names
977 public void setFilterColumns(String
[] columnNames
) {
978 getShowFilterDialogAction().getFilterDialog().setColumnNames(columnNames
);
982 * Sets the time graph content provider used by this time graph combo.
984 * @param timeGraphContentProvider
985 * the time graph content provider
987 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider
) {
988 fTimeGraphViewer
.setTimeGraphContentProvider(timeGraphContentProvider
);
992 * Sets the time graph presentation provider used by this time graph combo.
994 * @param timeGraphProvider the time graph provider
996 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider
) {
997 fTimeGraphViewer
.setTimeGraphProvider(timeGraphProvider
);
1001 * Sets or clears the input for this time graph combo.
1003 * @param input the input of this time graph combo, or <code>null</code> if none
1005 public void setInput(Object input
) {
1006 fInhibitTreeSelection
= true;
1007 fTreeViewer
.setInput(input
);
1008 for (SelectionListenerWrapper listenerWrapper
: fSelectionListenerMap
.values()) {
1009 listenerWrapper
.selection
= null;
1011 fInhibitTreeSelection
= false;
1012 if (fScrollBarsInTreeWorkaround
) {
1013 fTreeViewer
.getTree().getVerticalBar().setEnabled(false);
1014 fTreeViewer
.getTree().getVerticalBar().setVisible(false);
1016 fTimeGraphViewer
.setInput(input
);
1017 fTimeGraphViewer
.setItemHeight(getItemHeight(fTreeViewer
.getTree(), false));
1018 // queue the alignment update because in Linux the item bounds are not
1019 // set properly until the tree has been painted at least once
1020 fVisibleExpandedItems
= null; // invalidate the cache
1021 getDisplay().asyncExec(new Runnable() {
1024 alignTreeItems(true);
1029 * Gets the input for this time graph combo.
1031 * @return The input of this time graph combo, or <code>null</code> if none
1033 public Object
getInput() {
1034 return fTreeViewer
.getInput();
1038 * Sets or clears the list of links to display on this combo
1040 * @param links the links to display in this time graph combo
1042 public void setLinks(List
<ILinkEvent
> links
) {
1043 fTimeGraphViewer
.setLinks(links
);
1047 * @param filter The filter object to be attached to the view
1049 public void addFilter(@NonNull ViewerFilter filter
) {
1050 fInhibitTreeSelection
= true;
1051 ViewerFilter wrapper
= new ViewerFilterWrapper(filter
);
1052 fTreeViewer
.addFilter(wrapper
);
1053 fTimeGraphViewer
.addFilter(filter
);
1054 fViewerFilterMap
.put(filter
, wrapper
);
1055 alignTreeItems(true);
1056 fInhibitTreeSelection
= false;
1060 * @param filter The filter object to be removed from the view
1062 public void removeFilter(@NonNull ViewerFilter filter
) {
1063 fInhibitTreeSelection
= true;
1064 ViewerFilter wrapper
= fViewerFilterMap
.get(filter
);
1065 fTreeViewer
.removeFilter(wrapper
);
1066 fTimeGraphViewer
.removeFilter(filter
);
1067 fViewerFilterMap
.remove(filter
);
1068 alignTreeItems(true);
1069 fInhibitTreeSelection
= false;
1073 * Returns this viewer's filters.
1075 * @return an array of viewer filters
1078 public @NonNull ViewerFilter
[] getFilters() {
1079 return fTimeGraphViewer
.getFilters();
1083 * Sets the filters, replacing any previous filters, and triggers
1084 * refiltering of the elements.
1087 * an array of viewer filters, or null
1090 public void setFilters(@NonNull ViewerFilter
[] filters
) {
1091 fInhibitTreeSelection
= true;
1092 fViewerFilterMap
.clear();
1093 if (filters
== null) {
1094 fTreeViewer
.resetFilters();
1096 for (ViewerFilter filter
: filters
) {
1097 ViewerFilter wrapper
= new ViewerFilterWrapper(filter
);
1098 fViewerFilterMap
.put(filter
, wrapper
);
1100 ViewerFilter
[] wrappers
= Iterables
.toArray(fViewerFilterMap
.values(), ViewerFilter
.class);
1101 fTreeViewer
.setFilters(wrappers
);
1103 fTimeGraphViewer
.setFilters(filters
);
1104 alignTreeItems(true);
1105 fInhibitTreeSelection
= false;
1109 * Refreshes this time graph completely with information freshly obtained from its model.
1111 public void refresh() {
1112 fInhibitTreeSelection
= true;
1113 Tree tree
= fTreeViewer
.getTree();
1115 tree
.setRedraw(false);
1116 fTreeViewer
.refresh();
1118 tree
.setRedraw(true);
1120 fTimeGraphViewer
.refresh();
1121 alignTreeItems(true);
1122 fInhibitTreeSelection
= false;
1126 * Adds a listener for selection changes in this time graph combo.
1128 * @param listener a selection listener
1130 public void addSelectionListener(ITimeGraphSelectionListener listener
) {
1131 SelectionListenerWrapper listenerWrapper
= new SelectionListenerWrapper(listener
);
1132 fTreeViewer
.addSelectionChangedListener(listenerWrapper
);
1133 fSelectionListenerMap
.put(listener
, listenerWrapper
);
1134 fTimeGraphViewer
.addSelectionListener(listenerWrapper
);
1138 * Removes the given selection listener from this time graph combo.
1140 * @param listener a selection changed listener
1142 public void removeSelectionListener(ITimeGraphSelectionListener listener
) {
1143 SelectionListenerWrapper listenerWrapper
= fSelectionListenerMap
.remove(listener
);
1144 fTreeViewer
.removeSelectionChangedListener(listenerWrapper
);
1145 fTimeGraphViewer
.removeSelectionListener(listenerWrapper
);
1149 * Sets the current selection for this time graph combo.
1151 * @param selection the new selection
1153 public void setSelection(ITimeGraphEntry selection
) {
1154 fTimeGraphViewer
.setSelection(selection
);
1155 fInhibitTreeSelection
= true; // block the tree selection changed listener
1156 if (selection
!= null) {
1157 StructuredSelection structuredSelection
= new StructuredSelection(selection
);
1158 fTreeViewer
.setSelection(structuredSelection
);
1160 fTreeViewer
.setSelection(new StructuredSelection());
1162 fInhibitTreeSelection
= false;
1163 alignTreeItems(false);
1167 * Sets the auto-expand level to be used for new entries discovered when
1168 * calling {@link #setInput(Object)} or {@link #refresh()}. The value 0
1169 * means that there is no auto-expand; 1 means that top-level entries are
1170 * expanded, but not their children; 2 means that top-level entries are
1171 * expanded, and their children, but not grand-children; and so on.
1173 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
1177 * non-negative level, or <code>ALL_LEVELS</code> to expand all
1178 * levels of the tree
1180 public void setAutoExpandLevel(int level
) {
1181 fTimeGraphViewer
.setAutoExpandLevel(level
);
1183 fTreeViewer
.setAutoExpandLevel(level
);
1185 fTreeViewer
.setAutoExpandLevel(level
+ 1);
1190 * Returns the auto-expand level.
1192 * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of
1193 * the tree are expanded automatically
1194 * @see #setAutoExpandLevel
1196 public int getAutoExpandLevel() {
1197 return fTimeGraphViewer
.getAutoExpandLevel();
1201 * Get the expanded state of an entry.
1205 * @return true if the entry is expanded, false if collapsed
1208 public boolean getExpandedState(ITimeGraphEntry entry
) {
1209 return fTimeGraphViewer
.getExpandedState(entry
);
1213 * Set the expanded state of an entry
1216 * The entry to expand/collapse
1218 * True for expanded, false for collapsed
1220 public void setExpandedState(ITimeGraphEntry entry
, boolean expanded
) {
1221 fTimeGraphViewer
.setExpandedState(entry
, expanded
);
1222 fTreeViewer
.setExpandedState(entry
, expanded
);
1223 alignTreeItems(true);
1227 * Collapses all nodes of the viewer's tree, starting with the root.
1229 public void collapseAll() {
1230 fTimeGraphViewer
.collapseAll();
1231 fTreeViewer
.collapseAll();
1232 alignTreeItems(true);
1236 * Expands all nodes of the viewer's tree, starting with the root.
1238 public void expandAll() {
1239 fTimeGraphViewer
.expandAll();
1240 fTreeViewer
.expandAll();
1241 alignTreeItems(true);
1244 // ------------------------------------------------------------------------
1246 // ------------------------------------------------------------------------
1248 private List
<TreeItem
> getVisibleExpandedItems(Tree tree
, boolean refresh
) {
1249 if (fVisibleExpandedItems
== null || refresh
) {
1250 List
<TreeItem
> visibleExpandedItems
= new ArrayList
<>();
1251 addVisibleExpandedItems(visibleExpandedItems
, tree
.getItems());
1252 fVisibleExpandedItems
= visibleExpandedItems
;
1254 return fVisibleExpandedItems
;
1257 private void addVisibleExpandedItems(List
<TreeItem
> visibleExpandedItems
, TreeItem
[] items
) {
1258 for (TreeItem item
: items
) {
1259 Object data
= item
.getData();
1260 if (data
== FILLER
) {
1263 visibleExpandedItems
.add(item
);
1264 boolean expandedState
= fTimeGraphViewer
.getExpandedState((ITimeGraphEntry
) data
);
1265 if (item
.getExpanded() != expandedState
) {
1266 /* synchronize the expanded state of both viewers */
1267 fTreeViewer
.setExpandedState(data
, expandedState
);
1269 if (expandedState
) {
1270 addVisibleExpandedItems(visibleExpandedItems
, item
.getItems());
1275 private int getItemHeight(final Tree tree
, boolean force
) {
1277 * Bug in Linux. The method getItemHeight doesn't always return the correct value.
1279 if (fLinuxItemHeight
>= 0 && System
.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
1280 if (fLinuxItemHeight
!= 0 && !force
) {
1281 return fLinuxItemHeight
;
1284 if (getVisibleExpandedItems(tree
, true).size() > 1) {
1285 PaintListener paintListener
= new PaintListener() {
1287 public void paintControl(PaintEvent e
) {
1288 // get the treeItems here to have all items
1289 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, true);
1290 if (treeItems
.size() < 2) {
1293 final TreeItem treeItem0
= treeItems
.get(0);
1294 final TreeItem treeItem1
= treeItems
.get(1);
1295 tree
.removePaintListener(this);
1296 int y0
= treeItem0
.getBounds().y
;
1297 int y1
= treeItem1
.getBounds().y
;
1298 int itemHeight
= y1
- y0
;
1299 if (itemHeight
> 0) {
1300 fLinuxItemHeight
= itemHeight
;
1301 fTimeGraphViewer
.setItemHeight(itemHeight
);
1305 tree
.addPaintListener(paintListener
);
1308 fLinuxItemHeight
= -1; // Not Linux, don't perform os.name check anymore
1310 return tree
.getItemHeight();
1313 private void alignTreeItems(boolean refreshExpandedItems
) {
1315 // align the tree top item with the time graph top item
1316 Tree tree
= fTreeViewer
.getTree();
1317 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, refreshExpandedItems
);
1318 int topIndex
= fTimeGraphViewer
.getTopIndex();
1319 if (topIndex
>= treeItems
.size()) {
1322 TreeItem item
= treeItems
.get(topIndex
);
1323 tree
.setTopItem(item
);
1325 * In GTK3, the bounds of the tree items are only sure to be correct
1326 * after the tree has been painted.
1328 tree
.addPaintListener(new PaintListener() {
1330 public void paintControl(PaintEvent e
) {
1331 tree
.removePaintListener(this);
1335 * Bug in GTK. Calling setTopItem() can scroll to the wrong item
1336 * when the 'tree view' is dirty. Set it again once it is clean.
1338 if (SWT
.getPlatform().equals("gtk")) { //$NON-NLS-1$
1339 tree
.getDisplay().asyncExec(() -> {
1340 TreeItem topItem
= tree
.getTopItem();
1341 if (!tree
.isDisposed() && topItem
!= null && !topItem
.isDisposed()) {
1342 tree
.setTopItem(topItem
);
1348 /* Make sure the paint event is triggered. */
1352 private void doAlignTreeItems() {
1353 Tree tree
= fTreeViewer
.getTree();
1354 List
<TreeItem
> treeItems
= getVisibleExpandedItems(tree
, false);
1355 int topIndex
= fTimeGraphViewer
.getTopIndex();
1356 if (topIndex
>= treeItems
.size()) {
1359 TreeItem item
= treeItems
.get(topIndex
);
1361 // get the first filler item so we can calculate the last item's height
1362 TreeItem fillerItem
= null;
1363 for (TreeItem treeItem
: fTreeViewer
.getTree().getItems()) {
1364 if (treeItem
.getData() == FILLER
) {
1365 fillerItem
= treeItem
;
1370 // ensure the time graph item heights are equal to the tree item heights
1371 int treeHeight
= fTreeViewer
.getTree().getBounds().height
;
1372 int index
= topIndex
;
1373 Rectangle bounds
= item
.getBounds();
1374 while (index
< treeItems
.size()) {
1375 if (bounds
.y
> treeHeight
) {
1378 TreeItem nextItem
= (index
+ 1 == treeItems
.size()) ? fillerItem
: treeItems
.get(index
+ 1);
1379 Rectangle nextBounds
= alignTreeItem(item
, bounds
, nextItem
);
1382 bounds
= nextBounds
;
1386 * When an item's height in the time graph changes, it is possible that
1387 * the time graph readjusts its top index to fill empty space at the
1388 * bottom of the viewer. Calling method setTopIndex() triggers this
1389 * adjustment, if needed. In that case, we need to make sure that the
1390 * newly visible items at the top of the viewer are also aligned.
1392 fTimeGraphViewer
.setTopIndex(topIndex
);
1393 if (fTimeGraphViewer
.getTopIndex() != topIndex
) {
1394 alignTreeItems(false);
1398 private Rectangle
alignTreeItem(TreeItem item
, Rectangle bounds
, TreeItem nextItem
) {
1400 * Bug in Linux. The method getBounds doesn't always return the correct height.
1401 * Use the difference of y position between items to calculate the height.
1403 Rectangle nextBounds
= nextItem
.getBounds();
1404 Integer itemHeight
= nextBounds
.y
- bounds
.y
;
1405 if (itemHeight
> 0) {
1406 ITimeGraphEntry entry
= (ITimeGraphEntry
) item
.getData();
1407 fTimeGraphViewer
.getTimeGraphControl().setItemHeight(entry
, itemHeight
);
1413 * Return the time alignment information
1415 * @return the time alignment information
1417 * @see ITmfTimeAligned
1421 public TmfTimeViewAlignmentInfo
getTimeViewAlignmentInfo() {
1422 Point location
= fSashForm
.toDisplay(0, 0);
1423 int timeAxisOffset
= fTreeViewer
.getControl().getSize().x
+ fSashForm
.getSashWidth();
1424 return new TmfTimeViewAlignmentInfo(fSashForm
.getShell(), location
, timeAxisOffset
);
1428 * Return the available width for the time-axis.
1430 * @see ITmfTimeAligned
1432 * @param requestedOffset
1433 * the requested offset
1434 * @return the available width for the time-axis
1438 public int getAvailableWidth(int requestedOffset
) {
1439 int vBarWidth
= ((fTimeGraphViewer
.getVerticalBar() != null) && (fTimeGraphViewer
.getVerticalBar().isVisible())) ? fTimeGraphViewer
.getVerticalBar().getSize().x
: 0;
1440 int totalWidth
= fSashForm
.getBounds().width
;
1441 return Math
.min(totalWidth
, Math
.max(0, totalWidth
- requestedOffset
- vBarWidth
));
1445 * Perform the alignment operation.
1448 * the alignment offset
1450 * the alignment width
1452 * @see ITmfTimeAligned
1456 public void performAlign(int offset
, int width
) {
1457 int total
= fSashForm
.getBounds().width
;
1458 int timeAxisOffset
= Math
.min(offset
, total
);
1459 int width1
= Math
.max(0, timeAxisOffset
- fSashForm
.getSashWidth());
1460 int width2
= total
- timeAxisOffset
;
1461 if (width1
>= 0 && width2
> 0 || width1
> 0 && width2
>= 0) {
1462 fSashForm
.setWeights(new int[] { width1
, width2
});
1466 Composite composite
= fTimeGraphViewer
.getTimeAlignedComposite();
1467 GridLayout layout
= (GridLayout
) composite
.getLayout();
1468 int timeBasedControlsWidth
= composite
.getSize().x
;
1469 int marginSize
= timeBasedControlsWidth
- width
;
1470 layout
.marginRight
= Math
.max(0, marginSize
);