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