blob: 31cb6ea63267045cb7900a453d6ba03564b17839 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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.tools.idea.uibuilder.fixtures;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.ViewInfo;
import com.android.tools.idea.uibuilder.model.AndroidCoordinate;
import com.android.utils.XmlUtils;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.xml.XmlTag;
import junit.framework.TestCase;
import java.awt.*;
import java.util.List;
import static com.android.SdkConstants.*;
public class ComponentDescriptor {
@NonNull private final String myTagName;
@NonNull private ComponentDescriptor[] myChildren = new ComponentDescriptor[0];
@AndroidCoordinate private int myX;
@AndroidCoordinate private int myY;
@AndroidCoordinate private int myWidth;
@AndroidCoordinate private int myHeight;
@NonNull List<Pair<String, String>> myAttributes = Lists.newArrayList();
@Nullable private ViewInfo myViewInfo;
public ComponentDescriptor(@NonNull String tagName) {
myTagName = tagName;
}
public ComponentDescriptor withBounds(@AndroidCoordinate int x,
@AndroidCoordinate int y,
@AndroidCoordinate int width,
@AndroidCoordinate int height) {
myX = x;
myY = y;
myWidth = width;
myHeight = height;
return this;
}
public ComponentDescriptor withAttribute(@NonNull String name, @NonNull String value) {
myAttributes.add(Pair.create(name, value));
return this;
}
public ComponentDescriptor id(@NonNull String id) {
return withAttribute(ANDROID_URI, ATTR_ID, id);
}
public ComponentDescriptor text(@NonNull String text) {
return withAttribute(ANDROID_URI, ATTR_TEXT, text);
}
public ComponentDescriptor width(@NonNull String width) {
return withAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, width);
}
public ComponentDescriptor height(@NonNull String height) {
return withAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT, height);
}
public ComponentDescriptor matchParentWidth() {
return width(VALUE_MATCH_PARENT);
}
public ComponentDescriptor matchParentHeight() {
return height(VALUE_MATCH_PARENT);
}
public ComponentDescriptor wrapContentWidth() {
return width(VALUE_WRAP_CONTENT);
}
public ComponentDescriptor wrapContentHeight() {
return height(VALUE_WRAP_CONTENT);
}
public ComponentDescriptor withAttribute(@NonNull String namespace, @NonNull String name, @NonNull String value) {
if (ANDROID_URI.equals(namespace)) {
return withAttribute(PREFIX_ANDROID + name, value);
}
else if (TOOLS_URI.equals(namespace)) {
return withAttribute(TOOLS_PREFIX + ":" + name, value);
}
myAttributes.add(Pair.create(name, value));
return this;
}
private Rectangle getBounds() {
return new Rectangle(myX, myY, myWidth, myHeight);
}
public ComponentDescriptor children(@NonNull ComponentDescriptor... children) {
// Make sure that all the children have bounds that fit within this component
Rectangle bounds = getBounds();
for (ComponentDescriptor child : children) {
TestCase.assertTrue("Expected parent layout with bounds " +
bounds +
" to fully contain child bounds " +
child.getBounds() +
" where parent=" +
this +
" and child=" +
child, bounds.contains(child.getBounds()));
}
myChildren = children;
return this;
}
public void appendXml(@NonNull StringBuilder sb, int depth) {
for (int i = 0; i < depth; i++) {
sb.append(" ");
}
sb.append('<');
sb.append(myTagName);
if (depth == 0) {
sb.append(" xmlns:android=\"http://schemas.android.com/apk/res/android\"");
}
for (Pair<String, String> attribute : myAttributes) {
sb.append("\n");
for (int i = 0; i < depth + 1; i++) {
sb.append(" ");
}
String name = attribute.getFirst();
String value = attribute.getSecond();
sb.append(name).append("=\"").append(XmlUtils.toXmlAttributeValue(value)).append("\"");
}
if (myChildren.length > 0) {
sb.append(">\n");
for (ComponentDescriptor child : myChildren) {
child.appendXml(sb, depth + 1);
}
sb.append("</").append(myTagName).append(">\n");
}
else {
sb.append("/>\n");
}
}
@NonNull
public ViewInfo createViewInfo(@Nullable ComponentDescriptor parent, @NonNull XmlTag tag) {
TestCase.assertNull(myViewInfo);
int left = myX;
int top = myY;
if (parent != null) {
left -= parent.myX;
top -= parent.myY;
}
int right = left + myWidth;
int bottom = top + myHeight;
myViewInfo = new ViewInfo(myTagName, tag, left, top, right, bottom);
List<ViewInfo> childList = Lists.newArrayList();
XmlTag[] subTags = tag.getSubTags();
TestCase.assertEquals(subTags.length, myChildren.length);
for (int i = 0; i < subTags.length; i++) {
ComponentDescriptor childDescriptor = myChildren[i];
XmlTag childTag = subTags[i];
childList.add(childDescriptor.createViewInfo(this, childTag));
}
myViewInfo.setChildren(childList);
return myViewInfo;
}
}