blob: f223506a708b6411b4f88b4ddbed0ec3a0dea9ea [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.android.tools.idea.npw;
import com.android.SdkConstants;
import com.android.assetstudiolib.GraphicGenerator;
import com.android.builder.model.SourceProvider;
import com.android.resources.Density;
import com.android.resources.ResourceFolderType;
import com.android.resources.ResourceType;
import com.android.tools.idea.templates.*;
import com.android.tools.idea.ui.ComboBoxItemWithApiTag;
import com.android.tools.idea.ui.ImageComponent;
import com.android.tools.idea.wizard.dynamic.DynamicWizardStepWithDescription;
import com.android.tools.idea.wizard.dynamic.RadioButtonGroupBinding;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ColorPanel;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.text.Document;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import static com.android.assetstudiolib.ActionBarIconGenerator.Theme;
import static com.android.tools.idea.npw.AssetStudioAssetGenerator.*;
import static com.android.tools.idea.wizard.dynamic.ScopedStateStore.Key;
import static com.android.tools.idea.wizard.dynamic.ScopedStateStore.Scope.PATH;
import static com.android.tools.idea.wizard.dynamic.ScopedStateStore.Scope.STEP;
import static com.android.tools.idea.wizard.dynamic.ScopedStateStore.createKey;
/**
* {@linkplain IconStep} is a wizard page that lets the user create a variety of density-scaled assets.
* TODO: It seems like the "Launcher" and "Action Bar and Tabs" modes might not be used anymore.
*/
public class IconStep extends DynamicWizardStepWithDescription implements Disposable {
public static final Key<String> ATTR_ASSET_NAME = createKey(AssetStudioAssetGenerator.ATTR_ASSET_NAME, PATH, String.class);
public static final Key<String> ATTR_CLIPART_NAME = createKey(AssetStudioAssetGenerator.ATTR_CLIPART_NAME, PATH, String.class);
public static final Key<String> ATTR_VECTOR_LIB_ICON_PATH = createKey(AssetStudioAssetGenerator.ATTR_VECTOR_LIB_ICON_PATH, PATH, String.class);
public static final Key<String> ATTR_TEXT = createKey(AssetStudioAssetGenerator.ATTR_TEXT, PATH, String.class);
public static final Key<String> ATTR_FONT = createKey(AssetStudioAssetGenerator.ATTR_FONT, PATH, String.class);
public static final Key<AssetType> ATTR_ASSET_TYPE = createKey(AssetStudioAssetGenerator.ATTR_ASSET_TYPE, PATH, AssetType.class);
public static final Key<String> ATTR_ASSET_THEME = createKey(AssetStudioAssetGenerator.ATTR_ASSET_THEME, PATH, String.class);
public static final Key<Scaling> ATTR_SCALING = createKey(AssetStudioAssetGenerator.ATTR_SCALING, PATH, Scaling.class);
public static final Key<GraphicGenerator.Shape> ATTR_SHAPE =
createKey(AssetStudioAssetGenerator.ATTR_SHAPE, PATH, GraphicGenerator.Shape.class);
public static final Key<SourceType> ATTR_SOURCE_TYPE = createKey(AssetStudioAssetGenerator.ATTR_SOURCE_TYPE, PATH, SourceType.class);
public static final Key<Boolean> ATTR_TRIM = createKey(AssetStudioAssetGenerator.ATTR_TRIM, PATH, Boolean.class);
public static final Key<Boolean> ATTR_DOGEAR = createKey(AssetStudioAssetGenerator.ATTR_DOGEAR, PATH, Boolean.class);
public static final Key<Integer> ATTR_PADDING = createKey(AssetStudioAssetGenerator.ATTR_PADDING, PATH, Integer.class);
public static final Key<Color> ATTR_FOREGROUND_COLOR = createKey(AssetStudioAssetGenerator.ATTR_FOREGROUND_COLOR, PATH, Color.class);
public static final Key<Color> ATTR_BACKGROUND_COLOR = createKey(AssetStudioAssetGenerator.ATTR_BACKGROUND_COLOR, PATH, Color.class);
public static final Key<String> ATTR_IMAGE_PATH = createKey(AssetStudioAssetGenerator.ATTR_IMAGE_PATH, PATH, String.class);
public static final Key<String> ATTR_ICON_RESOURCE = createKey("icon_resource", PATH, String.class);
public static final Key<Integer> ATTR_FONT_SIZE = createKey(AssetStudioAssetGenerator.ATTR_FONT_SIZE, PATH, Integer.class);
public static final Key<File> ATTR_OUTPUT_FOLDER = createKey(ChooseOutputResDirStep.ATTR_OUTPUT_FOLDER, STEP, File.class);
public static final Key<String> ATTR_ERROR_LOG = createKey(AssetStudioAssetGenerator.ATTR_ERROR_LOG, PATH, String.class);
public static final Key<String> ATTR_VECTOR_DRAWBLE_WIDTH = createKey(AssetStudioAssetGenerator.ATTR_VECTOR_DRAWBLE_WIDTH, STEP, String.class);
public static final Key<String> ATTR_VECTOR_DRAWBLE_HEIGHT = createKey(AssetStudioAssetGenerator.ATTR_VECTOR_DRAWBLE_HEIGHT, STEP, String.class);
public static final Key<Integer> ATTR_ORIGINAL_WIDTH = createKey(AssetStudioAssetGenerator.ATTR_ORIGINAL_WIDTH, STEP, Integer.class);
public static final Key<Integer> ATTR_ORIGINAL_HEIGHT = createKey(AssetStudioAssetGenerator.ATTR_ORIGINAL_HEIGHT, STEP, Integer.class);
public static final Key<Integer> ATTR_VECTOR_DRAWBLE_OPACTITY = createKey(AssetStudioAssetGenerator.ATTR_VECTOR_DRAWBLE_OPACTITY, STEP, Integer.class);
public static final Key<Boolean> ATTR_VECTOR_DRAWBLE_AUTO_MIRRORED = createKey(AssetStudioAssetGenerator.ATTR_VECTOR_DRAWBLE_AUTO_MIRRORED, STEP, Boolean.class);
private static final Logger LOG = Logger.getInstance(IconStep.class);
private static final int CLIPART_ICON_SIZE = 32;
private static final int CLIPART_DIALOG_BORDER = 10;
private static final int DIALOG_HEADER = 20;
private static final String V11 = "V11";
private static final String V9 = "V9";
private final StringEvaluator myStringEvaluator = new StringEvaluator();
private final MergingUpdateQueue myUpdateQueue;
private final Map<String, Map<String, BufferedImage>> myImageMap = new ConcurrentHashMap<String, Map<String, BufferedImage>>();
private final Key<TemplateEntry> myTemplateKey;
private final Key<SourceProvider> mySourceProviderKey;
private final SourceProvider[] mySourceProviders;
private AssetStudioAssetGenerator myAssetGenerator;
private JPanel myPanel;
private JRadioButton myImageRadioButton;
private JRadioButton myClipartRadioButton;
private JRadioButton myTextRadioButton;
private JRadioButton myCropRadioButton;
private JRadioButton myCenterRadioButton;
private JRadioButton myCircleRadioButton;
private JRadioButton mySquareRadioButton;
private JRadioButton myNoneRadioButton;
private JButton myChooseClipart;
private JCheckBox myTrimBlankSpace;
private JTextField myText;
private JComboBox myFontFamily;
private TextFieldWithBrowseButton myImageFile;
private ColorPanel myBackgroundColor;
private ColorPanel myForegroundColor;
private ImageComponent myMdpiPreview;
private ImageComponent myHdpiPreview;
private ImageComponent myXHdpiPreview;
private JSlider myPaddingSlider;
private ImageComponent myXXHdpiPreview;
private JLabel myForegroundColorLabel;
private JLabel myAssetTypeLabel;
private JComboBox myChooseThemeComboBox;
private JTextField myResourceNameField;
private ImageComponent myV9XHdpiPreview;
private ImageComponent myV9XXHdpiPreview;
private ImageComponent myV9MdpiPreview;
private ImageComponent myV9HdpiPreview;
private ImageComponent myV11MdpiPreview;
private ImageComponent myV11HdpiPreview;
private ImageComponent myV11XHdpiPreview;
private ImageComponent myV11XXHdpiPreview;
private JTextField myPaddingTextField;
private JRadioButton myLauncherRadioButton;
private JRadioButton myActionBarAndTabsRadioButton;
private JRadioButton myNotificationRadioButton;
private JPanel myPageBook;
private JLabel mySourceSetLabel;
private JComboBox mySourceSetComboBox;
private JPanel myTypePanel;
private JPanel myAssetSourceCardPanel;
private JPanel myTypeCardPanel;
private String myDefaultName;
@SuppressWarnings("UseJBColor") // Colors are used for the graphics generator, not the plugin UI
public IconStep(Key<TemplateEntry> templateKey, Key<SourceProvider> sourceProviderKey,
@Nullable SourceProvider[] sourceProviders, Disposable disposable) {
super(disposable);
myTemplateKey = templateKey;
mySourceProviderKey = sourceProviderKey;
mySourceProviders = sourceProviders;
myUpdateQueue = new MergingUpdateQueue("asset.studio", 200, true, null, this, null, false);
myImageFile.addBrowseFolderListener(null, null, null, FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
myForegroundColor.setSelectedColor(Color.BLUE);
myBackgroundColor.setSelectedColor(Color.WHITE);
for (String font : GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()) {
myFontFamily.addItem(new ComboBoxItemWithApiTag(font, font, 1, 1));
if (font.equals(myState.get(ATTR_FONT))) {
myFontFamily.setSelectedIndex(myFontFamily.getItemCount() - 1);
}
}
myChooseClipart.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
displayClipartDialog();
}
});
setBodyComponent(myPanel);
}
@Nullable
private static Icon getClipartIcon(@Nullable String clipartName) {
if (StringUtil.isEmpty(clipartName)) {
return null;
}
BufferedImage icon = null;
try {
icon = GraphicGenerator.getClipartIcon(clipartName);
}
catch (IOException e) {
Logger.getInstance(IconStep.class).error(e);
}
return new ImageIcon(icon, clipartName);
}
private static void populateThemeComboBox(JComboBox comboBox) {
for (Theme theme : Theme.values()) {
String themeName = theme.name();
comboBox.addItem(new ComboBoxItemWithApiTag(themeName, themeName, 0, 0));
}
}
private static void show(JComponent... components) {
for (JComponent component : components) {
component.setVisible(true);
component.getParent().invalidate();
}
}
private static void hide(JComponent... components) {
for (JComponent component : components) {
component.setVisible(false);
component.getParent().invalidate();
}
}
private static void setIconOrClear(@NotNull ImageComponent component, @Nullable BufferedImage image) {
if (image == null) {
component.setIcon(null);
}
else {
component.setIcon(new ImageIcon(image));
}
}
@Nullable
private static BufferedImage getImage(@NotNull Map<String, Map<String, BufferedImage>> map, @NotNull String name) {
final Map<String, BufferedImage> images = map.get(name);
if (images == null) {
return null;
}
final Collection<BufferedImage> values = images.values();
return values.isEmpty() ? null : values.iterator().next();
}
@Nullable
private static BufferedImage getImage(@NotNull Map<String, Map<String, BufferedImage>> map,
@NotNull String category, @NotNull Density density) {
String densityString = density.getResourceValue();
final Map<String, BufferedImage> images = map.get(category);
if (images == null) {
return null;
}
for (String key : images.keySet()) {
if (key.contains(densityString)) {
return images.get(key);
}
}
return null;
}
private static String getResourceDirLabel(@Nullable Module module, File directory) {
if (module == null) {
return directory.getName();
}
String filePath = module.getModuleFilePath();
String parent = new File(filePath).getParent();
String path = directory.getPath();
return path.startsWith(parent) ? path.substring(parent.length() + 1) : directory.getName();
}
@Override
public void init() {
super.init();
myAssetGenerator = new AssetStudioAssetGenerator(new ScopedStateStoreAdapter(myState));
myState.put(ATTR_ASSET_TYPE, AssetType.LAUNCHER);
//noinspection deprecation
String relativeTemplatePath = FileUtil
.join(Template.CATEGORY_PROJECTS, NewProjectWizardState.MODULE_TEMPLATE_NAME,
"root", "res", "mipmap-xhdpi", "ic_launcher.png");
myState.put(ATTR_IMAGE_PATH, new File(TemplateManager.getTemplateRootFolder(), relativeTemplatePath).getAbsolutePath());
register(ATTR_OUTPUT_FOLDER, mySourceSetComboBox);
register(ATTR_IMAGE_PATH, myImageFile);
register(ATTR_TEXT, myText);
register(ATTR_SCALING, ImmutableMap.of(myCropRadioButton, Scaling.CROP, myCenterRadioButton, Scaling.CENTER));
register(ATTR_SHAPE, ImmutableMap
.of(myCircleRadioButton, GraphicGenerator.Shape.CIRCLE, mySquareRadioButton, GraphicGenerator.Shape.SQUARE, myNoneRadioButton,
GraphicGenerator.Shape.NONE));
register(ATTR_PADDING, myPaddingSlider);
register(ATTR_PADDING, myPaddingTextField, new ComponentBinding<Integer, JTextField>() {
@Override
public void setValue(@Nullable Integer newValue, @NotNull JTextField component) {
component.setText(newValue == null ? "" : String.valueOf(newValue));
}
@Nullable
@Override
public Integer getValue(@NotNull JTextField component) {
try {
// Shoehorn user input into acceptable bounds. There's slider and preview
// so the user already receives enough feedback.
return Math.max(0, Math.min(Integer.parseInt(component.getText()), 100));
}
catch (NumberFormatException e) {
return 0;
}
}
@Override
public void addActionListener(@NotNull ActionListener listener, @NotNull JTextField component) {
component.addActionListener(listener);
}
@Nullable
@Override
public Document getDocument(@NotNull JTextField component) {
return component.getDocument();
}
});
register(ATTR_TRIM, myTrimBlankSpace);
register(ATTR_FONT, myFontFamily);
register(ATTR_SOURCE_TYPE, ImmutableMap
.of(myImageRadioButton, SourceType.IMAGE, myClipartRadioButton, SourceType.CLIPART, myTextRadioButton, SourceType.TEXT));
register(ATTR_FOREGROUND_COLOR, myForegroundColor);
register(ATTR_BACKGROUND_COLOR, myBackgroundColor);
register(ATTR_ASSET_TYPE, ImmutableMap
.of(myLauncherRadioButton, AssetType.LAUNCHER, myActionBarAndTabsRadioButton, AssetType.ACTIONBAR, myNotificationRadioButton,
AssetType.NOTIFICATION));
register(ATTR_ASSET_THEME, myChooseThemeComboBox);
register(ATTR_ASSET_NAME, myResourceNameField);
register(ATTR_CLIPART_NAME, myChooseClipart, new ComponentBinding<String, JButton>() {
@Override
public void setValue(@Nullable String newValue, @NotNull JButton component) {
component.setIcon(getClipartIcon(newValue));
component.setText(newValue);
}
});
populateThemeComboBox(myChooseThemeComboBox);
String theme = myState.get(ATTR_ASSET_NAME);
// Theme chooser
if (myChooseThemeComboBox.isVisible() && !StringUtil.isEmpty(theme)) {
if (Theme.valueOf(theme).equals(Theme.CUSTOM)) {
show(myForegroundColor, myForegroundColorLabel);
}
else {
hide(myForegroundColor, myForegroundColorLabel);
}
}
}
private void updateDirectoryCombo() {
final boolean showLabelAndCombo;
List<File> folders = getResourceFolders();
File res = myState.get(ATTR_OUTPUT_FOLDER);
if (!folders.isEmpty()) {
if (res == null || !folders.contains(res)) {
res = folders.get(0);
myState.put(ATTR_OUTPUT_FOLDER, res);
}
showLabelAndCombo = folders.size() > 1;
mySourceSetComboBox.removeAllItems();
if (showLabelAndCombo) {
ComboBoxItemWithApiTag selected = null;
for (File directory : folders) {
ComboBoxItemWithApiTag item = new ComboBoxItemWithApiTag(directory, getResourceDirLabel(getModule(), directory), 0, 0);
if (Objects.equal(directory, res)) {
selected = item;
}
mySourceSetComboBox.addItem(item);
}
mySourceSetComboBox.setSelectedItem(selected);
}
}
else {
showLabelAndCombo = false;
}
mySourceSetComboBox.setVisible(showLabelAndCombo);
mySourceSetLabel.setVisible(showLabelAndCombo);
}
private List<File> getResourceFolders() {
SourceProvider[] providers = mySourceProviders;
if (providers == null) {
SourceProvider provider = myState.get(mySourceProviderKey);
if (provider == null) {
return Collections.emptyList();
}
providers = new SourceProvider[]{provider};
}
List<File> dirs = Lists.newLinkedList();
for (final SourceProvider provider : providers) {
dirs.addAll(provider.getResDirectories());
}
return dirs;
}
private <E> void register(Key<E> key, Map<JRadioButton, E> buttonsToValues) {
RadioButtonGroupBinding<E> binding = new RadioButtonGroupBinding<E>(buttonsToValues);
for (JRadioButton button : buttonsToValues.keySet()) {
register(key, button, binding);
}
}
@Override
public boolean isStepVisible() {
TemplateEntry templateEntry = myState.get(myTemplateKey);
boolean isVisible = false;
if (templateEntry != null) {
TemplateMetadata templateMetadata = templateEntry.getMetadata();
if (templateMetadata.getIconType() != null) {
isVisible = true;
}
}
return isVisible;
}
@Override
public void deriveValues(Set<Key> modified) {
super.deriveValues(modified);
AssetType iconType = null;
TemplateEntry templateEntry = myState.get(myTemplateKey);
if (templateEntry != null) {
iconType = templateEntry.getMetadata().getIconType();
}
finalizeAssetType(iconType);
// Note that this combo may need to reflect source set from another wizard page
updateDirectoryCombo();
myState.put(ATTR_ICON_RESOURCE, myState.get(ATTR_ASSET_NAME));
SourceType sourceType = myState.get(ATTR_SOURCE_TYPE);
if (sourceType != null) {
switch (sourceType) {
case IMAGE:
((CardLayout)myAssetSourceCardPanel.getLayout()).show(myAssetSourceCardPanel, "ImageCard");
hide(myForegroundColor, myForegroundColorLabel);
break;
case CLIPART:
((CardLayout)myAssetSourceCardPanel.getLayout()).show(myAssetSourceCardPanel, "ClipartCard");
show(myForegroundColor, myForegroundColorLabel);
break;
case TEXT:
((CardLayout)myAssetSourceCardPanel.getLayout()).show(myAssetSourceCardPanel, "TextCard");
show(myForegroundColor, myForegroundColorLabel);
myFontFamily.setSelectedItem(myState.get(ATTR_FONT));
break;
}
}
// Asset Type Combo Box
AssetType assetType = myState.get(ATTR_ASSET_TYPE);
if (assetType != null) {
switch (assetType) {
case LAUNCHER:
((CardLayout)myTypeCardPanel.getLayout()).show(myTypeCardPanel, "LauncherCard");
break;
case ACTIONBAR:
((CardLayout)myTypeCardPanel.getLayout()).show(myTypeCardPanel, "ActionbarCard");
break;
case NOTIFICATION:
((CardLayout)myTypeCardPanel.getLayout()).show(myTypeCardPanel, "NotificationCard");
break;
}
String name = myState.get(ATTR_ASSET_NAME);
if (name == null || Objects.equal(myDefaultName, name)) {
myDefaultName = computeResourceName(assetType);
myState.put(ATTR_ASSET_NAME, myDefaultName);
}
}
// Theme chooser
String assetTheme = myState.get(ATTR_ASSET_THEME);
if (myChooseThemeComboBox.isVisible() && !StringUtil.isEmpty(assetTheme)) {
if (Theme.valueOf(assetTheme).equals(Theme.CUSTOM)) {
show(myForegroundColor, myForegroundColorLabel);
}
else {
hide(myForegroundColor, myForegroundColorLabel);
}
}
requestPreviewUpdate();
}
@Override
public boolean validate() {
if (!super.validate()) {
return false;
}
String assetName = myState.get(ATTR_ASSET_NAME);
boolean canProceed = true;
String error = null;
if (StringUtil.isEmpty(assetName)) {
canProceed = false;
error = "Missing resource name";
}
else if (drawableExists(assetName)) {
error = String.format("A drawable resource named %s already exists and will be overwritten.", assetName);
}
setErrorHtml(error);
return canProceed;
}
/**
* (Re)schedule the background task which updates the preview images.
*/
private void requestPreviewUpdate() {
myUpdateQueue.cancelAllUpdates();
myUpdateQueue.queue(new Update("update") {
@Override
public void run() {
try {
if (myAssetGenerator == null) { // Init not done yet
return;
}
myAssetGenerator.generateImages(myImageMap, true, true);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
updatePreviewImages();
}
});
}
catch (final ImageGeneratorException e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
setErrorHtml(e.getMessage());
}
});
}
}
});
}
private void updatePreviewImages() {
AssetType assetType = myState.get(ATTR_ASSET_TYPE);
if (assetType == null || myImageMap.isEmpty()) {
return;
}
if (assetType.equals(AssetType.NOTIFICATION)) {
final BufferedImage v9_mdpi = getImage(myImageMap, V9, Density.MEDIUM);
final BufferedImage v9_hdpi = getImage(myImageMap, V9, Density.HIGH);
final BufferedImage v9_xhdpi = getImage(myImageMap, V9, Density.XHIGH);
final BufferedImage v9_xxhdpi = getImage(myImageMap, V9, Density.XXHIGH);
setIconOrClear(myV9MdpiPreview, v9_mdpi);
setIconOrClear(myV9HdpiPreview, v9_hdpi);
setIconOrClear(myV9XHdpiPreview, v9_xhdpi);
setIconOrClear(myV9XXHdpiPreview, v9_xxhdpi);
final BufferedImage v11_mdpi = getImage(myImageMap, V11, Density.MEDIUM);
final BufferedImage v11_hdpi = getImage(myImageMap, V11, Density.HIGH);
final BufferedImage v11_xhdpi = getImage(myImageMap, V11, Density.XHIGH);
final BufferedImage v11_xxhdpi = getImage(myImageMap, V11, Density.XXHIGH);
setIconOrClear(myV11MdpiPreview, v11_mdpi);
setIconOrClear(myV11HdpiPreview, v11_hdpi);
setIconOrClear(myV11XHdpiPreview, v11_xhdpi);
setIconOrClear(myV11XXHdpiPreview, v11_xxhdpi);
}
else {
final BufferedImage mdpi = getImage(myImageMap, Density.MEDIUM.getResourceValue());
final BufferedImage hdpi = getImage(myImageMap, Density.HIGH.getResourceValue());
final BufferedImage xhdpi = getImage(myImageMap, Density.XHIGH.getResourceValue());
final BufferedImage xxhdpi = getImage(myImageMap, Density.XXHIGH.getResourceValue());
setIconOrClear(myMdpiPreview, mdpi);
setIconOrClear(myHdpiPreview, hdpi);
setIconOrClear(myXHdpiPreview, xhdpi);
setIconOrClear(myXXHdpiPreview, xxhdpi);
}
((CardLayout)myPageBook.getLayout()).show(myPageBook, assetType == AssetType.NOTIFICATION ? "versions" : "DPI");
}
/**
* Displays a modal dialog with one button for each entry in the {@link com.android.assetstudiolib.GraphicGenerator}
* clipart library. Clicking on a button sets that entry into the {@link #ATTR_CLIPART_NAME} key.
*/
private void displayClipartDialog() {
Window window = SwingUtilities.getWindowAncestor(myPanel);
final JDialog dialog = new JDialog(window, Dialog.ModalityType.DOCUMENT_MODAL);
FlowLayout layout = new FlowLayout();
dialog.getRootPane().setLayout(layout);
int count = 0;
for (Iterator<String> iter = GraphicGenerator.getResourcesNames(RasterAssetSetStep.IMAGES_CLIPART_BIG,
SdkConstants.DOT_PNG);
iter.hasNext(); ) {
final String name = iter.next();
try {
JButton btn = new JButton();
btn.setIcon(new ImageIcon(GraphicGenerator.getClipartIcon(name)));
Dimension d = new Dimension(CLIPART_ICON_SIZE, CLIPART_ICON_SIZE);
btn.setMaximumSize(d);
btn.setPreferredSize(d);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myState.put(ATTR_CLIPART_NAME, name);
dialog.setVisible(false);
}
});
dialog.getRootPane().add(btn);
count++;
}
catch (IOException e) {
LOG.error(e);
}
}
int size = (int)(Math.sqrt(count) + 1) * (CLIPART_ICON_SIZE + layout.getHgap()) + CLIPART_DIALOG_BORDER * 2;
dialog.setSize(size, size + DIALOG_HEADER);
dialog.setLocationRelativeTo(window);
dialog.setVisible(true);
}
public void finalizeAssetType(@Nullable AssetType type) {
myState.put(ATTR_ASSET_TYPE, type);
myTypePanel.setVisible(type == null);
myAssetTypeLabel.setVisible(type == null);
}
@NotNull
private String computeResourceName(AssetType assetType) {
String resourceName = null;
TemplateEntry templateEntry = myState.get(myTemplateKey);
String nameExpression;
if (templateEntry != null) {
nameExpression = templateEntry.getMetadata().getIconName();
if (!StringUtil.isEmpty(nameExpression)) {
Set<Key> allKeys = myState.getAllKeys();
Map<String, Object> parameters = Maps.newHashMapWithExpectedSize(allKeys.size());
for (Key key : allKeys) {
parameters.put(key.name, myState.get(key));
}
resourceName = myStringEvaluator.evaluate(nameExpression, parameters);
}
}
if (resourceName == null) {
resourceName = String.format(assetType.getDefaultNameFormat(), "name");
}
// It's unusual to have > 1 launcher icon, don't fix the name for launcher icons.
if (drawableExists(resourceName) && assetType != AssetType.LAUNCHER) {
// While uniqueness isn't satisfied, increment number and add to end
int i = 2;
while (drawableExists(resourceName + Integer.toString(i))) {
i++;
}
resourceName += Integer.toString(i);
}
return resourceName;
}
/**
* Must be run inside a write action. Creates the asset files on disk.
*/
public void createAssets() {
if (isStepVisible()) {
File destination = myState.get(ATTR_OUTPUT_FOLDER);
assert destination != null;
// Asset generator will append "res" by itself
myAssetGenerator.outputImagesIntoVariantRoot(destination.getParentFile());
}
}
private boolean drawableExists(String resourceName) {
File resDir = myState.get(ATTR_OUTPUT_FOLDER);
if (resDir != null) {
return Parameter.existsResourceFile(resDir, ResourceFolderType.DRAWABLE, resourceName);
}
else {
return Parameter.existsResourceFile(getModule(), ResourceType.DRAWABLE, resourceName);
}
}
@Override
public JComponent getPreferredFocusedComponent() {
return myImageRadioButton;
}
@NotNull
@Override
public String getStepName() {
return "Asset Studio";
}
@NotNull
@Override
protected String getStepTitle() {
return "Asset Studio";
}
@Nullable
@Override
protected String getStepDescription() {
return null;
}
@Override
public void dispose() {
myUpdateQueue.cancelAllUpdates();
}
}