diff options
author | Tor Norbye <tnorbye@google.com> | 2012-04-03 16:32:53 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2012-06-12 15:11:56 -0700 |
commit | fb6d52d71a7461cb1ac4149f4f71d6a63e7436da (patch) | |
tree | ddae10c083d2532d6b340f8b5699630c9c24142b /eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout | |
parent | 9208fab7341aebfcf800fa9a293e06ec803927de (diff) | |
download | sdk-fb6d52d71a7461cb1ac4149f4f71d6a63e7436da.zip sdk-fb6d52d71a7461cb1ac4149f4f71d6a63e7436da.tar.gz sdk-fb6d52d71a7461cb1ac4149f4f71d6a63e7436da.tar.bz2 |
GridLayout support work
Lots of miscellaneous fixes to the GridLayout support in ADT. The
changes include using the GridLayout state (via reflection) to
populate the model; caching the grid model for performance, and a
bunch of fixes to the code which handles insertions and
removals. There are also some new unit tests. This is not done, but is
an improvement over the current state.
Change-Id: I4851153d3e409630c2d2024c4894d1ad1535fb47
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout')
4 files changed, 1084 insertions, 14 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/GravityHelperTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/GravityHelperTest.java index c05cdb5..f162924 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/GravityHelperTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/GravityHelperTest.java @@ -18,7 +18,12 @@ package com.android.ide.common.layout; import static com.android.ide.common.layout.GravityHelper.GRAVITY_BOTTOM; import static com.android.ide.common.layout.GravityHelper.GRAVITY_CENTER_HORIZ; import static com.android.ide.common.layout.GravityHelper.GRAVITY_CENTER_VERT; +import static com.android.ide.common.layout.GravityHelper.GRAVITY_FILL_HORIZ; +import static com.android.ide.common.layout.GravityHelper.GRAVITY_FILL_VERT; import static com.android.ide.common.layout.GravityHelper.GRAVITY_LEFT; +import static com.android.ide.common.layout.GravityHelper.GRAVITY_RIGHT; +import static com.android.ide.common.layout.GravityHelper.GRAVITY_TOP; +import static com.android.ide.common.layout.GravityHelper.getGravity; import junit.framework.TestCase; @SuppressWarnings("javadoc") @@ -29,4 +34,52 @@ public class GravityHelperTest extends TestCase { assertEquals(GRAVITY_CENTER_HORIZ | GRAVITY_CENTER_VERT, GravityHelper.getGravity("center", 0)); } + + public void testGravityString() throws Exception { + assertEquals("left", getGravity(GRAVITY_LEFT)); + assertEquals("right", getGravity(GRAVITY_RIGHT)); + assertEquals("top", getGravity(GRAVITY_TOP)); + assertEquals("bottom", getGravity(GRAVITY_BOTTOM)); + assertEquals("center_horizontal", getGravity(GRAVITY_CENTER_HORIZ)); + assertEquals("center_vertical", getGravity(GRAVITY_CENTER_VERT)); + assertEquals("fill_horizontal", getGravity(GRAVITY_FILL_HORIZ)); + assertEquals("fill_vertical", getGravity(GRAVITY_FILL_VERT)); + + assertEquals("center", getGravity(GRAVITY_CENTER_HORIZ|GRAVITY_CENTER_VERT)); + + assertEquals("left|bottom", getGravity(GRAVITY_LEFT|GRAVITY_BOTTOM)); + assertEquals("center_horizontal|top", getGravity(GRAVITY_CENTER_HORIZ|GRAVITY_TOP)); + } + + public void testConstrained() throws Exception { + assertTrue(GravityHelper.isConstrainedHorizontally(GRAVITY_LEFT)); + assertTrue(GravityHelper.isConstrainedHorizontally(GRAVITY_RIGHT)); + assertTrue(GravityHelper.isConstrainedHorizontally(GRAVITY_CENTER_HORIZ)); + assertTrue(GravityHelper.isConstrainedHorizontally(GRAVITY_FILL_HORIZ)); + + assertFalse(GravityHelper.isConstrainedVertically(GRAVITY_LEFT)); + assertFalse(GravityHelper.isConstrainedVertically(GRAVITY_RIGHT)); + assertFalse(GravityHelper.isConstrainedVertically(GRAVITY_CENTER_HORIZ)); + assertFalse(GravityHelper.isConstrainedVertically(GRAVITY_FILL_HORIZ)); + + assertTrue(GravityHelper.isConstrainedVertically(GRAVITY_TOP)); + assertTrue(GravityHelper.isConstrainedVertically(GRAVITY_BOTTOM)); + assertTrue(GravityHelper.isConstrainedVertically(GRAVITY_CENTER_VERT)); + assertTrue(GravityHelper.isConstrainedVertically(GRAVITY_FILL_VERT)); + + assertFalse(GravityHelper.isConstrainedHorizontally(GRAVITY_TOP)); + assertFalse(GravityHelper.isConstrainedHorizontally(GRAVITY_BOTTOM)); + assertFalse(GravityHelper.isConstrainedHorizontally(GRAVITY_CENTER_VERT)); + assertFalse(GravityHelper.isConstrainedHorizontally(GRAVITY_FILL_VERT)); + } + + public void testAligned() throws Exception { + assertTrue(GravityHelper.isLeftAligned(GRAVITY_LEFT|GRAVITY_TOP)); + assertTrue(GravityHelper.isLeftAligned(GRAVITY_LEFT)); + assertFalse(GravityHelper.isLeftAligned(GRAVITY_RIGHT)); + + assertTrue(GravityHelper.isTopAligned(GRAVITY_LEFT|GRAVITY_TOP)); + assertTrue(GravityHelper.isTopAligned(GRAVITY_TOP)); + assertFalse(GravityHelper.isTopAligned(GRAVITY_BOTTOM)); + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java index 826f36c..b59144a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java @@ -192,10 +192,10 @@ public class LayoutTestBase extends TestCase { rule.onInitialize(fqn, new TestRulesEngine(fqn)); } - private static class TestRulesEngine implements IClientRulesEngine { + public static class TestRulesEngine implements IClientRulesEngine { private final String mFqn; - protected TestRulesEngine(String fqn) { + public TestRulesEngine(String fqn) { mFqn = fqn; } @@ -320,8 +320,14 @@ public class LayoutTestBase extends TestCase { @Override public int pxToDp(int px) { - fail("Not supported in tests yet"); - return px; + // Arbitrary conversion + return px / 3; + } + + @Override + public int dpToPx(int dp) { + // Arbitrary conversion + return 3 * dp; } @Override @@ -333,17 +339,17 @@ public class LayoutTestBase extends TestCase { @Override public int screenToLayout(int pixels) { fail("Not supported in tests yet"); - return 0; + return pixels; } @Override - public int dpToPx(int dp) { + public @NonNull String getAppNameSpace() { fail("Not supported in tests yet"); - return 0; + return null; } @Override - public @NonNull String getAppNameSpace() { + public @Nullable Object getViewObject(@NonNull INode node) { fail("Not supported in tests yet"); return null; } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java index 8984f38..b9176f6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java @@ -15,8 +15,13 @@ */ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; +import static com.android.ide.common.layout.LayoutConstants.ANDROID_WIDGET_PREFIX; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; +import static com.android.tools.lint.detector.api.LintConstants.ANDROID_URI; +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import com.android.annotations.NonNull; import com.android.annotations.Nullable; @@ -25,14 +30,30 @@ import com.android.ide.common.api.INode; import com.android.ide.common.api.INodeHandler; import com.android.ide.common.api.Margins; import com.android.ide.common.api.Rect; +import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatPreferences; +import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatStyle; +import com.android.ide.eclipse.adt.internal.editors.formatting.XmlPrettyPrinter; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; +import com.google.common.base.Splitter; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.IOException; +import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import junit.framework.Assert; /** Test/mock implementation of {@link INode} */ +@SuppressWarnings("javadoc") public class TestNode implements INode { private TestNode mParent; @@ -193,8 +214,9 @@ public class TestNode implements INode { @Override public String toString() { - return "TestNode [fqn=" + mFqcn + ", infos=" + mAttributeInfos - + ", attributes=" + mAttributes + ", bounds=" + mBounds + "]"; + String id = getStringAttr(ANDROID_URI, ATTR_ID); + return "TestNode [id=" + (id != null ? id : "?") + ", fqn=" + mFqcn + ", infos=" + + mAttributeInfos + ", attributes=" + mAttributes + ", bounds=" + mBounds + "]"; } @Override @@ -215,4 +237,197 @@ public class TestNode implements INode { public void setAttributeSources(List<String> attributeSources) { mAttributeSources = attributeSources; } + + /** Create a test node from the given XML */ + public static TestNode createFromXml(String xml) { + Document document = DomUtilities.parseDocument(xml, false); + assertNotNull(document); + assertNotNull(document.getDocumentElement()); + + return createFromNode(document.getDocumentElement()); + } + + public static String toXml(TestNode node) { + assertTrue("This method only works with nodes constructed from XML", + node instanceof TestXmlNode); + Document document = ((TestXmlNode) node).mElement.getOwnerDocument(); + // Insert new whitespace nodes etc + String xml = dumpDocument(document); + document = DomUtilities.parseDocument(xml, false); + + XmlPrettyPrinter printer = new XmlPrettyPrinter(XmlFormatPreferences.create(), + XmlFormatStyle.LAYOUT, "\n"); + StringBuilder sb = new StringBuilder(1000); + sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); + printer.prettyPrint(-1, document, null, null, sb, false); + return sb.toString(); + } + + @SuppressWarnings("deprecation") + private static String dumpDocument(Document document) { + // Diagnostics: print out the XML that we're about to render + org.apache.xml.serialize.OutputFormat outputFormat = + new org.apache.xml.serialize.OutputFormat( + "XML", "ISO-8859-1", true); //$NON-NLS-1$ //$NON-NLS-2$ + outputFormat.setIndent(2); + outputFormat.setLineWidth(100); + outputFormat.setIndenting(true); + outputFormat.setOmitXMLDeclaration(true); + outputFormat.setOmitDocumentType(true); + StringWriter stringWriter = new StringWriter(); + // Using FQN here to avoid having an import above, which will result + // in a deprecation warning, and there isn't a way to annotate a single + // import element with a SuppressWarnings. + org.apache.xml.serialize.XMLSerializer serializer = + new org.apache.xml.serialize.XMLSerializer(stringWriter, outputFormat); + serializer.setNamespaces(true); + try { + serializer.serialize(document.getDocumentElement()); + return stringWriter.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + private static TestNode createFromNode(Element element) { + String fqcn = ANDROID_WIDGET_PREFIX + element.getTagName(); + TestNode node = new TestXmlNode(fqcn, element); + + for (Element child : DomUtilities.getChildren(element)) { + node.add(createFromNode(child)); + } + + return node; + } + + @Nullable + public static TestNode findById(TestNode node, String id) { + id = BaseLayoutRule.stripIdPrefix(id); + return node.findById(id); + } + + private TestNode findById(String targetId) { + String id = getStringAttr(ANDROID_URI, ATTR_ID); + if (id != null && targetId.equals(BaseLayoutRule.stripIdPrefix(id))) { + return this; + } + + for (TestNode child : mChildren) { + TestNode result = child.findById(targetId); + if (result != null) { + return result; + } + } + + return null; + } + + private static String getTagName(String fqcn) { + return fqcn.substring(fqcn.lastIndexOf('.') + 1); + } + + private static class TestXmlNode extends TestNode { + private final Element mElement; + + public TestXmlNode(String fqcn, Element element) { + super(fqcn); + mElement = element; + } + + @Override + public boolean setAttribute(String uri, String localName, String value) { + mElement.setAttributeNS(uri, localName, value); + return super.setAttribute(uri, localName, value); + } + + @Override + public INode appendChild(String viewFqcn) { + Element child = mElement.getOwnerDocument().createElement(getTagName(viewFqcn)); + mElement.appendChild(child); + return new TestXmlNode(viewFqcn, child); + } + + @Override + public INode insertChildAt(String viewFqcn, int index) { + if (index == -1) { + return appendChild(viewFqcn); + } + Element child = mElement.getOwnerDocument().createElement(getTagName(viewFqcn)); + List<Element> children = DomUtilities.getChildren(mElement); + if (children.size() >= index) { + Element before = children.get(index); + mElement.insertBefore(child, before); + } else { + fail("Unexpected index"); + mElement.appendChild(child); + } + return new TestXmlNode(viewFqcn, child); + } + + @Override + public String getStringAttr(String uri, String name) { + String value; + if (uri == null) { + value = mElement.getAttribute(name); + } else { + value = mElement.getAttributeNS(uri, name); + } + if (value.isEmpty()) { + value = null; + } + + return value; + } + + @Override + public void removeChild(INode node) { + assert node instanceof TestXmlNode; + mElement.removeChild(((TestXmlNode) node).mElement); + } + + @Override + public void removeChild(int index) { + List<Element> children = DomUtilities.getChildren(mElement); + assertTrue(index < children.size()); + Element oldChild = children.get(index); + mElement.removeChild(oldChild); + } + } + + // Recursively initialize this node with the bounds specified in the given hierarchy + // dump (from ViewHierarchy's DUMP_INFO flag + public void assignBounds(String bounds) { + Iterable<String> split = Splitter.on('\n').trimResults().split(bounds); + assignBounds(split.iterator()); + } + + private void assignBounds(Iterator<String> iterator) { + assertTrue(iterator.hasNext()); + String desc = iterator.next(); + + Pattern pattern = Pattern.compile("^\\s*(.+)\\s+\\[(.+)\\]\\s*(<.+>)?\\s*(\\S+)?\\s*$"); + Matcher matcher = pattern.matcher(desc); + assertTrue(matcher.matches()); + String fqn = matcher.group(1); + assertEquals(getFqcn(), fqn); + String boundsString = matcher.group(2); + String[] bounds = boundsString.split(","); + assertEquals(boundsString, 4, bounds.length); + try { + int left = Integer.parseInt(bounds[0]); + int top = Integer.parseInt(bounds[1]); + int right = Integer.parseInt(bounds[2]); + int bottom = Integer.parseInt(bounds[3]); + mBounds = new Rect(left, top, right - left, bottom - top); + } catch (NumberFormatException nufe) { + Assert.fail(nufe.getLocalizedMessage()); + } + String tag = matcher.group(3); + + for (INode child : getChildren()) { + assertTrue(iterator.hasNext()); + ((TestNode) child).assignBounds(iterator); + } + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/grid/GridModelTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/grid/GridModelTest.java index 680b7ca..f3405c1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/grid/GridModelTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/grid/GridModelTest.java @@ -15,15 +15,24 @@ */ package com.android.ide.common.layout.grid; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_COLUMN_COUNT; +import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_COLUMN; +import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_COLUMN_SPAN; +import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ROW; import static com.android.ide.common.layout.LayoutConstants.FQCN_BUTTON; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.ide.common.api.INode; import com.android.ide.common.api.Rect; import com.android.ide.common.layout.LayoutTestBase; import com.android.ide.common.layout.TestNode; +import com.android.ide.common.layout.grid.GridModel.ViewData; +import java.util.Arrays; +import java.util.Collections; + +@SuppressWarnings("javadoc") public class GridModelTest extends LayoutTestBase { public void testRemoveFlag() { assertEquals("left", GridModel.removeFlag("top", "top|left")); @@ -38,7 +47,7 @@ public class GridModelTest extends LayoutTestBase { TestNode targetNode = TestNode.create("android.widget.GridLayout").id("@+id/GridLayout1") .bounds(new Rect(0, 0, 240, 480)).set(ANDROID_URI, ATTR_COLUMN_COUNT, "3"); - GridModel model = new GridModel(null, targetNode, null); + GridModel model = GridModel.get(null, targetNode, null); assertEquals(3, model.declaredColumnCount); assertEquals(1, model.actualColumnCount); assertEquals(1, model.actualRowCount); @@ -48,9 +57,796 @@ public class GridModelTest extends LayoutTestBase { targetNode.add(TestNode.create(FQCN_BUTTON).id("@+id/Button3")); targetNode.add(TestNode.create(FQCN_BUTTON).id("@+id/Button4")); - model = new GridModel(null, targetNode, null); + model = GridModel.get(null, targetNode, null); + assertEquals(3, model.declaredColumnCount); + assertEquals(3, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + } + + public void testSplitColumn() { + TestNode targetNode = TestNode.create("android.widget.GridLayout").id("@+id/GridLayout1") + .bounds(new Rect(0, 0, 240, 480)).set(ANDROID_URI, ATTR_COLUMN_COUNT, "3"); + TestNode b1 = TestNode.create(FQCN_BUTTON).id("@+id/Button1"); + TestNode b2 = TestNode.create(FQCN_BUTTON).id("@+id/Button2"); + TestNode b3 = TestNode.create(FQCN_BUTTON).id("@+id/Button3"); + TestNode b4 = TestNode.create(FQCN_BUTTON).id("@+id/Button4"); + targetNode.add(b1); + targetNode.add(b2); + targetNode.add(b3); + targetNode.add(b4); + b4.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN, "2"); + + GridModel model = GridModel.get(new LayoutTestBase.TestRulesEngine(targetNode.getFqcn()), + targetNode, null); + assertEquals(3, model.declaredColumnCount); + assertEquals(3, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + + model.applyPositionAttributes(); + assertEquals("0", b1.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN)); + assertEquals("0", b1.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW)); + + assertEquals("1", b2.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN)); + assertEquals("0", b2.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW)); + + assertEquals("2", b3.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN)); + assertEquals("0", b3.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW)); + + assertEquals("0", b4.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN)); + assertEquals("1", b4.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW)); + assertEquals("2", b4.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN)); + + model.splitColumn(1, false /*insertMarginColumn*/, 100 /*columnWidthDp*/, 300 /* x */); + model.applyPositionAttributes(); + + assertEquals(4, model.declaredColumnCount); + assertEquals(4, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + + assertEquals("0", b1.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN)); + assertEquals("0", b1.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW)); + + assertEquals("1", b2.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN)); + assertEquals("2", b2.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN)); + assertEquals("0", b2.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW)); + + assertEquals("3", b3.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN)); + assertEquals("0", b3.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW)); + + assertEquals("0", b4.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN)); + assertEquals("1", b4.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW)); + assertEquals("3", b4.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN)); + } + + public void testDeletion1() { + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:columnCount=\"4\" >\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button1\"\n" + + " android:layout_column=\"1\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <TextView\n" + + " android:id=\"@+id/TextView1\"\n" + + " android:layout_column=\"3\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Text\" />\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/wspace1\"\n" + + " android:layout_width=\"21dp\"\n" + + " android:layout_height=\"1dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/hspace1\"\n" + + " android:layout_width=\"1dp\"\n" + + " android:layout_height=\"55dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/wspace2\"\n" + + " android:layout_width=\"10dp\"\n" + + " android:layout_height=\"1dp\"\n" + + " android:layout_column=\"2\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + "</GridLayout>"; + + TestNode targetNode = TestNode.createFromXml(xml); + assertNotNull(targetNode); + + TestNode button1 = TestNode.findById(targetNode, "@+id/button1"); + TestNode textView1 = TestNode.findById(targetNode, "@+id/TextView1"); + TestNode wspace1 = TestNode.findById(targetNode, "@+id/wspace1"); + TestNode wspace2 = TestNode.findById(targetNode, "@+id/wspace2"); + TestNode hspace1 = TestNode.findById(targetNode, "@+id/hspace1"); + assertNotNull(wspace1); + assertNotNull(hspace1); + assertNotNull(wspace2); + assertNotNull(button1); + assertNotNull(textView1); + + // Assign some bounds such that the model makes sense when merging spacer sizes + // TODO: MAke test utility method to automatically assign half divisions!! + button1.bounds(new Rect(90, 10, 100, 40)); + textView1.bounds(new Rect(200, 10, 100, 40)); + wspace1.bounds(new Rect(0, 0, 90, 1)); + wspace1.bounds(new Rect(190, 0, 10, 1)); + hspace1.bounds(new Rect(0, 0, 1, 10)); + + GridModel model = GridModel.get(new LayoutTestBase.TestRulesEngine(targetNode.getFqcn()), + targetNode, null); + assertEquals(4, model.declaredColumnCount); + assertEquals(4, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + + ViewData textViewData = model.getView(textView1); + assertEquals(3, textViewData.column); + + // Delete button1 + button1.getParent().removeChild(button1); + model.onDeleted(Arrays.<INode>asList(button1)); + model.applyPositionAttributes(); + + assertEquals(2, model.declaredColumnCount); + assertEquals(2, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + assertNotNull(model.getView(textView1)); + assertNull(model.getView(button1)); + + assertEquals( + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:columnCount=\"2\">\n" + + "\n" + + " <TextView\n" + + " android:id=\"@+id/TextView1\"\n" + + " android:layout_column=\"1\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Text\">\n" + + " </TextView>\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/wspace1\"\n" + + " android:layout_width=\"66dp\"\n" + + " android:layout_height=\"1dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\">\n" + + " </Space>\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/hspace1\"\n" + + " android:layout_width=\"1dp\"\n" + + " android:layout_height=\"55dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\">\n" + + " </Space>\n" + + "\n" + + "</GridLayout>", TestNode.toXml(targetNode)); + + // Delete textView1 + + textView1.getParent().removeChild(textView1); + model.onDeleted(Arrays.<INode>asList(textView1)); + model.applyPositionAttributes(); + + assertEquals(2, model.declaredColumnCount); + assertEquals(0, model.actualColumnCount); + assertEquals(0, model.actualRowCount); + assertNull(model.getView(textView1)); + assertNull(model.getView(button1)); + + assertEquals( + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:columnCount=\"0\">\n" + + "\n" + + "</GridLayout>", TestNode.toXml(targetNode)); + + } + + public void testDelete2() throws Exception { + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:columnCount=\"4\"\n" + + " android:orientation=\"vertical\" >\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button1\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_columnSpan=\"2\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"0\"\n" + + " android:text=\"Button1\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button3\"\n" + + " android:layout_column=\"1\"\n" + + " android:layout_columnSpan=\"2\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Button2\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button2\"\n" + + " android:layout_column=\"2\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"0\"\n" + + " android:text=\"Button3\" />\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/spacer_177\"\n" + + " android:layout_width=\"46dp\"\n" + + " android:layout_height=\"1dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + "</GridLayout>"; + + TestNode targetNode = TestNode.createFromXml(xml); + assertNotNull(targetNode); + + TestNode button1 = TestNode.findById(targetNode, "@+id/button1"); + TestNode button2 = TestNode.findById(targetNode, "@+id/button2"); + TestNode button3 = TestNode.findById(targetNode, "@+id/button3"); + TestNode hspacer = TestNode.findById(targetNode, "@+id/spacer_177"); + assertNotNull(button1); + assertNotNull(button2); + assertNotNull(button3); + assertNotNull(hspacer); + + // Assign some bounds such that the model makes sense when merging spacer sizes + // TODO: MAke test utility method to automatically assign half divisions!! + button1.bounds(new Rect(0, 0, 100, 40)); + button2.bounds(new Rect(100, 0, 100, 40)); + button3.bounds(new Rect(50, 40, 100, 40)); + hspacer.bounds(new Rect(0, 0, 50, 1)); + + GridModel model = GridModel.get(new LayoutTestBase.TestRulesEngine(targetNode.getFqcn()), + targetNode, null); + assertEquals(4, model.declaredColumnCount); + assertEquals(3, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + + ViewData buttonData = model.getView(button1); + assertEquals(0, buttonData.column); + + // Delete button1 + button1.getParent().removeChild(button1); + model.onDeleted(Arrays.<INode>asList(button1)); + model.applyPositionAttributes(); + + assertEquals(3, model.declaredColumnCount); + assertEquals(3, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + assertNull(model.getView(button1)); + + assertEquals( + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:columnCount=\"3\"\n" + + " android:orientation=\"vertical\">\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button3\"\n" + + " android:layout_column=\"1\"\n" + + " android:layout_columnSpan=\"2\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Button2\">\n" + + " </Button>\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button2\"\n" + + " android:layout_column=\"2\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"0\"\n" + + " android:text=\"Button3\">\n" + + " </Button>\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/spacer_177\"\n" + + " android:layout_width=\"46dp\"\n" + + " android:layout_height=\"1dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\">\n" + + " </Space>\n" + + "\n" + + "</GridLayout>", TestNode.toXml(targetNode)); + } + + public void testDelete3_INCOMPLETE() throws Exception { + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:layout_width=\"match_parent\" android:layout_height=\"match_parent\"\n" + + " android:columnCount=\"6\">\n" + + " <Button android:id=\"@+id/button1\" android:layout_column=\"1\"\n" + + " android:layout_columnSpan=\"2\" android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\" android:layout_rowSpan=\"2\" android:text=\"Button\" />\n" + + " <TextView android:id=\"@+id/TextView1\" android:layout_column=\"4\"\n" + + " android:layout_gravity=\"left|top\" android:layout_row=\"1\"\n" + + " android:text=\"Text\" />\n" + + " <Button android:id=\"@+id/button3\" android:layout_column=\"5\"\n" + + " android:layout_gravity=\"left|top\" android:layout_row=\"2\"\n" + + " android:layout_rowSpan=\"2\" android:text=\"Button\" />\n" + + " <Button android:id=\"@+id/button2\" android:layout_column=\"2\"\n" + + " android:layout_columnSpan=\"3\" android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"4\" android:text=\"Button\" />\n" + + " <Space android:id=\"@+id/wspace1\" android:layout_width=\"21dp\"\n" + + " android:layout_height=\"1dp\" android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + " <Space android:id=\"@+id/spacer_630\" android:layout_width=\"1dp\"\n" + + " android:layout_height=\"55dp\" android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + " <Space android:id=\"@+id/wspace2\" android:layout_width=\"10dp\"\n" + + " android:layout_height=\"1dp\" android:layout_column=\"3\"\n" + + " android:layout_row=\"0\" />\n" + + " <Space android:id=\"@+id/spacer_619\" android:layout_width=\"59dp\"\n" + + " android:layout_height=\"1dp\" android:layout_column=\"1\"\n" + + " android:layout_row=\"0\" />\n" + + " <Space android:id=\"@+id/spacer_102\" android:layout_width=\"1dp\"\n" + + " android:layout_height=\"30dp\" android:layout_column=\"0\"\n" + + " android:layout_row=\"1\" />\n" + + " <Space android:id=\"@+id/spacer_109\" android:layout_width=\"1dp\"\n" + + " android:layout_height=\"28dp\" android:layout_column=\"0\"\n" + + " android:layout_row=\"2\" />\n" + + " <Space android:id=\"@+id/spacer_146\" android:layout_width=\"1dp\"\n" + + " android:layout_height=\"70dp\" android:layout_column=\"0\"\n" + + " android:layout_row=\"3\" />\n" + + "</GridLayout>"; + TestNode targetNode = TestNode.createFromXml(xml); + assertNotNull(targetNode); + targetNode.assignBounds( + "android.widget.GridLayout [0,109,480,800] <GridLayout>\n" + + " android.widget.Button [32,83,148,155] <Button> @+id/button1\n" + + " android.widget.TextView [163,83,205,109] <TextView> @+id/TextView1\n" + + " android.widget.Button [237,128,353,200] <Button> @+id/button3\n" + + " android.widget.Button [121,275,237,347] <Button> @+id/button2\n" + + " android.widget.Space [0,0,32,2] <Space> @+id/wspace1\n" + + " android.widget.Space [0,0,2,83] <Space> @+id/spacer_630\n" + + " android.widget.Space [148,0,163,2] <Space> @+id/wspace2\n" + + " android.widget.Space [32,0,121,2] <Space> @+id/spacer_619\n" + + " android.widget.Space [0,83,2,128] <Space> @+id/spacer_102\n" + + " android.widget.Space [0,128,2,170] <Space> @+id/spacer_109\n" + + " android.widget.Space [0,170,2,275] <Space> @+id/spacer_146\n"); + TestNode layout = TestNode.findById(targetNode, "@+id/GridLayout1"); + //TestNode button1 = TestNode.findById(targetNode, "@+id/button1"); + TestNode button2 = TestNode.findById(targetNode, "@+id/button2"); + TestNode button3 = TestNode.findById(targetNode, "@+id/button3"); + + GridModel model = GridModel.get(new LayoutTestBase.TestRulesEngine(targetNode.getFqcn()), + targetNode, null); + assertEquals(6, model.declaredColumnCount); + assertEquals(6, model.actualColumnCount); + assertEquals(5, model.actualRowCount); + + // TODO: Delete button2 or button3: bad stuff happens visually + fail("Finish test"); + } + + public void testDelete4_INCOMPLETE() { + String xml = "" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " xmlns:tools=\"http://schemas.android.com/tools\" " + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\" android:columnCount=\"3\"\n" + + " android:gravity=\"center\" android:text=\"@string/hello_world\"\n" + + " tools:context=\".MainActivity\">\n" + + " <Button android:id=\"@+id/button2\" android:layout_column=\"1\"\n" + + " android:layout_columnSpan=\"2\" android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\" android:text=\"Button\" />\n" + + " <Button android:id=\"@+id/button1\" android:layout_column=\"1\"\n" + + " android:layout_columnSpan=\"2\" android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"3\" android:text=\"Button\" />\n" + + " <Space android:id=\"@+id/spacer_167\" android:layout_width=\"74dp\"\n" + + " android:layout_height=\"1dp\" android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + " <Space android:id=\"@+id/spacer_133\" android:layout_width=\"1dp\"\n" + + " android:layout_height=\"21dp\" android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + " <Space android:id=\"@+id/spacer_142\" android:layout_width=\"1dp\"\n" + + " android:layout_height=\"26dp\" android:layout_column=\"0\"\n" + + " android:layout_row=\"2\" />\n" + + " <Space android:id=\"@+id/spacer_673\" android:layout_width=\"43dp\"\n" + + " android:layout_height=\"1dp\" android:layout_column=\"1\"\n" + + " android:layout_row=\"0\" />\n" + + " <Space android:id=\"@+id/spacer_110\" android:layout_width=\"202dp\"\n" + + " android:layout_height=\"15dp\" android:layout_column=\"2\" />\n" + + "</GridLayout>"; + TestNode targetNode = TestNode.createFromXml(xml); + assertNotNull(targetNode); + targetNode.assignBounds( + "android.widget.GridLayout [0,109,480,800] <GridLayout>\n" + + " android.widget.Button [111,32,227,104] <Button> @+id/button2\n" + + " android.widget.Button [111,143,227,215] <Button> @+id/button1\n" + + " android.widget.Space [0,0,111,2] <Space> @+id/spacer_167\n" + + " android.widget.Space [0,0,2,32] <Space> @+id/spacer_133\n" + + " android.widget.Space [0,104,2,143] <Space> @+id/spacer_142\n" + + " android.widget.Space [111,0,176,2] <Space> @+id/spacer_673\n" + + " android.widget.Space [176,668,479,691] <Space> @+id/spacer_110"); + + + // Remove button2; button1 shifts to the right! + + //TestNode layout = TestNode.findById(targetNode, "@+id/GridLayout1"); + //TestNode button1 = TestNode.findById(targetNode, "@+id/button1"); + TestNode button2 = TestNode.findById(targetNode, "@+id/button2"); + TestNode button3 = TestNode.findById(targetNode, "@+id/button3"); + assertEquals(new Rect(111, 32, 227 - 111, 104 - 32), button2.getBounds()); + + GridModel model = GridModel.get(new LayoutTestBase.TestRulesEngine(targetNode.getFqcn()), + targetNode, null); + assertEquals(3, model.declaredColumnCount); + assertEquals(3, model.actualColumnCount); + assertEquals(4, model.actualRowCount); + fail("Finish test"); + } + + public void testDelete5_INCOMPLETE() { + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:id=\"@+id/GridLayout1\" android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\" android:columnCount=\"4\"\n" + + " android:orientation=\"vertical\">\n" + + " <Button android:id=\"@+id/button1\" android:layout_column=\"0\"\n" + + " android:layout_gravity=\"center_horizontal|bottom\"\n" + + " android:layout_row=\"0\" android:text=\"Button\" />\n" + + " <Space android:layout_width=\"66dp\" android:layout_height=\"1dp\"\n" + + " android:layout_column=\"0\" android:layout_row=\"0\" />\n" + + " <Button android:id=\"@+id/button3\" android:layout_column=\"2\"\n" + + " android:layout_gravity=\"left|bottom\" android:layout_row=\"0\"\n" + + " android:text=\"Button\" />\n" + + " <Button android:id=\"@+id/button2\" android:layout_column=\"3\"\n" + + " android:layout_columnSpan=\"2\" android:layout_gravity=\"left|bottom\"\n" + + " android:layout_row=\"0\" android:text=\"Button\" />\n" + + " <Space android:id=\"@+id/spacer_109\" android:layout_width=\"51dp\"\n" + + " android:layout_height=\"1dp\" android:layout_column=\"1\"\n" + + " android:layout_row=\"0\" />\n" + + " <Space android:layout_width=\"129dp\" android:layout_height=\"1dp\"\n" + + " android:layout_column=\"2\" android:layout_row=\"0\" />\n" + + " <Space android:layout_width=\"62dp\" android:layout_height=\"1dp\"\n" + + " android:layout_column=\"3\" android:layout_row=\"0\" />\n" + + " <Space android:id=\"@+id/spacer_397\" android:layout_width=\"1dp\"\n" + + " android:layout_height=\"103dp\" android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + " <Space android:layout_width=\"1dp\" android:layout_height=\"356dp\"\n" + + " android:layout_column=\"0\" android:layout_row=\"1\" />\n" + + "</GridLayout>"; + TestNode targetNode = TestNode.createFromXml(xml); + assertNotNull(targetNode); + + targetNode.assignBounds( + "android.widget.GridLayout [0,109,480,800] <GridLayout> @+id/GridLayout1\n" + + " android.widget.Button [0,83,116,155] <Button> @+id/button1\n" + + " android.widget.Space [0,0,99,2] <Space>\n" + + " android.widget.Button [193,83,309,155] <Button> @+id/button3\n" + + " android.widget.Button [387,83,503,155] <Button> @+id/button2\n" + + " android.widget.Space [116,0,193,2] <Space> @+id/spacer_109\n" + + " android.widget.Space [193,0,387,2] <Space>\n" + + " android.widget.Space [387,0,480,2] <Space>\n" + + " android.widget.Space [0,0,2,155] <Space> @+id/spacer_397\n" + + " android.widget.Space [0,155,2,689] <Space>"); + + // Delete button3. This causes an array out of bounds exception currently. + + //TestNode layout = TestNode.findById(targetNode, "@+id/GridLayout1"); + //TestNode button1 = TestNode.findById(targetNode, "@+id/button1"); + TestNode button2 = TestNode.findById(targetNode, "@+id/button2"); + TestNode button3 = TestNode.findById(targetNode, "@+id/button3"); + assertEquals(new Rect(387, 83, 503 - 387, 155- 83), button2.getBounds()); + + GridModel model = GridModel.get(new LayoutTestBase.TestRulesEngine(targetNode.getFqcn()), + targetNode, null); + assertEquals(4, model.declaredColumnCount); + assertEquals(4, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + + model.onDeleted(Collections.<INode>singletonList(button3)); + // Exception fixed; todo: Test that the model updates are correct. + assertEquals(3, model.declaredColumnCount); assertEquals(3, model.actualColumnCount); assertEquals(2, model.actualRowCount); + + fail("Finish test"); + } + + public void testInsert1() throws Exception { + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:id=\"@+id/GridLayout1\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:columnCount=\"4\"\n" + + " android:orientation=\"vertical\" >\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button1\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_columnSpan=\"4\"\n" + + " android:layout_gravity=\"center_horizontal|bottom\"\n" + + " android:layout_row=\"0\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button2\"\n" + + " android:layout_column=\"2\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button3\"\n" + + " android:layout_column=\"3\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/spacer_393\"\n" + + " android:layout_width=\"81dp\"\n" + + " android:layout_height=\"1dp\"\n" + + " android:layout_column=\"1\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/spacer_397\"\n" + + " android:layout_width=\"1dp\"\n" + + " android:layout_height=\"103dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + "</GridLayout>"; + + TestNode targetNode = TestNode.createFromXml(xml); + assertNotNull(targetNode); + + TestNode layout = TestNode.findById(targetNode, "@+id/GridLayout1"); + TestNode button1 = TestNode.findById(targetNode, "@+id/button1"); + TestNode button2 = TestNode.findById(targetNode, "@+id/button2"); + TestNode button3 = TestNode.findById(targetNode, "@+id/button3"); + TestNode hspacer = TestNode.findById(targetNode, "@+id/spacer_393"); + TestNode vspacer = TestNode.findById(targetNode, "@+id/spacer_397"); + assertNotNull(layout); + assertNotNull(button1); + assertNotNull(button2); + assertNotNull(button3); + assertNotNull(hspacer); + + // Obtained by setting ViewHierarchy.DUMP_INFO=true: + layout.bounds(new Rect(0, 109, 480, 800-109)); + button1.bounds(new Rect(182, 83, 298-182, 155-83)); + button2.bounds(new Rect(124, 155, 240-124, 227-155)); + button3.bounds(new Rect(240, 155, 356-240, 227-155)); + hspacer.bounds(new Rect(2, 0, 124-2, 2)); + vspacer.bounds(new Rect(0, 0, 2, 155)); + + GridModel model = GridModel.get(new LayoutTestBase.TestRulesEngine(targetNode.getFqcn()), + targetNode, null); + assertEquals(4, model.declaredColumnCount); + assertEquals(4, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + + + model.splitColumn(1, false, 21, 32); + int index = model.getInsertIndex(2, 1); + GridModel.ViewData next = model.getView(index); + INode newChild = targetNode.insertChildAt(FQCN_BUTTON, index); + next.applyPositionAttributes(); + model.setGridAttribute(newChild, ATTR_LAYOUT_COLUMN, 1); + model.setGridAttribute(newChild, ATTR_LAYOUT_COLUMN_SPAN, 3); + } + + public void testInsert2() throws Exception { + // Drop into a view where there is a centered view: when dropping to the right of + // it (on a row further down), ensure that the row span is increased for the + // non-left-justified centered view which does not horizontally overlap the view + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:id=\"@+id/GridLayout1\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:columnCount=\"3\"\n" + + " android:orientation=\"vertical\" >\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button1\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_columnSpan=\"3\"\n" + + " android:layout_gravity=\"center_horizontal|bottom\"\n" + + " android:layout_row=\"0\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button2\"\n" + + " android:layout_column=\"1\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button3\"\n" + + " android:layout_column=\"2\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/spacer_393\"\n" + + " android:layout_width=\"81dp\"\n" + + " android:layout_height=\"1dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + " \n" + + " <Space\n" + + " android:id=\"@+id/spacer_397\"\n" + + " android:layout_width=\"1dp\"\n" + + " android:layout_height=\"103dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + " \n" + + "</GridLayout>"; + + TestNode targetNode = TestNode.createFromXml(xml); + assertNotNull(targetNode); + + TestNode layout = TestNode.findById(targetNode, "@+id/GridLayout1"); + TestNode button1 = TestNode.findById(targetNode, "@+id/button1"); + TestNode button2 = TestNode.findById(targetNode, "@+id/button2"); + TestNode button3 = TestNode.findById(targetNode, "@+id/button3"); + TestNode hspacer = TestNode.findById(targetNode, "@+id/spacer_393"); + TestNode vspacer = TestNode.findById(targetNode, "@+id/spacer_397"); + assertNotNull(layout); + assertNotNull(button1); + assertNotNull(button2); + assertNotNull(button3); + assertNotNull(hspacer); + + // Obtained by setting ViewHierarchy.DUMP_INFO=true: + layout.bounds(new Rect(0, 109, 480, 800-109)); + button1.bounds(new Rect(182, 83, 298-182, 155-83)); + button2.bounds(new Rect(122, 155, 238-122, 227-155)); + button3.bounds(new Rect(238, 155, 354-238, 227-155)); + hspacer.bounds(new Rect(0, 0, 122, 2)); + vspacer.bounds(new Rect(0, 0, 2, 155)); + + GridModel model = GridModel.get(new LayoutTestBase.TestRulesEngine(targetNode.getFqcn()), + targetNode, null); + assertEquals(3, model.declaredColumnCount); + assertEquals(3, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + + ViewData view = model.getView(button1); + assertNotNull(view); + assertEquals(0, view.column); + assertEquals(3, view.columnSpan); + assertEquals("3", view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN)); + + model.splitColumn(3, false, 53, 318); + assertEquals(0, view.column); + assertEquals(4, view.columnSpan); + assertEquals("4", view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN)); + } + + public void testInsert3_BROKEN() throws Exception { + // Check that when we insert a new gap column near an existing column, the + // view in that new column does not get moved + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<GridLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:id=\"@+id/GridLayout1\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:columnCount=\"3\"\n" + + " android:orientation=\"vertical\" >\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button1\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_columnSpan=\"3\"\n" + + " android:layout_gravity=\"center_horizontal|bottom\"\n" + + " android:layout_row=\"0\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button2\"\n" + + " android:layout_column=\"1\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Button\n" + + " android:id=\"@+id/button3\"\n" + + " android:layout_column=\"2\"\n" + + " android:layout_gravity=\"left|top\"\n" + + " android:layout_row=\"1\"\n" + + " android:text=\"Button\" />\n" + + "\n" + + " <Space\n" + + " android:id=\"@+id/spacer_393\"\n" + + " android:layout_width=\"81dp\"\n" + + " android:layout_height=\"1dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + " \n" + + " <Space\n" + + " android:id=\"@+id/spacer_397\"\n" + + " android:layout_width=\"1dp\"\n" + + " android:layout_height=\"103dp\"\n" + + " android:layout_column=\"0\"\n" + + " android:layout_row=\"0\" />\n" + + "\n" + + " \n" + + "</GridLayout>"; + + TestNode targetNode = TestNode.createFromXml(xml); + assertNotNull(targetNode); + + TestNode layout = TestNode.findById(targetNode, "@+id/GridLayout1"); + TestNode button1 = TestNode.findById(targetNode, "@+id/button1"); + TestNode button2 = TestNode.findById(targetNode, "@+id/button2"); + TestNode button3 = TestNode.findById(targetNode, "@+id/button3"); + TestNode hspacer = TestNode.findById(targetNode, "@+id/spacer_393"); + TestNode vspacer = TestNode.findById(targetNode, "@+id/spacer_397"); + assertNotNull(layout); + assertNotNull(button1); + assertNotNull(button2); + assertNotNull(button3); + assertNotNull(hspacer); + + // Obtained by setting ViewHierarchy.DUMP_INFO=true: + layout.bounds(new Rect(0, 109, 480, 800-109)); + button1.bounds(new Rect(182, 83, 298-182, 155-83)); + button2.bounds(new Rect(122, 155, 238-122, 227-155)); + button3.bounds(new Rect(238, 155, 354-238, 227-155)); + hspacer.bounds(new Rect(0, 0, 122, 2)); + vspacer.bounds(new Rect(0, 0, 2, 155)); + + GridModel model = GridModel.get(new LayoutTestBase.TestRulesEngine(targetNode.getFqcn()), + targetNode, null); + assertEquals(3, model.declaredColumnCount); + assertEquals(3, model.actualColumnCount); + assertEquals(2, model.actualRowCount); + + ViewData view = model.getView(button3); + assertNotNull(view); + assertEquals(2, view.column); + assertEquals(1, view.columnSpan); + assertNull("1", view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN)); + + model.splitColumn(2, true, 10, 253); + // TODO: Finish this test: Assert that the cells are in the right place + //assertEquals(4, view.column); + //assertEquals(1, view.columnSpan); + //assertEquals("4", view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN)); + fail("Finish test"); } } |