Home | History | Annotate | Download | only in assetstudio
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.ide.eclipse.adt.internal.assetstudio;
     17 
     18 import com.android.ide.eclipse.adt.AdtConstants;
     19 import com.android.ide.eclipse.adt.AdtPlugin;
     20 import com.android.ide.eclipse.adt.AdtUtils;
     21 import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
     22 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
     23 import com.android.utils.Pair;
     24 
     25 import org.eclipse.core.resources.IContainer;
     26 import org.eclipse.core.resources.IFile;
     27 import org.eclipse.core.resources.IProject;
     28 import org.eclipse.core.resources.IResource;
     29 import org.eclipse.core.runtime.CoreException;
     30 import org.eclipse.core.runtime.IAdaptable;
     31 import org.eclipse.core.runtime.IPath;
     32 import org.eclipse.core.runtime.NullProgressMonitor;
     33 import org.eclipse.core.runtime.Path;
     34 import org.eclipse.jdt.core.IJavaProject;
     35 import org.eclipse.jdt.ui.JavaUI;
     36 import org.eclipse.jface.dialogs.MessageDialog;
     37 import org.eclipse.jface.viewers.ISelectionProvider;
     38 import org.eclipse.jface.viewers.IStructuredSelection;
     39 import org.eclipse.jface.viewers.TreePath;
     40 import org.eclipse.jface.viewers.TreeSelection;
     41 import org.eclipse.jface.wizard.Wizard;
     42 import org.eclipse.swt.SWT;
     43 import org.eclipse.ui.IEditorPart;
     44 import org.eclipse.ui.INewWizard;
     45 import org.eclipse.ui.IViewPart;
     46 import org.eclipse.ui.IWorkbench;
     47 import org.eclipse.ui.IWorkbenchPage;
     48 import org.eclipse.ui.IWorkbenchPartSite;
     49 import org.eclipse.ui.IWorkbenchWindow;
     50 import org.eclipse.ui.PlatformUI;
     51 import org.eclipse.ui.part.FileEditorInput;
     52 
     53 import java.awt.image.BufferedImage;
     54 import java.io.ByteArrayInputStream;
     55 import java.io.ByteArrayOutputStream;
     56 import java.io.IOException;
     57 import java.io.InputStream;
     58 import java.util.ArrayList;
     59 import java.util.Collections;
     60 import java.util.List;
     61 import java.util.Map;
     62 
     63 import javax.imageio.ImageIO;
     64 
     65 /**
     66  * Wizard for creating a new icon set
     67  */
     68 public class CreateAssetSetWizard extends Wizard implements INewWizard {
     69     private ChooseAssetTypePage mChooseAssetPage;
     70     private ConfigureAssetSetPage mConfigureAssetPage;
     71     private IProject mInitialProject;
     72     private List<IResource> mCreatedFiles;
     73     private CreateAssetSetWizardState mValues = new CreateAssetSetWizardState();
     74 
     75     /** Creates a new asset set wizard */
     76     public CreateAssetSetWizard() {
     77         setWindowTitle("Create Asset Set");
     78     }
     79 
     80     @Override
     81     public void addPages() {
     82         mValues.project = mInitialProject;
     83 
     84         mChooseAssetPage = new ChooseAssetTypePage(mValues);
     85         mConfigureAssetPage = new ConfigureAssetSetPage(mValues);
     86 
     87         addPage(mChooseAssetPage);
     88         addPage(mConfigureAssetPage);
     89     }
     90 
     91     @Override
     92     public boolean performFinish() {
     93         Map<String, Map<String, BufferedImage>> categories =
     94                 ConfigureAssetSetPage.generateImages(mValues, false, null);
     95 
     96         IProject project = mValues.project;
     97 
     98         // Write out the images into the project
     99         boolean yesToAll = false;
    100         mCreatedFiles = new ArrayList<IResource>();
    101 
    102         for (Map<String, BufferedImage> previews : categories.values()) {
    103             for (Map.Entry<String, BufferedImage> entry : previews.entrySet()) {
    104                 String relativePath = entry.getKey();
    105                 IPath dest = new Path(relativePath);
    106                 IFile file = project.getFile(dest);
    107                 if (file.exists()) {
    108                     // Warn that the file already exists and ask the user what to do
    109                     if (!yesToAll) {
    110                         MessageDialog dialog = new MessageDialog(null, "File Already Exists", null,
    111                                 String.format(
    112                                         "%1$s already exists.\nWould you like to replace it?",
    113                                         file.getProjectRelativePath().toOSString()),
    114                                 MessageDialog.QUESTION, new String[] {
    115                                         // Yes will be moved to the end because it's the default
    116                                         "Yes", "No", "Cancel", "Yes to All"
    117                                 }, 0);
    118                         int result = dialog.open();
    119                         switch (result) {
    120                             case 0:
    121                                 // Yes
    122                                 break;
    123                             case 3:
    124                                 // Yes to all
    125                                 yesToAll = true;
    126                                 break;
    127                             case 1:
    128                                 // No
    129                                 continue;
    130                             case SWT.DEFAULT:
    131                             case 2:
    132                                 // Cancel
    133                                 return false;
    134                         }
    135                     }
    136 
    137                     try {
    138                         file.delete(true, new NullProgressMonitor());
    139                     } catch (CoreException e) {
    140                         AdtPlugin.log(e, null);
    141                     }
    142                 }
    143 
    144                 AdtUtils.createWsParentDirectory(file.getParent());
    145                 BufferedImage image = entry.getValue();
    146 
    147                 ByteArrayOutputStream stream = new ByteArrayOutputStream();
    148                 try {
    149                     ImageIO.write(image, "PNG", stream); //$NON-NLS-1$
    150                     byte[] bytes = stream.toByteArray();
    151                     InputStream is = new ByteArrayInputStream(bytes);
    152                     file.create(is, true /*force*/, null /*progress*/);
    153                     mCreatedFiles.add(file);
    154                 } catch (IOException e) {
    155                     AdtPlugin.log(e, null);
    156                 } catch (CoreException e) {
    157                     AdtPlugin.log(e, null);
    158                 }
    159 
    160                 try {
    161                     file.getParent().refreshLocal(1, new NullProgressMonitor());
    162                 } catch (CoreException e) {
    163                     AdtPlugin.log(e, null);
    164                 }
    165             }
    166         }
    167 
    168         // Finally select the files themselves
    169         selectFiles(project, mCreatedFiles);
    170 
    171         return true;
    172     }
    173 
    174     private void selectFiles(IProject project, List<? extends IResource> createdFiles) {
    175         // Attempt to select the newly created files in the Package Explorer
    176         IWorkbench workbench = AdtPlugin.getDefault().getWorkbench();
    177         IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage();
    178         IViewPart viewPart = page.findView(JavaUI.ID_PACKAGES);
    179         if (viewPart != null) {
    180             IWorkbenchPartSite site = viewPart.getSite();
    181             IJavaProject javaProject = null;
    182             try {
    183                 javaProject = BaseProjectHelper.getJavaProject(project);
    184             } catch (CoreException e) {
    185                 AdtPlugin.log(e, null);
    186             }
    187             final ISelectionProvider provider = site.getSelectionProvider();
    188             if (provider != null) {
    189                 List<TreePath> pathList = new ArrayList<TreePath>();
    190                 for (IResource file : createdFiles) {
    191                     // Create a TreePath for the given file,
    192                     // which should be the JavaProject, followed by the folders down to
    193                     // the final file.
    194                     List<Object> segments = new ArrayList<Object>();
    195                     segments.add(file);
    196                     IContainer folder = file.getParent();
    197                     if (folder != null && !(folder instanceof IProject)) {
    198                         segments.add(folder);
    199                         // res folder
    200                         folder = folder.getParent();
    201                         if (folder != null && !(folder instanceof IProject)) {
    202                             segments.add(folder);
    203                         }
    204                     }
    205                     // project
    206                     segments.add(javaProject);
    207 
    208                     Collections.reverse(segments);
    209                     TreePath path = new TreePath(segments.toArray());
    210                     pathList.add(path);
    211 
    212                     // IDEA: Maybe normalize the files backwards (IFile objects aren't unique)
    213                     // by maybe using the package explorer icons instead
    214                 }
    215 
    216                 TreePath[] paths = pathList.toArray(new TreePath[pathList.size()]);
    217                 final TreeSelection selection = new TreeSelection(paths);
    218 
    219                 provider.setSelection(selection);
    220 
    221                 // Workaround: The above doesn't always work; it will frequently select
    222                 // some siblings of the real files. I've tried a number of workarounds:
    223                 // normalizing the IFile objects by looking up the canonical ones via
    224                 // their relative paths from the project; deferring execution with
    225                 // Display.asyncRun; first calling select on the parents, etc.
    226                 // However, it turns out a simple workaround works best: Calling this
    227                 // method TWICE. The first call seems to expand all the necessary parents,
    228                 // and the second call ensures that the correct children are selected!
    229                 provider.setSelection(selection);
    230 
    231                 viewPart.setFocus();
    232             }
    233         }
    234     }
    235 
    236     /** Sets the initial project to be used by the wizard */
    237     void setProject(IProject project) {
    238         mInitialProject = project;
    239         mValues.project = project;
    240     }
    241 
    242     @Override
    243     public void init(IWorkbench workbench, IStructuredSelection selection) {
    244         setHelpAvailable(false);
    245 
    246         mInitialProject = guessProject(selection);
    247         mValues.project = mInitialProject;
    248     }
    249 
    250     private IProject guessProject(IStructuredSelection selection) {
    251         if (selection == null) {
    252             return null;
    253         }
    254 
    255         for (Object element : selection.toList()) {
    256             if (element instanceof IAdaptable) {
    257                 IResource res = (IResource) ((IAdaptable) element).getAdapter(IResource.class);
    258                 IProject project = res != null ? res.getProject() : null;
    259 
    260                 // Is this an Android project?
    261                 try {
    262                     if (project == null || !project.hasNature(AdtConstants.NATURE_DEFAULT)) {
    263                         continue;
    264                     }
    265                 } catch (CoreException e) {
    266                     // checking the nature failed, ignore this resource
    267                     continue;
    268                 }
    269 
    270                 return project;
    271             } else if (element instanceof Pair<?, ?>) {
    272                 // Pair of Project/String
    273                 @SuppressWarnings("unchecked")
    274                 Pair<IProject, String> pair = (Pair<IProject, String>) element;
    275                 return pair.getFirst();
    276             }
    277         }
    278 
    279         // Try to figure out the project from the active editor
    280         IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
    281         if (window != null) {
    282             IWorkbenchPage page = window.getActivePage();
    283             if (page != null) {
    284                 IEditorPart activeEditor = page.getActiveEditor();
    285                 if (activeEditor instanceof AndroidXmlEditor) {
    286                     Object input = ((AndroidXmlEditor) activeEditor).getEditorInput();
    287                     if (input instanceof FileEditorInput) {
    288                         FileEditorInput fileInput = (FileEditorInput) input;
    289                         return fileInput.getFile().getProject();
    290                     }
    291                 }
    292             }
    293         }
    294 
    295         IJavaProject[] projects = AdtUtils.getOpenAndroidProjects();
    296         if (projects != null && projects.length == 1) {
    297             return projects[0].getProject();
    298         }
    299 
    300         return null;
    301     }
    302 
    303     /**
    304      * Returns the list of files created by the wizard. This method will return
    305      * null if {@link #performFinish()} has not yet been called.
    306      *
    307      * @return a list of files created by the wizard, or null
    308      */
    309     List<IResource> getCreatedFiles() {
    310         return mCreatedFiles;
    311     }
    312 }
    313