aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-06-18 10:31:49 -0700
committerandroid code review <noreply-gerritcodereview@google.com>2012-06-18 10:31:49 -0700
commitd6215b7fcc4e732e7cfd297c8260a1bead9a6bc7 (patch)
treecb501d970ace59729ac0b96d21e2c670fcb1b71f
parenta3c24ed7a9205f9bbe28128247469009a62da161 (diff)
parent802de810020fba3f86282cd1d66597a2a41698e3 (diff)
downloadsdk-d6215b7fcc4e732e7cfd297c8260a1bead9a6bc7.zip
sdk-d6215b7fcc4e732e7cfd297c8260a1bead9a6bc7.tar.gz
sdk-d6215b7fcc4e732e7cfd297c8260a1bead9a6bc7.tar.bz2
Merge "Preview support in the templates"
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java20
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java52
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureAssetSetPage.java13
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/CreateAssetSetWizardState.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java10
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/CreateFileChange.java107
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java103
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java186
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java97
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java24
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java248
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplatePreviewPage.java46
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateWizard.java187
16 files changed, 756 insertions, 349 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
index dc443db..eb5edb2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
@@ -52,7 +52,8 @@ Require-Bundle: com.android.ide.eclipse.base,
org.eclipse.jdt.junit.runtime,
org.eclipse.ltk.core.refactoring,
org.eclipse.ltk.ui.refactoring,
- org.eclipse.core.expressions
+ org.eclipse.core.expressions,
+ org.eclipse.compare
Eclipse-LazyStart: true
Export-Package: com.android.ide.common.layout;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.common.log;x-friends:="com.android.ide.eclipse.tests",
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java
index 9c1040e..1aa4221 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java
@@ -127,6 +127,8 @@ public class AdtConstants {
public static final String DOT_SVG = ".svg"; //$NON-NLS-1$
/** Dot-Extension for template files */
public static final String DOT_FTL = ".ftl"; //$NON-NLS-1$
+ /** Dot-Extension of text files, i.e. ".txt" */
+ public final static String DOT_TXT = ".txt"; //$NON-NLS-1$
/** Name of the android sources directory */
public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
index 42423b1..af8cb38 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
@@ -22,6 +22,8 @@ import static com.android.sdklib.SdkConstants.PLATFORM_LINUX;
import static com.android.sdklib.SdkConstants.PLATFORM_WINDOWS;
import com.android.AndroidConstants;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.common.log.ILogger;
import com.android.ide.common.resources.ResourceFile;
import com.android.ide.common.sdk.LoadStatus;
@@ -49,6 +51,7 @@ import com.android.resources.ResourceFolderType;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants;
+import com.google.common.io.Closeables;
import org.eclipse.core.commands.Command;
import org.eclipse.core.resources.IFile;
@@ -429,12 +432,16 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger, ISdkLog {
* @param file the file to be read
* @return the String read from the file, or null if there was an error
*/
- public static String readFile(IFile file) {
+ @SuppressWarnings("resource") // Eclipse doesn't understand Closeables.closeQuietly yet
+ @Nullable
+ public static String readFile(@NonNull IFile file) {
InputStream contents = null;
+ InputStreamReader reader = null;
try {
contents = file.getContents();
String charset = file.getCharset();
- return readFile(new InputStreamReader(contents, charset));
+ reader = new InputStreamReader(contents, charset);
+ return readFile(reader);
} catch (CoreException e) {
// pass -- ignore files we can't read
} catch (IOException e) {
@@ -447,13 +454,8 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger, ISdkLog {
// which is handled by this IOException catch.
} finally {
- try {
- if (contents != null) {
- contents.close();
- }
- } catch (IOException e) {
- // ignore
- }
+ Closeables.closeQuietly(reader);
+ Closeables.closeQuietly(contents);
}
return null;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
index 18d488d..37b569d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
@@ -31,9 +31,13 @@ import com.android.sdklib.IAndroidTarget;
import com.android.util.XmlUtils;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.Closeables;
import org.eclipse.core.filesystem.URIUtil;
+import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
@@ -67,6 +71,7 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.io.File;
+import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
@@ -986,4 +991,51 @@ public class AdtUtils {
return combined;
}
+
+ /**
+ * Reads the contents of an {@link IFile} and return it as a byte array
+ *
+ * @param file the file to be read
+ * @return the String read from the file, or null if there was an error
+ */
+ @SuppressWarnings("resource") // Eclipse doesn't understand Closeables.closeQuietly yet
+ @Nullable
+ public static byte[] readData(@NonNull IFile file) {
+ InputStream contents = null;
+ try {
+ contents = file.getContents();
+ return ByteStreams.toByteArray(contents);
+ } catch (Exception e) {
+ // Pass -- just return null
+ } finally {
+ Closeables.closeQuietly(contents);
+ }
+
+ return null;
+ }
+
+ /**
+ * Ensure that a given folder (and all its parents) are created
+ *
+ * @param container the container to ensure exists
+ * @throws CoreException if an error occurs
+ */
+ public static void ensureExists(@Nullable IContainer container) throws CoreException {
+ if (container == null || container.exists()) {
+ return;
+ }
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IFolder folder = root.getFolder(container.getFullPath());
+ ensureExists(folder);
+ }
+
+ private static void ensureExists(IFolder folder) throws CoreException {
+ if (folder != null && !folder.exists()) {
+ IContainer parent = folder.getParent();
+ if (parent instanceof IFolder) {
+ ensureExists((IFolder) parent);
+ }
+ folder.create(false, false, null);
+ }
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureAssetSetPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureAssetSetPage.java
index 187120c..0c9e5b7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureAssetSetPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/ConfigureAssetSetPage.java
@@ -700,9 +700,11 @@ public class ConfigureAssetSetPage extends WizardPage implements SelectionListen
if (source == mCropRadio) {
mCropRadio.setSelection(true); // Ensure that you can't toggle it off
mCenterRadio.setSelection(false);
+ mValues.crop = true;
} else if (source == mCenterRadio) {
mCenterRadio.setSelection(true);
mCropRadio.setSelection(false);
+ mValues.crop = false;
}
if (source == mSquareRadio) {
mValues.shape = GraphicGenerator.Shape.SQUARE;
@@ -1117,15 +1119,8 @@ public class ConfigureAssetSetPage extends WizardPage implements SelectionListen
generator = new LauncherIconGenerator();
LauncherIconGenerator.LauncherOptions launcherOptions =
new LauncherIconGenerator.LauncherOptions();
- if (mCircleButton.getSelection()) {
- launcherOptions.shape = GraphicGenerator.Shape.CIRCLE;
- } else if (mSquareRadio.getSelection()) {
- launcherOptions.shape = GraphicGenerator.Shape.SQUARE;
- } else {
- assert mNoShapeRadio.getSelection();
- launcherOptions.shape = GraphicGenerator.Shape.NONE;
- }
- launcherOptions.crop = mCropRadio.getSelection();
+ launcherOptions.shape = mValues.shape;
+ launcherOptions.crop = mValues.crop;
if (SUPPORT_LAUNCHER_ICON_TYPES) {
launcherOptions.style = mFancyRadio.getSelection() ?
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/CreateAssetSetWizardState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/CreateAssetSetWizardState.java
index 624a99a..62176ca 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/CreateAssetSetWizardState.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/assetstudio/CreateAssetSetWizardState.java
@@ -69,6 +69,9 @@ public class CreateAssetSetWizardState {
/** The background shape */
public Shape shape = Shape.SQUARE;
+ /** Whether the image should be cropped */
+ public boolean crop;
+
/** The background color to use for the shape (unless the shape is {@link Shape#NONE} */
public RGB background = new RGB(0xff, 0x00, 0x00);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java
index ad34309..83ea758 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java
@@ -641,7 +641,7 @@ public class NewProjectCreator {
}
public interface ProjectPopulator {
- public void populate(IProject project);
+ public void populate(IProject project) throws InvocationTargetException;
}
/**
@@ -693,7 +693,11 @@ public class NewProjectCreator {
}
if (projectPopulator != null) {
- projectPopulator.populate(project);
+ try {
+ projectPopulator.populate(project);
+ } catch (InvocationTargetException ite) {
+ AdtPlugin.log(ite, null);
+ }
}
// Setup class path: mark folders as source folders
@@ -768,7 +772,7 @@ public class NewProjectCreator {
// Necessary for existing projects and good for new ones to.
ProjectHelper.fixProject(project);
- Boolean isLibraryProject = parameters.containsKey(PARAM_IS_LIBRARY);
+ Boolean isLibraryProject = (Boolean) parameters.get(PARAM_IS_LIBRARY);
if (isLibraryProject != null && isLibraryProject.booleanValue()
&& Sdk.getCurrent() != null && project.isOpen()) {
ProjectState state = Sdk.getProjectState(project);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/CreateFileChange.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/CreateFileChange.java
new file mode 100644
index 0000000..3b41c36
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/CreateFileChange.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.wizards.templates;
+
+import com.android.annotations.NonNull;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.AdtUtils;
+import com.google.common.io.Closeables;
+import com.google.common.io.Files;
+import com.google.common.io.InputSupplier;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.resource.ResourceChange;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URI;
+
+/** Change which lazily copies a file */
+public class CreateFileChange extends ResourceChange {
+ private String mName;
+ private final IPath mPath;
+ private final File mSource;
+
+ CreateFileChange(@NonNull String name, @NonNull IPath workspacePath, File source) {
+ mName = name;
+ mPath = workspacePath;
+ mSource = source;
+ }
+
+ @Override
+ protected IResource getModifiedResource() {
+ return ResourcesPlugin.getWorkspace().getRoot().getFile(mPath);
+ }
+
+ @Override
+ public String getName() {
+ return mName;
+ }
+
+ @Override
+ public RefactoringStatus isValid(IProgressMonitor pm)
+ throws CoreException, OperationCanceledException {
+ RefactoringStatus result = new RefactoringStatus();
+ IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(mPath);
+ URI location = file.getLocationURI();
+ if (location == null) {
+ result.addFatalError("Unknown location " + file.getFullPath().toString());
+ return result;
+ }
+ return result;
+ }
+
+ @SuppressWarnings("resource") // Eclipse doesn't know about Guava's Closeables.closeQuietly
+ @Override
+ public Change perform(IProgressMonitor pm) throws CoreException {
+ InputSupplier<FileInputStream> supplier = Files.newInputStreamSupplier(mSource);
+ InputStream is = null;
+ try {
+ pm.beginTask("Creating file", 3);
+ IFile file = (IFile) getModifiedResource();
+
+ IContainer parent = file.getParent();
+ if (parent != null && !parent.exists()) {
+ IFolder folder = ResourcesPlugin.getWorkspace().getRoot().getFolder(
+ parent.getFullPath());
+ AdtUtils.ensureExists(folder);
+ }
+
+ is = supplier.getInput();
+ file.create(is, false, new SubProgressMonitor(pm, 1));
+ pm.worked(1);
+ } catch (Exception ioe) {
+ AdtPlugin.log(ioe, null);
+ } finally {
+ Closeables.closeQuietly(is);
+ pm.done();
+ }
+ return null;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java
index 52d7cec..92e9333 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java
@@ -19,27 +19,17 @@ import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectW
import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_API_LEVEL;
import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_PACKAGE_NAME;
import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_TARGET_API;
-import static org.eclipse.core.resources.IResource.DEPTH_INFINITE;
-import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.annotations.NonNull;
import com.android.ide.eclipse.adt.AdtUtils;
-import com.android.ide.eclipse.adt.internal.editors.IconFactory;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.INewWizard;
+import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ui.IWorkbench;
-import java.io.File;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
@@ -49,15 +39,10 @@ import java.util.Set;
* second page, but beyond that it runs the normal template wizard when it comes
* time to create the template.
*/
-public class NewActivityWizard extends Wizard implements INewWizard {
- private static final String PROJECT_LOGO_LARGE = "android-64"; //$NON-NLS-1$
-
- private IWorkbench mWorkbench;
- private UpdateToolsPage mUpdatePage;
+public class NewActivityWizard extends TemplateWizard {
private NewTemplatePage mTemplatePage;
private ActivityPage mActivityPage;
private NewProjectWizardState mValues;
- protected InstallDependencyPage mDependencyPage;
private NewTemplateWizardState mActivityValues;
/** Creates a new {@link NewActivityWizard} */
@@ -66,16 +51,9 @@ public class NewActivityWizard extends Wizard implements INewWizard {
@Override
public void init(IWorkbench workbench, IStructuredSelection selection) {
- mWorkbench = workbench;
+ super.init(workbench, selection);
setWindowTitle("New Activity");
- setHelpAvailable(false);
- ImageDescriptor desc = IconFactory.getInstance().getImageDescriptor(PROJECT_LOGO_LARGE);
- setDefaultPageImageDescriptor(desc);
-
- if (!UpdateToolsPage.isUpToDate()) {
- mUpdatePage = new UpdateToolsPage();
- }
mValues = new NewProjectWizardState();
mActivityPage = new ActivityPage(mValues);
@@ -89,22 +67,11 @@ public class NewActivityWizard extends Wizard implements INewWizard {
@Override
public void addPages() {
- if (mUpdatePage != null) {
- addPage(mUpdatePage);
- }
-
+ super.addPages();
addPage(mActivityPage);
}
@Override
- public IWizardPage getStartingPage() {
- if (mUpdatePage != null && mUpdatePage.isPageComplete()) {
- return mActivityPage;
- }
- return super.getStartingPage();
- }
-
- @Override
public IWizardPage getNextPage(IWizardPage page) {
if (page == mActivityPage) {
if (mTemplatePage == null) {
@@ -122,16 +89,16 @@ public class NewActivityWizard extends Wizard implements INewWizard {
TemplateMetadata template = mActivityValues.getTemplateHandler().getTemplate();
if (template != null) {
if (InstallDependencyPage.isInstalled(template.getDependencies())) {
- return null;
+ return getPreviewPage(mActivityValues);
} else {
- if (mDependencyPage == null) {
- mDependencyPage = new InstallDependencyPage();
- addPage(mDependencyPage);
- }
- mDependencyPage.setTemplate(template);
- return mDependencyPage;
+ return getDependencyPage(template, true);
}
}
+ } else {
+ TemplateMetadata template = mActivityValues.getTemplateHandler().getTemplate();
+ if (template != null && page == getDependencyPage(template, false)) {
+ return getPreviewPage(mActivityValues);
+ }
}
return super.getNextPage(page);
@@ -149,40 +116,20 @@ public class NewActivityWizard extends Wizard implements INewWizard {
}
@Override
- public boolean performFinish() {
- try {
- Shell shell = getShell();
- if (shell != null) {
- shell.setVisible(false);
- }
- IProject project = mActivityValues.project;
- File outputPath = AdtUtils.getAbsolutePath(project).toFile();
- assert mValues.createActivity;
- NewTemplateWizardState activityValues = mValues.activityValues;
- Map<String, Object> parameters = activityValues.parameters;
- ManifestInfo manifest = ManifestInfo.get(project);
- parameters.put(ATTR_PACKAGE_NAME, manifest.getPackage());
- parameters.put(ATTR_MIN_API, manifest.getMinSdkVersion());
- parameters.put(ATTR_MIN_API_LEVEL, manifest.getMinSdkName());
- parameters.put(ATTR_TARGET_API, manifest.getTargetSdkVersion());
- TemplateHandler activityTemplate = activityValues.getTemplateHandler();
- activityTemplate.setBackupMergedFiles(false);
- activityTemplate.render(outputPath, parameters);
- List<String> filesToOpen = activityTemplate.getFilesToOpen();
-
- try {
- project.refreshLocal(DEPTH_INFINITE, new NullProgressMonitor());
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
+ @NonNull
+ protected IProject getProject() {
+ return mActivityValues.project;
+ }
- // Open the primary file/files
- NewTemplateWizard.openFiles(project, filesToOpen, mWorkbench);
+ @Override
+ @NonNull
+ protected List<String> getFilesToOpen() {
+ TemplateHandler activityTemplate = mActivityValues.getTemplateHandler();
+ return activityTemplate.getFilesToOpen();
+ }
- return true;
- } catch (Exception ioe) {
- AdtPlugin.log(ioe, null);
- return false;
- }
+ @Override
+ protected List<Change> computeChanges() {
+ return mActivityValues.computeChanges();
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java
index 312fbcf..563fcbf 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java
@@ -17,13 +17,12 @@ package com.android.ide.eclipse.adt.internal.wizards.templates;
import static org.eclipse.core.resources.IResource.DEPTH_INFINITE;
+import com.android.annotations.NonNull;
import com.android.assetstudiolib.GraphicGenerator;
import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AdtUtils;
import com.android.ide.eclipse.adt.internal.assetstudio.AssetType;
import com.android.ide.eclipse.adt.internal.assetstudio.ConfigureAssetSetPage;
import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState;
-import com.android.ide.eclipse.adt.internal.editors.IconFactory;
import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreator;
import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreator.ProjectPopulator;
import com.android.ide.eclipse.adt.internal.wizards.newxmlfile.NewXmlFileWizard;
@@ -38,13 +37,11 @@ import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
-import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
-import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.swt.graphics.RGB;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import java.awt.image.BufferedImage;
@@ -53,6 +50,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -63,63 +61,41 @@ import javax.imageio.ImageIO;
/**
* Wizard for creating new projects
*/
-public class NewProjectWizard extends Wizard implements INewWizard {
+public class NewProjectWizard extends TemplateWizard {
private static final String ATTR_COPY_ICONS = "copyIcons"; //$NON-NLS-1$
static final String ATTR_TARGET_API = "targetApi"; //$NON-NLS-1$
static final String ATTR_MIN_API = "minApi"; //$NON-NLS-1$
static final String ATTR_MIN_API_LEVEL = "minApiLevel"; //$NON-NLS-1$
static final String ATTR_PACKAGE_NAME = "packageName"; //$NON-NLS-1$
static final String ATTR_APP_TITLE = "appTitle"; //$NON-NLS-1$
- private static final String PROJECT_LOGO_LARGE = "android-64"; //$NON-NLS-1$
- private IWorkbench mWorkbench;
- private UpdateToolsPage mUpdatePage;
private NewProjectPage mMainPage;
private ActivityPage mActivityPage;
private NewTemplatePage mTemplatePage;
- protected InstallDependencyPage mDependencyPage;
private ConfigureAssetSetPage mIconPage;
private NewProjectWizardState mValues;
+ /** The project being created */
+ private IProject mProject;
@Override
public void init(IWorkbench workbench, IStructuredSelection selection) {
- mWorkbench = workbench;
+ super.init(workbench, selection);
setWindowTitle("New Android App");
- setHelpAvailable(false);
- setImageDescriptor();
-
- if (!UpdateToolsPage.isUpToDate()) {
- mUpdatePage = new UpdateToolsPage();
- }
mValues = new NewProjectWizardState();
mMainPage = new NewProjectPage(mValues);
mActivityPage = new ActivityPage(mValues);
}
- /**
- * Adds pages to this wizard.
- */
@Override
public void addPages() {
- if (mUpdatePage != null) {
- addPage(mUpdatePage);
- }
-
+ super.addPages();
addPage(mMainPage);
addPage(mActivityPage);
}
@Override
- public IWizardPage getStartingPage() {
- if (mUpdatePage != null && mUpdatePage.isPageComplete()) {
- return mMainPage;
- }
- return super.getStartingPage();
- }
-
- @Override
public IWizardPage getNextPage(IWizardPage page) {
if (page == mMainPage) {
if (mValues.createIcon) {
@@ -177,17 +153,12 @@ public class NewProjectWizard extends Wizard implements INewWizard {
TemplateMetadata template = mValues.activityValues.getTemplateHandler().getTemplate();
if (template != null
&& !InstallDependencyPage.isInstalled(template.getDependencies())) {
- if (mDependencyPage == null) {
- mDependencyPage = new InstallDependencyPage();
- addPage(mDependencyPage);
- }
- mDependencyPage.setTemplate(template);
- return mDependencyPage;
+ return getDependencyPage(template, true);
}
}
if (page == mTemplatePage || !mValues.createActivity && page == mActivityPage
- || page == mDependencyPage) {
+ || page == getDependencyPage(null, false)) {
return null;
}
@@ -224,15 +195,41 @@ public class NewProjectWizard extends Wizard implements INewWizard {
}
@Override
- public boolean performFinish() {
+ @NonNull
+ protected IProject getProject() {
+ return mProject;
+ }
+
+ @Override
+ @NonNull
+ protected List<String> getFilesToOpen() {
+ return mValues.template.getFilesToOpen();
+ }
+
+ @Override
+ protected List<Change> computeChanges() {
+ final TemplateHandler template = mValues.template;
+ // We'll be merging in an activity template, but don't create *~ backup files
+ // of the merged files (such as the manifest file) in that case.
+ // (NOTE: After the change from direct file manipulation to creating a list of Change
+ // objects, this no longer applies - but the code is kept around a little while longer
+ // in case we want to generate change objects that makes backups of merged files)
+ template.setBackupMergedFiles(false);
+
+ // Generate basic output skeleton
+ Map<String, Object> paramMap = new HashMap<String, Object>();
+ addProjectInfo(paramMap);
+
+ return template.render(mProject, paramMap);
+ }
+
+ @Override
+ protected boolean performFinish(final IProgressMonitor monitor)
+ throws InvocationTargetException {
try {
- Shell shell = getShell();
- if (shell != null) {
- shell.setVisible(false);
- }
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
String name = mValues.projectName;
- final IProject newProject = root.getProject(name);
+ mProject = root.getProject(name);
final TemplateHandler template = mValues.template;
// We'll be merging in an activity template, but don't create *~ backup files
@@ -241,13 +238,13 @@ public class NewProjectWizard extends Wizard implements INewWizard {
ProjectPopulator projectPopulator = new ProjectPopulator() {
@Override
- public void populate(IProject project) {
+ public void populate(IProject project) throws InvocationTargetException {
// Copy in the proguard file; templates don't provide this one.
// add the default proguard config
File libFolder = new File(AdtPlugin.getOsSdkToolsFolder(),
SdkConstants.FD_LIB);
try {
- assert project == newProject;
+ assert project == mProject;
NewProjectCreator.addLocalFile(project,
new File(libFolder, SdkConstants.FN_PROJECT_PROGUARD_FILE),
// Write ProGuard config files with the extension .pro which
@@ -258,42 +255,54 @@ public class NewProjectWizard extends Wizard implements INewWizard {
AdtPlugin.log(e, null);
}
- // Generate basic output skeleton
- Map<String, Object> paramMap = new HashMap<String, Object>();
- paramMap.put(ATTR_PACKAGE_NAME, mValues.packageName);
- paramMap.put(ATTR_APP_TITLE, mValues.applicationName);
- paramMap.put(ATTR_MIN_API, mValues.minSdk);
- paramMap.put(ATTR_MIN_API_LEVEL, mValues.minSdkLevel);
- paramMap.put(ATTR_TARGET_API, 15);
- paramMap.put(ATTR_COPY_ICONS, !mValues.createIcon);
+ try {
+ mProject.refreshLocal(DEPTH_INFINITE, new NullProgressMonitor());
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ }
- File outputPath = AdtUtils.getAbsolutePath(newProject).toFile();
- template.render(outputPath, paramMap);
+ // Render the project template
+ List<Change> changes = computeChanges();
+ if (!changes.isEmpty()) {
+ monitor.beginTask("Creating project...", changes.size());
+ try {
+ CompositeChange composite = new CompositeChange("",
+ changes.toArray(new Change[changes.size()]));
+ composite.perform(monitor);
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ throw new InvocationTargetException(e);
+ } finally {
+ monitor.done();
+ }
+ }
- if (mValues.createIcon) {
- generateIcons(newProject);
+ if (mValues.createIcon) { // TODO: Set progress
+ generateIcons(mProject);
}
+ // Render the embedded activity template template
if (mValues.createActivity) {
- generateActivity(template, paramMap, outputPath);
+ final TemplateHandler activityTemplate =
+ mValues.activityValues.getTemplateHandler();
+ // We'll be merging in an activity template, but don't create
+ // *~ backup files of the merged files (such as the manifest file)
+ // in that case.
+ activityTemplate.setBackupMergedFiles(false);
+ generateActivity(template, project, monitor);
}
}
};
- IProgressMonitor monitor = new NullProgressMonitor();
- NewProjectCreator.create(monitor, newProject, mValues.target, projectPopulator,
+ NewProjectCreator.create(monitor, mProject, mValues.target, projectPopulator,
mValues.isLibrary);
try {
- newProject.refreshLocal(DEPTH_INFINITE, new NullProgressMonitor());
+ mProject.refreshLocal(DEPTH_INFINITE, new NullProgressMonitor());
} catch (CoreException e) {
AdtPlugin.log(e, null);
}
- // Open the primary file/files
- final List<String> filesToOpen = template.getFilesToOpen();
- NewTemplateWizard.openFiles(newProject, filesToOpen, mWorkbench);
-
return true;
} catch (Exception ioe) {
AdtPlugin.log(ioe, null);
@@ -353,30 +362,41 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* activity needs but that we don't need to ask about when creating a new
* project
*/
- private void generateActivity(final TemplateHandler template,
- Map<String, Object> paramMap, File outputPath) {
+ private void generateActivity(TemplateHandler projectTemplate, IProject project,
+ IProgressMonitor monitor) throws InvocationTargetException {
assert mValues.createActivity;
NewTemplateWizardState activityValues = mValues.activityValues;
Map<String, Object> parameters = activityValues.parameters;
- parameters.put(ATTR_PACKAGE_NAME, paramMap.get(ATTR_PACKAGE_NAME));
- parameters.put(ATTR_APP_TITLE, paramMap.get(ATTR_APP_TITLE));
- parameters.put(ATTR_MIN_API, paramMap.get(ATTR_MIN_API));
- parameters.put(ATTR_MIN_API_LEVEL, paramMap.get(ATTR_MIN_API_LEVEL));
- parameters.put(ATTR_TARGET_API, paramMap.get(ATTR_TARGET_API));
+ addProjectInfo(parameters);
TemplateHandler activityTemplate = activityValues.getTemplateHandler();
activityTemplate.setBackupMergedFiles(false);
- activityTemplate.render(outputPath, parameters);
+ List<Change> changes = activityTemplate.render(project, parameters);
+ if (!changes.isEmpty()) {
+ monitor.beginTask("Creating template...", changes.size());
+ try {
+ CompositeChange composite = new CompositeChange("",
+ changes.toArray(new Change[changes.size()]));
+ composite.perform(monitor);
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ throw new InvocationTargetException(e);
+ } finally {
+ monitor.done();
+ }
+ }
+
List<String> filesToOpen = activityTemplate.getFilesToOpen();
- template.getFilesToOpen().addAll(filesToOpen);
+ projectTemplate.getFilesToOpen().addAll(filesToOpen);
}
- /**
- * Returns an image descriptor for the wizard logo.
- */
- private void setImageDescriptor() {
- ImageDescriptor desc = IconFactory.getInstance().getImageDescriptor(PROJECT_LOGO_LARGE);
- setDefaultPageImageDescriptor(desc);
+ private void addProjectInfo(Map<String, Object> parameters) {
+ parameters.put(ATTR_PACKAGE_NAME, mValues.packageName);
+ parameters.put(ATTR_APP_TITLE, mValues.applicationName);
+ parameters.put(ATTR_MIN_API, mValues.minSdk);
+ parameters.put(ATTR_MIN_API_LEVEL, mValues.minSdkLevel);
+ parameters.put(ATTR_TARGET_API, 15);
+ parameters.put(ATTR_COPY_ICONS, !mValues.createIcon);
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java
index ea9774e..6178c3e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java
@@ -496,7 +496,7 @@ public class NewTemplatePage extends WizardPage
// -- validate project
if (mChooseProject && mValues.project == null) {
- status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID,
+ status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
"Please select an Android project.");
}
@@ -507,7 +507,7 @@ public class NewTemplatePage extends WizardPage
String value = parameter.value == null ? "" : parameter.value.toString();
String error = validator.isValid(value);
if (error != null) {
- status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, error);
+ status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, error);
if (decoration != null) {
updateDecorator(decoration, status, parameter.help);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java
index 666e2f6..43e437b 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java
@@ -19,47 +19,35 @@ import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectW
import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_API_LEVEL;
import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_PACKAGE_NAME;
import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_TARGET_API;
-import static org.eclipse.core.resources.IResource.DEPTH_INFINITE;
import com.android.annotations.NonNull;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtUtils;
-import com.android.ide.eclipse.adt.internal.editors.IconFactory;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
-import org.eclipse.jface.wizard.Wizard;
-import org.eclipse.ui.INewWizard;
+import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.wizards.newresource.BasicNewResourceWizard;
import java.io.File;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
* Template wizard which creates parameterized templates
*/
-public class NewTemplateWizard extends Wizard implements INewWizard {
+public class NewTemplateWizard extends TemplateWizard {
/** Template name and location under $sdk/templates for the default activity */
static final String BLANK_ACTIVITY = "activities/BlankActivity"; //$NON-NLS-1$
/** Template name and location under $sdk/templates for the custom view template */
static final String CUSTOM_VIEW = "other/CustomView"; //$NON-NLS-1$
- private static final String PROJECT_LOGO_LARGE = "android-64"; //$NON-NLS-1$
- protected IWorkbench mWorkbench;
protected NewTemplatePage mMainPage;
- protected UpdateToolsPage mUpdatePage;
- protected InstallDependencyPage mDependencyPage;
protected NewTemplateWizardState mValues;
private final String mTemplateName;
@@ -69,20 +57,15 @@ public class NewTemplateWizard extends Wizard implements INewWizard {
@Override
public void init(IWorkbench workbench, IStructuredSelection selection) {
- mWorkbench = workbench;
-
- setHelpAvailable(false);
- setImageDescriptor();
+ super.init(workbench, selection);
mValues = new NewTemplateWizardState();
File template = TemplateHandler.getTemplateLocation(mTemplateName);
- mValues.setTemplateLocation(template);
- hideBuiltinParameters();
-
- if (!UpdateToolsPage.isUpToDate()) {
- mUpdatePage = new UpdateToolsPage();
+ if (template != null) {
+ mValues.setTemplateLocation(template);
}
+ hideBuiltinParameters();
List<IProject> projects = AdtUtils.getSelectedProjects(selection);
if (projects.size() == 1) {
@@ -107,80 +90,44 @@ public class NewTemplateWizard extends Wizard implements INewWizard {
@Override
public void addPages() {
- if (mUpdatePage != null) {
- addPage(mUpdatePage);
- }
-
+ super.addPages();
addPage(mMainPage);
}
@Override
public IWizardPage getNextPage(IWizardPage page) {
+ TemplateMetadata template = mValues.getTemplateHandler().getTemplate();
if (page == mMainPage) {
- TemplateMetadata template = mValues.getTemplateHandler().getTemplate();
if (template != null) {
if (InstallDependencyPage.isInstalled(template.getDependencies())) {
- return null;
+ return getPreviewPage(mValues);
} else {
- if (mDependencyPage == null) {
- mDependencyPage = new InstallDependencyPage();
- addPage(mDependencyPage);
- }
- mDependencyPage.setTemplate(template);
- return mDependencyPage;
+ return getDependencyPage(template, true);
}
}
+ } else if (page == getDependencyPage(template, false)) {
+ return getPreviewPage(mValues);
}
return super.getNextPage(page);
}
@Override
- public IWizardPage getStartingPage() {
- if (mUpdatePage != null && mUpdatePage.isPageComplete()) {
- return mMainPage;
- }
- return super.getStartingPage();
+ @NonNull
+ protected IProject getProject() {
+ return mValues.project;
}
@Override
- public boolean performFinish() {
- try {
- Map<String, Object> parameters = mValues.parameters;
- IProject project = mValues.project;
-
- ManifestInfo manifest = ManifestInfo.get(project);
- parameters.put(ATTR_PACKAGE_NAME, manifest.getPackage());
- parameters.put(ATTR_MIN_API, manifest.getMinSdkVersion());
- parameters.put(ATTR_MIN_API_LEVEL, manifest.getMinSdkName());
- parameters.put(ATTR_TARGET_API, manifest.getTargetSdkVersion());
-
- File outputPath = AdtUtils.getAbsolutePath(project).toFile();
- TemplateHandler handler = mValues.getTemplateHandler();
- handler.render(outputPath, parameters);
-
- try {
- project.refreshLocal(DEPTH_INFINITE, new NullProgressMonitor());
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
-
- List<String> filesToOpen = handler.getFilesToOpen();
- NewTemplateWizard.openFiles(project, filesToOpen, mWorkbench);
-
- return true;
- } catch (Exception ioe) {
- AdtPlugin.log(ioe, null);
- return false;
- }
+ @NonNull
+ protected List<String> getFilesToOpen() {
+ TemplateHandler activityTemplate = mValues.getTemplateHandler();
+ return activityTemplate.getFilesToOpen();
}
- /**
- * Returns an image descriptor for the wizard logo.
- */
- private void setImageDescriptor() {
- ImageDescriptor desc = IconFactory.getInstance().getImageDescriptor(PROJECT_LOGO_LARGE);
- setDefaultPageImageDescriptor(desc);
+ @Override
+ protected List<Change> computeChanges() {
+ return mValues.computeChanges();
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java
index aaf1a6a..2ea101a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java
@@ -16,15 +16,23 @@
package com.android.ide.eclipse.adt.internal.wizards.templates;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_API;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_API_LEVEL;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_PACKAGE_NAME;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_TARGET_API;
import static com.android.ide.eclipse.adt.internal.wizards.templates.NewTemplateWizard.BLANK_ACTIVITY;
import com.android.annotations.NonNull;
+import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
import org.eclipse.core.resources.IProject;
+import org.eclipse.ltk.core.refactoring.Change;
import java.io.File;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -89,4 +97,20 @@ public class NewTemplateWizardState {
File getTemplateLocation() {
return mTemplateLocation;
}
+
+ /** Computes the changes this wizard will make */
+ @NonNull
+ List<Change> computeChanges() {
+ if (project == null) {
+ return Collections.emptyList();
+ }
+
+ ManifestInfo manifest = ManifestInfo.get(project);
+ parameters.put(ATTR_PACKAGE_NAME, manifest.getPackage());
+ parameters.put(ATTR_MIN_API, manifest.getMinSdkVersion());
+ parameters.put(ATTR_MIN_API_LEVEL, manifest.getMinSdkName());
+ parameters.put(ATTR_TARGET_API, manifest.getTargetSdkVersion());
+
+ return getTemplateHandler().render(project, parameters);
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java
index 16b38e3..c145f2c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java
@@ -15,8 +15,14 @@
*/
package com.android.ide.eclipse.adt.internal.wizards.templates;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_AIDL;
import static com.android.ide.eclipse.adt.AdtConstants.DOT_FTL;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_JAVA;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_RS;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_SVG;
+import static com.android.ide.eclipse.adt.AdtConstants.DOT_TXT;
import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML;
+import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML;
import static com.android.ide.eclipse.adt.internal.wizards.templates.InstallDependencyPage.SUPPORT_LIBRARY_NAME;
import static com.android.sdklib.SdkConstants.FD_EXTRAS;
import static com.android.sdklib.SdkConstants.FD_NATIVE_LIBS;
@@ -25,6 +31,7 @@ import static com.android.sdklib.SdkConstants.FD_TOOLS;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtUtils;
import com.android.ide.eclipse.adt.internal.actions.AddCompatibilityJarAction;
@@ -47,11 +54,21 @@ import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.NullChange;
+import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.swt.SWT;
+import org.eclipse.text.edits.InsertEdit;
+import org.eclipse.text.edits.MultiTextEdit;
+import org.eclipse.text.edits.ReplaceEdit;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
import org.w3c.dom.Document;
@@ -159,6 +176,14 @@ class TemplateHandler {
@NonNull
private final File mRootPath;
+ /** The changes being processed by the template handler */
+ private List<Change> mMergeChanges;
+ private List<Change> mTextChanges;
+ private List<Change> mOtherChanges;
+
+ /** The project to write the template into */
+ private IProject mProject;
+
/** The template loader which is responsible for finding (and sharing) template files */
private final MyTemplateLoader mLoader;
@@ -200,10 +225,14 @@ class TemplateHandler {
mBackupMergedFiles = backupMergedFiles;
}
- public void render(final File outputPath, Map<String, Object> args) {
- if (!outputPath.exists()) {
- outputPath.mkdirs();
- }
+ @NonNull
+ public List<Change> render(IProject project, Map<String, Object> args) {
+ mOpen.clear();
+
+ mProject = project;
+ mMergeChanges = new ArrayList<Change>();
+ mTextChanges = new ArrayList<Change>();
+ mOtherChanges = new ArrayList<Change>();
// Render the instruction list template.
Map<String, Object> paramMap = createParameterMap(args);
@@ -211,7 +240,15 @@ class TemplateHandler {
freemarker.setObjectWrapper(new DefaultObjectWrapper());
freemarker.setTemplateLoader(mLoader);
- processVariables(freemarker, TEMPLATE_XML, paramMap, outputPath);
+ processVariables(freemarker, TEMPLATE_XML, paramMap);
+
+ // Add the changes in the order where merges are shown first, then text files,
+ // and finally other files (like jars and icons which don't have previews).
+ List<Change> changes = new ArrayList<Change>();
+ changes.addAll(mMergeChanges);
+ changes.addAll(mTextChanges);
+ changes.addAll(mOtherChanges);
+ return changes;
}
Map<String, Object> createParameterMap(Map<String, Object> args) {
@@ -389,7 +426,7 @@ class TemplateHandler {
/** Read the given FreeMarker file and process the variable definitions */
private void processVariables(final Configuration freemarker,
- String file, final Map<String, Object> paramMap, final File outputPath) {
+ String file, final Map<String, Object> paramMap) {
try {
String xml;
if (file.endsWith(DOT_XML)) {
@@ -430,12 +467,12 @@ class TemplateHandler {
// Handle evaluation of variables
String path = attributes.getValue(ATTR_FILE);
if (path != null) {
- processVariables(freemarker, path, paramMap, outputPath);
+ processVariables(freemarker, path, paramMap);
} // else: <globals> root element
} else if (TAG_EXECUTE.equals(name)) {
String path = attributes.getValue(ATTR_FILE);
if (path != null) {
- execute(freemarker, path, paramMap, outputPath);
+ execute(freemarker, path, paramMap);
}
} else if (TAG_DEPENDENCY.equals(name)) {
String dependencyName = attributes.getValue(ATTR_NAME);
@@ -444,8 +481,7 @@ class TemplateHandler {
// by the wizard
File path = AddCompatibilityJarAction.getCompatJarFile();
if (path != null) {
- File to = new File(outputPath, FD_NATIVE_LIBS
- + File.separator + path.getName());
+ IPath to = getTargetPath(FD_NATIVE_LIBS +'/' + path.getName());
try {
copy(path, to);
} catch (IOException ioe) {
@@ -466,7 +502,7 @@ class TemplateHandler {
}
private boolean canOverwrite(File file) {
- if (file.exists() && !file.isDirectory()) {
+ if (file.exists()) {
// Warn that the file already exists and ask the user what to do
if (!mYesToAll) {
MessageDialog dialog = new MessageDialog(null, "File Already Exists", null,
@@ -511,8 +547,7 @@ class TemplateHandler {
private void execute(
final Configuration freemarker,
String file,
- final Map<String, Object> paramMap,
- final File outputPath) {
+ final Map<String, Object> paramMap) {
try {
mLoader.setTemplateFile(new File(mRootPath, file));
Template freemarkerTemplate = freemarker.getTemplate(file);
@@ -545,11 +580,11 @@ class TemplateHandler {
toPath = attributes.getValue(ATTR_FROM);
toPath = AdtUtils.stripSuffix(toPath, DOT_FTL);
}
- File to = new File(outputPath, toPath);
+ IPath to = getTargetPath(toPath);
if (instantiate) {
instantiate(freemarker, paramMap, fromPath, to);
} else {
- copyBundledResource(fromPath, to);
+ copyTemplateResource(fromPath, to);
}
} else if (TAG_MERGE.equals(name)) {
String fromPath = attributes.getValue(ATTR_FROM);
@@ -559,7 +594,7 @@ class TemplateHandler {
toPath = AdtUtils.stripSuffix(toPath, DOT_FTL);
}
// Resources in template.xml are located within root/
- File to = new File(outputPath, toPath);
+ IPath to = getTargetPath(toPath);
merge(freemarker, paramMap, fromPath, to);
} else if (name.equals(TAG_OPEN)) {
// The relative path here is within the output directory:
@@ -591,23 +626,44 @@ class TemplateHandler {
return new File(mRootPath, DATA_ROOT + File.separator + fromPath);
}
+ @NonNull
+ private IPath getTargetPath(@NonNull String relative) {
+ if (relative.indexOf('\\') != -1) {
+ relative = relative.replace('\\', '/');
+ }
+ return new Path(relative);
+ }
+
+ @NonNull
+ private IFile getTargetFile(@NonNull IPath path) {
+ return mProject.getFile(path);
+ }
+
private void merge(
@NonNull final Configuration freemarker,
@NonNull final Map<String, Object> paramMap,
@NonNull String relativeFrom,
- @NonNull File to) throws IOException, TemplateException {
- if (!to.exists()) {
+ @NonNull IPath toPath) throws IOException, TemplateException {
+
+ String currentXml = null;
+
+ IFile to = getTargetFile(toPath);
+ if (to.exists()) {
+ currentXml = AdtPlugin.readFile(to);
+ }
+
+ if (currentXml == null) {
// The target file doesn't exist: don't merge, just copy
boolean instantiate = relativeFrom.endsWith(DOT_FTL);
if (instantiate) {
- instantiate(freemarker, paramMap, relativeFrom, to);
+ instantiate(freemarker, paramMap, relativeFrom, toPath);
} else {
- copyBundledResource(relativeFrom, to);
+ copyTemplateResource(relativeFrom, toPath);
}
return;
}
- if (!to.getPath().endsWith(DOT_XML)) {
+ if (!to.getFileExtension().equals(EXT_XML)) {
throw new RuntimeException("Only XML files can be merged at this point: " + to);
}
@@ -628,21 +684,21 @@ class TemplateHandler {
}
}
- String currentXml = Files.toString(to, Charsets.UTF_8);
Document currentManifest = DomUtilities.parseStructuredDocument(currentXml);
Document fragment = DomUtilities.parseStructuredDocument(xml);
XmlFormatStyle formatStyle = XmlFormatStyle.MANIFEST;
boolean modified;
boolean ok;
- if (to.getName().equals(SdkConstants.FN_ANDROID_MANIFEST_XML)) {
+ String fileName = to.getName();
+ if (fileName.equals(SdkConstants.FN_ANDROID_MANIFEST_XML)) {
modified = ok = mergeManifest(currentManifest, fragment);
} else {
// Merge plain XML files
- ResourceFolderType folderType =
- ResourceFolderType.getFolderType(to.getParentFile().getName());
+ String parentFolderName = to.getParent().getName();
+ ResourceFolderType folderType = ResourceFolderType.getFolderType(parentFolderName);
if (folderType != null) {
- formatStyle = XmlFormatStyle.getForFolderType(folderType);
+ formatStyle = XmlFormatStyle.getForFile(toPath);
} else {
formatStyle = XmlFormatStyle.FILE;
}
@@ -652,58 +708,34 @@ class TemplateHandler {
}
// Finally write out the merged file (formatting etc)
+ String contents = null;
if (ok) {
if (modified) {
XmlPrettyPrinter printer = new XmlPrettyPrinter(
XmlFormatPreferences.create(), formatStyle, null);
StringBuilder sb = new StringBuilder(2 );
printer.prettyPrint(-1, currentManifest, null, null, sb, false /*openTagOnly*/);
- String contents = sb.toString();
- writeString(to, contents, false);
+ contents = sb.toString();
}
} else {
// Just insert into file along with comment, using the "standard" conflict
// syntax that many tools and editors recognize.
String sep = AdtUtils.getLineSeparator();
- String contents =
+ contents =
"<<<<<<< Original" + sep
+ currentXml + sep
+ "=======" + sep
+ xml
+ ">>>>>>> Added" + sep;
- writeString(to, contents, false);
}
- }
- /**
- * Writes the given contents into the given file (unless that file already
- * contains the given contents), and if the file exists ask user whether
- * the file should be overwritten (unless the user has already answered "Yes to All"
- * or "Cancel" (no to all).
- */
- private void writeString(File destination, String contents, boolean confirmOverwrite)
- throws IOException {
- // First make sure that the files aren't identical, in which case we can do
- // nothing (and not involve user)
- if (!(destination.exists()
- && isIdentical(contents.getBytes(Charsets.UTF_8), destination))) {
- // And if the file does exist (and is now known to be different),
- // ask user whether it should be replaced (canOverwrite will also
- // return true if the file doesn't exist)
- if (confirmOverwrite) {
- if (!canOverwrite(destination)) {
- return;
- }
- } else {
- if (destination.exists()) {
- if (mBackupMergedFiles) {
- makeBackup(destination);
- } else {
- destination.delete();
- }
- }
- }
- Files.write(contents, destination, Charsets.UTF_8);
+ if (contents != null) {
+ TextFileChange change = new TextFileChange("Merge " + fileName, to);
+ MultiTextEdit rootEdit = new MultiTextEdit();
+ rootEdit.addChild(new ReplaceEdit(0, currentXml.length(), contents));
+ change.setEdit(rootEdit);
+ change.setTextType(AdtConstants.EXT_XML);
+ mMergeChanges.add(change);
}
}
@@ -830,18 +862,13 @@ class TemplateHandler {
@NonNull final Configuration freemarker,
@NonNull final Map<String, Object> paramMap,
@NonNull String relativeFrom,
- @NonNull File to) throws IOException, TemplateException {
- File parentFile = to.getParentFile();
- if (!parentFile.exists()) {
- parentFile.mkdirs();
- }
-
+ @NonNull IPath to) throws IOException, TemplateException {
// For now, treat extension-less files as directories... this isn't quite right
// so I should refine this! Maybe with a unique attribute in the template file?
boolean isDirectory = relativeFrom.indexOf('.') == -1;
if (isDirectory) {
// It's a directory
- copyBundledResource(relativeFrom, to);
+ copyTemplateResource(relativeFrom, to);
} else {
File from = getFullPath(relativeFrom);
mLoader.setTemplateFile(from);
@@ -852,13 +879,32 @@ class TemplateHandler {
String contents = out.toString();
if (relativeFrom.endsWith(DOT_XML)) {
- XmlFormatStyle formatStyle = XmlFormatStyle.getForFile(new Path(to.getPath()));
+ XmlFormatStyle formatStyle = XmlFormatStyle.getForFile(to);
XmlFormatPreferences prefs = XmlFormatPreferences.create();
contents = XmlPrettyPrinter.prettyPrint(contents, prefs, formatStyle, null);
}
- writeString(to, contents, true);
+ IFile targetFile = getTargetFile(to);
+ TextFileChange change = createTextChange(targetFile);
+ MultiTextEdit rootEdit = new MultiTextEdit();
+ rootEdit.addChild(new InsertEdit(0, contents));
+ change.setEdit(rootEdit);
+ mTextChanges.add(change);
+ }
+ }
+
+ private static TextFileChange createTextChange(IFile targetFile) {
+ String fileName = targetFile.getName();
+ String message;
+ if (targetFile.exists()) {
+ message = String.format("Replace %1$s", fileName);
+ } else {
+ message = String.format("Create %1$s", fileName);
}
+
+ TextFileChange change = new TextFileChange(message, targetFile);
+ change.setTextType(fileName.substring(fileName.lastIndexOf('.') + 1));
+ return change;
}
/**
@@ -871,19 +917,18 @@ class TemplateHandler {
return mOpen;
}
- /** Copy a bundled resource (part of the plugin .jar file) into the given file system path */
- private final void copyBundledResource(
+ /** Copy a template resource */
+ private final void copyTemplateResource(
@NonNull String relativeFrom,
- @NonNull File output) throws IOException {
+ @NonNull IPath output) throws IOException {
File from = getFullPath(relativeFrom);
copy(from, output);
}
/** Returns true if the given file contains the given bytes */
- private static boolean isIdentical(@Nullable byte[] data, @NonNull File dest)
- throws IOException {
- assert dest.isFile();
- byte[] existing = Files.toByteArray(dest);
+ private static boolean isIdentical(@Nullable byte[] data, @NonNull IFile dest) {
+ assert dest.exists();
+ byte[] existing = AdtUtils.readData(dest);
return Arrays.equals(existing, data);
}
@@ -892,30 +937,55 @@ class TemplateHandler {
* source is allowed to be a directory, in which case the whole directory is
* copied recursively)
*/
- private void copy(File src, File dest) throws IOException {
- if (src.isDirectory()){
- if (!dest.exists() && !dest.mkdirs()) {
- throw new IOException("Could not create directory " + dest);
- }
+ private void copy(File src, IPath path) throws IOException {
+ if (src.isDirectory()) {
File[] children = src.listFiles();
if (children != null) {
for (File child : children) {
- copy(child, new File(dest, child.getName()));
+ copy(child, path.append(child.getName()));
}
}
} else {
- if (dest.exists() && isIdentical(Files.toByteArray(src), dest)) {
+ IResource dest = mProject.getFile(path);
+ if (dest.exists() && !(dest instanceof IFile)) {// Don't attempt to overwrite a folder
+ assert false : dest.getClass().getName();
return;
}
- if (!canOverwrite(dest)) {
- return;
+ IFile file = (IFile) dest;
+ String targetName = path.lastSegment();
+ if (dest instanceof IFile) {
+ if (dest.exists() && isIdentical(Files.toByteArray(src), file)) {
+ String label = String.format(
+ "Not overwriting %1$s because the files are identical", targetName);
+ NullChange change = new NullChange(label);
+ change.setEnabled(false);
+ mOtherChanges.add(change);
+ return;
+ }
}
- File parent = dest.getParentFile();
- if (parent != null && !parent.exists()) {
- parent.mkdirs();
+ if (targetName.endsWith(DOT_XML)
+ || targetName.endsWith(DOT_JAVA)
+ || targetName.endsWith(DOT_TXT)
+ || targetName.endsWith(DOT_RS)
+ || targetName.endsWith(DOT_AIDL)
+ || targetName.endsWith(DOT_SVG)) {
+
+ String newFile = Files.toString(src, Charsets.UTF_8);
+ if (targetName.endsWith(DOT_XML)) {
+ newFile = XmlPrettyPrinter.prettyPrint(newFile,
+ XmlFormatPreferences.create(), XmlFormatStyle.getForFile(path),
+ null /*lineSeparator*/);
+ }
+
+ TextFileChange addFile = createTextChange(file);
+ addFile.setEdit(new InsertEdit(0, newFile));
+ mTextChanges.add(addFile);
+ } else {
+ // Write binary file: Need custom change for that
+ IPath workspacePath = mProject.getFullPath().append(path);
+ mOtherChanges.add(new CreateFileChange(targetName, workspacePath, src));
}
- Files.copy(src, dest);
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplatePreviewPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplatePreviewPage.java
new file mode 100644
index 0000000..c3d28fc
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplatePreviewPage.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.wizards.templates;
+
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.CompositeChange;
+import org.eclipse.ltk.internal.ui.refactoring.PreviewWizardPage;
+
+import java.util.List;
+
+@SuppressWarnings("restriction") // Refactoring UI
+class TemplatePreviewPage extends PreviewWizardPage {
+ private final NewTemplateWizardState mValues;
+
+ TemplatePreviewPage(NewTemplateWizardState values) {
+ super(true);
+ mValues = values;
+ setTitle("Preview");
+ setDescription("Optionally review pending changes");
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ List<Change> changes = mValues.computeChanges();
+ CompositeChange root = new CompositeChange("Create template",
+ changes.toArray(new Change[changes.size()]));
+ setChange(root);
+ }
+
+ super.setVisible(visible);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateWizard.java
new file mode 100644
index 0000000..a062665
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateWizard.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.wizards.templates;
+
+import static org.eclipse.core.resources.IResource.DEPTH_INFINITE;
+
+import com.android.annotations.NonNull;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.IconFactory;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.CompositeChange;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+abstract class TemplateWizard extends Wizard implements INewWizard {
+ private static final String PROJECT_LOGO_LARGE = "android-64"; //$NON-NLS-1$
+ protected IWorkbench mWorkbench;
+ private UpdateToolsPage mUpdatePage;
+ private InstallDependencyPage mDependencyPage;
+ private TemplatePreviewPage mPreviewPage;
+
+ protected TemplateWizard() {
+ }
+
+ @Override
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ mWorkbench = workbench;
+
+ setHelpAvailable(false);
+ ImageDescriptor desc = IconFactory.getInstance().getImageDescriptor(PROJECT_LOGO_LARGE);
+ setDefaultPageImageDescriptor(desc);
+
+ if (!UpdateToolsPage.isUpToDate()) {
+ mUpdatePage = new UpdateToolsPage();
+ }
+
+ setNeedsProgressMonitor(true);
+ }
+
+ @Override
+ public void addPages() {
+ super.addPages();
+ if (mUpdatePage != null) {
+ addPage(mUpdatePage);
+ }
+ }
+
+ @Override
+ public IWizardPage getStartingPage() {
+ if (mUpdatePage != null && mUpdatePage.isPageComplete()) {
+ return getNextPage(mUpdatePage);
+ }
+
+ return super.getStartingPage();
+ }
+
+ protected WizardPage getPreviewPage(NewTemplateWizardState values) {
+ if (mPreviewPage == null) {
+ mPreviewPage = new TemplatePreviewPage(values);
+ addPage(mPreviewPage);
+ }
+
+ return mPreviewPage;
+ }
+
+ protected WizardPage getDependencyPage(TemplateMetadata template, boolean create) {
+ if (!create) {
+ return mDependencyPage;
+ }
+
+ if (mDependencyPage == null) {
+ mDependencyPage = new InstallDependencyPage();
+ addPage(mDependencyPage);
+ }
+ mDependencyPage.setTemplate(template);
+ return mDependencyPage;
+ }
+
+ /**
+ * Returns the project where the template is being inserted
+ *
+ * @return the project to insert the template into
+ */
+ @NonNull
+ protected abstract IProject getProject();
+
+ /**
+ * Returns the list of files to open, which might be empty. This method will
+ * only be called <b>after</b> {@link #computeChanges()} has been called.
+ *
+ * @return a list of files to open
+ */
+ @NonNull
+ protected abstract List<String> getFilesToOpen();
+
+ /**
+ * Computes the changes to the {@link #getProject()} this template should
+ * perform
+ *
+ * @return the changes to perform
+ */
+ protected abstract List<Change> computeChanges();
+
+ protected boolean performFinish(IProgressMonitor monitor) throws InvocationTargetException {
+ List<Change> changes = computeChanges();
+ if (!changes.isEmpty()) {
+ monitor.beginTask("Creating template...", changes.size());
+ try {
+ CompositeChange composite = new CompositeChange("",
+ changes.toArray(new Change[changes.size()]));
+ composite.perform(monitor);
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ throw new InvocationTargetException(e);
+ } finally {
+ monitor.done();
+ }
+ }
+
+ // TBD: Is this necessary now that we're using IFile objects?
+ try {
+ getProject().refreshLocal(DEPTH_INFINITE, new NullProgressMonitor());
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean performFinish() {
+ final AtomicBoolean success = new AtomicBoolean();
+ try {
+ getContainer().run(true, false, new IRunnableWithProgress() {
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException,
+ InterruptedException {
+ boolean ok = performFinish(monitor);
+ success.set(ok);
+ }
+ });
+ } catch (InvocationTargetException e) {
+ AdtPlugin.log(e, null);
+ return false;
+ } catch (InterruptedException e) {
+ AdtPlugin.log(e, null);
+ return false;
+ }
+
+ if (success.get()) {
+ // Open the primary file/files
+ NewTemplateWizard.openFiles(getProject(), getFilesToOpen(), mWorkbench);
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+}