aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@google.com>2010-01-26 16:04:50 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2010-01-26 16:04:50 -0800
commitcf68c35f51388b6764615a16a9585561b360b0b4 (patch)
treeb4f6cfb86a9b4861ed77495b091dcfd5a5fee2a3
parentaf44fbeb406ba3997614cabc70bf0d10d2693a50 (diff)
parentaae21fc056ff15325c5ff5158648b7c6be7728de (diff)
downloadsdk-cf68c35f51388b6764615a16a9585561b360b0b4.zip
sdk-cf68c35f51388b6764615a16a9585561b360b0b4.tar.gz
sdk-cf68c35f51388b6764615a16a9585561b360b0b4.tar.bz2
am aae21fc0: Merge "ADT/GLE: Support more layouts in explode mode." into eclair
Merge commit 'aae21fc056ff15325c5ff5158648b7c6be7728de' into eclair-plus-aosp * commit 'aae21fc056ff15325c5ff5158648b7c6be7728de': ADT/GLE: Support more layouts in explode mode.
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java337
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java17
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java18
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/ExplodeRenderingHelperTest.java257
4 files changed, 583 insertions, 46 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
index de9bb3b..62d1b6c 100644
--- 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
@@ -18,15 +18,24 @@ 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 com.android.sdklib.SdkConstants;
import org.eclipse.core.resources.IProject;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
/**
* This class computes the new screen size in "exploded rendering" mode.
@@ -45,16 +54,40 @@ public final class ExplodedRenderingHelper {
public final static int PADDING_VALUE = 10;
private final int[] mPadding = new int[] { 0, 0 };
- private List<ElementDescriptor> mLayoutDescriptors;
+ private Set<String> mLayoutNames;
- public ExplodedRenderingHelper(UiElementNode top, IProject iProject) {
- // get the layout descriptor
+ /**
+ * Computes the padding. access the result through {@link #getWidthPadding()} and
+ * {@link #getHeightPadding()}.
+ * @param root the root node (ie the top layout).
+ * @param iProject the project to which the layout belong.
+ */
+ public ExplodedRenderingHelper(Node root, IProject iProject) {
+ // get the layout descriptors to get the name of all the layout classes.
IAndroidTarget target = Sdk.getCurrent().getTarget(iProject);
AndroidTargetData data = Sdk.getCurrent().getTargetData(target);
LayoutDescriptors descriptors = data.getLayoutDescriptors();
- mLayoutDescriptors = descriptors.getLayoutDescriptors();
- computePadding(top, mPadding);
+ mLayoutNames = new HashSet<String>();
+ List<ElementDescriptor> layoutDescriptors = descriptors.getLayoutDescriptors();
+ for (ElementDescriptor desc : layoutDescriptors) {
+ mLayoutNames.add(desc.getXmlLocalName());
+ }
+
+ computePadding(root, mPadding);
+ }
+
+ /**
+ * (Unit tests only)
+ * Computes the padding. access the result through {@link #getWidthPadding()} and
+ * {@link #getHeightPadding()}.
+ * @param root the root node (ie the top layout).
+ * @param layoutNames the list of layout classes
+ */
+ ExplodedRenderingHelper(Node root, Set<String> layoutNames) {
+ mLayoutNames = layoutNames;
+
+ computePadding(root, mPadding);
}
/**
@@ -79,53 +112,76 @@ public final class ExplodedRenderingHelper {
* @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();
+ private void computePadding(Node view, int[] padding) {
+ String localName = view.getLocalName();
// first compute for each children
- List<UiElementNode> children = view.getUiChildren();
- int count = children.size();
+ NodeList children = view.getChildNodes();
+ int count = children.getLength();
if (count > 0) {
// compute the padding for all the children.
- List<int[]> childrenPadding = new ArrayList<int[]>(count);
+ Map<Node, int[]> childrenPadding = new HashMap<Node, 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);
+ Node child = children.item(i);
+ short type = child.getNodeType();
+ if (type == Node.ELEMENT_NODE) { // ignore TEXT/CDATA nodes.
+ int[] p = new int[] { 0, 0 };
+ childrenPadding.put(child, p);
+ computePadding(child, p);
+ }
}
+ // since the non ELEMENT_NODE children were filtered out, count must be updated.
+ count = childrenPadding.size();
+
// 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);
+ int[] p = childrenPadding.get(childrenPadding.keySet().iterator().next());
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);
+ if ("LinearLayout".equals(localName)) { //$NON-NLS-1$
+ String orientation = getAttribute(view, "orientation", null); //$NON-NLS-1$
+
+ // default value is horizontal
+ boolean horizontal = orientation == null ||
+ "horizontal".equals("vertical"); //$NON-NLS-1$ //$NON-NLS-2$
+ combineLinearLayout(childrenPadding.values(), padding, horizontal);
+ } else if ("TableLayout".equals(localName)) { //$NON-NLS-1$
+ combineLinearLayout(childrenPadding.values(), padding, false /*horizontal*/);
+ } else if ("TableRow".equals(localName)) { //$NON-NLS-1$
+ combineLinearLayout(childrenPadding.values(), padding, true /*true*/);
+ // TODO: properly support Relative Layouts.
+// } else if ("RelativeLayout".equals(localName)) { //$NON-NLS-1$
+// combineRelativeLayout(childrenPadding, padding);
} else {
- // unknown layouts are not exploded.
+ // unknown layout. For now, let's consider it's better to add the children
+ // margins in both dimensions than not at all.
+ for (int[] p : childrenPadding.values()) {
+ padding[0] += p[0];
+ padding[1] += p[1];
+ }
}
}
}
// if the view itself is a layout, add its padding
- for (ElementDescriptor desc : mLayoutDescriptors) {
- if (localName.equals(desc.getXmlName())) {
- padding[0]++;
- padding[1]++;
- break;
- }
+ if (mLayoutNames.contains(localName)) {
+ padding[0]++;
+ padding[1]++;
}
}
- private void combineLinearLayout(List<int[]> paddings, int[] resultPadding,
+ /**
+ * Combines the padding of the children of a linear layout.
+ * <p/>For this layout, the padding of the children are added in the direction of
+ * the layout, while the max is taken for the other direction.
+ * @param paddings the list of the padding for the children.
+ * @param resultPadding the result padding array to fill.
+ * @param horizontal whether this layout is horizontal (<code>true</code>) or vertical
+ * (<code>false</code>)
+ */
+ private void combineLinearLayout(Collection<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
@@ -145,4 +201,221 @@ public final class ExplodedRenderingHelper {
}
resultPadding[maxIndex] = max;
}
+
+ /**
+ * Combine the padding of children of a relative layout.
+ * @param childrenPadding a map of the children. This is guaranteed that the node object
+ * are of type ELEMENT_NODE
+ * @param padding
+ *
+ * TODO: Not used yet. Still need (lots of) work.
+ */
+ private void combineRelativeLayout(Map<Node, int[]> childrenPadding, int[] padding) {
+ /*
+ * Combines the children of the layout.
+ * The way this works: for each children, for each direction, look for all the chidrens
+ * connected and compute the combined margin in that direction.
+ *
+ * There's a chance the returned value will be too much. this is due to the layout sometimes
+ * dropping views which will not be dropped here. It's ok, as it's better to have too
+ * much than not enough.
+ * We could fix this by matching those UiElementNode with their bounds as returned
+ * by the rendering (ie if bounds is 0/0 in h/w, then ignore the child)
+ */
+
+ // list of the UiElementNode
+ Set<Node> nodeSet = childrenPadding.keySet();
+ // map of Id -> node
+ Map<String, Node> idNodeMap = computeIdNodeMap(nodeSet);
+
+ for (Entry<Node, int[]> entry : childrenPadding.entrySet()) {
+ Node node = entry.getKey();
+
+ // first horizontal, to the left.
+ int[] leftResult = getBiggestMarginInDirection(node, 0 /*horizontal*/,
+ "layout_toRightOf", "layout_toLeftOf", //$NON-NLS-1$ //$NON-NLS-2$
+ childrenPadding, nodeSet, idNodeMap,
+ false /*includeThisPadding*/);
+
+ // then to the right
+ int[] rightResult = getBiggestMarginInDirection(node, 0 /*horizontal*/,
+ "layout_toLeftOf", "layout_toRightOf", //$NON-NLS-1$ //$NON-NLS-2$
+ childrenPadding, nodeSet, idNodeMap,
+ false /*includeThisPadding*/);
+
+ // compute total horizontal margins
+ int[] thisPadding = childrenPadding.get(node);
+ int combinedMargin =
+ (thisPadding != null ? thisPadding[0] : 0) +
+ (leftResult != null ? leftResult[0] : 0) +
+ (rightResult != null ? rightResult[0] : 0);
+ if (combinedMargin > padding[0]) {
+ padding[0] = combinedMargin;
+ }
+
+ // first vertical, above.
+ int[] topResult = getBiggestMarginInDirection(node, 1 /*horizontal*/,
+ "layout_below", "layout_above", //$NON-NLS-1$ //$NON-NLS-2$
+ childrenPadding, nodeSet, idNodeMap,
+ false /*includeThisPadding*/);
+
+ // then below
+ int[] bottomResult = getBiggestMarginInDirection(node, 1 /*horizontal*/,
+ "layout_above", "layout_below", //$NON-NLS-1$ //$NON-NLS-2$
+ childrenPadding, nodeSet, idNodeMap,
+ false /*includeThisPadding*/);
+
+ // compute total horizontal margins
+ combinedMargin =
+ (thisPadding != null ? thisPadding[1] : 0) +
+ (topResult != null ? topResult[1] : 0) +
+ (bottomResult != null ? bottomResult[1] : 0);
+ if (combinedMargin > padding[1]) {
+ padding[1] = combinedMargin;
+ }
+ }
+ }
+
+ /**
+ * Computes the biggest margin in a given direction.
+ *
+ * TODO: Not used yet. Still need (lots of) work.
+ */
+ private int[] getBiggestMarginInDirection(Node node, int resIndex, String relativeTo,
+ String inverseRelation, Map<Node, int[]> childrenPadding,
+ Set<Node> nodeSet, Map<String, Node> idNodeMap,
+ boolean includeThisPadding) {
+ NamedNodeMap attributes = node.getAttributes();
+
+ String viewId = getAttribute(node, "id", attributes); //$NON-NLS-1$
+
+ // first get the item this one is positioned relative to.
+ String toLeftOfRef = getAttribute(node, relativeTo, attributes);
+ Node toLeftOf = null;
+ if (toLeftOfRef != null) {
+ toLeftOf = idNodeMap.get(cleanUpIdReference(toLeftOfRef));
+ }
+
+ ArrayList<Node> list = null;
+ if (viewId != null) {
+ // now to the left for items being placed to the left of this one.
+ list = getMatchingNode(nodeSet, cleanUpIdReference(viewId), inverseRelation);
+ }
+
+ // now process each children in the same direction.
+ if (toLeftOf != null) {
+ if (list == null) {
+ list = new ArrayList<Node>();
+ }
+
+ if (list.indexOf(toLeftOf) == -1) {
+ list.add(toLeftOf);
+ }
+ }
+
+ int[] thisPadding = childrenPadding.get(node);
+
+ if (list != null) {
+ // since there's a combination to do, we'll return a new result object
+ int[] result = null;
+ for (Node nodeOnLeft : list) {
+ int[] tempRes = getBiggestMarginInDirection(nodeOnLeft, resIndex, relativeTo,
+ inverseRelation, childrenPadding, nodeSet, idNodeMap, true);
+ if (tempRes != null && (result == null || result[resIndex] < tempRes[resIndex])) {
+ result = tempRes;
+ }
+ }
+
+ // return the combined padding
+ if (includeThisPadding == false || thisPadding[resIndex] == 0) {
+ // just return the one we got since this object adds no padding (or doesn't
+ // need to be comibined)
+ return result;
+ } else if (result != null) { // if result is null, the main return below is used.
+ // add the result we got with the padding from the current node
+ int[] realRes = new int [2];
+ realRes[resIndex] = thisPadding[resIndex] + result[resIndex];
+ return realRes;
+ }
+ }
+
+ // if we reach this, there were no other views to the left of this one, so just return
+ // the view padding.
+ return includeThisPadding ? thisPadding : null;
+ }
+
+ /**
+ * Computes and returns a map of (id, node) for each node of a given {@link Set}.
+ * <p/>
+ * Nodes with no id are ignored and not put in the map.
+ * @param nodes the nodes to fill the map with.
+ * @return a newly allocated, non-null, map of (id, node)
+ */
+ private Map<String, Node> computeIdNodeMap(Set<Node> nodes) {
+ Map<String, Node> map = new HashMap<String, Node>();
+ for (Node node : nodes) {
+ String viewId = getAttribute(node, "id", null); //$NON-NLS-1$
+ if (viewId != null) {
+ map.put(cleanUpIdReference(viewId), node);
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Cleans up a reference to an ID to return the ID itself only.
+ * @param reference the reference to "clean up".
+ * @return the id string only.
+ */
+ private String cleanUpIdReference(String reference) {
+ // format is @id/foo or @+id/foo or @android:id/foo, or something similar.
+ int slash = reference.indexOf('/');
+ return reference.substring(slash);
+ }
+
+ /**
+ * Returns a list of nodes for which a given attribute contains a reference to a given ID.
+ *
+ * @param nodes the list of nodes to search through
+ * @param resId the requested ID
+ * @param attribute the name of the attribute to test.
+ * @return a newly allocated, non-null, list of nodes. Could be empty.
+ */
+ private ArrayList<Node> getMatchingNode(Set<Node> nodes, String resId,
+ String attribute) {
+ ArrayList<Node> list = new ArrayList<Node>();
+
+ for (Node node : nodes) {
+ String value = getAttribute(node, attribute, null);
+ if (value != null) {
+ value = cleanUpIdReference(value);
+ if (value.equals(resId)) {
+ list.add(node);
+ }
+ }
+ }
+
+ return list;
+ }
+
+ /**
+ * Returns an attribute for a given node.
+ * @param node the node to query
+ * @param name the name of an attribute
+ * @param attributes the option {@link NamedNodeMap} object to use to read the attributes from.
+ */
+ private static String getAttribute(Node node, String name, NamedNodeMap attributes) {
+ if (attributes == null) {
+ attributes = node.getAttributes();
+ }
+
+ if (attributes != null) {
+ Node attribute = attributes.getNamedItemNS(SdkConstants.NS_RESOURCES, name);
+ if (attribute != null) {
+ return attribute.getNodeValue();
+ }
+ }
+
+ return null;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java
index 034f91e..edb5f87 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java
@@ -1009,15 +1009,18 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
int height = rect.height;
if (mUseExplodeMode) {
// compute how many padding in x and y will bump the screen size
- ExplodedRenderingHelper helper = new ExplodedRenderingHelper(
- getModel(), iProject);
+ List<UiElementNode> children = getModel().getUiChildren();
+ if (children.size() == 1) {
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(
+ children.get(0).getXmlNode(), iProject);
- // there are 2 paddings for each view
- // left and right, or top and bottom.
- int paddingValue = ExplodedRenderingHelper.PADDING_VALUE * 2;
+ // 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;
+ width += helper.getWidthPadding() * paddingValue;
+ height += helper.getHeightPadding() * paddingValue;
+ }
}
int density = mConfigComposite.getDensity().getDpiValue();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
index c277c25..ef6c59d 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
@@ -86,6 +86,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
+import java.util.List;
import java.util.Map;
/**
@@ -963,15 +964,18 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE
int height = rect.height;
if (mUseExplodeMode) {
// compute how many padding in x and y will bump the screen size
- ExplodedRenderingHelper helper = new ExplodedRenderingHelper(
- getModel(), iProject);
+ List<UiElementNode> children = getModel().getUiChildren();
+ if (children.size() == 1) {
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(
+ children.get(0).getXmlNode(), iProject);
- // there are 2 paddings for each view
- // left and right, or top and bottom.
- int paddingValue = ExplodedRenderingHelper.PADDING_VALUE * 2;
+ // 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;
+ width += helper.getWidthPadding() * paddingValue;
+ height += helper.getHeightPadding() * paddingValue;
+ }
}
int density = mConfigComposite.getDensity().getDpiValue();
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/ExplodeRenderingHelperTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/ExplodeRenderingHelperTest.java
new file mode 100644
index 0000000..690bd22
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/ExplodeRenderingHelperTest.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2010 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.mock.MockXmlNode;
+import com.android.sdklib.SdkConstants;
+
+import org.w3c.dom.Node;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class ExplodeRenderingHelperTest extends TestCase {
+
+ private final List<String> mLayoutNames = new ArrayList<String>();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mLayoutNames.add("LinearLayout");
+ mLayoutNames.add("RelativeLayout");
+ }
+
+ public void testSingleHorizontalLinearLayout() {
+ // Single layout, horizontal, 2 buttons.
+ MockXmlNode layout = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()} );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(1, helper.getHeightPadding());
+ assertEquals(1, helper.getWidthPadding());
+ }
+
+ public void testSingleVerticalLinearLayout() {
+ // Single layout, horizontal, with 2 buttons.
+ // LinearLayout(H:[Button Button])
+ MockXmlNode layout = createLinearLayout(false /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()} );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(1, helper.getWidthPadding());
+ assertEquals(1, helper.getHeightPadding());
+ }
+
+ public void testEmbeddedLinearLayouts() {
+ /*
+ * LinearLayout(vertical):
+ * LinearLayout(H:[Button Button])
+ * LinearLayout(H:[Button Button Button])
+ *
+ * Result should be 2 in x, 3 in y
+ */
+ MockXmlNode layout = createLinearLayout(false /*horizontal*/,
+ new MockXmlNode[] {
+ createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()}),
+ createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton(), createButton()}),
+ } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(2, helper.getWidthPadding());
+ assertEquals(3, helper.getHeightPadding());
+ }
+
+ public void testSimpleRelativeLayoutWithOneLinearLayouts() {
+ /*
+ * RelativeLayout:
+ * LinearLayout(H:[Button Button])
+ *
+ * Result should be 2 in x, 2 in y
+ */
+ MockXmlNode layout = createRelativeLayout(
+ new MockXmlNode[] {
+ createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()}),
+ } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(2, helper.getWidthPadding());
+ assertEquals(2, helper.getHeightPadding());
+ }
+
+ public void /*test*/RelativeLayoutWithVerticalLinearLayouts() {
+ //FIXME: Reenable once the relative layout are properly supported.
+ /*
+ * Children of the relative layouts, one below the other.
+ * Each with only buttons in them.
+ * RelativeLayout:
+ * LinearLayout(H:[Button Button])
+ * ^
+ * LinearLayout(H:[Button Button])
+ *
+ * Result should be 2 in x, 3 in y
+ */
+
+ // create the linearlayouts.
+ MockXmlNode linear1 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()});
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear1");
+
+ MockXmlNode linear2 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()});
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear2");
+
+ // position linear2 below linear1
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "layout_below", "@+id/linear1");
+
+
+ MockXmlNode layout = createRelativeLayout(new MockXmlNode[] { linear1, linear2 } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(2, helper.getWidthPadding());
+ assertEquals(3, helper.getHeightPadding());
+ }
+
+ public void /*test*/RelativeLayoutWithVerticalLinearLayouts2() {
+ //FIXME: Reenable once the relative layout are properly supported.
+ /*
+ * Children of the relative layouts, one above the other.
+ * Each with only buttons in them.
+ * RelativeLayout:
+ * LinearLayout(H:[Button Button])
+ * v
+ * LinearLayout(H:[Button Button])
+ *
+ * Result should be 2 in x, 3 in y
+ */
+
+ // create the linearlayouts.
+ MockXmlNode linear1 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton() } );
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear1");
+
+ MockXmlNode linear2 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton() } );
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear2");
+
+ // position linear2 below linear1
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "layout_above", "@+id/linear1");
+
+
+ MockXmlNode layout = createRelativeLayout(new MockXmlNode[] { linear1, linear2 } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(2, helper.getWidthPadding());
+ assertEquals(3, helper.getHeightPadding());
+ }
+
+ public void /*test*/ComplexRelativeLayout() {
+ //FIXME: Reenable once the relative layout are properly supported.
+ /*
+ * RelativeLayout:
+ *
+ * < LinearLayout1(V: [button]) > LinearLayout2(V: [button])
+ * v
+ * Button1 > LinearLayout3(V: [button]) < Button2
+ * v
+ * < LinearLayout4(V: [button])
+ * ^
+ * <LinearLayout5(V: [button])
+ *
+ * Result should be 4 in x, 5 in y
+ */
+
+ // create the elements
+ MockXmlNode button1 = createButton();
+ button1.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/button1");
+
+ MockXmlNode button2 = createButton();
+ button2.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/button2");
+
+ MockXmlNode linear1 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear1");
+
+ MockXmlNode linear2 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear2");
+
+ MockXmlNode linear3 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear3.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear3");
+
+ MockXmlNode linear4 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear4.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear4");
+
+ MockXmlNode linear5 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear5.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear5");
+
+
+ // link them
+ button1.addAttributes(SdkConstants.NS_RESOURCES, "layout_toLeftOf", "@+id/linear3");
+
+ button2.addAttributes(SdkConstants.NS_RESOURCES, "layout_toRightOf", "@+id/linear3");
+
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "layout_toRightOf", "@+id/linear3");
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "layout_toLeftOf", "@+id/linear2");
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "layout_above", "@+id/button2");
+
+ linear3.addAttributes(SdkConstants.NS_RESOURCES, "layout_above", "@+id/linear4");
+
+ linear4.addAttributes(SdkConstants.NS_RESOURCES, "layout_toRightOf", "@+id/button1");
+
+ linear5.addAttributes(SdkConstants.NS_RESOURCES, "layout_toRightOf", "@+id/linear4");
+ linear5.addAttributes(SdkConstants.NS_RESOURCES, "layout_below", "@+id/linear4");
+
+ MockXmlNode layout = createRelativeLayout(
+ new MockXmlNode[] {
+ button1, button2, linear1, linear2, linear3, linear4, linear5 } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(4, helper.getWidthPadding());
+ assertEquals(5, helper.getHeightPadding());
+ }
+
+
+ // ----- helper to deal with mocks
+
+ private MockXmlNode createButton() {
+ return new MockXmlNode(null, "Button", Node.ELEMENT_NODE, null);
+ }
+
+ private MockXmlNode createLinearLayout(boolean horizontal, MockXmlNode[] children) {
+ MockXmlNode layout = new MockXmlNode(null, "LinearLayout", Node.ELEMENT_NODE, children);
+
+ layout.addAttributes(SdkConstants.NS_RESOURCES, "orientation",
+ horizontal ? "horizontal" : "vertical");
+
+ return layout;
+ }
+
+ private MockXmlNode createRelativeLayout(MockXmlNode[] children) {
+ MockXmlNode layout = new MockXmlNode(null, "RelativeLayout", Node.ELEMENT_NODE, children);
+
+ return layout;
+ }
+}