1 /* 2 * Copyright (C) 2012 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.wizards.templates; 17 18 import static org.eclipse.core.resources.IResource.DEPTH_INFINITE; 19 20 import com.android.annotations.NonNull; 21 import com.android.ide.eclipse.adt.AdtPlugin; 22 import com.android.ide.eclipse.adt.internal.assetstudio.ConfigureAssetSetPage; 23 import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState; 24 import com.android.ide.eclipse.adt.internal.editors.IconFactory; 25 import com.google.common.collect.Lists; 26 27 import org.eclipse.core.resources.IProject; 28 import org.eclipse.core.runtime.CoreException; 29 import org.eclipse.core.runtime.IProgressMonitor; 30 import org.eclipse.core.runtime.NullProgressMonitor; 31 import org.eclipse.jface.operation.IRunnableWithProgress; 32 import org.eclipse.jface.resource.ImageDescriptor; 33 import org.eclipse.jface.viewers.IStructuredSelection; 34 import org.eclipse.jface.wizard.IWizardPage; 35 import org.eclipse.jface.wizard.Wizard; 36 import org.eclipse.jface.wizard.WizardPage; 37 import org.eclipse.ltk.core.refactoring.Change; 38 import org.eclipse.ltk.core.refactoring.CompositeChange; 39 import org.eclipse.swt.widgets.Display; 40 import org.eclipse.ui.INewWizard; 41 import org.eclipse.ui.IWorkbench; 42 import org.eclipse.ui.actions.WorkspaceModifyOperation; 43 44 import java.lang.reflect.InvocationTargetException; 45 import java.util.List; 46 import java.util.concurrent.atomic.AtomicBoolean; 47 48 import javax.swing.SwingUtilities; 49 50 abstract class TemplateWizard extends Wizard implements INewWizard { 51 private static final String PROJECT_LOGO_LARGE = "android-64"; //$NON-NLS-1$ 52 protected IWorkbench mWorkbench; 53 private UpdateToolsPage mUpdatePage; 54 private InstallDependencyPage mDependencyPage; 55 private TemplatePreviewPage mPreviewPage; 56 protected ConfigureAssetSetPage mIconPage; 57 TemplateWizard()58 protected TemplateWizard() { 59 } 60 61 /** Should this wizard add an icon page? */ shouldAddIconPage()62 protected boolean shouldAddIconPage() { 63 return false; 64 } 65 66 @Override init(IWorkbench workbench, IStructuredSelection selection)67 public void init(IWorkbench workbench, IStructuredSelection selection) { 68 mWorkbench = workbench; 69 70 setHelpAvailable(false); 71 ImageDescriptor desc = IconFactory.getInstance().getImageDescriptor(PROJECT_LOGO_LARGE); 72 setDefaultPageImageDescriptor(desc); 73 74 if (!UpdateToolsPage.isUpToDate()) { 75 mUpdatePage = new UpdateToolsPage(); 76 } 77 78 setNeedsProgressMonitor(true); 79 80 // Trigger a check to see if the SDK needs to be reloaded (which will 81 // invoke onSdkLoaded asynchronously as needed). 82 AdtPlugin.getDefault().refreshSdk(); 83 } 84 85 @Override addPages()86 public void addPages() { 87 super.addPages(); 88 if (mUpdatePage != null) { 89 addPage(mUpdatePage); 90 } 91 } 92 93 @Override getStartingPage()94 public IWizardPage getStartingPage() { 95 if (mUpdatePage != null && mUpdatePage.isPageComplete()) { 96 return getNextPage(mUpdatePage); 97 } 98 99 return super.getStartingPage(); 100 } 101 getPreviewPage(NewTemplateWizardState values)102 protected WizardPage getPreviewPage(NewTemplateWizardState values) { 103 if (mPreviewPage == null) { 104 mPreviewPage = new TemplatePreviewPage(values); 105 addPage(mPreviewPage); 106 } 107 108 return mPreviewPage; 109 } 110 getIconPage(CreateAssetSetWizardState iconState)111 protected WizardPage getIconPage(CreateAssetSetWizardState iconState) { 112 if (mIconPage == null) { 113 mIconPage = new ConfigureAssetSetPage(iconState); 114 mIconPage.setTitle("Configure Icon"); 115 addPage(mIconPage); 116 } 117 118 return mIconPage; 119 } 120 getDependencyPage(TemplateMetadata template, boolean create)121 protected WizardPage getDependencyPage(TemplateMetadata template, boolean create) { 122 if (!create) { 123 return mDependencyPage; 124 } 125 126 if (mDependencyPage == null) { 127 mDependencyPage = new InstallDependencyPage(); 128 addPage(mDependencyPage); 129 } 130 mDependencyPage.setTemplate(template); 131 return mDependencyPage; 132 } 133 134 /** 135 * Returns the project where the template is being inserted 136 * 137 * @return the project to insert the template into 138 */ 139 @NonNull getProject()140 protected abstract IProject getProject(); 141 142 /** 143 * Returns the list of files to open, which might be empty. This method will 144 * only be called <b>after</b> {@link #computeChanges()} has been called. 145 * 146 * @return a list of files to open 147 */ 148 @NonNull getFilesToOpen()149 protected abstract List<String> getFilesToOpen(); 150 151 /** 152 * Returns the list of files to open, which might be empty. This method will 153 * only be called <b>after</b> {@link #computeChanges()} has been called. 154 * 155 * @return a list of files to open 156 */ 157 @NonNull getFinalizingActions()158 protected abstract List<Runnable> getFinalizingActions(); 159 160 /** 161 * Computes the changes to the {@link #getProject()} this template should 162 * perform 163 * 164 * @return the changes to perform 165 */ computeChanges()166 protected abstract List<Change> computeChanges(); 167 performFinish(IProgressMonitor monitor)168 protected boolean performFinish(IProgressMonitor monitor) throws InvocationTargetException { 169 List<Change> changes = computeChanges(); 170 if (!changes.isEmpty()) { 171 monitor.beginTask("Creating template...", changes.size()); 172 try { 173 CompositeChange composite = new CompositeChange("", 174 changes.toArray(new Change[changes.size()])); 175 composite.perform(monitor); 176 } catch (CoreException e) { 177 AdtPlugin.log(e, null); 178 throw new InvocationTargetException(e); 179 } finally { 180 monitor.done(); 181 } 182 } 183 184 // TBD: Is this necessary now that we're using IFile objects? 185 try { 186 getProject().refreshLocal(DEPTH_INFINITE, new NullProgressMonitor()); 187 } catch (CoreException e) { 188 AdtPlugin.log(e, null); 189 } 190 return true; 191 } 192 193 @Override performFinish()194 public boolean performFinish() { 195 final AtomicBoolean success = new AtomicBoolean(); 196 try { 197 getContainer().run(true, false, new IRunnableWithProgress() { 198 @Override 199 public void run(IProgressMonitor monitor) throws InvocationTargetException, 200 InterruptedException { 201 boolean ok = performFinish(monitor); 202 success.set(ok); 203 } 204 }); 205 206 } catch (InvocationTargetException e) { 207 AdtPlugin.log(e, null); 208 return false; 209 } catch (InterruptedException e) { 210 AdtPlugin.log(e, null); 211 return false; 212 } 213 214 if (success.get()) { 215 // Open the primary file/files 216 NewTemplateWizard.openFiles(getProject(), getFilesToOpen(), mWorkbench); 217 return true; 218 } else { 219 return false; 220 } 221 } 222 } 223