aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java149
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalEditorPart.java23
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java35
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParser.java334
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/ElementFigure.java10
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/LayoutFigure.java5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiElementsEditPartFactory.java15
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiLayoutEditPart.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiViewEditPart.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParserTest.java36
10 files changed, 553 insertions, 63 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java
new file mode 100644
index 0000000..8d244dd
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2009 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;
+
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
+import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.sdklib.IAndroidTarget;
+
+import org.eclipse.core.resources.IProject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class computes the new screen size in "exploded rendering" mode.
+ * It goes through the whole layout tree and figures out how many embedded layouts will have
+ * extra padding and compute how that will affect the screen size.
+ *
+ * TODO
+ * - find a better class name :)
+ * - move the logic for each layout to groovy scripts?
+ * - support custom classes (by querying JDT for its super class and reverting to its behavior)
+ */
+final class ExplodedRenderingHelper {
+ /** value of the padding in pixel.
+ * TODO: make a preference?
+ */
+ public final static int PADDING_VALUE = 10;
+
+ private final int[] mPadding = new int[] { 0, 0 };
+ private List<ElementDescriptor> mLayoutDescriptors;
+
+ ExplodedRenderingHelper(UiElementNode top, IProject iProject) {
+ // get the layout descriptor
+ IAndroidTarget target = Sdk.getCurrent().getTarget(iProject);
+ AndroidTargetData data = Sdk.getCurrent().getTargetData(target);
+ LayoutDescriptors descriptors = data.getLayoutDescriptors();
+ mLayoutDescriptors = descriptors.getLayoutDescriptors();
+
+ computePadding(top, mPadding);
+ }
+
+ /**
+ * Returns the number of extra padding in the X axis. This doesn't return a number of pixel
+ * or dip, but how many paddings are pushing the screen dimension out.
+ */
+ int getWidthPadding() {
+ return mPadding[0];
+ }
+
+ /**
+ * Returns the number of extra padding in the Y axis. This doesn't return a number of pixel
+ * or dip, but how many paddings are pushing the screen dimension out.
+ */
+ int getHeightPadding() {
+ return mPadding[1];
+ }
+
+ /**
+ * Computes the number of padding for a given view, and fills the given array of int.
+ * <p/>index 0 is X axis, index 1 is Y axis
+ * @param view the view to compute
+ * @param padding the result padding (index 0 is X axis, index 1 is Y axis)
+ */
+ private void computePadding(UiElementNode view, int[] padding) {
+ String localName = view.getDescriptor().getXmlLocalName();
+
+ // first compute for each children
+ List<UiElementNode> children = view.getUiChildren();
+ int count = children.size();
+ if (count > 0) {
+ // compute the padding for all the children.
+ List<int[]> childrenPadding = new ArrayList<int[]>(count);
+ for (int i = 0 ; i < count ; i++) {
+ UiElementNode child = children.get(i);
+ int[] p = new int[] { 0, 0 };
+ childrenPadding.add(p);
+ computePadding(child, p);
+ }
+
+ // now combine/compare based on the parent.
+ // TODO: need a better way to do this, groovy or other.
+ if (count == 1) {
+ int[] p = childrenPadding.get(0);
+ padding[0] = p[0];
+ padding[1] = p[1];
+ } else {
+ if ("LinearLayout".equals(localName)) {
+ // TODO: figure out the orientation of the layout
+ combineLinearLayout(childrenPadding, padding, false);
+ } else if ("TableLayout".equals(localName)) {
+ combineLinearLayout(childrenPadding, padding, false);
+ } else if ("TableRow".equals(localName)) {
+ combineLinearLayout(childrenPadding, padding, true);
+ } else {
+ // TODO: need to figure out what we do here
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ // if the view itself is a layout, add its padding
+ for (ElementDescriptor desc : mLayoutDescriptors) {
+ if (localName.equals(desc.getXmlName())) {
+ padding[0]++;
+ padding[1]++;
+ break;
+ }
+ }
+ }
+
+ private void combineLinearLayout(List<int[]> paddings, int[] resultPadding,
+ boolean horizontal) {
+ // The way the children are combined will depend on the direction.
+ // For instance in a vertical layout, we add the y padding as they all add to the length
+ // of the needed canvas, while we take the biggest x padding needed by the children
+
+ // the axis in which we take the sum of the padding of the children
+ int sumIndex = horizontal ? 0 : 1;
+ // the axis in which we take the max of the padding of the children
+ int maxIndex = horizontal ? 1 : 0;
+
+ int max = -1;
+ for (int[] p : paddings) {
+ resultPadding[sumIndex] += p[sumIndex];
+ if (max == -1 || max < p[maxIndex]) {
+ max = p[maxIndex];
+ }
+ }
+ resultPadding[maxIndex] = max;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalEditorPart.java
index dc6a865..1d4a71c 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalEditorPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalEditorPart.java
@@ -882,15 +882,32 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE
// get the selected theme
String theme = mConfigComposite.getTheme();
if (theme != null) {
-
// Compute the layout
- UiElementPullParser parser = new UiElementPullParser(getModel());
Rectangle rect = getBounds();
- boolean isProjectTheme = mConfigComposite.isProjectTheme();
+
+ boolean explodedView = !mConfigComposite.getClipping(); //FIXME: need new toggle
+ int width = rect.width;
+ int height = rect.height;
+ if (explodedView) {
+ // compute how many padding in x and y will bump the screen size
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(
+ getModel(), iProject);
+
+ // there are 2 paddings for each view
+ // left and right, or top and bottom.
+ int paddingValue = ExplodedRenderingHelper.PADDING_VALUE * 2;
+
+ width += helper.getWidthPadding() * paddingValue;
+ height += helper.getHeightPadding() * paddingValue;
+ }
int density = mConfigComposite.getDensity().getDpiValue();
float xdpi = mConfigComposite.getXDpi();
float ydpi = mConfigComposite.getYDpi();
+ boolean isProjectTheme = mConfigComposite.isProjectTheme();
+
+ UiElementPullParser parser = new UiElementPullParser(getModel(),
+ explodedView, density, xdpi, iProject);
ILayoutResult result = computeLayout(bridge, parser,
iProject /* projectKey */,
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java
index 7e4311f..400f729 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/GraphicalLayoutEditor.java
@@ -27,6 +27,7 @@ import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewEleme
import com.android.ide.eclipse.adt.internal.editors.layout.parts.ElementCreateCommand;
import com.android.ide.eclipse.adt.internal.editors.layout.parts.UiElementEditPart;
import com.android.ide.eclipse.adt.internal.editors.layout.parts.UiElementsEditPartFactory;
+import com.android.ide.eclipse.adt.internal.editors.layout.parts.UiElementsEditPartFactory.IOutlineProvider;
import com.android.ide.eclipse.adt.internal.editors.ui.tree.CopyCutAction;
import com.android.ide.eclipse.adt.internal.editors.ui.tree.PasteAction;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
@@ -116,7 +117,7 @@ import java.util.Map;
* @since GLE1
*/
public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
- implements IGraphicalLayoutEditor, IConfigListener, ILayoutReloadListener {
+ implements IGraphicalLayoutEditor, IConfigListener, ILayoutReloadListener, IOutlineProvider {
/** Reference to the layout editor */
@@ -187,6 +188,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
}
};
+ private boolean mExplodedView;
public GraphicalLayoutEditor(LayoutEditor layoutEditor) {
mLayoutEditor = layoutEditor;
@@ -318,7 +320,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
super.configureGraphicalViewer();
GraphicalViewer viewer = getGraphicalViewer();
- viewer.setEditPartFactory(new UiElementsEditPartFactory(mParent.getDisplay()));
+ viewer.setEditPartFactory(new UiElementsEditPartFactory(mParent.getDisplay(), this));
viewer.setRootEditPart(new ScalableFreeformRootEditPart());
// Disable the following -- we don't drag *from* the GraphicalViewer yet:
@@ -943,19 +945,36 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
// get the selected theme
String theme = mConfigComposite.getTheme();
if (theme != null) {
-
// Compute the layout
- UiElementPullParser parser = new UiElementPullParser(getModel());
Rectangle rect = getBounds();
- boolean isProjectTheme = mConfigComposite.isProjectTheme();
+
+ mExplodedView = !mConfigComposite.getClipping(); //FIXME: need new toggle
+ int width = rect.width;
+ int height = rect.height;
+ if (mExplodedView) {
+ // compute how many padding in x and y will bump the screen size
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(
+ getModel(), iProject);
+
+ // there are 2 paddings for each view
+ // left and right, or top and bottom.
+ int paddingValue = ExplodedRenderingHelper.PADDING_VALUE * 2;
+
+ width += helper.getWidthPadding() * paddingValue;
+ height += helper.getHeightPadding() * paddingValue;
+ }
int density = mConfigComposite.getDensity().getDpiValue();
float xdpi = mConfigComposite.getXDpi();
float ydpi = mConfigComposite.getYDpi();
+ boolean isProjectTheme = mConfigComposite.isProjectTheme();
+
+ UiElementPullParser parser = new UiElementPullParser(getModel(),
+ mExplodedView, density, xdpi, iProject);
ILayoutResult result = computeLayout(bridge, parser,
iProject /* projectKey */,
- rect.width, rect.height, !mConfigComposite.getClipping(),
+ width, height, !mConfigComposite.getClipping(),
density, xdpi, ydpi,
theme, isProjectTheme,
configuredProjectRes, frameworkResources, mProjectCallback,
@@ -1350,4 +1369,8 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
logger);
}
}
+
+ public boolean hasOutline() {
+ return mExplodedView;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParser.java
index 3443272..a7ecdd5 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParser.java
@@ -16,14 +16,29 @@
package com.android.ide.eclipse.adt.internal.editors.layout;
+import com.android.ide.eclipse.adt.AndroidConstants;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
+import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.layoutlib.api.IXmlPullParser;
+import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.SdkConstants;
+import org.eclipse.core.resources.IProject;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xmlpull.v1.XmlPullParserException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* {@link IXmlPullParser} implementation on top of {@link UiElementNode}.
@@ -31,24 +46,47 @@ import java.util.List;
* files.
*/
public final class UiElementPullParser extends BasePullParser {
-
+ private final static String ATTR_PADDING = "padding"; //$NON-NLS-1$
+ private final static Pattern sFloatPattern = Pattern.compile("(-?[0-9]+(?:\\.[0-9]+)?)(.*)"); //$NON-NLS-1$
+
+ private final int[] sIntOut = new int[1];
+
private final ArrayList<UiElementNode> mNodeStack = new ArrayList<UiElementNode>();
private UiElementNode mRoot;
-
- public UiElementPullParser(UiElementNode top) {
+ private final boolean mExplodedRendering;
+ private boolean mZeroAttributeIsPadding = false;
+ private boolean mIncreaseExistingPadding = false;
+ private List<ElementDescriptor> mLayoutDescriptors;
+ private final int mDensityValue;
+ private final float mXdpi;
+ private final String mDefaultPaddingValue;
+
+ public UiElementPullParser(UiElementNode top, boolean explodeRendering, int densityValue,
+ float xdpi, IProject project) {
super();
mRoot = top;
+ mExplodedRendering = explodeRendering;
+ mDensityValue = densityValue;
+ mXdpi = xdpi;
+ mDefaultPaddingValue = ExplodedRenderingHelper.PADDING_VALUE + "px"; //$NON-NLS-1$
+ if (mExplodedRendering) {
+ // get the layout descriptor
+ IAndroidTarget target = Sdk.getCurrent().getTarget(project);
+ AndroidTargetData data = Sdk.getCurrent().getTargetData(target);
+ LayoutDescriptors descriptors = data.getLayoutDescriptors();
+ mLayoutDescriptors = descriptors.getLayoutDescriptors();
+ }
push(mRoot);
}
-
+
private UiElementNode getCurrentNode() {
if (mNodeStack.size() > 0) {
return mNodeStack.get(mNodeStack.size()-1);
}
-
+
return null;
}
-
+
private Node getAttribute(int i) {
if (mParsingState != START_TAG) {
throw new IndexOutOfBoundsException();
@@ -56,7 +94,7 @@ public final class UiElementPullParser extends BasePullParser {
// get the current uiNode
UiElementNode uiNode = getCurrentNode();
-
+
// get its xml node
Node xmlNode = uiNode.getXmlNode();
@@ -66,11 +104,33 @@ public final class UiElementPullParser extends BasePullParser {
return null;
}
-
+
private void push(UiElementNode node) {
mNodeStack.add(node);
+
+ mZeroAttributeIsPadding = false;
+ mIncreaseExistingPadding = false;
+
+ if (mExplodedRendering) {
+ // first get the node name
+ String xml = node.getDescriptor().getXmlLocalName();
+ for (ElementDescriptor descriptor : mLayoutDescriptors) {
+ if (xml.equals(descriptor.getXmlLocalName())) {
+ NamedNodeMap attributes = node.getXmlNode().getAttributes();
+ Node padding = attributes.getNamedItemNS(SdkConstants.NS_RESOURCES, "padding");
+ if (padding == null) {
+ // we'll return an extra padding
+ mZeroAttributeIsPadding = true;
+ } else {
+ mIncreaseExistingPadding = true;
+ }
+
+ break;
+ }
+ }
+ }
}
-
+
private UiElementNode pop() {
return mNodeStack.remove(mNodeStack.size()-1);
}
@@ -79,7 +139,7 @@ public final class UiElementPullParser extends BasePullParser {
/**
* {@inheritDoc}
- *
+ *
* This implementation returns the underlying DOM node.
*/
public Object getViewKey() {
@@ -92,16 +152,36 @@ public final class UiElementPullParser extends BasePullParser {
return "XML DOM element depth:" + mNodeStack.size();
}
+ /*
+ * This does not seem to be called by the layoutlib, but we keep this (and maintain
+ * it) just in case.
+ */
public int getAttributeCount() {
UiElementNode node = getCurrentNode();
+
if (node != null) {
- return node.getUiAttributes().size();
+ Collection<UiAttributeNode> attributes = node.getUiAttributes();
+ int count = attributes.size();
+
+ return count + (mZeroAttributeIsPadding ? 1 : 0);
}
return 0;
}
+ /*
+ * This does not seem to be called by the layoutlib, but we keep this (and maintain
+ * it) just in case.
+ */
public String getAttributeName(int i) {
+ if (mZeroAttributeIsPadding) {
+ if (i == 0) {
+ return ATTR_PADDING;
+ } else {
+ i--;
+ }
+ }
+
Node attribute = getAttribute(i);
if (attribute != null) {
return attribute.getLocalName();
@@ -110,7 +190,19 @@ public final class UiElementPullParser extends BasePullParser {
return null;
}
+ /*
+ * This does not seem to be called by the layoutlib, but we keep this (and maintain
+ * it) just in case.
+ */
public String getAttributeNamespace(int i) {
+ if (mZeroAttributeIsPadding) {
+ if (i == 0) {
+ return SdkConstants.NS_RESOURCES;
+ } else {
+ i--;
+ }
+ }
+
Node attribute = getAttribute(i);
if (attribute != null) {
return attribute.getNamespaceURI();
@@ -118,7 +210,21 @@ public final class UiElementPullParser extends BasePullParser {
return ""; //$NON-NLS-1$
}
+ /*
+ * This does not seem to be called by the layoutlib, but we keep this (and maintain
+ * it) just in case.
+ */
public String getAttributePrefix(int i) {
+ if (mZeroAttributeIsPadding) {
+ if (i == 0) {
+ // figure out the prefix associated with the android namespace.
+ Document doc = mRoot.getXmlDocument();
+ return doc.lookupPrefix(AndroidConstants.NS_CUSTOM_RESOURCES);
+ } else {
+ i--;
+ }
+ }
+
Node attribute = getAttribute(i);
if (attribute != null) {
return attribute.getPrefix();
@@ -126,26 +232,58 @@ public final class UiElementPullParser extends BasePullParser {
return null;
}
+ /*
+ * This does not seem to be called by the layoutlib, but we keep this (and maintain
+ * it) just in case.
+ */
public String getAttributeValue(int i) {
+ if (mZeroAttributeIsPadding) {
+ if (i == 0) {
+ return mDefaultPaddingValue;
+ } else {
+ i--;
+ }
+ }
+
Node attribute = getAttribute(i);
if (attribute != null) {
- return attribute.getNodeValue();
+ String value = attribute.getNodeValue();
+ if (mIncreaseExistingPadding && ATTR_PADDING.equals(attribute.getLocalName()) &&
+ SdkConstants.NS_RESOURCES.equals(attribute.getNamespaceURI())) {
+ // add the padding and return the value
+ return addPaddingToValue(value);
+ }
+ return value;
}
-
+
return null;
}
+ /*
+ * This is the main method used by the LayoutInflater to query for attributes.
+ */
public String getAttributeValue(String namespace, String localName) {
+ if (mZeroAttributeIsPadding && ATTR_PADDING.equals(localName) &&
+ SdkConstants.NS_RESOURCES.equals(namespace)) {
+ return mDefaultPaddingValue;
+ }
+
// get the current uiNode
UiElementNode uiNode = getCurrentNode();
-
+
// get its xml node
Node xmlNode = uiNode.getXmlNode();
-
+
if (xmlNode != null) {
Node attribute = xmlNode.getAttributes().getNamedItemNS(namespace, localName);
if (attribute != null) {
- return attribute.getNodeValue();
+ String value = attribute.getNodeValue();
+ if (mIncreaseExistingPadding && ATTR_PADDING.equals(localName) &&
+ SdkConstants.NS_RESOURCES.equals(namespace)) {
+ // add the padding and return the value
+ return addPaddingToValue(value);
+ }
+ return value;
}
}
@@ -174,10 +312,8 @@ public final class UiElementPullParser extends BasePullParser {
public String getPrefix() {
if (mParsingState == START_TAG || mParsingState == END_TAG) {
- // FIXME will NEVER work
- if (getCurrentNode().getDescriptor().getXmlLocalName().startsWith("android:")) { //$NON-NLS-1$
- return "android"; //$NON-NLS-1$
- }
+ Document doc = mRoot.getXmlDocument();
+ return doc.lookupPrefix(getCurrentNode().getDescriptor().getNamespace());
}
return null;
@@ -187,16 +323,16 @@ public final class UiElementPullParser extends BasePullParser {
if (mParsingState == START_TAG) {
return getCurrentNode().getUiChildren().size() == 0;
}
-
+
throw new XmlPullParserException("Call to isEmptyElementTag while not in START_TAG",
this, null);
}
-
+
@Override
public void onNextFromStartDocument() {
onNextFromStartTag();
}
-
+
@Override
public void onNextFromStartTag() {
// get the current node, and look for text or children (children first)
@@ -205,7 +341,7 @@ public final class UiElementPullParser extends BasePullParser {
if (children.size() > 0) {
// move to the new child, and don't change the state.
push(children.get(0));
-
+
// in case the current state is CURRENT_DOC, we set the proper state.
mParsingState = START_TAG;
} else {
@@ -217,7 +353,7 @@ public final class UiElementPullParser extends BasePullParser {
}
}
}
-
+
@Override
public void onNextFromEndTag() {
// look for a sibling. if no sibling, go back to the parent
@@ -232,7 +368,7 @@ public final class UiElementPullParser extends BasePullParser {
} else {
// move back to the parent
pop();
-
+
// we have only one element left (mRoot), then we're done with the document.
if (mNodeStack.size() == 1) {
mParsingState = END_DOCUMENT;
@@ -241,4 +377,150 @@ public final class UiElementPullParser extends BasePullParser {
}
}
}
+
+ // ------- TypedValue stuff
+ // This is adapted from com.android.layoutlib.bridge.ResourceHelper
+ // (but modified to directly take the parsed value and convert it into pixel instead of
+ // storing it into a TypedValue)
+ // this was originally taken from platform/frameworks/base/libs/utils/ResourceTypes.cpp
+
+ private static final class DimensionEntry {
+ String name;
+ int type;
+
+ DimensionEntry(String name, int unit) {
+ this.name = name;
+ this.type = unit;
+ }
+ }
+
+ /** {@link #TYPE_DIMENSION} complex unit: Value is raw pixels. */
+ public static final int COMPLEX_UNIT_PX = 0;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is Device Independent
+ * Pixels. */
+ public static final int COMPLEX_UNIT_DIP = 1;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is a scaled pixel. */
+ public static final int COMPLEX_UNIT_SP = 2;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is in points. */
+ public static final int COMPLEX_UNIT_PT = 3;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is in inches. */
+ public static final int COMPLEX_UNIT_IN = 4;
+ /** {@link #TYPE_DIMENSION} complex unit: Value is in millimeters. */
+ public static final int COMPLEX_UNIT_MM = 5;
+
+ private final static DimensionEntry[] sDimensions = new DimensionEntry[] {
+ new DimensionEntry("px", COMPLEX_UNIT_PX),
+ new DimensionEntry("dip", COMPLEX_UNIT_DIP),
+ new DimensionEntry("dp", COMPLEX_UNIT_DIP),
+ new DimensionEntry("sp", COMPLEX_UNIT_SP),
+ new DimensionEntry("pt", COMPLEX_UNIT_PT),
+ new DimensionEntry("in", COMPLEX_UNIT_IN),
+ new DimensionEntry("mm", COMPLEX_UNIT_MM),
+ };
+
+ /**
+ * Adds padding to an existing dimension.
+ * <p/>This will resolve the attribute value (which can be px, dip, dp, sp, pt, in, mm) to
+ * a pixel value, add the padding value ({@link ExplodedRenderingHelper#PADDING_VALUE}),
+ * and then return a string with the new value as a px string ("42px");
+ * If the conversion fails, only the special padding is returned.
+ */
+ private String addPaddingToValue(String s) {
+ int padding = ExplodedRenderingHelper.PADDING_VALUE;
+ if (stringToPixel(s)) {
+ padding += sIntOut[0];
+ }
+
+ return padding + "px"; //$NON-NLS-1$
+ }
+
+ /**
+ * Convert the string into a pixel value, and puts it in {@link #sIntOut}
+ * @param s the dimension value from an XML attribute
+ * @return true if success.
+ */
+ private boolean stringToPixel(String s) {
+ // remove the space before and after
+ s.trim();
+ int len = s.length();
+
+ if (len <= 0) {
+ return false;
+ }
+
+ // check that there's no non ascii characters.
+ char[] buf = s.toCharArray();
+ for (int i = 0 ; i < len ; i++) {
+ if (buf[i] > 255) {
+ return false;
+ }
+ }
+
+ // check the first character
+ if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+ return false;
+ }
+
+ // now look for the string that is after the float...
+ Matcher m = sFloatPattern.matcher(s);
+ if (m.matches()) {
+ String f_str = m.group(1);
+ String end = m.group(2);
+
+ float f;
+ try {
+ f = Float.parseFloat(f_str);
+ } catch (NumberFormatException e) {
+ // this shouldn't happen with the regexp above.
+ return false;
+ }
+
+ if (end.length() > 0 && end.charAt(0) != ' ') {
+ // We only support dimension-type values, so try to parse the unit for dimension
+ DimensionEntry dimension = parseDimension(end);
+ if (dimension != null) {
+ // convert the value into pixel based on the dimention type
+ // This is similar to TypedValue.applyDimension()
+ switch (dimension.type) {
+ case COMPLEX_UNIT_PX:
+ // do nothing, value is already in px
+ break;
+ case COMPLEX_UNIT_DIP:
+ case COMPLEX_UNIT_SP: // intended fall-through since we don't
+ // adjust for font size
+ f *= (float)mDensityValue / Density.DEFAULT_DENSITY;
+ break;
+ case COMPLEX_UNIT_PT:
+ f *= mXdpi * (1.0f / 72);
+ break;
+ case COMPLEX_UNIT_IN:
+ f *= mXdpi;
+ break;
+ case COMPLEX_UNIT_MM:
+ f *= mXdpi * (1.0f / 25.4f);
+ break;
+ }
+
+ // store result (converted to int)
+ sIntOut[0] = (int) (f + 0.5);
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static DimensionEntry parseDimension(String str) {
+ str = str.trim();
+
+ for (DimensionEntry d : sDimensions) {
+ if (d.name.equals(str)) {
+ return d;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/ElementFigure.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/ElementFigure.java
index 23c2c9e..f3dc1ac 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/ElementFigure.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/ElementFigure.java
@@ -16,6 +16,8 @@
package com.android.ide.eclipse.adt.internal.editors.layout.parts;
+import com.android.ide.eclipse.adt.internal.editors.layout.parts.UiElementsEditPartFactory.IOutlineProvider;
+
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
@@ -34,8 +36,10 @@ class ElementFigure extends Figure {
private boolean mIsSelected;
private Rectangle mInnerBounds;
+ private final IOutlineProvider mProvider;
- public ElementFigure() {
+ public ElementFigure(IOutlineProvider provider) {
+ mProvider = provider;
setOpaque(false);
}
@@ -67,10 +71,10 @@ class ElementFigure extends Figure {
protected void paintBorder(Graphics graphics) {
super.paintBorder(graphics);
- if (mIsSelected) {
+ if (mIsSelected || (mProvider != null && mProvider.hasOutline())) {
graphics.setLineWidth(1);
graphics.setLineStyle(SWT.LINE_SOLID);
- graphics.setForegroundColor(ColorConstants.red);
+ graphics.setForegroundColor(mIsSelected ? ColorConstants.red : ColorConstants.white);
graphics.drawRectangle(getInnerBounds());
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/LayoutFigure.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/LayoutFigure.java
index 6334751..a4e3573 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/LayoutFigure.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/LayoutFigure.java
@@ -16,6 +16,7 @@
package com.android.ide.eclipse.adt.internal.editors.layout.parts;
+import com.android.ide.eclipse.adt.internal.editors.layout.parts.UiElementsEditPartFactory.IOutlineProvider;
import com.android.ide.eclipse.adt.internal.editors.layout.parts.UiLayoutEditPart.HighlightInfo;
import org.eclipse.draw2d.ColorConstants;
@@ -37,8 +38,8 @@ class LayoutFigure extends ElementFigure {
private HighlightInfo mHighlightInfo;
- public LayoutFigure() {
- super();
+ public LayoutFigure(IOutlineProvider provider) {
+ super(provider);
}
public void setHighlighInfo(HighlightInfo highlightInfo) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiElementsEditPartFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiElementsEditPartFactory.java
index 5f17937..31a1e2e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiElementsEditPartFactory.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiElementsEditPartFactory.java
@@ -34,9 +34,16 @@ import org.eclipse.swt.widgets.Display;
public class UiElementsEditPartFactory implements EditPartFactory {
private Display mDisplay;
+ private boolean mShowOutline = false;
+ private IOutlineProvider mProvider;
- public UiElementsEditPartFactory(Display display) {
+ public interface IOutlineProvider {
+ boolean hasOutline();
+ }
+
+ public UiElementsEditPartFactory(Display display, IOutlineProvider provider) {
mDisplay = display;
+ mProvider = provider;
}
public EditPart createEditPart(EditPart context, Object model) {
@@ -46,7 +53,7 @@ public class UiElementsEditPartFactory implements EditPartFactory {
UiElementNode node = (UiElementNode) model;
if (node.getDescriptor().hasChildren()) {
- return new UiLayoutEditPart(node);
+ return new UiLayoutEditPart(node, mProvider);
}
return new UiViewEditPart(node);
@@ -54,4 +61,8 @@ public class UiElementsEditPartFactory implements EditPartFactory {
return null;
}
+ public void setShowOutline(boolean showOutline) {
+ mShowOutline = showOutline;
+ }
+
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiLayoutEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiLayoutEditPart.java
index 14d6edb..d0495e2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiLayoutEditPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiLayoutEditPart.java
@@ -16,6 +16,7 @@
package com.android.ide.eclipse.adt.internal.editors.layout.parts;
+import com.android.ide.eclipse.adt.internal.editors.layout.parts.UiElementsEditPartFactory.IOutlineProvider;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import org.eclipse.draw2d.IFigure;
@@ -52,9 +53,11 @@ public final class UiLayoutEditPart extends UiElementEditPart {
}
private final HighlightInfo mHighlightInfo = new HighlightInfo();
+ private final IOutlineProvider mProvider;
- public UiLayoutEditPart(UiElementNode uiElementNode) {
+ public UiLayoutEditPart(UiElementNode uiElementNode, IOutlineProvider provider) {
super(uiElementNode);
+ mProvider = provider;
}
@Override
@@ -73,7 +76,7 @@ public final class UiLayoutEditPart extends UiElementEditPart {
@Override
protected IFigure createFigure() {
- IFigure f = new LayoutFigure();
+ IFigure f = new LayoutFigure(mProvider);
f.setLayoutManager(new XYLayout());
return f;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiViewEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiViewEditPart.java
index 430e1ce..f90bd67 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiViewEditPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/parts/UiViewEditPart.java
@@ -34,7 +34,7 @@ public class UiViewEditPart extends UiElementEditPart {
@Override
protected IFigure createFigure() {
- IFigure f = new ElementFigure();
+ IFigure f = new ElementFigure(null);
f.setLayoutManager(new XYLayout());
return f;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParserTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParserTest.java
index e234d6b..649b400 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParserTest.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParserTest.java
@@ -77,7 +77,7 @@ public class UiElementPullParserTest extends TestCase {
ElementDescriptor[] a = new ElementDescriptor[] {
buttonDescriptor, textDescriptor, linearDescriptor, relativeDescriptor
};
-
+
linearDescriptor.setChildren(a);
relativeDescriptor.setChildren(a);
@@ -85,9 +85,9 @@ public class UiElementPullParserTest extends TestCase {
ElementDescriptor rootDescriptor = new ElementDescriptor("root", "", "", "",
new AttributeDescriptor[] { }, a, false);
-
+
ui = new UiElementNode(rootDescriptor);
-
+
/* create a dummy XML file.
* <LinearLayout android:orientation="vertical">
* <Button android:name="button1" android:text="button1text"/>
@@ -101,7 +101,7 @@ public class UiElementPullParserTest extends TestCase {
null);
button1.addAttributes(SdkConstants.NS_RESOURCES, "name", "button1");
button1.addAttributes(SdkConstants.NS_RESOURCES, "text", "button1text");
-
+
// create a map of the attributes we add to the multi-attribute nodes so that
// we can more easily test the values when we parse the XML.
// This is due to some attributes showing in a certain order for a node and in a different
@@ -118,7 +118,7 @@ public class UiElementPullParserTest extends TestCase {
button2Map = new HashMap<String, String>();
button2Map.put("name", "button2");
button2Map.put("text", "button2text");
-
+
MockXmlNode text = new MockXmlNode(null /* namespace */, "TextView", Node.ELEMENT_NODE,
null);
text.addAttributes(SdkConstants.NS_RESOURCES, "name", "text1");
@@ -131,14 +131,14 @@ public class UiElementPullParserTest extends TestCase {
MockXmlNode relative = new MockXmlNode(null /* namespace */, "RelativeLayout",
Node.ELEMENT_NODE, new MockXmlNode[] { button2, text });
relative.addAttributes(SdkConstants.NS_RESOURCES, "orientation", "toto");
-
+
MockXmlNode linear = new MockXmlNode(null /* namespace */, "LinearLayout",
Node.ELEMENT_NODE, new MockXmlNode[] { button1, relative });
linear.addAttributes(SdkConstants.NS_RESOURCES, "orientation", "vertical");
-
+
MockXmlNode root = new MockXmlNode(null /* namespace */, "root", Node.ELEMENT_NODE,
new MockXmlNode[] { linear });
-
+
// put the namespace/prefix in place
root.setPrefix(SdkConstants.NS_RESOURCES, "android");
@@ -152,14 +152,14 @@ public class UiElementPullParserTest extends TestCase {
protected void tearDown() throws Exception {
super.tearDown();
}
-
+
public void testParser() {
try {
// wrap the parser around the ui element node, and start parsing
- UiElementPullParser parser = new UiElementPullParser(ui);
-
+ UiElementPullParser parser = new UiElementPullParser(ui, false, null);
+
assertEquals(XmlPullParser.START_DOCUMENT, parser.getEventType());
-
+
// top level Linear layout
assertEquals(XmlPullParser.START_TAG, parser.next());
assertEquals("LinearLayout", parser.getName());
@@ -168,7 +168,7 @@ public class UiElementPullParserTest extends TestCase {
assertEquals(SdkConstants.NS_RESOURCES, parser.getAttributeNamespace(0));
assertEquals("android", parser.getAttributePrefix(0));
assertEquals("vertical", parser.getAttributeValue(0));
-
+
// Button
assertEquals(XmlPullParser.START_TAG, parser.next());
assertEquals("Button", parser.getName());
@@ -204,14 +204,14 @@ public class UiElementPullParserTest extends TestCase {
check(parser, 1, textMap);
// end of TextView
assertEquals(XmlPullParser.END_TAG, parser.next());
-
+
// end of RelativeLayout
assertEquals(XmlPullParser.END_TAG, parser.next());
-
+
// end of top level linear layout
assertEquals(XmlPullParser.END_TAG, parser.next());
-
+
assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
} catch (XmlPullParserException e) {
e.printStackTrace();
@@ -229,11 +229,11 @@ public class UiElementPullParserTest extends TestCase {
private void check(UiElementPullParser parser, int i, HashMap<String, String> map) {
String name = parser.getAttributeName(i);
String value = parser.getAttributeValue(i);
-
+
String referenceValue = map.get(name);
assertNotNull(referenceValue);
assertEquals(referenceValue, value);
-
+
assertEquals(SdkConstants.NS_RESOURCES, parser.getAttributeNamespace(i));
assertEquals("android", parser.getAttributePrefix(i));
}