diff options
author | Xavier Ducrohet <xav@google.com> | 2010-01-26 16:04:50 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2010-01-26 16:04:50 -0800 |
commit | cf68c35f51388b6764615a16a9585561b360b0b4 (patch) | |
tree | b4f6cfb86a9b4861ed77495b091dcfd5a5fee2a3 | |
parent | af44fbeb406ba3997614cabc70bf0d10d2693a50 (diff) | |
parent | aae21fc056ff15325c5ff5158648b7c6be7728de (diff) | |
download | sdk-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.
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; + } +} |