1 /* 2 * Copyright (C) 2010 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 17 package com.android.ide.eclipse.adt.internal.editors.layout.gle2; 18 19 import com.android.ide.eclipse.adt.internal.editors.IconFactory; 20 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate; 21 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; 22 23 import org.eclipse.core.resources.IMarker; 24 import org.eclipse.swt.graphics.GC; 25 import org.eclipse.swt.graphics.Image; 26 import org.eclipse.swt.graphics.ImageData; 27 import org.eclipse.swt.graphics.Rectangle; 28 import org.w3c.dom.Node; 29 30 import java.util.Collection; 31 32 import lombok.ast.libs.org.parboiled.google.collect.Lists; 33 34 /** 35 * The {@link LintOverlay} paints an icon over each view that contains at least one 36 * lint error (unless the view is smaller than the icon) 37 */ 38 public class LintOverlay extends Overlay { 39 /** Approximate size of lint overlay icons */ 40 static final int ICON_SIZE = 8; 41 /** Alpha to draw lint overlay icons with */ 42 private static final int ALPHA = 192; 43 44 private final LayoutCanvas mCanvas; 45 private Image mWarningImage; 46 private Image mErrorImage; 47 48 /** 49 * Constructs a new {@link LintOverlay} 50 * 51 * @param canvas the associated canvas 52 */ 53 public LintOverlay(LayoutCanvas canvas) { 54 mCanvas = canvas; 55 } 56 57 @Override 58 public boolean isHiding() { 59 return super.isHiding() || !AdtPrefs.getPrefs().isLintOnSave(); 60 } 61 62 @Override 63 public void paint(GC gc) { 64 LayoutEditorDelegate editor = mCanvas.getEditorDelegate(); 65 Collection<Node> nodes = editor.getLintNodes(); 66 if (nodes != null && !nodes.isEmpty()) { 67 // Copy list before iterating through it to avoid a concurrent list modification 68 // in case lint runs in the background while painting and updates this list 69 nodes = Lists.newArrayList(nodes); 70 ViewHierarchy hierarchy = mCanvas.getViewHierarchy(); 71 Image icon = getWarningIcon(); 72 ImageData imageData = icon.getImageData(); 73 int iconWidth = imageData.width; 74 int iconHeight = imageData.height; 75 CanvasTransform mHScale = mCanvas.getHorizontalTransform(); 76 CanvasTransform mVScale = mCanvas.getVerticalTransform(); 77 78 // Right/bottom edges of the canvas image; don't paint overlays outside of 79 // that. (With for example RelativeLayouts with margins rendered on smaller 80 // screens than they are intended for this can happen.) 81 int maxX = mHScale.translate(0) + mHScale.getScaledImgSize(); 82 int maxY = mVScale.translate(0) + mVScale.getScaledImgSize(); 83 84 int oldAlpha = gc.getAlpha(); 85 try { 86 gc.setAlpha(ALPHA); 87 for (Node node : nodes) { 88 CanvasViewInfo vi = hierarchy.findViewInfoFor(node); 89 if (vi != null) { 90 Rectangle bounds = vi.getAbsRect(); 91 int x = mHScale.translate(bounds.x); 92 int y = mVScale.translate(bounds.y); 93 int w = mHScale.scale(bounds.width); 94 int h = mVScale.scale(bounds.height); 95 if (w < iconWidth || h < iconHeight) { 96 // Don't draw badges on tiny widgets (including those 97 // that aren't tiny but are zoomed out too far) 98 continue; 99 } 100 101 x += w - iconWidth; 102 y += h - iconHeight; 103 104 if (x > maxX || y > maxY) { 105 continue; 106 } 107 108 boolean isError = false; 109 IMarker marker = editor.getIssueForNode(vi.getUiViewNode()); 110 if (marker != null) { 111 int severity = marker.getAttribute(IMarker.SEVERITY, 0); 112 isError = severity == IMarker.SEVERITY_ERROR; 113 } 114 115 icon = isError ? getErrorIcon() : getWarningIcon(); 116 117 gc.drawImage(icon, x, y); 118 } 119 } 120 } finally { 121 gc.setAlpha(oldAlpha); 122 } 123 } 124 } 125 126 private Image getWarningIcon() { 127 if (mWarningImage == null) { 128 mWarningImage = IconFactory.getInstance().getIcon("warning-badge"); //$NON-NLS-1$ 129 } 130 131 return mWarningImage; 132 } 133 134 private Image getErrorIcon() { 135 if (mErrorImage == null) { 136 mErrorImage = IconFactory.getInstance().getIcon("error-badge"); //$NON-NLS-1$ 137 } 138 139 return mErrorImage; 140 } 141 } 142