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