blob: 10c9413d8e9e6dcea21fa33b40c523ee3680bbe9 [file] [log] [blame]
/*
* Copyright (C) 2013 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.configurations;
import com.android.ide.common.rendering.LayoutLibrary;
import com.android.ide.common.rendering.api.Features;
import com.android.ide.common.resources.configuration.FolderConfiguration;
import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
import com.android.resources.ScreenOrientation;
import com.android.resources.ScreenSize;
import com.android.sdklib.IAndroidTarget;
import com.android.tools.idea.actions.OverrideResourceAction;
import com.android.tools.idea.rendering.RenderService;
import com.android.tools.idea.rendering.ResourceHelper;
import com.android.tools.idea.rendering.multi.RenderPreviewManager;
import com.android.tools.idea.rendering.multi.RenderPreviewMode;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import icons.AndroidIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.List;
import static com.android.SdkConstants.FD_RES_LAYOUT;
import static com.android.tools.idea.rendering.multi.RenderPreviewManager.SUPPORTS_MANUAL_PREVIEWS;
public class ConfigurationMenuAction extends FlatComboAction {
private final RenderContext myRenderContext;
public ConfigurationMenuAction(RenderContext renderContext) {
myRenderContext = renderContext;
Presentation presentation = getTemplatePresentation();
presentation.setDescription("Configuration to render this layout with inside the IDE");
if (RenderService.NELE_ENABLED) {
presentation.setText("Preview");
presentation.setIcon(AndroidIcons.NeleIcons.Preview);
} else {
presentation.setIcon(AndroidIcons.AndroidFile);
}
}
@Override
@NotNull
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
DefaultActionGroup group = new DefaultActionGroup("Configuration", true);
VirtualFile virtualFile = myRenderContext.getVirtualFile();
if (virtualFile != null) {
Module module = myRenderContext.getModule();
if (module == null) {
return group;
}
Project project = module.getProject();
List<VirtualFile> variations = ResourceHelper.getResourceVariations(virtualFile, true);
if (variations.size() > 1) {
for (VirtualFile file : variations) {
String title = String.format("Switch to %1$s", file.getParent().getName());
group.add(new SwitchToVariationAction(title, project, file, virtualFile.equals(file)));
}
group.addSeparator();
}
boolean haveLandscape = false;
boolean haveLarge = false;
for (VirtualFile file : variations) {
String name = file.getParent().getName();
if (name.startsWith(FD_RES_LAYOUT)) {
FolderConfiguration config = FolderConfiguration.getConfigForFolder(name);
if (config != null) {
ScreenOrientationQualifier orientation = config.getScreenOrientationQualifier();
if (orientation != null && orientation.getValue() == ScreenOrientation.LANDSCAPE) {
haveLandscape = true;
if (haveLarge) {
break;
}
}
ScreenSizeQualifier size = config.getScreenSizeQualifier();
if (size != null && size.getValue() == ScreenSize.XLARGE) {
haveLarge = true;
if (haveLandscape) {
break;
}
}
}
}
}
// Create actions for creating "common" versions of a layout (that don't exist),
// e.g. Create Landscape Version, Create RTL Version, Create XLarge version
// Do statistics on what is needed!
if (!haveLandscape) {
group.add(new CreateVariationAction(myRenderContext, "Create Landscape Variation", "layout-land"));
}
if (!haveLarge) {
group.add(new CreateVariationAction(myRenderContext, "Create layout-xlarge Variation", "layout-xlarge"));
//group.add(new CreateVariationAction(myRenderContext, "Create layout-sw600dp Variation...", "layout-sw600dp"));
}
group.add(new CreateVariationAction(myRenderContext, "Create Other...", null));
if (myRenderContext.supportsPreviews()) {
addMultiConfigActions(group);
}
}
return group;
}
private void addMultiConfigActions(DefaultActionGroup group) {
VirtualFile file = myRenderContext.getVirtualFile();
if (file == null) {
return;
}
Configuration configuration = myRenderContext.getConfiguration();
if (configuration == null) {
return;
}
ConfigurationManager configurationManager = configuration.getConfigurationManager();
group.addSeparator();
// Configuration Previews
if (SUPPORTS_MANUAL_PREVIEWS) {
group.add(new PreviewAction(myRenderContext, "Add As Thumbnail...", ACTION_ADD, null, true));
RenderPreviewMode mode = RenderPreviewMode.getCurrent();
if (mode == RenderPreviewMode.CUSTOM) {
RenderPreviewManager previewManager = myRenderContext.getPreviewManager(false);
boolean hasPreviews = previewManager != null && previewManager.hasManualPreviews();
group.add(new PreviewAction(myRenderContext, "Delete All Thumbnails", ACTION_DELETE_ALL, null, hasPreviews));
}
group.addSeparator();
}
group.add(new PreviewAction(myRenderContext, "Preview Representative Sample", ACTION_PREVIEW_MODE, RenderPreviewMode.DEFAULT, true));
addScreenSizeAction(myRenderContext, group);
boolean haveMultipleLocales = configurationManager.getLocales().size() > 1;
addLocalePreviewAction(myRenderContext, group, haveMultipleLocales);
addRtlPreviewAction(myRenderContext, group);
addApiLevelPreviewAction(myRenderContext, group);
// TODO: Support included layouts
boolean DISABLE_RENDER_INCLUDED = true;
boolean canPreviewIncluded = !DISABLE_RENDER_INCLUDED && hasCapability(myRenderContext, Features.EMBEDDED_LAYOUT);
group.add(new PreviewAction(myRenderContext, "Preview Included", ACTION_PREVIEW_MODE, RenderPreviewMode.INCLUDES, canPreviewIncluded));
List<VirtualFile> variations = ResourceHelper.getResourceVariations(file, true);
group.add(new PreviewAction(myRenderContext, "Preview Layout Versions", ACTION_PREVIEW_MODE, RenderPreviewMode.VARIATIONS,
variations.size() > 1));
if (SUPPORTS_MANUAL_PREVIEWS) {
group.add(new PreviewAction(myRenderContext, "Manual Previews", ACTION_PREVIEW_MODE, RenderPreviewMode.CUSTOM, true));
}
group.add(new PreviewAction(myRenderContext, "None", ACTION_PREVIEW_MODE, RenderPreviewMode.NONE, true));
// Debugging only
group.addSeparator();
group.add(new AnAction("Toggle Layout Mode") {
@Override
public void actionPerformed(AnActionEvent e) {
RenderPreviewManager.toggleLayoutMode(myRenderContext);
}
});
}
static void addLocalePreviewAction(@NotNull RenderContext context, @NotNull DefaultActionGroup group, boolean enabled) {
group.add(new PreviewAction(context, "Preview All Locales", ACTION_PREVIEW_MODE, RenderPreviewMode.LOCALES, enabled));
}
static void addRtlPreviewAction(@NotNull RenderContext context, @NotNull DefaultActionGroup group) {
boolean enabled = hasCapability(context, Features.RTL);
group.add(new PreviewAction(context, "Preview Right-to-Left Layout", ACTION_PREVIEW_MODE, RenderPreviewMode.RTL, enabled));
}
static void addApiLevelPreviewAction(@NotNull RenderContext context, @NotNull DefaultActionGroup group) {
boolean enabled = hasCapability(context, Features.SIMULATE_PLATFORM);
group.add(new PreviewAction(context, "Preview Android Versions", ACTION_PREVIEW_MODE, RenderPreviewMode.API_LEVELS, enabled));
}
private static boolean hasCapability(RenderContext context, int capability) {
boolean enabled = false;
Configuration configuration = context.getConfiguration();
Module module = context.getModule();
if (configuration != null && module != null) {
ConfigurationManager configurationManager = configuration.getConfigurationManager();
IAndroidTarget target = configurationManager.getTarget();
if (target != null) {
LayoutLibrary library = RenderService.getLayoutLibrary(module, target);
enabled = library != null && library.supports(capability);
}
}
return enabled;
}
static void addScreenSizeAction(@NotNull RenderContext context, @NotNull DefaultActionGroup group) {
boolean enabled = context.supportsPreviews();
group.add(new PreviewAction(context, "Preview All Screen Sizes", ACTION_PREVIEW_MODE, RenderPreviewMode.SCREENS, enabled));
}
static void addRemovePreviewsAction(@NotNull RenderContext context, @NotNull DefaultActionGroup group) {
boolean enabled = context.supportsPreviews();
group.add(new PreviewAction(context, "Remove Previews", ACTION_PREVIEW_MODE, RenderPreviewMode.NONE, enabled));
}
private static final int ACTION_ADD = 1;
private static final int ACTION_DELETE_ALL = 2;
private static final int ACTION_PREVIEW_MODE = 3;
private static class PreviewAction extends AnAction {
private final int myAction;
private final RenderPreviewMode myMode;
private final RenderContext myRenderContext;
public PreviewAction(@NotNull RenderContext renderContext, @NotNull String title, int action,
@Nullable RenderPreviewMode mode, boolean enabled) {
super(title, null, null);
myRenderContext = renderContext;
myAction = action;
myMode = mode;
if (mode != null && mode == RenderPreviewMode.getCurrent()) {
// Select
Presentation templatePresentation = getTemplatePresentation();
templatePresentation.setIcon(AllIcons.Actions.Checked);
templatePresentation.setEnabled(false);
}
if (!enabled) {
getTemplatePresentation().setEnabled(false);
}
}
@Override
public void actionPerformed(AnActionEvent e) {
RenderPreviewManager previewManager = myRenderContext.getPreviewManager(true);
assert previewManager != null;
switch (myAction) {
case ACTION_ADD: {
previewManager.addAsThumbnail();
break;
}
case ACTION_PREVIEW_MODE: {
assert myMode != null;
previewManager.selectMode(myMode);
break;
}
case ACTION_DELETE_ALL: {
previewManager.deleteManualPreviews();
break;
}
default: assert false : myAction;
}
myRenderContext.updateLayout();
//myRenderContext.zoomFit(true /*onlyZoomOut*/, false /*allowZoomIn*/);
}
}
private static class SwitchToVariationAction extends AnAction {
private final Project myProject;
private final VirtualFile myFile;
public SwitchToVariationAction(String title, @NotNull Project project, VirtualFile file, boolean select) {
super(title, null, null);
myFile = file;
myProject = project;
if (select) {
Presentation templatePresentation = getTemplatePresentation();
templatePresentation.setIcon(AllIcons.Actions.Checked);
templatePresentation.setEnabled(false);
}
}
@Override
public void actionPerformed(AnActionEvent e) {
OpenFileDescriptor descriptor = new OpenFileDescriptor(myProject, myFile, -1);
FileEditorManager.getInstance(myProject).openEditor(descriptor, true);
}
}
private static class CreateVariationAction extends AnAction {
@NotNull private RenderContext myRenderContext;
@Nullable private String myNewFolder;
public CreateVariationAction(@NotNull RenderContext renderContext, @NotNull String title, @Nullable String newFolder) {
super(title, null, null);
myRenderContext = renderContext;
myNewFolder = newFolder;
}
@Override
public void actionPerformed(AnActionEvent e) {
OverrideResourceAction.forkResourceFile(myRenderContext, myNewFolder, true);
}
}
}