diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintTooltipManager.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintTooltipManager.java | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintTooltipManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintTooltipManager.java new file mode 100644 index 000000000..f71935889 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintTooltipManager.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ide.eclipse.adt.internal.editors.layout.gle2; + +import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.LintOverlay.ICON_SIZE; + +import com.android.annotations.Nullable; +import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate; +import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; +import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.w3c.dom.Node; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** Tooltip in the layout editor showing lint errors under the cursor */ +class LintTooltipManager implements Listener { + private final LayoutCanvas mCanvas; + private Shell mTip = null; + private List<UiViewElementNode> mShowingNodes; + + /** + * Sets up a custom tooltip when hovering over tree items. It currently displays the error + * message for the lint warning associated with each node, if any (and only if the hover + * is over the icon portion). + */ + LintTooltipManager(LayoutCanvas canvas) { + mCanvas = canvas; + } + + void register() { + mCanvas.addListener(SWT.Dispose, this); + mCanvas.addListener(SWT.KeyDown, this); + mCanvas.addListener(SWT.MouseMove, this); + mCanvas.addListener(SWT.MouseHover, this); + } + + void unregister() { + if (!mCanvas.isDisposed()) { + mCanvas.removeListener(SWT.Dispose, this); + mCanvas.removeListener(SWT.KeyDown, this); + mCanvas.removeListener(SWT.MouseMove, this); + mCanvas.removeListener(SWT.MouseHover, this); + } + } + + @Override + public void handleEvent(Event event) { + switch(event.type) { + case SWT.MouseMove: + // See if we're still overlapping this or *other* errors; if so, keep the + // tip up (or update it). + if (mShowingNodes != null) { + List<UiViewElementNode> nodes = computeNodes(event); + if (nodes != null && !nodes.isEmpty()) { + if (nodes.equals(mShowingNodes)) { + return; + } else { + show(nodes); + } + break; + } + } + + // If not, fall through and hide the tooltip + + //$FALL-THROUGH$ + case SWT.Dispose: + case SWT.FocusOut: + case SWT.KeyDown: + case SWT.MouseExit: + case SWT.MouseDown: + hide(); + break; + case SWT.MouseHover: + hide(); + show(event); + break; + } + } + + void hide() { + if (mTip != null) { + mTip.dispose(); + mTip = null; + } + mShowingNodes = null; + } + + private void show(Event event) { + List<UiViewElementNode> nodes = computeNodes(event); + if (nodes != null && !nodes.isEmpty()) { + show(nodes); + } + } + + /** Show a tooltip listing the lint errors for the given nodes */ + private void show(List<UiViewElementNode> nodes) { + hide(); + + if (!AdtPrefs.getPrefs().isLintOnSave()) { + return; + } + + mTip = new LintTooltip(mCanvas, nodes); + Rectangle rect = mCanvas.getBounds(); + Point size = mTip.computeSize(SWT.DEFAULT, SWT.DEFAULT); + Point pos = mCanvas.toDisplay(rect.x, rect.y + rect.height); + if (size.x > rect.width) { + size = mTip.computeSize(rect.width, SWT.DEFAULT); + } + mTip.setBounds(pos.x, pos.y, size.x, size.y); + + mShowingNodes = nodes; + mTip.setVisible(true); + } + + /** + * Compute the list of nodes which have lint warnings near the given mouse + * coordinates + * + * @param event the mouse cursor event + * @return a list of nodes, possibly empty + */ + @Nullable + private List<UiViewElementNode> computeNodes(Event event) { + LayoutPoint p = ControlPoint.create(mCanvas, event.x, event.y).toLayout(); + LayoutEditorDelegate delegate = mCanvas.getEditorDelegate(); + ViewHierarchy viewHierarchy = mCanvas.getViewHierarchy(); + CanvasTransform mHScale = mCanvas.getHorizontalTransform(); + CanvasTransform mVScale = mCanvas.getVerticalTransform(); + + int layoutIconSize = mHScale.inverseScale(ICON_SIZE); + int slop = mVScale.inverseScale(10); // extra space around icon where tip triggers + + Collection<Node> xmlNodes = delegate.getLintNodes(); + if (xmlNodes == null) { + return null; + } + List<UiViewElementNode> nodes = new ArrayList<UiViewElementNode>(); + for (Node xmlNode : xmlNodes) { + CanvasViewInfo v = viewHierarchy.findViewInfoFor(xmlNode); + if (v != null) { + Rectangle b = v.getAbsRect(); + int x2 = b.x + b.width; + int y2 = b.y + b.height; + if (p.x < x2 - layoutIconSize - slop + || p.x > x2 + slop + || p.y < y2 - layoutIconSize - slop + || p.y > y2 + slop) { + continue; + } + + nodes.add(v.getUiViewNode()); + } + } + + return nodes; + } +} |