Home | History | Annotate | Download | only in gle2
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
     17 
     18 import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.LintOverlay.ICON_SIZE;
     19 
     20 import com.android.annotations.Nullable;
     21 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
     22 import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
     23 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
     24 
     25 import org.eclipse.swt.SWT;
     26 import org.eclipse.swt.graphics.Point;
     27 import org.eclipse.swt.graphics.Rectangle;
     28 import org.eclipse.swt.widgets.Event;
     29 import org.eclipse.swt.widgets.Listener;
     30 import org.eclipse.swt.widgets.Shell;
     31 import org.w3c.dom.Node;
     32 
     33 import java.util.ArrayList;
     34 import java.util.Collection;
     35 import java.util.List;
     36 
     37 /** Tooltip in the layout editor showing lint errors under the cursor */
     38 class LintTooltipManager implements Listener {
     39     private final LayoutCanvas mCanvas;
     40     private Shell mTip = null;
     41     private List<UiViewElementNode> mShowingNodes;
     42 
     43     /**
     44      * Sets up a custom tooltip when hovering over tree items. It currently displays the error
     45      * message for the lint warning associated with each node, if any (and only if the hover
     46      * is over the icon portion).
     47      */
     48     LintTooltipManager(LayoutCanvas canvas) {
     49         mCanvas = canvas;
     50     }
     51 
     52     void register() {
     53         mCanvas.addListener(SWT.Dispose, this);
     54         mCanvas.addListener(SWT.KeyDown, this);
     55         mCanvas.addListener(SWT.MouseMove, this);
     56         mCanvas.addListener(SWT.MouseHover, this);
     57     }
     58 
     59     void unregister() {
     60         if (!mCanvas.isDisposed()) {
     61             mCanvas.removeListener(SWT.Dispose, this);
     62             mCanvas.removeListener(SWT.KeyDown, this);
     63             mCanvas.removeListener(SWT.MouseMove, this);
     64             mCanvas.removeListener(SWT.MouseHover, this);
     65         }
     66     }
     67 
     68     @Override
     69     public void handleEvent(Event event) {
     70         switch(event.type) {
     71         case SWT.MouseMove:
     72             // See if we're still overlapping this or *other* errors; if so, keep the
     73             // tip up (or update it).
     74             if (mShowingNodes != null) {
     75                 List<UiViewElementNode> nodes = computeNodes(event);
     76                 if (nodes != null && !nodes.isEmpty()) {
     77                     if (nodes.equals(mShowingNodes)) {
     78                         return;
     79                     } else {
     80                         show(nodes);
     81                     }
     82                     break;
     83                 }
     84             }
     85 
     86             // If not, fall through and hide the tooltip
     87 
     88             //$FALL-THROUGH$
     89         case SWT.Dispose:
     90         case SWT.FocusOut:
     91         case SWT.KeyDown:
     92         case SWT.MouseExit:
     93         case SWT.MouseDown:
     94             hide();
     95             break;
     96         case SWT.MouseHover:
     97             hide();
     98             show(event);
     99             break;
    100         }
    101     }
    102 
    103     void hide() {
    104         if (mTip != null) {
    105             mTip.dispose();
    106             mTip = null;
    107         }
    108         mShowingNodes = null;
    109     }
    110 
    111     private void show(Event event) {
    112         List<UiViewElementNode> nodes = computeNodes(event);
    113         if (nodes != null && !nodes.isEmpty()) {
    114             show(nodes);
    115         }
    116     }
    117 
    118     /** Show a tooltip listing the lint errors for the given nodes */
    119     private void show(List<UiViewElementNode> nodes) {
    120         hide();
    121 
    122         if (!AdtPrefs.getPrefs().isLintOnSave()) {
    123             return;
    124         }
    125 
    126         mTip = new LintTooltip(mCanvas, nodes);
    127         Rectangle rect = mCanvas.getBounds();
    128         Point size = mTip.computeSize(SWT.DEFAULT, SWT.DEFAULT);
    129         Point pos = mCanvas.toDisplay(rect.x, rect.y + rect.height);
    130         if (size.x > rect.width) {
    131             size = mTip.computeSize(rect.width, SWT.DEFAULT);
    132         }
    133         mTip.setBounds(pos.x, pos.y, size.x, size.y);
    134 
    135         mShowingNodes = nodes;
    136         mTip.setVisible(true);
    137     }
    138 
    139     /**
    140      * Compute the list of nodes which have lint warnings near the given mouse
    141      * coordinates
    142      *
    143      * @param event the mouse cursor event
    144      * @return a list of nodes, possibly empty
    145      */
    146     @Nullable
    147     private List<UiViewElementNode> computeNodes(Event event) {
    148         LayoutPoint p = ControlPoint.create(mCanvas, event.x, event.y).toLayout();
    149         LayoutEditorDelegate delegate = mCanvas.getEditorDelegate();
    150         ViewHierarchy viewHierarchy = mCanvas.getViewHierarchy();
    151         CanvasTransform mHScale = mCanvas.getHorizontalTransform();
    152         CanvasTransform mVScale = mCanvas.getVerticalTransform();
    153 
    154         int layoutIconSize = mHScale.inverseScale(ICON_SIZE);
    155         int slop = mVScale.inverseScale(10); // extra space around icon where tip triggers
    156 
    157         Collection<Node> xmlNodes = delegate.getLintNodes();
    158         if (xmlNodes == null) {
    159             return null;
    160         }
    161         List<UiViewElementNode> nodes = new ArrayList<UiViewElementNode>();
    162         for (Node xmlNode : xmlNodes) {
    163             CanvasViewInfo v = viewHierarchy.findViewInfoFor(xmlNode);
    164             if (v != null) {
    165                 Rectangle b = v.getAbsRect();
    166                 int x2 = b.x + b.width;
    167                 int y2 = b.y + b.height;
    168                 if (p.x < x2 - layoutIconSize - slop
    169                         || p.x > x2 + slop
    170                         || p.y < y2 - layoutIconSize - slop
    171                         || p.y > y2 + slop) {
    172                     continue;
    173                 }
    174 
    175                 nodes.add(v.getUiViewNode());
    176             }
    177         }
    178 
    179         return nodes;
    180     }
    181 }
    182