tmf: Fix some critical and major Sonar warnings
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / widgets / timegraph / widgets / TimeGraphControl.java
index 712da69de470d15b8336a629653578fdec97f0d1..59ee111f75e5eebacf888b7aa5cf51c8165d5ae2 100644 (file)
@@ -41,10 +41,15 @@ import org.eclipse.jface.viewers.AbstractTreeViewer;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.ViewerFilter;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
 import org.eclipse.swt.events.FocusEvent;
 import org.eclipse.swt.events.FocusListener;
 import org.eclipse.swt.events.KeyEvent;
@@ -74,6 +79,9 @@ import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.tracecompass.common.core.math.SaturatedArithmetic;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
 import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
 import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentSignal;
@@ -109,6 +117,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
     /** Constant indicating that all levels of the time graph should be expanded */
     public static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
 
+    private static final int DRAG_MARGIN = 5;
+
     private static final int DRAG_NONE = 0;
     private static final int DRAG_TRACE_ITEM = 1;
     private static final int DRAG_SPLIT_LINE = 2;
@@ -121,9 +131,11 @@ public class TimeGraphControl extends TimeGraphBaseControl
     private static final double ZOOM_IN_FACTOR = 0.8;
     private static final double ZOOM_OUT_FACTOR = 1.25;
 
-    private static final int SNAP_WIDTH = 2;
+    private static final int SNAP_WIDTH = 3;
     private static final int ARROW_HOVER_MAX_DIST = 5;
 
+    private static final double ARROW_RATIO = Math.sqrt(3) / 2; // base to height ratio
+
     private static final int NO_STATUS = -1;
     private static final int STATUS_WITHOUT_CURSOR_TIME = -2;
 
@@ -134,6 +146,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
 
     private static final int VERTICAL_ZOOM_DELAY = 400;
 
+    private static final String PREFERRED_WIDTH = "width"; //$NON-NLS-1$
+
     /** Resource manager */
     private LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
 
@@ -141,7 +155,9 @@ public class TimeGraphControl extends TimeGraphBaseControl
     private Color[] fEventColorMap = null;
 
     private ITimeDataProvider fTimeProvider;
+    private ITableLabelProvider fLabelProvider;
     private IStatusLineManager fStatusLineManager = null;
+    private Tree fTree = null;
     private TimeGraphScale fTimeGraphScale = null;
 
     private boolean fIsInFocus = false;
@@ -160,6 +176,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
     private boolean fHasNamespaceFocus = false;
     private long fDragTime0 = 0; // used to preserve accuracy of modified selection
     private int fIdealNameSpace = 0;
+    private boolean fAutoResizeColumns = true;
     private long fTime0bak;
     private long fTime1bak;
     private ITimeGraphPresentationProvider fTimeGraphProvider = null;
@@ -244,6 +261,16 @@ public class TimeGraphControl extends TimeGraphBaseControl
         return fTimeGraphProvider;
     }
 
+    /**
+     * Gets the time data provider used by this viewer.
+     *
+     * @return The time data provider, or <code>null</code> if not set
+     * @since 2.1
+     */
+    public ITimeDataProvider getTimeDataProvider() {
+        return fTimeProvider;
+    }
+
     /**
      * Gets the color map used by this timegraph viewer.
      *
@@ -264,6 +291,28 @@ public class TimeGraphControl extends TimeGraphBaseControl
         redraw();
     }
 
+    /**
+     * Set the label provider for the name space
+     *
+     * @param labelProvider
+     *            The label provider
+     * @since 2.3
+     */
+    public void setLabelProvider(ITableLabelProvider labelProvider) {
+        fLabelProvider = labelProvider;
+        redraw();
+    }
+
+    /**
+     * Get the label provider for the name space
+     *
+     * @return The label provider
+     * @since 2.3
+     */
+    public ITableLabelProvider getLabelProvider() {
+        return fLabelProvider;
+    }
+
     /**
      * Assign the status line manager
      *
@@ -277,6 +326,63 @@ public class TimeGraphControl extends TimeGraphBaseControl
         fStatusLineManager = statusLineManager;
     }
 
+    /**
+     * Assign the tree that represents the name space header
+     *
+     * @param tree
+     *            The tree
+     * @since 2.3
+     */
+    public void setTree(Tree tree) {
+        fTree = tree;
+    }
+
+    /**
+     * Returns the tree control associated with this time graph control. The
+     * tree is only used for column handling of the name space and contains no
+     * tree items.
+     *
+     * @return the tree control
+     * @since 2.3
+     */
+    public Tree getTree() {
+        return fTree;
+    }
+
+    /**
+     * Sets the columns for this time graph control's name space.
+     *
+     * @param columnNames
+     *            the column names
+     * @since 2.3
+     */
+    public void setColumns(String[] columnNames) {
+        for (TreeColumn column : fTree.getColumns()) {
+            column.dispose();
+        }
+        ControlListener controlListener = new ControlListener() {
+            @Override
+            public void controlResized(ControlEvent e) {
+                if (fAutoResizeColumns && ((TreeColumn) e.widget).getWidth() < (Integer) e.widget.getData(PREFERRED_WIDTH)) {
+                    fAutoResizeColumns = false;
+                }
+                redraw();
+            }
+            @Override
+            public void controlMoved(ControlEvent e) {
+                redraw();
+            }
+        };
+        for (String columnName : columnNames) {
+            TreeColumn column = new TreeColumn(fTree, SWT.LEFT);
+            column.setMoveable(true);
+            column.setText(columnName);
+            column.pack();
+            column.setData(PREFERRED_WIDTH, column.getWidth());
+            column.addControlListener(controlListener);
+        }
+    }
+
     /**
      * Assign the time graph scale
      *
@@ -833,19 +939,25 @@ public class TimeGraphControl extends TimeGraphBaseControl
         return super.setFocus();
     }
 
+    /**
+     * Returns the current selection for this time graph. If a time graph entry
+     * is selected, it will be the first element in the selection. If a time
+     * event is selected, it will be the second element in the selection.
+     *
+     * @return the current selection
+     */
     @Override
     public ISelection getSelection() {
-        TimeGraphSelection sel = new TimeGraphSelection();
-        ITimeGraphEntry trace = getSelectedTrace();
-        if (null != trace && null != fTimeProvider) {
+        ITimeGraphEntry entry = getSelectedTrace();
+        if (null != entry && null != fTimeProvider) {
             long selectedTime = fTimeProvider.getSelectionBegin();
-            ITimeEvent event = Utils.findEvent(trace, selectedTime, 0);
-            sel.add(trace);
-            if (event != null) {
-                sel.add(event);
+            ITimeEvent event = Utils.findEvent(entry, selectedTime, 0);
+            if (event == null) {
+                return new StructuredSelection(entry);
             }
+            return new StructuredSelection(new Object[] { entry, event });
         }
-        return sel;
+        return StructuredSelection.EMPTY;
     }
 
     /**
@@ -854,12 +966,11 @@ public class TimeGraphControl extends TimeGraphBaseControl
      * @return The selection
      */
     public ISelection getSelectionTrace() {
-        TimeGraphSelection sel = new TimeGraphSelection();
-        ITimeGraphEntry trace = getSelectedTrace();
-        if (null != trace) {
-            sel.add(trace);
+        ITimeGraphEntry entry = getSelectedTrace();
+        if (null != entry) {
+            return new StructuredSelection(entry);
         }
-        return sel;
+        return StructuredSelection.EMPTY;
     }
 
     /**
@@ -1385,9 +1496,13 @@ public class TimeGraphControl extends TimeGraphBaseControl
             return false;
         }
         int nameWidth = fTimeProvider.getNameSpace();
-        return Math.abs(x - nameWidth) < SNAP_WIDTH;
+        return Math.abs(x - nameWidth) <= SNAP_WIDTH;
     }
 
+    boolean isOverTimeSpace(int x, int y) {
+        Point size = getSize();
+        return x >= fTimeProvider.getNameSpace() && x < size.x && y >= 0 && y < size.y;
+    }
     /**
      * Gets the {@link ITimeGraphEntry} at the given location.
      *
@@ -1446,7 +1561,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
         int width = getSize().x;
         int nameSpace = fTimeProvider.getNameSpace();
         double pixelsPerNanoSec = (width - nameSpace <= RIGHT_MARGIN) ? 0 : (double) (width - nameSpace - RIGHT_MARGIN) / (time1 - time0);
-        int x = getBounds().x + nameSpace + (int) ((time - time0) * pixelsPerNanoSec);
+        int x = SaturatedArithmetic.add(getBounds().x + nameSpace, (int) ((time - time0) * pixelsPerNanoSec));
         return x;
     }
 
@@ -1475,6 +1590,10 @@ public class TimeGraphControl extends TimeGraphBaseControl
     }
 
     void selectItem(int idx, boolean addSelection) {
+        selectItem(idx, addSelection, true);
+    }
+
+    void selectItem(int idx, boolean addSelection, boolean reveal) {
         boolean changed = false;
         if (addSelection) {
             if (idx >= 0 && idx < fItemData.fExpandedItems.length) {
@@ -1491,25 +1610,46 @@ public class TimeGraphControl extends TimeGraphBaseControl
                 item.fSelected = i == idx;
             }
         }
-        changed |= ensureVisibleItem(idx, true);
+        if (reveal) {
+            changed |= ensureVisibleItem(idx, true);
+        }
         if (changed) {
             redraw();
         }
     }
 
     /**
-     * Callback for item selection
+     * Select an entry and make it visible
      *
-     * @param trace
-     *            The entry matching the trace
+     * @param entry
+     *            The entry to select
      * @param addSelection
-     *            If the selection is added or removed
+     *            <code>true</code> to add the entry to the current selection,
+     *            or <code>false</code> to set a new selection
      */
-    public void selectItem(ITimeGraphEntry trace, boolean addSelection) {
-        int idx = fItemData.findItemIndex(trace);
+    public void selectItem(ITimeGraphEntry entry, boolean addSelection) {
+        int idx = fItemData.findItemIndex(entry);
         selectItem(idx, addSelection);
     }
 
+    /**
+     * Select an entry
+     *
+     * @param entry
+     *            The entry to select
+     * @param addSelection
+     *            <code>true</code> to add the entry to the current selection,
+     *            or <code>false</code> to set a new selection
+     * @param reveal
+     *            <code>true</code> if the selection is to be made visible, and
+     *            <code>false</code> otherwise
+     * @since 2.3
+     */
+    public void selectItem(ITimeGraphEntry entry, boolean addSelection, boolean reveal) {
+        int idx = fItemData.findItemIndex(entry);
+        selectItem(idx, addSelection, reveal);
+    }
+
     /**
      * Retrieve the number of entries shown per page.
      *
@@ -1582,6 +1722,21 @@ public class TimeGraphControl extends TimeGraphBaseControl
         return fItemData.fExpandedItems[index].fEntry;
     }
 
+    /**
+     * Get the bounds of the specified entry
+     *
+     * @param entry the time graph entry
+     * @return the bounds of the entry, or null if the entry is not visible
+     * @since 2.3
+     */
+    public Rectangle getItemBounds(ITimeGraphEntry entry) {
+        int idx = fItemData.findItemIndex(entry);
+        if (idx >= 0) {
+            return getItemRect(getBounds(), idx);
+        }
+        return null;
+    }
+
     Rectangle getNameRect(Rectangle bounds, int idx, int nameWidth) {
         Rectangle rect = getItemRect(bounds, idx);
         rect.width = nameWidth;
@@ -1650,8 +1805,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
         long selectionBegin = fTimeProvider.getSelectionBegin();
         long selectionEnd = fTimeProvider.getSelectionEnd();
         double pixelsPerNanoSec = (bounds.width - nameSpace <= RIGHT_MARGIN) ? 0 : (double) (bounds.width - nameSpace - RIGHT_MARGIN) / (time1 - time0);
-        int x0 = bounds.x + nameSpace + (int) ((selectionBegin - time0) * pixelsPerNanoSec);
-        int x1 = bounds.x + nameSpace + (int) ((selectionEnd - time0) * pixelsPerNanoSec);
+        int x0 = SaturatedArithmetic.add(bounds.x + nameSpace, (int) ((selectionBegin - time0) * pixelsPerNanoSec));
+        int x1 = SaturatedArithmetic.add(bounds.x + nameSpace, (int) ((selectionEnd - time0) * pixelsPerNanoSec));
 
         // draw selection lines
         if (fDragState != DRAG_SELECTION) {
@@ -1688,11 +1843,16 @@ public class TimeGraphControl extends TimeGraphBaseControl
             }
         }
 
-        // draw drag line
-        if (DRAG_SPLIT_LINE == fDragState) {
-            gc.setForeground(getColorScheme().getColor(TimeGraphColorScheme.BLACK));
-            gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);
-        } else if (DRAG_ZOOM == fDragState && Math.max(fDragX, fDragX0) > nameSpace) {
+        // draw split line
+        if (DRAG_SPLIT_LINE == fDragState ||
+                (DRAG_NONE == fDragState && fMouseOverSplitLine && fTimeProvider.getNameSpace() > 0)) {
+            gc.setBackground(getColorScheme().getColor(TimeGraphColorScheme.DARK_GRAY));
+        } else {
+            gc.setBackground(getColorScheme().getColor(TimeGraphColorScheme.GRAY));
+        }
+        gc.fillRectangle(bounds.x + nameSpace - SNAP_WIDTH, bounds.y, SNAP_WIDTH, bounds.height);
+
+        if (DRAG_ZOOM == fDragState && Math.max(fDragX, fDragX0) > nameSpace) {
             gc.setForeground(getColorScheme().getColor(TimeGraphColorScheme.TOOL_FOREGROUND));
             gc.drawLine(fDragX0, bounds.y, fDragX0, bounds.y + bounds.height - 1);
             if (fDragX != fDragX0) {
@@ -1704,9 +1864,6 @@ public class TimeGraphControl extends TimeGraphBaseControl
             if (fDragX != fDragX0) {
                 gc.drawLine(fDragX, bounds.y, fDragX, bounds.y + bounds.height - 1);
             }
-        } else if (DRAG_NONE == fDragState && fMouseOverSplitLine && fTimeProvider.getNameSpace() > 0) {
-            gc.setForeground(getColorScheme().getColor(TimeGraphColorScheme.RED));
-            gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);
         }
 
         gc.setAlpha(alpha);
@@ -1750,12 +1907,10 @@ public class TimeGraphControl extends TimeGraphBaseControl
                 gc.setBackground(getColorScheme().getBkColor(true, fIsInFocus, false));
                 gc.fillRectangle(nameSpace, itemRect.y, itemRect.width - nameSpace, itemRect.height);
             }
-            // draw the name and middle line
-            if (! item.fEntry.hasTimeEvents()) {
-                drawName(item, itemRect, gc);
-            } else {
-                Rectangle nameRect = new Rectangle(itemRect.x, itemRect.y, nameSpace, itemRect.height);
-                drawName(item, nameRect, gc);
+            // draw the name space
+            Rectangle nameRect = new Rectangle(itemRect.x, itemRect.y, nameSpace, itemRect.height);
+            drawName(item, nameRect, gc);
+            if (item.fEntry.hasTimeEvents()) {
                 Rectangle rect = new Rectangle(nameSpace, itemRect.y, itemRect.width - nameSpace, itemRect.height);
                 drawMidLine(rect, gc);
             }
@@ -1942,8 +2097,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
             int lastX = -1;
             while (iterator.hasNext()) {
                 ITimeEvent event = iterator.next();
-                int x = rect.x + (int) ((event.getTime() - time0) * pixelsPerNanoSec);
-                int xEnd = rect.x + (int) ((event.getTime() + event.getDuration() - time0) * pixelsPerNanoSec);
+                int x = SaturatedArithmetic.add(rect.x, (int) ((event.getTime() - time0) * pixelsPerNanoSec));
+                int xEnd = SaturatedArithmetic.add(rect.x, (int) ((event.getTime() + event.getDuration() - time0) * pixelsPerNanoSec));
                 if (x >= rect.x + rect.width || xEnd < rect.x) {
                     // event is out of bounds
                     continue;
@@ -2112,7 +2267,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
     }
 
     /**
-     * Draw the name of an item.
+     * Draw the name space of an item.
      *
      * @param item
      *            Item object
@@ -2122,82 +2277,98 @@ public class TimeGraphControl extends TimeGraphBaseControl
      *            Graphics context
      */
     protected void drawName(Item item, Rectangle bounds, GC gc) {
-        boolean hasTimeEvents = item.fEntry.hasTimeEvents();
-
-        // No name to be drawn
+        // No name space to be drawn
         if (fTimeProvider.getNameSpace() == 0) {
             return;
         }
 
+        boolean hasTimeEvents = item.fEntry.hasTimeEvents();
+        if (hasTimeEvents) {
+            gc.setClipping(bounds);
+        }
+
         int height = bounds.height - getMarginForHeight(bounds.height);
         setFontForHeight(height, gc);
 
-        int leftMargin = MARGIN + item.fLevel * EXPAND_SIZE;
-        if (item.fHasChildren) {
-            gc.setForeground(getColorScheme().getFgColorGroup(false, false));
-            gc.setBackground(getColorScheme().getBkColor(false, false, false));
-            Rectangle rect = Utils.clone(bounds);
-            rect.x += leftMargin;
-            rect.y += (bounds.height - EXPAND_SIZE) / 2;
-            rect.width = EXPAND_SIZE;
-            rect.height = EXPAND_SIZE;
-            gc.fillRectangle(rect);
-            gc.drawRectangle(rect.x, rect.y, rect.width - 1, rect.height - 1);
-            int midy = rect.y + rect.height / 2;
-            gc.drawLine(rect.x + 2, midy, rect.x + rect.width - 3, midy);
-            if (!item.fExpanded) {
-                int midx = rect.x + rect.width / 2;
-                gc.drawLine(midx, rect.y + 2, midx, rect.y + rect.height - 3);
-            }
-        }
-        leftMargin += EXPAND_SIZE + MARGIN;
-
-        Image img = fTimeGraphProvider.getItemImage(item.fEntry);
-        if (img != null) {
-            // draw icon
-            int imgHeight = img.getImageData().height;
-            int imgWidth = img.getImageData().width;
-            int x = leftMargin;
-            int y = bounds.y + (bounds.height - imgHeight) / 2;
-            gc.drawImage(img, x, y);
-            leftMargin += imgWidth + MARGIN;
-        }
-        String name = item.fName;
-        Point size = gc.stringExtent(name);
-        if (fIdealNameSpace < leftMargin + size.x + MARGIN) {
-            fIdealNameSpace = leftMargin + size.x + MARGIN;
-        }
-        if (hasTimeEvents) {
-            // cut long string with "..."
-            int width = bounds.width - leftMargin;
-            int cuts = 0;
-            while (size.x > width && name.length() > 1) {
-                cuts++;
-                name = name.substring(0, name.length() - 1);
-                size = gc.stringExtent(name + "..."); //$NON-NLS-1$
-            }
-            if (cuts > 0) {
-                name += "..."; //$NON-NLS-1$
-            }
-        }
+        String name = fLabelProvider == null ? item.fName : fLabelProvider.getColumnText(item.fEntry, 0);
         Rectangle rect = Utils.clone(bounds);
-        rect.x += leftMargin;
-        rect.width -= leftMargin;
-        // draw text
-        if (rect.width > 0) {
-            rect.y += (bounds.height - gc.stringExtent(name).y) / 2;
+        rect.y += (bounds.height - gc.stringExtent(name).y) / 2;
+        TreeColumn[] columns = fTree.getColumns();
+        int idealNameSpace = 0;
+        for (int i = 0; i < columns.length; i++) {
+            int columnIndex = fTree.getColumnOrder()[i];
+            TreeColumn column = columns[columnIndex];
+            rect.width = column.getWidth();
+            gc.setClipping(rect.x, bounds.y, Math.min(rect.width, bounds.x + bounds.width - rect.x - SNAP_WIDTH), bounds.height);
+            int width = MARGIN;
+            if (i == 0) {
+                // first visible column
+                width += item.fLevel * EXPAND_SIZE;
+                if (item.fHasChildren) {
+                    // draw expand/collapse arrow
+                    gc.setBackground(getColorScheme().getColor(TimeGraphColorScheme.DARK_GRAY));
+                    int arrowHeightHint = (height < 4) ? height : (height < 6) ? height - 1 : height - 2;
+                    int arrowHalfHeight = Math.max(1, Math.min(arrowHeightHint, (int) Math.round((EXPAND_SIZE - 2) / ARROW_RATIO))) / 2;
+                    int arrowHalfWidth = (Math.max(1, Math.min(EXPAND_SIZE - 2, (int) Math.round(arrowHeightHint * ARROW_RATIO))) + 1) / 2;
+                    int x1 = bounds.x + width + 1;
+                    int x2 = x1 + 2 * arrowHalfWidth;
+                    int midy = bounds.y + bounds.height / 2;
+                    int y1 = midy - arrowHalfHeight;
+                    int y2 = midy + arrowHalfHeight;
+                    if (!item.fExpanded) { // >
+                        gc.fillPolygon(new int[] { x1, y1, x2, midy, x1, y2 });
+                    } else { // v
+                        int midx = x1 + arrowHalfWidth;
+                        gc.fillPolygon(new int[] { x1, y1, x2, y1, midx, y2 });
+                    }
+                }
+                width += EXPAND_SIZE + MARGIN;
+
+                Image img = fLabelProvider != null ? fLabelProvider.getColumnImage(item.fEntry, columnIndex)
+                        : columnIndex == 0 ? fTimeGraphProvider.getItemImage(item.fEntry) : null;
+                if (img != null) {
+                    // draw icon
+                    int imgHeight = img.getImageData().height;
+                    int imgWidth = img.getImageData().width;
+                    int dstHeight = Math.min(bounds.height, imgHeight);
+                    int dstWidth = dstHeight * imgWidth / imgHeight;
+                    int x = width;
+                    int y = bounds.y + (bounds.height - dstHeight) / 2;
+                    gc.drawImage(img, 0, 0, imgWidth, imgHeight, x, y, dstWidth, dstHeight);
+                    width += imgWidth + MARGIN;
+                }
+            } else {
+                if (fLabelProvider == null) {
+                    break;
+                }
+            }
+            String label = fLabelProvider != null ? fLabelProvider.getColumnText(item.fEntry, columnIndex)
+                    : columnIndex == 0 ? item.fName : ""; //$NON-NLS-1$
             gc.setForeground(getColorScheme().getFgColor(item.fSelected, fIsInFocus));
-            int textWidth = Utils.drawText(gc, name, rect, true);
-            leftMargin += textWidth + MARGIN;
-
-            if (hasTimeEvents) {
-                // draw middle line
-                rect.x = bounds.x + leftMargin;
-                rect.y = bounds.y;
-                rect.width = bounds.width - rect.x;
-                drawMidLine(rect, gc);
+            Rectangle textRect = new Rectangle(rect.x + width, rect.y, rect.width - width, rect.height);
+            int textWidth = Utils.drawText(gc, label, textRect, true);
+            width += textWidth + MARGIN;
+            if (textWidth > 0) {
+                idealNameSpace = rect.x + width;
+            }
+            if (columns.length == 1) {
+                drawMidLine(new Rectangle(bounds.x + width, bounds.y, bounds.x + bounds.width, bounds.height), gc);
             }
+            if (fAutoResizeColumns && width > column.getWidth()) {
+                column.setData(PREFERRED_WIDTH, width);
+                column.setWidth(width);
+            }
+            gc.setForeground(getColorScheme().getColor(TimeGraphColorScheme.MID_LINE));
+            if (i < columns.length - 1) {
+                // not the last visible column: draw the vertical cell border
+                int x = rect.x + rect.width - 1;
+                gc.drawLine(x, bounds.y, x, bounds.y + bounds.height);
+            }
+            rect.x += rect.width;
         }
+        fIdealNameSpace = Math.max(fIdealNameSpace, idealNameSpace);
+
+        gc.setClipping((Rectangle) null);
     }
 
     /**
@@ -2672,12 +2843,9 @@ public class TimeGraphControl extends TimeGraphBaseControl
 
     @Override
     public void mouseDown(MouseEvent e) {
-        if (fDragState != DRAG_NONE || null == fTimeProvider ||
-                fTimeProvider.getTime0() == fTimeProvider.getTime1() ||
-                getSize().x - fTimeProvider.getNameSpace() <= 0) {
+        if (fDragState != DRAG_NONE) {
             return;
         }
-        int idx;
         if (1 == e.button && (e.stateMask & SWT.MODIFIER_MASK) == 0) {
             int nameSpace = fTimeProvider.getNameSpace();
             if (nameSpace != 0 && isOverSplitLine(e.x)) {
@@ -2685,13 +2853,17 @@ public class TimeGraphControl extends TimeGraphBaseControl
                 fDragButton = e.button;
                 fDragX = e.x;
                 fDragX0 = fDragX;
-                fTime0bak = fTimeProvider.getTime0();
-                fTime1bak = fTimeProvider.getTime1();
                 redraw();
                 updateCursor(e.x, e.stateMask);
                 return;
             }
         }
+        if (fTimeProvider == null ||
+                fTimeProvider.getTime0() == fTimeProvider.getTime1() ||
+                getSize().x - fTimeProvider.getNameSpace() <= 0) {
+            return;
+        }
+        int idx;
         if (1 == e.button && ((e.stateMask & SWT.MODIFIER_MASK) == 0 || (e.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT)) {
             int nameSpace = fTimeProvider.getNameSpace();
             idx = getItemIndexAtY(e.y);
@@ -2784,19 +2956,28 @@ public class TimeGraphControl extends TimeGraphBaseControl
     @Override
     public void mouseUp(MouseEvent e) {
         if (fPendingMenuDetectEvent != null && e.button == 3) {
+            if ((fDragState == DRAG_ZOOM) && isInDragZoomMargin()) {
+                // Select entry and time event for single click
+                long time = getTimeAtX(fDragX0);
+                fTimeProvider.setSelectionRangeNotify(time, time, false);
+                int idx = getItemIndexAtY(e.y);
+                selectItem(idx, false);
+                fireSelectionChanged();
+            }
             menuDetected(fPendingMenuDetectEvent);
         }
         if (DRAG_NONE != fDragState) {
             setCapture(false);
             if (e.button == fDragButton && DRAG_TRACE_ITEM == fDragState) {
+                fDragState = DRAG_NONE;
                 if (fDragX != fDragX0) {
                     fTimeProvider.notifyStartFinishTime();
                 }
-                fDragState = DRAG_NONE;
             } else if (e.button == fDragButton && DRAG_SPLIT_LINE == fDragState) {
                 fDragState = DRAG_NONE;
                 redraw();
             }  else if (e.button == fDragButton && DRAG_SELECTION == fDragState) {
+                fDragState = DRAG_NONE;
                 if (fDragX == fDragX0) { // click without selecting anything
                     long time = getTimeAtX(e.x);
                     fTimeProvider.setSelectedTimeNotify(time, false);
@@ -2805,12 +2986,12 @@ public class TimeGraphControl extends TimeGraphBaseControl
                     long time1 = fDragBeginMarker ? fDragTime0 : getTimeAtX(fDragX);
                     fTimeProvider.setSelectionRangeNotify(time0, time1, false);
                 }
-                fDragState = DRAG_NONE;
                 redraw();
                 fTimeGraphScale.setDragRange(-1, -1);
             } else if (e.button == fDragButton && DRAG_ZOOM == fDragState) {
+                fDragState = DRAG_NONE;
                 int nameWidth = fTimeProvider.getNameSpace();
-                if (Math.max(fDragX, fDragX0) > nameWidth && fDragX != fDragX0) {
+                if ((Math.max(fDragX, fDragX0) > nameWidth) && !isInDragZoomMargin()) {
                     long time0 = getTimeAtX(fDragX0);
                     long time1 = getTimeAtX(fDragX);
                     if (time0 < time1) {
@@ -2821,7 +3002,6 @@ public class TimeGraphControl extends TimeGraphBaseControl
                 } else {
                     redraw();
                 }
-                fDragState = DRAG_NONE;
                 fTimeGraphScale.setDragRange(-1, -1);
             }
         }
@@ -3098,12 +3278,10 @@ public class TimeGraphControl extends TimeGraphBaseControl
 
     @Override
     public void setSelection(ISelection selection) {
-        if (selection instanceof TimeGraphSelection) {
-            TimeGraphSelection sel = (TimeGraphSelection) selection;
-            Object ob = sel.getFirstElement();
+        if (selection instanceof IStructuredSelection) {
+            Object ob = ((IStructuredSelection) selection).getFirstElement();
             if (ob instanceof ITimeGraphEntry) {
-                ITimeGraphEntry trace = (ITimeGraphEntry) ob;
-                selectItem(trace, false);
+                selectItem((ITimeGraphEntry) ob, false);
             }
         }
 
@@ -3129,7 +3307,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
      * Returns this control's filters.
      *
      * @return an array of viewer filters
-     * @since 2.0
+     * @since 1.2
      */
     public @NonNull ViewerFilter[] getFilters() {
         return Iterables.toArray(fFilters, ViewerFilter.class);
@@ -3140,7 +3318,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
      *
      * @param filters
      *            an array of viewer filters, or null
-     * @since 2.0
+     * @since 1.2
      */
     public void setFilters(@NonNull ViewerFilter[] filters) {
         fFilters.clear();
@@ -3325,8 +3503,13 @@ public class TimeGraphControl extends TimeGraphBaseControl
         if (null == fTimeProvider) {
             return;
         }
+        /*
+         * This flag indicates if menu was prevented from being shown below and
+         * therefore must be made visible on callback from mouseUp().
+         */
+        boolean pendingEventCallback = fPendingMenuDetectEvent != null;
         Point p = toControl(e.x, e.y);
-        if (e.detail == SWT.MENU_MOUSE) {
+        if (e.detail == SWT.MENU_MOUSE && isOverTimeSpace(p.x, p.y)) {
             if (fPendingMenuDetectEvent == null) {
                 /* Feature in Linux. The MenuDetectEvent is received before mouseDown.
                  * Store the event and trigger it later just before handling mouseUp.
@@ -3334,25 +3517,35 @@ public class TimeGraphControl extends TimeGraphBaseControl
                  */
                 fPendingMenuDetectEvent = e;
                 /*
-                 *  Prevent the platform to show the menu when returning. The
-                 *  menu will be shown (see below) when this method is called
-                 *  again during mouseup().
+                 * Prevent the platform to show the menu when returning. The
+                 * menu will be shown (see below) when this method is called
+                 * again during mouseUp().
                  */
                 e.doit = false;
                 return;
             }
             fPendingMenuDetectEvent = null;
-            if ((p.x >= fTimeProvider.getNameSpace()) && (fDragState != DRAG_ZOOM || fDragX != fDragX0)) {
+            if (fDragState != DRAG_ZOOM || !isInDragZoomMargin()) {
+                /*
+                 * Don't show the menu on mouseUp() if a drag zoom is in
+                 * progress with a drag range outside of the drag zoom margin,
+                 * or if any other drag operation, or none, is in progress.
+                 */
+                e.doit = false;
                 return;
             }
         } else {
             if (fDragState != DRAG_NONE) {
+                /*
+                 * Don't show the menu on keyboard menu or mouse menu outside of
+                 * the time space if any drag operation is in progress.
+                 */
+                e.doit = false;
                 return;
             }
         }
         int idx = getItemIndexAtY(p.y);
         if (idx >= 0 && idx < fItemData.fExpandedItems.length) {
-            e.doit = true;
             Item item = fItemData.fExpandedItems[idx];
             ITimeGraphEntry entry = item.fEntry;
 
@@ -3361,7 +3554,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
             e.data = entry;
             fireMenuEventOnTimeGraphEntry(e);
             Menu menu = getMenu();
-            if (e.doit && (menu != null)) {
+            if (pendingEventCallback && e.doit && (menu != null)) {
                 menu.setVisible(true);
             }
 
@@ -3373,7 +3566,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
                     e.data = event;
                     fireMenuEventOnTimeEvent(e);
                     menu = getMenu();
-                    if (e.doit && (menu != null)) {
+                    if (pendingEventCallback && e.doit && (menu != null)) {
                         menu.setVisible(true);
                     }
                 }
@@ -3407,4 +3600,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
     public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
         return new TmfTimeViewAlignmentInfo(getShell(), toDisplay(0, 0), fTimeProvider.getNameSpace());
     }
+
+    private boolean isInDragZoomMargin() {
+        return (Math.abs(fDragX - fDragX0) < DRAG_MARGIN);
+    }
 }
This page took 0.034782 seconds and 5 git commands to generate.