blob: c33e8e2877315695662fcf6f679fdb2456d994a6 [file] [log] [blame]
/*
* Copyright (C) 2014 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.intellij.android.designer.designSurface;
import com.google.common.base.Objects;
import com.intellij.android.designer.AndroidDesignerEditor;
import com.intellij.android.designer.componentTree.AndroidTreeDecorator;
import com.intellij.android.designer.model.RadComponentOperations;
import com.intellij.android.designer.model.RadModelBuilder;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.android.designer.model.ViewsMetaManager;
import com.intellij.designer.componentTree.AttributeWrapper;
import com.intellij.designer.designSurface.EditOperation;
import com.intellij.designer.designSurface.OperationContext;
import com.intellij.designer.designSurface.tools.ComponentCreationFactory;
import com.intellij.designer.designSurface.tools.CreationTool;
import com.intellij.designer.model.MetaModel;
import com.intellij.designer.model.Property;
import com.intellij.designer.palette.DefaultPaletteItem;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.XmlElementFactory;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.ui.SimpleColoredRenderer;
import org.jetbrains.android.AndroidTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.io.File;
import java.util.Collections;
public abstract class LayoutEditorTestBase extends AndroidTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
}
@Override
protected boolean requireRecentSdk() {
return true;
}
protected File getTestDir() {
return new File(FileUtil.toSystemDependentName(getTestDataPath()), "designer");
}
@NotNull
protected VirtualFile getTestFile(String filename) {
File sourceFile = new File(getTestDir(), filename);
return myFixture.copyFileToProject(sourceFile.getPath(), "res/layout/" + filename);
}
protected AndroidDesignerEditorPanel createLayoutEditor(VirtualFile xmlFile) {
Project project = getProject();
AndroidDesignerEditor editor = new AndroidDesignerEditor(project, xmlFile);
AndroidDesignerEditorPanel panel = (AndroidDesignerEditorPanel)editor.getDesignerPanel();
panel.requestImmediateRender();
Disposer.register(project, editor);
return panel;
}
public static String printTree(RadViewComponent root, boolean internal) {
StringBuilder sb = new StringBuilder(200);
if (internal) {
describe(sb, root, 0);
} else {
decorate(sb, root, 0);
}
return sb.toString().trim();
}
private static void decorate(StringBuilder sb, RadViewComponent component, int depth) {
for (int i = 0; i < depth; i++) {
sb.append(" ");
}
SimpleColoredRenderer renderer = new SimpleColoredRenderer();
AndroidTreeDecorator decorator = new AndroidTreeDecorator(RadModelBuilder.getProject(component));
decorator.decorate(component, renderer, AttributeWrapper.DEFAULT, true);
sb.append(renderer);
sb.append('\n');
for (RadViewComponent child : RadViewComponent.getViewComponents(component.getChildren())) {
decorate(sb, child, depth + 1);
}
}
private static void describe(StringBuilder sb, RadViewComponent component, int depth) {
for (int i = 0; i < depth; i++) {
sb.append(" ");
}
sb.append(describe(component));
sb.append('\n');
for (RadViewComponent child : RadViewComponent.getViewComponents(component.getChildren())) {
describe(sb, child, depth + 1);
}
}
private static String describe(RadViewComponent root) {
return Objects.toStringHelper(root).omitNullValues()
.add("tag", describe(root.getTag()))
.add("id", root.getId())
.add("bounds", describe(root.getBounds()))
.toString();
}
private static String describe(@Nullable XmlTag tag) {
if (tag == null) {
return "";
} else {
return '<' + tag.getName() + '>';
}
}
private static String describe(Rectangle rectangle) {
// More brief description than toString default: java.awt.Rectangle[x=0,y=100,width=768,height=1084]
return "[" + rectangle.x + "," + rectangle.y + ":" + rectangle.width + "x" + rectangle.height;
}
@NotNull
protected Property getProperty(@NotNull RadViewComponent component, @NotNull String name) {
for (Property property : component.getProperties()) {
if (name.equals(property.getName())) {
return property;
}
}
fail("Did not find property as expected");
throw new RuntimeException("not reached");
}
protected RadViewComponent addComponent(@NotNull AndroidDesignerEditorPanel editor, @NotNull final RadViewComponent parent,
@Nullable final RadViewComponent before, @NotNull String tagName) throws Exception {
XmlFile psiFile = editor.getXmlFile();
ViewsMetaManager metaManager = ViewsMetaManager.getInstance(getProject());
MetaModel metaModel = metaManager.getModelByTag(tagName);
assertNotNull(metaModel);
final boolean ADD_AS_DROP_OPERATION = true;
//noinspection ConstantConditions
if (ADD_AS_DROP_OPERATION) {
DefaultPaletteItem paletteItem = new DefaultPaletteItem(tagName, "", "", "", "", "");
paletteItem.setMetaModel(metaModel);
ComponentCreationFactory factory = editor.createCreationFactory(paletteItem);
final OperationContext context = new OperationContext();
context.setType(OperationContext.CREATE);
CreationTool tool = new CreationTool(true, factory);
context.setComponents(Collections.singletonList(tool.getFactory().create()));
EditOperation operation = new AbstractEditOperation(parent, context) {
@Override
public void showFeedback() {
}
@Override
public void eraseFeedback() {
}
@Override
public void execute() throws Exception {
AbstractEditOperation.execute(myContext, (RadViewComponent)myContainer, myComponents, before);
}
};
operation.setComponents(context.getComponents());
editor.getToolProvider().execute(Collections.singletonList(operation), context.getMessage());
final RadViewComponent newComponent = (RadViewComponent)context.getComponents().get(0);
assertNotNull(newComponent);
return newComponent;
} else {
// Add as XML tag edit
XmlTag tag = XmlElementFactory.getInstance(getProject()).createTagFromText(metaModel.getCreation());
assertNotNull(tag);
final RadViewComponent newComponent = RadComponentOperations.createComponent(tag, metaModel);
assertNotNull(newComponent.getTag());
assertEquals(tagName, newComponent.getTag().getName());
WriteCommandAction<Void> action = new WriteCommandAction<Void>(getProject(), "Add Tag " + tagName, psiFile) {
@Override
protected void run(@NotNull Result<Void> result) throws Throwable {
RadComponentOperations.addComponent(parent, newComponent, before);
}
};
action.execute();
return newComponent;
}
}
protected void setProperty(@NotNull AndroidDesignerEditorPanel editor, @NotNull final RadViewComponent component,
@NotNull final String name, @Nullable final Object value) {
XmlFile psiFile = editor.getXmlFile();
WriteCommandAction<Void> action = new WriteCommandAction<Void>(getProject(), "Set Attribute " + name + " to " + value, psiFile) {
@Override
protected void run(@NotNull Result<Void> result) throws Throwable {
//noinspection unchecked
getProperty(component, name).setValue(component, value);
}
};
action.execute();
}
}