/* * 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.Capability; 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"); 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, Capability.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, Capability.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, Capability.SIMULATE_PLATFORM); group.add(new PreviewAction(context, "Preview Android Versions", ACTION_PREVIEW_MODE, RenderPreviewMode.API_LEVELS, enabled)); } private static boolean hasCapability(RenderContext context, Capability 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) { group.add(new PreviewAction(context, "Preview All Screen Sizes", ACTION_PREVIEW_MODE, RenderPreviewMode.SCREENS, true)); } static void addRemovePreviewsAction(@NotNull RenderContext context, @NotNull DefaultActionGroup group) { group.add(new PreviewAction(context, "Remove Previews", ACTION_PREVIEW_MODE, RenderPreviewMode.NONE, true)); } 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); } } }