de.mprengemann.intellij.plugin.androidicons.dialogs.AndroidMultiDrawableImporter.java Source code

Java tutorial

Introduction

Here is the source code for de.mprengemann.intellij.plugin.androidicons.dialogs.AndroidMultiDrawableImporter.java

Source

/*
 * Copyright 2015 Marc Prengemann
 *
 * 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 de.mprengemann.intellij.plugin.androidicons.dialogs;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.io.ZipUtil;
import com.intellij.util.ui.UIUtil;
import de.mprengemann.intellij.plugin.androidicons.IconApplication;
import de.mprengemann.intellij.plugin.androidicons.controllers.multi.IMultiImporterController;
import de.mprengemann.intellij.plugin.androidicons.controllers.multi.MultiImporterController;
import de.mprengemann.intellij.plugin.androidicons.controllers.multi.MultiImporterObserver;
import de.mprengemann.intellij.plugin.androidicons.controllers.settings.ISettingsController;
import de.mprengemann.intellij.plugin.androidicons.listeners.SimpleMouseListener;
import de.mprengemann.intellij.plugin.androidicons.model.Format;
import de.mprengemann.intellij.plugin.androidicons.model.ImageInformation;
import de.mprengemann.intellij.plugin.androidicons.model.Resolution;
import de.mprengemann.intellij.plugin.androidicons.util.ImageUtils;
import de.mprengemann.intellij.plugin.androidicons.widgets.ExportNameField;
import de.mprengemann.intellij.plugin.androidicons.widgets.FileBrowserField;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.activation.MimetypesFileTypeMap;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class AndroidMultiDrawableImporter extends DialogWrapper implements MultiImporterObserver {

    private final FileChooserDescriptor archiveDescriptor = new FileChooserDescriptor(true, false, true, true,
            false, false) {
        @Override
        public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
            return file.isDirectory() || isZip(file.getName());
        }

        @Override
        public boolean isFileSelectable(VirtualFile file) {
            return isZip(file.getName());
        }

        private boolean isZip(String name) {
            return name.contains(".zip");
        }
    };
    private static final Resolution[] RESOLUTIONS = new Resolution[] { Resolution.XXXHDPI, Resolution.XXHDPI,
            Resolution.XHDPI, Resolution.HDPI, Resolution.MDPI, Resolution.LDPI, Resolution.TVDPI };
    private static final String TAG = AndroidMultiDrawableImporter.class.getSimpleName();
    private static final Logger LOGGER = Logger.getInstance(TAG);
    private final Project project;
    private final Module module;
    private final IMultiImporterController controller;
    private Action zipImportAction;

    private FileBrowserField resRoot;
    private FileBrowserField ldpiFile;
    private FileBrowserField mdpiFile;
    private FileBrowserField hdpiFile;
    private FileBrowserField xhdpiFile;
    private FileBrowserField xxhdpiFile;
    private FileBrowserField xxxhdpiFile;
    private FileBrowserField tvdpiFile;
    private JLabel imageContainer;
    private ExportNameField resExportName;
    private JPanel uiContainer;
    private JComboBox formatSpinner;
    private final ActionListener formatListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            final JComboBox source = (JComboBox) e.getSource();
            final Format selectedItem = (Format) source.getSelectedItem();
            controller.setFormat(selectedItem);
        }
    };
    private final ISettingsController settingsController;
    private final IconApplication container;

    public AndroidMultiDrawableImporter(final Project project, final Module module) {
        super(project, true);
        this.project = project;
        this.module = module;

        container = ApplicationManager.getApplication().getComponent(IconApplication.class);
        settingsController = container.getControllerFactory().getSettingsController();
        this.controller = new MultiImporterController(container.getControllerFactory().getDefaultsController());
        this.controller.addObserver(this);

        initResourceRoot();
        initBrowser(Resolution.LDPI, ldpiFile);
        initBrowser(Resolution.MDPI, mdpiFile);
        initBrowser(Resolution.HDPI, hdpiFile);
        initBrowser(Resolution.XHDPI, xhdpiFile);
        initBrowser(Resolution.XXHDPI, xxhdpiFile);
        initBrowser(Resolution.XXXHDPI, xxxhdpiFile);
        initBrowser(Resolution.TVDPI, tvdpiFile);

        setTitle("Android Multi Drawable Importer");
        init();
        pack();
    }

    @Nullable
    @Override
    protected ValidationInfo doValidate() {
        if (StringUtils.isEmpty(controller.getTargetRoot())) {
            return new ValidationInfo("Please select the resources root.", resRoot);
        }

        if (StringUtils.isEmpty(controller.getExportName())) {
            return new ValidationInfo("Please select a name for the drawable.", resExportName);
        }

        return super.doValidate();
    }

    @Override
    protected void doOKAction() {
        controller.getTask(project).queue();
        if (!controller.containsNinePatch()) {
            container.getControllerFactory().getDefaultsController().setFormat(controller.getFormat());
        }
        super.doOKAction();
    }

    @Override
    public void updated() {
        updateImage();
        updateTargetRoot();
        updateName();
        updateFormat();
    }

    private void updateFormat() {
        formatSpinner.removeActionListener(formatListener);
        formatSpinner.removeAllItems();
        for (Format format : Format.nonVectorValues()) {
            formatSpinner.addItem(format);
        }
        formatSpinner.setSelectedItem(controller.getFormat());
        formatSpinner.setEnabled(!controller.containsNinePatch());
        formatSpinner.addActionListener(formatListener);
    }

    private void updateTargetRoot() {
        final String targetRoot = controller.getTargetRoot();
        if (targetRoot == null) {
            return;
        }
        resRoot.setText(targetRoot);
    }

    private void updateName() {
        final String exportName = controller.getExportName();
        if (exportName == null) {
            return;
        }
        resExportName.setText(exportName);
        resExportName.addPropertyChangeListener("value", new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
                controller.setExportName(((String) resExportName.getValue()));
            }
        });
    }

    private void updateImage() {
        final File file = controller.getMostRecentImage();
        if (file == null) {
            return;
        }
        ImageUtils.updateImage(imageContainer, file, controller.getFormat());
    }

    @Nullable
    @Override
    protected JComponent createCenterPanel() {
        return uiContainer;
    }

    private void initResourceRoot() {
        resRoot.setSelectionListener(new Consumer<File>() {
            @Override
            public void consume(File file) {
                controller.setTargetRoot(file);
            }
        });
        resRoot.initWithResourceRoot(project, module, settingsController);
    }

    private void initBrowser(final Resolution resolution, final FileBrowserField fileBrowser) {
        fileBrowser.init(project, settingsController);
        fileBrowser.setSelectionListener(new Consumer<File>() {
            @Override
            public void consume(File file) {
                controller.addImage(file, resolution);
            }
        });
        fileBrowser.getTextField().addMouseListener(new SimpleMouseListener() {
            @Override
            public void mouseClicked(MouseEvent mouseEvent) {
                controller.setMostRecentImage(resolution);
            }
        });
    }

    private void createUIComponents() {
        resRoot = new FileBrowserField(FileBrowserField.RESOURCE_DIR_CHOOSER);
        ldpiFile = new FileBrowserField(FileBrowserField.IMAGE_FILE_CHOOSER);
        mdpiFile = new FileBrowserField(FileBrowserField.IMAGE_FILE_CHOOSER);
        hdpiFile = new FileBrowserField(FileBrowserField.IMAGE_FILE_CHOOSER);
        xhdpiFile = new FileBrowserField(FileBrowserField.IMAGE_FILE_CHOOSER);
        xxhdpiFile = new FileBrowserField(FileBrowserField.IMAGE_FILE_CHOOSER);
        xxxhdpiFile = new FileBrowserField(FileBrowserField.IMAGE_FILE_CHOOSER);
        tvdpiFile = new FileBrowserField(FileBrowserField.IMAGE_FILE_CHOOSER);
    }

    @Override
    protected void createDefaultActions() {
        super.createDefaultActions();
        this.zipImportAction = new AndroidMultiDrawableImporter.ZipImportAction();
    }

    protected final Action getZipImportAction() {
        return this.zipImportAction;
    }

    private void openZipArchive() {
        FileChooser.chooseFile(archiveDescriptor, project, getInitialFile(), new Consumer<VirtualFile>() {
            @Override
            public void consume(VirtualFile virtualFile) {
                if (virtualFile == null) {
                    return;
                }
                final String filePath = virtualFile.getCanonicalPath();
                if (filePath == null) {
                    return;
                }
                settingsController.saveLastImageFolder(filePath);
                controller.resetZipInformation();
                importZipArchive(virtualFile);
            }
        });
    }

    private void importZipArchive(VirtualFile virtualFile) {
        final String filePath = virtualFile.getCanonicalPath();
        if (filePath == null) {
            return;
        }
        final File tempDir = new File(ImageInformation.getTempDir(), virtualFile.getNameWithoutExtension());
        final String archiveName = virtualFile.getName();
        new Task.Modal(project, "Importing Archive...", true) {
            @Override
            public void run(@NotNull final ProgressIndicator progressIndicator) {
                progressIndicator.setIndeterminate(true);
                try {
                    FileUtils.forceMkdir(tempDir);
                    ZipUtil.extract(new File(filePath), tempDir, new FilenameFilter() {
                        @Override
                        public boolean accept(File dir, String name) {
                            final String mimeType = new MimetypesFileTypeMap().getContentType(name);
                            final String type = mimeType.split("/")[0];
                            return type.equals("image");
                        }
                    }, true);
                    progressIndicator.checkCanceled();

                    final Iterator<File> fileIterator = FileUtils.iterateFiles(tempDir, TrueFileFilter.INSTANCE,
                            TrueFileFilter.INSTANCE);
                    while (fileIterator.hasNext()) {
                        File file = fileIterator.next();
                        if (file.isDirectory() || file.isHidden()) {
                            continue;
                        }
                        final String fileRoot = file.getParent().toUpperCase();
                        final String name = FilenameUtils.getBaseName(file.toString());
                        if (name.startsWith(".") || fileRoot.contains("__MACOSX")) {
                            continue;
                        }
                        for (Resolution resolution : RESOLUTIONS) {
                            if (name.toUpperCase().contains("-" + resolution)
                                    || name.toUpperCase().contains("_" + resolution)
                                    || fileRoot.contains(resolution.toString())) {
                                controller.addZipImage(file, resolution);
                                break;
                            }
                        }
                    }
                    progressIndicator.checkCanceled();

                    final Map<Resolution, List<ImageInformation>> zipImages = controller.getZipImages();
                    final List<Resolution> foundResolutions = new ArrayList<Resolution>();
                    int foundAssets = 0;
                    for (Resolution resolution : zipImages.keySet()) {
                        final List<ImageInformation> assetInformation = zipImages.get(resolution);
                        if (assetInformation != null && assetInformation.size() > 0) {
                            foundAssets += assetInformation.size();
                            foundResolutions.add(resolution);
                        }
                    }
                    progressIndicator.checkCanceled();

                    final int finalFoundAssets = foundAssets;
                    UIUtil.invokeLaterIfNeeded(new DumbAwareRunnable() {
                        public void run() {
                            final String title = String.format("Import '%s'", archiveName);
                            if (foundResolutions.size() == 0 || finalFoundAssets == 0) {
                                Messages.showErrorDialog("No assets found.", title);
                                FileUtils.deleteQuietly(tempDir);
                                return;
                            }
                            final String[] options = new String[] { "Import", "Cancel" };
                            final String description = String.format("Import %d assets for %s to %s.",
                                    finalFoundAssets, StringUtils.join(foundResolutions, ", "),
                                    controller.getTargetRoot());
                            final int selection = Messages.showDialog(description, title, options, 0,
                                    Messages.getQuestionIcon());
                            if (selection == 0) {
                                controller.getZipTask(project, tempDir).queue();
                                close(0);
                            } else {
                                FileUtils.deleteQuietly(tempDir);
                            }
                        }
                    });
                } catch (ProcessCanceledException e) {
                    FileUtils.deleteQuietly(tempDir);
                } catch (IOException e) {
                    LOGGER.error(e);
                }
            }
        }.queue();
    }

    private VirtualFile getInitialFile() {
        String directoryName = settingsController.getLastImageFolder();
        VirtualFile path;
        String expandPath = expandPath(directoryName);
        if (expandPath == null) {
            return null;
        }
        for (path = LocalFileSystem.getInstance().findFileByPath(expandPath); path == null
                && directoryName.length() > 0; path = LocalFileSystem.getInstance().findFileByPath(directoryName)) {
            int pos = directoryName.lastIndexOf(47);
            if (pos <= 0) {
                break;
            }
            directoryName = directoryName.substring(0, pos);
        }

        return path;
    }

    private String expandPath(String dirName) {
        if (project != null) {
            dirName = PathMacroManager.getInstance(project).expandPath(dirName);
        }
        if (module != null) {
            dirName = PathMacroManager.getInstance(module).expandPath(dirName);
        }
        return dirName;
    }

    @Override
    @NotNull
    protected Action[] createActions() {
        final ArrayList<Action> actions = new ArrayList<Action>();
        actions.add(this.getZipImportAction());
        actions.add(this.getCancelAction());
        actions.add(this.getOKAction());
        if (SystemInfo.isMac) {
            Collections.reverse(actions);
        }
        return actions.toArray(new Action[actions.size()]);
    }

    private class ZipImportAction extends AbstractAction {
        public ZipImportAction() {
            this.putValue("Name", "Import Zip Archive");
        }

        public void actionPerformed(ActionEvent e) {
            AndroidMultiDrawableImporter.this.openZipArchive();
        }
    }
}