aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2011-06-04 10:14:46 -0700
committerTor Norbye <tnorbye@google.com>2011-06-06 15:06:02 -0700
commitbc095ab3017f4127ba3d4cf86499db21a5a19b76 (patch)
treeabce49f5253ffe1892675df74031257707c4b101 /eclipse
parentc38d9301959fec24347cc612e0929e1ec01ac20c (diff)
downloadsdk-bc095ab3017f4127ba3d4cf86499db21a5a19b76.zip
sdk-bc095ab3017f4127ba3d4cf86499db21a5a19b76.tar.gz
sdk-bc095ab3017f4127ba3d4cf86499db21a5a19b76.tar.bz2
Show previews of resources in the resource & reference choosers
This is a first cut of previews in the Resource Chooser and the Reference Chooser. When the selected resource is a drawable or a color, then a tray is shown on the right hand side of the dialog with a preview of the given drawable or color. If the color is a state list, then the fallback color is shown. The previews only work for resource/reference choosers associated with a layout editor (because it looks up the associated rendering configuration from that editor). This should be made more generic such that it can work for example when bringing up the resource chooser from a manifest form editor. Change-Id: I9f2896cb7ce1468076a3ca83f820be7e9affcda6
Diffstat (limited to 'eclipse')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java26
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtils.java44
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PreviewIconFactory.java106
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java11
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java76
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java10
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceHelper.java121
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ReferenceChooserDialog.java20
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java10
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourcePreviewHelper.java184
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/AdtUtilsTest.java32
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java11
15 files changed, 557 insertions, 112 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java
index a33323e..f7d8d5d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java
@@ -40,6 +40,9 @@ public class ImageViewRule extends BaseViewRule {
new PropertySettingNodeHandler(ANDROID_URI, ATTR_SRC,
src.length() > 0 ? src : null));
return;
+ } else {
+ // Remove the view; the insertion was canceled
+ parent.removeChild(node);
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java
index e7c5157..d89acb5 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java
@@ -108,6 +108,14 @@ public class AdtConstants {
public final static String DOT_RES = DOT + EXT_RES;
/** Dot-Extension for PNG files, i.e. ".png" */
public static final String DOT_PNG = ".png"; //$NON-NLS-1$
+ /** Dot-Extension for 9-patch files, i.e. ".9.png" */
+ public static final String DOT_9PNG = ".9.png"; //$NON-NLS-1$
+ /** Dot-Extension for GIF files, i.e. ".gif" */
+ public static final String DOT_GIF = ".gif"; //$NON-NLS-1$
+ /** Dot-Extension for JPEG files, i.e. ".jpg" */
+ public static final String DOT_JPG = ".jpg"; //$NON-NLS-1$
+ /** Dot-Extension for BMP files, i.e. ".bmp" */
+ public static final String DOT_BMP = ".bmp"; //$NON-NLS-1$
/** Name of the android sources directory */
public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
new file mode 100644
index 0000000..bd40d1b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 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;
+
+
+/** Utility methods for ADT */
+public class AdtUtils {
+ public static boolean endsWithIgnoreCase(String string, String suffix) {
+ return string.regionMatches(true /* ignoreCase */, string.length() - suffix.length(),
+ suffix, 0, suffix.length());
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java
index 7af89f8..d04e3d6 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java
@@ -71,6 +71,13 @@ public class ImageControl extends Canvas implements MouseTrackListener {
});
}
+ public void setImage(Image image) {
+ if (mDisposeImage) {
+ mImage.dispose();
+ }
+ mImage = image;
+ }
+
public void setScale(float scale) {
mScale = scale;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtils.java
index b574eae..fbeecb9 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtils.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtils.java
@@ -15,6 +15,13 @@
*/
package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_9PNG;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_BMP;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_GIF;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_JPG;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_PNG;
+import static com.android.ide.eclipse.adt.AdtUtils.endsWithIgnoreCase;
+
import com.android.ide.common.api.Rect;
import org.eclipse.swt.graphics.RGB;
@@ -484,8 +491,8 @@ public class ImageUtils {
public static BufferedImage scale(BufferedImage source, double xScale, double yScale) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
- int destWidth = (int) (xScale * sourceWidth);
- int destHeight = (int) (yScale * sourceHeight);
+ int destWidth = Math.max(1, (int) (xScale * sourceWidth));
+ int destHeight = Math.max(1, (int) (yScale * sourceHeight));
BufferedImage scaled = new BufferedImage(destWidth, destHeight, source.getType());
Graphics2D g2 = scaled.createGraphics();
g2.setComposite(AlphaComposite.Src);
@@ -500,4 +507,37 @@ public class ImageUtils {
return scaled;
}
+
+ /**
+ * Returns true if the given file path points to an image file recognized by
+ * Android. See http://developer.android.com/guide/appendix/media-formats.html
+ * for details.
+ *
+ * @param path the filename to be tested
+ * @return true if the file represents an image file
+ */
+ public static boolean hasImageExtension(String path) {
+ return endsWithIgnoreCase(path, DOT_PNG)
+ || endsWithIgnoreCase(path, DOT_9PNG)
+ || endsWithIgnoreCase(path, DOT_GIF)
+ || endsWithIgnoreCase(path, DOT_JPG)
+ || endsWithIgnoreCase(path, DOT_BMP);
+ }
+
+ /**
+ * Creates a new image of the given size filled with the given color
+ *
+ * @param width the width of the image
+ * @param height the height of the image
+ * @param color the color of the image
+ * @return a new image of the given size filled with the given color
+ */
+ public static BufferedImage createColoredImage(int width, int height, RGB color) {
+ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(color.red, color.green, color.blue));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+ return image;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PreviewIconFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PreviewIconFactory.java
index b2ebbf1..ae41f84 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PreviewIconFactory.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PreviewIconFactory.java
@@ -16,13 +16,11 @@
package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
-import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
import static com.android.ide.common.layout.LayoutConstants.FQCN_DATE_PICKER;
import static com.android.ide.common.layout.LayoutConstants.FQCN_EXPANDABLE_LIST_VIEW;
import static com.android.ide.common.layout.LayoutConstants.FQCN_LIST_VIEW;
import static com.android.ide.common.layout.LayoutConstants.FQCN_TIME_PICKER;
import static com.android.ide.eclipse.adt.AdtConstants.DOT_PNG;
-import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML;
import com.android.ide.common.rendering.LayoutLibrary;
import com.android.ide.common.rendering.api.Capability;
@@ -41,6 +39,7 @@ import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepos
import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository.RenderMode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
import com.android.sdklib.IAndroidTarget;
import com.android.util.Pair;
@@ -49,13 +48,10 @@ import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.RGB;
-import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
@@ -70,16 +66,12 @@ import java.util.List;
import java.util.Properties;
import javax.imageio.ImageIO;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
/**
* Factory which can provide preview icons for android views of a particular SDK and
* editor's configuration chooser
*/
public class PreviewIconFactory {
- private static final String TAG_ITEM = "item"; //$NON-NLS-1$
- private static final String ATTR_COLOR = "color"; //$NON-NLS-1$
private PaletteControl mPalette;
private RGB mBackground;
private RGB mForeground;
@@ -438,9 +430,11 @@ public class PreviewIconFactory {
*/
private RGB renderDrawableResource(String themeItemName) {
GraphicalEditorPart editor = mPalette.getEditor();
+ ResourceResolver resources = editor.getResourceResolver();
+ ResourceValue resourceValue = resources.findItemInTheme(themeItemName);
BufferedImage image = RenderService.create(editor)
.setSize(100, 100)
- .renderThemeItem(themeItemName);
+ .renderDrawable(resourceValue);
if (image != null) {
// Use the middle pixel as the color since that works better for gradients;
// solid colors work too.
@@ -453,97 +447,7 @@ public class PreviewIconFactory {
private static RGB resolveThemeColor(ResourceResolver resources, String resourceName) {
ResourceValue textColor = resources.findItemInTheme(resourceName);
- textColor = resources.resolveResValue(textColor);
- if (textColor == null) {
- return null;
- }
- String value = textColor.getValue();
-
- while (value != null) {
- if (value.startsWith("#")) { //$NON-NLS-1$
- try {
- int rgba = ImageUtils.getColor(value);
- // Drop alpha channel
- return ImageUtils.intToRgb(rgba);
- } catch (NumberFormatException nfe) {
- ;
- }
- return null;
- }
- if (value.startsWith("@")) { //$NON-NLS-1$
- boolean isFramework = textColor.isFramework();
- textColor = resources.findResValue(value, isFramework);
- if (textColor != null) {
- value = textColor.getValue();
- } else {
- break;
- }
- } else {
- File file = new File(value);
- if (file.exists() && file.getName().endsWith(DOT_XML)) {
- // Parse
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- BufferedInputStream bis = null;
- try {
- bis = new BufferedInputStream(new FileInputStream(file));
- InputSource is = new InputSource(bis);
- factory.setNamespaceAware(true);
- factory.setValidating(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
- Document document = builder.parse(is);
- NodeList items = document.getElementsByTagName(TAG_ITEM);
-
- value = findColorValue(items);
- continue;
- } catch (Exception e) {
- AdtPlugin.log(e, "Failed parsing color file %1$s", file.getName());
- } finally {
- if (bis != null) {
- try {
- bis.close();
- } catch (IOException e) {
- // Nothing useful can be done here
- }
- }
- }
- }
-
- return null;
- }
- }
-
- return null;
- }
-
- /**
- * Searches a color XML file for the color definition element that does not
- * have an associated state and returns its color
- */
- private static String findColorValue(NodeList items) {
- for (int i = 0, n = items.getLength(); i < n; i++) {
- // Find non-state color definition
- Node item = items.item(i);
- boolean hasState = false;
- if (item.getNodeType() == Node.ELEMENT_NODE) {
- Element element = (Element) item;
- if (element.hasAttributeNS(ANDROID_URI, ATTR_COLOR)) {
- NamedNodeMap attributes = element.getAttributes();
- for (int j = 0, m = attributes.getLength(); j < m; j++) {
- Attr attribute = (Attr) attributes.item(j);
- if (attribute.getLocalName().startsWith("state_")) { //$NON-NLS-1$
- hasState = true;
- break;
- }
- }
-
- if (!hasState) {
- return element.getAttributeNS(ANDROID_URI, ATTR_COLOR);
- }
- }
- }
- }
-
- return null;
+ return ResourceHelper.resolveColor(resources, textColor);
}
private String getFileName(ElementDescriptor descriptor) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
index bee1289..36cea84 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
@@ -387,16 +387,19 @@ public class RenderService {
}
/**
- * Renders the given resource which should refer to a drawable and returns it
+ * Renders the given resource value (which should refer to a drawable) and returns it
* as an image
*
- * @param itemName the theme item to be looked up and rendered
+ * @param drawableResourceValue the drawable resource value to be rendered, or null
* @return the image, or null if something went wrong
*/
- public BufferedImage renderThemeItem(String itemName) {
+ public BufferedImage renderDrawable(ResourceValue drawableResourceValue) {
+ if (drawableResourceValue == null) {
+ return null;
+ }
+
finishConfiguration();
- ResourceValue drawableResourceValue = mResourceResolver.findItemInTheme(itemName);
DrawableParams params = new DrawableParams(drawableResourceValue, mProject, mWidth, mHeight,
mDensity, mXdpi, mYdpi, mResourceResolver, mProjectCallback, mMinSdkVersion,
mTargetSdkVersion, mLogger);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java
index 3d872c7..22ebf10 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java
@@ -17,13 +17,17 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
import com.android.ide.common.api.Rect;
+import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
+import java.awt.Graphics;
import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.WritableRaster;
import java.util.List;
@@ -61,6 +65,44 @@ public class SwtUtils {
}
/**
+ * Returns true if the given type of {@link BufferedImage} is supported for
+ * conversion. For unsupported formats, use
+ * {@link #convertToCompatibleFormat(BufferedImage)} first.
+ *
+ * @param imageType the {@link BufferedImage#getType()}
+ * @return true if we can convert the given buffered image format
+ */
+ private static boolean isSupportedPaletteType(int imageType) {
+ switch (imageType) {
+ case BufferedImage.TYPE_INT_RGB:
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ case BufferedImage.TYPE_3BYTE_BGR:
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** Converts the given arbitrary {@link BufferedImage} to another {@link BufferedImage}
+ * in a format that is supported (see {@link #isSupportedPaletteType(int)})
+ *
+ * @param image the image to be converted
+ * @return a new image that is in a guaranteed compatible format
+ */
+ private static BufferedImage convertToCompatibleFormat(BufferedImage image) {
+ BufferedImage converted = new BufferedImage(image.getWidth(), image.getHeight(),
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics graphics = converted.getGraphics();
+ graphics.drawImage(image, 0, 0, null);
+ graphics.dispose();
+
+ return converted;
+ }
+
+ /**
* Converts an AWT {@link BufferedImage} into an equivalent SWT {@link Image}. Whether
* the transparency data is transferred is optional, and this method can also apply an
* alpha adjustment during the conversion.
@@ -79,16 +121,31 @@ public class SwtUtils {
*/
public static Image convertToSwt(Display display, BufferedImage awtImage,
boolean transferAlpha, int globalAlpha) {
+ if (!isSupportedPaletteType(awtImage.getType())) {
+ awtImage = convertToCompatibleFormat(awtImage);
+ }
+
int width = awtImage.getWidth();
int height = awtImage.getHeight();
WritableRaster raster = awtImage.getRaster();
- int[] imageDataBuffer = ((DataBufferInt) raster.getDataBuffer()).getData();
-
+ DataBuffer dataBuffer = raster.getDataBuffer();
ImageData imageData =
new ImageData(width, height, 32, getAwtPaletteData(awtImage.getType()));
- imageData.setPixels(0, 0, imageDataBuffer.length, imageDataBuffer, 0);
+ if (dataBuffer instanceof DataBufferInt) {
+ int[] imageDataBuffer = ((DataBufferInt) dataBuffer).getData();
+ imageData.setPixels(0, 0, imageDataBuffer.length, imageDataBuffer, 0);
+ } else if (dataBuffer instanceof DataBufferByte) {
+ byte[] imageDataBuffer = ((DataBufferByte) dataBuffer).getData();
+ try {
+ imageData.setPixels(0, 0, imageDataBuffer.length, imageDataBuffer, 0);
+ } catch (SWTException se) {
+ // Unsupported depth
+ return convertToSwt(display, convertToCompatibleFormat(awtImage),
+ transferAlpha, globalAlpha);
+ }
+ }
if (transferAlpha) {
byte[] alphaData = new byte[height * width];
@@ -250,6 +307,19 @@ public class SwtUtils {
}
/**
+ * Creates a new empty/blank image of the given size
+ *
+ * @param display the display to associate the image with
+ * @param width the width of the image
+ * @param height the height of the image
+ * @return a new blank image of the given size
+ */
+ public static Image createEmptyImage(Display display, int width, int height) {
+ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ return SwtUtils.convertToSwt(display, image, false, 0);
+ }
+
+ /**
* Converts the given SWT {@link Rectangle} into an ADT {@link Rect}
*
* @param swtRect the SWT {@link Rectangle}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java
index e775420..5f60911 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java
@@ -30,6 +30,7 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.actions.AddCompatibilityJarAction;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderService;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionManager;
@@ -40,6 +41,7 @@ import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.ide.eclipse.adt.internal.ui.MarginChooser;
+import com.android.ide.eclipse.adt.internal.ui.ResourcePreviewHelper;
import com.android.ide.eclipse.adt.internal.ui.ReferenceChooserDialog;
import com.android.ide.eclipse.adt.internal.ui.ResourceChooser;
import com.android.resources.ResourceType;
@@ -180,7 +182,8 @@ class ClientRulesEngine implements IClientRulesEngine {
}
public String displayReferenceInput(String currentValue) {
- AndroidXmlEditor editor = mRulesEngine.getEditor().getLayoutEditor();
+ GraphicalEditorPart graphicalEditor = mRulesEngine.getEditor();
+ AndroidXmlEditor editor = graphicalEditor.getLayoutEditor();
IProject project = editor.getProject();
if (project != null) {
// get the resource repository for this project and the system resources.
@@ -194,6 +197,7 @@ class ClientRulesEngine implements IClientRulesEngine {
project,
projectRepository,
shell);
+ dlg.setPreviewHelper(new ResourcePreviewHelper(dlg, graphicalEditor));
dlg.setCurrentResource(currentValue);
@@ -211,7 +215,8 @@ class ClientRulesEngine implements IClientRulesEngine {
private String displayResourceInput(String resourceTypeName, String currentValue,
IInputValidator validator) {
- AndroidXmlEditor editor = mRulesEngine.getEditor().getLayoutEditor();
+ GraphicalEditorPart graphicalEditor = mRulesEngine.getEditor();
+ AndroidXmlEditor editor = graphicalEditor.getLayoutEditor();
IProject project = editor.getProject();
ResourceType type = ResourceType.getEnum(resourceTypeName);
if (project != null) {
@@ -229,6 +234,7 @@ class ClientRulesEngine implements IClientRulesEngine {
// open a resource chooser dialog for specified resource type.
ResourceChooser dlg = new ResourceChooser(project, type, projectRepository,
systemRepository, shell);
+ dlg.setPreviewHelper(new ResourcePreviewHelper(dlg, graphicalEditor));
if (validator != null) {
// Ensure wide enough to accommodate validator error message
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceHelper.java
index 467ae49..107ac4e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceHelper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceHelper.java
@@ -17,15 +17,19 @@
package com.android.ide.eclipse.adt.internal.resources;
import static com.android.AndroidConstants.FD_RES_VALUES;
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
import static com.android.ide.common.resources.ResourceResolver.PREFIX_ANDROID_STYLE;
import static com.android.ide.common.resources.ResourceResolver.PREFIX_STYLE;
import static com.android.ide.eclipse.adt.AdtConstants.ANDROID_PKG;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML;
import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML;
import static com.android.ide.eclipse.adt.AdtConstants.WS_SEP;
import static com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors.NAME_ATTR;
import static com.android.sdklib.SdkConstants.FD_RESOURCES;
+import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.resources.ResourceDeltaKind;
+import com.android.ide.common.resources.ResourceResolver;
import com.android.ide.common.resources.configuration.CountryCodeQualifier;
import com.android.ide.common.resources.configuration.DockModeQualifier;
import com.android.ide.common.resources.configuration.FolderConfiguration;
@@ -48,6 +52,7 @@ import com.android.ide.common.resources.configuration.VersionQualifier;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils;
import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.VisualRefactoring;
import com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors;
import com.android.ide.eclipse.adt.internal.editors.xml.Hyperlinks;
@@ -67,19 +72,27 @@ import org.eclipse.core.runtime.Path;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGB;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
+import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
+import org.xml.sax.InputSource;
+import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
@@ -87,12 +100,18 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
/**
* Helper class to deal with SWT specifics for the resources.
*/
@SuppressWarnings("restriction") // XML model
public class ResourceHelper {
+ private static final String TAG_ITEM = "item"; //$NON-NLS-1$
+ private static final String ATTR_COLOR = "color"; //$NON-NLS-1$
+
private final static Map<Class<?>, Image> sIconMap = new HashMap<Class<?>, Image>(
FolderConfiguration.getQualifierCount());
@@ -443,4 +462,106 @@ public class ResourceHelper {
}
return layoutName;
}
+
+ /**
+ * Tries to resolve the given resource value to an actual RGB color. For state lists
+ * it will pick the simplest/fallback color.
+ *
+ * @param resources the resource resolver to use to follow color references
+ * @param color the color to resolve
+ * @return the corresponding {@link RGB} color, or null
+ */
+ public static RGB resolveColor(ResourceResolver resources, ResourceValue color) {
+ color = resources.resolveResValue(color);
+ if (color == null) {
+ return null;
+ }
+ String value = color.getValue();
+
+ while (value != null) {
+ if (value.startsWith("#")) { //$NON-NLS-1$
+ try {
+ int rgba = ImageUtils.getColor(value);
+ // Drop alpha channel
+ return ImageUtils.intToRgb(rgba);
+ } catch (NumberFormatException nfe) {
+ ;
+ }
+ return null;
+ }
+ if (value.startsWith("@")) { //$NON-NLS-1$
+ boolean isFramework = color.isFramework();
+ color = resources.findResValue(value, isFramework);
+ if (color != null) {
+ value = color.getValue();
+ } else {
+ break;
+ }
+ } else {
+ File file = new File(value);
+ if (file.exists() && file.getName().endsWith(DOT_XML)) {
+ // Parse
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ BufferedInputStream bis = null;
+ try {
+ bis = new BufferedInputStream(new FileInputStream(file));
+ InputSource is = new InputSource(bis);
+ factory.setNamespaceAware(true);
+ factory.setValidating(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.parse(is);
+ NodeList items = document.getElementsByTagName(TAG_ITEM);
+
+ value = findColorValue(items);
+ continue;
+ } catch (Exception e) {
+ AdtPlugin.log(e, "Failed parsing color file %1$s", file.getName());
+ } finally {
+ if (bis != null) {
+ try {
+ bis.close();
+ } catch (IOException e) {
+ // Nothing useful can be done here
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Searches a color XML file for the color definition element that does not
+ * have an associated state and returns its color
+ */
+ private static String findColorValue(NodeList items) {
+ for (int i = 0, n = items.getLength(); i < n; i++) {
+ // Find non-state color definition
+ Node item = items.item(i);
+ boolean hasState = false;
+ if (item.getNodeType() == Node.ELEMENT_NODE) {
+ Element element = (Element) item;
+ if (element.hasAttributeNS(ANDROID_URI, ATTR_COLOR)) {
+ NamedNodeMap attributes = element.getAttributes();
+ for (int j = 0, m = attributes.getLength(); j < m; j++) {
+ Attr attribute = (Attr) attributes.item(j);
+ if (attribute.getLocalName().startsWith("state_")) { //$NON-NLS-1$
+ hasState = true;
+ break;
+ }
+ }
+
+ if (!hasState) {
+ return element.getAttributeNS(ANDROID_URI, ATTR_COLOR);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ReferenceChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ReferenceChooserDialog.java
index b436471..caf05aa 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ReferenceChooserDialog.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ReferenceChooserDialog.java
@@ -72,6 +72,7 @@ public class ReferenceChooserDialog extends SelectionStatusDialog {
private Button mNewResButton;
private final IProject mProject;
private TreeViewer mTreeViewer;
+ private ResourcePreviewHelper mPreviewHelper;
/**
* @param project
@@ -92,6 +93,10 @@ public class ReferenceChooserDialog extends SelectionStatusDialog {
setDialogBoundsSettings(sDialogSettings, getDialogBoundsStrategy());
}
+ public void setPreviewHelper(ResourcePreviewHelper previewHelper) {
+ mPreviewHelper = previewHelper;
+ }
+
public void setCurrentResource(String resource) {
mCurrentResource = resource;
}
@@ -183,6 +188,21 @@ public class ReferenceChooserDialog extends SelectionStatusDialog {
protected void handleSelection() {
validateCurrentSelection();
updateNewResButton();
+
+ if (mPreviewHelper != null) {
+ TreePath treeSelection = getSelection();
+ ResourceType type = null;
+ if (treeSelection != null && treeSelection.getSegmentCount() == 2) {
+ Object segment = treeSelection.getSegment(0);
+ if (segment instanceof ResourceType) {
+ type = (ResourceType) segment;
+ // Ensure that mCurrentResource is valid
+ computeResult();
+ }
+ }
+
+ mPreviewHelper.updatePreview(type, mCurrentResource);
+ }
}
protected void handleDoubleClick() {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java
index 5388b4e..fc026e4 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourceChooser.java
@@ -80,6 +80,7 @@ public class ResourceChooser extends AbstractElementListSelectionDialog {
private String mCurrentResource;
private final IProject mProject;
private IInputValidator mInputValidator;
+ private ResourcePreviewHelper mPreviewHelper;
/**
* Creates a Resource Chooser dialog.
@@ -111,6 +112,10 @@ public class ResourceChooser extends AbstractElementListSelectionDialog {
mResourceType.getDisplayName().toLowerCase()));
}
+ public void setPreviewHelper(ResourcePreviewHelper previewHelper) {
+ mPreviewHelper = previewHelper;
+ }
+
@Override
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, CLEAR_BUTTON_ID, "Clear", false /*defaultButton*/);
@@ -255,6 +260,11 @@ public class ResourceChooser extends AbstractElementListSelectionDialog {
updateStatus(status);
}
}
+
+ if (mPreviewHelper != null) {
+ computeResult();
+ mPreviewHelper.updatePreview(mResourceType, mCurrentResource);
+ }
}
private String createNewValue(ResourceType type) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourcePreviewHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourcePreviewHelper.java
new file mode 100644
index 0000000..d26cbae
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ResourcePreviewHelper.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011 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.ui;
+
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_9PNG;
+import static com.android.ide.eclipse.adt.AdtUtils.endsWithIgnoreCase;
+
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.resources.ResourceResolver;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderService;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SwtUtils;
+import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
+import com.android.resources.ResourceType;
+
+import org.eclipse.jface.dialogs.DialogTray;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+/**
+ * The {@link ResourcePreviewHelper} provides help to {@link TrayDialog} resource choosers
+ * where some resources (such as drawables and colors) are previewed in the tray area.
+ */
+public class ResourcePreviewHelper {
+ /**
+ * The width of the preview rendering
+ * <p>
+ * TODO: Make the preview rendering resize if the tray area is resized
+ */
+ private static final int WIDTH = 100;
+ /** The height of the preview rendering */
+ private static final int HEIGHT = 100;
+
+ private final GraphicalEditorPart mEditor;
+ private final TrayDialog mTrayDialog;
+
+ private boolean mShowingPreview;
+ private DialogTray mPreviewTray;
+ private ImageControl mPreviewImageControl;
+
+ /**
+ * Constructs a new {@link ResourcePreviewHelper}.
+ * <p>
+ * TODO: Add support for performing previews without an associated graphical editor,
+ * such as previewing icons from the manifest form editor; just pick default
+ * configuration settings in that case.
+ *
+ * @param trayDialog the associated tray-capable dialog
+ * @param editor a graphical editor. This is currently needed in order to provide
+ * configuration data for the rendering.
+ */
+ public ResourcePreviewHelper(TrayDialog trayDialog, GraphicalEditorPart editor) {
+ this.mTrayDialog = trayDialog;
+ this.mEditor = editor;
+ }
+
+ /**
+ * Updates the preview based on the current selection and resource type, possibly
+ * hiding or opening the tray in the process.
+ *
+ * @param type the resource type for the selected resource
+ * @param resource the full resource url
+ */
+ public void updatePreview(ResourceType type, String resource) {
+ boolean showPreview = type == ResourceType.DRAWABLE || type == ResourceType.COLOR;
+ if (showPreview) {
+ if (mPreviewTray == null) {
+ mPreviewTray = new DialogTray() {
+ @Override
+ protected Control createContents(Composite parent) {
+ // This creates a centered image control
+ Composite panel = new Composite(parent, SWT.NONE);
+ panel.setLayout(new GridLayout(3, false));
+ Label dummy1 = new Label(panel, SWT.NONE);
+ dummy1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true, 1, 1));
+ mPreviewImageControl = new ImageControl(panel, SWT.NONE, SwtUtils
+ .createEmptyImage(parent.getDisplay(), WIDTH, HEIGHT));
+ GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1);
+ gd.widthHint = WIDTH;
+ gd.heightHint = HEIGHT;
+ mPreviewImageControl.setLayoutData(gd);
+ Label dummy2 = new Label(panel, SWT.NONE);
+ dummy2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true, 1, 1));
+
+ return panel;
+ }
+
+ };
+ }
+
+ if (!mShowingPreview) {
+ mTrayDialog.openTray(mPreviewTray);
+ }
+
+ BufferedImage image = null;
+ if (type == ResourceType.COLOR) {
+ ResourceResolver resources = mEditor.getResourceResolver();
+ ResourceValue value = resources.findResValue(resource, false);
+ if (value != null) {
+ RGB color = ResourceHelper.resolveColor(resources, value);
+ if (color != null) {
+ image = ImageUtils.createColoredImage(WIDTH, HEIGHT, color);
+ }
+ }
+ } else {
+ assert type == ResourceType.DRAWABLE;
+
+ ResourceResolver resources = mEditor.getResourceResolver();
+ ResourceValue drawable = resources.findResValue(resource, false);
+ if (drawable != null) {
+ String path = drawable.getValue();
+
+ // Special-case image files (other than 9-patch files) and render these
+ // directly, in order to provide proper aspect ratio handling and
+ // to handle scaling to show the full contents:
+ if (ImageUtils.hasImageExtension(path)
+ && !endsWithIgnoreCase(path, DOT_9PNG)) {
+ File file = new File(path);
+ if (file.exists()) {
+ try {
+ image = ImageIO.read(file);
+ int width = image.getWidth();
+ int height = image.getHeight();
+ if (width > WIDTH || height > HEIGHT) {
+ double xScale = WIDTH / (double) width;
+ double yScale = HEIGHT / (double) height;
+ double scale = Math.min(xScale, yScale);
+ image = ImageUtils.scale(image, scale, scale);
+ }
+ } catch (IOException e) {
+ AdtPlugin.log(e, "Can't read preview image %1$s", path);
+ }
+ }
+ }
+
+ if (image == null) {
+ RenderService renderService = RenderService.create(mEditor);
+ renderService.setSize(WIDTH, HEIGHT);
+ image = renderService.renderDrawable(drawable);
+ }
+ }
+ }
+ Display display = mEditor.getSite().getShell().getDisplay();
+ if (image != null) {
+ mPreviewImageControl.setImage(SwtUtils.convertToSwt(display, image, true, -1));
+ } else {
+ mPreviewImageControl.setImage(SwtUtils.createEmptyImage(display, WIDTH, HEIGHT));
+ }
+ mPreviewImageControl.redraw();
+ } else if (mPreviewTray != null && mShowingPreview) {
+ mTrayDialog.closeTray();
+ }
+ mShowingPreview = showPreview;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/AdtUtilsTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/AdtUtilsTest.java
new file mode 100644
index 0000000..01fbe1b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/AdtUtilsTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 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;
+
+import junit.framework.TestCase;
+
+public class AdtUtilsTest extends TestCase {
+ public void testEndsWithIgnoreCase() {
+ assertTrue(AdtUtils.endsWithIgnoreCase("foo", "foo"));
+ assertTrue(AdtUtils.endsWithIgnoreCase("foo", "Foo"));
+ assertTrue(AdtUtils.endsWithIgnoreCase("foo", "foo"));
+ assertTrue(AdtUtils.endsWithIgnoreCase("Barfoo", "foo"));
+ assertTrue(AdtUtils.endsWithIgnoreCase("BarFoo", "foo"));
+ assertTrue(AdtUtils.endsWithIgnoreCase("BarFoo", "foO"));
+
+ assertFalse(AdtUtils.endsWithIgnoreCase("foob", "foo"));
+ assertFalse(AdtUtils.endsWithIgnoreCase("foo", "fo"));
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java
index 8f08fe9..4bd0bba 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java
@@ -17,6 +17,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
import com.android.ide.common.api.Rect;
+import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import java.awt.Color;
@@ -345,4 +346,14 @@ public class ImageUtilsTest extends TestCase {
assertEquals(0xFFFF0000, scaled.getRGB(100, 100));
assertEquals(0xFF00FF00, scaled.getRGB(199, 199));
}
+
+ public void testCreateColoredImage() throws Exception {
+ BufferedImage image = ImageUtils.createColoredImage(120, 110, new RGB(0xFE, 0xFD, 0xFC));
+ assertEquals(120, image.getWidth());
+ assertEquals(110, image.getHeight());
+ assertEquals(0xFFFEFDFC, image.getRGB(0, 0));
+ assertEquals(0xFFFEFDFC, image.getRGB(50, 50));
+ assertEquals(0xFFFEFDFC, image.getRGB(119, 109));
+ }
+
}