/***************************************************************************** * Copyright (c) 2007, 2016 Intel Corporation, Ericsson, others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Intel Corporation - Initial API and implementation * Ruslan A. Scherbakov, Intel - Initial API and implementation * Alexander N. Alexeev, Intel - Add monitors statistics support * Alvaro Sanchez-Leon - Adapted for TMF * Patrick Tasse - Refactoring * Geneviève Bastien - Add event links between entries *****************************************************************************/ package org.eclipse.tracecompass.tmf.ui.widgets.timegraph; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuCreator; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.AbstractTreeViewer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseWheelListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGBA; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Slider; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.tracecompass.internal.tmf.ui.Activator; import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants; import org.eclipse.tracecompass.internal.tmf.ui.Messages; import org.eclipse.tracecompass.internal.tmf.ui.dialogs.AddBookmarkDialog; import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo; import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.ShowFilterDialogAction; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.dialogs.TimeGraphLegend; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.MarkerEvent; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.IMarkerAxisListener; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.ITimeDataProvider; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeDataProviderCyclesConverter; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphColorScheme; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphMarkerAxis; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphScale; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphTooltipHandler; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat; import org.eclipse.ui.PlatformUI; /** * Generic time graph viewer implementation * * @author Patrick Tasse, and others */ public class TimeGraphViewer extends Viewer implements ITimeDataProvider, IMarkerAxisListener, SelectionListener { /** Constant indicating that all levels of the time graph should be expanded */ public static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS; private static final int DEFAULT_NAME_WIDTH = 200; private static final int MIN_NAME_WIDTH = 3; private static final int MAX_NAME_WIDTH = 1000; private static final int DEFAULT_HEIGHT = 22; private static final String HIDE_ARROWS_KEY = "hide.arrows"; //$NON-NLS-1$ private static final long DEFAULT_FREQUENCY = 1000000000L; private static final int H_SCROLLBAR_MAX = Integer.MAX_VALUE - 1; private static final ImageDescriptor ADD_BOOKMARK = Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ADD_BOOKMARK); private static final ImageDescriptor NEXT_BOOKMARK = Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_BOOKMARK); private static final ImageDescriptor PREVIOUS_BOOKMARK = Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREVIOUS_BOOKMARK); private static final ImageDescriptor REMOVE_BOOKMARK = Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_REMOVE_BOOKMARK); private long fMinTimeInterval; private ITimeGraphEntry fSelectedEntry; private long fBeginTime = SWT.DEFAULT; // The user-specified bounds start time private long fEndTime = SWT.DEFAULT; // The user-specified bounds end time private long fTime0 = SWT.DEFAULT; // The current window start time private long fTime1 = SWT.DEFAULT; // The current window end time private long fSelectionBegin = SWT.DEFAULT; private long fSelectionEnd = SWT.DEFAULT; private long fTime0Bound = SWT.DEFAULT; // The bounds start time private long fTime1Bound = SWT.DEFAULT; // The bounds end time private long fTime0ExtSynch = SWT.DEFAULT; private long fTime1ExtSynch = SWT.DEFAULT; private boolean fTimeRangeFixed; private int fNameWidthPref = DEFAULT_NAME_WIDTH; private int fMinNameWidth = MIN_NAME_WIDTH; private int fNameWidth; private int[] fWeights; private Composite fDataViewer; private TimeGraphControl fTimeGraphCtrl; private Tree fTree; private TimeGraphScale fTimeScaleCtrl; private TimeGraphMarkerAxis fMarkerAxisCtrl; private Slider fHorizontalScrollBar; private Slider fVerticalScrollBar; private @NonNull TimeGraphColorScheme fColorScheme = new TimeGraphColorScheme(); private Object fInputElement; private ITimeGraphContentProvider fTimeGraphContentProvider; private ITimeGraphPresentationProvider fTimeGraphProvider; private ITableLabelProvider fLabelProvider; private @NonNull ITimeDataProvider fTimeDataProvider = this; private TimeGraphTooltipHandler fToolTipHandler; private List<ITimeGraphSelectionListener> fSelectionListeners = new ArrayList<>(); private List<ITimeGraphTimeListener> fTimeListeners = new ArrayList<>(); private List<ITimeGraphRangeListener> fRangeListeners = new ArrayList<>(); private List<ITimeGraphBookmarkListener> fBookmarkListeners = new ArrayList<>(); // Time format, using Epoch reference, Relative time format(default), // Number, or Cycles private TimeFormat fTimeFormat = TimeFormat.RELATIVE; // Clock frequency to use for Cycles time format private long fClockFrequency = DEFAULT_FREQUENCY; private int fBorderWidth = 0; private int fTimeScaleHeight = DEFAULT_HEIGHT; private Action fResetScaleAction; private Action fShowLegendAction; private Action fNextEventAction; private Action fPrevEventAction; private Action fNextItemAction; private Action fPreviousItemAction; private Action fZoomInAction; private Action fZoomOutAction; private Action fHideArrowsAction; private Action fFollowArrowFwdAction; private Action fFollowArrowBwdAction; private ShowFilterDialogAction fShowFilterDialogAction; private Action fToggleBookmarkAction; private Action fNextMarkerAction; private Action fPreviousMarkerAction; private MenuManager fMarkersMenu; /** The list of bookmarks */ private final List<IMarkerEvent> fBookmarks = new ArrayList<>(); /** The list of marker categories */ private final List<String> fMarkerCategories = new ArrayList<>(); /** The set of hidden marker categories */ private final Set<String> fHiddenMarkerCategories = new HashSet<>(); /** The set of skipped marker categories */ private final Set<String> fSkippedMarkerCategories = new HashSet<>(); /** The list of markers */ private final List<IMarkerEvent> fMarkers = new ArrayList<>(); private ListenerNotifier fListenerNotifier; private Composite fTimeAlignedComposite; private class ListenerNotifier extends Thread { private static final long DELAY = 400L; private static final long POLLING_INTERVAL = 10L; private long fLastUpdateTime = Long.MAX_VALUE; private boolean fSelectionChanged = false; private boolean fTimeRangeUpdated = false; private boolean fTimeSelected = false; @Override public void run() { while ((System.currentTimeMillis() - fLastUpdateTime) < DELAY) { try { Thread.sleep(POLLING_INTERVAL); } catch (Exception e) { return; } } Display.getDefault().asyncExec(new Runnable() { @Override public void run() { if (fListenerNotifier != ListenerNotifier.this) { return; } fListenerNotifier = null; if (ListenerNotifier.this.isInterrupted() || fDataViewer.isDisposed()) { return; } if (fSelectionChanged) { fireSelectionChanged(fSelectedEntry); } if (fTimeRangeUpdated) { fireTimeRangeUpdated(fTime0, fTime1); } if (fTimeSelected) { fireTimeSelected(fSelectionBegin, fSelectionEnd); } } }); } public void selectionChanged() { fSelectionChanged = true; fLastUpdateTime = System.currentTimeMillis(); } public void timeRangeUpdated() { fTimeRangeUpdated = true; fLastUpdateTime = System.currentTimeMillis(); } public void timeSelected() { fTimeSelected = true; fLastUpdateTime = System.currentTimeMillis(); } public boolean hasSelectionChanged() { return fSelectionChanged; } public boolean hasTimeRangeUpdated() { return fTimeRangeUpdated; } public boolean hasTimeSelected() { return fTimeSelected; } } private final static class MarkerComparator implements Comparator<IMarkerEvent> { @Override public int compare(IMarkerEvent o1, IMarkerEvent o2) { int res = Long.compare(o1.getTime(), o2.getTime()); if (res != 0) { return res; } return Long.compare(o1.getDuration(), o2.getDuration()); } } /** * Standard constructor. * <p> * The default timegraph content provider accepts an ITimeGraphEntry[] as input element. * * @param parent * The parent UI composite object * @param style * The style to use */ public TimeGraphViewer(Composite parent, int style) { createDataViewer(parent, style); fTimeGraphContentProvider = new TimeGraphContentProvider(); } /** * Sets the timegraph content provider used by this timegraph viewer. * * @param timeGraphContentProvider * the timegraph content provider */ public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider) { fTimeGraphContentProvider = timeGraphContentProvider; } /** * Gets the timegraph content provider used by this timegraph viewer. * * @return the timegraph content provider */ public ITimeGraphContentProvider getTimeGraphContentProvider() { return fTimeGraphContentProvider; } /** * Sets the timegraph presentation provider used by this timegraph viewer. * * @param timeGraphProvider * the timegraph provider */ public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) { fTimeGraphProvider = timeGraphProvider; fTimeGraphCtrl.setTimeGraphProvider(timeGraphProvider); fToolTipHandler = new TimeGraphTooltipHandler(fTimeGraphProvider, fTimeDataProvider); fToolTipHandler.activateHoverHelp(fTimeGraphCtrl); } /** * Sets the tree label provider used for the name space * * @param labelProvider the tree label provider * @since 2.3 */ public void setTimeGraphLabelProvider(ITableLabelProvider labelProvider) { fLabelProvider = labelProvider; if (fTimeGraphCtrl != null) { fTimeGraphCtrl.setLabelProvider(labelProvider); } } /** * Sets the tree columns for this time graph combo's filter dialog. * * @param columnNames the tree column names * @since 1.2 */ public void setFilterColumns(String[] columnNames) { getShowFilterDialogAction().getFilterDialog().setColumnNames(columnNames); } /** * Sets the tree content provider used by the filter dialog * * @param contentProvider the tree content provider * @since 1.2 */ public void setFilterContentProvider(ITreeContentProvider contentProvider) { getShowFilterDialogAction().getFilterDialog().setContentProvider(contentProvider); } /** * Sets the tree label provider used by the filter dialog * * @param labelProvider the tree label provider * @since 1.2 */ public void setFilterLabelProvider(ITableLabelProvider labelProvider) { getShowFilterDialogAction().getFilterDialog().setLabelProvider(labelProvider); } @Override public void setInput(Object inputElement) { Object oldInput = fInputElement; fTimeGraphContentProvider.inputChanged(this, oldInput, inputElement); fInputElement = inputElement; ITimeGraphEntry[] input = fTimeGraphContentProvider.getElements(inputElement); fListenerNotifier = null; if (fTimeGraphCtrl != null) { setTimeRange(input); setTopIndex(0); fSelectionBegin = SWT.DEFAULT; fSelectionEnd = SWT.DEFAULT; updateMarkerActions(); fSelectedEntry = null; refreshAllData(input); } } @Override public Object getInput() { return fInputElement; } /** * Sets (or clears if null) the list of links to display on this combo * * @param links * the links to display in this time graph combo */ public void setLinks(List<ILinkEvent> links) { if (fTimeGraphCtrl != null) { fTimeGraphCtrl.refreshArrows(links); } } @Override public void refresh() { ITimeGraphEntry[] input = fTimeGraphContentProvider.getElements(fInputElement); setTimeRange(input); refreshAllData(input); } /** * Callback for when the control is moved * * @param e * The caller event */ public void controlMoved(ControlEvent e) { } /** * Callback for when the control is resized * * @param e * The caller event */ public void controlResized(ControlEvent e) { resizeControls(); } /** * @return The string representing the view type */ protected String getViewTypeStr() { return "viewoption.threads"; //$NON-NLS-1$ } int getMarginWidth() { return 0; } int getMarginHeight() { return 0; } void loadOptions() { fMinTimeInterval = 1; fSelectionBegin = SWT.DEFAULT; fSelectionEnd = SWT.DEFAULT; fNameWidth = Utils.loadIntOption(getPreferenceString("namewidth"), //$NON-NLS-1$ fNameWidthPref, fMinNameWidth, MAX_NAME_WIDTH); } void saveOptions() { Utils.saveIntOption(getPreferenceString("namewidth"), fNameWidth); //$NON-NLS-1$ } /** * Create a data viewer. * * @param parent * Parent composite * @param style * Style to use * @return The new data viewer */ protected Control createDataViewer(Composite parent, int style) { loadOptions(); fDataViewer = new Composite(parent, style) { @Override public void redraw() { fTree.redraw(); fTimeScaleCtrl.redraw(); fTimeGraphCtrl.redraw(); fMarkerAxisCtrl.redraw(); super.redraw(); } }; fDataViewer.addDisposeListener((e) -> { if (fMarkersMenu != null) { fMarkersMenu.dispose(); } }); GridLayout gl = new GridLayout(2, false); gl.marginHeight = fBorderWidth; gl.marginWidth = 0; gl.verticalSpacing = 0; gl.horizontalSpacing = 0; fDataViewer.setLayout(gl); fTimeAlignedComposite = new Composite(fDataViewer, style) { @Override public void redraw() { fDataViewer.redraw(); super.redraw(); } }; GridLayout gl2 = new GridLayout(2, false); gl2.marginHeight = fBorderWidth; gl2.marginWidth = 0; gl2.verticalSpacing = 0; gl2.horizontalSpacing = 0; fTimeAlignedComposite.setLayout(gl2); fTimeAlignedComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); fTree = new Tree(fTimeAlignedComposite, SWT.NO_SCROLL); fTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); fTree.setHeaderVisible(true); // add a default column TreeColumn column = new TreeColumn(fTree, SWT.LEFT); column.setResizable(false); /* * Bug in Linux. The tree header height is 0 in constructor, so we need * to reset it later when the control is painted. This work around used * to be done on control resized but the header height was not * initialized on the initial resize on GTK3. */ fTree.addPaintListener(new PaintListener() { @Override public void paintControl(PaintEvent e) { int headerHeight = fTree.getHeaderHeight(); if (headerHeight > 0) { fTree.removePaintListener(this); setHeaderHeight(headerHeight); } } }); fTimeScaleCtrl = new TimeGraphScale(fTimeAlignedComposite, fColorScheme); fTimeScaleCtrl.setTimeProvider(fTimeDataProvider); fTimeScaleCtrl.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false)); fTimeScaleCtrl.setHeight(fTimeScaleHeight); fTimeScaleCtrl.addMouseWheelListener(new MouseWheelListener() { @Override public void mouseScrolled(MouseEvent e) { if (e.count == 0) { return; } if ((e.stateMask & SWT.CTRL) != 0) { fTimeGraphCtrl.zoom(e.count > 0); } else { fTimeGraphCtrl.horizontalScroll(e.count > 0); } } }); fTimeGraphCtrl = createTimeGraphControl(fTimeAlignedComposite, fColorScheme); fTimeGraphCtrl.setTimeProvider(this); fTimeGraphCtrl.setLabelProvider(fLabelProvider); fTimeGraphCtrl.setTree(fTree); fTimeGraphCtrl.setTimeGraphScale(fTimeScaleCtrl); fTimeGraphCtrl.addSelectionListener(this); fTimeGraphCtrl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); fTimeGraphCtrl.addMouseWheelListener(new MouseWheelListener() { @Override public void mouseScrolled(MouseEvent e) { if (e.count == 0) { return; } /* * On some platforms the mouse scroll event is sent to the * control that has focus even if it is not under the cursor. * Handle the event only if not over the time graph control. */ Point ctrlParentCoords = fTimeAlignedComposite.toControl(fTimeGraphCtrl.toDisplay(e.x, e.y)); Point scrollBarParentCoords = fDataViewer.toControl(fTimeGraphCtrl.toDisplay(e.x, e.y)); if (fTimeGraphCtrl.getBounds().contains(ctrlParentCoords)) { /* the time graph control handles the event */ adjustVerticalScrollBar(); } else if (fTimeScaleCtrl.getBounds().contains(ctrlParentCoords) || fMarkerAxisCtrl.getBounds().contains(ctrlParentCoords) || fHorizontalScrollBar.getBounds().contains(scrollBarParentCoords)) { if ((e.stateMask & SWT.CTRL) != 0) { fTimeGraphCtrl.zoom(e.count > 0); } else { fTimeGraphCtrl.horizontalScroll(e.count > 0); } } else { /* over the vertical scroll bar or outside of the viewer */ setTopIndex(getTopIndex() - e.count); } } }); fTimeGraphCtrl.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.keyCode == '.') { boolean extend = (e.stateMask & SWT.SHIFT) != 0; if (extend) { extendToNextMarker(); } else { selectNextMarker(); } } else if (e.keyCode == ',') { boolean extend = (e.stateMask & SWT.SHIFT) != 0; if (extend) { extendToPrevMarker(); } else { selectPrevMarker(); } } adjustVerticalScrollBar(); } }); fMarkerAxisCtrl = createTimeGraphMarkerAxis(fTimeAlignedComposite, fColorScheme, this); fMarkerAxisCtrl.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false, 2, 1)); fMarkerAxisCtrl.addMarkerAxisListener(this); fMarkerAxisCtrl.addMouseWheelListener(new MouseWheelListener() { @Override public void mouseScrolled(MouseEvent e) { if (e.count == 0) { return; } if ((e.stateMask & SWT.CTRL) != 0) { fTimeGraphCtrl.zoom(e.count > 0); } else { fTimeGraphCtrl.horizontalScroll(e.count > 0); } } }); fVerticalScrollBar = new Slider(fDataViewer, SWT.VERTICAL | SWT.NO_FOCUS); fVerticalScrollBar.setLayoutData(new GridData(SWT.DEFAULT, SWT.FILL, false, true, 1, 1)); fVerticalScrollBar.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setTopIndex(fVerticalScrollBar.getSelection()); } }); fHorizontalScrollBar = new Slider(fDataViewer, SWT.HORIZONTAL | SWT.NO_FOCUS); fHorizontalScrollBar.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false)); fHorizontalScrollBar.addListener(SWT.MouseWheel, new Listener() { @Override public void handleEvent(Event event) { // don't handle the immediately following SWT.Selection event event.doit = false; if (event.count == 0) { return; } if ((event.stateMask & SWT.CTRL) != 0) { fTimeGraphCtrl.zoom(event.count > 0); } else { fTimeGraphCtrl.horizontalScroll(event.count > 0); } } }); fHorizontalScrollBar.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { int start = fHorizontalScrollBar.getSelection(); long time0 = getTime0(); long time1 = getTime1(); long timeMin = getMinTime(); long timeMax = getMaxTime(); long delta = timeMax - timeMin; long range = time1 - time0; time0 = timeMin + Math.round(delta * ((double) start / H_SCROLLBAR_MAX)); time1 = time0 + range; setStartFinishTimeNotify(time0, time1); } }); Composite filler = new Composite(fDataViewer, SWT.NONE); GridData gd = new GridData(SWT.DEFAULT, SWT.DEFAULT, false, false); gd.heightHint = fHorizontalScrollBar.getSize().y; filler.setLayoutData(gd); filler.setLayout(new FillLayout()); fTimeGraphCtrl.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent event) { resizeControls(); } }); resizeControls(); fDataViewer.update(); adjustHorizontalScrollBar(); adjustVerticalScrollBar(); fDataViewer.addDisposeListener((e) -> { saveOptions(); fColorScheme.dispose(); }); return fDataViewer; } /** * Dispose the time graph viewer. */ public void dispose() { fDataViewer.dispose(); } /** * Create a new time graph control. * * @param parent * The parent composite * @param colors * The color scheme * @return The new TimeGraphControl */ protected TimeGraphControl createTimeGraphControl(Composite parent, TimeGraphColorScheme colors) { return new TimeGraphControl(parent, colors); } /** * Create a new time graph marker axis. * * @param parent * The parent composite object * @param colorScheme * The color scheme to use * @param timeProvider * The time data provider * @return The new TimeGraphMarkerAxis * @since 2.0 */ protected TimeGraphMarkerAxis createTimeGraphMarkerAxis(Composite parent, @NonNull TimeGraphColorScheme colorScheme, @NonNull ITimeDataProvider timeProvider) { return new TimeGraphMarkerAxis(parent, colorScheme, timeProvider); } /** * Resize the controls */ public void resizeControls() { Rectangle r = fDataViewer.getClientArea(); if (r.isEmpty()) { return; } if (fWeights != null) { setWeights(fWeights); fWeights = null; } int width = r.width; if (fNameWidth > width - fMinNameWidth) { fNameWidth = width - fMinNameWidth; } if (fNameWidth < fMinNameWidth) { fNameWidth = fMinNameWidth; } if (fTree.getColumnCount() == 1) { fTree.getColumn(0).setWidth(fNameWidth); } adjustHorizontalScrollBar(); adjustVerticalScrollBar(); } /** * Recalculate the time bounds based on the time graph entries, * if the user-specified bound is set to SWT.DEFAULT. * * @param entries * The root time graph entries in the model */ public void setTimeRange(ITimeGraphEntry entries[]) { fTime0Bound = (fBeginTime != SWT.DEFAULT ? fBeginTime : fEndTime); fTime1Bound = (fEndTime != SWT.DEFAULT ? fEndTime : fBeginTime); if (fBeginTime != SWT.DEFAULT && fEndTime != SWT.DEFAULT) { return; } if (entries == null || entries.length == 0) { return; } if (fTime0Bound == SWT.DEFAULT) { fTime0Bound = Long.MAX_VALUE; } if (fTime1Bound == SWT.DEFAULT) { fTime1Bound = Long.MIN_VALUE; } for (ITimeGraphEntry entry : entries) { setTimeRange(entry); } if (fTime0Bound > fTime1Bound) { fTime0Bound = SWT.DEFAULT; fTime1Bound = SWT.DEFAULT; } } private void setTimeRange(ITimeGraphEntry entry) { if (fBeginTime == SWT.DEFAULT && entry.hasTimeEvents() && entry.getStartTime() != SWT.DEFAULT) { fTime0Bound = Math.min(entry.getStartTime(), fTime0Bound); } if (fEndTime == SWT.DEFAULT && entry.hasTimeEvents() && entry.getEndTime() != SWT.DEFAULT) { fTime1Bound = Math.max(entry.getEndTime(), fTime1Bound); } if (entry.hasChildren()) { for (ITimeGraphEntry child : entry.getChildren()) { setTimeRange(child); } } } /** * Set the time bounds to the provided values. * * @param beginTime * The bounds begin time, or SWT.DEFAULT to use the input bounds * @param endTime * The bounds end time, or SWT.DEFAULT to use the input bounds */ public void setTimeBounds(long beginTime, long endTime) { fBeginTime = beginTime; fEndTime = endTime; fTime0Bound = (fBeginTime != SWT.DEFAULT ? fBeginTime : fEndTime); fTime1Bound = (fEndTime != SWT.DEFAULT ? fEndTime : fBeginTime); if (fTime0Bound > fTime1Bound) { // only possible if both are not default fBeginTime = endTime; fEndTime = beginTime; fTime0Bound = fBeginTime; fTime1Bound = fEndTime; } adjustHorizontalScrollBar(); } /** * Recalculate the current time window when bounds have changed. */ public void setTimeBounds() { if (!fTimeRangeFixed) { fTime0 = fTime0Bound; fTime1 = fTime1Bound; } fTime0 = Math.max(fTime0Bound, Math.min(fTime0, fTime1Bound)); fTime1 = Math.max(fTime0Bound, Math.min(fTime1, fTime1Bound)); if (fTime1 - fTime0 < fMinTimeInterval) { fTime1 = Math.min(fTime1Bound, fTime0 + fMinTimeInterval); } } /** * @param traces */ private void refreshAllData(ITimeGraphEntry[] traces) { setTimeBounds(); if (fSelectionBegin < fBeginTime) { fSelectionBegin = fBeginTime; } else if (fSelectionBegin > fEndTime) { fSelectionBegin = fEndTime; } if (fSelectionEnd < fBeginTime) { fSelectionEnd = fBeginTime; } else if (fSelectionEnd > fEndTime) { fSelectionEnd = fEndTime; } fTimeGraphCtrl.refreshData(traces); fTimeScaleCtrl.redraw(); fMarkerAxisCtrl.redraw(); updateMarkerActions(); adjustVerticalScrollBar(); } /** * Callback for when this view is focused */ public void setFocus() { if (null != fTimeGraphCtrl) { fTimeGraphCtrl.setFocus(); } } /** * Get the current focus status of this view. * * @return If the view is currently focused, or not */ public boolean isInFocus() { return fTimeGraphCtrl.isInFocus(); } /** * Get the view's current selection * * @return The entry that is selected */ @Override public ITimeGraphEntry getSelection() { return fTimeGraphCtrl.getSelectedTrace(); } /** * Get the index of the current selection * * @return The index */ public int getSelectionIndex() { return fTimeGraphCtrl.getSelectedIndex(); } @Override public long getTime0() { return fTime0; } @Override public long getTime1() { return fTime1; } @Override public long getMinTimeInterval() { return fMinTimeInterval; } /** * Sets the relative horizontal weight of each part of the time graph * viewer. The first number is the name space weight, and the second number * is the time space weight. * * @param weights * The array of relative weights of each part of the viewer * @since 2.3 */ public void setWeights(final int[] weights) { if (weights.length != 2) { return; } int width = fTimeAlignedComposite.getSize().x; if (width == 0) { /* the weigths will be applied when the control is resized */ fWeights = Arrays.copyOf(weights, weights.length); return; } setNameSpace(width * weights[0] / (weights[0] + weights[1])); } @Override public int getNameSpace() { return fNameWidth; } @Override public void setNameSpace(int width) { fNameWidth = width; int w = fTimeGraphCtrl.getClientArea().width; if (fNameWidth > w - MIN_NAME_WIDTH) { fNameWidth = w - MIN_NAME_WIDTH; } if (fNameWidth < MIN_NAME_WIDTH) { fNameWidth = MIN_NAME_WIDTH; } GridData gd = (GridData) fTree.getLayoutData(); gd.widthHint = fNameWidth; if (fTree.getColumnCount() == 1) { fTree.getColumn(0).setWidth(fNameWidth); } fTimeAlignedComposite.layout(); fTree.redraw(); fTimeGraphCtrl.redraw(); fTimeScaleCtrl.redraw(); fMarkerAxisCtrl.redraw(); } @Override public int getTimeSpace() { int w = fTimeGraphCtrl.getClientArea().width; return w - fNameWidth; } @Override public long getBeginTime() { return fBeginTime; } @Override public long getEndTime() { return fEndTime; } @Override public long getMaxTime() { return fTime1Bound; } @Override public long getMinTime() { return fTime0Bound; } @Override public long getSelectionBegin() { return fSelectionBegin; } @Override public long getSelectionEnd() { return fSelectionEnd; } @Override public void setStartFinishTimeNotify(long time0, long time1) { setStartFinishTimeInt(time0, time1); notifyRangeListeners(); } @Override public void notifyStartFinishTime() { notifyRangeListeners(); } @Override public void setStartFinishTime(long time0, long time1) { /* if there is a pending time range, ignore this one */ if (fListenerNotifier != null && fListenerNotifier.hasTimeRangeUpdated()) { return; } setStartFinishTimeInt(time0, time1); updateExtSynchValues(); } private void setStartFinishTimeInt(long time0, long time1) { fTime0 = time0; if (fTime0 < fTime0Bound) { fTime0 = fTime0Bound; } if (fTime0 > fTime1Bound) { fTime0 = fTime1Bound; } fTime1 = time1; if (fTime1 < fTime0Bound) { fTime1 = fTime0Bound; } if (fTime1 > fTime1Bound) { fTime1 = fTime1Bound; } if (fTime1 - fTime0 < fMinTimeInterval) { fTime1 = Math.min(fTime1Bound, fTime0 + fMinTimeInterval); } fTimeRangeFixed = true; adjustHorizontalScrollBar(); fTimeGraphCtrl.redraw(); fTimeScaleCtrl.redraw(); fMarkerAxisCtrl.redraw(); } @Override public void resetStartFinishTime() { setStartFinishTimeNotify(fTime0Bound, fTime1Bound); fTimeRangeFixed = false; } /** * @since 2.0 */ @Override public void resetStartFinishTime(boolean notify) { if (notify) { setStartFinishTimeNotify(fTime0Bound, fTime1Bound); } else { setStartFinishTime(fTime0Bound, fTime1Bound); } fTimeRangeFixed = false; } @Override public void setSelectedTimeNotify(long time, boolean ensureVisible) { setSelectedTimeInt(time, ensureVisible, true); } @Override public void setSelectedTime(long time, boolean ensureVisible) { /* if there is a pending time selection, ignore this one */ if (fListenerNotifier != null && fListenerNotifier.hasTimeSelected()) { return; } setSelectedTimeInt(time, ensureVisible, false); } private void setSelectedTimeInt(long time, boolean ensureVisible, boolean doNotify) { setSelectionRangeInt(time, time, ensureVisible, doNotify); } /** * @since 1.2 */ @Override public void setSelectionRangeNotify(long beginTime, long endTime, boolean ensureVisible) { setSelectionRangeInt(beginTime, endTime, ensureVisible, true); } /** * @since 1.2 */ @Override public void setSelectionRange(long beginTime, long endTime, boolean ensureVisible) { /* if there is a pending time selection, ignore this one */ if (fListenerNotifier != null && fListenerNotifier.hasTimeSelected()) { return; } setSelectionRangeInt(beginTime, endTime, ensureVisible, false); } private void setSelectionRangeInt(long beginTime, long endTime, boolean ensureVisible, boolean doNotify) { long time0 = fTime0; long time1 = fTime1; long selectionBegin = fSelectionBegin; long selectionEnd = fSelectionEnd; fSelectionBegin = Math.max(fTime0Bound, Math.min(fTime1Bound, beginTime)); fSelectionEnd = Math.max(fTime0Bound, Math.min(fTime1Bound, endTime)); boolean changed = (selectionBegin != fSelectionBegin || selectionEnd != fSelectionEnd); if (ensureVisible) { ensureVisible(selectionBegin != fSelectionBegin ? fSelectionBegin : fSelectionEnd); } fTimeGraphCtrl.redraw(); fTimeScaleCtrl.redraw(); fMarkerAxisCtrl.redraw(); updateMarkerActions(); if ((time0 != fTime0) || (time1 != fTime1)) { notifyRangeListeners(); } if (doNotify && changed) { notifyTimeListeners(); } } private void ensureVisible(long time) { long timeMid = (fTime1 - fTime0) / 2; if (time < fTime0) { long dt = fTime0 - time + timeMid; fTime0 -= dt; fTime1 -= dt; } else if (time > fTime1) { long dt = time - fTime1 + timeMid; fTime0 += dt; fTime1 += dt; } if (fTime0 < fTime0Bound) { fTime1 = Math.min(fTime1Bound, fTime1 + (fTime0Bound - fTime0)); fTime0 = fTime0Bound; } else if (fTime1 > fTime1Bound) { fTime0 = Math.max(fTime0Bound, fTime0 - (fTime1 - fTime1Bound)); fTime1 = fTime1Bound; } if (fTime1 - fTime0 < fMinTimeInterval) { fTime1 = Math.min(fTime1Bound, fTime0 + fMinTimeInterval); } adjustHorizontalScrollBar(); } @Override public void widgetDefaultSelected(SelectionEvent e) { if (fSelectedEntry != getSelection()) { fSelectedEntry = getSelection(); notifySelectionListeners(); } } @Override public void widgetSelected(SelectionEvent e) { if (fSelectedEntry != getSelection()) { fSelectedEntry = getSelection(); notifySelectionListeners(); } } /** * Callback for when the next event is selected * * @param extend * true to extend selection range, false for single selection * @since 1.0 */ public void selectNextEvent(boolean extend) { fTimeGraphCtrl.selectNextEvent(extend); adjustVerticalScrollBar(); } /** * Callback for when the previous event is selected * * @param extend * true to extend selection range, false for single selection * @since 1.0 */ public void selectPrevEvent(boolean extend) { fTimeGraphCtrl.selectPrevEvent(extend); adjustVerticalScrollBar(); } /** * Callback for when the next item is selected */ public void selectNextItem() { fTimeGraphCtrl.selectNextTrace(); adjustVerticalScrollBar(); } /** * Callback for when the previous item is selected */ public void selectPrevItem() { fTimeGraphCtrl.selectPrevTrace(); adjustVerticalScrollBar(); } /** * Callback for the show legend action */ public void showLegend() { if (fDataViewer == null || fDataViewer.isDisposed()) { return; } TimeGraphLegend.open(fDataViewer.getShell(), fTimeGraphProvider); } /** * Callback for the Zoom In action */ public void zoomIn() { fTimeGraphCtrl.zoomIn(); } /** * Callback for the Zoom Out action */ public void zoomOut() { fTimeGraphCtrl.zoomOut(); } private String getPreferenceString(String string) { return getViewTypeStr() + "." + string; //$NON-NLS-1$ } /** * Add a selection listener * * @param listener * The listener to add */ public void addSelectionListener(ITimeGraphSelectionListener listener) { fSelectionListeners.add(listener); } /** * Remove a selection listener * * @param listener * The listener to remove */ public void removeSelectionListener(ITimeGraphSelectionListener listener) { fSelectionListeners.remove(listener); } private void notifySelectionListeners() { if (fListenerNotifier == null) { fListenerNotifier = new ListenerNotifier(); fListenerNotifier.start(); } fListenerNotifier.selectionChanged(); } private void fireSelectionChanged(ITimeGraphEntry selection) { TimeGraphSelectionEvent event = new TimeGraphSelectionEvent(this, selection); for (ITimeGraphSelectionListener listener : fSelectionListeners) { listener.selectionChanged(event); } ISelection structuredSelection = (selection == null) ? StructuredSelection.EMPTY : new StructuredSelection(selection); fireSelectionChanged(new SelectionChangedEvent(this, structuredSelection)); } /** * Add a time listener * * @param listener * The listener to add */ public void addTimeListener(ITimeGraphTimeListener listener) { fTimeListeners.add(listener); } /** * Remove a time listener * * @param listener * The listener to remove */ public void removeTimeListener(ITimeGraphTimeListener listener) { fTimeListeners.remove(listener); } private void notifyTimeListeners() { if (fListenerNotifier == null) { fListenerNotifier = new ListenerNotifier(); fListenerNotifier.start(); } fListenerNotifier.timeSelected(); } private void fireTimeSelected(long startTime, long endTime) { TimeGraphTimeEvent event = new TimeGraphTimeEvent(this, startTime, endTime); for (ITimeGraphTimeListener listener : fTimeListeners) { listener.timeSelected(event); } } /** * Add a range listener * * @param listener * The listener to add */ public void addRangeListener(ITimeGraphRangeListener listener) { fRangeListeners.add(listener); } /** * Remove a range listener * * @param listener * The listener to remove */ public void removeRangeListener(ITimeGraphRangeListener listener) { fRangeListeners.remove(listener); } private void notifyRangeListeners() { if (fListenerNotifier == null) { fListenerNotifier = new ListenerNotifier(); fListenerNotifier.start(); } fListenerNotifier.timeRangeUpdated(); } private void fireTimeRangeUpdated(long startTime, long endTime) { // Check if the time has actually changed from last notification if (startTime != fTime0ExtSynch || endTime != fTime1ExtSynch) { // Notify Time Scale Selection Listeners TimeGraphRangeUpdateEvent event = new TimeGraphRangeUpdateEvent(this, startTime, endTime); for (ITimeGraphRangeListener listener : fRangeListeners) { listener.timeRangeUpdated(event); } // update external synch values updateExtSynchValues(); } } /** * Add a bookmark listener * * @param listener * The listener to add * @since 2.0 */ public void addBookmarkListener(ITimeGraphBookmarkListener listener) { fBookmarkListeners.add(listener); } /** * Remove a bookmark listener * * @param listener * The listener to remove * @since 2.0 */ public void removeBookmarkListener(ITimeGraphBookmarkListener listener) { fBookmarkListeners.remove(listener); } private void fireBookmarkAdded(IMarkerEvent bookmark) { TimeGraphBookmarkEvent event = new TimeGraphBookmarkEvent(this, bookmark); for (ITimeGraphBookmarkListener listener : fBookmarkListeners) { listener.bookmarkAdded(event); } } private void fireBookmarkRemoved(IMarkerEvent bookmark) { TimeGraphBookmarkEvent event = new TimeGraphBookmarkEvent(this, bookmark); for (ITimeGraphBookmarkListener listener : fBookmarkListeners) { listener.bookmarkRemoved(event); } } /** * Set the bookmarks list. * * @param bookmarks * The bookmarks list, or null * @since 2.0 */ public void setBookmarks(List<IMarkerEvent> bookmarks) { fBookmarks.clear(); if (bookmarks != null) { fBookmarks.addAll(bookmarks); } updateMarkerList(); updateMarkerActions(); } /** * Get the bookmarks list. * * @return The bookmarks list * @since 2.0 */ public List<IMarkerEvent> getBookmarks() { return Collections.unmodifiableList(fBookmarks); } /** * Set the list of marker categories. * * @param categories * The list of marker categories, or null * @since 2.0 */ public void setMarkerCategories(List<String> categories) { fMarkerCategories.clear(); if (categories != null) { fMarkerCategories.addAll(categories); } fMarkerCategories.add(IMarkerEvent.BOOKMARKS); fMarkerAxisCtrl.setMarkerCategories(fMarkerCategories); } /** * @since 2.0 */ @Override public void setMarkerCategoryVisible(String category, boolean visible) { boolean changed = false; if (visible) { changed = fHiddenMarkerCategories.remove(category); } else { changed = fHiddenMarkerCategories.add(category); } if (changed) { updateMarkerList(); updateMarkerActions(); getControl().redraw(); } } /** * Set the markers list. * * @param markers * The markers list, or null * @since 2.0 */ public void setMarkers(List<IMarkerEvent> markers) { fMarkers.clear(); if (markers != null) { fMarkers.addAll(markers); } updateMarkerList(); updateMarkerActions(); } /** * Get the markers list. * * @return The markers list, or null * @since 2.0 */ public List<IMarkerEvent> getMarkers() { return Collections.unmodifiableList(fMarkers); } /** * Callback to set a selected event in the view * * @param event * The event that was selected * @param source * The source of this selection event */ public void setSelectedEvent(ITimeEvent event, Object source) { if (event == null || source == this) { return; } fSelectedEntry = event.getEntry(); fTimeGraphCtrl.selectItem(fSelectedEntry, false); setSelectedTimeInt(event.getTime(), true, true); adjustVerticalScrollBar(); } /** * Set the seeked time of a trace * * @param trace * The trace that was seeked * @param time * The target time * @param source * The source of this seek event */ public void setSelectedTraceTime(ITimeGraphEntry trace, long time, Object source) { if (trace == null || source == this) { return; } fSelectedEntry = trace; fTimeGraphCtrl.selectItem(trace, false); setSelectedTimeInt(time, true, true); } /** * Sets a new selection for this viewer and makes it visible. * * @param entry * The entry to select * @deprecated Use {@link #setSelection(ISelection, boolean)} instead. */ @Deprecated public void setSelection(ITimeGraphEntry entry) { setSelection(entry, true); } @Override public void setSelection(ISelection selection, boolean reveal) { /* if there is a pending selection, ignore this one */ if (fListenerNotifier != null && fListenerNotifier.hasSelectionChanged()) { return; } Object element = selection; if (selection instanceof IStructuredSelection) { element = ((IStructuredSelection) selection).getFirstElement(); } if (!(element instanceof ITimeGraphEntry)) { return; } ITimeGraphEntry entry = (ITimeGraphEntry) element; fSelectedEntry = entry; fTimeGraphCtrl.selectItem(entry, false, reveal); adjustVerticalScrollBar(); } /** * Callback for a time window selection * * @param time0 * Start time of the range * @param time1 * End time of the range * @param source * Source of the event */ public void setSelectVisTimeWindow(long time0, long time1, Object source) { if (source == this) { return; } setStartFinishTimeInt(time0, time1); // update notification time values since we are now in synch with the // external application updateExtSynchValues(); } /** * update the cache values used to identify the need to send a time window * update to external registered listeners */ private void updateExtSynchValues() { // last time notification cache fTime0ExtSynch = fTime0; fTime1ExtSynch = fTime1; } @Override public TimeFormat getTimeFormat() { return fTimeFormat; } /** * @param tf * the {@link TimeFormat} used to display timestamps */ public void setTimeFormat(TimeFormat tf) { this.fTimeFormat = tf; if (tf == TimeFormat.CYCLES) { fTimeDataProvider = new TimeDataProviderCyclesConverter(this, fClockFrequency); } else { fTimeDataProvider = this; } fTimeScaleCtrl.setTimeProvider(fTimeDataProvider); if (fToolTipHandler != null) { fToolTipHandler.setTimeProvider(fTimeDataProvider); } } /** * Sets the clock frequency. Used when the time format is set to CYCLES. * * @param clockFrequency * the clock frequency in Hz */ public void setClockFrequency(long clockFrequency) { fClockFrequency = clockFrequency; if (fTimeFormat == TimeFormat.CYCLES) { fTimeDataProvider = new TimeDataProviderCyclesConverter(this, fClockFrequency); fTimeScaleCtrl.setTimeProvider(fTimeDataProvider); if (fToolTipHandler != null) { fToolTipHandler.setTimeProvider(fTimeDataProvider); } } } /** * Retrieve the border width * * @return The width */ public int getBorderWidth() { return fBorderWidth; } /** * Set the border width * * @param borderWidth * The width */ public void setBorderWidth(int borderWidth) { if (borderWidth > -1) { this.fBorderWidth = borderWidth; GridLayout gl = (GridLayout) fDataViewer.getLayout(); gl.marginHeight = borderWidth; } } /** * Retrieve the height of the header * * @return The height */ public int getHeaderHeight() { return fTimeScaleHeight; } /** * Set the height of the header * * @param headerHeight * The height to set */ public void setHeaderHeight(int headerHeight) { if (headerHeight > -1) { this.fTimeScaleHeight = headerHeight; fTimeScaleCtrl.setHeight(headerHeight); } } /** * Retrieve the height of an item row * * @return The height */ public int getItemHeight() { if (fTimeGraphCtrl != null) { return fTimeGraphCtrl.getItemHeight(); } return 0; } /** * Set the height of an item row * * @param rowHeight * The height to set */ public void setItemHeight(int rowHeight) { if (fTimeGraphCtrl != null) { fTimeGraphCtrl.setItemHeight(rowHeight); } } /** * Set the minimum item width * * @param width * The min width */ public void setMinimumItemWidth(int width) { if (fTimeGraphCtrl != null) { fTimeGraphCtrl.setMinimumItemWidth(width); } } /** * Set the width for the name column * * @param width * The width */ public void setNameWidthPref(int width) { fNameWidthPref = width; if (width == 0) { fMinNameWidth = 0; fNameWidth = 0; } } /** * Retrieve the configure width for the name column * * @param width * Unused? * @return The width */ public int getNameWidthPref(int width) { return fNameWidthPref; } @Override public Control getControl() { return fDataViewer; } /** * Returns the time graph control associated with this viewer. * * @return the time graph control */ public TimeGraphControl getTimeGraphControl() { return fTimeGraphCtrl; } /** * Returns the tree control associated with this viewer. The tree is only * used for column handling of the name space and contains no tree items. * * @return the tree control * @since 2.3 */ public Tree getTree() { return fTree; } /** * Sets the columns for this time graph viewer's name space. * * @param columnNames * the column names * @since 2.3 */ public void setColumns(String[] columnNames) { fTimeGraphCtrl.setColumns(columnNames); } /** * Returns the time graph scale associated with this viewer. * * @return the time graph scale */ public TimeGraphScale getTimeGraphScale() { return fTimeScaleCtrl; } /** * Returns the composite containing all the controls that are time aligned, * i.e. TimeGraphScale, TimeGraphControl. * * @return the time based composite * @since 1.0 */ public Composite getTimeAlignedComposite() { return fTimeAlignedComposite; } /** * Return the x coordinate corresponding to a time * * @param time * the time * @return the x coordinate corresponding to the time */ public int getXForTime(long time) { return fTimeGraphCtrl.getXForTime(time); } /** * Return the time corresponding to an x coordinate * * @param x * the x coordinate * @return the time corresponding to the x coordinate */ public long getTimeAtX(int x) { return fTimeGraphCtrl.getTimeAtX(x); } /** * Get the selection provider * * @return the selection provider */ public ISelectionProvider getSelectionProvider() { return fTimeGraphCtrl; } /** * Wait for the cursor * * @param waitInd * Wait indefinitely? */ public void waitCursor(boolean waitInd) { fTimeGraphCtrl.waitCursor(waitInd); } /** * Get the horizontal scroll bar object * * @return The scroll bar */ public Slider getHorizontalBar() { return fHorizontalScrollBar; } /** * Get the vertical scroll bar object * * @return The scroll bar */ public Slider getVerticalBar() { return fVerticalScrollBar; } /** * Set the given index as the top one * * @param index * The index that will go to the top */ public void setTopIndex(int index) { fTimeGraphCtrl.setTopIndex(index); adjustVerticalScrollBar(); } /** * Retrieve the current top index * * @return The top index */ public int getTopIndex() { return fTimeGraphCtrl.getTopIndex(); } /** * Sets the auto-expand level to be used for new entries discovered when * calling {@link #setInput(Object)} or {@link #refresh()}. The value 0 * means that there is no auto-expand; 1 means that top-level entries are * expanded, but not their children; 2 means that top-level entries are * expanded, and their children, but not grand-children; and so on. * <p> * The value {@link #ALL_LEVELS} means that all subtrees should be expanded. * </p> * * @param level * non-negative level, or <code>ALL_LEVELS</code> to expand all * levels of the tree */ public void setAutoExpandLevel(int level) { fTimeGraphCtrl.setAutoExpandLevel(level); } /** * Returns the auto-expand level. * * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of * the tree are expanded automatically * @see #setAutoExpandLevel */ public int getAutoExpandLevel() { return fTimeGraphCtrl.getAutoExpandLevel(); } /** * Get the expanded state of an entry. * * @param entry * The entry * @return true if the entry is expanded, false if collapsed * @since 1.1 */ public boolean getExpandedState(ITimeGraphEntry entry) { return fTimeGraphCtrl.getExpandedState(entry); } /** * Set the expanded state of an entry * * @param entry * The entry to expand/collapse * @param expanded * True for expanded, false for collapsed */ public void setExpandedState(ITimeGraphEntry entry, boolean expanded) { fTimeGraphCtrl.setExpandedState(entry, expanded); adjustVerticalScrollBar(); } /** * Collapses all nodes of the viewer's tree, starting with the root. */ public void collapseAll() { fTimeGraphCtrl.collapseAll(); adjustVerticalScrollBar(); } /** * Expands all entries of the viewer's tree, starting with the root. */ public void expandAll() { fTimeGraphCtrl.expandAll(); adjustVerticalScrollBar(); } /** * Select an entry and reveal it * * @param entry * The entry to select * @since 2.0 */ public void selectAndReveal(@NonNull ITimeGraphEntry entry) { final ITimeGraphEntry parent = entry.getParent(); if (parent != null) { fTimeGraphCtrl.setExpandedState(parent, true); } fSelectedEntry = entry; fTimeGraphCtrl.selectItem(entry, false); adjustVerticalScrollBar(); } /** * Get the number of expanded (visible) time graph entries. This includes * leafs and does not include filtered-out entries. * * @return The number of expanded (visible) time graph entries */ public int getExpandedElementCount() { return fTimeGraphCtrl.getExpandedElementCount(); } /** * Get the expanded (visible) time graph entries. This includes leafs and * does not include filtered-out entries. * * @return The array of expanded (visible) time graph entries */ public ITimeGraphEntry[] getExpandedElements() { return fTimeGraphCtrl.getExpandedElements(); } /** * Add a tree listener * * @param listener * The listener to add */ public void addTreeListener(ITimeGraphTreeListener listener) { fTimeGraphCtrl.addTreeListener(listener); } /** * Remove a tree listener * * @param listener * The listener to remove */ public void removeTreeListener(ITimeGraphTreeListener listener) { fTimeGraphCtrl.removeTreeListener(listener); } /** * Get the reset scale action. * * @return The Action object */ public Action getResetScaleAction() { if (fResetScaleAction == null) { // resetScale fResetScaleAction = new Action() { @Override public void run() { resetStartFinishTime(); } }; fResetScaleAction.setText(Messages.TmfTimeGraphViewer_ResetScaleActionNameText); fResetScaleAction.setToolTipText(Messages.TmfTimeGraphViewer_ResetScaleActionToolTipText); fResetScaleAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_HOME_MENU)); } return fResetScaleAction; } /** * Get the show legend action. * * @return The Action object */ public Action getShowLegendAction() { if (fShowLegendAction == null) { // showLegend fShowLegendAction = new Action() { @Override public void run() { showLegend(); } }; fShowLegendAction.setText(Messages.TmfTimeGraphViewer_LegendActionNameText); fShowLegendAction.setToolTipText(Messages.TmfTimeGraphViewer_LegendActionToolTipText); fShowLegendAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_LEGEND)); } return fShowLegendAction; } /** * Get the the next event action. * * @return The action object */ public Action getNextEventAction() { if (fNextEventAction == null) { fNextEventAction = new Action() { @Override public void runWithEvent(Event event) { boolean extend = (event.stateMask & SWT.SHIFT) != 0; selectNextEvent(extend); } }; fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextStateChangeActionNameText); fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextStateChangeActionToolTipText); fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_STATE_CHANGE)); } return fNextEventAction; } /** * Get the previous event action. * * @return The Action object */ public Action getPreviousEventAction() { if (fPrevEventAction == null) { fPrevEventAction = new Action() { @Override public void runWithEvent(Event event) { boolean extend = (event.stateMask & SWT.SHIFT) != 0; selectPrevEvent(extend); } }; fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousStateChangeActionNameText); fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousStateChangeActionToolTipText); fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_STATE_CHANGE)); } return fPrevEventAction; } /** * Get the next item action. * * @return The Action object */ public Action getNextItemAction() { if (fNextItemAction == null) { fNextItemAction = new Action() { @Override public void run() { selectNextItem(); } }; fNextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText); fNextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText); fNextItemAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_ITEM)); } return fNextItemAction; } /** * Get the previous item action. * * @return The Action object */ public Action getPreviousItemAction() { if (fPreviousItemAction == null) { fPreviousItemAction = new Action() { @Override public void run() { selectPrevItem(); } }; fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText); fPreviousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText); fPreviousItemAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_ITEM)); } return fPreviousItemAction; } /** * Get the zoom in action * * @return The Action object */ public Action getZoomInAction() { if (fZoomInAction == null) { fZoomInAction = new Action() { @Override public void run() { zoomIn(); } }; fZoomInAction.setText(Messages.TmfTimeGraphViewer_ZoomInActionNameText); fZoomInAction.setToolTipText(Messages.TmfTimeGraphViewer_ZoomInActionToolTipText); fZoomInAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_IN_MENU)); } return fZoomInAction; } /** * Get the zoom out action * * @return The Action object */ public Action getZoomOutAction() { if (fZoomOutAction == null) { fZoomOutAction = new Action() { @Override public void run() { zoomOut(); } }; fZoomOutAction.setText(Messages.TmfTimeGraphViewer_ZoomOutActionNameText); fZoomOutAction.setToolTipText(Messages.TmfTimeGraphViewer_ZoomOutActionToolTipText); fZoomOutAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_OUT_MENU)); } return fZoomOutAction; } /** * Get the hide arrows action * * @param dialogSettings * The dialog settings section where the state should be stored, * or null * * @return The Action object */ public Action getHideArrowsAction(final IDialogSettings dialogSettings) { if (fHideArrowsAction == null) { fHideArrowsAction = new Action(Messages.TmfTimeGraphViewer_HideArrowsActionNameText, IAction.AS_CHECK_BOX) { @Override public void run() { boolean hideArrows = fHideArrowsAction.isChecked(); fTimeGraphCtrl.hideArrows(hideArrows); refresh(); if (dialogSettings != null) { dialogSettings.put(HIDE_ARROWS_KEY, hideArrows); } if (fFollowArrowFwdAction != null) { fFollowArrowFwdAction.setEnabled(!hideArrows); } if (fFollowArrowBwdAction != null) { fFollowArrowBwdAction.setEnabled(!hideArrows); } } }; fHideArrowsAction.setToolTipText(Messages.TmfTimeGraphViewer_HideArrowsActionToolTipText); fHideArrowsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_HIDE_ARROWS)); if (dialogSettings != null) { boolean hideArrows = dialogSettings.getBoolean(HIDE_ARROWS_KEY); fTimeGraphCtrl.hideArrows(hideArrows); fHideArrowsAction.setChecked(hideArrows); if (fFollowArrowFwdAction != null) { fFollowArrowFwdAction.setEnabled(!hideArrows); } if (fFollowArrowBwdAction != null) { fFollowArrowBwdAction.setEnabled(!hideArrows); } } } return fHideArrowsAction; } /** * Get the follow arrow forward action. * * @return The Action object */ public Action getFollowArrowFwdAction() { if (fFollowArrowFwdAction == null) { fFollowArrowFwdAction = new Action() { @Override public void runWithEvent(Event event) { boolean extend = (event.stateMask & SWT.SHIFT) != 0; fTimeGraphCtrl.followArrowFwd(extend); adjustVerticalScrollBar(); } }; fFollowArrowFwdAction.setText(Messages.TmfTimeGraphViewer_FollowArrowForwardActionNameText); fFollowArrowFwdAction.setToolTipText(Messages.TmfTimeGraphViewer_FollowArrowForwardActionToolTipText); fFollowArrowFwdAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FOLLOW_ARROW_FORWARD)); if (fHideArrowsAction != null) { fFollowArrowFwdAction.setEnabled(!fHideArrowsAction.isChecked()); } } return fFollowArrowFwdAction; } /** * Get the follow arrow backward action. * * @return The Action object */ public Action getFollowArrowBwdAction() { if (fFollowArrowBwdAction == null) { fFollowArrowBwdAction = new Action() { @Override public void runWithEvent(Event event) { boolean extend = (event.stateMask & SWT.SHIFT) != 0; fTimeGraphCtrl.followArrowBwd(extend); adjustVerticalScrollBar(); } }; fFollowArrowBwdAction.setText(Messages.TmfTimeGraphViewer_FollowArrowBackwardActionNameText); fFollowArrowBwdAction.setToolTipText(Messages.TmfTimeGraphViewer_FollowArrowBackwardActionToolTipText); fFollowArrowBwdAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FOLLOW_ARROW_BACKWARD)); if (fHideArrowsAction != null) { fFollowArrowBwdAction.setEnabled(!fHideArrowsAction.isChecked()); } } return fFollowArrowBwdAction; } /** * Get the show filter dialog action. * * @return The Action object * @since 1.2 */ public ShowFilterDialogAction getShowFilterDialogAction() { if (fShowFilterDialogAction == null) { fShowFilterDialogAction = new ShowFilterDialogAction(this); } return fShowFilterDialogAction; } /** * Get the toggle bookmark action. * * @return The Action object * @since 2.0 */ public Action getToggleBookmarkAction() { if (fToggleBookmarkAction == null) { fToggleBookmarkAction = new Action() { @Override public void runWithEvent(Event event) { IMarkerEvent selectedBookmark = getBookmarkAtSelection(); if (selectedBookmark == null) { final long time = Math.min(fSelectionBegin, fSelectionEnd); final long duration = Math.max(fSelectionBegin, fSelectionEnd) - time; final AddBookmarkDialog dialog = new AddBookmarkDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), null); if (dialog.open() == Window.OK) { final String label = dialog.getValue(); final RGBA rgba = dialog.getColorValue(); IMarkerEvent bookmark = new MarkerEvent(null, time, duration, IMarkerEvent.BOOKMARKS, rgba, label, true); fBookmarks.add(bookmark); updateMarkerList(); updateMarkerActions(); getControl().redraw(); fireBookmarkAdded(bookmark); } } else { fBookmarks.remove(selectedBookmark); updateMarkerList(); updateMarkerActions(); getControl().redraw(); fireBookmarkRemoved(selectedBookmark); } } }; fToggleBookmarkAction.setText(Messages.TmfTimeGraphViewer_BookmarkActionAddText); fToggleBookmarkAction.setToolTipText(Messages.TmfTimeGraphViewer_BookmarkActionAddText); fToggleBookmarkAction.setImageDescriptor(ADD_BOOKMARK); } return fToggleBookmarkAction; } /** * Get the next marker action. * * @return The Action object * @since 2.0 */ public Action getNextMarkerAction() { if (fNextMarkerAction == null) { fNextMarkerAction = new Action(Messages.TmfTimeGraphViewer_NextMarkerActionText, IAction.AS_DROP_DOWN_MENU) { @Override public void runWithEvent(Event event) { boolean extend = (event.stateMask & SWT.SHIFT) != 0; if (extend) { extendToNextMarker(); } else { selectNextMarker(); } } }; fNextMarkerAction.setToolTipText(Messages.TmfTimeGraphViewer_NextMarkerActionText); fNextMarkerAction.setImageDescriptor(NEXT_BOOKMARK); fNextMarkerAction.setMenuCreator(new IMenuCreator () { Menu menu = null; @Override public void dispose() { if (menu != null) { menu.dispose(); menu = null; } } @Override public Menu getMenu(Control parent) { if (menu != null) { menu.dispose(); } menu = new Menu(parent); for (String category : fMarkerCategories) { final Action action = new Action(category, IAction.AS_CHECK_BOX) { @Override public void runWithEvent(Event event) { if (isChecked()) { fSkippedMarkerCategories.remove(getText()); } else { fSkippedMarkerCategories.add(getText()); } updateMarkerActions(); } }; action.setEnabled(!fHiddenMarkerCategories.contains(category)); action.setChecked(action.isEnabled() && !fSkippedMarkerCategories.contains(category)); new ActionContributionItem(action).fill(menu, -1); } return menu; } @Override public Menu getMenu(Menu parent) { return null; } }); } return fNextMarkerAction; } /** * Get the previous marker action. * * @return The Action object * @since 2.0 */ public Action getPreviousMarkerAction() { if (fPreviousMarkerAction == null) { fPreviousMarkerAction = new Action() { @Override public void runWithEvent(Event event) { boolean extend = (event.stateMask & SWT.SHIFT) != 0; if (extend) { extendToPrevMarker(); } else { selectPrevMarker(); } } }; fPreviousMarkerAction.setText(Messages.TmfTimeGraphViewer_PreviousMarkerActionText); fPreviousMarkerAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousMarkerActionText); fPreviousMarkerAction.setImageDescriptor(PREVIOUS_BOOKMARK); } return fPreviousMarkerAction; } /** * Get the show markers menu. * * @return The menu manager object * @since 2.0 */ public MenuManager getMarkersMenu() { if (fMarkersMenu == null) { fMarkersMenu = new MenuManager(Messages.TmfTimeGraphViewer_ShowMarkersMenuText); fMarkersMenu.setRemoveAllWhenShown(true); fMarkersMenu.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { for (String category : fMarkerCategories) { final Action action = new Action(category, IAction.AS_CHECK_BOX) { @Override public void runWithEvent(Event event) { setMarkerCategoryVisible(getText(), isChecked()); } }; action.setChecked(!fHiddenMarkerCategories.contains(category)); manager.add(action); } } }); } return fMarkersMenu; } /** * Select the next marker that begins at or after the current selection * begin time. Markers that begin at the same time are ordered by end time. */ private void selectNextMarker() { List<IMarkerEvent> markers = getTimeGraphControl().getMarkers(); if (markers == null) { return; } for (IMarkerEvent marker : markers) { final long time = Math.min(fSelectionBegin, fSelectionEnd); final long duration = Math.max(fSelectionBegin, fSelectionEnd) - time; if ((marker.getTime() > time || (marker.getTime() == time && marker.getDuration() > duration)) && !fSkippedMarkerCategories.contains(marker.getCategory())) { setSelectionRangeNotify(marker.getTime(), marker.getTime() + marker.getDuration(), false); ensureVisible(marker.getTime()); notifyRangeListeners(); fTimeGraphCtrl.updateStatusLine(); return; } } } /** * Select the previous marker that begins at or before the current selection * begin time. Markers that begin at the same time are ordered by end time. */ private void selectPrevMarker() { List<IMarkerEvent> markers = getTimeGraphControl().getMarkers(); if (markers == null) { return; } final long time = Math.min(fSelectionBegin, fSelectionEnd); final long duration = Math.max(fSelectionBegin, fSelectionEnd) - time; for (int i = markers.size() - 1; i >= 0; i--) { IMarkerEvent marker = markers.get(i); if ((marker.getTime() < time || (marker.getTime() == time && marker.getDuration() < duration)) && !fSkippedMarkerCategories.contains(marker.getCategory())) { setSelectionRangeNotify(marker.getTime(), marker.getTime() + marker.getDuration(), false); ensureVisible(marker.getTime()); notifyRangeListeners(); fTimeGraphCtrl.updateStatusLine(); return; } } } /** * Extend the selection to the closest next marker end time. */ private void extendToNextMarker() { List<IMarkerEvent> markers = getTimeGraphControl().getMarkers(); if (markers == null) { return; } IMarkerEvent nextMarker = null; for (IMarkerEvent marker : markers) { if (marker.getTime() + marker.getDuration() > fSelectionEnd && !fSkippedMarkerCategories.contains(marker.getCategory()) && (nextMarker == null || marker.getTime() + marker.getDuration() < nextMarker.getTime() + nextMarker.getDuration())) { nextMarker = marker; } } if (nextMarker != null) { setSelectionRangeNotify(fSelectionBegin, nextMarker.getTime() + nextMarker.getDuration(), true); fTimeGraphCtrl.updateStatusLine(); } } /** * Extend the selection to the closest previous marker start time. */ private void extendToPrevMarker() { List<IMarkerEvent> markers = getTimeGraphControl().getMarkers(); if (markers == null) { return; } for (int i = markers.size() - 1; i >= 0; i--) { IMarkerEvent marker = markers.get(i); if (marker.getTime() < fSelectionEnd && !fSkippedMarkerCategories.contains(marker.getCategory())) { setSelectionRangeNotify(fSelectionBegin, marker.getTime(), true); fTimeGraphCtrl.updateStatusLine(); return; } } } private IMarkerEvent getBookmarkAtSelection() { final long time = Math.min(fSelectionBegin, fSelectionEnd); final long duration = Math.max(fSelectionBegin, fSelectionEnd) - time; for (IMarkerEvent bookmark : fBookmarks) { if (bookmark.getTime() == time && bookmark.getDuration() == duration) { return bookmark; } } return null; } private void updateMarkerActions() { boolean enabled = fTime0Bound != SWT.DEFAULT || fTime1Bound != SWT.DEFAULT; if (fToggleBookmarkAction != null) { if (getBookmarkAtSelection() != null) { fToggleBookmarkAction.setText(Messages.TmfTimeGraphViewer_BookmarkActionRemoveText); fToggleBookmarkAction.setToolTipText(Messages.TmfTimeGraphViewer_BookmarkActionRemoveText); fToggleBookmarkAction.setImageDescriptor(REMOVE_BOOKMARK); } else { fToggleBookmarkAction.setText(Messages.TmfTimeGraphViewer_BookmarkActionAddText); fToggleBookmarkAction.setToolTipText(Messages.TmfTimeGraphViewer_BookmarkActionAddText); fToggleBookmarkAction.setImageDescriptor(ADD_BOOKMARK); } fToggleBookmarkAction.setEnabled(enabled); } List<IMarkerEvent> markers = getTimeGraphControl().getMarkers(); if (markers == null) { markers = Collections.emptyList(); } if (fPreviousMarkerAction != null) { fPreviousMarkerAction.setEnabled(enabled && !markers.isEmpty()); } if (fNextMarkerAction != null) { fNextMarkerAction.setEnabled(enabled && !markers.isEmpty()); } } private void updateMarkerList() { List<IMarkerEvent> markers = new ArrayList<>(); for (IMarkerEvent marker : fMarkers) { if (!fHiddenMarkerCategories.contains(marker.getCategory())) { markers.add(marker); } } if (!fHiddenMarkerCategories.contains(IMarkerEvent.BOOKMARKS)) { markers.addAll(fBookmarks); } Collections.sort(markers, new MarkerComparator()); fTimeGraphCtrl.setMarkers(markers); fMarkerAxisCtrl.setMarkers(markers); } private void adjustHorizontalScrollBar() { long time0 = getTime0(); long time1 = getTime1(); long timeMin = getMinTime(); long timeMax = getMaxTime(); long delta = timeMax - timeMin; int timePos = 0; int thumb = H_SCROLLBAR_MAX; if (delta != 0) { // Thumb size (page size) thumb = Math.max(1, (int) (H_SCROLLBAR_MAX * ((double) (time1 - time0) / delta))); // At the beginning of visible window timePos = (int) (H_SCROLLBAR_MAX * ((double) (time0 - timeMin) / delta)); } fHorizontalScrollBar.setValues(timePos, 0, H_SCROLLBAR_MAX, thumb, Math.max(1, thumb / 2), Math.max(2, thumb)); } private void adjustVerticalScrollBar() { int topIndex = fTimeGraphCtrl.getTopIndex(); int countPerPage = fTimeGraphCtrl.countPerPage(); int expandedElementCount = fTimeGraphCtrl.getExpandedElementCount(); if (topIndex + countPerPage > expandedElementCount) { fTimeGraphCtrl.setTopIndex(Math.max(0, expandedElementCount - countPerPage)); } int selection = fTimeGraphCtrl.getTopIndex(); int min = 0; int max = Math.max(1, expandedElementCount - 1); int thumb = Math.min(max, Math.max(1, countPerPage - 1)); int increment = 1; int pageIncrement = Math.max(1, countPerPage); fVerticalScrollBar.setValues(selection, min, max, thumb, increment, pageIncrement); } /** * @param listener * a {@link MenuDetectListener} * @see org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl#addTimeGraphEntryMenuListener(org.eclipse.swt.events.MenuDetectListener) */ public void addTimeGraphEntryMenuListener(MenuDetectListener listener) { fTimeGraphCtrl.addTimeGraphEntryMenuListener(listener); } /** * @param listener * a {@link MenuDetectListener} * @see org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl#removeTimeGraphEntryMenuListener(org.eclipse.swt.events.MenuDetectListener) */ public void removeTimeGraphEntryMenuListener(MenuDetectListener listener) { fTimeGraphCtrl.removeTimeGraphEntryMenuListener(listener); } /** * @param listener * a {@link MenuDetectListener} * @see org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl#addTimeEventMenuListener(org.eclipse.swt.events.MenuDetectListener) */ public void addTimeEventMenuListener(MenuDetectListener listener) { fTimeGraphCtrl.addTimeEventMenuListener(listener); } /** * @param listener * a {@link MenuDetectListener} * @see org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl#removeTimeEventMenuListener(org.eclipse.swt.events.MenuDetectListener) */ public void removeTimeEventMenuListener(MenuDetectListener listener) { fTimeGraphCtrl.removeTimeEventMenuListener(listener); } /** * @param filter * The filter object to be attached to the view */ public void addFilter(@NonNull ViewerFilter filter) { fTimeGraphCtrl.addFilter(filter); refresh(); } /** * @param filter * The filter object to be attached to the view */ public void removeFilter(@NonNull ViewerFilter filter) { fTimeGraphCtrl.removeFilter(filter); refresh(); } /** * Returns this viewer's filters. * * @return an array of viewer filters * @since 1.2 */ public @NonNull ViewerFilter[] getFilters() { return fTimeGraphCtrl.getFilters(); } /** * Sets the filters, replacing any previous filters, and triggers * refiltering of the elements. * * @param filters * an array of viewer filters, or null * @since 1.2 */ public void setFilters(@NonNull ViewerFilter[] filters) { fTimeGraphCtrl.setFilters(filters); refresh(); } /** * Return the time alignment information * * @return the time alignment information * * @see ITmfTimeAligned * * @since 1.0 */ public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() { return fTimeGraphCtrl.getTimeViewAlignmentInfo(); } /** * Return the available width for the time-axis. * * @see ITmfTimeAligned * * @param requestedOffset * the requested offset * @return the available width for the time-axis * * @since 1.0 */ public int getAvailableWidth(int requestedOffset) { int totalWidth = fTimeAlignedComposite.getSize().x; return Math.min(totalWidth, Math.max(0, totalWidth - requestedOffset)); } /** * Perform the alignment operation. * * @param offset * the alignment offset * @param width * the alignment width * * @see ITmfTimeAligned * * @since 1.0 */ public void performAlign(int offset, int width) { fTimeGraphCtrl.performAlign(offset); int alignmentWidth = width; int size = fTimeAlignedComposite.getSize().x; GridLayout layout = (GridLayout) fTimeAlignedComposite.getLayout(); int marginSize = size - alignmentWidth - offset; layout.marginRight = Math.max(0, marginSize); fTimeAlignedComposite.layout(); } }