e741579a382e0c82ef249804820b22f4d3cfb356
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / widgets / timegraph / TimeGraphViewer.java
1 /*****************************************************************************
2 * Copyright (c) 2007, 2017 Intel Corporation, Ericsson, others
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Intel Corporation - Initial API and implementation
10 * Ruslan A. Scherbakov, Intel - Initial API and implementation
11 * Alexander N. Alexeev, Intel - Add monitors statistics support
12 * Alvaro Sanchez-Leon - Adapted for TMF
13 * Patrick Tasse - Refactoring
14 * Geneviève Bastien - Add event links between entries
15 *****************************************************************************/
16
17 package org.eclipse.tracecompass.tmf.ui.widgets.timegraph;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26
27 import org.eclipse.jdt.annotation.NonNull;
28 import org.eclipse.jface.action.Action;
29 import org.eclipse.jface.action.ActionContributionItem;
30 import org.eclipse.jface.action.IAction;
31 import org.eclipse.jface.action.IMenuCreator;
32 import org.eclipse.jface.action.IMenuListener;
33 import org.eclipse.jface.action.IMenuManager;
34 import org.eclipse.jface.action.MenuManager;
35 import org.eclipse.jface.dialogs.IDialogSettings;
36 import org.eclipse.jface.resource.ImageDescriptor;
37 import org.eclipse.jface.viewers.AbstractTreeViewer;
38 import org.eclipse.jface.viewers.ISelection;
39 import org.eclipse.jface.viewers.ISelectionProvider;
40 import org.eclipse.jface.viewers.IStructuredSelection;
41 import org.eclipse.jface.viewers.ITableLabelProvider;
42 import org.eclipse.jface.viewers.ITreeContentProvider;
43 import org.eclipse.jface.viewers.SelectionChangedEvent;
44 import org.eclipse.jface.viewers.StructuredSelection;
45 import org.eclipse.jface.viewers.Viewer;
46 import org.eclipse.jface.viewers.ViewerFilter;
47 import org.eclipse.jface.window.Window;
48 import org.eclipse.swt.SWT;
49 import org.eclipse.swt.events.ControlAdapter;
50 import org.eclipse.swt.events.ControlEvent;
51 import org.eclipse.swt.events.KeyAdapter;
52 import org.eclipse.swt.events.KeyEvent;
53 import org.eclipse.swt.events.MenuDetectListener;
54 import org.eclipse.swt.events.MouseEvent;
55 import org.eclipse.swt.events.MouseWheelListener;
56 import org.eclipse.swt.events.PaintEvent;
57 import org.eclipse.swt.events.PaintListener;
58 import org.eclipse.swt.events.SelectionAdapter;
59 import org.eclipse.swt.events.SelectionEvent;
60 import org.eclipse.swt.events.SelectionListener;
61 import org.eclipse.swt.graphics.Point;
62 import org.eclipse.swt.graphics.RGBA;
63 import org.eclipse.swt.graphics.Rectangle;
64 import org.eclipse.swt.layout.FillLayout;
65 import org.eclipse.swt.layout.GridData;
66 import org.eclipse.swt.layout.GridLayout;
67 import org.eclipse.swt.widgets.Composite;
68 import org.eclipse.swt.widgets.Control;
69 import org.eclipse.swt.widgets.Display;
70 import org.eclipse.swt.widgets.Event;
71 import org.eclipse.swt.widgets.Listener;
72 import org.eclipse.swt.widgets.Menu;
73 import org.eclipse.swt.widgets.Slider;
74 import org.eclipse.swt.widgets.Tree;
75 import org.eclipse.swt.widgets.TreeColumn;
76 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
77 import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
78 import org.eclipse.tracecompass.internal.tmf.ui.Messages;
79 import org.eclipse.tracecompass.internal.tmf.ui.dialogs.AddBookmarkDialog;
80 import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
81 import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
82 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.ShowFilterDialogAction;
83 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.TimeGraphLegend;
84 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
85 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent;
86 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
87 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
88 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.MarkerEvent;
89 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.IMarkerAxisListener;
90 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.ITimeDataProvider;
91 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeDataProviderCyclesConverter;
92 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphColorScheme;
93 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
94 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphMarkerAxis;
95 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphScale;
96 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphTooltipHandler;
97 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils;
98 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
99 import org.eclipse.ui.PlatformUI;
100
101 /**
102 * Generic time graph viewer implementation
103 *
104 * @author Patrick Tasse, and others
105 */
106 public class TimeGraphViewer extends Viewer implements ITimeDataProvider, IMarkerAxisListener, SelectionListener {
107
108 /** Constant indicating that all levels of the time graph should be expanded */
109 public static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
110
111 private static final int DEFAULT_NAME_WIDTH = 200;
112 private static final int MIN_NAME_WIDTH = 3;
113 private static final int MAX_NAME_WIDTH = 1000;
114 private static final int DEFAULT_HEIGHT = 22;
115 private static final String HIDE_ARROWS_KEY = "hide.arrows"; //$NON-NLS-1$
116 private static final long DEFAULT_FREQUENCY = 1000000000L;
117 private static final int H_SCROLLBAR_MAX = Integer.MAX_VALUE - 1;
118
119 private static final ImageDescriptor ADD_BOOKMARK = Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ADD_BOOKMARK);
120 private static final ImageDescriptor NEXT_BOOKMARK = Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_BOOKMARK);
121 private static final ImageDescriptor PREVIOUS_BOOKMARK = Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREVIOUS_BOOKMARK);
122 private static final ImageDescriptor REMOVE_BOOKMARK = Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_REMOVE_BOOKMARK);
123
124 private long fMinTimeInterval;
125 private ITimeGraphEntry fSelectedEntry;
126 private long fBeginTime = SWT.DEFAULT; // The user-specified bounds start time
127 private long fEndTime = SWT.DEFAULT; // The user-specified bounds end time
128 private long fTime0 = SWT.DEFAULT; // The current window start time
129 private long fTime1 = SWT.DEFAULT; // The current window end time
130 private long fSelectionBegin = SWT.DEFAULT;
131 private long fSelectionEnd = SWT.DEFAULT;
132 private long fTime0Bound = SWT.DEFAULT; // The bounds start time
133 private long fTime1Bound = SWT.DEFAULT; // The bounds end time
134 private long fTime0ExtSynch = SWT.DEFAULT;
135 private long fTime1ExtSynch = SWT.DEFAULT;
136 private boolean fTimeRangeFixed;
137 private int fNameWidthPref = DEFAULT_NAME_WIDTH;
138 private int fMinNameWidth = MIN_NAME_WIDTH;
139 private int fNameWidth;
140 private int[] fWeights;
141 private Composite fDataViewer;
142
143 private TimeGraphControl fTimeGraphCtrl;
144 private Tree fTree;
145 private TimeGraphScale fTimeScaleCtrl;
146 private TimeGraphMarkerAxis fMarkerAxisCtrl;
147 private Slider fHorizontalScrollBar;
148 private Slider fVerticalScrollBar;
149 private @NonNull TimeGraphColorScheme fColorScheme = new TimeGraphColorScheme();
150 private Object fInputElement;
151 private ITimeGraphContentProvider fTimeGraphContentProvider;
152 private ITimeGraphPresentationProvider fTimeGraphProvider;
153 private ITableLabelProvider fLabelProvider;
154 private @NonNull ITimeDataProvider fTimeDataProvider = this;
155 private TimeGraphTooltipHandler fToolTipHandler;
156
157 private List<ITimeGraphSelectionListener> fSelectionListeners = new ArrayList<>();
158 private List<ITimeGraphTimeListener> fTimeListeners = new ArrayList<>();
159 private List<ITimeGraphRangeListener> fRangeListeners = new ArrayList<>();
160 private List<ITimeGraphBookmarkListener> fBookmarkListeners = new ArrayList<>();
161
162 // Time format, using Epoch reference, Relative time format(default),
163 // Number, or Cycles
164 private TimeFormat fTimeFormat = TimeFormat.RELATIVE;
165 // Clock frequency to use for Cycles time format
166 private long fClockFrequency = DEFAULT_FREQUENCY;
167 private int fBorderWidth = 0;
168 private int fTimeScaleHeight = DEFAULT_HEIGHT;
169
170 private Action fResetScaleAction;
171 private Action fShowLegendAction;
172 private Action fNextEventAction;
173 private Action fPrevEventAction;
174 private Action fNextItemAction;
175 private Action fPreviousItemAction;
176 private Action fZoomInAction;
177 private Action fZoomOutAction;
178 private Action fHideArrowsAction;
179 private Action fFollowArrowFwdAction;
180 private Action fFollowArrowBwdAction;
181 private ShowFilterDialogAction fShowFilterDialogAction;
182 private Action fToggleBookmarkAction;
183 private Action fNextMarkerAction;
184 private Action fPreviousMarkerAction;
185 private MenuManager fMarkersMenu;
186
187 /** The list of bookmarks */
188 private final List<IMarkerEvent> fBookmarks = new ArrayList<>();
189
190 /** The list of marker categories */
191 private final List<String> fMarkerCategories = new ArrayList<>();
192
193 /** The set of hidden marker categories */
194 private final Set<String> fHiddenMarkerCategories = new HashSet<>();
195
196 /** The set of skipped marker categories */
197 private final Set<String> fSkippedMarkerCategories = new HashSet<>();
198
199 /** The list of markers */
200 private final List<IMarkerEvent> fMarkers = new ArrayList<>();
201
202 private ListenerNotifier fListenerNotifier;
203
204 private Composite fTimeAlignedComposite;
205
206 private class ListenerNotifier extends Thread {
207 private static final long DELAY = 400L;
208 private static final long POLLING_INTERVAL = 10L;
209 private long fLastUpdateTime = Long.MAX_VALUE;
210 private boolean fSelectionChanged = false;
211 private boolean fTimeRangeUpdated = false;
212 private boolean fTimeSelected = false;
213
214 @Override
215 public void run() {
216 while ((System.currentTimeMillis() - fLastUpdateTime) < DELAY) {
217 try {
218 Thread.sleep(POLLING_INTERVAL);
219 } catch (Exception e) {
220 return;
221 }
222 }
223 Display.getDefault().asyncExec(new Runnable() {
224 @Override
225 public void run() {
226 if (fListenerNotifier != ListenerNotifier.this) {
227 return;
228 }
229 fListenerNotifier = null;
230 if (ListenerNotifier.this.isInterrupted() || fDataViewer.isDisposed()) {
231 return;
232 }
233 if (fSelectionChanged) {
234 fireSelectionChanged(fSelectedEntry);
235 }
236 if (fTimeRangeUpdated) {
237 fireTimeRangeUpdated(fTime0, fTime1);
238 }
239 if (fTimeSelected) {
240 fireTimeSelected(fSelectionBegin, fSelectionEnd);
241 }
242 }
243 });
244 }
245
246 public void selectionChanged() {
247 fSelectionChanged = true;
248 fLastUpdateTime = System.currentTimeMillis();
249 }
250
251 public void timeRangeUpdated() {
252 fTimeRangeUpdated = true;
253 fLastUpdateTime = System.currentTimeMillis();
254 }
255
256 public void timeSelected() {
257 fTimeSelected = true;
258 fLastUpdateTime = System.currentTimeMillis();
259 }
260
261 public boolean hasSelectionChanged() {
262 return fSelectionChanged;
263 }
264
265 public boolean hasTimeRangeUpdated() {
266 return fTimeRangeUpdated;
267 }
268
269 public boolean hasTimeSelected() {
270 return fTimeSelected;
271 }
272 }
273
274 private final static class MarkerComparator implements Comparator<IMarkerEvent> {
275 @Override
276 public int compare(IMarkerEvent o1, IMarkerEvent o2) {
277 int res = Long.compare(o1.getTime(), o2.getTime());
278 if (res != 0) {
279 return res;
280 }
281 return Long.compare(o1.getDuration(), o2.getDuration());
282 }
283 }
284
285 /**
286 * Standard constructor.
287 * <p>
288 * The default timegraph content provider accepts an ITimeGraphEntry[] as input element.
289 *
290 * @param parent
291 * The parent UI composite object
292 * @param style
293 * The style to use
294 */
295 public TimeGraphViewer(Composite parent, int style) {
296 createDataViewer(parent, style);
297 fTimeGraphContentProvider = new TimeGraphContentProvider();
298 }
299
300 /**
301 * Sets the timegraph content provider used by this timegraph viewer.
302 *
303 * @param timeGraphContentProvider
304 * the timegraph content provider
305 */
306 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider) {
307 fTimeGraphContentProvider = timeGraphContentProvider;
308 }
309
310 /**
311 * Gets the timegraph content provider used by this timegraph viewer.
312 *
313 * @return the timegraph content provider
314 */
315 public ITimeGraphContentProvider getTimeGraphContentProvider() {
316 return fTimeGraphContentProvider;
317 }
318
319 /**
320 * Sets the timegraph presentation provider used by this timegraph viewer.
321 *
322 * @param timeGraphProvider
323 * the timegraph provider
324 */
325 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
326 fTimeGraphProvider = timeGraphProvider;
327 fTimeGraphCtrl.setTimeGraphProvider(timeGraphProvider);
328 fToolTipHandler = new TimeGraphTooltipHandler(fTimeGraphProvider, fTimeDataProvider);
329 fToolTipHandler.activateHoverHelp(fTimeGraphCtrl);
330 }
331
332 /**
333 * Sets the tree label provider used for the name space
334 *
335 * @param labelProvider the tree label provider
336 * @since 2.3
337 */
338 public void setTimeGraphLabelProvider(ITableLabelProvider labelProvider) {
339 fLabelProvider = labelProvider;
340 if (fTimeGraphCtrl != null) {
341 fTimeGraphCtrl.setLabelProvider(labelProvider);
342 }
343 }
344
345 /**
346 * Sets the tree columns for this time graph combo's filter dialog.
347 *
348 * @param columnNames the tree column names
349 * @since 1.2
350 */
351 public void setFilterColumns(String[] columnNames) {
352 getShowFilterDialogAction().getFilterDialog().setColumnNames(columnNames);
353 }
354
355 /**
356 * Sets the tree content provider used by the filter dialog
357 *
358 * @param contentProvider the tree content provider
359 * @since 1.2
360 */
361 public void setFilterContentProvider(ITreeContentProvider contentProvider) {
362 getShowFilterDialogAction().getFilterDialog().setContentProvider(contentProvider);
363 }
364
365 /**
366 * Sets the tree label provider used by the filter dialog
367 *
368 * @param labelProvider the tree label provider
369 * @since 1.2
370 */
371 public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
372 getShowFilterDialogAction().getFilterDialog().setLabelProvider(labelProvider);
373 }
374
375 @Override
376 public void setInput(Object inputElement) {
377 Object oldInput = fInputElement;
378 fTimeGraphContentProvider.inputChanged(this, oldInput, inputElement);
379 fInputElement = inputElement;
380 ITimeGraphEntry[] input = fTimeGraphContentProvider.getElements(inputElement);
381 fListenerNotifier = null;
382 if (fTimeGraphCtrl != null) {
383 setTimeRange(input);
384 setTopIndex(0);
385 fSelectionBegin = SWT.DEFAULT;
386 fSelectionEnd = SWT.DEFAULT;
387 updateMarkerActions();
388 fSelectedEntry = null;
389 refreshAllData(input);
390 }
391 }
392
393 @Override
394 public Object getInput() {
395 return fInputElement;
396 }
397
398 /**
399 * Sets (or clears if null) the list of links to display on this combo
400 *
401 * @param links
402 * the links to display in this time graph combo
403 */
404 public void setLinks(List<ILinkEvent> links) {
405 if (fTimeGraphCtrl != null) {
406 fTimeGraphCtrl.refreshArrows(links);
407 }
408 }
409
410 @Override
411 public void refresh() {
412 ITimeGraphEntry[] input = fTimeGraphContentProvider.getElements(fInputElement);
413 setTimeRange(input);
414 refreshAllData(input);
415 }
416
417 /**
418 * Callback for when the control is moved
419 *
420 * @param e
421 * The caller event
422 */
423 public void controlMoved(ControlEvent e) {
424 }
425
426 /**
427 * Callback for when the control is resized
428 *
429 * @param e
430 * The caller event
431 */
432 public void controlResized(ControlEvent e) {
433 resizeControls();
434 }
435
436 /**
437 * @return The string representing the view type
438 */
439 protected String getViewTypeStr() {
440 return "viewoption.threads"; //$NON-NLS-1$
441 }
442
443 int getMarginWidth() {
444 return 0;
445 }
446
447 int getMarginHeight() {
448 return 0;
449 }
450
451 void loadOptions() {
452 fMinTimeInterval = 1;
453 fSelectionBegin = SWT.DEFAULT;
454 fSelectionEnd = SWT.DEFAULT;
455 fNameWidth = Utils.loadIntOption(getPreferenceString("namewidth"), //$NON-NLS-1$
456 fNameWidthPref, fMinNameWidth, MAX_NAME_WIDTH);
457 }
458
459 void saveOptions() {
460 Utils.saveIntOption(getPreferenceString("namewidth"), fNameWidth); //$NON-NLS-1$
461 }
462
463 /**
464 * Create a data viewer.
465 *
466 * @param parent
467 * Parent composite
468 * @param style
469 * Style to use
470 * @return The new data viewer
471 */
472 protected Control createDataViewer(Composite parent, int style) {
473 loadOptions();
474 fDataViewer = new Composite(parent, style) {
475 @Override
476 public void redraw() {
477 fTree.redraw();
478 fTimeScaleCtrl.redraw();
479 fTimeGraphCtrl.redraw();
480 fMarkerAxisCtrl.redraw();
481 super.redraw();
482 }
483 };
484 fDataViewer.addDisposeListener((e) -> {
485 if (fMarkersMenu != null) {
486 fMarkersMenu.dispose();
487 }
488 });
489 GridLayout gl = new GridLayout(2, false);
490 gl.marginHeight = fBorderWidth;
491 gl.marginWidth = 0;
492 gl.verticalSpacing = 0;
493 gl.horizontalSpacing = 0;
494 fDataViewer.setLayout(gl);
495
496 fTimeAlignedComposite = new Composite(fDataViewer, style) {
497 @Override
498 public void redraw() {
499 fDataViewer.redraw();
500 super.redraw();
501 }
502 };
503 GridLayout gl2 = new GridLayout(2, false);
504 gl2.marginHeight = fBorderWidth;
505 gl2.marginWidth = 0;
506 gl2.verticalSpacing = 0;
507 gl2.horizontalSpacing = 0;
508 fTimeAlignedComposite.setLayout(gl2);
509 fTimeAlignedComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
510
511 fTree = new Tree(fTimeAlignedComposite, SWT.NO_SCROLL);
512 GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false);
513 gd.widthHint = fNameWidth;
514 fTree.setLayoutData(gd);
515 fTree.setHeaderVisible(true);
516 // add a default column
517 TreeColumn column = new TreeColumn(fTree, SWT.LEFT);
518 column.setResizable(false);
519
520 /*
521 * Bug in Linux. The tree header height is 0 in constructor, so we need
522 * to reset it later when the control is painted. This work around used
523 * to be done on control resized but the header height was not
524 * initialized on the initial resize on GTK3.
525 */
526 fTree.addPaintListener(new PaintListener() {
527 @Override
528 public void paintControl(PaintEvent e) {
529 int headerHeight = fTree.getHeaderHeight();
530 if (headerHeight > 0) {
531 fTree.removePaintListener(this);
532 setHeaderHeight(headerHeight);
533 }
534 }
535 });
536
537 fTimeScaleCtrl = new TimeGraphScale(fTimeAlignedComposite, fColorScheme);
538 fTimeScaleCtrl.setTimeProvider(fTimeDataProvider);
539 fTimeScaleCtrl.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false));
540 fTimeScaleCtrl.setHeight(fTimeScaleHeight);
541 fTimeScaleCtrl.addMouseWheelListener(new MouseWheelListener() {
542 @Override
543 public void mouseScrolled(MouseEvent e) {
544 if (e.count == 0) {
545 return;
546 }
547 if ((e.stateMask & SWT.CTRL) != 0) {
548 fTimeGraphCtrl.zoom(e.count > 0);
549 } else {
550 fTimeGraphCtrl.horizontalScroll(e.count > 0);
551 }
552 }
553 });
554
555 fTimeGraphCtrl = createTimeGraphControl(fTimeAlignedComposite, fColorScheme);
556
557 fTimeGraphCtrl.setTimeProvider(this);
558 fTimeGraphCtrl.setLabelProvider(fLabelProvider);
559 fTimeGraphCtrl.setTree(fTree);
560 fTimeGraphCtrl.setTimeGraphScale(fTimeScaleCtrl);
561 fTimeGraphCtrl.addSelectionListener(this);
562 fTimeGraphCtrl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
563 fTimeGraphCtrl.addMouseWheelListener(new MouseWheelListener() {
564 @Override
565 public void mouseScrolled(MouseEvent e) {
566 if (e.count == 0) {
567 return;
568 }
569 /*
570 * On some platforms the mouse scroll event is sent to the
571 * control that has focus even if it is not under the cursor.
572 * Handle the event only if not over the time graph control.
573 */
574 Point ctrlParentCoords = fTimeAlignedComposite.toControl(fTimeGraphCtrl.toDisplay(e.x, e.y));
575 Point scrollBarParentCoords = fDataViewer.toControl(fTimeGraphCtrl.toDisplay(e.x, e.y));
576 if (fTimeGraphCtrl.getBounds().contains(ctrlParentCoords)) {
577 /* the time graph control handles the event */
578 adjustVerticalScrollBar();
579 } else if (fTimeScaleCtrl.getBounds().contains(ctrlParentCoords)
580 || fMarkerAxisCtrl.getBounds().contains(ctrlParentCoords)
581 || fHorizontalScrollBar.getBounds().contains(scrollBarParentCoords)) {
582 if ((e.stateMask & SWT.CTRL) != 0) {
583 fTimeGraphCtrl.zoom(e.count > 0);
584 } else {
585 fTimeGraphCtrl.horizontalScroll(e.count > 0);
586 }
587 } else {
588 /* over the vertical scroll bar or outside of the viewer */
589 setTopIndex(getTopIndex() - e.count);
590 }
591 }
592 });
593 fTimeGraphCtrl.addKeyListener(new KeyAdapter() {
594 @Override
595 public void keyPressed(KeyEvent e) {
596 if (e.keyCode == '.') {
597 boolean extend = (e.stateMask & SWT.SHIFT) != 0;
598 if (extend) {
599 extendToNextMarker();
600 } else {
601 selectNextMarker();
602 }
603 } else if (e.keyCode == ',') {
604 boolean extend = (e.stateMask & SWT.SHIFT) != 0;
605 if (extend) {
606 extendToPrevMarker();
607 } else {
608 selectPrevMarker();
609 }
610 }
611 adjustVerticalScrollBar();
612 }
613 });
614
615 fMarkerAxisCtrl = createTimeGraphMarkerAxis(fTimeAlignedComposite, fColorScheme, this);
616 fMarkerAxisCtrl.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false, 2, 1));
617 fMarkerAxisCtrl.addMarkerAxisListener(this);
618 fMarkerAxisCtrl.addMouseWheelListener(new MouseWheelListener() {
619 @Override
620 public void mouseScrolled(MouseEvent e) {
621 if (e.count == 0) {
622 return;
623 }
624 if ((e.stateMask & SWT.CTRL) != 0) {
625 fTimeGraphCtrl.zoom(e.count > 0);
626 } else {
627 fTimeGraphCtrl.horizontalScroll(e.count > 0);
628 }
629 }
630 });
631
632 fVerticalScrollBar = new Slider(fDataViewer, SWT.VERTICAL | SWT.NO_FOCUS);
633 fVerticalScrollBar.setLayoutData(new GridData(SWT.DEFAULT, SWT.FILL, false, true, 1, 1));
634 fVerticalScrollBar.addSelectionListener(new SelectionAdapter() {
635 @Override
636 public void widgetSelected(SelectionEvent e) {
637 setTopIndex(fVerticalScrollBar.getSelection());
638 }
639 });
640
641 fHorizontalScrollBar = new Slider(fDataViewer, SWT.HORIZONTAL | SWT.NO_FOCUS);
642 fHorizontalScrollBar.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false));
643 fHorizontalScrollBar.addListener(SWT.MouseWheel, new Listener() {
644 @Override
645 public void handleEvent(Event event) {
646 // don't handle the immediately following SWT.Selection event
647 event.doit = false;
648 if (event.count == 0) {
649 return;
650 }
651 if ((event.stateMask & SWT.CTRL) != 0) {
652 fTimeGraphCtrl.zoom(event.count > 0);
653 } else {
654 fTimeGraphCtrl.horizontalScroll(event.count > 0);
655 }
656 }
657 });
658 fHorizontalScrollBar.addListener(SWT.Selection, new Listener() {
659 @Override
660 public void handleEvent(Event event) {
661 int start = fHorizontalScrollBar.getSelection();
662 long time0 = getTime0();
663 long time1 = getTime1();
664 long timeMin = getMinTime();
665 long timeMax = getMaxTime();
666 long delta = timeMax - timeMin;
667
668 long range = time1 - time0;
669 time0 = timeMin + Math.round(delta * ((double) start / H_SCROLLBAR_MAX));
670 time1 = time0 + range;
671
672 setStartFinishTimeNotify(time0, time1);
673 }
674 });
675
676 Composite filler = new Composite(fDataViewer, SWT.NONE);
677 gd = new GridData(SWT.DEFAULT, SWT.DEFAULT, false, false);
678 gd.heightHint = fHorizontalScrollBar.getSize().y;
679 filler.setLayoutData(gd);
680 filler.setLayout(new FillLayout());
681
682 fTimeGraphCtrl.addControlListener(new ControlAdapter() {
683 @Override
684 public void controlResized(ControlEvent event) {
685 resizeControls();
686 }
687 });
688 resizeControls();
689 fDataViewer.update();
690 adjustHorizontalScrollBar();
691 adjustVerticalScrollBar();
692
693 fDataViewer.addDisposeListener((e) -> {
694 saveOptions();
695 fColorScheme.dispose();
696 });
697
698 return fDataViewer;
699 }
700
701 /**
702 * Dispose the time graph viewer.
703 */
704 public void dispose() {
705 fDataViewer.dispose();
706 }
707
708 /**
709 * Create a new time graph control.
710 *
711 * @param parent
712 * The parent composite
713 * @param colors
714 * The color scheme
715 * @return The new TimeGraphControl
716 */
717 protected TimeGraphControl createTimeGraphControl(Composite parent,
718 TimeGraphColorScheme colors) {
719 return new TimeGraphControl(parent, colors);
720 }
721
722 /**
723 * Create a new time graph marker axis.
724 *
725 * @param parent
726 * The parent composite object
727 * @param colorScheme
728 * The color scheme to use
729 * @param timeProvider
730 * The time data provider
731 * @return The new TimeGraphMarkerAxis
732 * @since 2.0
733 */
734 protected TimeGraphMarkerAxis createTimeGraphMarkerAxis(Composite parent,
735 @NonNull TimeGraphColorScheme colorScheme, @NonNull ITimeDataProvider timeProvider) {
736 return new TimeGraphMarkerAxis(parent, colorScheme, timeProvider);
737 }
738
739 /**
740 * Resize the controls
741 */
742 public void resizeControls() {
743 Rectangle r = fDataViewer.getClientArea();
744 if (r.isEmpty()) {
745 return;
746 }
747
748 if (fWeights != null) {
749 setWeights(fWeights);
750 fWeights = null;
751 }
752 int width = r.width;
753 if (fNameWidth > width - fMinNameWidth) {
754 fNameWidth = width - fMinNameWidth;
755 }
756 if (fNameWidth < fMinNameWidth) {
757 fNameWidth = fMinNameWidth;
758 }
759 GridData gd = (GridData) fTree.getLayoutData();
760 gd.widthHint = fNameWidth;
761 if (fTree.getColumnCount() == 1) {
762 fTree.getColumn(0).setWidth(fNameWidth);
763 }
764 adjustHorizontalScrollBar();
765 adjustVerticalScrollBar();
766 }
767
768 /**
769 * Recalculate the time bounds based on the time graph entries,
770 * if the user-specified bound is set to SWT.DEFAULT.
771 *
772 * @param entries
773 * The root time graph entries in the model
774 */
775 public void setTimeRange(ITimeGraphEntry entries[]) {
776 fTime0Bound = (fBeginTime != SWT.DEFAULT ? fBeginTime : fEndTime);
777 fTime1Bound = (fEndTime != SWT.DEFAULT ? fEndTime : fBeginTime);
778 if (fBeginTime != SWT.DEFAULT && fEndTime != SWT.DEFAULT) {
779 return;
780 }
781 if (entries == null || entries.length == 0) {
782 return;
783 }
784 if (fTime0Bound == SWT.DEFAULT) {
785 fTime0Bound = Long.MAX_VALUE;
786 }
787 if (fTime1Bound == SWT.DEFAULT) {
788 fTime1Bound = Long.MIN_VALUE;
789 }
790 for (ITimeGraphEntry entry : entries) {
791 setTimeRange(entry);
792 }
793 if (fTime0Bound > fTime1Bound) {
794 fTime0Bound = SWT.DEFAULT;
795 fTime1Bound = SWT.DEFAULT;
796 }
797 }
798
799 private void setTimeRange(ITimeGraphEntry entry) {
800 if (fBeginTime == SWT.DEFAULT && entry.hasTimeEvents() && entry.getStartTime() != SWT.DEFAULT) {
801 fTime0Bound = Math.min(entry.getStartTime(), fTime0Bound);
802 }
803 if (fEndTime == SWT.DEFAULT && entry.hasTimeEvents() && entry.getEndTime() != SWT.DEFAULT) {
804 fTime1Bound = Math.max(entry.getEndTime(), fTime1Bound);
805 }
806 if (entry.hasChildren()) {
807 for (ITimeGraphEntry child : entry.getChildren()) {
808 setTimeRange(child);
809 }
810 }
811 }
812
813 /**
814 * Set the time bounds to the provided values.
815 *
816 * @param beginTime
817 * The bounds begin time, or SWT.DEFAULT to use the input bounds
818 * @param endTime
819 * The bounds end time, or SWT.DEFAULT to use the input bounds
820 */
821 public void setTimeBounds(long beginTime, long endTime) {
822 fBeginTime = beginTime;
823 fEndTime = endTime;
824 fTime0Bound = (fBeginTime != SWT.DEFAULT ? fBeginTime : fEndTime);
825 fTime1Bound = (fEndTime != SWT.DEFAULT ? fEndTime : fBeginTime);
826 if (fTime0Bound > fTime1Bound) {
827 // only possible if both are not default
828 fBeginTime = endTime;
829 fEndTime = beginTime;
830 fTime0Bound = fBeginTime;
831 fTime1Bound = fEndTime;
832 }
833 adjustHorizontalScrollBar();
834 }
835
836 /**
837 * Recalculate the current time window when bounds have changed.
838 */
839 public void setTimeBounds() {
840 if (!fTimeRangeFixed) {
841 fTime0 = fTime0Bound;
842 fTime1 = fTime1Bound;
843 }
844 fTime0 = Math.max(fTime0Bound, Math.min(fTime0, fTime1Bound));
845 fTime1 = Math.max(fTime0Bound, Math.min(fTime1, fTime1Bound));
846 if (fTime1 - fTime0 < fMinTimeInterval) {
847 fTime1 = Math.min(fTime1Bound, fTime0 + fMinTimeInterval);
848 }
849 }
850
851 /**
852 * @param traces
853 */
854 private void refreshAllData(ITimeGraphEntry[] traces) {
855 setTimeBounds();
856 if (fSelectionBegin < fBeginTime) {
857 fSelectionBegin = fBeginTime;
858 } else if (fSelectionBegin > fEndTime) {
859 fSelectionBegin = fEndTime;
860 }
861 if (fSelectionEnd < fBeginTime) {
862 fSelectionEnd = fBeginTime;
863 } else if (fSelectionEnd > fEndTime) {
864 fSelectionEnd = fEndTime;
865 }
866 fTimeGraphCtrl.refreshData(traces);
867 fTimeScaleCtrl.redraw();
868 fMarkerAxisCtrl.redraw();
869 updateMarkerActions();
870 adjustVerticalScrollBar();
871 }
872
873 /**
874 * Callback for when this view is focused
875 */
876 public void setFocus() {
877 if (null != fTimeGraphCtrl) {
878 fTimeGraphCtrl.setFocus();
879 }
880 }
881
882 /**
883 * Get the current focus status of this view.
884 *
885 * @return If the view is currently focused, or not
886 */
887 public boolean isInFocus() {
888 return fTimeGraphCtrl.isInFocus();
889 }
890
891 /**
892 * Get the view's current selection
893 *
894 * @return The entry that is selected
895 */
896 @Override
897 public ITimeGraphEntry getSelection() {
898 return fTimeGraphCtrl.getSelectedTrace();
899 }
900
901 /**
902 * Get the index of the current selection
903 *
904 * @return The index
905 */
906 public int getSelectionIndex() {
907 return fTimeGraphCtrl.getSelectedIndex();
908 }
909
910 @Override
911 public long getTime0() {
912 return fTime0;
913 }
914
915 @Override
916 public long getTime1() {
917 return fTime1;
918 }
919
920 @Override
921 public long getMinTimeInterval() {
922 return fMinTimeInterval;
923 }
924
925 /**
926 * Sets the relative horizontal weight of each part of the time graph
927 * viewer. The first number is the name space weight, and the second number
928 * is the time space weight.
929 *
930 * @param weights
931 * The array of relative weights of each part of the viewer
932 * @since 2.3
933 */
934 public void setWeights(final int[] weights) {
935 if (weights.length != 2) {
936 return;
937 }
938 int width = fTimeAlignedComposite.getSize().x;
939 if (width == 0) {
940 /* the weigths will be applied when the control is resized */
941 fWeights = Arrays.copyOf(weights, weights.length);
942 return;
943 }
944 setNameSpace(width * weights[0] / (weights[0] + weights[1]));
945 }
946
947 @Override
948 public int getNameSpace() {
949 return fNameWidth;
950 }
951
952 @Override
953 public void setNameSpace(int width) {
954 fNameWidth = width;
955 int w = fTimeGraphCtrl.getClientArea().width;
956 if (fNameWidth > w - MIN_NAME_WIDTH) {
957 fNameWidth = w - MIN_NAME_WIDTH;
958 }
959 if (fNameWidth < MIN_NAME_WIDTH) {
960 fNameWidth = MIN_NAME_WIDTH;
961 }
962 GridData gd = (GridData) fTree.getLayoutData();
963 gd.widthHint = fNameWidth;
964 if (fTree.getColumnCount() == 1) {
965 fTree.getColumn(0).setWidth(fNameWidth);
966 }
967 fTimeAlignedComposite.layout();
968 fTree.redraw();
969 fTimeGraphCtrl.redraw();
970 fTimeScaleCtrl.redraw();
971 fMarkerAxisCtrl.redraw();
972 }
973
974 @Override
975 public int getTimeSpace() {
976 int w = fTimeGraphCtrl.getClientArea().width;
977 return w - fNameWidth;
978 }
979
980 @Override
981 public long getBeginTime() {
982 return fBeginTime;
983 }
984
985 @Override
986 public long getEndTime() {
987 return fEndTime;
988 }
989
990 @Override
991 public long getMaxTime() {
992 return fTime1Bound;
993 }
994
995 @Override
996 public long getMinTime() {
997 return fTime0Bound;
998 }
999
1000 @Override
1001 public long getSelectionBegin() {
1002 return fSelectionBegin;
1003 }
1004
1005 @Override
1006 public long getSelectionEnd() {
1007 return fSelectionEnd;
1008 }
1009
1010 @Override
1011 public void setStartFinishTimeNotify(long time0, long time1) {
1012 setStartFinishTimeInt(time0, time1);
1013 notifyRangeListeners();
1014 }
1015
1016 @Override
1017 public void notifyStartFinishTime() {
1018 notifyRangeListeners();
1019 }
1020
1021 @Override
1022 public void setStartFinishTime(long time0, long time1) {
1023 /* if there is a pending time range, ignore this one */
1024 if (fListenerNotifier != null && fListenerNotifier.hasTimeRangeUpdated()) {
1025 return;
1026 }
1027 setStartFinishTimeInt(time0, time1);
1028 updateExtSynchValues();
1029 }
1030
1031 private void setStartFinishTimeInt(long time0, long time1) {
1032 fTime0 = time0;
1033 if (fTime0 < fTime0Bound) {
1034 fTime0 = fTime0Bound;
1035 }
1036 if (fTime0 > fTime1Bound) {
1037 fTime0 = fTime1Bound;
1038 }
1039 fTime1 = time1;
1040 if (fTime1 < fTime0Bound) {
1041 fTime1 = fTime0Bound;
1042 }
1043 if (fTime1 > fTime1Bound) {
1044 fTime1 = fTime1Bound;
1045 }
1046 if (fTime1 - fTime0 < fMinTimeInterval) {
1047 fTime1 = Math.min(fTime1Bound, fTime0 + fMinTimeInterval);
1048 }
1049 fTimeRangeFixed = true;
1050 adjustHorizontalScrollBar();
1051 fTimeGraphCtrl.redraw();
1052 fTimeScaleCtrl.redraw();
1053 fMarkerAxisCtrl.redraw();
1054 }
1055
1056 @Override
1057 public void resetStartFinishTime() {
1058 setStartFinishTimeNotify(fTime0Bound, fTime1Bound);
1059 fTimeRangeFixed = false;
1060 }
1061
1062 /**
1063 * @since 2.0
1064 */
1065 @Override
1066 public void resetStartFinishTime(boolean notify) {
1067 if (notify) {
1068 setStartFinishTimeNotify(fTime0Bound, fTime1Bound);
1069 } else {
1070 setStartFinishTime(fTime0Bound, fTime1Bound);
1071 }
1072 fTimeRangeFixed = false;
1073 }
1074
1075 @Override
1076 public void setSelectedTimeNotify(long time, boolean ensureVisible) {
1077 setSelectedTimeInt(time, ensureVisible, true);
1078 }
1079
1080 @Override
1081 public void setSelectedTime(long time, boolean ensureVisible) {
1082 /* if there is a pending time selection, ignore this one */
1083 if (fListenerNotifier != null && fListenerNotifier.hasTimeSelected()) {
1084 return;
1085 }
1086 setSelectedTimeInt(time, ensureVisible, false);
1087 }
1088
1089 private void setSelectedTimeInt(long time, boolean ensureVisible, boolean doNotify) {
1090 setSelectionRangeInt(time, time, ensureVisible, doNotify);
1091 }
1092
1093 /**
1094 * @since 1.2
1095 */
1096 @Override
1097 public void setSelectionRangeNotify(long beginTime, long endTime, boolean ensureVisible) {
1098 setSelectionRangeInt(beginTime, endTime, ensureVisible, true);
1099 }
1100
1101 /**
1102 * @since 1.2
1103 */
1104 @Override
1105 public void setSelectionRange(long beginTime, long endTime, boolean ensureVisible) {
1106 /* if there is a pending time selection, ignore this one */
1107 if (fListenerNotifier != null && fListenerNotifier.hasTimeSelected()) {
1108 return;
1109 }
1110 setSelectionRangeInt(beginTime, endTime, ensureVisible, false);
1111 }
1112
1113 private void setSelectionRangeInt(long beginTime, long endTime, boolean ensureVisible, boolean doNotify) {
1114 long time0 = fTime0;
1115 long time1 = fTime1;
1116 long selectionBegin = fSelectionBegin;
1117 long selectionEnd = fSelectionEnd;
1118 fSelectionBegin = Math.max(fTime0Bound, Math.min(fTime1Bound, beginTime));
1119 fSelectionEnd = Math.max(fTime0Bound, Math.min(fTime1Bound, endTime));
1120 boolean changed = (selectionBegin != fSelectionBegin || selectionEnd != fSelectionEnd);
1121
1122 if (ensureVisible) {
1123 ensureVisible(selectionBegin != fSelectionBegin ? fSelectionBegin : fSelectionEnd);
1124 }
1125
1126 fTimeGraphCtrl.redraw();
1127 fTimeScaleCtrl.redraw();
1128 fMarkerAxisCtrl.redraw();
1129 updateMarkerActions();
1130
1131 if ((time0 != fTime0) || (time1 != fTime1)) {
1132 notifyRangeListeners();
1133 }
1134
1135 if (doNotify && changed) {
1136 notifyTimeListeners();
1137 }
1138 }
1139
1140 private void ensureVisible(long time) {
1141 long timeMid = (fTime1 - fTime0) / 2;
1142 if (time < fTime0) {
1143 long dt = fTime0 - time + timeMid;
1144 fTime0 -= dt;
1145 fTime1 -= dt;
1146 } else if (time > fTime1) {
1147 long dt = time - fTime1 + timeMid;
1148 fTime0 += dt;
1149 fTime1 += dt;
1150 }
1151 if (fTime0 < fTime0Bound) {
1152 fTime1 = Math.min(fTime1Bound, fTime1 + (fTime0Bound - fTime0));
1153 fTime0 = fTime0Bound;
1154 } else if (fTime1 > fTime1Bound) {
1155 fTime0 = Math.max(fTime0Bound, fTime0 - (fTime1 - fTime1Bound));
1156 fTime1 = fTime1Bound;
1157 }
1158 if (fTime1 - fTime0 < fMinTimeInterval) {
1159 fTime1 = Math.min(fTime1Bound, fTime0 + fMinTimeInterval);
1160 }
1161 adjustHorizontalScrollBar();
1162 }
1163
1164 @Override
1165 public void widgetDefaultSelected(SelectionEvent e) {
1166 if (fSelectedEntry != getSelection()) {
1167 fSelectedEntry = getSelection();
1168 notifySelectionListeners();
1169 }
1170 }
1171
1172 @Override
1173 public void widgetSelected(SelectionEvent e) {
1174 if (fSelectedEntry != getSelection()) {
1175 fSelectedEntry = getSelection();
1176 notifySelectionListeners();
1177 }
1178 }
1179
1180 /**
1181 * Callback for when the next event is selected
1182 *
1183 * @param extend
1184 * true to extend selection range, false for single selection
1185 * @since 1.0
1186 */
1187 public void selectNextEvent(boolean extend) {
1188 fTimeGraphCtrl.selectNextEvent(extend);
1189 adjustVerticalScrollBar();
1190 }
1191
1192 /**
1193 * Callback for when the previous event is selected
1194 *
1195 * @param extend
1196 * true to extend selection range, false for single selection
1197 * @since 1.0
1198 */
1199 public void selectPrevEvent(boolean extend) {
1200 fTimeGraphCtrl.selectPrevEvent(extend);
1201 adjustVerticalScrollBar();
1202 }
1203
1204 /**
1205 * Callback for when the next item is selected
1206 */
1207 public void selectNextItem() {
1208 fTimeGraphCtrl.selectNextTrace();
1209 adjustVerticalScrollBar();
1210 }
1211
1212 /**
1213 * Callback for when the previous item is selected
1214 */
1215 public void selectPrevItem() {
1216 fTimeGraphCtrl.selectPrevTrace();
1217 adjustVerticalScrollBar();
1218 }
1219
1220 /**
1221 * Callback for the show legend action
1222 */
1223 public void showLegend() {
1224 if (fDataViewer == null || fDataViewer.isDisposed()) {
1225 return;
1226 }
1227
1228 TimeGraphLegend.open(fDataViewer.getShell(), fTimeGraphProvider);
1229 }
1230
1231 /**
1232 * Callback for the Zoom In action
1233 */
1234 public void zoomIn() {
1235 fTimeGraphCtrl.zoomIn();
1236 }
1237
1238 /**
1239 * Callback for the Zoom Out action
1240 */
1241 public void zoomOut() {
1242 fTimeGraphCtrl.zoomOut();
1243 }
1244
1245 private String getPreferenceString(String string) {
1246 return getViewTypeStr() + "." + string; //$NON-NLS-1$
1247 }
1248
1249 /**
1250 * Add a selection listener
1251 *
1252 * @param listener
1253 * The listener to add
1254 */
1255 public void addSelectionListener(ITimeGraphSelectionListener listener) {
1256 fSelectionListeners.add(listener);
1257 }
1258
1259 /**
1260 * Remove a selection listener
1261 *
1262 * @param listener
1263 * The listener to remove
1264 */
1265 public void removeSelectionListener(ITimeGraphSelectionListener listener) {
1266 fSelectionListeners.remove(listener);
1267 }
1268
1269 private void notifySelectionListeners() {
1270 if (fListenerNotifier == null) {
1271 fListenerNotifier = new ListenerNotifier();
1272 fListenerNotifier.start();
1273 }
1274 fListenerNotifier.selectionChanged();
1275 }
1276
1277 private void fireSelectionChanged(ITimeGraphEntry selection) {
1278 TimeGraphSelectionEvent event = new TimeGraphSelectionEvent(this, selection);
1279
1280 for (ITimeGraphSelectionListener listener : fSelectionListeners) {
1281 listener.selectionChanged(event);
1282 }
1283
1284 ISelection structuredSelection = (selection == null) ? StructuredSelection.EMPTY : new StructuredSelection(selection);
1285 fireSelectionChanged(new SelectionChangedEvent(this, structuredSelection));
1286 }
1287
1288 /**
1289 * Add a time listener
1290 *
1291 * @param listener
1292 * The listener to add
1293 */
1294 public void addTimeListener(ITimeGraphTimeListener listener) {
1295 fTimeListeners.add(listener);
1296 }
1297
1298 /**
1299 * Remove a time listener
1300 *
1301 * @param listener
1302 * The listener to remove
1303 */
1304 public void removeTimeListener(ITimeGraphTimeListener listener) {
1305 fTimeListeners.remove(listener);
1306 }
1307
1308 private void notifyTimeListeners() {
1309 if (fListenerNotifier == null) {
1310 fListenerNotifier = new ListenerNotifier();
1311 fListenerNotifier.start();
1312 }
1313 fListenerNotifier.timeSelected();
1314 }
1315
1316 private void fireTimeSelected(long startTime, long endTime) {
1317 TimeGraphTimeEvent event = new TimeGraphTimeEvent(this, startTime, endTime);
1318
1319 for (ITimeGraphTimeListener listener : fTimeListeners) {
1320 listener.timeSelected(event);
1321 }
1322 }
1323
1324 /**
1325 * Add a range listener
1326 *
1327 * @param listener
1328 * The listener to add
1329 */
1330 public void addRangeListener(ITimeGraphRangeListener listener) {
1331 fRangeListeners.add(listener);
1332 }
1333
1334 /**
1335 * Remove a range listener
1336 *
1337 * @param listener
1338 * The listener to remove
1339 */
1340 public void removeRangeListener(ITimeGraphRangeListener listener) {
1341 fRangeListeners.remove(listener);
1342 }
1343
1344 private void notifyRangeListeners() {
1345 if (fListenerNotifier == null) {
1346 fListenerNotifier = new ListenerNotifier();
1347 fListenerNotifier.start();
1348 }
1349 fListenerNotifier.timeRangeUpdated();
1350 }
1351
1352 private void fireTimeRangeUpdated(long startTime, long endTime) {
1353 // Check if the time has actually changed from last notification
1354 if (startTime != fTime0ExtSynch || endTime != fTime1ExtSynch) {
1355 // Notify Time Scale Selection Listeners
1356 TimeGraphRangeUpdateEvent event = new TimeGraphRangeUpdateEvent(this, startTime, endTime);
1357
1358 for (ITimeGraphRangeListener listener : fRangeListeners) {
1359 listener.timeRangeUpdated(event);
1360 }
1361
1362 // update external synch values
1363 updateExtSynchValues();
1364 }
1365 }
1366
1367 /**
1368 * Add a bookmark listener
1369 *
1370 * @param listener
1371 * The listener to add
1372 * @since 2.0
1373 */
1374 public void addBookmarkListener(ITimeGraphBookmarkListener listener) {
1375 fBookmarkListeners.add(listener);
1376 }
1377
1378 /**
1379 * Remove a bookmark listener
1380 *
1381 * @param listener
1382 * The listener to remove
1383 * @since 2.0
1384 */
1385 public void removeBookmarkListener(ITimeGraphBookmarkListener listener) {
1386 fBookmarkListeners.remove(listener);
1387 }
1388
1389 private void fireBookmarkAdded(IMarkerEvent bookmark) {
1390 TimeGraphBookmarkEvent event = new TimeGraphBookmarkEvent(this, bookmark);
1391
1392 for (ITimeGraphBookmarkListener listener : fBookmarkListeners) {
1393 listener.bookmarkAdded(event);
1394 }
1395 }
1396
1397 private void fireBookmarkRemoved(IMarkerEvent bookmark) {
1398 TimeGraphBookmarkEvent event = new TimeGraphBookmarkEvent(this, bookmark);
1399
1400 for (ITimeGraphBookmarkListener listener : fBookmarkListeners) {
1401 listener.bookmarkRemoved(event);
1402 }
1403 }
1404
1405 /**
1406 * Set the bookmarks list.
1407 *
1408 * @param bookmarks
1409 * The bookmarks list, or null
1410 * @since 2.0
1411 */
1412 public void setBookmarks(List<IMarkerEvent> bookmarks) {
1413 fBookmarks.clear();
1414 if (bookmarks != null) {
1415 fBookmarks.addAll(bookmarks);
1416 }
1417 updateMarkerList();
1418 updateMarkerActions();
1419 }
1420
1421 /**
1422 * Get the bookmarks list.
1423 *
1424 * @return The bookmarks list
1425 * @since 2.0
1426 */
1427 public List<IMarkerEvent> getBookmarks() {
1428 return Collections.unmodifiableList(fBookmarks);
1429 }
1430
1431 /**
1432 * Set the list of marker categories.
1433 *
1434 * @param categories
1435 * The list of marker categories, or null
1436 * @since 2.0
1437 */
1438 public void setMarkerCategories(List<String> categories) {
1439 fMarkerCategories.clear();
1440 if (categories != null) {
1441 fMarkerCategories.addAll(categories);
1442 }
1443 fMarkerCategories.add(IMarkerEvent.BOOKMARKS);
1444 fMarkerAxisCtrl.setMarkerCategories(fMarkerCategories);
1445 }
1446
1447 /**
1448 * @since 2.0
1449 */
1450 @Override
1451 public void setMarkerCategoryVisible(String category, boolean visible) {
1452 boolean changed = false;
1453 if (visible) {
1454 changed = fHiddenMarkerCategories.remove(category);
1455 } else {
1456 changed = fHiddenMarkerCategories.add(category);
1457 }
1458 if (changed) {
1459 updateMarkerList();
1460 updateMarkerActions();
1461 getControl().redraw();
1462 }
1463 }
1464
1465 /**
1466 * Set the markers list.
1467 *
1468 * @param markers
1469 * The markers list, or null
1470 * @since 2.0
1471 */
1472 public void setMarkers(List<IMarkerEvent> markers) {
1473 fMarkers.clear();
1474 if (markers != null) {
1475 fMarkers.addAll(markers);
1476 }
1477 updateMarkerList();
1478 updateMarkerActions();
1479 }
1480
1481 /**
1482 * Get the markers list.
1483 *
1484 * @return The markers list, or null
1485 * @since 2.0
1486 */
1487 public List<IMarkerEvent> getMarkers() {
1488 return Collections.unmodifiableList(fMarkers);
1489 }
1490
1491 /**
1492 * Callback to set a selected event in the view
1493 *
1494 * @param event
1495 * The event that was selected
1496 * @param source
1497 * The source of this selection event
1498 */
1499 public void setSelectedEvent(ITimeEvent event, Object source) {
1500 if (event == null || source == this) {
1501 return;
1502 }
1503 fSelectedEntry = event.getEntry();
1504 fTimeGraphCtrl.selectItem(fSelectedEntry, false);
1505
1506 setSelectedTimeInt(event.getTime(), true, true);
1507 adjustVerticalScrollBar();
1508 }
1509
1510 /**
1511 * Set the seeked time of a trace
1512 *
1513 * @param trace
1514 * The trace that was seeked
1515 * @param time
1516 * The target time
1517 * @param source
1518 * The source of this seek event
1519 */
1520 public void setSelectedTraceTime(ITimeGraphEntry trace, long time, Object source) {
1521 if (trace == null || source == this) {
1522 return;
1523 }
1524 fSelectedEntry = trace;
1525 fTimeGraphCtrl.selectItem(trace, false);
1526
1527 setSelectedTimeInt(time, true, true);
1528 }
1529
1530 /**
1531 * Sets a new selection for this viewer and makes it visible.
1532 *
1533 * @param entry
1534 * The entry to select
1535 * @deprecated Use {@link #setSelection(ISelection, boolean)} instead.
1536 */
1537 @Deprecated
1538 public void setSelection(ITimeGraphEntry entry) {
1539 setSelection(entry, true);
1540 }
1541
1542 @Override
1543 public void setSelection(ISelection selection, boolean reveal) {
1544 /* if there is a pending selection, ignore this one */
1545 if (fListenerNotifier != null && fListenerNotifier.hasSelectionChanged()) {
1546 return;
1547 }
1548 Object element = selection;
1549 if (selection instanceof IStructuredSelection) {
1550 element = ((IStructuredSelection) selection).getFirstElement();
1551 }
1552 if (!(element instanceof ITimeGraphEntry)) {
1553 return;
1554 }
1555 ITimeGraphEntry entry = (ITimeGraphEntry) element;
1556 fSelectedEntry = entry;
1557 fTimeGraphCtrl.selectItem(entry, false, reveal);
1558 adjustVerticalScrollBar();
1559 }
1560
1561 /**
1562 * Callback for a time window selection
1563 *
1564 * @param time0
1565 * Start time of the range
1566 * @param time1
1567 * End time of the range
1568 * @param source
1569 * Source of the event
1570 */
1571 public void setSelectVisTimeWindow(long time0, long time1, Object source) {
1572 if (source == this) {
1573 return;
1574 }
1575
1576 setStartFinishTimeInt(time0, time1);
1577
1578 // update notification time values since we are now in synch with the
1579 // external application
1580 updateExtSynchValues();
1581 }
1582
1583 /**
1584 * update the cache values used to identify the need to send a time window
1585 * update to external registered listeners
1586 */
1587 private void updateExtSynchValues() {
1588 // last time notification cache
1589 fTime0ExtSynch = fTime0;
1590 fTime1ExtSynch = fTime1;
1591 }
1592
1593 @Override
1594 public TimeFormat getTimeFormat() {
1595 return fTimeFormat;
1596 }
1597
1598 /**
1599 * @param tf
1600 * the {@link TimeFormat} used to display timestamps
1601 */
1602 public void setTimeFormat(TimeFormat tf) {
1603 this.fTimeFormat = tf;
1604 if (tf == TimeFormat.CYCLES) {
1605 fTimeDataProvider = new TimeDataProviderCyclesConverter(this, fClockFrequency);
1606 } else {
1607 fTimeDataProvider = this;
1608 }
1609 fTimeScaleCtrl.setTimeProvider(fTimeDataProvider);
1610 if (fToolTipHandler != null) {
1611 fToolTipHandler.setTimeProvider(fTimeDataProvider);
1612 }
1613 }
1614
1615 /**
1616 * Sets the clock frequency. Used when the time format is set to CYCLES.
1617 *
1618 * @param clockFrequency
1619 * the clock frequency in Hz
1620 */
1621 public void setClockFrequency(long clockFrequency) {
1622 fClockFrequency = clockFrequency;
1623 if (fTimeFormat == TimeFormat.CYCLES) {
1624 fTimeDataProvider = new TimeDataProviderCyclesConverter(this, fClockFrequency);
1625 fTimeScaleCtrl.setTimeProvider(fTimeDataProvider);
1626 if (fToolTipHandler != null) {
1627 fToolTipHandler.setTimeProvider(fTimeDataProvider);
1628 }
1629 }
1630 }
1631
1632 /**
1633 * Retrieve the border width
1634 *
1635 * @return The width
1636 */
1637 public int getBorderWidth() {
1638 return fBorderWidth;
1639 }
1640
1641 /**
1642 * Set the border width
1643 *
1644 * @param borderWidth
1645 * The width
1646 */
1647 public void setBorderWidth(int borderWidth) {
1648 if (borderWidth > -1) {
1649 this.fBorderWidth = borderWidth;
1650 GridLayout gl = (GridLayout) fDataViewer.getLayout();
1651 gl.marginHeight = borderWidth;
1652 }
1653 }
1654
1655 /**
1656 * Retrieve the height of the header
1657 *
1658 * @return The height
1659 */
1660 public int getHeaderHeight() {
1661 return fTimeScaleHeight;
1662 }
1663
1664 /**
1665 * Set the height of the header
1666 *
1667 * @param headerHeight
1668 * The height to set
1669 */
1670 public void setHeaderHeight(int headerHeight) {
1671 if (headerHeight > -1) {
1672 this.fTimeScaleHeight = headerHeight;
1673 fTimeScaleCtrl.setHeight(headerHeight);
1674 }
1675 }
1676
1677 /**
1678 * Retrieve the height of an item row
1679 *
1680 * @return The height
1681 */
1682 public int getItemHeight() {
1683 if (fTimeGraphCtrl != null) {
1684 return fTimeGraphCtrl.getItemHeight();
1685 }
1686 return 0;
1687 }
1688
1689 /**
1690 * Set the height of an item row
1691 *
1692 * @param rowHeight
1693 * The height to set
1694 */
1695 public void setItemHeight(int rowHeight) {
1696 if (fTimeGraphCtrl != null) {
1697 fTimeGraphCtrl.setItemHeight(rowHeight);
1698 }
1699 }
1700
1701 /**
1702 * Set the minimum item width
1703 *
1704 * @param width
1705 * The min width
1706 */
1707 public void setMinimumItemWidth(int width) {
1708 if (fTimeGraphCtrl != null) {
1709 fTimeGraphCtrl.setMinimumItemWidth(width);
1710 }
1711 }
1712
1713 /**
1714 * Set the width for the name column
1715 *
1716 * @param width
1717 * The width
1718 */
1719 public void setNameWidthPref(int width) {
1720 fNameWidthPref = width;
1721 if (width == 0) {
1722 fMinNameWidth = 0;
1723 fNameWidth = 0;
1724 }
1725 }
1726
1727 /**
1728 * Retrieve the configure width for the name column
1729 *
1730 * @param width
1731 * Unused?
1732 * @return The width
1733 */
1734 public int getNameWidthPref(int width) {
1735 return fNameWidthPref;
1736 }
1737
1738 @Override
1739 public Control getControl() {
1740 return fDataViewer;
1741 }
1742
1743 /**
1744 * Returns the time graph control associated with this viewer.
1745 *
1746 * @return the time graph control
1747 */
1748 public TimeGraphControl getTimeGraphControl() {
1749 return fTimeGraphCtrl;
1750 }
1751
1752 /**
1753 * Returns the tree control associated with this viewer. The tree is only
1754 * used for column handling of the name space and contains no tree items.
1755 *
1756 * @return the tree control
1757 * @since 2.3
1758 */
1759 public Tree getTree() {
1760 return fTree;
1761 }
1762
1763 /**
1764 * Sets the columns for this time graph viewer's name space.
1765 *
1766 * @param columnNames
1767 * the column names
1768 * @since 2.3
1769 */
1770 public void setColumns(String[] columnNames) {
1771 fTimeGraphCtrl.setColumns(columnNames);
1772 }
1773
1774 /**
1775 * Returns the time graph scale associated with this viewer.
1776 *
1777 * @return the time graph scale
1778 */
1779 public TimeGraphScale getTimeGraphScale() {
1780 return fTimeScaleCtrl;
1781 }
1782
1783 /**
1784 * Returns the composite containing all the controls that are time aligned,
1785 * i.e. TimeGraphScale, TimeGraphControl.
1786 *
1787 * @return the time based composite
1788 * @since 1.0
1789 */
1790 public Composite getTimeAlignedComposite() {
1791 return fTimeAlignedComposite;
1792 }
1793
1794 /**
1795 * Return the x coordinate corresponding to a time
1796 *
1797 * @param time
1798 * the time
1799 * @return the x coordinate corresponding to the time
1800 */
1801 public int getXForTime(long time) {
1802 return fTimeGraphCtrl.getXForTime(time);
1803 }
1804
1805 /**
1806 * Return the time corresponding to an x coordinate
1807 *
1808 * @param x
1809 * the x coordinate
1810 * @return the time corresponding to the x coordinate
1811 */
1812 public long getTimeAtX(int x) {
1813 return fTimeGraphCtrl.getTimeAtX(x);
1814 }
1815
1816 /**
1817 * Get the selection provider
1818 *
1819 * @return the selection provider
1820 */
1821 public ISelectionProvider getSelectionProvider() {
1822 return fTimeGraphCtrl;
1823 }
1824
1825 /**
1826 * Wait for the cursor
1827 *
1828 * @param waitInd
1829 * Wait indefinitely?
1830 */
1831 public void waitCursor(boolean waitInd) {
1832 fTimeGraphCtrl.waitCursor(waitInd);
1833 }
1834
1835 /**
1836 * Get the horizontal scroll bar object
1837 *
1838 * @return The scroll bar
1839 */
1840 public Slider getHorizontalBar() {
1841 return fHorizontalScrollBar;
1842 }
1843
1844 /**
1845 * Get the vertical scroll bar object
1846 *
1847 * @return The scroll bar
1848 */
1849 public Slider getVerticalBar() {
1850 return fVerticalScrollBar;
1851 }
1852
1853 /**
1854 * Set the given index as the top one
1855 *
1856 * @param index
1857 * The index that will go to the top
1858 */
1859 public void setTopIndex(int index) {
1860 fTimeGraphCtrl.setTopIndex(index);
1861 adjustVerticalScrollBar();
1862 }
1863
1864 /**
1865 * Retrieve the current top index
1866 *
1867 * @return The top index
1868 */
1869 public int getTopIndex() {
1870 return fTimeGraphCtrl.getTopIndex();
1871 }
1872
1873 /**
1874 * Sets the auto-expand level to be used for new entries discovered when
1875 * calling {@link #setInput(Object)} or {@link #refresh()}. The value 0
1876 * means that there is no auto-expand; 1 means that top-level entries are
1877 * expanded, but not their children; 2 means that top-level entries are
1878 * expanded, and their children, but not grand-children; and so on.
1879 * <p>
1880 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
1881 * </p>
1882 *
1883 * @param level
1884 * non-negative level, or <code>ALL_LEVELS</code> to expand all
1885 * levels of the tree
1886 */
1887 public void setAutoExpandLevel(int level) {
1888 fTimeGraphCtrl.setAutoExpandLevel(level);
1889 }
1890
1891 /**
1892 * Returns the auto-expand level.
1893 *
1894 * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of
1895 * the tree are expanded automatically
1896 * @see #setAutoExpandLevel
1897 */
1898 public int getAutoExpandLevel() {
1899 return fTimeGraphCtrl.getAutoExpandLevel();
1900 }
1901
1902 /**
1903 * Get the expanded state of an entry.
1904 *
1905 * @param entry
1906 * The entry
1907 * @return true if the entry is expanded, false if collapsed
1908 * @since 1.1
1909 */
1910 public boolean getExpandedState(ITimeGraphEntry entry) {
1911 return fTimeGraphCtrl.getExpandedState(entry);
1912 }
1913
1914 /**
1915 * Set the expanded state of an entry
1916 *
1917 * @param entry
1918 * The entry to expand/collapse
1919 * @param expanded
1920 * True for expanded, false for collapsed
1921 */
1922 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
1923 fTimeGraphCtrl.setExpandedState(entry, expanded);
1924 adjustVerticalScrollBar();
1925 }
1926
1927 /**
1928 * Collapses all nodes of the viewer's tree, starting with the root.
1929 */
1930 public void collapseAll() {
1931 fTimeGraphCtrl.collapseAll();
1932 adjustVerticalScrollBar();
1933 }
1934
1935 /**
1936 * Expands all entries of the viewer's tree, starting with the root.
1937 */
1938 public void expandAll() {
1939 fTimeGraphCtrl.expandAll();
1940 adjustVerticalScrollBar();
1941 }
1942
1943 /**
1944 * Select an entry and reveal it
1945 *
1946 * @param entry
1947 * The entry to select
1948 * @since 2.0
1949 */
1950 public void selectAndReveal(@NonNull ITimeGraphEntry entry) {
1951 final ITimeGraphEntry parent = entry.getParent();
1952 if (parent != null) {
1953 fTimeGraphCtrl.setExpandedState(parent, true);
1954 }
1955 fSelectedEntry = entry;
1956 fTimeGraphCtrl.selectItem(entry, false);
1957 adjustVerticalScrollBar();
1958 }
1959
1960 /**
1961 * Get the number of expanded (visible) time graph entries. This includes
1962 * leafs and does not include filtered-out entries.
1963 *
1964 * @return The number of expanded (visible) time graph entries
1965 */
1966 public int getExpandedElementCount() {
1967 return fTimeGraphCtrl.getExpandedElementCount();
1968 }
1969
1970 /**
1971 * Get the expanded (visible) time graph entries. This includes leafs and
1972 * does not include filtered-out entries.
1973 *
1974 * @return The array of expanded (visible) time graph entries
1975 */
1976 public ITimeGraphEntry[] getExpandedElements() {
1977 return fTimeGraphCtrl.getExpandedElements();
1978 }
1979
1980 /**
1981 * Add a tree listener
1982 *
1983 * @param listener
1984 * The listener to add
1985 */
1986 public void addTreeListener(ITimeGraphTreeListener listener) {
1987 fTimeGraphCtrl.addTreeListener(listener);
1988 }
1989
1990 /**
1991 * Remove a tree listener
1992 *
1993 * @param listener
1994 * The listener to remove
1995 */
1996 public void removeTreeListener(ITimeGraphTreeListener listener) {
1997 fTimeGraphCtrl.removeTreeListener(listener);
1998 }
1999
2000 /**
2001 * Get the reset scale action.
2002 *
2003 * @return The Action object
2004 */
2005 public Action getResetScaleAction() {
2006 if (fResetScaleAction == null) {
2007 // resetScale
2008 fResetScaleAction = new Action() {
2009 @Override
2010 public void run() {
2011 resetStartFinishTime();
2012 }
2013 };
2014 fResetScaleAction.setText(Messages.TmfTimeGraphViewer_ResetScaleActionNameText);
2015 fResetScaleAction.setToolTipText(Messages.TmfTimeGraphViewer_ResetScaleActionToolTipText);
2016 fResetScaleAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_HOME_MENU));
2017 }
2018 return fResetScaleAction;
2019 }
2020
2021 /**
2022 * Get the show legend action.
2023 *
2024 * @return The Action object
2025 */
2026 public Action getShowLegendAction() {
2027 if (fShowLegendAction == null) {
2028 // showLegend
2029 fShowLegendAction = new Action() {
2030 @Override
2031 public void run() {
2032 showLegend();
2033 }
2034 };
2035 fShowLegendAction.setText(Messages.TmfTimeGraphViewer_LegendActionNameText);
2036 fShowLegendAction.setToolTipText(Messages.TmfTimeGraphViewer_LegendActionToolTipText);
2037 fShowLegendAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_LEGEND));
2038 }
2039
2040 return fShowLegendAction;
2041 }
2042
2043 /**
2044 * Get the the next event action.
2045 *
2046 * @return The action object
2047 */
2048 public Action getNextEventAction() {
2049 if (fNextEventAction == null) {
2050 fNextEventAction = new Action() {
2051 @Override
2052 public void runWithEvent(Event event) {
2053 boolean extend = (event.stateMask & SWT.SHIFT) != 0;
2054 selectNextEvent(extend);
2055 }
2056 };
2057
2058 fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextStateChangeActionNameText);
2059 fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextStateChangeActionToolTipText);
2060 fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_STATE_CHANGE));
2061 }
2062
2063 return fNextEventAction;
2064 }
2065
2066 /**
2067 * Get the previous event action.
2068 *
2069 * @return The Action object
2070 */
2071 public Action getPreviousEventAction() {
2072 if (fPrevEventAction == null) {
2073 fPrevEventAction = new Action() {
2074 @Override
2075 public void runWithEvent(Event event) {
2076 boolean extend = (event.stateMask & SWT.SHIFT) != 0;
2077 selectPrevEvent(extend);
2078 }
2079 };
2080
2081 fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousStateChangeActionNameText);
2082 fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousStateChangeActionToolTipText);
2083 fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_STATE_CHANGE));
2084 }
2085
2086 return fPrevEventAction;
2087 }
2088
2089 /**
2090 * Get the next item action.
2091 *
2092 * @return The Action object
2093 */
2094 public Action getNextItemAction() {
2095 if (fNextItemAction == null) {
2096
2097 fNextItemAction = new Action() {
2098 @Override
2099 public void run() {
2100 selectNextItem();
2101 }
2102 };
2103 fNextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);
2104 fNextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);
2105 fNextItemAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_ITEM));
2106 }
2107 return fNextItemAction;
2108 }
2109
2110 /**
2111 * Get the previous item action.
2112 *
2113 * @return The Action object
2114 */
2115 public Action getPreviousItemAction() {
2116 if (fPreviousItemAction == null) {
2117
2118 fPreviousItemAction = new Action() {
2119 @Override
2120 public void run() {
2121 selectPrevItem();
2122 }
2123 };
2124 fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
2125 fPreviousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);
2126 fPreviousItemAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_ITEM));
2127 }
2128 return fPreviousItemAction;
2129 }
2130
2131 /**
2132 * Get the zoom in action
2133 *
2134 * @return The Action object
2135 */
2136 public Action getZoomInAction() {
2137 if (fZoomInAction == null) {
2138 fZoomInAction = new Action() {
2139 @Override
2140 public void run() {
2141 zoomIn();
2142 }
2143 };
2144 fZoomInAction.setText(Messages.TmfTimeGraphViewer_ZoomInActionNameText);
2145 fZoomInAction.setToolTipText(Messages.TmfTimeGraphViewer_ZoomInActionToolTipText);
2146 fZoomInAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_IN_MENU));
2147 }
2148 return fZoomInAction;
2149 }
2150
2151 /**
2152 * Get the zoom out action
2153 *
2154 * @return The Action object
2155 */
2156 public Action getZoomOutAction() {
2157 if (fZoomOutAction == null) {
2158 fZoomOutAction = new Action() {
2159 @Override
2160 public void run() {
2161 zoomOut();
2162 }
2163 };
2164 fZoomOutAction.setText(Messages.TmfTimeGraphViewer_ZoomOutActionNameText);
2165 fZoomOutAction.setToolTipText(Messages.TmfTimeGraphViewer_ZoomOutActionToolTipText);
2166 fZoomOutAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_OUT_MENU));
2167 }
2168 return fZoomOutAction;
2169 }
2170
2171 /**
2172 * Get the hide arrows action
2173 *
2174 * @param dialogSettings
2175 * The dialog settings section where the state should be stored,
2176 * or null
2177 *
2178 * @return The Action object
2179 */
2180 public Action getHideArrowsAction(final IDialogSettings dialogSettings) {
2181 if (fHideArrowsAction == null) {
2182 fHideArrowsAction = new Action(Messages.TmfTimeGraphViewer_HideArrowsActionNameText, IAction.AS_CHECK_BOX) {
2183 @Override
2184 public void run() {
2185 boolean hideArrows = fHideArrowsAction.isChecked();
2186 fTimeGraphCtrl.hideArrows(hideArrows);
2187 refresh();
2188 if (dialogSettings != null) {
2189 dialogSettings.put(HIDE_ARROWS_KEY, hideArrows);
2190 }
2191 if (fFollowArrowFwdAction != null) {
2192 fFollowArrowFwdAction.setEnabled(!hideArrows);
2193 }
2194 if (fFollowArrowBwdAction != null) {
2195 fFollowArrowBwdAction.setEnabled(!hideArrows);
2196 }
2197 }
2198 };
2199 fHideArrowsAction.setToolTipText(Messages.TmfTimeGraphViewer_HideArrowsActionToolTipText);
2200 fHideArrowsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_HIDE_ARROWS));
2201 if (dialogSettings != null) {
2202 boolean hideArrows = dialogSettings.getBoolean(HIDE_ARROWS_KEY);
2203 fTimeGraphCtrl.hideArrows(hideArrows);
2204 fHideArrowsAction.setChecked(hideArrows);
2205 if (fFollowArrowFwdAction != null) {
2206 fFollowArrowFwdAction.setEnabled(!hideArrows);
2207 }
2208 if (fFollowArrowBwdAction != null) {
2209 fFollowArrowBwdAction.setEnabled(!hideArrows);
2210 }
2211 }
2212 }
2213 return fHideArrowsAction;
2214 }
2215
2216 /**
2217 * Get the follow arrow forward action.
2218 *
2219 * @return The Action object
2220 */
2221 public Action getFollowArrowFwdAction() {
2222 if (fFollowArrowFwdAction == null) {
2223 fFollowArrowFwdAction = new Action() {
2224 @Override
2225 public void runWithEvent(Event event) {
2226 boolean extend = (event.stateMask & SWT.SHIFT) != 0;
2227 fTimeGraphCtrl.followArrowFwd(extend);
2228 adjustVerticalScrollBar();
2229 }
2230 };
2231 fFollowArrowFwdAction.setText(Messages.TmfTimeGraphViewer_FollowArrowForwardActionNameText);
2232 fFollowArrowFwdAction.setToolTipText(Messages.TmfTimeGraphViewer_FollowArrowForwardActionToolTipText);
2233 fFollowArrowFwdAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FOLLOW_ARROW_FORWARD));
2234 if (fHideArrowsAction != null) {
2235 fFollowArrowFwdAction.setEnabled(!fHideArrowsAction.isChecked());
2236 }
2237 }
2238 return fFollowArrowFwdAction;
2239 }
2240
2241 /**
2242 * Get the follow arrow backward action.
2243 *
2244 * @return The Action object
2245 */
2246 public Action getFollowArrowBwdAction() {
2247 if (fFollowArrowBwdAction == null) {
2248 fFollowArrowBwdAction = new Action() {
2249 @Override
2250 public void runWithEvent(Event event) {
2251 boolean extend = (event.stateMask & SWT.SHIFT) != 0;
2252 fTimeGraphCtrl.followArrowBwd(extend);
2253 adjustVerticalScrollBar();
2254 }
2255 };
2256 fFollowArrowBwdAction.setText(Messages.TmfTimeGraphViewer_FollowArrowBackwardActionNameText);
2257 fFollowArrowBwdAction.setToolTipText(Messages.TmfTimeGraphViewer_FollowArrowBackwardActionToolTipText);
2258 fFollowArrowBwdAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FOLLOW_ARROW_BACKWARD));
2259 if (fHideArrowsAction != null) {
2260 fFollowArrowBwdAction.setEnabled(!fHideArrowsAction.isChecked());
2261 }
2262 }
2263 return fFollowArrowBwdAction;
2264 }
2265
2266 /**
2267 * Get the show filter dialog action.
2268 *
2269 * @return The Action object
2270 * @since 1.2
2271 */
2272 public ShowFilterDialogAction getShowFilterDialogAction() {
2273 if (fShowFilterDialogAction == null) {
2274 fShowFilterDialogAction = new ShowFilterDialogAction(this);
2275 }
2276 return fShowFilterDialogAction;
2277 }
2278
2279 /**
2280 * Get the toggle bookmark action.
2281 *
2282 * @return The Action object
2283 * @since 2.0
2284 */
2285 public Action getToggleBookmarkAction() {
2286 if (fToggleBookmarkAction == null) {
2287 fToggleBookmarkAction = new Action() {
2288 @Override
2289 public void runWithEvent(Event event) {
2290 IMarkerEvent selectedBookmark = getBookmarkAtSelection();
2291 if (selectedBookmark == null) {
2292 final long time = Math.min(fSelectionBegin, fSelectionEnd);
2293 final long duration = Math.max(fSelectionBegin, fSelectionEnd) - time;
2294 final AddBookmarkDialog dialog = new AddBookmarkDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), null);
2295 if (dialog.open() == Window.OK) {
2296 final String label = dialog.getValue();
2297 final RGBA rgba = dialog.getColorValue();
2298 IMarkerEvent bookmark = new MarkerEvent(null, time, duration, IMarkerEvent.BOOKMARKS, rgba, label, true);
2299 fBookmarks.add(bookmark);
2300 updateMarkerList();
2301 updateMarkerActions();
2302 getControl().redraw();
2303 fireBookmarkAdded(bookmark);
2304 }
2305 } else {
2306 fBookmarks.remove(selectedBookmark);
2307 updateMarkerList();
2308 updateMarkerActions();
2309 getControl().redraw();
2310 fireBookmarkRemoved(selectedBookmark);
2311 }
2312 }
2313 };
2314 fToggleBookmarkAction.setText(Messages.TmfTimeGraphViewer_BookmarkActionAddText);
2315 fToggleBookmarkAction.setToolTipText(Messages.TmfTimeGraphViewer_BookmarkActionAddText);
2316 fToggleBookmarkAction.setImageDescriptor(ADD_BOOKMARK);
2317 }
2318 return fToggleBookmarkAction;
2319 }
2320
2321 /**
2322 * Get the next marker action.
2323 *
2324 * @return The Action object
2325 * @since 2.0
2326 */
2327 public Action getNextMarkerAction() {
2328 if (fNextMarkerAction == null) {
2329 fNextMarkerAction = new Action(Messages.TmfTimeGraphViewer_NextMarkerActionText, IAction.AS_DROP_DOWN_MENU) {
2330 @Override
2331 public void runWithEvent(Event event) {
2332 boolean extend = (event.stateMask & SWT.SHIFT) != 0;
2333 if (extend) {
2334 extendToNextMarker();
2335 } else {
2336 selectNextMarker();
2337 }
2338 }
2339 };
2340 fNextMarkerAction.setToolTipText(Messages.TmfTimeGraphViewer_NextMarkerActionText);
2341 fNextMarkerAction.setImageDescriptor(NEXT_BOOKMARK);
2342 fNextMarkerAction.setMenuCreator(new IMenuCreator () {
2343 Menu menu = null;
2344 @Override
2345 public void dispose() {
2346 if (menu != null) {
2347 menu.dispose();
2348 menu = null;
2349 }
2350 }
2351
2352 @Override
2353 public Menu getMenu(Control parent) {
2354 if (menu != null) {
2355 menu.dispose();
2356 }
2357 menu = new Menu(parent);
2358 for (String category : fMarkerCategories) {
2359 final Action action = new Action(category, IAction.AS_CHECK_BOX) {
2360 @Override
2361 public void runWithEvent(Event event) {
2362 if (isChecked()) {
2363 fSkippedMarkerCategories.remove(getText());
2364 } else {
2365 fSkippedMarkerCategories.add(getText());
2366 }
2367 updateMarkerActions();
2368 }
2369 };
2370 action.setEnabled(!fHiddenMarkerCategories.contains(category));
2371 action.setChecked(action.isEnabled() && !fSkippedMarkerCategories.contains(category));
2372 new ActionContributionItem(action).fill(menu, -1);
2373 }
2374 return menu;
2375 }
2376
2377 @Override
2378 public Menu getMenu(Menu parent) {
2379 return null;
2380 }
2381 });
2382 }
2383 return fNextMarkerAction;
2384 }
2385
2386 /**
2387 * Get the previous marker action.
2388 *
2389 * @return The Action object
2390 * @since 2.0
2391 */
2392 public Action getPreviousMarkerAction() {
2393 if (fPreviousMarkerAction == null) {
2394 fPreviousMarkerAction = new Action() {
2395 @Override
2396 public void runWithEvent(Event event) {
2397 boolean extend = (event.stateMask & SWT.SHIFT) != 0;
2398 if (extend) {
2399 extendToPrevMarker();
2400 } else {
2401 selectPrevMarker();
2402 }
2403 }
2404 };
2405 fPreviousMarkerAction.setText(Messages.TmfTimeGraphViewer_PreviousMarkerActionText);
2406 fPreviousMarkerAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousMarkerActionText);
2407 fPreviousMarkerAction.setImageDescriptor(PREVIOUS_BOOKMARK);
2408 }
2409 return fPreviousMarkerAction;
2410 }
2411
2412 /**
2413 * Get the show markers menu.
2414 *
2415 * @return The menu manager object
2416 * @since 2.0
2417 */
2418 public MenuManager getMarkersMenu() {
2419 if (fMarkersMenu == null) {
2420 fMarkersMenu = new MenuManager(Messages.TmfTimeGraphViewer_ShowMarkersMenuText);
2421 fMarkersMenu.setRemoveAllWhenShown(true);
2422 fMarkersMenu.addMenuListener(new IMenuListener() {
2423 @Override
2424 public void menuAboutToShow(IMenuManager manager) {
2425 for (String category : fMarkerCategories) {
2426 final Action action = new Action(category, IAction.AS_CHECK_BOX) {
2427 @Override
2428 public void runWithEvent(Event event) {
2429 setMarkerCategoryVisible(getText(), isChecked());
2430 }
2431 };
2432 action.setChecked(!fHiddenMarkerCategories.contains(category));
2433 manager.add(action);
2434 }
2435 }
2436 });
2437 }
2438 return fMarkersMenu;
2439 }
2440
2441 /**
2442 * Select the next marker that begins at or after the current selection
2443 * begin time. Markers that begin at the same time are ordered by end time.
2444 */
2445 private void selectNextMarker() {
2446 List<IMarkerEvent> markers = getTimeGraphControl().getMarkers();
2447 if (markers == null) {
2448 return;
2449 }
2450 for (IMarkerEvent marker : markers) {
2451 final long time = Math.min(fSelectionBegin, fSelectionEnd);
2452 final long duration = Math.max(fSelectionBegin, fSelectionEnd) - time;
2453 if ((marker.getTime() > time ||
2454 (marker.getTime() == time && marker.getDuration() > duration))
2455 && !fSkippedMarkerCategories.contains(marker.getCategory())) {
2456 setSelectionRangeNotify(marker.getTime(), marker.getTime() + marker.getDuration(), false);
2457 ensureVisible(marker.getTime());
2458 notifyRangeListeners();
2459 fTimeGraphCtrl.updateStatusLine();
2460 return;
2461 }
2462 }
2463 }
2464
2465 /**
2466 * Select the previous marker that begins at or before the current selection
2467 * begin time. Markers that begin at the same time are ordered by end time.
2468 */
2469 private void selectPrevMarker() {
2470 List<IMarkerEvent> markers = getTimeGraphControl().getMarkers();
2471 if (markers == null) {
2472 return;
2473 }
2474 final long time = Math.min(fSelectionBegin, fSelectionEnd);
2475 final long duration = Math.max(fSelectionBegin, fSelectionEnd) - time;
2476 for (int i = markers.size() - 1; i >= 0; i--) {
2477 IMarkerEvent marker = markers.get(i);
2478 if ((marker.getTime() < time ||
2479 (marker.getTime() == time && marker.getDuration() < duration))
2480 && !fSkippedMarkerCategories.contains(marker.getCategory())) {
2481 setSelectionRangeNotify(marker.getTime(), marker.getTime() + marker.getDuration(), false);
2482 ensureVisible(marker.getTime());
2483 notifyRangeListeners();
2484 fTimeGraphCtrl.updateStatusLine();
2485 return;
2486 }
2487 }
2488 }
2489
2490 /**
2491 * Extend the selection to the closest next marker end time.
2492 */
2493 private void extendToNextMarker() {
2494 List<IMarkerEvent> markers = getTimeGraphControl().getMarkers();
2495 if (markers == null) {
2496 return;
2497 }
2498 IMarkerEvent nextMarker = null;
2499 for (IMarkerEvent marker : markers) {
2500 if (marker.getTime() + marker.getDuration() > fSelectionEnd
2501 && !fSkippedMarkerCategories.contains(marker.getCategory())
2502 && (nextMarker == null || marker.getTime() + marker.getDuration() < nextMarker.getTime() + nextMarker.getDuration())) {
2503 nextMarker = marker;
2504 }
2505 }
2506 if (nextMarker != null) {
2507 setSelectionRangeNotify(fSelectionBegin, nextMarker.getTime() + nextMarker.getDuration(), true);
2508 fTimeGraphCtrl.updateStatusLine();
2509 }
2510 }
2511
2512 /**
2513 * Extend the selection to the closest previous marker start time.
2514 */
2515 private void extendToPrevMarker() {
2516 List<IMarkerEvent> markers = getTimeGraphControl().getMarkers();
2517 if (markers == null) {
2518 return;
2519 }
2520 for (int i = markers.size() - 1; i >= 0; i--) {
2521 IMarkerEvent marker = markers.get(i);
2522 if (marker.getTime() < fSelectionEnd
2523 && !fSkippedMarkerCategories.contains(marker.getCategory())) {
2524 setSelectionRangeNotify(fSelectionBegin, marker.getTime(), true);
2525 fTimeGraphCtrl.updateStatusLine();
2526 return;
2527 }
2528 }
2529 }
2530
2531 private IMarkerEvent getBookmarkAtSelection() {
2532 final long time = Math.min(fSelectionBegin, fSelectionEnd);
2533 final long duration = Math.max(fSelectionBegin, fSelectionEnd) - time;
2534 for (IMarkerEvent bookmark : fBookmarks) {
2535 if (bookmark.getTime() == time && bookmark.getDuration() == duration) {
2536 return bookmark;
2537 }
2538 }
2539 return null;
2540 }
2541
2542 private void updateMarkerActions() {
2543 boolean enabled = fTime0Bound != SWT.DEFAULT || fTime1Bound != SWT.DEFAULT;
2544 if (fToggleBookmarkAction != null) {
2545 if (getBookmarkAtSelection() != null) {
2546 fToggleBookmarkAction.setText(Messages.TmfTimeGraphViewer_BookmarkActionRemoveText);
2547 fToggleBookmarkAction.setToolTipText(Messages.TmfTimeGraphViewer_BookmarkActionRemoveText);
2548 fToggleBookmarkAction.setImageDescriptor(REMOVE_BOOKMARK);
2549 } else {
2550 fToggleBookmarkAction.setText(Messages.TmfTimeGraphViewer_BookmarkActionAddText);
2551 fToggleBookmarkAction.setToolTipText(Messages.TmfTimeGraphViewer_BookmarkActionAddText);
2552 fToggleBookmarkAction.setImageDescriptor(ADD_BOOKMARK);
2553 }
2554 fToggleBookmarkAction.setEnabled(enabled);
2555 }
2556 List<IMarkerEvent> markers = getTimeGraphControl().getMarkers();
2557 if (markers == null) {
2558 markers = Collections.emptyList();
2559 }
2560 if (fPreviousMarkerAction != null) {
2561 fPreviousMarkerAction.setEnabled(enabled && !markers.isEmpty());
2562 }
2563 if (fNextMarkerAction != null) {
2564 fNextMarkerAction.setEnabled(enabled && !markers.isEmpty());
2565 }
2566 }
2567
2568 private void updateMarkerList() {
2569 List<IMarkerEvent> markers = new ArrayList<>();
2570 for (IMarkerEvent marker : fMarkers) {
2571 if (!fHiddenMarkerCategories.contains(marker.getCategory())) {
2572 markers.add(marker);
2573 }
2574 }
2575 if (!fHiddenMarkerCategories.contains(IMarkerEvent.BOOKMARKS)) {
2576 markers.addAll(fBookmarks);
2577 }
2578 Collections.sort(markers, new MarkerComparator());
2579 fTimeGraphCtrl.setMarkers(markers);
2580 fMarkerAxisCtrl.setMarkers(markers);
2581 }
2582
2583 private void adjustHorizontalScrollBar() {
2584 long time0 = getTime0();
2585 long time1 = getTime1();
2586 long timeMin = getMinTime();
2587 long timeMax = getMaxTime();
2588 long delta = timeMax - timeMin;
2589 int timePos = 0;
2590 int thumb = H_SCROLLBAR_MAX;
2591 if (delta != 0) {
2592 // Thumb size (page size)
2593 thumb = Math.max(1, (int) (H_SCROLLBAR_MAX * ((double) (time1 - time0) / delta)));
2594 // At the beginning of visible window
2595 timePos = (int) (H_SCROLLBAR_MAX * ((double) (time0 - timeMin) / delta));
2596 }
2597 fHorizontalScrollBar.setValues(timePos, 0, H_SCROLLBAR_MAX, thumb, Math.max(1, thumb / 2), Math.max(2, thumb));
2598 }
2599
2600 private void adjustVerticalScrollBar() {
2601 int topIndex = fTimeGraphCtrl.getTopIndex();
2602 int countPerPage = fTimeGraphCtrl.countPerPage();
2603 int expandedElementCount = fTimeGraphCtrl.getExpandedElementCount();
2604 if (topIndex + countPerPage > expandedElementCount) {
2605 fTimeGraphCtrl.setTopIndex(Math.max(0, expandedElementCount - countPerPage));
2606 }
2607
2608 int selection = fTimeGraphCtrl.getTopIndex();
2609 int min = 0;
2610 int max = Math.max(1, expandedElementCount - 1);
2611 int thumb = Math.min(max, Math.max(1, countPerPage - 1));
2612 int increment = 1;
2613 int pageIncrement = Math.max(1, countPerPage);
2614 fVerticalScrollBar.setValues(selection, min, max, thumb, increment, pageIncrement);
2615 }
2616
2617 /**
2618 * @param listener
2619 * a {@link MenuDetectListener}
2620 * @see org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl#addTimeGraphEntryMenuListener(org.eclipse.swt.events.MenuDetectListener)
2621 */
2622 public void addTimeGraphEntryMenuListener(MenuDetectListener listener) {
2623 fTimeGraphCtrl.addTimeGraphEntryMenuListener(listener);
2624 }
2625
2626 /**
2627 * @param listener
2628 * a {@link MenuDetectListener}
2629 * @see org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl#removeTimeGraphEntryMenuListener(org.eclipse.swt.events.MenuDetectListener)
2630 */
2631 public void removeTimeGraphEntryMenuListener(MenuDetectListener listener) {
2632 fTimeGraphCtrl.removeTimeGraphEntryMenuListener(listener);
2633 }
2634
2635 /**
2636 * @param listener
2637 * a {@link MenuDetectListener}
2638 * @see org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl#addTimeEventMenuListener(org.eclipse.swt.events.MenuDetectListener)
2639 */
2640 public void addTimeEventMenuListener(MenuDetectListener listener) {
2641 fTimeGraphCtrl.addTimeEventMenuListener(listener);
2642 }
2643
2644 /**
2645 * @param listener
2646 * a {@link MenuDetectListener}
2647 * @see org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl#removeTimeEventMenuListener(org.eclipse.swt.events.MenuDetectListener)
2648 */
2649 public void removeTimeEventMenuListener(MenuDetectListener listener) {
2650 fTimeGraphCtrl.removeTimeEventMenuListener(listener);
2651 }
2652
2653 /**
2654 * @param filter
2655 * The filter object to be attached to the view
2656 */
2657 public void addFilter(@NonNull ViewerFilter filter) {
2658 fTimeGraphCtrl.addFilter(filter);
2659 refresh();
2660 }
2661
2662 /**
2663 * @param filter
2664 * The filter object to be attached to the view
2665 */
2666 public void removeFilter(@NonNull ViewerFilter filter) {
2667 fTimeGraphCtrl.removeFilter(filter);
2668 refresh();
2669 }
2670
2671 /**
2672 * Returns this viewer's filters.
2673 *
2674 * @return an array of viewer filters
2675 * @since 1.2
2676 */
2677 public @NonNull ViewerFilter[] getFilters() {
2678 return fTimeGraphCtrl.getFilters();
2679 }
2680
2681 /**
2682 * Sets the filters, replacing any previous filters, and triggers
2683 * refiltering of the elements.
2684 *
2685 * @param filters
2686 * an array of viewer filters, or null
2687 * @since 1.2
2688 */
2689 public void setFilters(@NonNull ViewerFilter[] filters) {
2690 fTimeGraphCtrl.setFilters(filters);
2691 refresh();
2692 }
2693
2694 /**
2695 * Return the time alignment information
2696 *
2697 * @return the time alignment information
2698 *
2699 * @see ITmfTimeAligned
2700 *
2701 * @since 1.0
2702 */
2703 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
2704 return fTimeGraphCtrl.getTimeViewAlignmentInfo();
2705 }
2706
2707 /**
2708 * Return the available width for the time-axis.
2709 *
2710 * @see ITmfTimeAligned
2711 *
2712 * @param requestedOffset
2713 * the requested offset
2714 * @return the available width for the time-axis
2715 *
2716 * @since 1.0
2717 */
2718 public int getAvailableWidth(int requestedOffset) {
2719 int totalWidth = fTimeAlignedComposite.getSize().x;
2720 return Math.min(totalWidth, Math.max(0, totalWidth - requestedOffset));
2721 }
2722
2723 /**
2724 * Perform the alignment operation.
2725 *
2726 * @param offset
2727 * the alignment offset
2728 * @param width
2729 * the alignment width
2730 *
2731 * @see ITmfTimeAligned
2732 *
2733 * @since 1.0
2734 */
2735 public void performAlign(int offset, int width) {
2736 fTimeGraphCtrl.performAlign(offset);
2737 int alignmentWidth = width;
2738 int size = fTimeAlignedComposite.getSize().x;
2739 GridLayout layout = (GridLayout) fTimeAlignedComposite.getLayout();
2740 int marginSize = size - alignmentWidth - offset;
2741 layout.marginRight = Math.max(0, marginSize);
2742 fTimeAlignedComposite.layout();
2743 }
2744
2745 }
This page took 0.092097 seconds and 4 git commands to generate.