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