/*******************************************************************************
- * Copyright (c) 2012, 2015 Ericsson, École Polytechnique de Montréal
+ * Copyright (c) 2012, 2016 Ericsson, École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
package org.eclipse.tracecompass.tmf.ui.views.timegraph;
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
-
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MenuDetectEvent;
+import org.eclipse.swt.events.MenuDetectListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGBA;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.tracecompass.common.core.NonNullUtils;
+import org.eclipse.tracecompass.common.core.log.TraceCompassLog;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.core.resources.ITmfMarker;
+import org.eclipse.tracecompass.tmf.core.signal.TmfMarkerEventSourceUpdatedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
-import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceAdapterManager;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.eclipse.tracecompass.tmf.ui.TmfUiRefreshHandler;
import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphBookmarkListener;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphContentProvider;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphBookmarkEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphCombo;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphContentProvider;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
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.IMarkerEventSource;
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.model.TimeGraphEntry;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
/**
* An abstract view all time graph views can inherit
* This view contains either a time graph viewer, or a time graph combo which is
* divided between a tree viewer on the left and a time graph viewer on the right.
*/
-public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeAligned {
+public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeAligned, IResourceChangeListener {
/** Constant indicating that all levels of the time graph should be expanded */
protected static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
+ private static final Pattern RGBA_PATTERN = Pattern.compile("RGBA \\{(\\d+), (\\d+), (\\d+), (\\d+)\\}"); //$NON-NLS-1$
+
+ private static final Logger LOGGER = TraceCompassLog.getLogger(AbstractTimeGraphView.class);
+ private static final String LOG_STRING_WITH_PARAM = "[TimeGraphView:%s] viewId=%s, %s"; //$NON-NLS-1$
+ private static final String LOG_STRING = "[TimeGraphView:%s] viewId=%s"; //$NON-NLS-1$
+
/**
* Redraw state enum
*/
/** The timegraph wrapper */
private ITimeGraphWrapper fTimeGraphWrapper;
+ private AtomicInteger fDirty = new AtomicInteger();
+
+ private final Object fZoomThreadResultLock = new Object();
+
/** The selected trace */
private ITmfTrace fTrace;
+ /** The selected trace editor file*/
+ private IFile fEditorFile;
+
/** The timegraph entry list */
private List<TimeGraphEntry> fEntryList;
/** The trace to entry list hash map */
private final Map<ITmfTrace, List<TimeGraphEntry>> fEntryListMap = new HashMap<>();
+ /** The trace to filters hash map */
+ private final Map<ITmfTrace, @NonNull ViewerFilter[]> fFiltersMap = new HashMap<>();
+
+ /** The trace to view context hash map */
+ private final Map<ITmfTrace, ViewContext> fViewContext = new HashMap<>();
+
+ /** The trace to marker event sources hash map */
+ private final Map<ITmfTrace, List<IMarkerEventSource>> fMarkerEventSourcesMap = new HashMap<>();
+
/** The trace to build thread hash map */
- private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
+ private final Map<ITmfTrace, Job> fBuildJobMap = new HashMap<>();
/** The start time */
- private long fStartTime;
+ private long fStartTime = SWT.DEFAULT;
/** The end time */
- private long fEndTime;
+ private long fEndTime = SWT.DEFAULT;
/** The display width */
private final int fDisplayWidth;
/** The tree column label array, or null if combo is not used */
private String[] fColumns;
+ private Comparator<ITimeGraphEntry>[] fColumnComparators;
+
/** The tree label provider, or null if combo is not used */
private TreeLabelProvider fLabelProvider = null;
/** The pack done flag */
private boolean fPackDone = false;
+ /** The filter content provider, or null if filter is not used */
+ private ITreeContentProvider fFilterContentProvider;
+
/** The filter label provider, or null if filter is not used */
private TreeLabelProvider fFilterLabelProvider;
private int fAutoExpandLevel = ALL_LEVELS;
+ /** The default column index for sorting */
+ private int fInitialSortColumn = 0;
+
+ /** The default column index for sorting */
+ private int fCurrentSortColumn = 0;
+
+ /** The current sort direction */
+ private int fSortDirection = SWT.DOWN;
+
+ /** Flag to indicate to reveal selection */
+ private volatile boolean fIsRevealSelection = false;
+
+ /**
+ * Menu Manager for context-sensitive menu for time graph entries.
+ * This will be used on the tree viewer in case of the time graph combo
+ * or the on the namespace in case of a single time graph viewer.
+ */
+ private final @NonNull MenuManager fEntryMenuManager = new MenuManager();
+
+ /** Time Graph View part listener */
+ private TimeGraphPartListener fPartListener;
+
+ /** Action for the find command. There is only one for all Time Graph views */
+ private static final ShowFindDialogAction FIND_ACTION = new ShowFindDialogAction();
+
+ /** The find action handler */
+ private ActionHandler fFindActionHandler;
+
+ /** The find handler activation */
+ private IHandlerActivation fFindHandlerActivation;
+
+ /** The find target to use */
+ private final FindTarget fFindTarget;
+
// ------------------------------------------------------------------------
// Classes
// ------------------------------------------------------------------------
private interface ITimeGraphWrapper {
- void setTimeGraphProvider(TimeGraphPresentationProvider fPresentation);
+ void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider);
+
+ void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider);
TimeGraphViewer getTimeGraphViewer();
- void addSelectionListener(ITimeGraphSelectionListener iTimeGraphSelectionListener);
+ void addSelectionListener(ITimeGraphSelectionListener listener);
ISelectionProvider getSelectionProvider();
Object getInput();
+ void setFilters(@NonNull ViewerFilter[] filters);
+
+ @NonNull ViewerFilter[] getFilters();
+
void redraw();
void update();
void setAutoExpandLevel(int level);
+ boolean getExpandedState(ITimeGraphEntry entry);
+
+ void setExpandedState(ITimeGraphEntry entry, boolean expanded);
+
+ void setFilterColumns(String[] columnNames);
+
+ void setFilterContentProvider(ITreeContentProvider contentProvider);
+
+ void setFilterLabelProvider(ITableLabelProvider labelProvider);
+
+ IAction getShowFilterDialogAction();
+
void performAlign(int offset, int width);
TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo();
int getAvailableWidth(int requestedOffset);
+
+ ITimeGraphEntry getSelection();
+
+ void setSelection(ITimeGraphEntry selection);
+
+ void selectAndReveal(@NonNull ITimeGraphEntry selection);
+
}
private class TimeGraphViewerWrapper implements ITimeGraphWrapper {
}
@Override
- public void setTimeGraphProvider(TimeGraphPresentationProvider timeGraphProvider) {
- viewer.setTimeGraphProvider(timeGraphProvider);
+ public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider) {
+ viewer.setTimeGraphContentProvider(timeGraphContentProvider);
+ }
+
+ @Override
+ public void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider) {
+ viewer.setTimeGraphProvider(timeGraphPresentationProvider);
}
@Override
return viewer.getInput();
}
+ @Override
+ public void setFilterColumns(String[] columnNames) {
+ viewer.setFilterColumns(columnNames);
+ }
+
+ @Override
+ public void setFilterContentProvider(ITreeContentProvider contentProvider) {
+ viewer.setFilterContentProvider(contentProvider);
+ }
+
+ @Override
+ public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
+ viewer.setFilterLabelProvider(labelProvider);
+ }
+
+ @Override
+ public void setFilters(@NonNull ViewerFilter[] filters) {
+ viewer.setFilters(filters);
+ }
+
+ @Override
+ public @NonNull ViewerFilter[] getFilters() {
+ return viewer.getFilters();
+ }
+
+ @Override
+ public IAction getShowFilterDialogAction() {
+ return viewer.getShowFilterDialogAction();
+ }
+
@Override
public void refresh() {
viewer.refresh();
viewer.setAutoExpandLevel(level);
}
+ @Override
+ public boolean getExpandedState(ITimeGraphEntry entry) {
+ return viewer.getExpandedState(entry);
+ }
+
+ @Override
+ public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
+ viewer.setExpandedState(entry, expanded);
+ }
+
@Override
public void performAlign(int offset, int width) {
viewer.performAlign(offset, width);
public int getAvailableWidth(int requestedOffset) {
return viewer.getAvailableWidth(requestedOffset);
}
+
+ @Override
+ public ITimeGraphEntry getSelection() {
+ return viewer.getSelection();
+ }
+
+ @Override
+ public void setSelection(ITimeGraphEntry selection) {
+ viewer.setSelection(selection);
+ }
+
+ @Override
+ public void selectAndReveal(@NonNull ITimeGraphEntry selection) {
+ viewer.selectAndReveal(selection);
+ }
}
private class TimeGraphComboWrapper implements ITimeGraphWrapper {
}
@Override
- public void setTimeGraphProvider(TimeGraphPresentationProvider timeGraphProvider) {
- combo.setTimeGraphProvider(timeGraphProvider);
+ public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider) {
+ combo.setTimeGraphContentProvider(timeGraphContentProvider);
+ }
+
+ @Override
+ public void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider) {
+ combo.setTimeGraphProvider(timeGraphPresentationProvider);
}
@Override
return combo.getInput();
}
+ @Override
+ public void setFilterColumns(String[] columnNames) {
+ combo.setFilterColumns(columnNames);
+ }
+
+ @Override
+ public void setFilterContentProvider(ITreeContentProvider contentProvider) {
+ combo.setFilterContentProvider(contentProvider);
+ }
+
+ @Override
+ public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
+ combo.setFilterLabelProvider(labelProvider);
+ }
+
+ @Override
+ public void setFilters(@NonNull ViewerFilter[] filters) {
+ combo.setFilters(filters);
+ }
+
+ @Override
+ public @NonNull ViewerFilter[] getFilters() {
+ return combo.getFilters();
+ }
+
+ @Override
+ public IAction getShowFilterDialogAction() {
+ return combo.getShowFilterDialogAction();
+ }
+
@Override
public void refresh() {
combo.refresh();
combo.setAutoExpandLevel(level);
}
+ @Override
+ public boolean getExpandedState(ITimeGraphEntry entry) {
+ return combo.getExpandedState(entry);
+ }
+
+ @Override
+ public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
+ combo.setExpandedState(entry, expanded);
+ }
+
TimeGraphCombo getTimeGraphCombo() {
return combo;
}
return combo.getTreeViewer();
}
- IAction getShowFilterAction() {
- return combo.getShowFilterAction();
- }
-
@Override
public void performAlign(int offset, int width) {
combo.performAlign(offset, width);
public int getAvailableWidth(int requestedOffset) {
return combo.getAvailableWidth(requestedOffset);
}
+
+ @Override
+ public ITimeGraphEntry getSelection() {
+ return combo.getTimeGraphViewer().getSelection();
+ }
+
+ @Override
+ public void setSelection(ITimeGraphEntry selection) {
+ combo.setSelection(selection);
+ }
+
+ @Override
+ public void selectAndReveal(@NonNull ITimeGraphEntry selection) {
+ combo.selectAndReveal(selection);
+ }
}
/**
}
- private class BuildThread extends Thread {
+ // TODO: This can implement ICoreRunnable once support for Eclipse 4.5. is not necessary anymore.
+ private class BuildRunnable {
private final @NonNull ITmfTrace fBuildTrace;
private final @NonNull ITmfTrace fParentTrace;
- private final @NonNull IProgressMonitor fMonitor;
- public BuildThread(final @NonNull ITmfTrace trace, final @NonNull ITmfTrace parentTrace, final String name) {
- super(name + " build"); //$NON-NLS-1$
+ public BuildRunnable(final @NonNull ITmfTrace trace, final @NonNull ITmfTrace parentTrace) {
fBuildTrace = trace;
fParentTrace = parentTrace;
- fMonitor = new NullProgressMonitor();
}
- @Override
- public void run() {
- buildEventList(fBuildTrace, fParentTrace, fMonitor);
- synchronized (fBuildThreadMap) {
- fBuildThreadMap.remove(fBuildTrace);
+ public void run(IProgressMonitor monitor) {
+ LOGGER.info(() -> getLogMessage("BuildThreadStart", "trace=" + fBuildTrace.getName())); //$NON-NLS-1$ //$NON-NLS-2$
+
+ buildEntryList(fBuildTrace, fParentTrace, NonNullUtils.checkNotNull(monitor));
+ synchronized (fBuildJobMap) {
+ fBuildJobMap.remove(fBuildTrace);
}
- }
- public void cancel() {
- fMonitor.setCanceled(true);
+ LOGGER.info(() -> getLogMessage("BuildThreadEnd", null)); //$NON-NLS-1$
}
}
- private class ZoomThread extends Thread {
- private final @NonNull List<TimeGraphEntry> fZoomEntryList;
+ /**
+ * Zoom thread
+ * @since 1.1
+ */
+ protected abstract class ZoomThread extends Thread {
private final long fZoomStartTime;
private final long fZoomEndTime;
private final long fResolution;
private final @NonNull IProgressMonitor fMonitor;
- public ZoomThread(@NonNull List<TimeGraphEntry> entryList, long startTime, long endTime, String name) {
- super(name + " zoom"); //$NON-NLS-1$
- fZoomEntryList = entryList;
+ /**
+ * Constructor
+ *
+ * @param startTime
+ * the start time
+ * @param endTime
+ * the end time
+ * @param resolution
+ * the resolution
+ */
+ public ZoomThread(long startTime, long endTime, long resolution) {
+ super(AbstractTimeGraphView.this.getName() + " zoom"); //$NON-NLS-1$
fZoomStartTime = startTime;
fZoomEndTime = endTime;
- fResolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
+ fResolution = resolution;
fMonitor = new NullProgressMonitor();
}
+ /**
+ * @return the zoom start time
+ */
+ public long getZoomStartTime() {
+ return fZoomStartTime;
+ }
+
+ /**
+ * @return the zoom end time
+ */
+ public long getZoomEndTime() {
+ return fZoomEndTime;
+ }
+
+ /**
+ * @return the resolution
+ */
+ public long getResolution() {
+ return fResolution;
+ }
+
+ /**
+ * @return the monitor
+ */
+ public @NonNull IProgressMonitor getMonitor() {
+ return fMonitor;
+ }
+
+ /**
+ * Cancel the zoom thread
+ */
+ public void cancel() {
+ fMonitor.setCanceled(true);
+ }
+
@Override
- public void run() {
+ public final void run() {
+ LOGGER.info(() -> getLogMessage("ZoomThreadStart", "start=" + fZoomStartTime + ", end=" + fZoomEndTime)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ doRun();
+ fDirty.decrementAndGet();
+
+ LOGGER.info(() -> getLogMessage("ZoomThreadEnd", null)); //$NON-NLS-1$
+ }
+
+ /**
+ * Applies the results of the ZoomThread calculations.
+ *
+ * Note: This method makes sure that only the results of the last
+ * created ZoomThread are applied.
+ *
+ * @param runnable
+ * the code to run in order to apply the results
+ * @since 2.0
+ */
+ protected void applyResults(Runnable runnable) {
+ synchronized (fZoomThreadResultLock) {
+ if (this == fZoomThread) {
+ runnable.run();
+ }
+ }
+ }
+
+ /**
+ * Run the zoom operation.
+ * @since 2.0
+ */
+ public abstract void doRun();
+ }
+
+ private class ZoomThreadByEntry extends ZoomThread {
+ private final @NonNull List<TimeGraphEntry> fZoomEntryList;
+
+ public ZoomThreadByEntry(@NonNull List<TimeGraphEntry> entryList, long startTime, long endTime, long resolution) {
+ super(startTime, endTime, resolution);
+ fZoomEntryList = entryList;
+ }
+
+ @Override
+ public void doRun() {
+ LOGGER.config(() -> getLogMessage("ZoomThreadGettingStates", null)); //$NON-NLS-1$
+
for (TimeGraphEntry entry : fZoomEntryList) {
- if (fMonitor.isCanceled()) {
+ if (getMonitor().isCanceled()) {
+ LOGGER.info(() -> getLogMessage("ZoomThreadCanceled", null)); //$NON-NLS-1$
return;
}
if (entry == null) {
break;
}
- zoom(entry, fMonitor);
+ zoom(entry, getMonitor());
}
/* Refresh the arrows when zooming */
- List<ILinkEvent> events = getLinkList(fZoomStartTime, fZoomEndTime, fResolution, fMonitor);
- if (events != null) {
- fTimeGraphWrapper.getTimeGraphViewer().setLinks(events);
+ LOGGER.config(() -> getLogMessage("ZoomThreadGettingLinks", null)); //$NON-NLS-1$
+ List<ILinkEvent> events = getLinkList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
+
+ /* Refresh the view-specific markers when zooming */
+ LOGGER.config(() -> getLogMessage("ZoomThreadGettingMarkers", null)); //$NON-NLS-1$
+ List<IMarkerEvent> markers = new ArrayList<>(getViewMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
+ /* Refresh the trace-specific markers when zooming */
+ markers.addAll(getTraceMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
+ applyResults(() -> {
+ if (events != null) {
+ fTimeGraphWrapper.getTimeGraphViewer().setLinks(events);
+ }
+ fTimeGraphWrapper.getTimeGraphViewer().setMarkerCategories(getMarkerCategories());
+ fTimeGraphWrapper.getTimeGraphViewer().setMarkers(markers);
redraw();
- }
+ });
}
private void zoom(@NonNull TimeGraphEntry entry, @NonNull IProgressMonitor monitor) {
- if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {
- entry.setZoomedEventList(null);
+ if (getZoomStartTime() <= fStartTime && getZoomEndTime() >= fEndTime) {
+ applyResults(() -> {
+ entry.setZoomedEventList(null);
+ });
} else {
- List<ITimeEvent> zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, fResolution, monitor);
+ List<ITimeEvent> zoomedEventList = getEventList(entry, getZoomStartTime(), getZoomEndTime(), getResolution(), monitor);
if (zoomedEventList != null) {
- entry.setZoomedEventList(zoomedEventList);
+ applyResults(() -> {
+ entry.setZoomedEventList(zoomedEventList);
+ });
}
}
redraw();
- for (ITimeGraphEntry child : entry.getChildren()) {
- if (fMonitor.isCanceled()) {
+ for (TimeGraphEntry child : entry.getChildren()) {
+ if (monitor.isCanceled()) {
return;
}
- if (child instanceof TimeGraphEntry) {
- zoom((TimeGraphEntry) child, monitor);
- }
+ zoom(child, monitor);
}
}
- public void cancel() {
- fMonitor.setCanceled(true);
- }
}
// ------------------------------------------------------------------------
super(id);
fPresentation = pres;
fDisplayWidth = Display.getDefault().getBounds().width;
+ fFindTarget = new FindTarget();
}
// ------------------------------------------------------------------------
/**
* Sets the tree column labels.
+ * <p>
* This should be called from the constructor.
*
* @param columns
* The array of tree column labels
*/
protected void setTreeColumns(final String[] columns) {
+ setTreeColumns(columns, null, 0);
+ }
+
+ /**
+ * Sets the tree column labels.
+ * <p>
+ * This should be called from the constructor.
+ *
+ * @param columns
+ * The array of tree column labels
+ * @param comparators
+ * An array of column comparators for sorting of columns when
+ * clicking on column header
+ * @param initialSortColumn
+ * Index of column to sort initially
+ * @since 2.0
+ */
+ protected void setTreeColumns(final String[] columns, final Comparator<ITimeGraphEntry>[] comparators, int initialSortColumn) {
+ checkPartNotCreated();
fColumns = columns;
+ fColumnComparators = comparators;
+ fInitialSortColumn = initialSortColumn;
}
/**
* Sets the tree label provider.
+ * <p>
* This should be called from the constructor.
*
* @param tlp
* The tree label provider
*/
protected void setTreeLabelProvider(final TreeLabelProvider tlp) {
+ checkPartNotCreated();
fLabelProvider = tlp;
}
/**
- * Sets the time graph content provider. This should be called from the
- * constructor.
+ * Sets the time graph content provider.
+ * <p>
+ * This should be called from the constructor.
*
* @param tgcp
* The time graph content provider
* @since 1.0
*/
protected void setTimeGraphContentProvider(final @NonNull ITimeGraphContentProvider tgcp) {
+ checkPartNotCreated();
fTimeGraphContentProvider = tgcp;
}
/**
* Sets the relative weight of each part of the time graph combo.
+ * <p>
* This should be called from the constructor.
*
* @param weights
* The array (length 2) of relative weights of each part of the combo
*/
protected void setWeight(final int[] weights) {
+ checkPartNotCreated();
fWeight = weights;
}
/**
* Sets the filter column labels.
+ * <p>
* This should be called from the constructor.
*
* @param filterColumns
* The array of filter column labels
*/
protected void setFilterColumns(final String[] filterColumns) {
+ checkPartNotCreated();
fFilterColumns = filterColumns;
}
+ /**
+ * Sets the filter content provider.
+ * <p>
+ * This should be called from the constructor.
+ *
+ * @param contentProvider
+ * The filter content provider
+ * @since 1.2
+ */
+ protected void setFilterContentProvider(final ITreeContentProvider contentProvider) {
+ checkPartNotCreated();
+ fFilterContentProvider = contentProvider;
+ }
+
/**
* Sets the filter label provider.
+ * <p>
* This should be called from the constructor.
*
* @param labelProvider
* The filter label provider
*/
protected void setFilterLabelProvider(final TreeLabelProvider labelProvider) {
+ checkPartNotCreated();
fFilterLabelProvider = labelProvider;
}
+ private void checkPartNotCreated() {
+ if (getParentComposite() != null) {
+ throw new IllegalStateException("This method must be called before createPartControl."); //$NON-NLS-1$
+ }
+ }
+
/**
* Gets the display width
*
}
/**
- * Sets the comparator class for the entries
+ * Sets the comparator class for the entries.
+ * <p>
+ * This comparator will apply recursively to entries that implement
+ * {@link TimeGraphEntry#sortChildren(Comparator)}.
*
* @param comparator
* A comparator object
return Messages.AbstractTimeGraphView_PreviousTooltip;
}
+
+ FindTarget getFindTarget() {
+ return fFindTarget;
+ }
+
+ /**
+ * Formats a log message for this class
+ *
+ * @param event
+ * The event to log, that will be appended to the class name to
+ * make the full event name
+ * @param parameters
+ * The string of extra parameters to add to the log message, in
+ * the format name=value[, name=value]*, or <code>null</code> for
+ * no params
+ * @return The complete log message for this class
+ */
+ private String getLogMessage(String event, @Nullable String parameters) {
+ if (parameters == null) {
+ return String.format(LOG_STRING, event, getViewId());
+ }
+ return String.format(LOG_STRING_WITH_PARAM, event, getViewId(), parameters);
+ }
+
// ------------------------------------------------------------------------
// ViewPart
// ------------------------------------------------------------------------
super.createPartControl(parent);
if (fColumns == null || fLabelProvider == null) {
fTimeGraphWrapper = new TimeGraphViewerWrapper(parent, SWT.NONE);
- TimeGraphViewer viewer = fTimeGraphWrapper.getTimeGraphViewer();
- viewer.setTimeGraphContentProvider(fTimeGraphContentProvider);
} else {
TimeGraphComboWrapper wrapper = new TimeGraphComboWrapper(parent, SWT.NONE);
fTimeGraphWrapper = wrapper;
combo.setTreeContentProvider(fTimeGraphContentProvider);
combo.setTreeLabelProvider(fLabelProvider);
combo.setTreeColumns(fColumns);
- combo.setFilterContentProvider(fTimeGraphContentProvider);
- combo.setFilterLabelProvider(fFilterLabelProvider);
- combo.setFilterColumns(fFilterColumns);
- combo.setTimeGraphContentProvider(fTimeGraphContentProvider);
+ if (fColumnComparators != null) {
+ createColumnSelectionListener(combo.getTreeViewer());
+ }
+ // Add double click listener to tree viewer
+ createDoubleClickListener(combo.getTreeViewer());
}
+ fTimeGraphWrapper.setTimeGraphContentProvider(fTimeGraphContentProvider);
+ fTimeGraphWrapper.setFilterContentProvider(fFilterContentProvider != null ? fFilterContentProvider : fTimeGraphContentProvider);
+ fTimeGraphWrapper.setFilterLabelProvider(fFilterLabelProvider);
+ fTimeGraphWrapper.setFilterColumns(fFilterColumns);
- fTimeGraphWrapper.setTimeGraphProvider(fPresentation);
+ fTimeGraphWrapper.setTimeGraphPresentationProvider(fPresentation);
fTimeGraphWrapper.setAutoExpandLevel(fAutoExpandLevel);
fTimeGraphWrapper.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
final long startTime = event.getStartTime();
final long endTime = event.getEndTime();
- TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
+ TmfTimeRange range = new TmfTimeRange(TmfTimestamp.fromNanos(startTime), TmfTimestamp.fromNanos(endTime));
broadcast(new TmfWindowRangeUpdatedSignal(AbstractTimeGraphView.this, range));
startZoomThread(startTime, endTime);
}
fTimeGraphWrapper.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
@Override
public void timeSelected(TimeGraphTimeEvent event) {
- TmfNanoTimestamp startTime = new TmfNanoTimestamp(event.getBeginTime());
- TmfNanoTimestamp endTime = new TmfNanoTimestamp(event.getEndTime());
+ ITmfTimestamp startTime = TmfTimestamp.fromNanos(event.getBeginTime());
+ ITmfTimestamp endTime = TmfTimestamp.fromNanos(event.getEndTime());
broadcast(new TmfSelectionRangeUpdatedSignal(AbstractTimeGraphView.this, startTime, endTime));
}
});
+ fTimeGraphWrapper.getTimeGraphViewer().addBookmarkListener(new ITimeGraphBookmarkListener() {
+ @Override
+ public void bookmarkAdded(final TimeGraphBookmarkEvent event) {
+ try {
+ ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
+ @Override
+ public void run(IProgressMonitor monitor) throws CoreException {
+ IMarkerEvent bookmark = event.getBookmark();
+ IMarker marker = fEditorFile.createMarker(IMarker.BOOKMARK);
+ marker.setAttribute(IMarker.MESSAGE, bookmark.getLabel());
+ marker.setAttribute(ITmfMarker.MARKER_TIME, Long.toString(bookmark.getTime()));
+ if (bookmark.getDuration() > 0) {
+ marker.setAttribute(ITmfMarker.MARKER_DURATION, Long.toString(bookmark.getDuration()));
+ marker.setAttribute(IMarker.LOCATION,
+ NLS.bind(org.eclipse.tracecompass.internal.tmf.ui.Messages.TmfMarker_LocationTimeRange,
+ TmfTimestamp.fromNanos(bookmark.getTime()),
+ TmfTimestamp.fromNanos(bookmark.getTime() + bookmark.getDuration())));
+ } else {
+ marker.setAttribute(IMarker.LOCATION,
+ NLS.bind(org.eclipse.tracecompass.internal.tmf.ui.Messages.TmfMarker_LocationTime,
+ TmfTimestamp.fromNanos(bookmark.getTime())));
+ }
+ marker.setAttribute(ITmfMarker.MARKER_COLOR, bookmark.getColor().toString());
+ }
+ }, null);
+ } catch (CoreException e) {
+ Activator.getDefault().logError(e.getMessage());
+ }
+ }
+
+ @Override
+ public void bookmarkRemoved(TimeGraphBookmarkEvent event) {
+ try {
+ IMarkerEvent bookmark = event.getBookmark();
+ IMarker[] markers = fEditorFile.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO);
+ for (IMarker marker : markers) {
+ if (bookmark.getLabel().equals(marker.getAttribute(IMarker.MESSAGE)) &&
+ Long.toString(bookmark.getTime()).equals(marker.getAttribute(ITmfMarker.MARKER_TIME, (String) null)) &&
+ Long.toString(bookmark.getDuration()).equals(marker.getAttribute(ITmfMarker.MARKER_DURATION, Long.toString(0))) &&
+ bookmark.getColor().toString().equals(marker.getAttribute(ITmfMarker.MARKER_COLOR))) {
+ marker.delete();
+ break;
+ }
+ }
+ } catch (CoreException e) {
+ Activator.getDefault().logError(e.getMessage());
+ }
+ }
+ });
+
fTimeGraphWrapper.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
// make selection available to other views
getSite().setSelectionProvider(fTimeGraphWrapper.getSelectionProvider());
+
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
+
+ createContextMenu();
+ fPartListener = new TimeGraphPartListener();
+ getSite().getPage().addPartListener(fPartListener);
}
@Override
fTimeGraphWrapper.setFocus();
}
+ @Override
+ public void dispose() {
+ super.dispose();
+ synchronized (fBuildJobMap) {
+ fBuildJobMap.values().forEach(buildJob -> {
+ buildJob.cancel();
+ });
+ }
+ if (fZoomThread != null) {
+ fZoomThread.cancel();
+ }
+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
+ getSite().getPage().removePartListener(fPartListener);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public void resourceChanged(final IResourceChangeEvent event) {
+ for (final IMarkerDelta delta : event.findMarkerDeltas(IMarker.BOOKMARK, false)) {
+ if (delta.getResource().equals(fEditorFile)) {
+ fTimeGraphWrapper.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile));
+ redraw();
+ return;
+ }
+ }
+ }
+
+ private static List<IMarkerEvent> refreshBookmarks(final IFile editorFile) {
+ List<IMarkerEvent> bookmarks = new ArrayList<>();
+ if (editorFile == null || !editorFile.exists()) {
+ return bookmarks;
+ }
+ try {
+ IMarker[] markers = editorFile.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO);
+ for (IMarker marker : markers) {
+ String label = marker.getAttribute(IMarker.MESSAGE, (String) null);
+ String time = marker.getAttribute(ITmfMarker.MARKER_TIME, (String) null);
+ String duration = marker.getAttribute(ITmfMarker.MARKER_DURATION, Long.toString(0));
+ String rgba = marker.getAttribute(ITmfMarker.MARKER_COLOR, (String) null);
+ if (label != null && time != null && rgba != null) {
+ Matcher matcher = RGBA_PATTERN.matcher(rgba);
+ if (matcher.matches()) {
+ try {
+ int red = Integer.valueOf(matcher.group(1));
+ int green = Integer.valueOf(matcher.group(2));
+ int blue = Integer.valueOf(matcher.group(3));
+ int alpha = Integer.valueOf(matcher.group(4));
+ RGBA color = new RGBA(red, green, blue, alpha);
+ bookmarks.add(new MarkerEvent(null, Long.valueOf(time), Long.valueOf(duration), IMarkerEvent.BOOKMARKS, color, label, true));
+ } catch (NumberFormatException e) {
+ Activator.getDefault().logError(e.getMessage());
+ }
+ }
+ }
+ }
+ } catch (CoreException e) {
+ Activator.getDefault().logError(e.getMessage());
+ }
+ return bookmarks;
+ }
+
+
+
// ------------------------------------------------------------------------
// Signal handlers
// ------------------------------------------------------------------------
*/
@TmfSignalHandler
public void traceOpened(TmfTraceOpenedSignal signal) {
- fTrace = signal.getTrace();
- loadTrace();
+ loadTrace(signal.getTrace());
}
/**
if (signal.getTrace() == fTrace) {
return;
}
- fTrace = signal.getTrace();
-
- loadTrace();
+ loadTrace(signal.getTrace());
}
/**
*/
@TmfSignalHandler
public void traceClosed(final TmfTraceClosedSignal signal) {
- synchronized (fBuildThreadMap) {
- for (ITmfTrace trace : getTracesToBuild(signal.getTrace())) {
- BuildThread buildThread = fBuildThreadMap.remove(trace);
- if (buildThread != null) {
- buildThread.cancel();
- }
- }
- }
- synchronized (fEntryListMap) {
- fEntryListMap.remove(signal.getTrace());
- }
+ resetView(signal.getTrace());
if (signal.getTrace() == fTrace) {
fTrace = null;
- fStartTime = 0;
- fEndTime = 0;
- if (fZoomThread != null) {
- fZoomThread.cancel();
- }
+ fEditorFile = null;
+ setStartTime(SWT.DEFAULT);
+ setEndTime(SWT.DEFAULT);
refresh();
}
}
if (signal.getSource() == this || fTrace == null) {
return;
}
- final long beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
- final long endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long beginTime = signal.getBeginTime().toNanos();
+ final long endTime = signal.getEndTime().toNanos();
Display.getDefault().asyncExec(new Runnable() {
@Override
if (beginTime == endTime) {
fTimeGraphWrapper.getTimeGraphViewer().setSelectedTime(beginTime, true);
} else {
- fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(beginTime, endTime);
+ fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(beginTime, endTime, true);
}
- startZoomThread(fTimeGraphWrapper.getTimeGraphViewer().getTime0(), fTimeGraphWrapper.getTimeGraphViewer().getTime1());
-
- synchingToTime(beginTime);
+ synchingToTime(fTimeGraphWrapper.getTimeGraphViewer().getSelectionBegin());
}
});
}
if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
return;
}
- final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
- final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long startTime = signal.getCurrentRange().getStartTime().toNanos();
+ final long endTime = signal.getCurrentRange().getEndTime().toNanos();
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
fTimeGraphWrapper.refresh();
}
+ /**
+ * A marker event source has been updated
+ *
+ * @param signal
+ * the signal
+ * @since 2.1
+ */
+ @TmfSignalHandler
+ public void markerEventSourceUpdated(final TmfMarkerEventSourceUpdatedSignal signal) {
+ getTimeGraphViewer().setMarkerCategories(getMarkerCategories());
+ getTimeGraphViewer().setMarkers(null);
+ refresh();
+ }
+
// ------------------------------------------------------------------------
// Internal
// ------------------------------------------------------------------------
- private void loadTrace() {
+ private void loadTrace(final ITmfTrace trace) {
+ if (fZoomThread != null) {
+ fZoomThread.cancel();
+ fZoomThread = null;
+ }
+ if (fTrace != null) {
+ /* save the filters of the previous trace */
+ fFiltersMap.put(fTrace, fTimeGraphWrapper.getFilters());
+ fViewContext.put(fTrace, new ViewContext(fCurrentSortColumn, fSortDirection, fTimeGraphWrapper.getSelection()));
+ }
+ fTrace = trace;
+
+ LOGGER.info(() -> getLogMessage("LoadingTrace", "trace=" + trace.getName())); //$NON-NLS-1$ //$NON-NLS-2$
+
+ restoreViewContext();
+ fEditorFile = TmfTraceManager.getInstance().getTraceEditorFile(trace);
synchronized (fEntryListMap) {
fEntryList = fEntryListMap.get(fTrace);
if (fEntryList == null) {
rebuild();
} else {
- fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
- fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ setStartTime(fTrace.getStartTime().toNanos());
+ setEndTime(fTrace.getEndTime().toNanos());
refresh();
}
}
if (viewTrace == null) {
return;
}
- synchronized (fBuildThreadMap) {
+ resetView(viewTrace);
+
+ List<IMarkerEventSource> markerEventSources = new ArrayList<>();
+ synchronized (fBuildJobMap) {
for (ITmfTrace trace : getTracesToBuild(viewTrace)) {
if (trace == null) {
break;
}
- BuildThread buildThread = new BuildThread(trace, viewTrace, getName());
- fBuildThreadMap.put(trace, buildThread);
- buildThread.start();
+ markerEventSources.addAll(TmfTraceAdapterManager.getAdapters(trace, IMarkerEventSource.class));
+ Job buildJob = new Job(getTitle() + Messages.AbstractTimeGraphView_BuildJob) {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ new BuildRunnable(trace, viewTrace).run(monitor);
+ monitor.done();
+ return Status.OK_STATUS;
+ }
+ };
+ fBuildJobMap.put(trace, buildJob);
+ buildJob.schedule();
}
}
+ fMarkerEventSourcesMap.put(viewTrace, markerEventSources);
}
/**
* some of which may receive events in live streaming mode.
*
* @param trace
- * The trace associated with this view
+ * The trace associated with this view, can be null
* @return List of traces with data to display
*/
- protected @NonNull Iterable<ITmfTrace> getTracesToBuild(@NonNull ITmfTrace trace) {
+ protected @NonNull Iterable<ITmfTrace> getTracesToBuild(@Nullable ITmfTrace trace) {
return TmfTraceManager.getTraceSet(trace);
}
/**
- * Build the entries list to show in this time graph
+ * Build the entry list to show in this time graph view.
+ * <p>
+ * Called from the BuildJob for each trace returned by
+ * {@link #getTracesToBuild(ITmfTrace)}.
+ * <p>
+ * Root entries must be added to the entry list by calling the
+ * {@link #addToEntryList(ITmfTrace, List)} method with the list of entries
+ * to add and where the trace in parameter should be the parentTrace.
+ * Entries that are children of other entries will be automatically picked
+ * up after refreshing the root entries.
+ * <p>
+ * The full event list is also normally computed for every entry that is
+ * created. It should be set for each entry by calling the
+ * {@link TimeGraphEntry#setEventList(List)}. These full event lists will be
+ * used to display something while the zoomed event lists are being
+ * calculated when the window range is updated. Also, when fully zoomed out,
+ * it is this list of events that is displayed.
+ * <p>
+ * Also, when all the entries have been added and their events set, this
+ * method can finish by calling the refresh() method like this:
*
- * Called from the BuildThread
+ * <pre>
+ * if (parentTrace.equals(getTrace())) {
+ * refresh();
+ * }
+ * </pre>
*
* @param trace
* The trace being built
* The parent of the trace set, or the trace itself
* @param monitor
* The progress monitor object
+ * @since 2.0
*/
- protected abstract void buildEventList(@NonNull ITmfTrace trace, @NonNull ITmfTrace parentTrace, @NonNull IProgressMonitor monitor);
+ protected abstract void buildEntryList(@NonNull ITmfTrace trace, @NonNull ITmfTrace parentTrace, @NonNull IProgressMonitor monitor);
/**
- * Gets the list of event for an entry in a given timerange
+ * Gets the list of event for an entry in a given time range.
+ * <p>
+ * Called from the ZoomThread for every entry to update the zoomed event
+ * list. Can be an empty implementation if the view does not support zoomed
+ * event lists. Can also be used to compute the full event list.
*
* @param entry
* The entry to get events for
* The progress monitor object
* @return The list of events for the entry
*/
- protected abstract @Nullable List<ITimeEvent> getEventList(@NonNull TimeGraphEntry entry,
+ protected abstract @Nullable List<@NonNull ITimeEvent> getEventList(@NonNull TimeGraphEntry entry,
long startTime, long endTime, long resolution,
@NonNull IProgressMonitor monitor);
* The progress monitor object
* @return The list of link events
*/
- protected @Nullable List<ILinkEvent> getLinkList(long startTime, long endTime,
+ protected @Nullable List<@NonNull ILinkEvent> getLinkList(long startTime, long endTime,
long resolution, @NonNull IProgressMonitor monitor) {
return new ArrayList<>();
}
+ /**
+ * Gets the list of view-specific marker categories. Default implementation
+ * returns an empty list.
+ *
+ * @return The list of marker categories
+ * @since 2.0
+ */
+ protected @NonNull List<String> getViewMarkerCategories() {
+ return new ArrayList<>();
+ }
+
+ /**
+ * Gets the list of view-specific markers for a trace in a given time range.
+ * Default implementation returns an empty list.
+ *
+ * @param startTime
+ * Start of the time range
+ * @param endTime
+ * End of the time range
+ * @param resolution
+ * The resolution
+ * @param monitor
+ * The progress monitor object
+ * @return The list of marker events
+ * @since 2.0
+ */
+ protected @NonNull List<IMarkerEvent> getViewMarkerList(long startTime, long endTime,
+ long resolution, @NonNull IProgressMonitor monitor) {
+ return new ArrayList<>();
+ }
+
+ /**
+ * Gets the list of trace-specific markers for a trace in a given time range.
+ *
+ * @param startTime
+ * Start of the time range
+ * @param endTime
+ * End of the time range
+ * @param resolution
+ * The resolution
+ * @param monitor
+ * The progress monitor object
+ * @return The list of marker events
+ * @since 2.0
+ */
+ protected @NonNull List<IMarkerEvent> getTraceMarkerList(long startTime, long endTime,
+ long resolution, @NonNull IProgressMonitor monitor) {
+ List<IMarkerEvent> markers = new ArrayList<>();
+ for (IMarkerEventSource markerEventSource : getMarkerEventSources(fTrace)) {
+ for (String category : markerEventSource.getMarkerCategories()) {
+ if (monitor.isCanceled()) {
+ break;
+ }
+ markers.addAll(markerEventSource.getMarkerList(category, startTime, endTime, resolution, monitor));
+ }
+ }
+ return markers;
+ }
+
+ /**
+ * Get the list of current marker categories.
+ *
+ * @return The list of marker categories
+ * @since 2.1
+ */
+ protected @NonNull List<String> getMarkerCategories() {
+ Set<String> categories = new LinkedHashSet<>(getViewMarkerCategories());
+ for (IMarkerEventSource markerEventSource : getMarkerEventSources(fTrace)) {
+ categories.addAll(markerEventSource.getMarkerCategories());
+ }
+ return new ArrayList<>(categories);
+ }
+
+ /**
+ * Gets the list of marker event sources for a given trace.
+ *
+ * @param trace
+ * The trace
+ * @return The list of marker event sources
+ * @since 2.0
+ */
+ private @NonNull List<IMarkerEventSource> getMarkerEventSources(ITmfTrace trace) {
+ List<IMarkerEventSource> markerEventSources = fMarkerEventSourcesMap.get(trace);
+ if (markerEventSources == null) {
+ markerEventSources = Collections.emptyList();
+ }
+ return markerEventSources;
+ }
/**
* Refresh the display
*/
protected void refresh() {
+ LOGGER.info(() -> getLogMessage("RefreshRequested", null)); //$NON-NLS-1$
+ final boolean zoomThread = Thread.currentThread() instanceof ZoomThread;
TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
@Override
public void run() {
+ LOGGER.info(() -> getLogMessage("RefreshStart", null)); //$NON-NLS-1$
if (fTimeGraphWrapper.isDisposed()) {
return;
}
+ fDirty.incrementAndGet();
+
boolean hasEntries = false;
synchronized (fEntryListMap) {
fEntryList = fEntryListMap.get(fTrace);
} else if (fEntryComparator != null) {
List<TimeGraphEntry> list = new ArrayList<>(fEntryList);
Collections.sort(list, fEntryComparator);
+ for (ITimeGraphEntry entry : list) {
+ sortChildren(entry, fEntryComparator);
+ }
fEntryList.clear();
fEntryList.addAll(list);
}
- hasEntries = fEntryList.size() != 0;
+ hasEntries = !fEntryList.isEmpty();
}
- if (fEntryList != fTimeGraphWrapper.getInput()) {
- fTimeGraphWrapper.setInput(fEntryList);
- } else {
- fTimeGraphWrapper.refresh();
+ boolean inputChanged = fEntryList != fTimeGraphWrapper.getInput();
+ TimeGraphCombo combo = getTimeGraphCombo();
+ try {
+ // Set redraw to false to only draw once
+ if (combo != null) {
+ combo.getTreeViewer().getTree().setRedraw(false);
+ }
+ getTimeGraphViewer().getTimeGraphControl().setRedraw(false);
+ if (inputChanged) {
+ fTimeGraphWrapper.setInput(fEntryList);
+ /* restore the previously saved filters, if any */
+ fTimeGraphWrapper.setFilters(fFiltersMap.get(fTrace));
+ fTimeGraphWrapper.getTimeGraphViewer().setLinks(null);
+ fTimeGraphWrapper.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile));
+ fTimeGraphWrapper.getTimeGraphViewer().setMarkerCategories(getMarkerCategories());
+ fTimeGraphWrapper.getTimeGraphViewer().setMarkers(null);
+ applyViewContext();
+ } else {
+ fTimeGraphWrapper.refresh();
+ }
+ // reveal selection
+ if (fIsRevealSelection) {
+ fIsRevealSelection = false;
+ ITimeGraphEntry entry1 = fTimeGraphWrapper.getSelection();
+ fTimeGraphWrapper.setSelection(entry1);
+ }
+ } finally {
+ if (combo != null) {
+ combo.getTreeViewer().getTree().setRedraw(true);
+ }
+ getTimeGraphViewer().getTimeGraphControl().setRedraw(true);
}
- fTimeGraphWrapper.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
+ long startBound = (fStartTime == Long.MAX_VALUE ? SWT.DEFAULT : fStartTime);
+ long endBound = (fEndTime == Long.MIN_VALUE ? SWT.DEFAULT : fEndTime);
+ fTimeGraphWrapper.getTimeGraphViewer().setTimeBounds(startBound, endBound);
TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
- long selectionBeginTime = fTrace == null ? 0 : ctx.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
- long selectionEndTime = fTrace == null ? 0 : ctx.getSelectionRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
- long startTime = fTrace == null ? 0 : ctx.getWindowRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
- long endTime = fTrace == null ? 0 : ctx.getWindowRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
- startTime = Math.max(startTime, fStartTime);
- endTime = Math.min(endTime, fEndTime);
- fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime);
+ long selectionBeginTime = fTrace == null ? SWT.DEFAULT : ctx.getSelectionRange().getStartTime().toNanos();
+ long selectionEndTime = fTrace == null ? SWT.DEFAULT : ctx.getSelectionRange().getEndTime().toNanos();
+ long startTime = fTrace == null ? SWT.DEFAULT : ctx.getWindowRange().getStartTime().toNanos();
+ long endTime = fTrace == null ? SWT.DEFAULT : ctx.getWindowRange().getEndTime().toNanos();
+ startTime = (fStartTime == Long.MAX_VALUE ? SWT.DEFAULT : Math.max(startTime, fStartTime));
+ endTime = (fEndTime == Long.MIN_VALUE ? SWT.DEFAULT : Math.min(endTime, fEndTime));
+ fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime, false);
fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
+ if (inputChanged && selectionBeginTime != SWT.DEFAULT) {
+ synchingToTime(selectionBeginTime);
+ }
+
if (fTimeGraphWrapper instanceof TimeGraphComboWrapper && !fPackDone) {
for (TreeColumn column : ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getTree().getColumns()) {
column.pack();
}
}
- startZoomThread(startTime, endTime);
+ if (!zoomThread) {
+ startZoomThread(startTime, endTime);
+ }
+ fDirty.decrementAndGet();
+ LOGGER.info(() -> getLogMessage("RefreshEnd", null)); //$NON-NLS-1$
}
});
}
return;
}
}
+ LOGGER.info(() -> getLogMessage("RedrawRequested", null)); //$NON-NLS-1$
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
+ LOGGER.info(() -> getLogMessage("RedrawStart", null)); //$NON-NLS-1$
if (fTimeGraphWrapper.isDisposed()) {
return;
}
fRedrawState = State.IDLE;
}
}
+ LOGGER.info(() -> getLogMessage("RedrawEnd", null)); //$NON-NLS-1$
}
});
}
- private void startZoomThread(long startTime, long endTime) {
+ private void sortChildren(ITimeGraphEntry entry, Comparator<ITimeGraphEntry> comparator) {
+ if (entry instanceof TimeGraphEntry) {
+ ((TimeGraphEntry) entry).sortChildren(comparator);
+ }
+ for (ITimeGraphEntry child : entry.getChildren()) {
+ sortChildren(child, comparator);
+ }
+ }
+
+ /**
+ * Start or restart the zoom thread.
+ *
+ * @param startTime
+ * the zoom start time
+ * @param endTime
+ * the zoom end time
+ * @since 2.0
+ */
+ protected final void startZoomThread(long startTime, long endTime) {
+ long clampedStartTime = (fStartTime == Long.MAX_VALUE ? startTime : Math.min(Math.max(startTime, fStartTime), fEndTime));
+ long clampedEndTime = (fEndTime == Long.MIN_VALUE ? endTime : Math.max(Math.min(endTime, fEndTime), fStartTime));
+ fDirty.incrementAndGet();
+ boolean restart = false;
if (fZoomThread != null) {
fZoomThread.cancel();
+ if (fZoomThread.fZoomStartTime == clampedStartTime && fZoomThread.fZoomEndTime == clampedEndTime) {
+ restart = true;
+ }
+ }
+ long resolution = Math.max(1, (clampedEndTime - clampedStartTime) / fDisplayWidth);
+ fZoomThread = createZoomThread(clampedStartTime, clampedEndTime, resolution, restart);
+ if (fZoomThread != null) {
+ // Don't start a new thread right away if results are being applied
+ // from an old ZoomThread. Otherwise, the old results might
+ // overwrite the new results if it finishes after.
+ synchronized (fZoomThreadResultLock) {
+ fZoomThread.start();
+ }
+ } else {
+ fDirty.decrementAndGet();
}
+ }
+
+ /**
+ * Create a zoom thread.
+ *
+ * @param startTime
+ * the zoom start time
+ * @param endTime
+ * the zoom end time
+ * @param resolution
+ * the resolution
+ * @param restart
+ * true if restarting zoom for the same time range
+ * @return a zoom thread
+ * @since 1.1
+ */
+ protected @Nullable ZoomThread createZoomThread(long startTime, long endTime, long resolution, boolean restart) {
final List<TimeGraphEntry> entryList = fEntryList;
if (entryList == null) {
- return;
+ return null;
}
- fZoomThread = new ZoomThread(entryList, startTime, endTime, getName());
- fZoomThread.start();
+ return new ZoomThreadByEntry(entryList, startTime, endTime, resolution);
}
private void makeActions() {
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalToolBar(bars.getToolBarManager());
+ fillLocalMenu(bars.getMenuManager());
}
/**
* @param manager the tool bar manager
*/
protected void fillLocalToolBar(IToolBarManager manager) {
- if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
- if (fFilterColumns != null && fFilterLabelProvider != null && fFilterColumns.length > 0) {
- manager.add(((TimeGraphComboWrapper) fTimeGraphWrapper).getShowFilterAction());
- }
+ if (fFilterColumns != null && fFilterLabelProvider != null && fFilterColumns.length > 0) {
+ manager.add(fTimeGraphWrapper.getShowFilterDialogAction());
}
manager.add(fTimeGraphWrapper.getTimeGraphViewer().getShowLegendAction());
manager.add(new Separator());
manager.add(fTimeGraphWrapper.getTimeGraphViewer().getResetScaleAction());
manager.add(fTimeGraphWrapper.getTimeGraphViewer().getPreviousEventAction());
manager.add(fTimeGraphWrapper.getTimeGraphViewer().getNextEventAction());
+ manager.add(new Separator());
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getToggleBookmarkAction());
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getPreviousMarkerAction());
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getNextMarkerAction());
+ manager.add(new Separator());
manager.add(fPreviousResourceAction);
manager.add(fNextResourceAction);
manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomInAction());
manager.add(new Separator());
}
+ /**
+ * Add actions to local menu manager
+ *
+ * @param manager the tool bar manager
+ * @since 2.0
+ */
+ protected void fillLocalMenu(IMenuManager manager) {
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getMarkersMenu());
+ }
+
/**
* @since 1.0
*/
fTimeGraphWrapper.performAlign(offset, width);
}
}
+
+ /**
+ * Returns whether or not the time graph view is dirty. The time graph view
+ * is considered dirty if it has yet to completely update its model.
+ *
+ * This method is meant to be used by tests in order to know when it is safe
+ * to proceed.
+ *
+ * Note: If a trace is smaller than the initial window range (see
+ * {@link ITmfTrace#getInitialRangeOffset}) this method will return true
+ * forever.
+ *
+ * @return true if the time graph view has yet to completely update its
+ * model, false otherwise
+ * @since 2.0
+ */
+ public boolean isDirty() {
+ if (fTrace == null) {
+ return false;
+ }
+
+ TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
+ long startTime = ctx.getWindowRange().getStartTime().toNanos();
+ long endTime = ctx.getWindowRange().getEndTime().toNanos();
+
+ // If the time graph control hasn't updated all the way to the end of
+ // the window range then it's dirty. A refresh should happen later.
+ if (fTimeGraphWrapper.getTimeGraphViewer().getTime0() != startTime || fTimeGraphWrapper.getTimeGraphViewer().getTime1() != endTime) {
+ return true;
+ }
+
+ if (fZoomThread == null) {
+ // The zoom thread is null but we might be just about to create it (refresh called).
+ return fDirty.get() != 0;
+ }
+ // Dirty if the zoom thread is not done or if it hasn't zoomed all the
+ // way to the end of the window range. In the latter case, there should be
+ // a subsequent zoom thread that will be triggered.
+ return fDirty.get() != 0 || fZoomThread.getZoomStartTime() != startTime || fZoomThread.getZoomEndTime() != endTime;
+ }
+
+ private void createColumnSelectionListener(TreeViewer treeViewer) {
+ for (int i = 0; i < fColumnComparators.length; i++) {
+ final int index = i;
+ final Comparator<ITimeGraphEntry> comp = fColumnComparators[index];
+ final Tree tree = treeViewer.getTree();
+ final TreeColumn column = tree.getColumn(i);
+
+ if (comp != null) {
+ column.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ TreeColumn prevSortcolumn = tree.getSortColumn();
+ int direction = tree.getSortDirection();
+ if (prevSortcolumn == column) {
+ direction = (direction == SWT.DOWN) ? SWT.UP : SWT.DOWN;
+ } else {
+ direction = SWT.DOWN;
+ }
+ tree.setSortColumn(column);
+ tree.setSortDirection(direction);
+ fSortDirection = direction;
+ fCurrentSortColumn = index;
+ Comparator<ITimeGraphEntry> comparator = comp;
+
+ if (comparator instanceof ITimeGraphEntryComparator) {
+ ((ITimeGraphEntryComparator) comparator).setDirection(direction);
+ }
+ if (direction != SWT.DOWN) {
+ comparator = checkNotNull(Collections.reverseOrder(comparator));
+ }
+ setEntryComparator(comparator);
+ fIsRevealSelection = true;
+ if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
+ ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getControl().setFocus();
+ }
+ refresh();
+ }
+ });
+ }
+ }
+ }
+
+ private void createDoubleClickListener(TreeViewer treeViewer) {
+ treeViewer.addDoubleClickListener(event -> {
+ if (event.getSelection() instanceof TreeSelection) {
+ TreeSelection selection = (TreeSelection) event.getSelection();
+ if (selection.getFirstElement() instanceof ITimeGraphEntry) {
+ ITimeGraphEntry entry = (ITimeGraphEntry) selection.getFirstElement();
+ if (entry.hasChildren()) {
+ fTimeGraphWrapper.setExpandedState(entry, !fTimeGraphWrapper.getExpandedState(entry));
+ }
+ }
+ }
+ });
+ }
+
+
+ private void restoreViewContext() {
+ TimeGraphCombo combo = getTimeGraphCombo();
+ ViewContext viewContext = fViewContext.get(fTrace);
+ if (combo != null) {
+ if (fColumnComparators != null) {
+ // restore sort settings
+ fSortDirection = SWT.DOWN;
+ fCurrentSortColumn = fInitialSortColumn;
+ if (viewContext != null) {
+ fSortDirection = viewContext.getSortDirection();
+ fCurrentSortColumn = viewContext.getSortColumn();
+ }
+ if ((fCurrentSortColumn < fColumnComparators.length) && (fColumnComparators[fCurrentSortColumn] != null)) {
+ Comparator<ITimeGraphEntry> comparator = fColumnComparators[fCurrentSortColumn];
+ if (comparator instanceof ITimeGraphEntryComparator) {
+ ((ITimeGraphEntryComparator) comparator).setDirection(fSortDirection);
+ }
+ if (fSortDirection != SWT.DOWN) {
+ comparator = checkNotNull(Collections.reverseOrder(comparator));
+ }
+ setEntryComparator(comparator);
+ }
+ }
+ }
+ }
+
+ private void applyViewContext() {
+ TimeGraphCombo combo = getTimeGraphCombo();
+ ViewContext viewContext = fViewContext.get(fTrace);
+ if (combo != null) {
+ TreeViewer treeViewer = combo.getTreeViewer();
+ final Tree tree = treeViewer.getTree();
+ final TreeColumn column = tree.getColumn(fCurrentSortColumn);
+ tree.setSortDirection(fSortDirection);
+ tree.setSortColumn(column);
+ combo.getTreeViewer().getControl().setFocus();
+ }
+ // restore and reveal selection
+ if ((viewContext != null) && (viewContext.getSelection() != null)) {
+ fTimeGraphWrapper.setSelection(viewContext.getSelection());
+ }
+ fViewContext.remove(fTrace);
+ }
+
+ private static class ViewContext {
+ private int fSortColumnIndex;
+ private int fSortDirection;
+ private @Nullable ITimeGraphEntry fSelection;
+
+ ViewContext(int sortColunm, int sortDirection, ITimeGraphEntry selection) {
+ fSortColumnIndex = sortColunm;
+ fSortDirection = sortDirection;
+ fSelection = selection;
+ }
+ /**
+ * @return the sortColumn
+ */
+ public int getSortColumn() {
+ return fSortColumnIndex;
+ }
+ /**
+ * @return the sortDirection
+ */
+ public int getSortDirection() {
+ return fSortDirection;
+ }
+ /**
+ * @return the selection
+ */
+ public ITimeGraphEntry getSelection() {
+ return fSelection;
+ }
+ }
+
+ /**
+ * Method to reset the view internal data for a given trace.
+ *
+ * When overriding this method make sure to call the super
+ * implementation.
+ *
+ * @param viewTrace
+ * trace to reset the view for.
+ * @since 2.0
+ */
+ protected void resetView(ITmfTrace viewTrace) {
+ if (viewTrace == null) {
+ return;
+ }
+ synchronized (fBuildJobMap) {
+ for (ITmfTrace trace : getTracesToBuild(viewTrace)) {
+ Job buildJob = fBuildJobMap.remove(trace);
+ if (buildJob != null) {
+ buildJob.cancel();
+ }
+ }
+ }
+ synchronized (fEntryListMap) {
+ fEntryListMap.remove(viewTrace);
+ }
+ fViewContext.remove(viewTrace);
+ fFiltersMap.remove(viewTrace);
+ fMarkerEventSourcesMap.remove(viewTrace);
+ if (viewTrace == fTrace) {
+ if (fZoomThread != null) {
+ fZoomThread.cancel();
+ fZoomThread = null;
+ }
+ }
+ }
+
+ private void createContextMenu() {
+ TimeGraphCombo combo = getTimeGraphCombo();
+ fEntryMenuManager.setRemoveAllWhenShown(true);
+ if (combo != null) {
+ TreeViewer treeViewer = combo.getTreeViewer();
+ Tree tree = treeViewer.getTree();
+ Menu menu = fEntryMenuManager.createContextMenu(tree);
+ tree.setMenu(menu);
+ } else {
+ TimeGraphControl timeGraphControl = getTimeGraphViewer().getTimeGraphControl();
+ final Menu entryMenu = fEntryMenuManager.createContextMenu(timeGraphControl);
+ timeGraphControl.addTimeGraphEntryMenuListener(new MenuDetectListener() {
+ @Override
+ public void menuDetected(MenuDetectEvent event) {
+ Point p = timeGraphControl.toControl(event.x, event.y);
+ /*
+ * The TimeGraphControl will call the TimeGraphEntryMenuListener
+ * before the TimeEventMenuListener. If the event is
+ * triggered on the namespace then show the menu else
+ * clear the menu.
+ */
+ if (p.x < getTimeGraphViewer().getNameSpace()) {
+ timeGraphControl.setMenu(entryMenu);
+ } else {
+ timeGraphControl.setMenu(null);
+ event.doit = false;
+ }
+ }
+ });
+ }
+ fEntryMenuManager.addMenuListener(new IMenuListener() {
+ @Override
+ public void menuAboutToShow(IMenuManager manager) {
+ fillTimeGraphEntryContextMenu(fEntryMenuManager);
+ fEntryMenuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
+ }
+ });
+ getSite().registerContextMenu(fEntryMenuManager, fTimeGraphWrapper.getSelectionProvider());
+ }
+
+ /**
+ * Fill context menu
+ *
+ * @param menuManager
+ * a menuManager to fill
+ * @since 2.0
+ */
+ protected void fillTimeGraphEntryContextMenu (@NonNull IMenuManager menuManager) {
+ }
+
+ /*
+ * Inner classes used for searching
+ */
+ class FindTarget {
+ public ITimeGraphEntry getSelection() {
+ return fTimeGraphWrapper.getSelection();
+ }
+
+ public void selectAndReveal(@NonNull ITimeGraphEntry entry) {
+ fTimeGraphWrapper.selectAndReveal(entry);
+ }
+
+ public ITimeGraphEntry[] getEntries() {
+ TimeGraphViewer viewer = getTimeGraphViewer();
+ return viewer.getTimeGraphContentProvider().getElements(viewer.getInput());
+ }
+
+ public Shell getShell() {
+ return getSite().getShell();
+ }
+ }
+
+ class TimeGraphPartListener implements IPartListener {
+ @Override
+ public void partActivated(IWorkbenchPart part) {
+ if (part == AbstractTimeGraphView.this) {
+ synchronized (FIND_ACTION) {
+ if (fFindActionHandler == null) {
+ fFindActionHandler = new ActionHandler(FIND_ACTION);
+ }
+ if (fFindHandlerActivation == null) {
+ final Object service = PlatformUI.getWorkbench().getService(IHandlerService.class);
+ fFindHandlerActivation = ((IHandlerService) service).activateHandler(ActionFactory.FIND.getCommandId(), fFindActionHandler);
+ }
+ }
+ }
+ // Notify action for all parts
+ FIND_ACTION.partActivated(part);
+ }
+ @Override
+ public void partDeactivated(IWorkbenchPart part) {
+ if ((part == AbstractTimeGraphView.this) && (fFindHandlerActivation != null)) {
+ final Object service = PlatformUI.getWorkbench().getService(IHandlerService.class);
+ ((IHandlerService) service).deactivateHandler(fFindHandlerActivation);
+ fFindHandlerActivation = null;
+ }
+ }
+ @Override
+ public void partBroughtToTop(IWorkbenchPart part) {
+ }
+ @Override
+ public void partClosed(IWorkbenchPart part) {
+ }
+ @Override
+ public void partOpened(IWorkbenchPart part) {
+ }
+ }
}