diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LinearLayoutRuleTest.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LinearLayoutRuleTest.java | 466 |
1 files changed, 466 insertions, 0 deletions
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 000000000..9c4c934c0 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LinearLayoutRuleTest.java @@ -0,0 +1,466 @@ +/* + * 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 static com.android.SdkConstants.ANDROID_URI; +import static com.android.SdkConstants.ATTR_ID; +import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT; +import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH; +import static com.android.SdkConstants.ATTR_ORIENTATION; +import static com.android.SdkConstants.VALUE_HORIZONTAL; +import static com.android.SdkConstants.VALUE_VERTICAL; + +import com.android.ide.common.api.DropFeedback; +import com.android.ide.common.api.IAttributeInfo.Format; +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.Point; +import com.android.ide.common.api.Rect; +import com.android.ide.common.api.RuleAction; +import com.android.ide.common.api.RuleAction.NestedAction; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** Test the {@link LinearLayoutRule} */ +public class LinearLayoutRuleTest extends LayoutTestBase { + // 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, null/*targetView*/, 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), drawLine(1,0,1,480), " + + "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(1,0,101,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( + ANDROID_URI, 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(ANDROID_URI, + ATTR_ORIENTATION, + vertical ? VALUE_VERTICAL : 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(); + initialize(rule, "android.widget.LinearLayout"); + INode node = TestNode.create("android.widget.Button").id("@+id/Button012"); + + List<RuleAction> contextMenu = new ArrayList<RuleAction>(); + rule.addContextMenuActions(contextMenu, node); + assertEquals(6, contextMenu.size()); + assertEquals("Edit ID...", contextMenu.get(0).getTitle()); + assertTrue(contextMenu.get(1) instanceof RuleAction.Separator); + assertEquals("Layout Width", contextMenu.get(2).getTitle()); + assertEquals("Layout Height", contextMenu.get(3).getTitle()); + assertTrue(contextMenu.get(4) instanceof RuleAction.Separator); + assertEquals("Other Properties", contextMenu.get(5).getTitle()); + + RuleAction propertiesMenu = contextMenu.get(5); + assertTrue(propertiesMenu.getClass().getName(), + propertiesMenu instanceof NestedAction); + } + + public void testContextMenuCustom() { + LinearLayoutRule rule = new LinearLayoutRule(); + initialize(rule, "android.widget.LinearLayout"); + INode node = TestNode.create("android.widget.LinearLayout").id("@+id/LinearLayout") + .set(ANDROID_URI, ATTR_LAYOUT_WIDTH, "42dip") + .set(ANDROID_URI, ATTR_LAYOUT_HEIGHT, "50sp"); + + List<RuleAction> contextMenu = new ArrayList<RuleAction>(); + rule.addContextMenuActions(contextMenu, node); + assertEquals(6, contextMenu.size()); + assertEquals("Layout Width", contextMenu.get(2).getTitle()); + RuleAction menuAction = contextMenu.get(2); + assertTrue(menuAction instanceof RuleAction.Choices); + RuleAction.Choices choices = (RuleAction.Choices) menuAction; + List<String> titles = choices.getTitles(); + List<String> ids = choices.getIds(); + assertEquals("Wrap Content", titles.get(0)); + assertEquals("wrap_content", ids.get(0)); + assertEquals("Match Parent", titles.get(1)); + assertEquals("match_parent", ids.get(1)); + assertEquals("42dip", titles.get(2)); + assertEquals("42dip", ids.get(2)); + assertEquals("42dip", choices.getCurrent()); + } + + // Check that the context menu manipulates the orientation attribute + public void testOrientation() { + LinearLayoutRule rule = new LinearLayoutRule(); + initialize(rule, "android.widget.LinearLayout"); + TestNode node = TestNode.create("android.widget.LinearLayout").id("@+id/LinearLayout012"); + node.putAttributeInfo(ANDROID_URI, "orientation", + new TestAttributeInfo(ATTR_ORIENTATION, Format.ENUM_SET, + "android.widget.LinearLayout", + new String[] {"horizontal", "vertical"}, null, null)); + + assertNull(node.getStringAttr(ANDROID_URI, ATTR_ORIENTATION)); + + List<RuleAction> contextMenu = new ArrayList<RuleAction>(); + rule.addContextMenuActions(contextMenu, node); + assertEquals(7, contextMenu.size()); + RuleAction orientationAction = contextMenu.get(1); + assertEquals("Orientation", orientationAction.getTitle()); + + assertTrue(orientationAction.getClass().getName(), + orientationAction instanceof RuleAction.Choices); + + RuleAction.Choices choices = (RuleAction.Choices) orientationAction; + IMenuCallback callback = choices.getCallback(); + callback.action(orientationAction, Collections.singletonList(node), VALUE_VERTICAL, true); + + String orientation = node.getStringAttr(ANDROID_URI, + ATTR_ORIENTATION); + assertEquals(VALUE_VERTICAL, orientation); + callback.action(orientationAction, Collections.singletonList(node), VALUE_HORIZONTAL, + true); + orientation = node.getStringAttr(ANDROID_URI, ATTR_ORIENTATION); + assertEquals(VALUE_HORIZONTAL, orientation); + } + + // Check that the context menu manipulates the orientation attribute + public void testProperties() { + LinearLayoutRule rule = new LinearLayoutRule(); + initialize(rule, "android.widget.LinearLayout"); + TestNode node = TestNode.create("android.widget.LinearLayout").id("@+id/LinearLayout012"); + node.putAttributeInfo(ANDROID_URI, "orientation", + new TestAttributeInfo(ATTR_ORIENTATION, Format.ENUM_SET, + "android.widget.LinearLayout", + new String[] {"horizontal", "vertical"}, null, null)); + node.setAttributeSources(Arrays.asList("android.widget.LinearLayout", + "android.view.ViewGroup", "android.view.View")); + node.putAttributeInfo(ANDROID_URI, "gravity", + new TestAttributeInfo("gravity", Format.INTEGER_SET, + "android.widget.LinearLayout", null, null, null)); + + + assertNull(node.getStringAttr(ANDROID_URI, ATTR_ORIENTATION)); + + List<RuleAction> contextMenu = new ArrayList<RuleAction>(); + rule.addContextMenuActions(contextMenu, node); + assertEquals(8, contextMenu.size()); + + assertEquals("Orientation", contextMenu.get(1).getTitle()); + assertEquals("Edit Gravity...", contextMenu.get(2).getTitle()); + + assertEquals("Other Properties", contextMenu.get(7).getTitle()); + + RuleAction propertiesMenu = contextMenu.get(7); + assertTrue(propertiesMenu.getClass().getName(), + propertiesMenu instanceof NestedAction); + NestedAction nested = (NestedAction) propertiesMenu; + List<RuleAction> nestedActions = nested.getNestedActions(node); + assertEquals(9, nestedActions.size()); + assertEquals("Recent", nestedActions.get(0).getTitle()); + assertTrue(nestedActions.get(1) instanceof RuleAction.Separator); + assertEquals("Defined by LinearLayout", nestedActions.get(2).getTitle()); + assertEquals("Inherited from ViewGroup", nestedActions.get(3).getTitle()); + assertEquals("Inherited from View", nestedActions.get(4).getTitle()); + assertTrue(nestedActions.get(5) instanceof RuleAction.Separator); + assertEquals("Layout Parameters", nestedActions.get(6).getTitle()); + assertTrue(nestedActions.get(7) instanceof RuleAction.Separator); + assertEquals("All By Name", nestedActions.get(8).getTitle()); + + BaseViewRule.editedProperty(ATTR_ORIENTATION); + + RuleAction recentAction = nestedActions.get(0); + assertTrue(recentAction instanceof NestedAction); + NestedAction recentChoices = (NestedAction) recentAction; + List<RuleAction> recentItems = recentChoices.getNestedActions(node); + + assertEquals(1, recentItems.size()); + assertEquals("Orientation", recentItems.get(0).getTitle()); + + BaseViewRule.editedProperty("gravity"); + recentItems = recentChoices.getNestedActions(node); + assertEquals(2, recentItems.size()); + assertEquals("Gravity...", recentItems.get(0).getTitle()); + assertEquals("Orientation", recentItems.get(1).getTitle()); + + BaseViewRule.editedProperty(ATTR_ORIENTATION); + recentItems = recentChoices.getNestedActions(node); + assertEquals(2, recentItems.size()); + assertEquals("Orientation", recentItems.get(0).getTitle()); + assertEquals("Gravity...", recentItems.get(1).getTitle()); + + // Lots of other properties -- flushes out properties that apply to this view + for (int i = 0; i < 30; i++) { + BaseViewRule.editedProperty("dummy_" + i); + } + recentItems = recentChoices.getNestedActions(node); + assertEquals(0, recentItems.size()); + + BaseViewRule.editedProperty("gravity"); + recentItems = recentChoices.getNestedActions(node); + assertEquals(1, recentItems.size()); + assertEquals("Gravity...", recentItems.get(0).getTitle()); + } + + 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), " + + "drawLine(0,381,240,381)", + + // Active nearest line + "useStyle(DROP_ZONE_ACTIVE), useStyle(DROP_PREVIEW), drawLine(0,0,240,0)", + + // Preview of the dropped rectangle + "useStyle(DROP_PREVIEW), drawRect(0,-40,105,40)"); + + // 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), drawLine(0,381,240,381), ", + + // Active nearest line + "useStyle(DROP_ZONE_ACTIVE), useStyle(DROP_PREVIEW), drawLine(0,381,240,381)", + + // Preview of the dropped rectangle + "useStyle(DROP_PREVIEW), drawRect(0,381,105,461)"); + + // Check without bounds too + dragInto(true, new Rect(0, 0, 105, 80), new Point(30, 500), 4, -1, + "useStyle(DROP_PREVIEW), drawRect(0,381,105,461)"); + } + + 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(0,150,105,230)"); + + // Check without bounds too + dragInto(true, new Rect(0, 0, 105, 80), new Point(0, 170), 2, -1, + "useStyle(DROP_PREVIEW), drawRect(0,150,105,230)"); + } + + 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(0,250,100,330)"); + + // 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(0,100,100,180)"); + } + + public void testDragToLastPosition() { + // Drag a button to the last position -- and confirm that the preview rectangle + // is now shown midway between the second to last and last positions, but fully + // below the drop zone line: + dragInto(true, + // Bounds of the dragged item + new Rect(0, 100, 100, 80), + // Drag point + new Point(0, 400), + // Expected insert location + 3, + // Dragging 1st item + 1, + + // Bounds rectangle + "useStyle(DROP_RECIPIENT), drawRect(Rect[0,0,240,480])", + + // Drop Zones + "useStyle(DROP_ZONE), drawLine(0,0,240,0), drawLine(0,290,240,290), " + + "drawLine(0,381,240,381), ", + + // Active Drop Zone + "useStyle(DROP_ZONE_ACTIVE), useStyle(DROP_PREVIEW), drawLine(0,381,240,381)", + + // Drop Preview + "useStyle(DROP_PREVIEW), drawRect(0,381,100,461)"); + } + + // Left to test: + // Check inserting at last pos with multiple children + // Check inserting with no bounds rectangle for dragged element +} |