tmf: Add an abstract state system time graph view
authorPatrick Tasse <patrick.tasse@gmail.com>
Thu, 16 Jul 2015 21:38:11 +0000 (17:38 -0400)
committerPatrick Tasse <patrick.tasse@gmail.com>
Wed, 5 Aug 2015 20:12:00 +0000 (16:12 -0400)
This subclass of the abstract time graph view can be used when the time
events are built using a state system. The full states of the state
system are first queried chronologically for the whole time range using
a time resolution, and the list of full states is kept in memory and
reused by every time graph entry to build its time event list. This
avoids repeatedly loading the state system nodes from disk for each time
graph entry, which can be very slow if the full time range queries
require more nodes than is available in the state system cache.

Change-Id: I7dcac5d546a84462dba0e5a0cf320ba18d3617f5
Signed-off-by: Patrick Tasse <patrick.tasse@gmail.com>
Reviewed-on: https://git.eclipse.org/r/52965
Reviewed-by: Hudson CI
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Tested-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractStateSystemTimeGraphView.java [new file with mode: 0644]
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java

diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractStateSystemTimeGraphView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractStateSystemTimeGraphView.java
new file mode 100644 (file)
index 0000000..f1daa92
--- /dev/null
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.timegraph;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
+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.TimeGraphEntry;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
+/**
+ * An abstract time graph view where each entry's time event list is populated
+ * from a state system. The state system full state is queried in chronological
+ * order before creating the time event lists as this is optimal for state
+ * system queries.
+ *
+ * @since 1.1
+ */
+public abstract class AbstractStateSystemTimeGraphView extends AbstractTimeGraphView {
+
+    // ------------------------------------------------------------------------
+    // Constants
+    // ------------------------------------------------------------------------
+
+    private static final long MAX_INTERVALS = 1000000;
+
+    // ------------------------------------------------------------------------
+    // Fields
+    // ------------------------------------------------------------------------
+
+    /** The state system to entry list hash map */
+    private final Map<ITmfStateSystem, List<TimeGraphEntry>> fSSEntryListMap = new HashMap<>();
+
+    /** The trace to state system multi map */
+    private final Multimap<ITmfTrace, ITmfStateSystem> fTraceSSMap = HashMultimap.create();
+
+    // ------------------------------------------------------------------------
+    // Classes
+    // ------------------------------------------------------------------------
+
+    /**
+     * Handler for state system queries
+     */
+    public interface IQueryHandler {
+        /**
+         * Handle a full or partial list of full states. This can be called many
+         * times for the same query if the query result is split, in which case
+         * the previous full state is null only the first time it is called, and
+         * set to the last full state of the previous call from then on.
+         *
+         * @param fullStates
+         *            the list of full states
+         * @param prevFullState
+         *            the previous full state, or null
+         */
+        void handle(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState);
+    }
+
+    private class ZoomThreadByTime extends ZoomThread {
+        private final @NonNull List<ITmfStateSystem> fZoomSSList;
+        private boolean fClearZoomedLists;
+
+        public ZoomThreadByTime(@NonNull List<ITmfStateSystem> ssList, long startTime, long endTime, long resolution, boolean restart) {
+            super(startTime, endTime, resolution);
+            fZoomSSList = ssList;
+            fClearZoomedLists = !restart;
+        }
+
+        @Override
+        public void run() {
+            final List<ILinkEvent> links = new ArrayList<>();
+            if (fClearZoomedLists) {
+                clearZoomedLists();
+            }
+            for (ITmfStateSystem ss : fZoomSSList) {
+                List<TimeGraphEntry> entryList = null;
+                synchronized (fSSEntryListMap) {
+                    entryList = fSSEntryListMap.get(ss);
+                }
+                if (entryList != null) {
+                    zoomByTime(ss, entryList, links, getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
+                }
+            }
+            if (!getMonitor().isCanceled()) {
+                getTimeGraphViewer().setLinks(links);
+            }
+        }
+
+        @Override
+        public void cancel() {
+            super.cancel();
+            if (fClearZoomedLists) {
+                clearZoomedLists();
+            }
+        }
+
+        private void zoomByTime(final ITmfStateSystem ss, final List<TimeGraphEntry> entryList, final List<ILinkEvent> links,
+                long startTime, long endTime, long resolution, final @NonNull IProgressMonitor monitor) {
+            final long start = Math.max(startTime, ss.getStartTime());
+            final long end = Math.min(endTime, ss.getCurrentEndTime());
+            final boolean fullRange = getZoomStartTime() <= getStartTime() && getZoomEndTime() >= getEndTime();
+            if (end < start) {
+                return;
+            }
+            if (fullRange) {
+                redraw();
+            }
+            queryFullStates(ss, start, end, resolution, monitor, new IQueryHandler() {
+                @Override
+                public void handle(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState) {
+                    if (!fullRange) {
+                        for (TimeGraphEntry entry : entryList) {
+                            zoom(checkNotNull(entry), ss, fullStates, prevFullState, monitor);
+                        }
+                    }
+                    /* Refresh the arrows when zooming */
+                    links.addAll(getLinkList(ss, fullStates, monitor));
+                }
+            });
+            refresh();
+        }
+
+        private void zoom(@NonNull TimeGraphEntry entry, ITmfStateSystem ss, @NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, @NonNull IProgressMonitor monitor) {
+            List<ITimeEvent> eventList = getEventList(entry, ss, fullStates, prevFullState, monitor);
+            if (eventList != null) {
+                for (ITimeEvent event : eventList) {
+                    entry.addZoomedEvent(event);
+                }
+            }
+            for (ITimeGraphEntry child : entry.getChildren()) {
+                if (monitor.isCanceled()) {
+                    return;
+                }
+                if (child instanceof TimeGraphEntry) {
+                    zoom((TimeGraphEntry) child, ss, fullStates, prevFullState, monitor);
+                }
+            }
+        }
+
+        private void clearZoomedLists() {
+            for (ITmfStateSystem ss : fZoomSSList) {
+                List<TimeGraphEntry> entryList = null;
+                synchronized (fSSEntryListMap) {
+                    entryList = fSSEntryListMap.get(ss);
+                }
+                if (entryList != null) {
+                    for (TimeGraphEntry entry : entryList) {
+                        clearZoomedList(entry);
+                    }
+                }
+            }
+            fClearZoomedLists = false;
+        }
+
+        private void clearZoomedList(TimeGraphEntry entry) {
+            entry.setZoomedEventList(null);
+            for (ITimeGraphEntry child : entry.getChildren()) {
+                if (child instanceof TimeGraphEntry) {
+                    clearZoomedList((TimeGraphEntry) child);
+                }
+            }
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+
+    /**
+     * Constructs a time graph view that contains either a time graph viewer or
+     * a time graph combo.
+     *
+     * By default, the view uses a time graph viewer. To use a time graph combo,
+     * the subclass constructor must call {@link #setTreeColumns(String[])} and
+     * {@link #setTreeLabelProvider(TreeLabelProvider)}.
+     *
+     * @param id
+     *            The id of the view
+     * @param pres
+     *            The presentation provider
+     */
+    public AbstractStateSystemTimeGraphView(String id, TimeGraphPresentationProvider pres) {
+        super(id, pres);
+    }
+
+    // ------------------------------------------------------------------------
+    // Internal
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the entry list for a state system
+     *
+     * @param ss
+     *            the state system
+     *
+     * @return the entry list map
+     */
+    protected List<TimeGraphEntry> getEntryList(ITmfStateSystem ss) {
+        synchronized (fSSEntryListMap) {
+            return fSSEntryListMap.get(ss);
+        }
+    }
+
+    /**
+     * Adds a trace entry list to the entry list map
+     *
+     * @param trace
+     *            the trace
+     * @param ss
+     *            the state system
+     * @param list
+     *            the list of time graph entries
+     */
+    protected void putEntryList(ITmfTrace trace, ITmfStateSystem ss, List<TimeGraphEntry> list) {
+        super.putEntryList(trace, list);
+        synchronized (fSSEntryListMap) {
+            fSSEntryListMap.put(ss, new CopyOnWriteArrayList<>(list));
+            fTraceSSMap.put(trace, ss);
+        }
+    }
+
+    /**
+     * Adds a list of entries to a trace's entry list
+     *
+     * @param trace
+     *            the trace
+     * @param ss
+     *            the state system
+     * @param list
+     *            the list of time graph entries to add
+     */
+    protected void addToEntryList(ITmfTrace trace, ITmfStateSystem ss, List<TimeGraphEntry> list) {
+        super.addToEntryList(trace, list);
+        synchronized (fSSEntryListMap) {
+            List<TimeGraphEntry> entryList = fSSEntryListMap.get(ss);
+            if (entryList == null) {
+                fSSEntryListMap.put(ss, new CopyOnWriteArrayList<>(list));
+            } else {
+                entryList.addAll(list);
+            }
+            fTraceSSMap.put(trace, ss);
+        }
+    }
+
+    /**
+     * Removes a list of entries from a trace's entry list
+     *
+     * @param trace
+     *            the trace
+     * @param ss
+     *            the state system
+     * @param list
+     *            the list of time graph entries to remove
+     */
+    protected void removeFromEntryList(ITmfTrace trace, ITmfStateSystem ss, List<TimeGraphEntry> list) {
+        super.removeFromEntryList(trace, list);
+        synchronized (fSSEntryListMap) {
+            List<TimeGraphEntry> entryList = fSSEntryListMap.get(ss);
+            if (entryList != null) {
+                entryList.removeAll(list);
+                if (entryList.isEmpty()) {
+                    fTraceSSMap.remove(trace, ss);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected @Nullable ZoomThread createZoomThread(long startTime, long endTime, long resolution, boolean restart) {
+        List<ITmfStateSystem> ssList = null;
+        synchronized (fSSEntryListMap) {
+            ssList = new ArrayList<>(fTraceSSMap.get(getTrace()));
+        }
+        if (ssList.isEmpty()) {
+            return null;
+        }
+        return new ZoomThreadByTime(ssList, startTime, endTime, resolution, restart);
+    }
+
+    /**
+     * Query the state system full state for the given time range.
+     *
+     * @param ss
+     *            The state system
+     * @param start
+     *            The start time
+     * @param end
+     *            The end time
+     * @param resolution
+     *            The resolution
+     * @param monitor
+     *            The progress monitor
+     * @param handler
+     *            The query handler
+     */
+    protected void queryFullStates(ITmfStateSystem ss, long start, long end, long resolution,
+            @NonNull IProgressMonitor monitor, @NonNull IQueryHandler handler) {
+        List<List<ITmfStateInterval>> fullStates = new ArrayList<>();
+        List<ITmfStateInterval> prevFullState = null;
+        try {
+            long time = start;
+            while (true) {
+                if (monitor.isCanceled()) {
+                    break;
+                }
+                List<ITmfStateInterval> fullState = ss.queryFullState(time);
+                fullStates.add(fullState);
+                if (fullStates.size() * fullState.size() > MAX_INTERVALS) {
+                    handler.handle(fullStates, prevFullState);
+                    prevFullState = fullStates.get(fullStates.size() - 1);
+                    fullStates.clear();
+                }
+                if (time >= end) {
+                    break;
+                }
+                time = Math.min(end, time + resolution);
+            }
+            if (fullStates.size() > 0) {
+                handler.handle(fullStates, prevFullState);
+            }
+        } catch (StateSystemDisposedException e) {
+            /* Ignored */
+        }
+    }
+
+    /**
+     * Gets the list of events for an entry for a given list of full states.
+     *
+     * @param tgentry
+     *            The time graph entry
+     * @param ss
+     *            The state system
+     * @param fullStates
+     *            A list of full states
+     * @param prevFullState
+     *            The previous full state, or null
+     * @param monitor
+     *            A progress monitor
+     * @return The list of time graph events
+     * @since 1.1
+     */
+    protected abstract @Nullable List<ITimeEvent> getEventList(@NonNull TimeGraphEntry tgentry, ITmfStateSystem ss,
+            @NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, @NonNull IProgressMonitor monitor);
+
+    /**
+     * Gets the list of links (displayed as arrows) for a given list of full
+     * states. The default implementation returns an empty list.
+     *
+     * @param ss
+     *            The state system
+     * @param fullStates
+     *            A list of full states
+     * @param monitor
+     *            A progress monitor
+     * @return The list of link events
+     */
+    protected @NonNull List<ILinkEvent> getLinkList(ITmfStateSystem ss,
+            @NonNull List<List<ITmfStateInterval>> fullStates, @NonNull IProgressMonitor monitor) {
+        return new ArrayList<>();
+    }
+
+    /**
+     * @deprecated The subclass should call {@link #getEntryList(ITmfStateSystem)} instead.
+     */
+    @Deprecated
+    @Override
+    protected final List<TimeGraphEntry> getEntryList(ITmfTrace trace) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @deprecated The subclass should call {@link #addToEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
+     */
+    @Deprecated
+    @Override
+    protected final void addToEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @deprecated The subclass should call {@link #putEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
+     */
+    @Deprecated
+    @Override
+    protected final void putEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @deprecated The subclass should call {@link #removeFromEntryList(ITmfTrace, ITmfStateSystem, List)} instead.
+     */
+    @Deprecated
+    @Override
+    protected final void removeFromEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @deprecated The subclass should implement {@link #getEventList(TimeGraphEntry, ITmfStateSystem, List, List, IProgressMonitor)} instead.
+     */
+    @Deprecated
+    @Override
+    protected final List<ITimeEvent> getEventList(TimeGraphEntry entry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @deprecated The subclass should implement {@link #getLinkList(ITmfStateSystem, List, IProgressMonitor)} instead.
+     */
+    @Deprecated
+    @Override
+    protected final List<ILinkEvent> getLinkList(long startTime, long endTime, long resolution, IProgressMonitor monitor) {
+        throw new UnsupportedOperationException();
+    }
+
+    // ------------------------------------------------------------------------
+    // Signal handlers
+    // ------------------------------------------------------------------------
+
+    @TmfSignalHandler
+    @Override
+    public void traceClosed(final TmfTraceClosedSignal signal) {
+        super.traceClosed(signal);
+        synchronized (fSSEntryListMap) {
+            for (ITmfStateSystem ss : fTraceSSMap.removeAll(signal.getTrace())) {
+                fSSEntryListMap.remove(ss);
+            }
+        }
+    }
+}
index 9e5dfdaf79fc7aab5502e30cabe2c64a4e50cda2..7358c9f89103ac815ef85f78e2dbcdf935e62653 100644 (file)
@@ -460,35 +460,91 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         }
     }
 
-    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);
+        }
+    }
+
+    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 run() {
             for (TimeGraphEntry entry : fZoomEntryList) {
-                if (fMonitor.isCanceled()) {
+                if (getMonitor().isCanceled()) {
                     return;
                 }
                 if (entry == null) {
                     break;
                 }
-                zoom(entry, fMonitor);
+                zoom(entry, getMonitor());
             }
             /* Refresh the arrows when zooming */
-            List<ILinkEvent> events = getLinkList(fZoomStartTime, fZoomEndTime, fResolution, fMonitor);
+            List<ILinkEvent> events = getLinkList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
             if (events != null) {
                 fTimeGraphWrapper.getTimeGraphViewer().setLinks(events);
                 redraw();
@@ -496,17 +552,17 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         }
 
         private void zoom(@NonNull TimeGraphEntry entry, @NonNull IProgressMonitor monitor) {
-            if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {
+            if (getZoomStartTime() <= fStartTime && getZoomEndTime() >= fEndTime) {
                 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);
                 }
             }
             redraw();
             for (ITimeGraphEntry child : entry.getChildren()) {
-                if (fMonitor.isCanceled()) {
+                if (monitor.isCanceled()) {
                     return;
                 }
                 if (child instanceof TimeGraphEntry) {
@@ -515,9 +571,6 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             }
         }
 
-        public void cancel() {
-            fMonitor.setCanceled(true);
-        }
     }
 
     // ------------------------------------------------------------------------
@@ -939,7 +992,6 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             return;
         }
         fTrace = signal.getTrace();
-
         loadTrace();
     }
 
@@ -968,6 +1020,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             fEndTime = 0;
             if (fZoomThread != null) {
                 fZoomThread.cancel();
+                fZoomThread = null;
             }
             refresh();
         }
@@ -1048,6 +1101,10 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
     // ------------------------------------------------------------------------
 
     private void loadTrace() {
+        if (fZoomThread != null) {
+            fZoomThread.cancel();
+            fZoomThread = null;
+        }
         synchronized (fEntryListMap) {
             fEntryList = fEntryListMap.get(fTrace);
             if (fEntryList == null) {
@@ -1167,6 +1224,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      * Refresh the display
      */
     protected void refresh() {
+        final boolean zoomThread = Thread.currentThread() instanceof ZoomThread;
         TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
             @Override
             public void run() {
@@ -1188,6 +1246,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                 }
                 if (fEntryList != fTimeGraphWrapper.getInput()) {
                     fTimeGraphWrapper.setInput(fEntryList);
+                    fTimeGraphWrapper.getTimeGraphViewer().setLinks(null);
                 } else {
                     fTimeGraphWrapper.refresh();
                 }
@@ -1212,7 +1271,9 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                     }
                 }
 
-                startZoomThread(startTime, endTime);
+                if (!zoomThread) {
+                    startZoomThread(startTime, endTime);
+                }
             }
         });
     }
@@ -1250,15 +1311,40 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
     }
 
     private void startZoomThread(long startTime, long endTime) {
+        boolean restart = false;
         if (fZoomThread != null) {
             fZoomThread.cancel();
+            if (fZoomThread.fZoomStartTime == startTime && fZoomThread.fZoomEndTime == endTime) {
+                restart = true;
+            }
+        }
+        long resolution = Math.max(1, (endTime - startTime) / fDisplayWidth);
+        fZoomThread = createZoomThread(startTime, endTime, resolution, restart);
+        if (fZoomThread != null) {
+            fZoomThread.start();
         }
+    }
+
+    /**
+     * 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() {
index af63f1da43208bcaaf84fc60009ce3211178ba9c..925540e37381351ab21e1640a4d832804c4228ab 100644 (file)
@@ -1505,7 +1505,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
      * @param timeProvider
      *            The time provider
      * @param links
-     *            The array items to draw
+     *            The list of link events
      * @param nameSpace
      *            The width reserved for the names
      * @param gc
@@ -1517,8 +1517,9 @@ public class TimeGraphControl extends TimeGraphBaseControl
             return;
         }
         gc.setClipping(new Rectangle(nameSpace, 0, bounds.width - nameSpace, bounds.height));
-        for (ILinkEvent event : links) {
-            drawLink(event, bounds, timeProvider, nameSpace, gc);
+        /* the list can grow concurrently but cannot shrink */
+        for (int i = 0; i < links.size(); i++) {
+            drawLink(links.get(i), bounds, timeProvider, nameSpace, gc);
         }
         gc.setClipping((Rectangle) null);
     }
This page took 0.036054 seconds and 5 git commands to generate.