aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayout.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseView.java11
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java6
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java1
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbsoluteLayoutRuleTest.java73
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbstractLayoutRuleTest.java180
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/BaseLayoutTest.java240
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/BaseViewTest.java42
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/FrameLayoutRuleTest.java63
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LinearLayoutRuleTest.java308
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/RelativeLayoutRuleTest.java165
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java54
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttributeInfo.java56
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestColor.java36
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java142
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestGraphics.java148
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java164
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/ZoomControlsRuleTest.java50
19 files changed, 1742 insertions, 6 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java
index 6d640a1..e2d64eb 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java
@@ -54,7 +54,11 @@ public class AbsoluteLayoutRule extends BaseLayout {
});
}
- void drawFeedback(IGraphics gc, INode targetNode, IDragElement[] elements, DropFeedback feedback) {
+ void drawFeedback(
+ IGraphics gc,
+ INode targetNode,
+ IDragElement[] elements,
+ DropFeedback feedback) {
Rect b = targetNode.getBounds();
if (!b.isValid()) {
return;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayout.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayout.java
index 9d8e0c2..13b335e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayout.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayout.java
@@ -355,7 +355,8 @@ public class BaseLayout extends BaseView {
if (value != null && value.length() > 0) {
newNode.setAttribute(uri, name, value);
- if (uri.equals(ANDROID_URI) && name.equals(ATTR_ID) && oldId != null && !oldId.equals(value)) {
+ if (uri.equals(ANDROID_URI) && name.equals(ATTR_ID) &&
+ oldId != null && !oldId.equals(value)) {
newId = value;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseView.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseView.java
index 950ea2b..9bd82a7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseView.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseView.java
@@ -143,7 +143,10 @@ public class BaseView implements IViewRule {
IMenuCallback onChange = new IMenuCallback() {
- public void action(final MenuAction action, final String valueId, final Boolean newValue) {
+ public void action(
+ final MenuAction action,
+ final String valueId,
+ final Boolean newValue) {
String fullActionId = action.getId();
boolean isProp = fullActionId.startsWith("@prop@");
final String actionId = isProp ? fullActionId.substring(6) : fullActionId;
@@ -460,7 +463,11 @@ public class BaseView implements IViewRule {
// ignore
}
- public void onDropped(INode targetNode, IDragElement[] elements, DropFeedback feedback, Point p) {
+ public void onDropped(
+ INode targetNode,
+ IDragElement[] elements,
+ DropFeedback feedback,
+ Point p) {
// ignore
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java
index f3efb64..16b477b 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java
@@ -51,7 +51,11 @@ public class FrameLayoutRule extends BaseLayout {
});
}
- void drawFeedback(IGraphics gc, INode targetNode, IDragElement[] elements, DropFeedback feedback) {
+ void drawFeedback(
+ IGraphics gc,
+ INode targetNode,
+ IDragElement[] elements,
+ DropFeedback feedback) {
Rect b = targetNode.getBounds();
if (!b.isValid()) {
return;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
index 7a960b1..3e5bdcf 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
@@ -1152,7 +1152,6 @@ class LayoutCanvas extends Canvas implements ISelectionProvider {
int x = mHScale.inverseTranslate(e.x);
int y = mVScale.inverseTranslate(e.y);
- // test, remove me
if (e.button == 3) {
// Right click button is used to display a context menu.
// If there's an existing selection and the click is anywhere in this selection
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbsoluteLayoutRuleTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbsoluteLayoutRuleTest.java
new file mode 100644
index 0000000..2f4e22f
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbsoluteLayoutRuleTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.Point;
+import com.android.ide.common.api.Rect;
+
+/** Test the {@link AbsoluteLayoutRule} */
+public class AbsoluteLayoutRuleTest extends AbstractLayoutRuleTest {
+ // Utility for other tests
+ protected INode dragInto(Rect dragBounds, Point dragPoint, int insertIndex, int currentIndex,
+ String... graphicsFragments) {
+ INode layout = TestNode.create("android.widget.AbsoluteLayout").id("@+id/AbsoluteLayout01")
+ .bounds(new Rect(0, 0, 240, 480)).add(
+ TestNode.create("android.widget.Button").id("@+id/Button01").bounds(
+ new Rect(0, 0, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button02").bounds(
+ new Rect(0, 100, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button03").bounds(
+ new Rect(0, 200, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button04").bounds(
+ new Rect(0, 300, 100, 80)));
+
+ return super.dragInto(new AbsoluteLayoutRule(), layout, dragBounds, dragPoint, null,
+ insertIndex, currentIndex, graphicsFragments);
+ }
+
+ public void testDragMiddle() {
+ INode inserted = dragInto(
+ // Bounds of the dragged item
+ new Rect(0, 0, 105, 80),
+ // Drag point
+ new Point(30, -10),
+ // Expected insert location: We just append in absolute layout
+ 4,
+ // Not dragging one of the existing children
+ -1,
+ // Bounds rectangle
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Drop preview
+ "useStyle(DROP_PREVIEW), drawRect(Rect[30,-10,105,80])");
+
+ assertEquals("30dip", inserted.getStringAttr(BaseLayout.ANDROID_URI, "layout_x"));
+ assertEquals("-10dip", inserted.getStringAttr(BaseLayout.ANDROID_URI, "layout_y"));
+
+ // Without drag bounds we should just draw guide lines instead
+ inserted = dragInto(new Rect(0, 0, 0, 0), new Point(30, -10), 4, -1,
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+ // Guideline
+ "useStyle(GUIDELINE), drawLine(30,0,30,480), drawLine(0,-10,240,-10)",
+ // Drop preview
+ "useStyle(DROP_PREVIEW), drawLine(30,-10,240,-10), drawLine(30,-10,30,480)");
+ assertEquals("30dip", inserted.getStringAttr(BaseLayout.ANDROID_URI, "layout_x"));
+ assertEquals("-10dip", inserted.getStringAttr(BaseLayout.ANDROID_URI, "layout_y"));
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbstractLayoutRuleTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbstractLayoutRuleTest.java
new file mode 100644
index 0000000..96cdbb6
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbstractLayoutRuleTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.DropFeedback;
+import com.android.ide.common.api.IDragElement;
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.IViewRule;
+import com.android.ide.common.api.Point;
+import com.android.ide.common.api.Rect;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ * Common layout helpers from LayoutRule tests
+ */
+public abstract class AbstractLayoutRuleTest extends TestCase {
+ public static String ANDROID_URI = BaseLayout.ANDROID_URI;
+ public static String ATTR_ID = BaseLayout.ATTR_ID;
+
+ /**
+ * Helper function used by tests to drag a button into a canvas containing
+ * the given children.
+ *
+ * @param rule The rule to test on
+ * @param targetNode The target layout node to drag into
+ * @param dragBounds The (original) bounds of the dragged item
+ * @param dropPoint The drag point we should drag to and drop
+ * @param secondDropPoint An optional second drag point to drag to before
+ * drawing graphics and dropping (or null if not applicable)
+ * @param insertIndex The expected insert position we end up with after
+ * dropping at the dropPoint
+ * @param currentIndex If the dragged widget is already in the canvas this
+ * should be its child index; if not, pass in -1
+ * @param graphicshicsFragments This is a varargs array of String fragments
+ * we expect to see in the graphics output on the drag over
+ * event.
+ * @return The inserted node
+ */
+ protected INode dragInto(IViewRule rule, INode targetNode, Rect dragBounds, Point dropPoint,
+ Point secondDropPoint, int insertIndex, int currentIndex,
+ String... graphicsFragments) {
+
+ String draggedButtonId = (currentIndex == -1) ? "@+id/DraggedButton" : targetNode
+ .getChildren()[currentIndex].getStringAttr(ANDROID_URI, ATTR_ID);
+
+ IDragElement[] elements = TestDragElement.create(TestDragElement.create(
+ "android.widget.Button", dragBounds).id(draggedButtonId));
+
+ // Enter target
+ DropFeedback feedback = rule.onDropEnter(targetNode, elements);
+ assertNotNull(feedback);
+ assertFalse(feedback.invalidTarget);
+ assertNotNull(feedback.painter);
+
+ if (currentIndex != -1) {
+ feedback.sameCanvas = true;
+ }
+
+ // Move near top left corner of the target
+ feedback = rule.onDropMove(targetNode, elements, feedback, dropPoint);
+ assertNotNull(feedback);
+
+ if (secondDropPoint != null) {
+ feedback = rule.onDropMove(targetNode, elements, feedback, secondDropPoint);
+ assertNotNull(feedback);
+ }
+
+ if (insertIndex == -1) {
+ assertTrue(feedback.invalidTarget);
+ } else {
+ assertFalse(feedback.invalidTarget);
+ }
+
+ // Paint feedback and make sure it's what we expect
+ TestGraphics graphics = new TestGraphics();
+ assertNotNull(feedback.painter);
+ feedback.painter.paint(graphics, targetNode, feedback);
+ String drawn = graphics.getDrawn().toString();
+
+ // Check that each graphics fragment is drawn
+ for (String fragment : graphicsFragments) {
+ if (!drawn.contains(fragment)) {
+ // Get drawn-output since unit test truncates message in below
+ // contains-assertion
+ System.out.println("Could not find: " + fragment);
+ System.out.println("Full graphics output: " + drawn);
+ }
+ assertTrue(fragment + " not found; full=" + drawn, drawn.contains(fragment));
+ }
+
+ // Attempt a drop?
+ if (insertIndex == -1) {
+ // No, not expected to succeed (for example, when drop point is over an
+ // invalid region in RelativeLayout) - just return.
+ return null;
+ }
+ int childrenCountBefore = targetNode.getChildren().length;
+ rule.onDropped(targetNode, elements, feedback, dropPoint);
+
+ if (currentIndex == -1) {
+ // Inserting new from outside
+ assertEquals(childrenCountBefore+1, targetNode.getChildren().length);
+ } else {
+ // Moving from existing; must remove in old position first
+ ((TestNode) targetNode).removeChild(currentIndex);
+
+ assertEquals(childrenCountBefore, targetNode.getChildren().length);
+ }
+ // Ensure that it's inserted in the right place
+ String actualId = targetNode.getChildren()[insertIndex].getStringAttr(
+ ANDROID_URI, ATTR_ID);
+ if (!draggedButtonId.equals(actualId)) {
+ // Using assertEquals instead of fail to get nice diff view on test
+ // failure
+ List<String> childrenIds = new ArrayList<String>();
+ for (INode child : targetNode.getChildren()) {
+ childrenIds.add(child.getStringAttr(ANDROID_URI, ATTR_ID));
+ }
+ int index = childrenIds.indexOf(draggedButtonId);
+ String message = "Button found at index " + index + " instead of " + insertIndex
+ + " among " + childrenIds;
+ System.out.println(message);
+ assertEquals(message, draggedButtonId, actualId);
+ }
+
+
+ return targetNode.getChildren()[insertIndex];
+ }
+
+ /**
+ * Utility method for asserting that two collections contain exactly the
+ * same elements (regardless of order)
+ */
+ public static void assertContainsSame(Collection<String> expected, Collection<String> actual) {
+ if (expected.size() != actual.size()) {
+ fail("Collection sizes differ; expected " + expected.size() + " but was "
+ + actual.size());
+ }
+
+ // Sort prior to comparison to ensure we have the same elements
+ // regardless of order
+ List<String> expectedList = new ArrayList<String>(expected);
+ Collections.sort(expectedList);
+ List<String> actualList = new ArrayList<String>(actual);
+ Collections.sort(actualList);
+ // Instead of just assertEquals(expectedList, actualList);
+ // we iterate one element at a time so we can show the first
+ // -difference-.
+ for (int i = 0; i < expectedList.size(); i++) {
+ String expectedElement = expectedList.get(i);
+ String actualElement = actualList.get(i);
+ if (!expectedElement.equals(actualElement)) {
+ System.out.println("Expected items: " + expectedList);
+ System.out.println("Actual items : " + actualList);
+ }
+ assertEquals("Collections differ; first difference:", expectedElement, actualElement);
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/BaseLayoutTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/BaseLayoutTest.java
new file mode 100644
index 0000000..dad1420
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/BaseLayoutTest.java
@@ -0,0 +1,240 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.IDragElement;
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.Rect;
+import com.android.ide.common.layout.BaseLayout.AttributeFilter;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+// TODO: Check assertions
+// TODO: Check equals() but not == strings by using new String("") to prevent interning
+// TODO: Rename BaseLayout to BaseLayoutRule, and tests too of course
+
+public class BaseLayoutTest extends AbstractLayoutRuleTest {
+
+ /** Provides test data used by other test cases */
+ private IDragElement[] createSampleElements() {
+ IDragElement[] elements = TestDragElement.create(TestDragElement.create(
+ "android.widget.Button", new Rect(0, 0, 100, 80)).id("@+id/Button01"),
+ TestDragElement.create("android.widget.LinearLayout", new Rect(0, 80, 100, 280))
+ .id("@+id/LinearLayout01").add(
+ TestDragElement.create("android.widget.Button",
+ new Rect(0, 80, 100, 80)).id("@+id/Button011"),
+ TestDragElement.create("android.widget.Button",
+ new Rect(0, 180, 100, 80)).id("@+id/Button012")),
+ TestDragElement.create("android.widget.Button", new Rect(100, 0, 100, 80)).id(
+ "@+id/Button02"));
+ return elements;
+ }
+
+ /** Test {@link BaseLayout#collectIds}: Check that basic lookup of id works */
+ public final void testCollectIds1() {
+ IDragElement[] elements = TestDragElement.create(TestDragElement.create(
+ "android.widget.Button", new Rect(0, 0, 100, 80)).id("@+id/Button01"));
+ Map<String, Pair<String, String>> idMap = new HashMap<String, Pair<String, String>>();
+ Map<String, Pair<String, String>> ids = new BaseLayout().collectIds(idMap, elements);
+ assertEquals(1, ids.size());
+ assertEquals("@+id/Button01", ids.keySet().iterator().next());
+ }
+
+ /**
+ * Test {@link BaseLayout#collectIds}: Check that with the wrong URI we
+ * don't pick up the ID
+ */
+ public final void testCollectIds2() {
+ IDragElement[] elements = TestDragElement.create(TestDragElement.create(
+ "android.widget.Button", new Rect(0, 0, 100, 80)).set("myuri", BaseView.ATTR_ID,
+ "@+id/Button01"));
+
+ Map<String, Pair<String, String>> idMap = new HashMap<String, Pair<String, String>>();
+ Map<String, Pair<String, String>> ids = new BaseLayout().collectIds(idMap, elements);
+ assertEquals(0, ids.size());
+ }
+
+ /**
+ * Test {@link BaseLayout#normalizeId(String)}
+ */
+ public final void testNormalizeId() {
+ assertEquals("foo", new BaseLayout().normalizeId("foo"));
+ assertEquals("@+id/name", new BaseLayout().normalizeId("@id/name"));
+ assertEquals("@+id/name", new BaseLayout().normalizeId("@+id/name"));
+ }
+
+ /**
+ * Test {@link BaseLayout#collectExistingIds}
+ */
+ public final void testCollectExistingIds1() {
+ Set<String> existing = new HashSet<String>();
+ INode node = TestNode.create("android.widget.Button").id("@+id/Button012").add(
+ TestNode.create("android.widget.Button").id("@+id/Button2"));
+
+ new BaseLayout().collectExistingIds(node, existing);
+
+ assertEquals(2, existing.size());
+ assertContainsSame(Arrays.asList("@+id/Button2", "@+id/Button012"), existing);
+ }
+
+ /**
+ * Test {@link BaseLayout#collectIds}: Check that with multiple elements and
+ * some children we still pick up all the right id's
+ */
+ public final void testCollectIds3() {
+ Map<String, Pair<String, String>> idMap = new HashMap<String, Pair<String, String>>();
+
+ IDragElement[] elements = createSampleElements();
+ Map<String, Pair<String, String>> ids = new BaseLayout().collectIds(idMap, elements);
+ assertEquals(5, ids.size());
+ assertContainsSame(Arrays.asList("@+id/Button01", "@+id/Button02", "@+id/Button011",
+ "@+id/Button012", "@+id/LinearLayout01"), ids.keySet());
+
+ // Make sure the Pair has the right stuff too;
+ // (having the id again in the pair seems redundant; see if I really
+ // need it in the implementation)
+ assertEquals(Pair.of("@+id/LinearLayout01", "android.widget.LinearLayout"), ids
+ .get("@+id/LinearLayout01"));
+ }
+
+ /**
+ * Test {@link BaseLayout#remapIds}: Ensure that it identifies a conflict
+ */
+ public final void testRemapIds1() {
+ Map<String, Pair<String, String>> idMap = new HashMap<String, Pair<String, String>>();
+ BaseLayout baseLayout = new BaseLayout();
+ IDragElement[] elements = createSampleElements();
+ baseLayout.collectIds(idMap, elements);
+ INode node = TestNode.create("android.widget.Button").id("@+id/Button012").add(
+ TestNode.create("android.widget.Button").id("@+id/Button2"));
+
+ assertEquals(5, idMap.size());
+ Map<String, Pair<String, String>> remapped = baseLayout.remapIds(node, idMap);
+ // 4 original from the sample elements, plus overlap with one
+ // (Button012) - one new
+ // button added in
+ assertEquals(6, remapped.size());
+
+ // TODO: I'm a little confused about what exactly this method should do;
+ // check with Raphael.
+ }
+
+
+ /**
+ * Test {@link BaseLayout#getDropIdMap}
+ */
+ public final void testGetDropIdMap() {
+ BaseLayout baseLayout = new BaseLayout();
+ IDragElement[] elements = createSampleElements();
+ INode node = TestNode.create("android.widget.Button").id("@+id/Button012").add(
+ TestNode.create("android.widget.Button").id("@+id/Button2"));
+
+ Map<String, Pair<String, String>> idMap = baseLayout.getDropIdMap(node, elements, true);
+ assertContainsSame(Arrays.asList("@+id/Button01", "@+id/Button012", "@+id/Button011",
+ "@id/Button012", "@+id/Button02", "@+id/LinearLayout01"), idMap
+ .keySet());
+
+ // TODO: I'm a little confused about what exactly this method should do;
+ // check with Raphael.
+ }
+
+ public final void testAddAttributes1() {
+ BaseLayout layout = new BaseLayout();
+
+ // First try with no filter
+ IDragElement oldElement = TestDragElement.create("a.w.B").id("@+id/foo");
+ INode newNode = TestNode.create("a.w.B").id("@+id/foo").set("u", "key", "value").set("u",
+ "nothidden", "nothiddenvalue");
+ ;
+ AttributeFilter filter = null;
+ // No references in this test case
+ Map<String, Pair<String, String>> idMap = null;
+
+ layout.addAttributes(newNode, oldElement, idMap, filter);
+ assertEquals("value", newNode.getStringAttr("u", "key"));
+ assertEquals("nothiddenvalue", newNode.getStringAttr("u", "nothidden"));
+ }
+
+ public final void testAddAttributes2() {
+ // Test filtering
+ BaseLayout layout = new BaseLayout();
+
+ // First try with no filter
+ IDragElement oldElement = TestDragElement.create("a.w.B").id("@+id/foo");
+ INode newNode = TestNode.create("a.w.B").id("@+id/foo").set("u", "key", "value").set("u",
+ "hidden", "hiddenvalue");
+ AttributeFilter filter = new AttributeFilter() {
+
+ public String replace(String attributeUri, String attributeName,
+ String attributeValue) {
+ if (attributeName.equals("hidden")) {
+ return null;
+ }
+
+ return attributeValue;
+ }
+ };
+ // No references in this test case
+ Map<String, Pair<String, String>> idMap = null;
+
+ layout.addAttributes(newNode, oldElement, idMap, filter);
+ assertEquals("value", newNode.getStringAttr("u", "key"));
+ }
+
+ public final void testFindNewId() {
+ BaseLayout baseLayout = new BaseLayout();
+ Set<String> existing = new HashSet<String>();
+ assertEquals("@+id/Widget01", baseLayout.findNewId("a.w.Widget", existing));
+
+ existing.add("@+id/Widget01");
+ assertEquals("@+id/Widget02", baseLayout.findNewId("a.w.Widget", existing));
+
+ existing.add("@+id/Widget02");
+ assertEquals("@+id/Widget03", baseLayout.findNewId("a.w.Widget", existing));
+
+ existing.remove("@+id/Widget02");
+ assertEquals("@+id/Widget02", baseLayout.findNewId("a.w.Widget", existing));
+ }
+
+ public final void testDefaultAttributeFilter() {
+ assertEquals("true", BaseLayout.DEFAULT_ATTR_FILTER.replace("myuri", "layout_alignRight",
+ "true"));
+ assertEquals(null, BaseLayout.DEFAULT_ATTR_FILTER.replace(BaseLayout.ANDROID_URI,
+ "layout_alignRight", "true"));
+ assertEquals("true", BaseLayout.DEFAULT_ATTR_FILTER.replace(BaseLayout.ANDROID_URI,
+ "myproperty", "true"));
+ }
+
+ public final void testAddInnerElements() {
+ IDragElement oldElement = TestDragElement.create("root").add(
+ TestDragElement.create("a.w.B").id("@+id/child1")
+ .set("uri", "childprop1", "value1"),
+ TestDragElement.create("a.w.B").id("@+id/child2").set("uri", "childprop2a",
+ "value2a").set("uri", "childprop2b", "value2b"));
+ INode newNode = TestNode.create("a.w.B").id("@+id/foo");
+ Map<String, Pair<String, String>> idMap = new HashMap<String, Pair<String, String>>();
+ BaseLayout layout = new BaseLayout();
+ layout.addInnerElements(newNode, oldElement, idMap);
+ assertEquals(2, newNode.getChildren().length);
+
+ assertEquals("value2b", newNode.getChildren()[1].getStringAttr("uri", "childprop2b"));
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/BaseViewTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/BaseViewTest.java
new file mode 100644
index 0000000..3634569
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/BaseViewTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.common.layout;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+public class BaseViewTest extends TestCase {
+ public final void testPrettyName() {
+ assertEquals(null, BaseView.prettyName(null));
+ assertEquals("", BaseView.prettyName(""));
+ assertEquals("Foo", BaseView.prettyName("foo"));
+ assertEquals("Foo bar", BaseView.prettyName("foo_bar"));
+ // TODO: We should check this to capitalize each initial word
+ // assertEquals("Foo Bar", BaseView.prettyName("foo_bar"));
+ // TODO: We should also handle camelcase properties
+ // assertEquals("Foo Bar", BaseView.prettyName("fooBar"));
+ }
+
+ public final void testJoin() {
+ assertEquals("foo", BaseView.join('|', Arrays.asList("foo")));
+ assertEquals("", BaseView.join('|', Collections.<String>emptyList()));
+ assertEquals("foo,bar", BaseView.join(',', Arrays.asList("foo", "bar")));
+ assertEquals("foo|bar", BaseView.join('|', Arrays.asList("foo", "bar")));
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/FrameLayoutRuleTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/FrameLayoutRuleTest.java
new file mode 100644
index 0000000..2adf4f0
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/FrameLayoutRuleTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.Point;
+import com.android.ide.common.api.Rect;
+
+/** Test the {@link FrameLayoutRule} */
+public class FrameLayoutRuleTest extends AbstractLayoutRuleTest {
+ // Utility for other tests
+ protected void dragInto(Rect dragBounds, Point dragPoint, int insertIndex, int currentIndex,
+ String... graphicsFragments) {
+ INode layout = TestNode.create("android.widget.FrameLayout").id("@+id/FrameLayout01")
+ .bounds(new Rect(0, 0, 240, 480)).add(
+ TestNode.create("android.widget.Button").id("@+id/Button01").bounds(
+ new Rect(0, 0, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button02").bounds(
+ new Rect(0, 100, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button03").bounds(
+ new Rect(0, 200, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button04").bounds(
+ new Rect(0, 300, 100, 80)));
+
+ super.dragInto(new FrameLayoutRule(), layout, dragBounds, dragPoint, null,
+ insertIndex, currentIndex, graphicsFragments);
+ }
+
+ public void testDragMiddle() {
+ dragInto(
+ // Bounds of the dragged item
+ new Rect(0, 0, 105, 80),
+ // Drag point
+ new Point(30, -10),
+ // Expected insert location: We just append in absolute layout
+ 4,
+ // Not dragging one of the existing children
+ -1,
+ // Bounds rectangle
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Drop Preview
+ "useStyle(DROP_PREVIEW), drawRect(Rect[0,0,105,80])]");
+ // Without drag bounds we should just draw guide lines instead
+ dragInto(new Rect(0, 0, 0, 0), new Point(30, -10), 4, -1,
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+ "useStyle(DROP_PREVIEW), drawLine(1,0,1,480), drawLine(0,1,240,1)");
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LinearLayoutRuleTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LinearLayoutRuleTest.java
new file mode 100644
index 0000000..42dbb3c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LinearLayoutRuleTest.java
@@ -0,0 +1,308 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.DropFeedback;
+import com.android.ide.common.api.IDragElement;
+import com.android.ide.common.api.IMenuCallback;
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.IViewRule;
+import com.android.ide.common.api.MenuAction;
+import com.android.ide.common.api.Point;
+import com.android.ide.common.api.Rect;
+import com.android.ide.common.api.MenuAction.Choices;
+
+import java.util.List;
+
+/** Test the {@link LinearLayoutRule} */
+public class LinearLayoutRuleTest extends AbstractLayoutRuleTest {
+ // Utility for other tests
+ protected void dragIntoEmpty(Rect dragBounds) {
+ boolean haveBounds = dragBounds.isValid();
+
+ IViewRule rule = new LinearLayoutRule();
+ INode targetNode = TestNode.create("android.widget.LinearLayout").id(
+ "@+id/LinearLayout01").bounds(new Rect(0, 0, 240, 480));
+ Point dropPoint = new Point(10, 5);
+
+ IDragElement[] elements = TestDragElement.create(TestDragElement.create(
+ "android.widget.Button", dragBounds).id("@+id/Button01"));
+
+ // Enter target
+ DropFeedback feedback = rule.onDropEnter(targetNode, elements);
+ assertNotNull(feedback);
+ assertFalse(feedback.invalidTarget);
+ assertNotNull(feedback.painter);
+
+ feedback = rule.onDropMove(targetNode, elements, feedback, dropPoint);
+ assertNotNull(feedback);
+ assertFalse(feedback.invalidTarget);
+
+ // Paint feedback and make sure it's what we expect
+ TestGraphics graphics = new TestGraphics();
+ assertNotNull(feedback.painter);
+ feedback.painter.paint(graphics, targetNode, feedback);
+ assertEquals(
+ // Expect to see a recipient rectangle around the bounds of the
+ // LinearLayout,
+ // as well as a single vertical line as a drop preview located
+ // along the left
+ // edge (for this horizontal linear layout) showing insert
+ // position at index 0,
+ // and finally a rectangle for the bounds of the inserted button
+ // centered over
+ // the middle
+ "[useStyle(DROP_RECIPIENT), "
+ +
+ // Bounds rectangle
+ "drawRect(Rect[0,0,240,480]), " + "useStyle(DROP_ZONE), "
+ + "useStyle(DROP_ZONE_ACTIVE), " + "useStyle(DROP_PREVIEW), " +
+ // Insert position line
+ "drawLine(1,0,1,480)" + (haveBounds ?
+ // Outline of dragged node centered over position line
+ ", useStyle(DROP_PREVIEW), " + "drawRect(Rect[-49,0,100,80])"
+ // Nothing when we don't have bounds
+ : "") + "]", graphics.getDrawn().toString());
+
+ // Attempt a drop
+ assertEquals(0, targetNode.getChildren().length);
+ rule.onDropped(targetNode, elements, feedback, dropPoint);
+ assertEquals(1, targetNode.getChildren().length);
+ assertEquals("@+id/Button01", targetNode.getChildren()[0].getStringAttr(
+ BaseLayout.ANDROID_URI, BaseLayout.ATTR_ID));
+ }
+
+ // Utility for other tests
+ protected INode dragInto(boolean vertical, Rect dragBounds, Point dragPoint,
+ int insertIndex, int currentIndex,
+ String... graphicsFragments) {
+ INode linearLayout = TestNode.create("android.widget.LinearLayout").id(
+ "@+id/LinearLayout01").bounds(new Rect(0, 0, 240, 480)).set(BaseLayout.ANDROID_URI,
+ LinearLayoutRule.ATTR_ORIENTATION,
+ vertical ? LinearLayoutRule.VALUE_VERTICAL : LinearLayoutRule.VALUE_HORIZONTAL)
+ .add(
+ TestNode.create("android.widget.Button").id("@+id/Button01").bounds(
+ new Rect(0, 0, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button02").bounds(
+ new Rect(0, 100, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button03").bounds(
+ new Rect(0, 200, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button04").bounds(
+ new Rect(0, 300, 100, 80)));
+
+ return super.dragInto(new LinearLayoutRule(), linearLayout, dragBounds, dragPoint, null,
+ insertIndex, currentIndex, graphicsFragments);
+ }
+
+ // Check that the context menu registers the expected menu items
+ public void testContextMenu() {
+ LinearLayoutRule rule = new LinearLayoutRule();
+ INode node = TestNode.create("android.widget.Button").id("@+id/Button012");
+
+ List<MenuAction> contextMenu = rule.getContextMenu(node);
+ assertEquals(4, contextMenu.size());
+ assertEquals("Layout Width", contextMenu.get(0).getTitle());
+ assertEquals("Layout Height", contextMenu.get(1).getTitle());
+ assertEquals("Properties", contextMenu.get(2).getTitle());
+ assertEquals("Orientation", contextMenu.get(3).getTitle());
+
+ MenuAction propertiesMenu = contextMenu.get(2);
+ assertTrue(propertiesMenu.getClass().getName(), propertiesMenu instanceof MenuAction.Group);
+ // TODO: Test Properties-list
+ }
+
+ // Check that the context menu manipulates the orientation attribute
+ public void testOrientation() {
+ LinearLayoutRule rule = new LinearLayoutRule();
+ INode node = TestNode.create("android.widget.Button").id("@+id/Button012");
+
+ assertNull(node.getStringAttr(BaseLayout.ANDROID_URI, LinearLayoutRule.ATTR_ORIENTATION));
+
+ List<MenuAction> contextMenu = rule.getContextMenu(node);
+ assertEquals(4, contextMenu.size());
+ MenuAction orientationAction = contextMenu.get(3);
+
+ assertTrue(orientationAction.getClass().getName(),
+ orientationAction instanceof MenuAction.Choices);
+
+ MenuAction.Choices choices = (Choices) orientationAction;
+ IMenuCallback callback = choices.getCallback();
+ callback.action(orientationAction, LinearLayoutRule.VALUE_VERTICAL, true);
+
+ String orientation = node.getStringAttr(BaseLayout.ANDROID_URI,
+ LinearLayoutRule.ATTR_ORIENTATION);
+ assertEquals(LinearLayoutRule.VALUE_VERTICAL, orientation);
+ callback.action(orientationAction, LinearLayoutRule.VALUE_HORIZONTAL, true);
+ orientation = node.getStringAttr(BaseLayout.ANDROID_URI, LinearLayoutRule.ATTR_ORIENTATION);
+ assertEquals(LinearLayoutRule.VALUE_HORIZONTAL, orientation);
+ }
+
+ public void testDragInEmptyWithBounds() {
+ dragIntoEmpty(new Rect(0, 0, 100, 80));
+ }
+
+ public void testDragInEmptyWithoutBounds() {
+ dragIntoEmpty(new Rect(0, 0, 0, 0));
+ }
+
+ public void testDragInVerticalTop() {
+ dragInto(true,
+ // Bounds of the dragged item
+ new Rect(0, 0, 105, 80),
+ // Drag point
+ new Point(30, -10),
+ // Expected insert location
+ 0,
+ // Not dragging one of the existing children
+ -1,
+ // Bounds rectangle
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Drop zones
+ "useStyle(DROP_ZONE), drawLine(0,0,240,0), drawLine(0,90,240,90), "
+ + "drawLine(0,190,240,190), drawLine(0,290,240,290)",
+
+ // Active nearest line
+ "useStyle(DROP_ZONE_ACTIVE), useStyle(DROP_PREVIEW), drawLine(0,0,240,0)",
+
+ // Preview of the dropped rectangle
+ "useStyle(DROP_PREVIEW), drawRect(Rect[0,-40,105,80])");
+
+ // Without drag bounds it should be identical except no preview
+ // rectangle
+ dragInto(true,
+ new Rect(0, 0, 0, 0), // Invalid
+ new Point(30, -10), 0, -1,
+ "useStyle(DROP_ZONE_ACTIVE), useStyle(DROP_PREVIEW), drawLine(0,0,240,0)");
+ }
+
+ public void testDragInVerticalBottom() {
+ dragInto(true,
+ // Bounds of the dragged item
+ new Rect(0, 0, 105, 80),
+ // Drag point
+ new Point(30, 500),
+ // Expected insert location
+ 4,
+ // Not dragging one of the existing children
+ -1,
+ // Bounds rectangle
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Drop zones
+ "useStyle(DROP_ZONE), drawLine(0,0,240,0), drawLine(0,90,240,90), "
+ + "drawLine(0,190,240,190), drawLine(0,290,240,290)",
+
+ // Active nearest line
+ "useStyle(DROP_ZONE_ACTIVE), useStyle(DROP_PREVIEW), drawLine(0,381,240,381)",
+
+ // Preview of the dropped rectangle
+ "useStyle(DROP_PREVIEW), drawRect(Rect[0,341,105,80])");
+
+ // Check without bounds too
+ dragInto(true, new Rect(0, 0, 105, 80), new Point(30, 500), 4, -1,
+ "useStyle(DROP_PREVIEW), drawRect(Rect[0,341,105,80])");
+ }
+
+ public void testDragInVerticalMiddle() {
+ dragInto(true,
+ // Bounds of the dragged item
+ new Rect(0, 0, 105, 80),
+ // Drag point
+ new Point(0, 170),
+ // Expected insert location
+ 2,
+ // Not dragging one of the existing children
+ -1,
+ // Bounds rectangle
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Drop zones
+ "useStyle(DROP_ZONE), drawLine(0,0,240,0), drawLine(0,90,240,90), "
+ + "drawLine(0,190,240,190), drawLine(0,290,240,290)",
+
+ // Active nearest line
+ "useStyle(DROP_ZONE_ACTIVE), useStyle(DROP_PREVIEW), drawLine(0,190,240,190)",
+
+ // Preview of the dropped rectangle
+ "useStyle(DROP_PREVIEW), drawRect(Rect[0,150,105,80])");
+
+ // Check without bounds too
+ dragInto(true, new Rect(0, 0, 105, 80), new Point(0, 170), 2, -1,
+ "useStyle(DROP_PREVIEW), drawRect(Rect[0,150,105,80])");
+ }
+
+ public void testDragInVerticalMiddleSelfPos() {
+ // Drag the 2nd button, down to the position between 3rd and 4th
+ dragInto(true,
+ // Bounds of the dragged item
+ new Rect(0, 100, 100, 80),
+ // Drag point
+ new Point(0, 250),
+ // Expected insert location
+ 2,
+ // Dragging 1st item
+ 1,
+ // Bounds rectangle
+
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Drop zones - these are different because we exclude drop
+ // zones around the
+ // dragged item itself (it doesn't make sense to insert directly
+ // before or after
+ // myself
+ "useStyle(DROP_ZONE), drawLine(0,0,240,0), drawLine(0,290,240,290), "
+ + "drawLine(0,381,240,381)",
+
+ // Preview line along insert axis
+ "useStyle(DROP_ZONE_ACTIVE), useStyle(DROP_PREVIEW), drawLine(0,290,240,290)",
+
+ // Preview of dropped rectangle
+ "useStyle(DROP_PREVIEW), drawRect(Rect[0,250,100,80])");
+
+ // Test dropping on self (no position change):
+ dragInto(true,
+ // Bounds of the dragged item
+ new Rect(0, 100, 100, 80),
+ // Drag point
+ new Point(0, 210),
+ // Expected insert location
+ 1,
+ // Dragging from same pos
+ 1,
+ // Bounds rectangle
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Drop zones - these are different because we exclude drop
+ // zones around the
+ // dragged item itself (it doesn't make sense to insert directly
+ // before or after
+ // myself
+ "useStyle(DROP_ZONE), drawLine(0,0,240,0), drawLine(0,290,240,290), "
+ + "drawLine(0,381,240,381)",
+
+ // No active nearest line when you're over the self pos!
+
+ // Preview of the dropped rectangle
+ "useStyle(DROP_ZONE_ACTIVE), useStyle(DROP_PREVIEW), drawRect(Rect[0,100,100,80])");
+ }
+
+ // Left to test:
+ // Check inserting at last pos with multiple children
+ // Check inserting with no bounds rectangle for dragged element
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/RelativeLayoutRuleTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/RelativeLayoutRuleTest.java
new file mode 100644
index 0000000..cc47df1
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/RelativeLayoutRuleTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.Point;
+import com.android.ide.common.api.Rect;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Test the {@link RelativeLayoutRule} */
+public class RelativeLayoutRuleTest extends AbstractLayoutRuleTest {
+ // Utility for other tests
+ protected INode dragInto(Rect dragBounds, Point dragPoint, Point secondDragPoint,
+ int insertIndex, int currentIndex, String... graphicsFragments) {
+ INode layout = TestNode.create("android.widget.RelativeLayout").id("@+id/RelativeLayout01")
+ .bounds(new Rect(0, 0, 240, 480)).add(
+ // Add centered button as the anchor
+ TestNode.create("android.widget.Button").id("@+id/Centered").bounds(
+ new Rect(70, 200, 100, 80)).set(ANDROID_URI,
+ "layout_centerInParent", "true"),
+ // Add a second button anchored to it
+ TestNode.create("android.widget.Button").id("@+id/Below").bounds(
+ new Rect(70, 280, 100, 80)).set(ANDROID_URI, "layout_below",
+ "@+id/Centered").set(ANDROID_URI, "layout_alignLeft",
+ "@+id/Centered"));
+
+ return super.dragInto(new RelativeLayoutRule(), layout, dragBounds, dragPoint,
+ secondDragPoint, insertIndex, currentIndex, graphicsFragments);
+ }
+
+ protected INode dragInto(Rect dragBounds, Point dragPoint, Point secondDragPoint,
+ int insertIndex, int currentIndex, String[] extraFragments,
+ String... graphicsFragments) {
+
+ // When we switch to JDK6, use Arrays#copyOf instead
+ String[] combined = new String[extraFragments.length + graphicsFragments.length];
+ System.arraycopy(graphicsFragments, 0, combined, 0, graphicsFragments.length);
+ System.arraycopy(extraFragments, 0, combined, graphicsFragments.length,
+ extraFragments.length);
+
+ return dragInto(dragBounds, dragPoint, secondDragPoint, insertIndex,
+ currentIndex, combined);
+ }
+
+ public void testDropTopEdge() {
+ // If we drag right into the button itself, not a valid drop position
+ INode inserted = dragInto(
+ new Rect(0, 0, 105, 80), new Point(30, -10), null, 2, -1,
+ // Bounds rectangle
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Preview line + drop zone rectangle along the top
+ "useStyle(DROP_ZONE), drawRect(Rect[0,-10,240,20])",
+ "useStyle(DROP_ZONE_ACTIVE), fillRect(Rect[0,-10,240,20])",
+ "useStyle(DROP_PREVIEW), drawLine(0,0,240,0)",
+
+ // Tip
+ "useStyle(HELP), drawBoxedStrings(5,15,[alignParentTop])",
+
+ // Drop preview
+ "useStyle(DROP_PREVIEW), drawRect(Rect[0,0,105,80])");
+
+ assertEquals("true", inserted.getStringAttr(BaseLayout.ANDROID_URI,
+ "layout_alignParentTop"));
+ }
+
+ public void testDropZones() {
+ List<Pair<Point,String[]>> zones = new ArrayList<Pair<Point,String[]>>();
+
+ zones.add(Pair.of(new Point(51+10, 181+10),
+ new String[] {"above=@+id/Centered", "toLeftOf=@+id/Centered"}));
+ zones.add(Pair.of(new Point(71+10, 181+10),
+ new String[] {"above=@+id/Centered", "alignLeft=@+id/Centered"}));
+ zones.add(Pair.of(new Point(104+10, 181+10),
+ new String[] {"above=@+id/Centered", "alignRight=@+id/Centered"}));
+ zones.add(Pair.of(new Point(137+10, 181+10),
+ new String[] {"above=@+id/Centered", "alignRight=@+id/Centered"}));
+ zones.add(Pair.of(new Point(170+10, 181+10),
+ new String[] {"above=@+id/Centered", "toRightOf=@+id/Centered"}));
+ zones.add(Pair.of(new Point(51+10, 279+10),
+ new String[] {"below=@+id/Centered", "toLeftOf=@+id/Centered"}));
+ zones.add(Pair.of(new Point(71+10, 279+10),
+ new String[] {"below=@+id/Centered", "alignLeft=@+id/Centered"}));
+ zones.add(Pair.of(new Point(104+10, 279+10),
+ new String[] {"below=@+id/Centered", "alignLeft=@+id/Centered"}));
+ zones.add(Pair.of(new Point(137+10, 279+10),
+ new String[] {"below=@+id/Centered", "alignRight=@+id/Centered"}));
+ zones.add(Pair.of(new Point(170+10, 279+10),
+ new String[] {"below=@+id/Centered", "toRightOf=@+id/Centered"}));
+ zones.add(Pair.of(new Point(51+10, 201+10),
+ new String[] {"toLeftOf=@+id/Centered", "alignTop=@+id/Centered"}));
+ zones.add(Pair.of(new Point(51+10, 227+10),
+ new String[] {"toLeftOf=@+id/Centered", "alignTop=@+id/Centered"}));
+ zones.add(Pair.of(new Point(170+10, 201+10),
+ new String[] {"toRightOf=@+id/Centered", "alignTop=@+id/Centered"}));
+ zones.add(Pair.of(new Point(51+10, 253+10),
+ new String[] {"toLeftOf=@+id/Centered", "alignBottom=@+id/Centered"}));
+ zones.add(Pair.of(new Point(170+10, 227+10),
+ new String[] {"toRightOf=@+id/Centered", "alignTop=@+id/Centered",
+ "alignBottom=@+id/Centered"}));
+ zones.add(Pair.of(new Point(170+10, 253+10),
+ new String[] {"toRightOf=@+id/Centered", "alignBottom=@+id/Centered"}));
+
+ for (Pair<Point,String[]> zonePair : zones) {
+ Point dropPoint = zonePair.getFirst();
+ String[] attachments = zonePair.getSecond();
+ // If we drag right into the button itself, not a valid drop position
+
+ INode inserted = dragInto(
+ new Rect(0, 0, 105, 80), new Point(120, 240), dropPoint, 1, -1,
+ attachments,
+
+ // Bounds rectangle
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Drop zones
+ "useStyle(DROP_ZONE), "
+ + "drawRect(Rect[51,181,20,20]), drawRect(Rect[71,181,33,20]), "
+ + "drawRect(Rect[104,181,33,20]), drawRect(Rect[137,181,33,20]), "
+ + "drawRect(Rect[170,181,20,20]), drawRect(Rect[51,279,20,20]), "
+ + "drawRect(Rect[71,279,33,20]), drawRect(Rect[104,279,33,20]), "
+ + "drawRect(Rect[137,279,33,20]), drawRect(Rect[170,279,20,20]), "
+ + "drawRect(Rect[51,201,20,26]), drawRect(Rect[51,227,20,26]), "
+ + "drawRect(Rect[51,253,20,26]), drawRect(Rect[170,201,20,26]), "
+ + "drawRect(Rect[170,227,20,26]), drawRect(Rect[170,253,20,26])");
+
+ for (String attachment : attachments) {
+ String[] elements = attachment.split("=");
+ String name = "layout_" + elements[0];
+ String value = elements[1];
+ assertEquals(value, inserted.getStringAttr(BaseLayout.ANDROID_URI, name));
+ }
+ }
+ }
+
+
+ public void testDragInvalid() {
+ // If we drag right into the button itself, not a valid drop position
+ dragInto(new Rect(70, 200, 100, 80), new Point(120, 240), new Point(120, 240), -1, 0,
+ // Bounds rectangle
+ "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])",
+
+ // Invalid marker
+ "useStyle(INVALID), fillRect(Rect[70,200,100,80]), drawLine(70,200,170,280), "
+ + "drawLine(70,280,170,200)");
+ }
+
+ // TODO: Test error (dragging on ancestor)
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java
new file mode 100644
index 0000000..fc59ba8
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java
@@ -0,0 +1,54 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.IDragElement.IDragAttribute;
+import com.android.ide.common.api.INode.IAttribute;
+
+/** Test/mock implementation of {@link IAttribute} and {@link IDragAttribute} */
+public class TestAttribute implements IAttribute, IDragAttribute {
+ private String mUri;
+
+ private String mName;
+
+ private String mValue;
+
+ public TestAttribute(String mUri, String mName, String mValue) {
+ super();
+ this.mName = mName;
+ this.mUri = mUri;
+ this.mValue = mValue;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public String getUri() {
+ return mUri;
+ }
+
+ public String getValue() {
+ return mValue;
+ }
+
+ @Override
+ public String toString() {
+ return "TestAttribute [name=" + mName + ", uri=" + mUri + ", value=" + mValue + "]";
+ }
+
+
+} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttributeInfo.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttributeInfo.java
new file mode 100644
index 0000000..a864764
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttributeInfo.java
@@ -0,0 +1,56 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.IAttributeInfo;
+
+/** Test/mock implementation of {@link IAttributeInfo} */
+public class TestAttributeInfo implements IAttributeInfo {
+ private final String mName;
+
+ public TestAttributeInfo(String name) {
+ this.mName = name;
+ }
+
+ public String getDeprecatedDoc() {
+ BaseLayoutTest.fail("Not supported yet in tests");
+ return null;
+ }
+
+ public String[] getEnumValues() {
+ BaseLayoutTest.fail("Not supported yet in tests");
+ return null;
+ }
+
+ public String[] getFlagValues() {
+ BaseLayoutTest.fail("Not supported yet in tests");
+ return null;
+ }
+
+ public Format[] getFormats() {
+ BaseLayoutTest.fail("Not supported yet in tests");
+ return null;
+ }
+
+ public String getJavaDoc() {
+ BaseLayoutTest.fail("Not supported yet in tests");
+ return null;
+ }
+
+ public String getName() {
+ return mName;
+ }
+} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestColor.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestColor.java
new file mode 100644
index 0000000..449ad5e
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestColor.java
@@ -0,0 +1,36 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.IColor;
+
+public class TestColor implements IColor {
+ private int mRgb;
+
+ public TestColor(int rgb) {
+ this.mRgb = rgb;
+ }
+
+ public int getRgb() {
+ return mRgb;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("#%6x", mRgb);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java
new file mode 100644
index 0000000..b113ced
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java
@@ -0,0 +1,142 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.IDragElement;
+import com.android.ide.common.api.Rect;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Test/mock implementation of {@link IDragElement} */
+public class TestDragElement implements IDragElement {
+ private Rect mRect;
+
+ private final String mFqcn;
+
+ private Map<String, TestAttribute> mAttributes = new HashMap<String, TestAttribute>();
+
+ private List<TestDragElement> mChildren = new ArrayList<TestDragElement>();
+
+ private TestDragElement mParent;
+
+ public TestDragElement(String mFqcn, Rect mRect, List<TestDragElement> mChildren,
+ TestDragElement mParent) {
+ super();
+ this.mRect = mRect;
+ this.mFqcn = mFqcn;
+ this.mChildren = mChildren;
+ this.mParent = mParent;
+ }
+
+ public TestDragElement(String fqn) {
+ this(fqn, null, null, null);
+ }
+
+ public TestDragElement setBounds(Rect bounds) {
+ this.mRect = bounds;
+
+ return this;
+ }
+
+ // Builder stuff
+ public TestDragElement set(String uri, String name, String value) {
+ if (mAttributes == null) {
+ mAttributes = new HashMap<String, TestAttribute>();
+ }
+
+ mAttributes.put(uri + name, new TestAttribute(uri, name, value));
+
+ return this;
+ }
+
+ public TestDragElement add(TestDragElement... children) {
+ if (mChildren == null) {
+ mChildren = new ArrayList<TestDragElement>();
+ }
+
+ for (TestDragElement child : children) {
+ mChildren.add(child);
+ child.mParent = this;
+ }
+
+ return this;
+ }
+
+ public TestDragElement id(String id) {
+ return set(BaseView.ANDROID_URI, BaseView.ATTR_ID, id);
+ }
+
+ public static TestDragElement create(String fqn, Rect bounds) {
+ return create(fqn).setBounds(bounds);
+ }
+
+ public static TestDragElement create(String fqn) {
+ return new TestDragElement(fqn);
+ }
+
+ public static IDragElement[] create(TestDragElement... elements) {
+ return elements;
+ }
+
+ // ==== IDragElement ====
+
+ public IDragAttribute getAttribute(String uri, String localName) {
+ if (mAttributes == null) {
+ return new TestAttribute(uri, localName, "");
+ }
+
+ return mAttributes.get(uri + localName);
+ }
+
+ public IDragAttribute[] getAttributes() {
+ return mAttributes.values().toArray(new IDragAttribute[mAttributes.size()]);
+ }
+
+ public Rect getBounds() {
+ return mRect;
+ }
+
+ public String getFqcn() {
+ return mFqcn;
+ }
+
+ public IDragElement[] getInnerElements() {
+ if (mChildren == null) {
+ return new IDragElement[0];
+ }
+
+ return mChildren.toArray(new IDragElement[mChildren.size()]);
+ }
+
+ public Rect getParentBounds() {
+ return mParent != null ? mParent.getBounds() : null;
+ }
+
+ public String getParentFqcn() {
+ return mParent != null ? mParent.getFqcn() : null;
+ }
+
+ @Override
+ public String toString() {
+ return "TestDragElement [fqn=" + mFqcn + ", attributes=" + mAttributes + ", bounds="
+ + mRect + "]";
+ }
+
+
+} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestGraphics.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestGraphics.java
new file mode 100644
index 0000000..b82f309
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestGraphics.java
@@ -0,0 +1,148 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.DrawingStyle;
+import com.android.ide.common.api.IColor;
+import com.android.ide.common.api.IGraphics;
+import com.android.ide.common.api.Point;
+import com.android.ide.common.api.Rect;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+// TODO: Create box of ascii art
+
+public class TestGraphics implements IGraphics {
+ /** List of things we have drawn */
+ private List<String> mDrawn = new ArrayList<String>();
+
+ private IColor mBackground = new TestColor(0x000000);
+
+ private IColor mForeground = new TestColor(0xFFFFFF);
+
+ private int mAlpha = 128;
+
+ /** Return log of graphics calls */
+ public List<String> getDrawn() {
+ return Collections.unmodifiableList(mDrawn);
+ }
+
+ /** Wipe out log of graphics calls */
+ public void clear() {
+ mDrawn.clear();
+ }
+
+ // ==== IGraphics ====
+
+ public void drawBoxedStrings(int x, int y, List<?> strings) {
+ mDrawn.add("drawBoxedStrings(" + x + "," + y + "," + strings + ")");
+ }
+
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ mDrawn.add("drawLine(" + x1 + "," + y1 + "," + x2 + "," + y2 + ")");
+ }
+
+ public void drawLine(Point p1, Point p2) {
+ mDrawn.add("drawLine(" + p1 + "," + p2 + ")");
+ }
+
+ public void drawRect(int x1, int y1, int x2, int y2) {
+ mDrawn.add("drawRect(" + x1 + "," + y1 + "," + x2 + "," + y2 + ")");
+ }
+
+ public void drawRect(Point p1, Point p2) {
+ mDrawn.add("drawRect(" + p1 + "," + p2 + ")");
+ }
+
+ public void drawRect(Rect r) {
+ mDrawn.add("drawRect(" + rectToString(r) + ")");
+ }
+
+ public void drawString(String string, int x, int y) {
+ mDrawn.add("drawString(" + x + "," + y + "," + string + ")");
+ }
+
+ public void drawString(String string, Point topLeft) {
+ mDrawn.add("drawString(" + string + "," + topLeft + ")");
+ }
+
+ public void fillRect(int x1, int y1, int x2, int y2) {
+ mDrawn.add("fillRect(" + x1 + "," + y1 + "," + x2 + "," + y2 + ")");
+ }
+
+ public void fillRect(Point p1, Point p2) {
+ mDrawn.add("fillRect(" + p1 + "," + p2 + ")");
+ }
+
+ public void fillRect(Rect r) {
+ mDrawn.add("fillRect(" + rectToString(r) + ")");
+ }
+
+ public int getAlpha() {
+ return mAlpha;
+ }
+
+ public IColor getBackground() {
+ return mBackground;
+ }
+
+ public int getFontHeight() {
+ return 12;
+ }
+
+ public IColor getForeground() {
+ return mForeground;
+ }
+
+ public IColor registerColor(int rgb) {
+ mDrawn.add("registerColor(" + Integer.toHexString(rgb) + ")");
+ return new TestColor(rgb);
+ }
+
+ public void setAlpha(int alpha) {
+ mAlpha = alpha;
+ mDrawn.add("setAlpha(" + alpha + ")");
+ }
+
+ public void setBackground(IColor color) {
+ mDrawn.add("setBackground(" + color + ")");
+ mBackground = color;
+ }
+
+ public void setForeground(IColor color) {
+ mDrawn.add("setForeground(" + color + ")");
+ mForeground = color;
+ }
+
+ public void setLineStyle(LineStyle style) {
+ mDrawn.add("setLineStyle(" + style + ")");
+ }
+
+ public void setLineWidth(int width) {
+ mDrawn.add("setLineWidth(" + width + ")");
+ }
+
+ public void useStyle(DrawingStyle style) {
+ mDrawn.add("useStyle(" + style + ")");
+ }
+
+ private static String rectToString(Rect rect) {
+ return "Rect[" + rect.x + "," + rect.y + "," + rect.w + "," + rect.h + "]";
+ }
+}
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
new file mode 100644
index 0000000..21250de
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java
@@ -0,0 +1,164 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.IAttributeInfo;
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.INodeHandler;
+import com.android.ide.common.api.Rect;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Test/mock implementation of {@link INode} */
+public class TestNode implements INode {
+ private TestNode mParent;
+
+ private final List<TestNode> mChildren = new ArrayList<TestNode>();
+
+ private final String mFqcn;
+
+ private Rect mBounds = new Rect(); // Invalid bounds initially
+
+ private Map<String, IAttribute> mAttributes = new HashMap<String, IAttribute>();
+
+ private Map<String, IAttributeInfo> mAttributeInfos = new HashMap<String, IAttributeInfo>();
+
+ public TestNode(String fqcn) {
+ this.mFqcn = fqcn;
+ }
+
+ public TestNode bounds(Rect bounds) {
+ this.mBounds = bounds;
+
+ return this;
+ }
+
+ public TestNode id(String id) {
+ return set(BaseView.ANDROID_URI, BaseView.ATTR_ID, id);
+ }
+
+ public TestNode set(String uri, String name, String value) {
+ setAttribute(uri, name, value);
+
+ return this;
+ }
+
+ public TestNode add(TestNode child) {
+ mChildren.add(child);
+ child.mParent = this;
+
+ return this;
+ }
+
+ public TestNode add(TestNode... children) {
+ for (TestNode child : children) {
+ mChildren.add(child);
+ child.mParent = this;
+ }
+
+ return this;
+ }
+
+ public static TestNode create(String fcqn) {
+ return new TestNode(fcqn);
+ }
+
+ public void removeChild(int index) {
+ TestNode removed = mChildren.remove(index);
+ removed.mParent = null;
+ }
+
+ // ==== INODE ====
+
+ public INode appendChild(String viewFqcn) {
+ return insertChildAt(viewFqcn, mChildren.size());
+ }
+
+ public void editXml(String undoName, INodeHandler callback) {
+ callback.handle(this);
+ }
+
+ public IAttributeInfo getAttributeInfo(String uri, String attrName) {
+ return mAttributeInfos.get(uri + attrName);
+ }
+
+ public Rect getBounds() {
+ return mBounds;
+ }
+
+ public INode[] getChildren() {
+ return mChildren.toArray(new INode[mChildren.size()]);
+ }
+
+ public IAttributeInfo[] getDeclaredAttributes() {
+ return mAttributeInfos.values().toArray(new IAttributeInfo[mAttributeInfos.size()]);
+ }
+
+ public String getFqcn() {
+ return mFqcn;
+ }
+
+ public IAttribute[] getLiveAttributes() {
+ return mAttributes.values().toArray(new IAttribute[mAttributes.size()]);
+ }
+
+ public INode getParent() {
+ return mParent;
+ }
+
+ public INode getRoot() {
+ TestNode curr = this;
+ while (curr.mParent != null) {
+ curr = curr.mParent;
+ }
+
+ return curr;
+ }
+
+ public String getStringAttr(String uri, String attrName) {
+ IAttribute attr = mAttributes.get(uri + attrName);
+ if (attr == null) {
+ return null;
+ }
+
+ return attr.getValue();
+ }
+
+ public INode insertChildAt(String viewFqcn, int index) {
+ TestNode child = new TestNode(viewFqcn);
+ if (index == -1) {
+ mChildren.add(child);
+ } else {
+ mChildren.add(index, child);
+ }
+ child.mParent = this;
+ return child;
+ }
+
+ public boolean setAttribute(String uri, String localName, String value) {
+ mAttributes.put(uri + localName, new TestAttribute(uri, localName, value));
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "TestNode [fqn=" + mFqcn + ", infos=" + mAttributeInfos
+ + ", attributes=" + mAttributes + ", bounds=" + mBounds + "]";
+ }
+} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/ZoomControlsRuleTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/ZoomControlsRuleTest.java
new file mode 100644
index 0000000..ee08633
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/ZoomControlsRuleTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.DropFeedback;
+import com.android.ide.common.api.IDragElement;
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.Rect;
+
+/** Test the {@link ZoomControlsRule} */
+public class ZoomControlsRuleTest extends AbstractLayoutRuleTest {
+ public void testDoNothing() {
+ String draggedButtonId = "@+id/DraggedButton";
+
+ IDragElement[] elements = TestDragElement.create(TestDragElement.create(
+ "android.widget.Button").id(draggedButtonId));
+
+ INode layout = TestNode.create("android.widget.ZoomControls").id("@+id/ZoomControls01")
+ .bounds(new Rect(0, 0, 240, 480)).add(
+ TestNode.create("android.widget.Button").id("@+id/Button01").bounds(
+ new Rect(0, 0, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button02").bounds(
+ new Rect(0, 100, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button03").bounds(
+ new Rect(0, 200, 100, 80)),
+ TestNode.create("android.widget.Button").id("@+id/Button04").bounds(
+ new Rect(0, 300, 100, 80)));
+
+ ZoomControlsRule rule = new ZoomControlsRule();
+
+ // Enter target
+ DropFeedback feedback = rule.onDropEnter(layout, elements);
+ // Zoom controls don't respond to drags
+ assertNull(feedback);
+ }
+}