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