tmf: Preserve order of marker categories
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / timegraph / AbstractTimeGraphView.java
index c22734ab4367c30b6bad4319779eac719dc61359..6ad0a95602a4e20798a41925963f7a8e36107e27 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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
@@ -22,11 +22,12 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.HashSet;
+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.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -59,10 +60,13 @@ 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.graphics.Color;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGBA;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeColumn;
 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
 import org.eclipse.tracecompass.tmf.core.resources.ITmfMarker;
@@ -134,6 +138,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
     /** The timegraph wrapper */
     private ITimeGraphWrapper fTimeGraphWrapper;
 
+    private AtomicInteger fDirty = new AtomicInteger();
+
     /** The selected trace */
     private ITmfTrace fTrace;
 
@@ -147,7 +153,10 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
     private final Map<ITmfTrace, List<TimeGraphEntry>> fEntryListMap = new HashMap<>();
 
     /** The trace to filters hash map */
-    private final Map<ITmfTrace, ViewerFilter[]> fFiltersMap = new HashMap<>();
+    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<>();
@@ -188,6 +197,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
     /** 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;
 
@@ -211,8 +222,17 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
 
     private int fAutoExpandLevel = ALL_LEVELS;
 
-    /** The list of color resources created by this view */
-    private final List<Color> fColors = new ArrayList<>();
+    /** 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;
 
     // ------------------------------------------------------------------------
     // Classes
@@ -240,9 +260,9 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
 
         Object getInput();
 
-        void setFilters(ViewerFilter[] filters);
+        void setFilters(@NonNull ViewerFilter[] filters);
 
-        ViewerFilter[] getFilters();
+        @NonNull ViewerFilter[] getFilters();
 
         void redraw();
 
@@ -263,6 +283,10 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo();
 
         int getAvailableWidth(int requestedOffset);
+
+        ITimeGraphEntry getSelection();
+
+        void setSelection(ITimeGraphEntry selection);
     }
 
     private class TimeGraphViewerWrapper implements ITimeGraphWrapper {
@@ -333,12 +357,12 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         }
 
         @Override
-        public void setFilters(ViewerFilter[] filters) {
+        public void setFilters(@NonNull ViewerFilter[] filters) {
             viewer.setFilters(filters);
         }
 
         @Override
-        public ViewerFilter[] getFilters() {
+        public @NonNull ViewerFilter[] getFilters() {
             return viewer.getFilters();
         }
 
@@ -381,6 +405,16 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         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);
+        }
     }
 
     private class TimeGraphComboWrapper implements ITimeGraphWrapper {
@@ -451,12 +485,12 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         }
 
         @Override
-        public void setFilters(ViewerFilter[] filters) {
+        public void setFilters(@NonNull ViewerFilter[] filters) {
             combo.setFilters(filters);
         }
 
         @Override
-        public ViewerFilter[] getFilters() {
+        public @NonNull ViewerFilter[] getFilters() {
             return combo.getFilters();
         }
 
@@ -507,6 +541,16 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         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);
+        }
     }
 
     /**
@@ -647,6 +691,18 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         public void cancel() {
             fMonitor.setCanceled(true);
         }
+
+        @Override
+        public final void run() {
+            doRun();
+            fDirty.decrementAndGet();
+        }
+
+        /**
+         * Run the zoom operation.
+         * @since 2.0
+         */
+        public abstract void doRun();
     }
 
     private class ZoomThreadByEntry extends ZoomThread {
@@ -658,7 +714,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         }
 
         @Override
-        public void run() {
+        public void doRun() {
             for (TimeGraphEntry entry : fZoomEntryList) {
                 if (getMonitor().isCanceled()) {
                     return;
@@ -770,8 +826,28 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      *            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;
     }
 
     /**
@@ -1076,6 +1152,9 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             combo.setTreeContentProvider(fTimeGraphContentProvider);
             combo.setTreeLabelProvider(fLabelProvider);
             combo.setTreeColumns(fColumns);
+            if (fColumnComparators != null) {
+                createColumnSelectionListener(combo.getTreeViewer());
+            }
         }
         fTimeGraphWrapper.setTimeGraphContentProvider(fTimeGraphContentProvider);
         fTimeGraphWrapper.setFilterContentProvider(fFilterContentProvider != null ? fFilterContentProvider : fTimeGraphContentProvider);
@@ -1127,7 +1206,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                                         NLS.bind(org.eclipse.tracecompass.internal.tmf.ui.Messages.TmfMarker_LocationTime,
                                                 new TmfNanoTimestamp(bookmark.getTime())));
                             }
-                            marker.setAttribute(ITmfMarker.MARKER_COLOR, bookmark.getColor().getRGBA().toString());
+                            marker.setAttribute(ITmfMarker.MARKER_COLOR, bookmark.getColor().toString());
                         }
                     }, null);
                 } catch (CoreException e) {
@@ -1144,7 +1223,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                         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().getRGBA().toString().equals(marker.getAttribute(ITmfMarker.MARKER_COLOR))) {
+                                bookmark.getColor().toString().equals(marker.getAttribute(ITmfMarker.MARKER_COLOR))) {
                             marker.delete();
                             break;
                         }
@@ -1200,12 +1279,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         }
     }
 
-    private List<IMarkerEvent> refreshBookmarks(final IFile editorFile) {
+    private static List<IMarkerEvent> refreshBookmarks(final IFile editorFile) {
         List<IMarkerEvent> bookmarks = new ArrayList<>();
-        for (Color color : fColors) {
-            color.dispose();
-        }
-        fColors.clear();
         if (editorFile == null || !editorFile.exists()) {
             return bookmarks;
         }
@@ -1224,8 +1299,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                             int green = Integer.valueOf(matcher.group(2));
                             int blue = Integer.valueOf(matcher.group(3));
                             int alpha = Integer.valueOf(matcher.group(4));
-                            Color color = new Color(Display.getDefault(), red, green, blue, alpha);
-                            fColors.add(color);
+                            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());
@@ -1239,6 +1313,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         return bookmarks;
     }
 
+
+
     // ------------------------------------------------------------------------
     // Signal handlers
     // ------------------------------------------------------------------------
@@ -1289,6 +1365,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             fEntryListMap.remove(signal.getTrace());
         }
         fFiltersMap.remove(signal.getTrace());
+        fViewContext.remove(signal.getTrace());
         if (signal.getTrace() == fTrace) {
             fTrace = null;
             fEditorFile = null;
@@ -1382,8 +1459,10 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         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;
+        restoreViewContext();
         fEditorFile = TmfTraceManager.getInstance().getTraceEditorFile(trace);
         synchronized (fEntryListMap) {
             fEntryList = fEntryListMap.get(fTrace);
@@ -1568,7 +1647,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      * @since 2.0
      */
     private @NonNull List<String> getMarkerCategories() {
-        Set<String> categories = new HashSet<>(getViewMarkerCategories());
+        Set<String> categories = new LinkedHashSet<>(getViewMarkerCategories());
         for (IMarkerEventSource markerEventSource : getMarkerEventSources(fTrace)) {
             categories.addAll(markerEventSource.getMarkerCategories());
         }
@@ -1619,16 +1698,36 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                     hasEntries = !fEntryList.isEmpty();
                 }
                 boolean inputChanged = fEntryList != fTimeGraphWrapper.getInput();
-                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);
-                } else {
-                    fTimeGraphWrapper.refresh();
+                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);
                 }
                 long startBound = (fStartTime == Long.MAX_VALUE ? SWT.DEFAULT : fStartTime);
                 long endBound = (fEndTime == Long.MIN_VALUE ? SWT.DEFAULT : fEndTime);
@@ -1660,6 +1759,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
                 if (!zoomThread) {
                     startZoomThread(startTime, endTime);
                 }
+
             }
         });
     }
@@ -1696,7 +1796,7 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         });
     }
 
-    private static void sortChildren(ITimeGraphEntry entry, Comparator<ITimeGraphEntry> comparator) {
+    private void sortChildren(ITimeGraphEntry entry, Comparator<ITimeGraphEntry> comparator) {
         if (entry instanceof TimeGraphEntry) {
             ((TimeGraphEntry) entry).sortChildren(comparator);
         }
@@ -1714,7 +1814,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
      *            the zoom end time
      * @since 2.0
      */
-    protected void startZoomThread(long startTime, long endTime) {
+    protected final void startZoomThread(long startTime, long endTime) {
+        fDirty.incrementAndGet();
         boolean restart = false;
         if (fZoomThread != null) {
             fZoomThread.cancel();
@@ -1726,6 +1827,8 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
         fZoomThread = createZoomThread(startTime, endTime, resolution, restart);
         if (fZoomThread != null) {
             fZoomThread.start();
+        } else {
+            fDirty.decrementAndGet();
         }
     }
 
@@ -1833,4 +1936,135 @@ public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeA
             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.
+     *
+     * @return true if the time graph view has yet to completely update its
+     *         model, false otherwise
+     * @since 2.0
+     */
+    public boolean isDirty() {
+        if (fZoomThread == null) {
+            return false;
+        }
+        return fDirty.get() != 0 || fZoomThread.getZoomStartTime() != fTimeGraphWrapper.getTimeGraphViewer().getTime0() || fZoomThread.getZoomEndTime() != fTimeGraphWrapper.getTimeGraphViewer().getTime1();
+    }
+
+    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 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;
+        }
+    }
 }
This page took 0.033812 seconds and 5 git commands to generate.