tmf.ui: Add extra javadoc to the AbstractTimeGraphView
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / timegraph / AbstractTimeGraphView.java
index 0f5aca1193b61288b69298bc791c5e592e86614e..1a2cc5df578d2640678f41efece55179964221d8 100644 (file)
@@ -28,6 +28,7 @@ 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;
 
@@ -41,35 +42,51 @@ 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;
@@ -77,8 +94,9 @@ import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
-import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
 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;
@@ -107,8 +125,16 @@ 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
@@ -123,6 +149,10 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
 
     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
      */
@@ -139,6 +169,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
 
     private AtomicInteger fDirty = new AtomicInteger();
 
+    private final Object fZoomThreadResultLock = new Object();
+
     /** The selected trace */
     private ITmfTrace fTrace;
 
@@ -161,7 +193,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
     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 = SWT.DEFAULT;
@@ -233,6 +265,28 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
     /** 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
     // ------------------------------------------------------------------------
@@ -269,6 +323,10 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
 
         void setAutoExpandLevel(int level);
 
+        boolean getExpandedState(ITimeGraphEntry entry);
+
+        void setExpandedState(ITimeGraphEntry entry, boolean expanded);
+
         void setFilterColumns(String[] columnNames);
 
         void setFilterContentProvider(ITreeContentProvider contentProvider);
@@ -286,6 +344,9 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         ITimeGraphEntry getSelection();
 
         void setSelection(ITimeGraphEntry selection);
+
+        void selectAndReveal(@NonNull ITimeGraphEntry selection);
+
     }
 
     private class TimeGraphViewerWrapper implements ITimeGraphWrapper {
@@ -390,6 +451,16 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             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);
@@ -414,6 +485,11 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         public void setSelection(ITimeGraphEntry selection) {
             viewer.setSelection(selection);
         }
+
+        @Override
+        public void selectAndReveal(@NonNull ITimeGraphEntry selection) {
+            viewer.selectAndReveal(selection);
+        }
     }
 
     private class TimeGraphComboWrapper implements ITimeGraphWrapper {
@@ -518,6 +594,16 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             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;
         }
@@ -550,6 +636,11 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         public void setSelection(ITimeGraphEntry selection) {
             combo.setSelection(selection);
         }
+
+        @Override
+        public void selectAndReveal(@NonNull ITimeGraphEntry selection) {
+            combo.selectAndReveal(selection);
+        }
     }
 
     /**
@@ -603,28 +694,25 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
 
     }
 
-    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$
         }
     }
 
@@ -693,8 +781,30 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
 
         @Override
         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();
+                }
+            }
         }
 
         /**
@@ -714,8 +824,11 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
 
         @Override
         public void doRun() {
+            LOGGER.config(() -> getLogMessage("ZoomThreadGettingStates", null)); //$NON-NLS-1$
+
             for (TimeGraphEntry entry : fZoomEntryList) {
                 if (getMonitor().isCanceled()) {
+                    LOGGER.info(() -> getLogMessage("ZoomThreadCanceled", null)); //$NON-NLS-1$
                     return;
                 }
                 if (entry == null) {
@@ -724,36 +837,43 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                 zoom(entry, getMonitor());
             }
             /* Refresh the arrows when zooming */
+            LOGGER.config(() -> getLogMessage("ZoomThreadGettingLinks", null)); //$NON-NLS-1$
             List<ILinkEvent> events = getLinkList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
-            if (events != null) {
-                fTimeGraphWrapper.getTimeGraphViewer().setLinks(events);
-                redraw();
-            }
+
             /* 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()));
-            fTimeGraphWrapper.getTimeGraphViewer().setMarkers(markers);
-            redraw();
+            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 (getZoomStartTime() <= fStartTime && getZoomEndTime() >= fEndTime) {
-                entry.setZoomedEventList(null);
+                applyResults(() -> {
+                    entry.setZoomedEventList(null);
+                });
             } else {
                 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()) {
+            for (TimeGraphEntry child : entry.getChildren()) {
                 if (monitor.isCanceled()) {
                     return;
                 }
-                if (child instanceof TimeGraphEntry) {
-                    zoom((TimeGraphEntry) child, monitor);
-                }
+                zoom(child, monitor);
             }
         }
 
@@ -780,6 +900,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         super(id);
         fPresentation = pres;
         fDisplayWidth = Display.getDefault().getBounds().width;
+        fFindTarget = new FindTarget();
     }
 
     // ------------------------------------------------------------------------
@@ -909,7 +1030,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      *
      * @param contentProvider
      *            The filter content provider
-     * @since 2.0
+     * @since 1.2
      */
     protected void setFilterContentProvider(final ITreeContentProvider contentProvider) {
         checkPartNotCreated();
@@ -1135,6 +1256,30 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         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
     // ------------------------------------------------------------------------
@@ -1154,6 +1299,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             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);
@@ -1168,7 +1315,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             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);
             }
@@ -1177,8 +1324,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         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));
             }
         });
@@ -1198,12 +1345,12 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                                 marker.setAttribute(ITmfMarker.MARKER_DURATION, Long.toString(bookmark.getDuration()));
                                 marker.setAttribute(IMarker.LOCATION,
                                         NLS.bind(org.eclipse.tracecompass.internal.tmf.ui.Messages.TmfMarker_LocationTimeRange,
-                                                new TmfNanoTimestamp(bookmark.getTime()),
-                                                new TmfNanoTimestamp(bookmark.getTime() + bookmark.getDuration())));
+                                                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,
-                                                new TmfNanoTimestamp(bookmark.getTime())));
+                                                TmfTimestamp.fromNanos(bookmark.getTime())));
                             }
                             marker.setAttribute(ITmfMarker.MARKER_COLOR, bookmark.getColor().toString());
                         }
@@ -1251,6 +1398,10 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         getSite().setSelectionProvider(fTimeGraphWrapper.getSelectionProvider());
 
         ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
+
+        createContextMenu();
+        fPartListener = new TimeGraphPartListener();
+        getSite().getPage().addPartListener(fPartListener);
     }
 
     @Override
@@ -1261,7 +1412,16 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
     @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);
     }
 
     /**
@@ -1351,29 +1511,12 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      */
     @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();
-                }
-            }
-        }
-        fMarkerEventSourcesMap.remove(signal.getTrace());
-        synchronized (fEntryListMap) {
-            fEntryListMap.remove(signal.getTrace());
-        }
-        fFiltersMap.remove(signal.getTrace());
-        fViewContext.remove(signal.getTrace());
+        resetView(signal.getTrace());
         if (signal.getTrace() == fTrace) {
             fTrace = null;
             fEditorFile = null;
-            fStartTime = SWT.DEFAULT;
-            fEndTime = SWT.DEFAULT;
-            if (fZoomThread != null) {
-                fZoomThread.cancel();
-                fZoomThread = null;
-            }
+            setStartTime(SWT.DEFAULT);
+            setEndTime(SWT.DEFAULT);
             refresh();
         }
     }
@@ -1446,6 +1589,20 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         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
     // ------------------------------------------------------------------------
@@ -1461,6 +1618,9 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             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) {
@@ -1468,8 +1628,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             if (fEntryList == null) {
                 rebuild();
             } else {
-                fStartTime = fTrace.getStartTime().toNanos();
-                fEndTime = fTrace.getEndTime().toNanos();
+                setStartTime(fTrace.getStartTime().toNanos());
+                setEndTime(fTrace.getEndTime().toNanos());
                 refresh();
             }
         }
@@ -1486,16 +1646,25 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         if (viewTrace == null) {
             return;
         }
+        resetView(viewTrace);
+
         List<IMarkerEventSource> markerEventSources = new ArrayList<>();
-        synchronized (fBuildThreadMap) {
+        synchronized (fBuildJobMap) {
             for (ITmfTrace trace : getTracesToBuild(viewTrace)) {
                 if (trace == null) {
                     break;
                 }
                 markerEventSources.addAll(TmfTraceAdapterManager.getAdapters(trace, IMarkerEventSource.class));
-                BuildThread buildThread = new BuildThread(trace, viewTrace, getName());
-                fBuildThreadMap.put(trace, buildThread);
-                buildThread.start();
+                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);
@@ -1521,17 +1690,40 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      * 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
@@ -1539,11 +1731,16 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      *            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
@@ -1643,9 +1840,9 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      * Get the list of current marker categories.
      *
      * @return The list of marker categories
-     * @since 2.0
+     * @since 2.1
      */
-    private @NonNull List<String> getMarkerCategories() {
+    protected @NonNull List<String> getMarkerCategories() {
         Set<String> categories = new LinkedHashSet<>(getViewMarkerCategories());
         for (IMarkerEventSource markerEventSource : getMarkerEventSources(fTrace)) {
             categories.addAll(markerEventSource.getMarkerCategories());
@@ -1673,10 +1870,12 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      * 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;
                 }
@@ -1761,6 +1960,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                     startZoomThread(startTime, endTime);
                 }
                 fDirty.decrementAndGet();
+                LOGGER.info(() -> getLogMessage("RefreshEnd", null)); //$NON-NLS-1$
             }
         });
     }
@@ -1777,9 +1977,11 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                 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;
                 }
@@ -1793,6 +1995,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                         fRedrawState = State.IDLE;
                     }
                 }
+                LOGGER.info(() -> getLogMessage("RedrawEnd", null)); //$NON-NLS-1$
             }
         });
     }
@@ -1816,8 +2019,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      * @since 2.0
      */
     protected final void startZoomThread(long startTime, long endTime) {
-        long clampedStartTime = Math.min(Math.max(startTime, fStartTime), fEndTime);
-        long clampedEndTime = Math.max(Math.min(endTime, fEndTime), fStartTime);
+        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) {
@@ -1829,7 +2032,12 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         long resolution = Math.max(1, (clampedEndTime - clampedStartTime) / fDisplayWidth);
         fZoomThread = createZoomThread(clampedStartTime, clampedEndTime, resolution, restart);
         if (fZoomThread != null) {
-            fZoomThread.start();
+            // 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();
         }
@@ -2022,6 +2230,21 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         }
     }
 
+    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);
@@ -2095,4 +2318,148 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             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) {
+        }
+    }
 }
This page took 0.034731 seconds and 5 git commands to generate.