com.android.tools.idea.uibuilder.handlers.ViewEditorImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.android.tools.idea.uibuilder.handlers.ViewEditorImpl.java

Source

/*
 * 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.handlers;

import com.android.assetstudiolib.GraphicGenerator;
import com.android.assetstudiolib.MaterialDesignIcons;
import com.android.ide.common.rendering.api.ViewInfo;
import com.android.resources.ResourceType;
import com.android.sdklib.AndroidVersion;
import com.android.tools.idea.configurations.Configuration;
import com.android.tools.idea.model.AndroidModuleInfo;
import com.android.tools.idea.rendering.RenderLogger;
import com.android.tools.idea.rendering.RenderResult;
import com.android.tools.idea.rendering.RenderService;
import com.android.tools.idea.rendering.RenderTask;
import com.android.tools.idea.ui.resourcechooser.ChooseResourceDialog;
import com.android.tools.idea.uibuilder.api.ViewEditor;
import com.android.tools.idea.uibuilder.api.ViewHandler;
import com.android.tools.idea.uibuilder.model.NlComponent;
import com.android.tools.idea.uibuilder.model.NlModel;
import com.android.tools.idea.uibuilder.surface.ScreenView;
import com.google.common.collect.Maps;
import com.google.common.io.ByteStreams;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
import org.intellij.lang.annotations.Language;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.uipreview.ChooseClassDialog;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Predicate;

import static com.android.SdkConstants.*;

/**
 * Implementation of the {@link ViewEditor} abstraction presented
 * to {@link ViewHandler} instances
 */
public class ViewEditorImpl extends ViewEditor {
    private final ScreenView myScreen;

    public ViewEditorImpl(@NotNull ScreenView screen) {
        myScreen = screen;
    }

    @Override
    public int getDpi() {
        return myScreen.getConfiguration().getDensity().getDpiValue();
    }

    @Nullable
    @Override
    public AndroidVersion getCompileSdkVersion() {
        return AndroidModuleInfo.get(myScreen.getModel().getFacet()).getBuildSdkVersion();
    }

    @NotNull
    @Override
    public AndroidVersion getMinSdkVersion() {
        return AndroidModuleInfo.get(myScreen.getModel().getFacet()).getMinSdkVersion();
    }

    @NotNull
    @Override
    public AndroidVersion getTargetSdkVersion() {
        return AndroidModuleInfo.get(myScreen.getModel().getFacet()).getTargetSdkVersion();
    }

    @NotNull
    @Override
    public Configuration getConfiguration() {
        return myScreen.getConfiguration();
    }

    @NotNull
    @Override
    public NlModel getModel() {
        return myScreen.getModel();
    }

    @NotNull
    @Override
    public Collection<ViewInfo> getRootViews() {
        RenderResult result = myScreen.getModel().getRenderResult();

        if (result == null) {
            return Collections.emptyList();
        }

        return result.getRootViews();
    }

    @Override
    public boolean moduleContainsResource(@NotNull ResourceType type, @NotNull String name) {
        return myScreen.getModel().getFacet().getModuleResources(true).hasResourceItem(type, name);
    }

    @Override
    public void copyVectorAssetToMainModuleSourceSet(@NotNull String asset) {
        Project project = myScreen.getModel().getProject();
        String message = "Do you want to copy vector asset " + asset + " to your main module source set?";

        if (Messages.showYesNoDialog(project, message, "Copy Vector Asset",
                Messages.getQuestionIcon()) == Messages.NO) {
            return;
        }

        try (InputStream in = GraphicGenerator.class.getClassLoader()
                .getResourceAsStream(MaterialDesignIcons.getPathForBasename(asset))) {
            createResourceFile(FD_RES_DRAWABLE, asset + DOT_XML, ByteStreams.toByteArray(in));
        } catch (IOException exception) {
            Logger.getInstance(ViewEditorImpl.class).warn(exception);
        }
    }

    @Override
    public void copyLayoutToMainModuleSourceSet(@NotNull String layout, @Language("XML") @NotNull String xml) {
        String message = "Do you want to copy layout " + layout + " to your main module source set?";

        if (Messages.showYesNoDialog(myScreen.getModel().getProject(), message, "Copy Layout",
                Messages.getQuestionIcon()) == Messages.NO) {
            return;
        }

        createResourceFile(FD_RES_LAYOUT, layout + DOT_XML, xml.getBytes(StandardCharsets.UTF_8));
    }

    private void createResourceFile(@NotNull String resourceDirectory, @NotNull String resourceFile,
            @NotNull byte[] resourceFileContent) {
        try {
            VirtualFile directory = getResourceDirectoryChild(resourceDirectory);

            if (directory == null) {
                return;
            }

            directory.createChildData(this, resourceFile).setBinaryContent(resourceFileContent);
        } catch (IOException exception) {
            Logger.getInstance(ViewEditorImpl.class).warn(exception);
        }
    }

    @Nullable
    private VirtualFile getResourceDirectoryChild(@NotNull String child) throws IOException {
        VirtualFile resourceDirectory = myScreen.getModel().getFacet().getPrimaryResourceDir();

        if (resourceDirectory == null) {
            Logger.getInstance(ViewEditorImpl.class).warn("resourceDirectory is null");
            return null;
        }

        VirtualFile resourceDirectoryChild = resourceDirectory.findChild(child);

        if (resourceDirectoryChild == null) {
            return resourceDirectory.createChildDirectory(this, child);
        }

        return resourceDirectoryChild;
    }

    @Nullable
    @Override
    public Map<NlComponent, Dimension> measureChildren(@NotNull NlComponent parent,
            @Nullable RenderTask.AttributeFilter filter) {
        // TODO: Reuse snapshot!
        Map<NlComponent, Dimension> unweightedSizes = Maps.newHashMap();
        XmlTag parentTag = parent.getTag();
        if (parentTag.isValid()) {
            if (parent.getChildCount() == 0) {
                return Collections.emptyMap();
            }
            Map<XmlTag, NlComponent> tagToComponent = Maps.newHashMapWithExpectedSize(parent.getChildCount());
            for (NlComponent child : parent.getChildren()) {
                tagToComponent.put(child.getTag(), child);
            }

            NlModel model = myScreen.getModel();
            XmlFile xmlFile = model.getFile();
            AndroidFacet facet = model.getFacet();
            RenderService renderService = RenderService.get(facet);
            RenderLogger logger = renderService.createLogger();
            final RenderTask task = renderService.createTask(xmlFile, getConfiguration(), logger, null);
            if (task == null) {
                return null;
            }

            // Measure unweighted bounds
            Map<XmlTag, ViewInfo> map = task.measureChildren(parentTag, filter);
            task.dispose();
            if (map != null) {
                for (Map.Entry<XmlTag, ViewInfo> entry : map.entrySet()) {
                    ViewInfo viewInfo = entry.getValue();
                    viewInfo = RenderService.getSafeBounds(viewInfo);
                    Dimension size = new Dimension(viewInfo.getRight() - viewInfo.getLeft(),
                            viewInfo.getBottom() - viewInfo.getTop());
                    NlComponent child = tagToComponent.get(entry.getKey());
                    if (child != null) {
                        unweightedSizes.put(child, size);
                    }
                }
            }
        }

        return unweightedSizes;
    }

    @Nullable
    @Override
    public String displayResourceInput(@NotNull String title, @NotNull EnumSet<ResourceType> types) {
        NlModel model = myScreen.getModel();
        ChooseResourceDialog dialog = ChooseResourceDialog.builder().setModule(model.getModule()).setTypes(types)
                .setConfiguration(model.getConfiguration()).build();

        if (!title.isEmpty()) {
            dialog.setTitle(title);
        }

        dialog.show();

        if (dialog.isOK()) {
            String resource = dialog.getResourceName();

            if (resource != null && !resource.isEmpty()) {
                return resource;
            }
        }

        return null;
    }

    @Nullable
    @Override
    public String displayClassInput(@NotNull Set<String> superTypes, @Nullable final Predicate<String> filter,
            @Nullable String currentValue) {
        Module module = myScreen.getModel().getModule();
        String[] superTypesArray = ArrayUtil.toStringArray(superTypes);

        Condition<PsiClass> psiFilter = null;
        if (filter != null) {
            psiFilter = psiClass -> {
                String qualifiedName = psiClass.getQualifiedName();
                if (qualifiedName == null) {
                    return false;
                }
                return filter.test(qualifiedName);
            };
        }

        return ChooseClassDialog.openDialog(module, "Classes", true, psiFilter, superTypesArray);
    }

    @NotNull
    public ScreenView getScreenView() {
        return myScreen;
    }
}