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