diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards')
75 files changed, 0 insertions, 20974 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportAction.java deleted file mode 100644 index 4d3870b86..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportAction.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2007 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.actions; - -import com.android.ide.eclipse.adt.internal.lint.EclipseLintRunner; -import com.android.ide.eclipse.adt.internal.project.ExportHelper; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbenchPart; - -public class ExportAction implements IObjectActionDelegate { - - private ISelection mSelection; - private Shell mShell; - - /** - * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) - */ - @Override - public void setActivePart(IAction action, IWorkbenchPart targetPart) { - mShell = targetPart.getSite().getShell(); - } - - @Override - public void run(IAction action) { - if (mSelection instanceof IStructuredSelection) { - IStructuredSelection selection = (IStructuredSelection)mSelection; - // get the unique selected item. - if (selection.size() == 1) { - Object element = selection.getFirstElement(); - - // get the project object from it. - IProject project = null; - if (element instanceof IProject) { - project = (IProject) element; - } else if (element instanceof IAdaptable) { - project = (IProject) ((IAdaptable) element).getAdapter(IProject.class); - } - - // and finally do the action - if (project != null) { - if (!EclipseLintRunner.runLintOnExport(mShell, project)) { - return; - } - - ProjectState state = Sdk.getProjectState(project); - if (state.isLibrary()) { - MessageDialog.openError(mShell, "Android Export", - "Android library projects cannot be exported."); - } else { - ExportHelper.exportUnsignedReleaseApk(project); - } - } - } - } - } - - @Override - public void selectionChanged(IAction action, ISelection selection) { - mSelection = selection; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportWizardAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportWizardAction.java deleted file mode 100644 index 673d9569f..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportWizardAction.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2008 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.actions; - -import com.android.ide.eclipse.adt.internal.lint.EclipseLintRunner; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPart; - -public class ExportWizardAction implements IObjectActionDelegate { - - private ISelection mSelection; - private IWorkbench mWorkbench; - - /** - * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) - */ - @Override - public void setActivePart(IAction action, IWorkbenchPart targetPart) { - mWorkbench = targetPart.getSite().getWorkbenchWindow().getWorkbench(); - } - - @Override - public void run(IAction action) { - if (mSelection instanceof IStructuredSelection) { - IStructuredSelection selection = (IStructuredSelection)mSelection; - - // get the unique selected item. - if (selection.size() == 1) { - Object element = selection.getFirstElement(); - - // get the project object from it. - IProject project = null; - if (element instanceof IProject) { - project = (IProject) element; - } else if (element instanceof IAdaptable) { - project = (IProject) ((IAdaptable) element).getAdapter(IProject.class); - } - - // and finally do the action - if (project != null) { - if (!EclipseLintRunner.runLintOnExport( - mWorkbench.getActiveWorkbenchWindow().getShell(), project)) { - return; - } - - ProjectState state = Sdk.getProjectState(project); - if (state.isLibrary()) { - MessageDialog.openError(mWorkbench.getDisplay().getActiveShell(), - "Android Export", - "Android library projects cannot be exported."); - } else { - // call the export wizard on the current selection. - ExportWizard wizard = new ExportWizard(); - wizard.init(mWorkbench, selection); - WizardDialog dialog = new WizardDialog( - mWorkbench.getDisplay().getActiveShell(), wizard); - dialog.open(); - } - } - } - } - } - - @Override - public void selectionChanged(IAction action, ISelection selection) { - mSelection = selection; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/NewProjectAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/NewProjectAction.java deleted file mode 100644 index 38f4768b1..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/NewProjectAction.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2009 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.actions; - -import com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard; - -import org.eclipse.jface.action.IAction; -import org.eclipse.ui.IWorkbenchWizard; - -/** - * Delegate for the toolbar action "Android Project". - * It displays the Android New Project wizard to create a new Android Project (not a test project). - * - * @see NewTestProjectAction - */ -public class NewProjectAction extends OpenWizardAction { - - @Override - protected IWorkbenchWizard instanciateWizard(IAction action) { - return new NewProjectWizard(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/NewTestProjectAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/NewTestProjectAction.java deleted file mode 100755 index c8e45ef1a..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/NewTestProjectAction.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2009 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.actions; - -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewTestProjectWizard; - -import org.eclipse.jface.action.IAction; -import org.eclipse.ui.IWorkbenchWizard; - -/** - * Delegate for the toolbar action "Android Test Project". - * It displays the Android New Project wizard to create a new Test Project. - */ -public class NewTestProjectAction extends OpenWizardAction { - - @Override - protected IWorkbenchWizard instanciateWizard(IAction action) { - return new NewTestProjectWizard(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/NewXmlFileAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/NewXmlFileAction.java deleted file mode 100644 index ba349c30a..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/NewXmlFileAction.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2009 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.actions; - -import com.android.ide.eclipse.adt.internal.wizards.newxmlfile.NewXmlFileWizard; - -import org.eclipse.jface.action.IAction; -import org.eclipse.ui.IWorkbenchWizard; - -/** - * Delegate for the toolbar action "Android Project" or for the - * project > Android Project context menu. - * - * It displays the Android New XML file wizard. - */ -public class NewXmlFileAction extends OpenWizardAction { - - @Override - protected IWorkbenchWizard instanciateWizard(IAction action) { - return new NewXmlFileWizard(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/OpenWizardAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/OpenWizardAction.java deleted file mode 100644 index a3e6135e5..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/OpenWizardAction.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2009 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.actions; - -import com.android.ide.eclipse.adt.internal.ui.IUpdateWizardDialog; -import com.android.ide.eclipse.adt.internal.ui.WizardDialogEx; - -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.IWorkbenchWindowActionDelegate; -import org.eclipse.ui.IWorkbenchWizard; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.internal.IWorkbenchHelpContextIds; -import org.eclipse.ui.internal.LegacyResourceSupport; -import org.eclipse.ui.internal.actions.NewWizardShortcutAction; -import org.eclipse.ui.internal.util.Util; - -/** - * An abstract action that displays one of our wizards. - * Derived classes must provide the actual wizard to display. - */ -/*package*/ abstract class OpenWizardAction - implements IWorkbenchWindowActionDelegate, IObjectActionDelegate { - - /** - * The wizard dialog width, extracted from {@link NewWizardShortcutAction} - */ - private static final int SIZING_WIZARD_WIDTH = 500; - - /** - * The wizard dialog height, extracted from {@link NewWizardShortcutAction} - */ - private static final int SIZING_WIZARD_HEIGHT = 500; - - /** The wizard that was created by {@link #run(IAction)}. */ - private IWorkbenchWizard mWizard; - /** The result from the dialog */ - private int mDialogResult; - - private ISelection mSelection; - private IWorkbench mWorkbench; - - /** Returns the wizard that was created by {@link #run(IAction)}. */ - public IWorkbenchWizard getWizard() { - return mWizard; - } - - /** Returns the result from {@link Dialog#open()}, available after - * the completion of {@link #run(IAction)}. */ - public int getDialogResult() { - return mDialogResult; - } - - /* (non-Javadoc) - * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose() - */ - @Override - public void dispose() { - // pass - } - - /* (non-Javadoc) - * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow) - */ - @Override - public void init(IWorkbenchWindow window) { - // pass - } - - /** - * Opens and display the Android New Project Wizard. - * <p/> - * Most of this implementation is extracted from {@link NewWizardShortcutAction#run()}. - * - * @param action The action that got us here. Can be null when used internally. - * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) - */ - @Override - public void run(IAction action) { - - // get the workbench and the current window - IWorkbench workbench = mWorkbench != null ? mWorkbench : PlatformUI.getWorkbench(); - IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); - - // This code from NewWizardShortcutAction#run() gets the current window selection - // and converts it to a workbench structured selection for the wizard, if possible. - ISelection selection = mSelection; - if (selection == null) { - selection = window.getSelectionService().getSelection(); - } - - IStructuredSelection selectionToPass = StructuredSelection.EMPTY; - if (selection instanceof IStructuredSelection) { - selectionToPass = (IStructuredSelection) selection; - } else { - // Build the selection from the IFile of the editor - IWorkbenchPart part = window.getPartService().getActivePart(); - if (part instanceof IEditorPart) { - IEditorInput input = ((IEditorPart) part).getEditorInput(); - Class<?> fileClass = LegacyResourceSupport.getFileClass(); - if (input != null && fileClass != null) { - Object file = Util.getAdapter(input, fileClass); - if (file != null) { - selectionToPass = new StructuredSelection(file); - } - } - } - } - - // Create the wizard and initialize it with the selection - mWizard = instanciateWizard(action); - mWizard.init(workbench, selectionToPass); - - // It's not visible yet until a dialog is created and opened - Shell parent = window.getShell(); - WizardDialogEx dialog = new WizardDialogEx(parent, mWizard); - dialog.create(); - - if (mWizard instanceof IUpdateWizardDialog) { - ((IUpdateWizardDialog) mWizard).updateWizardDialog(dialog); - } - - // This code comes straight from NewWizardShortcutAction#run() - Point defaultSize = dialog.getShell().getSize(); - dialog.getShell().setSize( - Math.max(SIZING_WIZARD_WIDTH, defaultSize.x), - Math.max(SIZING_WIZARD_HEIGHT, defaultSize.y)); - window.getWorkbench().getHelpSystem().setHelp(dialog.getShell(), - IWorkbenchHelpContextIds.NEW_WIZARD_SHORTCUT); - - mDialogResult = dialog.open(); - } - - /** - * Called by {@link #run(IAction)} to instantiate the actual wizard. - * - * @param action The action parameter from {@link #run(IAction)}. - * This can be null. - * @return A new wizard instance. Must not be null. - */ - protected abstract IWorkbenchWizard instanciateWizard(IAction action); - - /* (non-Javadoc) - * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection) - */ - @Override - public void selectionChanged(IAction action, ISelection selection) { - mSelection = selection; - } - - /* (non-Javadoc) - * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart) - */ - @Override - public void setActivePart(IAction action, IWorkbenchPart targetPart) { - mWorkbench = targetPart.getSite().getWorkbenchWindow().getWorkbench(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java deleted file mode 100644 index 170da6d33..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (C) 2008 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.export; - -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.utils.FingerprintUtils; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.ExportHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.sdklib.BuildToolInfo; -import com.android.sdklib.BuildToolInfo.PathId; -import com.android.sdklib.internal.build.DebugKeyProvider.IKeyGenOutput; -import com.android.sdklib.internal.build.KeystoreHelper; -import com.android.utils.GrabProcessOutput; -import com.android.utils.GrabProcessOutput.IProcessOutput; -import com.android.utils.GrabProcessOutput.Wait; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.events.VerifyEvent; -import org.eclipse.swt.events.VerifyListener; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IExportWizard; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PlatformUI; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.lang.reflect.InvocationTargetException; -import java.security.KeyStore; -import java.security.KeyStore.PrivateKeyEntry; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.List; - -/** - * Export wizard to export an apk signed with a release key/certificate. - */ -public final class ExportWizard extends Wizard implements IExportWizard { - - private static final String PROJECT_LOGO_LARGE = "icons/android-64.png"; //$NON-NLS-1$ - - private static final String PAGE_PROJECT_CHECK = "Page_ProjectCheck"; //$NON-NLS-1$ - private static final String PAGE_KEYSTORE_SELECTION = "Page_KeystoreSelection"; //$NON-NLS-1$ - private static final String PAGE_KEY_CREATION = "Page_KeyCreation"; //$NON-NLS-1$ - private static final String PAGE_KEY_SELECTION = "Page_KeySelection"; //$NON-NLS-1$ - private static final String PAGE_KEY_CHECK = "Page_KeyCheck"; //$NON-NLS-1$ - - static final String PROPERTY_KEYSTORE = "keystore"; //$NON-NLS-1$ - static final String PROPERTY_ALIAS = "alias"; //$NON-NLS-1$ - static final String PROPERTY_DESTINATION = "destination"; //$NON-NLS-1$ - - static final int APK_FILE_SOURCE = 0; - static final int APK_FILE_DEST = 1; - static final int APK_COUNT = 2; - - /** - * Base page class for the ExportWizard page. This class add the {@link #onShow()} callback. - */ - static abstract class ExportWizardPage extends WizardPage { - - /** bit mask constant for project data change event */ - protected static final int DATA_PROJECT = 0x001; - /** bit mask constant for keystore data change event */ - protected static final int DATA_KEYSTORE = 0x002; - /** bit mask constant for key data change event */ - protected static final int DATA_KEY = 0x004; - - protected static final VerifyListener sPasswordVerifier = new VerifyListener() { - @Override - public void verifyText(VerifyEvent e) { - // verify the characters are valid for password. - int len = e.text.length(); - - // first limit to 127 characters max - if (len + ((Text)e.getSource()).getText().length() > 127) { - e.doit = false; - return; - } - - // now only take non control characters - for (int i = 0 ; i < len ; i++) { - if (e.text.charAt(i) < 32) { - e.doit = false; - return; - } - } - } - }; - - /** - * Bit mask indicating what changed while the page was hidden. - * @see #DATA_PROJECT - * @see #DATA_KEYSTORE - * @see #DATA_KEY - */ - protected int mProjectDataChanged = 0; - - ExportWizardPage(String name) { - super(name); - } - - abstract void onShow(); - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - if (visible) { - onShow(); - mProjectDataChanged = 0; - } - } - - final void projectDataChanged(int changeMask) { - mProjectDataChanged |= changeMask; - } - - /** - * Calls {@link #setErrorMessage(String)} and {@link #setPageComplete(boolean)} based on a - * {@link Throwable} object. - */ - protected void onException(Throwable t) { - String message = getExceptionMessage(t); - - setErrorMessage(message); - setPageComplete(false); - } - } - - private ExportWizardPage mPages[] = new ExportWizardPage[5]; - - private IProject mProject; - - private String mKeystore; - private String mKeystorePassword; - private boolean mKeystoreCreationMode; - - private String mKeyAlias; - private String mKeyPassword; - private int mValidity; - private String mDName; - - private PrivateKey mPrivateKey; - private X509Certificate mCertificate; - - private File mDestinationFile; - - private ExportWizardPage mKeystoreSelectionPage; - private ExportWizardPage mKeyCreationPage; - private ExportWizardPage mKeySelectionPage; - private ExportWizardPage mKeyCheckPage; - - private boolean mKeyCreationMode; - - private List<String> mExistingAliases; - - public ExportWizard() { - setHelpAvailable(false); // TODO have help - setWindowTitle("Export Android Application"); - setImageDescriptor(); - } - - @Override - public void addPages() { - addPage(mPages[0] = new ProjectCheckPage(this, PAGE_PROJECT_CHECK)); - addPage(mKeystoreSelectionPage = mPages[1] = new KeystoreSelectionPage(this, - PAGE_KEYSTORE_SELECTION)); - addPage(mKeyCreationPage = mPages[2] = new KeyCreationPage(this, PAGE_KEY_CREATION)); - addPage(mKeySelectionPage = mPages[3] = new KeySelectionPage(this, PAGE_KEY_SELECTION)); - addPage(mKeyCheckPage = mPages[4] = new KeyCheckPage(this, PAGE_KEY_CHECK)); - } - - @Override - public boolean performFinish() { - // save the properties - ProjectHelper.saveStringProperty(mProject, PROPERTY_KEYSTORE, mKeystore); - ProjectHelper.saveStringProperty(mProject, PROPERTY_ALIAS, mKeyAlias); - ProjectHelper.saveStringProperty(mProject, PROPERTY_DESTINATION, - mDestinationFile.getAbsolutePath()); - - // run the export in an UI runnable. - IWorkbench workbench = PlatformUI.getWorkbench(); - final boolean[] result = new boolean[1]; - try { - workbench.getProgressService().busyCursorWhile(new IRunnableWithProgress() { - /** - * Run the export. - * @throws InvocationTargetException - * @throws InterruptedException - */ - @Override - public void run(IProgressMonitor monitor) throws InvocationTargetException, - InterruptedException { - try { - result[0] = doExport(monitor); - } finally { - monitor.done(); - } - } - }); - } catch (InvocationTargetException e) { - return false; - } catch (InterruptedException e) { - return false; - } - - return result[0]; - } - - private boolean doExport(IProgressMonitor monitor) { - try { - // if needed, create the keystore and/or key. - if (mKeystoreCreationMode || mKeyCreationMode) { - final ArrayList<String> output = new ArrayList<String>(); - boolean createdStore = KeystoreHelper.createNewStore( - mKeystore, - null /*storeType*/, - mKeystorePassword, - mKeyAlias, - mKeyPassword, - mDName, - mValidity, - new IKeyGenOutput() { - @Override - public void err(String message) { - output.add(message); - } - @Override - public void out(String message) { - output.add(message); - } - }); - - if (createdStore == false) { - // keystore creation error! - displayError(output.toArray(new String[output.size()])); - return false; - } - - // keystore is created, now load the private key and certificate. - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - FileInputStream fis = new FileInputStream(mKeystore); - keyStore.load(fis, mKeystorePassword.toCharArray()); - fis.close(); - PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)keyStore.getEntry( - mKeyAlias, new KeyStore.PasswordProtection(mKeyPassword.toCharArray())); - - if (entry != null) { - mPrivateKey = entry.getPrivateKey(); - mCertificate = (X509Certificate)entry.getCertificate(); - - AdtPlugin.printToConsole(mProject, - String.format("New keystore %s has been created.", - mDestinationFile.getAbsolutePath()), - "Certificate fingerprints:", - String.format(" MD5 : %s", getCertMd5Fingerprint()), - String.format(" SHA1: %s", getCertSha1Fingerprint())); - - } else { - // this really shouldn't happen since we now let the user choose the key - // from a list read from the store. - displayError("Could not find key"); - return false; - } - } - - // check the private key/certificate again since it may have been created just above. - if (mPrivateKey != null && mCertificate != null) { - // check whether we can run zipalign. - boolean runZipAlign = false; - - ProjectState projectState = Sdk.getProjectState(mProject); - BuildToolInfo buildToolInfo = ExportHelper.getBuildTools(projectState); - - String zipAlignPath = buildToolInfo.getPath(PathId.ZIP_ALIGN); - runZipAlign = zipAlignPath != null && new File(zipAlignPath).isFile(); - - File apkExportFile = mDestinationFile; - if (runZipAlign) { - // create a temp file for the original export. - apkExportFile = File.createTempFile("androidExport_", ".apk"); - } - - // export the signed apk. - ExportHelper.exportReleaseApk(mProject, apkExportFile, - mPrivateKey, mCertificate, monitor); - - // align if we can - if (runZipAlign) { - String message = zipAlign(zipAlignPath, apkExportFile, mDestinationFile); - if (message != null) { - displayError(message); - return false; - } - } else { - AdtPlugin.displayWarning("Export Wizard", - "The zipalign tool was not found in the SDK.\n\n" + - "Please update to the latest SDK and re-export your application\n" + - "or run zipalign manually.\n\n" + - "Aligning applications allows Android to use application resources\n" + - "more efficiently."); - } - - return true; - } - } catch (Throwable t) { - displayError(t); - } - - return false; - } - - @Override - public boolean canFinish() { - // check if we have the apk to resign, the destination location, and either - // a private key/certificate or the creation mode. In creation mode, unless - // all the key/keystore info is valid, the user cannot reach the last page, so there's - // no need to check them again here. - return ((mPrivateKey != null && mCertificate != null) - || mKeystoreCreationMode || mKeyCreationMode) && - mDestinationFile != null; - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.IWorkbenchWizard#init(org.eclipse.ui.IWorkbench, - * org.eclipse.jface.viewers.IStructuredSelection) - */ - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - // get the project from the selection - Object selected = selection.getFirstElement(); - - if (selected instanceof IProject) { - mProject = (IProject)selected; - } else if (selected instanceof IAdaptable) { - IResource r = (IResource)((IAdaptable)selected).getAdapter(IResource.class); - if (r != null) { - mProject = r.getProject(); - } - } - } - - ExportWizardPage getKeystoreSelectionPage() { - return mKeystoreSelectionPage; - } - - ExportWizardPage getKeyCreationPage() { - return mKeyCreationPage; - } - - ExportWizardPage getKeySelectionPage() { - return mKeySelectionPage; - } - - ExportWizardPage getKeyCheckPage() { - return mKeyCheckPage; - } - - /** - * Returns an image descriptor for the wizard logo. - */ - private void setImageDescriptor() { - ImageDescriptor desc = AdtPlugin.getImageDescriptor(PROJECT_LOGO_LARGE); - setDefaultPageImageDescriptor(desc); - } - - IProject getProject() { - return mProject; - } - - void setProject(IProject project) { - mProject = project; - - updatePageOnChange(ExportWizardPage.DATA_PROJECT); - } - - void setKeystore(String path) { - mKeystore = path; - mPrivateKey = null; - mCertificate = null; - - updatePageOnChange(ExportWizardPage.DATA_KEYSTORE); - } - - String getKeystore() { - return mKeystore; - } - - void setKeystoreCreationMode(boolean createStore) { - mKeystoreCreationMode = createStore; - updatePageOnChange(ExportWizardPage.DATA_KEYSTORE); - } - - boolean getKeystoreCreationMode() { - return mKeystoreCreationMode; - } - - - void setKeystorePassword(String password) { - mKeystorePassword = password; - mPrivateKey = null; - mCertificate = null; - - updatePageOnChange(ExportWizardPage.DATA_KEYSTORE); - } - - String getKeystorePassword() { - return mKeystorePassword; - } - - void setKeyCreationMode(boolean createKey) { - mKeyCreationMode = createKey; - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - boolean getKeyCreationMode() { - return mKeyCreationMode; - } - - void setExistingAliases(List<String> aliases) { - mExistingAliases = aliases; - } - - List<String> getExistingAliases() { - return mExistingAliases; - } - - void setKeyAlias(String name) { - mKeyAlias = name; - mPrivateKey = null; - mCertificate = null; - - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - String getKeyAlias() { - return mKeyAlias; - } - - void setKeyPassword(String password) { - mKeyPassword = password; - mPrivateKey = null; - mCertificate = null; - - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - String getKeyPassword() { - return mKeyPassword; - } - - void setValidity(int validity) { - mValidity = validity; - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - int getValidity() { - return mValidity; - } - - void setDName(String dName) { - mDName = dName; - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - String getDName() { - return mDName; - } - - String getCertSha1Fingerprint() { - return FingerprintUtils.getFingerprint(mCertificate, "SHA1"); - } - - String getCertMd5Fingerprint() { - return FingerprintUtils.getFingerprint(mCertificate, "MD5"); - } - - void setSigningInfo(PrivateKey privateKey, X509Certificate certificate) { - mPrivateKey = privateKey; - mCertificate = certificate; - } - - void setDestination(File destinationFile) { - mDestinationFile = destinationFile; - } - - void resetDestination() { - mDestinationFile = null; - } - - void updatePageOnChange(int changeMask) { - for (ExportWizardPage page : mPages) { - page.projectDataChanged(changeMask); - } - } - - private void displayError(String... messages) { - String message = null; - if (messages.length == 1) { - message = messages[0]; - } else { - StringBuilder sb = new StringBuilder(messages[0]); - for (int i = 1; i < messages.length; i++) { - sb.append('\n'); - sb.append(messages[i]); - } - - message = sb.toString(); - } - - AdtPlugin.displayError("Export Wizard", message); - } - - private void displayError(Throwable t) { - String message = getExceptionMessage(t); - displayError(message); - - AdtPlugin.log(t, "Export Wizard Error"); - } - - /** - * Executes zipalign - * @param zipAlignPath location of the zipalign too - * @param source file to zipalign - * @param destination where to write the resulting file - * @return null if success, the error otherwise - * @throws IOException - */ - private String zipAlign(String zipAlignPath, File source, File destination) throws IOException { - // command line: zipaling -f 4 tmp destination - String[] command = new String[5]; - command[0] = zipAlignPath; - command[1] = "-f"; //$NON-NLS-1$ - command[2] = "4"; //$NON-NLS-1$ - command[3] = source.getAbsolutePath(); - command[4] = destination.getAbsolutePath(); - - Process process = Runtime.getRuntime().exec(command); - final ArrayList<String> output = new ArrayList<String>(); - try { - final IProject project = getProject(); - - int status = GrabProcessOutput.grabProcessOutput( - process, - Wait.WAIT_FOR_READERS, - new IProcessOutput() { - @Override - public void out(@Nullable String line) { - if (line != null) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, - project, line); - } - } - - @Override - public void err(@Nullable String line) { - if (line != null) { - output.add(line); - } - } - }); - - if (status != 0) { - // build a single message from the array list - StringBuilder sb = new StringBuilder("Error while running zipalign:"); - for (String msg : output) { - sb.append('\n'); - sb.append(msg); - } - - return sb.toString(); - } - } catch (InterruptedException e) { - // ? - } - return null; - } - - /** - * Returns the {@link Throwable#getMessage()}. If the {@link Throwable#getMessage()} returns - * <code>null</code>, the method is called again on the cause of the Throwable object. - * <p/>If no Throwable in the chain has a valid message, the canonical name of the first - * exception is returned. - */ - static String getExceptionMessage(Throwable t) { - String message = t.getMessage(); - if (message == null) { - // no error info? get the stack call to display it - // At least that'll give us a better bug report. - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - t.printStackTrace(new PrintStream(baos)); - message = baos.toString(); - } - - return message; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeyCheckPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeyCheckPage.java deleted file mode 100644 index c17f43e38..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeyCheckPage.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2008 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.export; - -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage; - -import org.eclipse.core.resources.IProject; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.ScrolledComposite; -import org.eclipse.swt.events.ControlAdapter; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.widgets.FormText; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStore.PrivateKeyEntry; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.UnrecoverableEntryException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Calendar; - -/** - * Final page of the wizard that checks the key and ask for the ouput location. - */ -final class KeyCheckPage extends ExportWizardPage { - - private static final int REQUIRED_YEARS = 25; - - private static final String VALIDITY_WARNING = - "<p>Make sure the certificate is valid for the planned lifetime of the product.</p>" - + "<p>If the certificate expires, you will be forced to sign your application with " - + "a different one.</p>" - + "<p>Applications cannot be upgraded if their certificate changes from " - + "one version to another, forcing a full uninstall/install, which will make " - + "the user lose his/her data.</p>" - + "<p>Google Play(Android Market) currently requires certificates to be valid " - + "until 2033.</p>"; - - private final ExportWizard mWizard; - private PrivateKey mPrivateKey; - private X509Certificate mCertificate; - private Text mDestination; - private boolean mFatalSigningError; - private FormText mDetailText; - private ScrolledComposite mScrolledComposite; - - private String mKeyDetails; - private String mDestinationDetails; - - protected KeyCheckPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Destination and key/certificate checks"); - setDescription(""); // TODO - } - - @Override - public void createControl(Composite parent) { - setErrorMessage(null); - setMessage(null); - - // build the ui. - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout gl = new GridLayout(3, false); - gl.verticalSpacing *= 3; - composite.setLayout(gl); - - GridData gd; - - new Label(composite, SWT.NONE).setText("Destination APK file:"); - mDestination = new Text(composite, SWT.BORDER); - mDestination.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mDestination.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - onDestinationChange(false /*forceDetailUpdate*/); - } - }); - final Button browseButton = new Button(composite, SWT.PUSH); - browseButton.setText("Browse..."); - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - FileDialog fileDialog = new FileDialog(browseButton.getShell(), SWT.SAVE); - - fileDialog.setText("Destination file name"); - // get a default apk name based on the project - String filename = ProjectHelper.getApkFilename(mWizard.getProject(), - null /*config*/); - fileDialog.setFileName(filename); - - String saveLocation = fileDialog.open(); - if (saveLocation != null) { - mDestination.setText(saveLocation); - } - } - }); - - mScrolledComposite = new ScrolledComposite(composite, SWT.V_SCROLL); - mScrolledComposite.setLayoutData(gd = new GridData(GridData.FILL_BOTH)); - gd.horizontalSpan = 3; - mScrolledComposite.setExpandHorizontal(true); - mScrolledComposite.setExpandVertical(true); - - mDetailText = new FormText(mScrolledComposite, SWT.NONE); - mScrolledComposite.setContent(mDetailText); - - mScrolledComposite.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - updateScrolling(); - } - }); - - setControl(composite); - } - - @Override - void onShow() { - // fill the texts with information loaded from the project. - if ((mProjectDataChanged & DATA_PROJECT) != 0) { - // reset the destination from the content of the project - IProject project = mWizard.getProject(); - - String destination = ProjectHelper.loadStringProperty(project, - ExportWizard.PROPERTY_DESTINATION); - if (destination != null) { - mDestination.setText(destination); - } - } - - // if anything change we basically reload the data. - if (mProjectDataChanged != 0) { - mFatalSigningError = false; - - // reset the wizard with no key/cert to make it not finishable, unless a valid - // key/cert is found. - mWizard.setSigningInfo(null, null); - mPrivateKey = null; - mCertificate = null; - mKeyDetails = null; - - if (mWizard.getKeystoreCreationMode() || mWizard.getKeyCreationMode()) { - int validity = mWizard.getValidity(); - StringBuilder sb = new StringBuilder( - String.format("<p>Certificate expires in %d years.</p>", - validity)); - - if (validity < REQUIRED_YEARS) { - sb.append(VALIDITY_WARNING); - } - - mKeyDetails = sb.toString(); - } else { - try { - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - FileInputStream fis = new FileInputStream(mWizard.getKeystore()); - keyStore.load(fis, mWizard.getKeystorePassword().toCharArray()); - fis.close(); - PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)keyStore.getEntry( - mWizard.getKeyAlias(), - new KeyStore.PasswordProtection( - mWizard.getKeyPassword().toCharArray())); - - if (entry != null) { - mPrivateKey = entry.getPrivateKey(); - mCertificate = (X509Certificate)entry.getCertificate(); - } else { - setErrorMessage("Unable to find key."); - - setPageComplete(false); - } - } catch (FileNotFoundException e) { - // this was checked at the first previous step and will not happen here, unless - // the file was removed during the export wizard execution. - onException(e); - } catch (KeyStoreException e) { - onException(e); - } catch (NoSuchAlgorithmException e) { - onException(e); - } catch (UnrecoverableEntryException e) { - onException(e); - } catch (CertificateException e) { - onException(e); - } catch (IOException e) { - onException(e); - } - - if (mPrivateKey != null && mCertificate != null) { - Calendar expirationCalendar = Calendar.getInstance(); - expirationCalendar.setTime(mCertificate.getNotAfter()); - Calendar today = Calendar.getInstance(); - - if (expirationCalendar.before(today)) { - mKeyDetails = String.format( - "<p>Certificate expired on %s</p>", - mCertificate.getNotAfter().toString()); - - // fatal error = nothing can make the page complete. - mFatalSigningError = true; - - setErrorMessage("Certificate is expired."); - setPageComplete(false); - } else { - // valid, key/cert: put it in the wizard so that it can be finished - mWizard.setSigningInfo(mPrivateKey, mCertificate); - - StringBuilder sb = new StringBuilder(String.format( - "<p>Certificate expires on %s.</p>", - mCertificate.getNotAfter().toString())); - - int expirationYear = expirationCalendar.get(Calendar.YEAR); - int thisYear = today.get(Calendar.YEAR); - - if (thisYear + REQUIRED_YEARS < expirationYear) { - // do nothing - } else { - if (expirationYear == thisYear) { - sb.append("<p>The certificate expires this year.</p>"); - } else { - int count = expirationYear-thisYear; - sb.append(String.format( - "<p>The Certificate expires in %1$s %2$s.</p>", - count, count == 1 ? "year" : "years")); - } - sb.append(VALIDITY_WARNING); - } - - // show certificate fingerprints - String sha1 = mWizard.getCertSha1Fingerprint(); - String md5 = mWizard.getCertMd5Fingerprint(); - - sb.append("<p></p>" /*blank line*/); - sb.append("<p>Certificate fingerprints:</p>"); - sb.append(String.format("<li>MD5 : %s</li>", md5)); - sb.append(String.format("<li>SHA1: %s</li>", sha1)); - sb.append("<p></p>" /*blank line*/); - - mKeyDetails = sb.toString(); - } - } else { - // fatal error = nothing can make the page complete. - mFatalSigningError = true; - } - } - } - - onDestinationChange(true /*forceDetailUpdate*/); - } - - /** - * Callback for destination field edition - * @param forceDetailUpdate if true, the detail {@link FormText} is updated even if a fatal - * error has happened in the signing. - */ - private void onDestinationChange(boolean forceDetailUpdate) { - if (mFatalSigningError == false) { - // reset messages for now. - setErrorMessage(null); - setMessage(null); - - String path = mDestination.getText().trim(); - - if (path.length() == 0) { - setErrorMessage("Enter destination for the APK file."); - // reset canFinish in the wizard. - mWizard.resetDestination(); - setPageComplete(false); - return; - } - - File file = new File(path); - if (file.isDirectory()) { - setErrorMessage("Destination is a directory."); - // reset canFinish in the wizard. - mWizard.resetDestination(); - setPageComplete(false); - return; - } - - File parentFolder = file.getParentFile(); - if (parentFolder == null || parentFolder.isDirectory() == false) { - setErrorMessage("Not a valid directory."); - // reset canFinish in the wizard. - mWizard.resetDestination(); - setPageComplete(false); - return; - } - - if (file.isFile()) { - mDestinationDetails = "<li>WARNING: destination file already exists</li>"; - setMessage("Destination file already exists.", WARNING); - } - - // no error, set the destination in the wizard. - mWizard.setDestination(file); - setPageComplete(true); - - updateDetailText(); - } else if (forceDetailUpdate) { - updateDetailText(); - } - } - - /** - * Updates the scrollbar to match the content of the {@link FormText} or the new size - * of the {@link ScrolledComposite}. - */ - private void updateScrolling() { - if (mDetailText != null) { - Rectangle r = mScrolledComposite.getClientArea(); - mScrolledComposite.setMinSize(mDetailText.computeSize(r.width, SWT.DEFAULT)); - mScrolledComposite.layout(); - } - } - - private void updateDetailText() { - StringBuilder sb = new StringBuilder("<form>"); - if (mKeyDetails != null) { - sb.append(mKeyDetails); - } - - if (mDestinationDetails != null && mFatalSigningError == false) { - sb.append(mDestinationDetails); - } - - sb.append("</form>"); - - mDetailText.setText(sb.toString(), true /* parseTags */, - true /* expandURLs */); - - mDetailText.getParent().layout(); - - updateScrolling(); - } - - @Override - protected void onException(Throwable t) { - super.onException(t); - - mKeyDetails = String.format("ERROR: %1$s", ExportWizard.getExceptionMessage(t)); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeyCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeyCreationPage.java deleted file mode 100644 index aea94ad8d..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeyCreationPage.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2008 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.export; - -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.VerifyEvent; -import org.eclipse.swt.events.VerifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.util.List; - -/** - * Key creation page. - */ -final class KeyCreationPage extends ExportWizardPage { - - private final ExportWizard mWizard; - private Text mAlias; - private Text mKeyPassword; - private Text mKeyPassword2; - private Text mCnField; - private boolean mDisableOnChange = false; - private Text mOuField; - private Text mOField; - private Text mLField; - private Text mStField; - private Text mCField; - private String mDName; - private int mValidity = 0; - private List<String> mExistingAliases; - - - protected KeyCreationPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Key Creation"); - setDescription(""); // TODO? - } - - @Override - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout gl = new GridLayout(2, false); - composite.setLayout(gl); - - GridData gd; - - new Label(composite, SWT.NONE).setText("Alias:"); - mAlias = new Text(composite, SWT.BORDER); - mAlias.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("Password:"); - mKeyPassword = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeyPassword.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mKeyPassword.addVerifyListener(sPasswordVerifier); - - new Label(composite, SWT.NONE).setText("Confirm:"); - mKeyPassword2 = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeyPassword2.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mKeyPassword2.addVerifyListener(sPasswordVerifier); - - new Label(composite, SWT.NONE).setText("Validity (years):"); - final Text validityText = new Text(composite, SWT.BORDER); - validityText.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - validityText.addVerifyListener(new VerifyListener() { - @Override - public void verifyText(VerifyEvent e) { - // check for digit only. - for (int i = 0 ; i < e.text.length(); i++) { - char letter = e.text.charAt(i); - if (letter < '0' || letter > '9') { - e.doit = false; - return; - } - } - } - }); - - new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL).setLayoutData( - gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 2; - - new Label(composite, SWT.NONE).setText("First and Last Name:"); - mCnField = new Text(composite, SWT.BORDER); - mCnField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("Organizational Unit:"); - mOuField = new Text(composite, SWT.BORDER); - mOuField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("Organization:"); - mOField = new Text(composite, SWT.BORDER); - mOField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("City or Locality:"); - mLField = new Text(composite, SWT.BORDER); - mLField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("State or Province:"); - mStField = new Text(composite, SWT.BORDER); - mStField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("Country Code (XX):"); - mCField = new Text(composite, SWT.BORDER); - mCField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - // Show description the first time - setErrorMessage(null); - setMessage(null); - setControl(composite); - - mAlias.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - mWizard.setKeyAlias(mAlias.getText().trim()); - onChange(); - } - }); - mKeyPassword.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - mWizard.setKeyPassword(mKeyPassword.getText()); - onChange(); - } - }); - mKeyPassword2.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - onChange(); - } - }); - - validityText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - try { - mValidity = Integer.parseInt(validityText.getText()); - } catch (NumberFormatException e2) { - // this should only happen if the text field is empty due to the verifyListener. - mValidity = 0; - } - mWizard.setValidity(mValidity); - onChange(); - } - }); - - ModifyListener dNameListener = new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - onDNameChange(); - } - }; - - mCnField.addModifyListener(dNameListener); - mOuField.addModifyListener(dNameListener); - mOField.addModifyListener(dNameListener); - mLField.addModifyListener(dNameListener); - mStField.addModifyListener(dNameListener); - mCField.addModifyListener(dNameListener); - } - - @Override - void onShow() { - // fill the texts with information loaded from the project. - if ((mProjectDataChanged & (DATA_PROJECT | DATA_KEYSTORE)) != 0) { - // reset the keystore/alias from the content of the project - IProject project = mWizard.getProject(); - - // disable onChange for now. we'll call it once at the end. - mDisableOnChange = true; - - String alias = ProjectHelper.loadStringProperty(project, ExportWizard.PROPERTY_ALIAS); - if (alias != null) { - mAlias.setText(alias); - } - - // get the existing list of keys if applicable - if (mWizard.getKeyCreationMode()) { - mExistingAliases = mWizard.getExistingAliases(); - } else { - mExistingAliases = null; - } - - // reset the passwords - mKeyPassword.setText(""); //$NON-NLS-1$ - mKeyPassword2.setText(""); //$NON-NLS-1$ - - // enable onChange, and call it to display errors and enable/disable pageCompleted. - mDisableOnChange = false; - onChange(); - } - } - - @Override - public IWizardPage getPreviousPage() { - if (mWizard.getKeyCreationMode()) { // this means we create a key from an existing store - return mWizard.getKeySelectionPage(); - } - - return mWizard.getKeystoreSelectionPage(); - } - - @Override - public IWizardPage getNextPage() { - return mWizard.getKeyCheckPage(); - } - - /** - * Handles changes and update the error message and calls {@link #setPageComplete(boolean)}. - */ - private void onChange() { - if (mDisableOnChange) { - return; - } - - setErrorMessage(null); - setMessage(null); - - if (mAlias.getText().trim().length() == 0) { - setErrorMessage("Enter key alias."); - setPageComplete(false); - return; - } else if (mExistingAliases != null) { - // we cannot use indexOf, because we need to do a case-insensitive check - String keyAlias = mAlias.getText().trim(); - for (String alias : mExistingAliases) { - if (alias.equalsIgnoreCase(keyAlias)) { - setErrorMessage("Key alias already exists in keystore."); - setPageComplete(false); - return; - } - } - } - - String value = mKeyPassword.getText(); - if (value.length() == 0) { - setErrorMessage("Enter key password."); - setPageComplete(false); - return; - } else if (value.length() < 6) { - setErrorMessage("Key password is too short - must be at least 6 characters."); - setPageComplete(false); - return; - } - - if (value.equals(mKeyPassword2.getText()) == false) { - setErrorMessage("Key passwords don't match."); - setPageComplete(false); - return; - } - - if (mValidity == 0) { - setErrorMessage("Key certificate validity is required."); - setPageComplete(false); - return; - } else if (mValidity < 25) { - setMessage("A 25 year certificate validity is recommended.", WARNING); - } else if (mValidity > 1000) { - setErrorMessage("Key certificate validity must be between 1 and 1000 years."); - setPageComplete(false); - return; - } - - if (mDName == null || mDName.length() == 0) { - setErrorMessage("At least one Certificate issuer field is required to be non-empty."); - setPageComplete(false); - return; - } - - setPageComplete(true); - } - - /** - * Handles changes in the DName fields. - */ - private void onDNameChange() { - StringBuilder sb = new StringBuilder(); - - buildDName("CN", mCnField, sb); - buildDName("OU", mOuField, sb); - buildDName("O", mOField, sb); - buildDName("L", mLField, sb); - buildDName("ST", mStField, sb); - buildDName("C", mCField, sb); - - mDName = sb.toString(); - mWizard.setDName(mDName); - - onChange(); - } - - /** - * Builds the distinguished name string with the provided {@link StringBuilder}. - * @param prefix the prefix of the entry. - * @param textField The {@link Text} field containing the entry value. - * @param sb the string builder containing the dname. - */ - private void buildDName(String prefix, Text textField, StringBuilder sb) { - if (textField != null) { - String value = textField.getText().trim(); - if (value.length() > 0) { - if (sb.length() > 0) { - sb.append(","); - } - - sb.append(prefix); - sb.append('='); - sb.append(value); - } - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeySelectionPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeySelectionPage.java deleted file mode 100644 index 604a208e6..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeySelectionPage.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2008 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.export; - -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.util.ArrayList; -import java.util.Enumeration; - -/** - * Key Selection Page. This is used when an existing keystore is used. - */ -final class KeySelectionPage extends ExportWizardPage { - - private final ExportWizard mWizard; - private Label mKeyAliasesLabel; - private Combo mKeyAliases; - private Label mKeyPasswordLabel; - private Text mKeyPassword; - private boolean mDisableOnChange = false; - private Button mUseExistingKey; - private Button mCreateKey; - - protected KeySelectionPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Key alias selection"); - setDescription(""); // TODO - } - - @Override - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout gl = new GridLayout(3, false); - composite.setLayout(gl); - - GridData gd; - - mUseExistingKey = new Button(composite, SWT.RADIO); - mUseExistingKey.setText("Use existing key"); - mUseExistingKey.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - mUseExistingKey.setSelection(true); - - new Composite(composite, SWT.NONE).setLayoutData(gd = new GridData()); - gd.heightHint = 0; - gd.widthHint = 50; - mKeyAliasesLabel = new Label(composite, SWT.NONE); - mKeyAliasesLabel.setText("Alias:"); - mKeyAliases = new Combo(composite, SWT.READ_ONLY); - mKeyAliases.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - new Composite(composite, SWT.NONE).setLayoutData(gd = new GridData()); - gd.heightHint = 0; - gd.widthHint = 50; - mKeyPasswordLabel = new Label(composite, SWT.NONE); - mKeyPasswordLabel.setText("Password:"); - mKeyPassword = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeyPassword.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mCreateKey = new Button(composite, SWT.RADIO); - mCreateKey.setText("Create new key"); - mCreateKey.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - - // Show description the first time - setErrorMessage(null); - setMessage(null); - setControl(composite); - - mUseExistingKey.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mWizard.setKeyCreationMode(!mUseExistingKey.getSelection()); - enableWidgets(); - onChange(); - } - }); - - mKeyAliases.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mWizard.setKeyAlias(mKeyAliases.getItem(mKeyAliases.getSelectionIndex())); - onChange(); - } - }); - - mKeyPassword.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - mWizard.setKeyPassword(mKeyPassword.getText()); - onChange(); - } - }); - } - - @Override - void onShow() { - // fill the texts with information loaded from the project. - if ((mProjectDataChanged & (DATA_PROJECT | DATA_KEYSTORE)) != 0) { - // disable onChange for now. we'll call it once at the end. - mDisableOnChange = true; - - // reset the alias from the content of the project - try { - // reset to using a key - mWizard.setKeyCreationMode(false); - mUseExistingKey.setSelection(true); - mCreateKey.setSelection(false); - enableWidgets(); - - // remove the content of the alias combo always and first, in case the - // keystore password is wrong - mKeyAliases.removeAll(); - - // get the alias list (also used as a keystore password test) - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - FileInputStream fis = new FileInputStream(mWizard.getKeystore()); - keyStore.load(fis, mWizard.getKeystorePassword().toCharArray()); - fis.close(); - - Enumeration<String> aliases = keyStore.aliases(); - - // get the alias from the project previous export, and look for a match as - // we add the aliases to the combo. - IProject project = mWizard.getProject(); - - String keyAlias = ProjectHelper.loadStringProperty(project, - ExportWizard.PROPERTY_ALIAS); - - ArrayList<String> aliasList = new ArrayList<String>(); - - int selection = -1; - int count = 0; - while (aliases.hasMoreElements()) { - String alias = aliases.nextElement(); - mKeyAliases.add(alias); - aliasList.add(alias); - if (selection == -1 && alias.equalsIgnoreCase(keyAlias)) { - selection = count; - } - count++; - } - - mWizard.setExistingAliases(aliasList); - - if (selection != -1) { - mKeyAliases.select(selection); - - // since a match was found and is selected, we need to give it to - // the wizard as well - mWizard.setKeyAlias(keyAlias); - } else { - mKeyAliases.clearSelection(); - } - - // reset the password - mKeyPassword.setText(""); //$NON-NLS-1$ - - // enable onChange, and call it to display errors and enable/disable pageCompleted. - mDisableOnChange = false; - onChange(); - } catch (KeyStoreException e) { - onException(e); - } catch (FileNotFoundException e) { - onException(e); - } catch (NoSuchAlgorithmException e) { - onException(e); - } catch (CertificateException e) { - onException(e); - } catch (IOException e) { - onException(e); - } finally { - // in case we exit with an exception, we need to reset this - mDisableOnChange = false; - } - } - } - - @Override - public IWizardPage getPreviousPage() { - return mWizard.getKeystoreSelectionPage(); - } - - @Override - public IWizardPage getNextPage() { - if (mWizard.getKeyCreationMode()) { - return mWizard.getKeyCreationPage(); - } - - return mWizard.getKeyCheckPage(); - } - - /** - * Handles changes and update the error message and calls {@link #setPageComplete(boolean)}. - */ - private void onChange() { - if (mDisableOnChange) { - return; - } - - setErrorMessage(null); - setMessage(null); - - if (mWizard.getKeyCreationMode() == false) { - if (mKeyAliases.getSelectionIndex() == -1) { - setErrorMessage("Select a key alias."); - setPageComplete(false); - return; - } - - if (mKeyPassword.getText().trim().length() == 0) { - setErrorMessage("Enter key password."); - setPageComplete(false); - return; - } - } - - setPageComplete(true); - } - - private void enableWidgets() { - boolean useKey = !mWizard.getKeyCreationMode(); - mKeyAliasesLabel.setEnabled(useKey); - mKeyAliases.setEnabled(useKey); - mKeyPassword.setEnabled(useKey); - mKeyPasswordLabel.setEnabled(useKey); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeystoreSelectionPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeystoreSelectionPage.java deleted file mode 100644 index eabee15a2..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/KeystoreSelectionPage.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2008 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.export; - -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.io.File; - -/** - * Keystore selection page. This page allows to choose to create a new keystore or use an - * existing one. - */ -final class KeystoreSelectionPage extends ExportWizardPage { - - private final ExportWizard mWizard; - private Button mUseExistingKeystore; - private Button mCreateKeystore; - private Text mKeystore; - private Text mKeystorePassword; - private Label mConfirmLabel; - private Text mKeystorePassword2; - private boolean mDisableOnChange = false; - - protected KeystoreSelectionPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Keystore selection"); - setDescription(""); //TODO - } - - @Override - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout gl = new GridLayout(3, false); - composite.setLayout(gl); - - GridData gd; - - mUseExistingKeystore = new Button(composite, SWT.RADIO); - mUseExistingKeystore.setText("Use existing keystore"); - mUseExistingKeystore.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - mUseExistingKeystore.setSelection(true); - - mCreateKeystore = new Button(composite, SWT.RADIO); - mCreateKeystore.setText("Create new keystore"); - mCreateKeystore.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - - new Label(composite, SWT.NONE).setText("Location:"); - mKeystore = new Text(composite, SWT.BORDER); - mKeystore.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - final Button browseButton = new Button(composite, SWT.PUSH); - browseButton.setText("Browse..."); - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - FileDialog fileDialog; - if (mUseExistingKeystore.getSelection()) { - fileDialog = new FileDialog(browseButton.getShell(),SWT.OPEN); - fileDialog.setText("Load Keystore"); - } else { - fileDialog = new FileDialog(browseButton.getShell(),SWT.SAVE); - fileDialog.setText("Select Keystore Name"); - } - - String fileName = fileDialog.open(); - if (fileName != null) { - mKeystore.setText(fileName); - } - } - }); - - new Label(composite, SWT.NONE).setText("Password:"); - mKeystorePassword = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeystorePassword.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mKeystorePassword.addVerifyListener(sPasswordVerifier); - new Composite(composite, SWT.NONE).setLayoutData(gd = new GridData()); - gd.heightHint = gd.widthHint = 0; - - mConfirmLabel = new Label(composite, SWT.NONE); - mConfirmLabel.setText("Confirm:"); - mKeystorePassword2 = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeystorePassword2.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mKeystorePassword2.addVerifyListener(sPasswordVerifier); - new Composite(composite, SWT.NONE).setLayoutData(gd = new GridData()); - gd.heightHint = gd.widthHint = 0; - mKeystorePassword2.setEnabled(false); - - // Show description the first time - setErrorMessage(null); - setMessage(null); - setControl(composite); - - mUseExistingKeystore.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - boolean createStore = !mUseExistingKeystore.getSelection(); - mKeystorePassword2.setEnabled(createStore); - mConfirmLabel.setEnabled(createStore); - mWizard.setKeystoreCreationMode(createStore); - onChange(); - } - }); - - mKeystore.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - mWizard.setKeystore(mKeystore.getText().trim()); - onChange(); - } - }); - - mKeystorePassword.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - mWizard.setKeystorePassword(mKeystorePassword.getText()); - onChange(); - } - }); - - mKeystorePassword2.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - onChange(); - } - }); - } - - @Override - public IWizardPage getNextPage() { - if (mUseExistingKeystore.getSelection()) { - return mWizard.getKeySelectionPage(); - } - - return mWizard.getKeyCreationPage(); - } - - @Override - void onShow() { - // fill the texts with information loaded from the project. - if ((mProjectDataChanged & DATA_PROJECT) != 0) { - // reset the keystore/alias from the content of the project - IProject project = mWizard.getProject(); - - // disable onChange for now. we'll call it once at the end. - mDisableOnChange = true; - - String keystore = ProjectHelper.loadStringProperty(project, - ExportWizard.PROPERTY_KEYSTORE); - if (keystore != null) { - mKeystore.setText(keystore); - } - - // reset the passwords - mKeystorePassword.setText(""); //$NON-NLS-1$ - mKeystorePassword2.setText(""); //$NON-NLS-1$ - - // enable onChange, and call it to display errors and enable/disable pageCompleted. - mDisableOnChange = false; - onChange(); - } - } - - /** - * Handles changes and update the error message and calls {@link #setPageComplete(boolean)}. - */ - private void onChange() { - if (mDisableOnChange) { - return; - } - - setErrorMessage(null); - setMessage(null); - - boolean createStore = !mUseExistingKeystore.getSelection(); - - // checks the keystore path is non null. - String keystore = mKeystore.getText().trim(); - if (keystore.length() == 0) { - setErrorMessage("Enter path to keystore."); - setPageComplete(false); - return; - } else { - File f = new File(keystore); - if (f.exists() == false) { - if (createStore == false) { - setErrorMessage("Keystore does not exist."); - setPageComplete(false); - return; - } - } else if (f.isDirectory()) { - setErrorMessage("Keystore path is a directory."); - setPageComplete(false); - return; - } else if (f.isFile()) { - if (createStore) { - setErrorMessage("File already exists."); - setPageComplete(false); - return; - } - } - } - - String value = mKeystorePassword.getText(); - if (value.length() == 0) { - setErrorMessage("Enter keystore password."); - setPageComplete(false); - return; - } else if (createStore && value.length() < 6) { - setErrorMessage("Keystore password is too short - must be at least 6 characters."); - setPageComplete(false); - return; - } - - if (createStore) { - if (mKeystorePassword2.getText().length() == 0) { - setErrorMessage("Confirm keystore password."); - setPageComplete(false); - return; - } - - if (mKeystorePassword.getText().equals(mKeystorePassword2.getText()) == false) { - setErrorMessage("Keystore passwords do not match."); - setPageComplete(false); - return; - } - } - - setPageComplete(true); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java deleted file mode 100644 index b8a7043da..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2008 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.export; - -import com.android.ide.common.xml.ManifestData; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.internal.editors.IconFactory; -import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.NonLibraryProjectOnlyFilter; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage; - -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -/** - * First Export Wizard Page. Display warning/errors. - */ -final class ProjectCheckPage extends ExportWizardPage { - private final static String IMG_ERROR = "error.png"; //$NON-NLS-1$ - private final static String IMG_WARNING = "warning.png"; //$NON-NLS-1$ - - private final ExportWizard mWizard; - private Image mError; - private Image mWarning; - private boolean mHasMessage = false; - private Composite mTopComposite; - private Composite mErrorComposite; - private Text mProjectText; - private ProjectChooserHelper mProjectChooserHelper; - private boolean mFirstOnShow = true; - - protected ProjectCheckPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Project Checks"); - setDescription("Performs a set of checks to make sure the application can be exported."); - } - - @Override - public void createControl(Composite parent) { - mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(), - new NonLibraryProjectOnlyFilter()); - - GridLayout gl = null; - GridData gd = null; - - mTopComposite = new Composite(parent, SWT.NONE); - mTopComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); - mTopComposite.setLayout(new GridLayout(1, false)); - - // composite for the project selection. - Composite projectComposite = new Composite(mTopComposite, SWT.NONE); - projectComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - projectComposite.setLayout(gl = new GridLayout(3, false)); - gl.marginHeight = gl.marginWidth = 0; - - Label label = new Label(projectComposite, SWT.NONE); - label.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - label.setText("Select the project to export:"); - - new Label(projectComposite, SWT.NONE).setText("Project:"); - mProjectText = new Text(projectComposite, SWT.BORDER); - mProjectText.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mProjectText.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - handleProjectNameChange(); - } - }); - - Button browseButton = new Button(projectComposite, SWT.PUSH); - browseButton.setText("Browse..."); - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - IJavaProject javaProject = mProjectChooserHelper.chooseJavaProject( - mProjectText.getText().trim(), - "Please select a project to export"); - - if (javaProject != null) { - IProject project = javaProject.getProject(); - - // set the new name in the text field. The modify listener will take - // care of updating the status and the ExportWizard object. - mProjectText.setText(project.getName()); - } - } - }); - - setControl(mTopComposite); - } - - @Override - void onShow() { - if (mFirstOnShow) { - // get the project and init the ui - IProject project = mWizard.getProject(); - if (project != null) { - mProjectText.setText(project.getName()); - } - - mFirstOnShow = false; - } - } - - private void buildErrorUi(IProject project) { - // Show description the first time - setErrorMessage(null); - setMessage(null); - setPageComplete(true); - mHasMessage = false; - - // composite parent for the warning/error - GridLayout gl = null; - mErrorComposite = new Composite(mTopComposite, SWT.NONE); - mErrorComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - gl = new GridLayout(2, false); - gl.marginHeight = gl.marginWidth = 0; - gl.verticalSpacing *= 3; // more spacing than normal. - mErrorComposite.setLayout(gl); - - if (project == null) { - setErrorMessage("Select project to export."); - mHasMessage = true; - } else { - try { - if (project.hasNature(AdtConstants.NATURE_DEFAULT) == false) { - addError(mErrorComposite, "Project is not an Android project."); - } else { - // check for errors - if (ProjectHelper.hasError(project, true)) { - addError(mErrorComposite, "Project has compilation error(s)"); - } - - // check the project output - IFolder outputIFolder = BaseProjectHelper.getJavaOutputFolder(project); - if (outputIFolder == null) { - addError(mErrorComposite, - "Unable to get the output folder of the project!"); - } - - // project is an android project, we check the debuggable attribute. - ManifestData manifestData = AndroidManifestHelper.parseForData(project); - Boolean debuggable = null; - if (manifestData != null) { - debuggable = manifestData.getDebuggable(); - } - - if (debuggable != null && debuggable == Boolean.TRUE) { - addWarning(mErrorComposite, - "The manifest 'debuggable' attribute is set to true.\n" + - "You should set it to false for applications that you release to the public.\n\n" + - "Applications with debuggable=true are compiled in debug mode always."); - } - - // check for mapview stuff - } - } catch (CoreException e) { - // unable to access nature - addError(mErrorComposite, "Unable to get project nature"); - } - } - - if (mHasMessage == false) { - Label label = new Label(mErrorComposite, SWT.NONE); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - label.setLayoutData(gd); - label.setText("No errors found. Click Next."); - } - - mTopComposite.layout(); - } - - /** - * Adds an error label to a {@link Composite} object. - * @param parent the Composite parent. - * @param message the error message. - */ - private void addError(Composite parent, String message) { - if (mError == null) { - mError = IconFactory.getInstance().getIcon(IMG_ERROR); - } - - new Label(parent, SWT.NONE).setImage(mError); - Label label = new Label(parent, SWT.NONE); - label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - label.setText(message); - - setErrorMessage("Application cannot be exported due to the error(s) below."); - setPageComplete(false); - mHasMessage = true; - } - - /** - * Adds a warning label to a {@link Composite} object. - * @param parent the Composite parent. - * @param message the warning message. - */ - private void addWarning(Composite parent, String message) { - if (mWarning == null) { - mWarning = IconFactory.getInstance().getIcon(IMG_WARNING); - } - - new Label(parent, SWT.NONE).setImage(mWarning); - Label label = new Label(parent, SWT.NONE); - label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - label.setText(message); - - mHasMessage = true; - } - - /** - * Checks the parameters for correctness, and update the error message and buttons. - */ - private void handleProjectNameChange() { - setPageComplete(false); - - if (mErrorComposite != null) { - mErrorComposite.dispose(); - mErrorComposite = null; - } - - // update the wizard with the new project - mWizard.setProject(null); - - //test the project name first! - String text = mProjectText.getText().trim(); - if (text.length() == 0) { - setErrorMessage("Select project to export."); - } else if (text.matches("[a-zA-Z0-9_ \\.-]+") == false) { - setErrorMessage("Project name contains unsupported characters!"); - } else { - IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null); - IProject found = null; - for (IJavaProject javaProject : projects) { - if (javaProject.getProject().getName().equals(text)) { - found = javaProject.getProject(); - break; - } - - } - - if (found != null) { - setErrorMessage(null); - - // update the wizard with the new project - mWizard.setProject(found); - - // now rebuild the error ui. - buildErrorUi(found); - } else { - setErrorMessage(String.format("There is no android project named '%1$s'", - text)); - } - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/BuildFileCreator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/BuildFileCreator.java deleted file mode 100644 index d3df0584f..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/BuildFileCreator.java +++ /dev/null @@ -1,642 +0,0 @@ -/* - * Copyright (C) 2013 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.exportgradle; - -import static com.android.SdkConstants.GRADLE_LATEST_VERSION; -import static com.android.SdkConstants.GRADLE_PLUGIN_LATEST_VERSION; -import static com.android.SdkConstants.GRADLE_PLUGIN_NAME; -import static com.android.tools.lint.checks.GradleDetector.APP_PLUGIN_ID; -import static com.android.tools.lint.checks.GradleDetector.LIB_PLUGIN_ID; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.io.IFolderWrapper; -import com.android.io.IAbstractFile; -import com.android.sdklib.io.FileOp; -import com.android.xml.AndroidManifest; -import com.google.common.base.Charsets; -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import com.google.common.io.Closeables; -import com.google.common.io.Files; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IWorkspaceRoot; -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.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.osgi.util.NLS; -import org.eclipse.swt.widgets.Shell; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.Properties; -import java.util.Set; -import java.util.TreeSet; - -/** - * Creates build.gradle and settings.gradle files for a set of projects. - * <p> - * Based on {@link org.eclipse.ant.internal.ui.datatransfer.BuildFileCreator} - */ -public class BuildFileCreator { - static final String BUILD_FILE = "build.gradle"; //$NON-NLS-1$ - static final String SETTINGS_FILE = "settings.gradle"; //$NON-NLS-1$ - private static final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$ - private static final String GRADLE_WRAPPER_LOCATION = - "tools/templates/gradle/wrapper"; //$NON-NLS-1$ - static final String PLUGIN_CLASSPATH = - "classpath '" + GRADLE_PLUGIN_NAME + GRADLE_PLUGIN_LATEST_VERSION + "'"; //$NON-NLS-1$ - static final String MAVEN_REPOSITORY = "jcenter()"; //$NON-NLS-1$ - - private static final String[] GRADLE_WRAPPER_FILES = new String[] { - "gradlew", //$NON-NLS-1$ - "gradlew.bat", //$NON-NLS-1$ - "gradle/wrapper/gradle-wrapper.jar", //$NON-NLS-1$ - "gradle/wrapper/gradle-wrapper.properties" //$NON-NLS-1$ - }; - - private static final Comparator<IFile> FILE_COMPARATOR = new Comparator<IFile>() { - @Override - public int compare(IFile o1, IFile o2) { - return o1.toString().compareTo(o2.toString()); - } - }; - - private final GradleModule mModule; - private final StringBuilder mBuildFile = new StringBuilder(); - - /** - * Create buildfile for the projects. - * - * @param shell parent instance for dialogs - * @return project names for which buildfiles were created - * @throws InterruptedException thrown when user cancels task - */ - public static void createBuildFiles( - @NonNull ProjectSetupBuilder builder, - @NonNull Shell shell, - @NonNull IProgressMonitor pm) { - - File gradleLocation = new File(Sdk.getCurrent().getSdkOsLocation(), GRADLE_WRAPPER_LOCATION); - SubMonitor localmonitor = null; - - try { - // See if we have a Gradle wrapper in the SDK templates directory. If so, we can copy - // it over. - boolean hasGradleWrapper = true; - for (File wrapperFile : getGradleWrapperFiles(gradleLocation)) { - if (!wrapperFile.exists()) { - hasGradleWrapper = false; - } - } - - Collection<GradleModule> modules = builder.getModules(); - boolean multiModules = modules.size() > 1; - - // determine files to create/change - List<IFile> files = new ArrayList<IFile>(); - - // add the build.gradle file for all modules. - for (GradleModule module : modules) { - // build.gradle file - IFile file = module.getProject().getFile(BuildFileCreator.BUILD_FILE); - files.add(file); - } - - // get the commonRoot for all modules. If only one module, this returns the path - // of the project. - IPath commonRoot = builder.getCommonRoot(); - - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - IPath workspaceLocation = workspaceRoot.getLocation(); - - IPath relativePath = commonRoot.makeRelativeTo(workspaceLocation); - // if makeRelativePath to returns the same path, then commonRoot is not in the - // workspace. - boolean rootInWorkspace = !relativePath.equals(commonRoot); - // we only care if the root is a workspace project. if it's the workspace folder itself, - // then the files won't be handled by the workspace. - rootInWorkspace = rootInWorkspace && relativePath.segmentCount() > 0; - - File settingsFile = new File(commonRoot.toFile(), SETTINGS_FILE); - - // more than one modules -> generate settings.gradle - if (multiModules && rootInWorkspace) { - - // Locate the settings.gradle file and add it to the changed files list - IPath settingsGradle = Path.fromOSString(settingsFile.getAbsolutePath()); - - // different path, means commonRoot is inside the workspace, which means we have - // to add settings.gradle and wrapper files to the list of files to add. - IFile iFile = workspaceRoot.getFile(settingsGradle); - if (iFile != null) { - files.add(iFile); - } - } - - // Gradle wrapper files - if (hasGradleWrapper && rootInWorkspace) { - // See if there already wrapper files there and only mark nonexistent ones for - // creation. - for (File wrapperFile : getGradleWrapperFiles(commonRoot.toFile())) { - if (!wrapperFile.exists()) { - IPath path = Path.fromOSString(wrapperFile.getAbsolutePath()); - IFile file = workspaceRoot.getFile(path); - files.add(file); - } - } - } - - ExportStatus status = new ExportStatus(); - builder.setStatus(status); - - // Trigger checkout of changed files - Set<IFile> confirmedFiles = validateEdit(files, status, shell); - - if (status.hasError()) { - return; - } - - // Now iterate over all the modules and generate the build files. - localmonitor = SubMonitor.convert(pm, ExportMessages.PageTitle, - confirmedFiles.size()); - List<String> projectSettingsPath = Lists.newArrayList(); - for (GradleModule currentModule : modules) { - IProject moduleProject = currentModule.getProject(); - - IFile file = moduleProject.getFile(BuildFileCreator.BUILD_FILE); - if (!confirmedFiles.contains(file)) { - continue; - } - - localmonitor.setTaskName(NLS.bind(ExportMessages.FileStatusMessage, - moduleProject.getName())); - - ProjectState projectState = Sdk.getProjectState(moduleProject); - BuildFileCreator instance = new BuildFileCreator(currentModule, shell); - if (projectState != null) { - // This is an Android project - if (!multiModules) { - instance.appendBuildScript(); - } - instance.appendHeader(projectState.isLibrary()); - instance.appendDependencies(); - instance.startAndroidTask(projectState); - //instance.appendDefaultConfig(); - instance.createAndroidSourceSets(); - instance.finishAndroidTask(); - } else { - // This is a plain Java project - instance.appendJavaHeader(); - instance.createJavaSourceSets(); - } - - try { - // Write the build file - String buildfile = instance.mBuildFile.toString(); - InputStream is = - new ByteArrayInputStream(buildfile.getBytes("UTF-8")); //$NON-NLS-1$ - if (file.exists()) { - file.setContents(is, true, true, null); - } else { - file.create(is, true, null); - } - } catch (Exception e) { - status.addFileStatus(ExportStatus.FileStatus.IO_FAILURE, - file.getLocation().toFile()); - status.setErrorMessage(e.getMessage()); - return; - } - - if (localmonitor.isCanceled()) { - return; - } - localmonitor.worked(1); - - // get the project path to add it to the settings.gradle. - projectSettingsPath.add(currentModule.getPath()); - } - - // write the settings file. - if (multiModules) { - try { - writeGradleSettingsFile(settingsFile, projectSettingsPath); - } catch (IOException e) { - status.addFileStatus(ExportStatus.FileStatus.IO_FAILURE, settingsFile); - status.setErrorMessage(e.getMessage()); - return; - } - File mainBuildFile = new File(commonRoot.toFile(), BUILD_FILE); - try { - writeRootBuildGradle(mainBuildFile); - } catch (IOException e) { - status.addFileStatus(ExportStatus.FileStatus.IO_FAILURE, mainBuildFile); - status.setErrorMessage(e.getMessage()); - return; - } - } - - // finally write the wrapper - // TODO check we can based on where it is - if (hasGradleWrapper) { - copyGradleWrapper(gradleLocation, commonRoot.toFile(), status); - if (status.hasError()) { - return; - } - } - - } finally { - if (localmonitor != null && !localmonitor.isCanceled()) { - localmonitor.done(); - } - if (pm != null) { - pm.done(); - } - } - } - - /** - * @param GradleModule create buildfile for this project - * @param shell parent instance for dialogs - */ - private BuildFileCreator(GradleModule module, Shell shell) { - mModule = module; - } - - /** - * Return the files that comprise the Gradle wrapper as a collection of {@link File} instances. - * @param root - * @return - */ - private static List<File> getGradleWrapperFiles(File root) { - List<File> files = new ArrayList<File>(GRADLE_WRAPPER_FILES.length); - for (String file : GRADLE_WRAPPER_FILES) { - files.add(new File(root, file)); - } - return files; - } - - /** - * Copy the Gradle wrapper files from one directory to another. - */ - private static void copyGradleWrapper(File from, File to, ExportStatus status) { - for (String file : GRADLE_WRAPPER_FILES) { - File dest = new File(to, file); - try { - File src = new File(from, file); - dest.getParentFile().mkdirs(); - new FileOp().copyFile(src, dest); - - if (src.getName().equals(GRADLE_PROPERTIES)) { - updateGradleDistributionUrl(GRADLE_LATEST_VERSION, dest); - } - dest.setExecutable(src.canExecute()); - status.addFileStatus(ExportStatus.FileStatus.OK, dest); - } catch (IOException e) { - status.addFileStatus(ExportStatus.FileStatus.IO_FAILURE, dest); - return; - } - } - } - - /** - * Outputs boilerplate buildscript information common to all Gradle build files. - */ - private void appendBuildScript() { - appendBuildScript(mBuildFile); - } - - /** - * Outputs boilerplate header information common to all Gradle build files. - */ - private static void appendBuildScript(StringBuilder builder) { - builder.append("buildscript {\n"); //$NON-NLS-1$ - builder.append(" repositories {\n"); //$NON-NLS-1$ - builder.append(" " + MAVEN_REPOSITORY + "\n"); //$NON-NLS-1$ - builder.append(" }\n"); //$NON-NLS-1$ - builder.append(" dependencies {\n"); //$NON-NLS-1$ - builder.append(" " + PLUGIN_CLASSPATH + "\n"); //$NON-NLS-1$ - builder.append(" }\n"); //$NON-NLS-1$ - builder.append("}\n"); //$NON-NLS-1$ - } - - /** - * Outputs boilerplate header information common to all Gradle build files. - */ - private void appendHeader(boolean isLibrary) { - if (isLibrary) { - mBuildFile.append("apply plugin: '").append(LIB_PLUGIN_ID).append("'\n"); //$NON-NLS-1$ //$NON-NLS-2$ - } else { - mBuildFile.append("apply plugin: '").append(APP_PLUGIN_ID).append("'\n"); //$NON-NLS-1$ //$NON-NLS-2$ - } - mBuildFile.append("\n"); //$NON-NLS-1$ - } - - /** - * Outputs a block which sets up library and project dependencies. - */ - private void appendDependencies() { - mBuildFile.append("dependencies {\n"); //$NON-NLS-1$ - - // first the local jars. - // TODO: Fix - mBuildFile.append(" compile fileTree(dir: 'libs', include: '*.jar')\n"); //$NON-NLS-1$ - - for (GradleModule dep : mModule.getDependencies()) { - mBuildFile.append(" compile project('" + dep.getPath() + "')\n"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - mBuildFile.append("}\n"); //$NON-NLS-1$ - mBuildFile.append("\n"); //$NON-NLS-1$ - } - - /** - * Outputs the beginning of an Android task in the build file. - */ - private void startAndroidTask(ProjectState projectState) { - int buildApi = projectState.getTarget().getVersion().getApiLevel(); - String toolsVersion = projectState.getTarget().getBuildToolInfo().getRevision().toString(); - mBuildFile.append("android {\n"); //$NON-NLS-1$ - mBuildFile.append(" compileSdkVersion " + buildApi + "\n"); //$NON-NLS-1$ - mBuildFile.append(" buildToolsVersion \"" + toolsVersion + "\"\n"); //$NON-NLS-1$ - mBuildFile.append("\n"); //$NON-NLS-1$ - - try { - IJavaProject javaProject = BaseProjectHelper.getJavaProject(projectState.getProject()); - // otherwise we check source compatibility - String source = javaProject.getOption(JavaCore.COMPILER_SOURCE, true); - if (JavaCore.VERSION_1_7.equals(source)) { - mBuildFile.append( - " compileOptions {\n" + //$NON-NLS-1$ - " sourceCompatibility JavaVersion.VERSION_1_7\n" + //$NON-NLS-1$ - " targetCompatibility JavaVersion.VERSION_1_7\n" + //$NON-NLS-1$ - " }\n" + //$NON-NLS-1$ - "\n"); //$NON-NLS-1$ - } - } catch (CoreException e) { - // Ignore compliance level, go with default - } - } - - /** - * Outputs a sourceSets block to the Android task that locates all of the various source - * subdirectories in the project. - */ - private void createAndroidSourceSets() { - IFolderWrapper projectFolder = new IFolderWrapper(mModule.getProject()); - IAbstractFile mManifestFile = AndroidManifest.getManifest(projectFolder); - if (mManifestFile == null) { - return; - } - List<String> srcDirs = new ArrayList<String>(); - for (IClasspathEntry entry : mModule.getJavaProject().readRawClasspath()) { - if (entry.getEntryKind() != IClasspathEntry.CPE_SOURCE || - SdkConstants.FD_GEN_SOURCES.equals(entry.getPath().lastSegment())) { - continue; - } - IPath path = entry.getPath().removeFirstSegments(1); - srcDirs.add("'" + path.toOSString() + "'"); //$NON-NLS-1$ - } - - String srcPaths = Joiner.on(",").join(srcDirs); - - mBuildFile.append(" sourceSets {\n"); //$NON-NLS-1$ - mBuildFile.append(" main {\n"); //$NON-NLS-1$ - mBuildFile.append(" manifest.srcFile '" + SdkConstants.FN_ANDROID_MANIFEST_XML + "'\n"); //$NON-NLS-1$ - mBuildFile.append(" java.srcDirs = [" + srcPaths + "]\n"); //$NON-NLS-1$ - mBuildFile.append(" resources.srcDirs = [" + srcPaths + "]\n"); //$NON-NLS-1$ - mBuildFile.append(" aidl.srcDirs = [" + srcPaths + "]\n"); //$NON-NLS-1$ - mBuildFile.append(" renderscript.srcDirs = [" + srcPaths + "]\n"); //$NON-NLS-1$ - mBuildFile.append(" res.srcDirs = ['res']\n"); //$NON-NLS-1$ - mBuildFile.append(" assets.srcDirs = ['assets']\n"); //$NON-NLS-1$ - mBuildFile.append(" }\n"); //$NON-NLS-1$ - mBuildFile.append("\n"); //$NON-NLS-1$ - mBuildFile.append(" // Move the tests to tests/java, tests/res, etc...\n"); //$NON-NLS-1$ - mBuildFile.append(" instrumentTest.setRoot('tests')\n"); //$NON-NLS-1$ - if (srcDirs.contains("'src'")) { - mBuildFile.append("\n"); //$NON-NLS-1$ - mBuildFile.append(" // Move the build types to build-types/<type>\n"); //$NON-NLS-1$ - mBuildFile.append(" // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...\n"); //$NON-NLS-1$ - mBuildFile.append(" // This moves them out of them default location under src/<type>/... which would\n"); //$NON-NLS-1$ - mBuildFile.append(" // conflict with src/ being used by the main source set.\n"); //$NON-NLS-1$ - mBuildFile.append(" // Adding new build types or product flavors should be accompanied\n"); //$NON-NLS-1$ - mBuildFile.append(" // by a similar customization.\n"); //$NON-NLS-1$ - mBuildFile.append(" debug.setRoot('build-types/debug')\n"); //$NON-NLS-1$ - mBuildFile.append(" release.setRoot('build-types/release')\n"); //$NON-NLS-1$ - } - mBuildFile.append(" }\n"); //$NON-NLS-1$ - } - - /** - * Outputs the completion of the Android task in the build file. - */ - private void finishAndroidTask() { - mBuildFile.append("}\n"); //$NON-NLS-1$ - } - - /** - * Outputs a boilerplate header for non-Android projects - */ - private void appendJavaHeader() { - mBuildFile.append("apply plugin: 'java'\n"); //$NON-NLS-1$ - } - - /** - * Outputs a sourceSets block for non-Android projects to locate the source directories. - */ - private void createJavaSourceSets() { - List<String> dirs = new ArrayList<String>(); - for (IClasspathEntry entry : mModule.getJavaProject().readRawClasspath()) { - if (entry.getEntryKind() != IClasspathEntry.CPE_SOURCE) { - continue; - } - IPath path = entry.getPath().removeFirstSegments(1); - dirs.add("'" + path.toOSString() + "'"); //$NON-NLS-1$ - } - - String srcPaths = Joiner.on(",").join(dirs); - - mBuildFile.append("sourceSets {\n"); //$NON-NLS-1$ - mBuildFile.append(" main.java.srcDirs = [" + srcPaths + "]\n"); //$NON-NLS-1$ - mBuildFile.append(" main.resources.srcDirs = [" + srcPaths + "]\n"); //$NON-NLS-1$ - mBuildFile.append(" test.java.srcDirs = ['tests/java']\n"); //$NON-NLS-1$ - mBuildFile.append(" test.resources.srcDirs = ['tests/resources']\n"); //$NON-NLS-1$ - mBuildFile.append("}\n"); //$NON-NLS-1$ - } - - /** - * Merges the new subproject dependencies into the settings.gradle file if it already exists, - * and creates one if it does not. - * @throws IOException - */ - private static void writeGradleSettingsFile(File settingsFile, List<String> projectPaths) - throws IOException { - StringBuilder contents = new StringBuilder(); - for (String path : projectPaths) { - contents.append("include '").append(path).append("'\n"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - Files.write(contents.toString(), settingsFile, Charsets.UTF_8); - } - - private static void writeRootBuildGradle(File buildFile) throws IOException { - StringBuilder sb = new StringBuilder( - "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n"); - - appendBuildScript(sb); - - Files.write(sb.toString(), buildFile, Charsets.UTF_8); - } - - /** - * Request write access to given files. Depending on the version control - * plug-in opens a confirm checkout dialog. - * - * @param shell - * parent instance for dialogs - * @return <code>IFile</code> objects for which user confirmed checkout - * @throws CoreException - * thrown if project is under version control, but not connected - */ - static Set<IFile> validateEdit( - @NonNull List<IFile> files, - @NonNull ExportStatus exportStatus, - @NonNull Shell shell) { - Set<IFile> confirmedFiles = new TreeSet<IFile>(FILE_COMPARATOR); - if (files.size() == 0) { - return confirmedFiles; - } - IStatus status = (files.get(0)).getWorkspace().validateEdit( - files.toArray(new IFile[files.size()]), shell); - if (status.isMultiStatus() && status.getChildren().length > 0) { - for (int i = 0; i < status.getChildren().length; i++) { - IStatus statusChild = status.getChildren()[i]; - if (statusChild.isOK()) { - confirmedFiles.add(files.get(i)); - } else { - exportStatus.addFileStatus( - ExportStatus.FileStatus.VCS_FAILURE, - files.get(i).getLocation().toFile()); - } - } - } else if (status.isOK()) { - confirmedFiles.addAll(files); - } - if (status.getSeverity() == IStatus.ERROR) { - // not possible to checkout files: not connected to version - // control plugin or hijacked files and made read-only, so - // collect error messages provided by validator and re-throw - StringBuffer message = new StringBuffer(status.getPlugin() + ": " //$NON-NLS-1$ - + status.getMessage() + NEWLINE); - if (status.isMultiStatus()) { - for (int i = 0; i < status.getChildren().length; i++) { - IStatus statusChild = status.getChildren()[i]; - message.append(statusChild.getMessage() + NEWLINE); - } - } - String s = message.toString(); - exportStatus.setErrorMessage(s); - } - - return confirmedFiles; - } - - // ------------------------------------------------------------------------------- - // Fix gradle wrapper version. This code is from GradleUtil in the Studio plugin: - // ------------------------------------------------------------------------------- - - private static final String GRADLE_PROPERTIES = "gradle-wrapper.properties"; - private static final String GRADLEW_PROPERTIES_PATH = - "gradle" + File.separator + "wrapper" + File.separator + GRADLE_PROPERTIES; - private static final String GRADLEW_DISTRIBUTION_URL_PROPERTY_NAME = "distributionUrl"; - - @NonNull - private static File getGradleWrapperPropertiesFilePath(@NonNull File projectRootDir) { - return new File(projectRootDir, GRADLEW_PROPERTIES_PATH); - } - - @Nullable - public static File findWrapperPropertiesFile(@NonNull File projectRootDir) { - File wrapperPropertiesFile = getGradleWrapperPropertiesFilePath(projectRootDir); - return wrapperPropertiesFile.isFile() ? wrapperPropertiesFile : null; - } - - private static boolean updateGradleDistributionUrl( - @NonNull String gradleVersion, - @NonNull File propertiesFile) throws IOException { - Properties properties = loadGradleWrapperProperties(propertiesFile); - String gradleDistributionUrl = getGradleDistributionUrl(gradleVersion, false); - String property = properties.getProperty(GRADLEW_DISTRIBUTION_URL_PROPERTY_NAME); - if (property != null - && (property.equals(gradleDistributionUrl) || property - .equals(getGradleDistributionUrl(gradleVersion, true)))) { - return false; - } - properties.setProperty(GRADLEW_DISTRIBUTION_URL_PROPERTY_NAME, gradleDistributionUrl); - FileOutputStream out = null; - try { - out = new FileOutputStream(propertiesFile); - properties.store(out, null); - return true; - } finally { - Closeables.close(out, true); - } - } - - @NonNull - private static Properties loadGradleWrapperProperties(@NonNull File propertiesFile) - throws IOException { - Properties properties = new Properties(); - FileInputStream fileInputStream = null; - try { - fileInputStream = new FileInputStream(propertiesFile); - properties.load(fileInputStream); - return properties; - } finally { - Closeables.close(fileInputStream, true); - } - } - - @NonNull - private static String getGradleDistributionUrl(@NonNull String gradleVersion, - boolean binOnly) { - String suffix = binOnly ? "bin" : "all"; - return String.format("https://services.gradle.org/distributions/gradle-%1$s-" + suffix - + ".zip", gradleVersion); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ConfirmationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ConfirmationPage.java deleted file mode 100644 index 1f236fb2b..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ConfirmationPage.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2013 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.exportgradle; - -import com.google.common.collect.Lists; - -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TableLayout; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.model.WorkbenchLabelProvider; - -import java.io.File; -import java.util.Collection; -import java.util.List; - -/** - * Confirmation page to review the actual project export - * list and see warning about existing files. - * - */ -public class ConfirmationPage extends WizardPage { - - private final ProjectSetupBuilder mBuilder; - private TableViewer mTableViewer; - private Label mModuleDescription1; - private Label mModuleDescription2; - private Label mModuleDescription3; - private Label mProjectRootLabel; - private Label mProjectRootWarning; - private List<IJavaProject> mOverrideProjects; - private boolean mOverrideWarning; - private Button mForceOverride; - - public ConfirmationPage(ProjectSetupBuilder builder) { - super("ConfirmationPage"); //$NON-NLS-1$ - mBuilder = builder; - setPageComplete(false); - setTitle(ExportMessages.PageTitle); - setDescription(ExportMessages.PageDescription); - } - - @Override - public void createControl(Composite parent) { - initializeDialogUnits(parent); - GridData data; - - Composite workArea = new Composite(parent, SWT.NONE); - setControl(workArea); - - workArea.setLayout(new GridLayout()); - workArea.setLayoutData(new GridData(GridData.FILL_BOTH - | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL)); - - Label title = new Label(workArea, SWT.NONE); - title.setText("Please review the export options."); - - Group group = new Group(workArea, SWT.NONE); - group.setText("Project root"); - group.setLayout(new GridLayout()); - group.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); - - mProjectRootLabel = new Label(group, SWT.NONE); - mProjectRootLabel.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); - - mProjectRootWarning = new Label(group, SWT.NONE); - mProjectRootWarning.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); - - Group group2 = new Group(workArea, SWT.NONE); - group2.setText("Exported Modules"); - group2.setLayout(new GridLayout()); - group2.setLayoutData(data = new GridData(SWT.FILL, SWT.FILL, true, true)); - data.heightHint = 300; - - Table table = new Table(group2, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); - mTableViewer = new TableViewer(table); - table.setLayout(new TableLayout()); - table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - mTableViewer.setContentProvider(new IStructuredContentProvider() { - @Override - public Object[] getElements(Object inputElement) { - if (inputElement instanceof ProjectSetupBuilder) { - ProjectSetupBuilder builder = (ProjectSetupBuilder) inputElement; - Collection<GradleModule> modules = builder.getModules(); - Object[] array = new Object[modules.size()]; - int i = 0; - for (GradleModule module : modules) { - array[i++] = module.getJavaProject(); - } - - return array; - } - - return null; - } - - @Override - public void dispose() { - } - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - }); - mTableViewer.setLabelProvider(new WorkbenchLabelProvider() { - @Override - protected String decorateText(String input, Object element) { - if (element instanceof IJavaProject) { - IJavaProject javaProject = (IJavaProject) element; - StringBuilder sb = new StringBuilder(input); - if (!mBuilder.isOriginalProject(javaProject)) { - sb.append('*'); - } - // TODO: decorate icon instead? - if (mOverrideProjects.contains(javaProject)) { - sb.append(" (1 warning)"); - } - - return sb.toString(); - } - - return input; - } - }); - mTableViewer.addSelectionChangedListener(new ISelectionChangedListener() { - @Override - public void selectionChanged(SelectionChangedEvent event) { - IStructuredSelection selection = (IStructuredSelection) event.getSelection(); - Object firstElement = selection.getFirstElement(); - if (firstElement instanceof IJavaProject) { - GradleModule module = mBuilder.getModule((IJavaProject) firstElement); - if (mBuilder.getOriginalModules().contains(module)) { - mModuleDescription1.setText("Exported because selected in previous page."); - } else { - List<GradleModule> list = mBuilder.getShortestDependencyTo(module); - StringBuilder sb = new StringBuilder(); - for (GradleModule m : list) { - if (sb.length() > 0) { - sb.append(" > "); - } - sb.append(m.getJavaProject().getProject().getName()); - } - mModuleDescription1.setText("Dependency chain: " + sb); - } - mModuleDescription2.setText("Path: " + module.getPath()); - - if (mOverrideProjects.contains(module.getJavaProject())) { - mModuleDescription3.setText( - "WARNING: build.gradle already exists for this project"); - } else { - mModuleDescription3.setText(""); - } - } else { - mModuleDescription1.setText(""); - mModuleDescription2.setText(""); - mModuleDescription3.setText(""); - } - } - }); - - mModuleDescription1 = new Label(group2, SWT.NONE); - mModuleDescription1.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); - mModuleDescription2 = new Label(group2, SWT.NONE); - mModuleDescription2.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); - mModuleDescription3 = new Label(group2, SWT.NONE); - mModuleDescription3.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); - - mForceOverride = new Button(workArea, SWT.CHECK); - mForceOverride.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false)); - mForceOverride.setText("Force overriding of existing files"); - mForceOverride.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - updateEnablement(); - } - }); - - setControl(workArea); - Dialog.applyDialogFont(parent); - } - - /** - * Get list of projects which have already a buildfile. - * - * @param javaProjects list of IJavaProject objects - * @return set of project names - */ - private void computeOverride(String commonRoot) { - mOverrideProjects = Lists.newArrayList(); - for (GradleModule module : mBuilder.getModules()) { - if (new File(module.getProject().getLocation().toFile(), - BuildFileCreator.BUILD_FILE).exists()) { - mOverrideProjects.add(module.getJavaProject()); - } - } - - // also check on the root settings.gradle/build.gradle - boolean settingsFile = new File(commonRoot, BuildFileCreator.SETTINGS_FILE).exists(); - boolean buildFile = new File(commonRoot, BuildFileCreator.BUILD_FILE).exists(); - if (settingsFile && buildFile) { - mProjectRootWarning.setText( - "WARNING: build.gradle/settings.gradle already exists at this location."); - } else if (settingsFile) { - mProjectRootWarning.setText( - "WARNING: settings.gradle already exists at this location."); - } else if (buildFile) { - mProjectRootWarning.setText("WARNING: build.gradle already exists at this location."); - } - - mOverrideWarning = mOverrideProjects.size() > 0 || settingsFile || buildFile; - } - - /** - * Enables/disables the finish button on the wizard and displays error messages as needed. - */ - private void updateEnablement() { - if (mOverrideWarning && !mForceOverride.getSelection()) { - setErrorMessage("Enable overriding of existing files before clicking Finish"); - mBuilder.setCanGenerate(false); - } else { - setErrorMessage(null); - mBuilder.setCanGenerate(true); - } - setPageComplete(false); - getContainer().updateButtons(); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - if (visible) { - mProjectRootWarning.setText(""); - - String commonRoot = mBuilder.getCommonRoot().toOSString(); - computeOverride(commonRoot); - mProjectRootLabel.setText(commonRoot); - mTableViewer.setInput(mBuilder); - mTableViewer.getTable().setFocus(); - mBuilder.setCanFinish(false); - mBuilder.setCanGenerate(true); - updateEnablement(); - } - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.java deleted file mode 100644 index c7d6c1748..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2013 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.exportgradle; - -import org.eclipse.osgi.util.NLS; - -public class ExportMessages extends NLS { - private static final String BUNDLE_NAME = - "com.android.ide.eclipse.adt.internal.wizards.exportgradle.ExportMessages";//$NON-NLS-1$ - - public static String PageTitle; - public static String PageDescription; - public static String SelectProjects; - public static String ConfirmOverwrite; - public static String ConfirmOverwriteTitle; - public static String CyclicProjectsError; - public static String ExportFailedError; - public static String SelectAll; - public static String DeselectAll; - public static String NoProjectsError; - public static String StatusMessage; - public static String FileStatusMessage; - public static String WindowTitle; - - static { - // load message values from bundle file - NLS.initializeMessages(BUNDLE_NAME, ExportMessages.class); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.properties deleted file mode 100644 index 1a6dbb192..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportMessages.properties +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (C) 2013 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. - -PageTitle=Generate Gradle Build files -PageDescription=Generates Gradle build files based on the configuration of the Java projects -SelectProjects=Select the projects to use to &generate the Gradle buildfiles: -ConfirmOverwrite=Are you sure you want to overwrite the buildfiles for these projects? -ConfirmOverwriteTitle=Overwrite Buildfiles? -CyclicProjectsError=A cycle was detected in the build path of project: {0} -ExportFailedError=Buildfile export failed: {0}. See the error log for more details. -SelectAll=&Select All -DeselectAll=&Deselect All -NoProjectsError=Select one or more projects to export. -StatusMessage=Creating Gradle build files... -FileStatusMessage=Generating build file for {0}... -WindowTitle=Export
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportStatus.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportStatus.java deleted file mode 100644 index 6fbe14e42..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ExportStatus.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2013 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.exportgradle; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Multimap; - -import java.io.File; - -public class ExportStatus { - - public static enum FileStatus { OK, VCS_FAILURE, IO_FAILURE; } - - private String mMainError = null; - private final Multimap<FileStatus, File> mFileStatus = ArrayListMultimap.create(); - - void addFileStatus(@NonNull FileStatus status, @NonNull File file) { - mFileStatus.put(status, file); - } - - boolean hasError() { - return mMainError != null || - !mFileStatus.get(FileStatus.VCS_FAILURE).isEmpty() || - !mFileStatus.get(FileStatus.IO_FAILURE).isEmpty(); - } - - public void setErrorMessage(String error) { - mMainError = error; - } - - @Nullable - public String getErrorMessage() { - return mMainError; - } - - @NonNull - public Multimap<FileStatus, File> getFileStatus() { - return mFileStatus; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/FinalPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/FinalPage.java deleted file mode 100644 index bbfadf855..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/FinalPage.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2013 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.exportgradle; - -import com.android.ide.eclipse.adt.internal.wizards.exportgradle.ExportStatus.FileStatus; -import com.google.common.collect.Multimap; - -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; - -import java.io.File; -import java.util.Collection; - -/** - * Final page to review the result of the export. - */ -public class FinalPage extends WizardPage { - - private final ProjectSetupBuilder mBuilder; - private ExportStatus mStatus; - - private Text mText; - - public FinalPage(ProjectSetupBuilder builder) { - super("FinalPage"); //$NON-NLS-1$ - mBuilder = builder; - setPageComplete(true); - setTitle(ExportMessages.PageTitle); - setDescription(ExportMessages.PageDescription); - } - - @Override - public void createControl(Composite parent) { - initializeDialogUnits(parent); - - mText = new Text(parent, SWT.MULTI | SWT.READ_ONLY); - mText.setLayoutData(new GridData(GridData.FILL_BOTH - | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL)); - - setControl(mText); - Dialog.applyDialogFont(parent); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - if (visible) { - mStatus = mBuilder.getStatus(); - mBuilder.setCanFinish(!mStatus.hasError()); - mBuilder.setCanGenerate(false); - - StringBuilder sb = new StringBuilder(); - if (mStatus.hasError()) { - sb.append("There was an error!").append("\n\n"); - - String errorMsg = mStatus.getErrorMessage(); - if (errorMsg != null) { - sb.append(errorMsg); - } - - Multimap<FileStatus, File> fileStatusMap = mStatus.getFileStatus(); - Collection<File> files = fileStatusMap.values(); - if (files != null) { - sb.append("\n\n").append("Error on files:").append('\n'); - for (File file : files) { - sb.append("\n").append(file.getAbsolutePath()); - } - } - } else { - sb.append("Export successful.\n\n"); - - int count = mBuilder.getModuleCount(); - if (count > 1) { - sb.append(String.format("Exported %s modules", count)).append('\n'); - sb.append(String.format( - "Root folder: %s", mBuilder.getCommonRoot().toOSString())); - } else { - sb.append("Exported project: ").append(mBuilder.getCommonRoot().toOSString()); - } - - sb.append("\n\n").append("Choose 'Import Non-Android Studio project' in Android Studio").append('\n'); - sb.append("and select the following file:").append("\n\t"); - - File bGradle = new File( - mBuilder.getCommonRoot().toFile(), BuildFileCreator.BUILD_FILE); - sb.append(bGradle.getAbsolutePath()); - - sb.append("\n\n").append("Do NOT import the Eclipse project itself!"); - } - - mText.setText(sb.toString()); - } - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportWizard.java deleted file mode 100644 index 8c74187ff..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleExportWizard.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2013 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.exportgradle; - -import com.android.ide.eclipse.adt.AdtPlugin; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.ui.IExportWizard; -import org.eclipse.ui.IWorkbench; - -import java.lang.reflect.InvocationTargetException; -import java.util.Collection; - -public class GradleExportWizard extends Wizard implements IExportWizard { - - private ProjectSetupBuilder mBuilder = new ProjectSetupBuilder(); - - private ProjectSelectionPage mFirstPage; - private ConfirmationPage mSecondPage; - private FinalPage mFinalPage; - - /** - * Creates buildfile. - */ - @Override - public boolean performFinish() { - if (mBuilder.canGenerate()) { - generateBuildfiles(mSecondPage); - getContainer().showPage(mFinalPage); - return false; - } - - return true; - } - - @Override - public void addPages() { - addPage(new ImportInsteadPage()); - mFirstPage = new ProjectSelectionPage(mBuilder); - addPage(mFirstPage); - mSecondPage = new ConfirmationPage(mBuilder); - addPage(mSecondPage); - mFinalPage = new FinalPage(mBuilder); - addPage(mFinalPage); - } - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - setWindowTitle(ExportMessages.WindowTitle); - setNeedsProgressMonitor(true); - } - - @Override - public boolean canFinish() { - return mBuilder.canFinish() || mBuilder.canGenerate(); - } - - /** - * Converts Eclipse Java projects to Gradle build files. Displays error dialogs. - */ - public boolean generateBuildfiles(final WizardPage page) { - IRunnableWithProgress runnable = new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor pm) throws InterruptedException { - Collection<GradleModule> modules = mBuilder.getModules(); - final int count = modules.size(); - - SubMonitor localmonitor = SubMonitor.convert(pm, ExportMessages.StatusMessage, - count); - BuildFileCreator.createBuildFiles( - mBuilder, - page.getShell(), - localmonitor.newChild(count)); - } - }; - - try { - getContainer().run(false, false, runnable); - } catch (InvocationTargetException e) { - AdtPlugin.log(e, null); - return false; - } catch (InterruptedException e) { - AdtPlugin.log(e, null); - return false; - } - if (page.getErrorMessage() != null) { - return false; - } - return true; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleModule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleModule.java deleted file mode 100644 index 684f03b9a..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/GradleModule.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2013 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.exportgradle; - -import com.android.annotations.NonNull; -import com.google.common.collect.Lists; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jdt.core.IJavaProject; - -import java.util.List; - -/** - * A configured Gradle module for export. This includes gradle path, dependency, type, etc... - */ -public class GradleModule { - - @NonNull - private final IJavaProject mJavaProject; - - private String mPath; - private Type mType; - - private final List<GradleModule> mDependencies = Lists.newArrayList(); - - public static enum Type { ANDROID, JAVA }; - - GradleModule(@NonNull IJavaProject javaProject) { - mJavaProject = javaProject; - } - - @NonNull - public IJavaProject getJavaProject() { - return mJavaProject; - } - - @NonNull - public IProject getProject() { - return mJavaProject.getProject(); - } - - boolean isConfigured() { - return mType != null; - } - - public void setType(Type type) { - mType = type; - } - - public Type getType() { - return mType; - } - - public void addDependency(GradleModule module) { - mDependencies.add(module); - } - - public List<GradleModule> getDependencies() { - return mDependencies; - } - - public void setPath(String path) { - mPath = path; - } - - public String getPath() { - return mPath; - } - - @Override - public String toString() { - return "GradleModule [mJavaProject=" + mJavaProject + ", mPath=" + mPath + ", mType=" - + mType + ", mDependencies=" + mDependencies + "]"; - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ImportInsteadPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ImportInsteadPage.java deleted file mode 100644 index cff9aca63..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ImportInsteadPage.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2014 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.exportgradle; - -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.CLabel; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; - -class ImportInsteadPage extends WizardPage { - public ImportInsteadPage() { - super("importInstead"); - setTitle("Import Instead?"); - setDescription("Consider importing directly into Android Studio instead of exporting from Eclipse"); - } - - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - setControl(container); - container.setLayout(new GridLayout(1, false)); - - CLabel label = new CLabel(container, SWT.NONE); - label.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 1, 1)); - label.setText( - "Recent versions of Android Studio now support direct import of ADT projects.\n" + - "\n" + - "There are advantages to importing from Studio instead of exporting from Eclipse:\n" + - "- It can replace jars and library projects with Gradle dependencies instead\n" + - "- On import, it creates a new copy of the project and changes the project structure\n" + - " to the new Gradle directory layout which better supports multiple resource directories.\n" + - "- It can merge instrumentation test projects into the same project\n" + - "- Android Studio is released more frequently than the ADT plugin, so the import\n" + - " mechanism more closely tracks the requirements of Studio Gradle projects.\n" + - "\n" + - "If you want to preserve your Eclipse directory structure, or if for some reason import\n" + - "in Studio doesn't work (please let us know by filing a bug), continue to export from\n" + - "Eclipse instead."); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ProjectSelectionPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ProjectSelectionPage.java deleted file mode 100644 index 81c7a7346..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ProjectSelectionPage.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2013 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.exportgradle; - -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import com.ibm.icu.text.MessageFormat; - -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaModelMarker; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.viewers.CheckStateChangedEvent; -import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.ICheckStateListener; -import org.eclipse.jface.viewers.TableLayout; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.eclipse.ui.model.WorkbenchContentProvider; -import org.eclipse.ui.model.WorkbenchLabelProvider; - -import java.util.ArrayList; -import java.util.List; - -/** - * Displays a wizard page that lets the user choose the projects for which to create Gradle build - * files. - * <p> - * Based on {@link org.eclipse.ant.internal.ui.datatransfer.AntBuildfileExportPage} - */ -public class ProjectSelectionPage extends WizardPage { - - private final ProjectSetupBuilder mBuilder; - private CheckboxTableViewer mTableViewer; - private List<IJavaProject> mSelectedJavaProjects = Lists.newArrayList(); - - public ProjectSelectionPage(ProjectSetupBuilder builder) { - super("GradleExportPage"); //$NON-NLS-1$ - mBuilder = builder; - setPageComplete(false); - setTitle(ExportMessages.PageTitle); - setDescription(ExportMessages.PageDescription); - } - - @Override - public void createControl(Composite parent) { - initializeDialogUnits(parent); - - Composite workArea = new Composite(parent, SWT.NONE); - setControl(workArea); - - workArea.setLayout(new GridLayout()); - workArea.setLayoutData(new GridData(GridData.FILL_BOTH - | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL)); - - Label title = new Label(workArea, SWT.NONE); - title.setText(ExportMessages.SelectProjects); - - Composite listComposite = new Composite(workArea, SWT.NONE); - GridLayout layout = new GridLayout(); - layout.numColumns = 2; - layout.marginWidth = 0; - layout.makeColumnsEqualWidth = false; - listComposite.setLayout(layout); - - listComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL - | GridData.GRAB_VERTICAL | GridData.FILL_BOTH)); - - Table table = new Table(listComposite, - SWT.CHECK | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); - mTableViewer = new CheckboxTableViewer(table); - table.setLayout(new TableLayout()); - GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); - data.heightHint = 300; - table.setLayoutData(data); - mTableViewer.setContentProvider(new WorkbenchContentProvider() { - @Override - public Object[] getElements(Object element) { - if (element instanceof IJavaProject[]) { - return (IJavaProject[]) element; - } - return null; - } - }); - mTableViewer.setLabelProvider(new WorkbenchLabelProvider()); - mTableViewer.addCheckStateListener(new ICheckStateListener() { - @Override - public void checkStateChanged(CheckStateChangedEvent event) { - if (event.getChecked()) { - mSelectedJavaProjects.add((IJavaProject) event.getElement()); - } else { - mSelectedJavaProjects.remove(event.getElement()); - } - updateEnablement(); - } - }); - - initializeProjects(); - createSelectionButtons(listComposite); - setControl(workArea); - updateEnablement(); - Dialog.applyDialogFont(parent); - } - - /** - * Creates select all/deselect all buttons. - */ - private void createSelectionButtons(Composite composite) { - Composite buttonsComposite = new Composite(composite, SWT.NONE); - GridLayout layout = new GridLayout(); - layout.marginWidth = 0; - layout.marginHeight = 0; - buttonsComposite.setLayout(layout); - - buttonsComposite.setLayoutData(new GridData( - GridData.VERTICAL_ALIGN_BEGINNING)); - - Button selectAll = new Button(buttonsComposite, SWT.PUSH); - selectAll.setText(ExportMessages.SelectAll); - selectAll.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - for (int i = 0; i < mTableViewer.getTable().getItemCount(); i++) { - mSelectedJavaProjects.add((IJavaProject) mTableViewer.getElementAt(i)); - } - mTableViewer.setAllChecked(true); - updateEnablement(); - } - }); - setButtonLayoutData(selectAll); - - Button deselectAll = new Button(buttonsComposite, SWT.PUSH); - deselectAll.setText(ExportMessages.DeselectAll); - deselectAll.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mSelectedJavaProjects.clear(); - mTableViewer.setAllChecked(false); - updateEnablement(); - } - }); - setButtonLayoutData(deselectAll); - } - - /** - * Populates the list with all the eligible projects in the workspace. - */ - private void initializeProjects() { - IWorkspaceRoot rootWorkspace = ResourcesPlugin.getWorkspace().getRoot(); - IJavaModel javaModel = JavaCore.create(rootWorkspace); - IJavaProject[] javaProjects; - try { - javaProjects = javaModel.getJavaProjects(); - } catch (JavaModelException e) { - javaProjects = new IJavaProject[0]; - } - mTableViewer.setInput(javaProjects); - // Check any necessary projects - if (mSelectedJavaProjects != null) { - mTableViewer.setCheckedElements(mSelectedJavaProjects.toArray( - new IJavaProject[mSelectedJavaProjects.size()])); - } - } - - /** - * Enables/disables the finish button on the wizard and displays error messages as needed. - */ - private void updateEnablement() { - String error = null; - try { - if (mSelectedJavaProjects.size() == 0) { - error = ExportMessages.NoProjectsError; - return; - } - - List<String> cyclicProjects; - try { - cyclicProjects = getCyclicProjects(mSelectedJavaProjects); - if (cyclicProjects.size() > 0) { - error = MessageFormat.format(ExportMessages.CyclicProjectsError, - new Object[] { Joiner.on(", ").join(cyclicProjects) }); //$NON-NLS-1$ - return; - } - - error = mBuilder.setProject(mSelectedJavaProjects); - if (error != null) { - return; - } - - } catch (CoreException ignored) { - // TODO: do something? - } - } finally { - setErrorMessage(error); - setPageComplete(error == null); - getContainer().updateButtons(); - } - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - if (visible) { - mTableViewer.getTable().setFocus(); - mBuilder.setCanFinish(false); - mBuilder.setCanGenerate(false); - } - } - - /** - * Returns given projects that have cyclic dependencies. - * - * @param javaProjects list of IJavaProject objects - * @return set of project names - */ - private List<String> getCyclicProjects(List<IJavaProject> projects) throws CoreException { - - List<String> cyclicProjects = new ArrayList<String>(); - for (IJavaProject javaProject : projects) { - if (hasCyclicDependency(javaProject)) { - cyclicProjects.add(javaProject.getProject().getName()); - } - } - return cyclicProjects; - } - - /** - * Check if given project has a cyclic dependency. - * <p> - * See {@link org.eclipse.jdt.core.tests.model.ClasspathTests.numberOfCycleMarkers} - */ - private static boolean hasCyclicDependency(IJavaProject javaProject) - throws CoreException { - IMarker[] markers = javaProject.getProject().findMarkers( - IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, - IResource.DEPTH_ONE); - for (IMarker marker : markers) { - String cycleAttr = (String) marker - .getAttribute(IJavaModelMarker.CYCLE_DETECTED); - if (cycleAttr != null && cycleAttr.equals("true")) { //$NON-NLS-1$ - return true; - } - } - return false; - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ProjectSetupBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ProjectSetupBuilder.java deleted file mode 100644 index 1fd6b74f6..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/exportgradle/ProjectSetupBuilder.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (C) 2013 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.exportgradle; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState.LibraryState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import org.eclipse.core.resources.IProject; -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.Path; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; - -import java.io.File; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -/** - * Class to setup the project and its modules. - */ -public class ProjectSetupBuilder { - - private final static class InternalException extends Exception { - private static final long serialVersionUID = 1L; - - InternalException(String message) { - super(message); - } - } - - private boolean mCanFinish = false; - private boolean mCanGenerate = false; - private final List<GradleModule> mOriginalModules = Lists.newArrayList(); - private final Map<IJavaProject, GradleModule> mModules = Maps.newHashMap(); - private IPath mCommonRoot; - private ExportStatus mStatus; - - public ProjectSetupBuilder() { - - } - - public void setCanGenerate(boolean generate) { - mCanGenerate = generate; - } - - public void setCanFinish(boolean canFinish) { - mCanFinish = canFinish; - } - - public boolean canFinish() { - return mCanFinish; - } - - public boolean canGenerate() { - return mCanGenerate; - } - - public void setStatus(ExportStatus status) { - mStatus = status; - } - - public ExportStatus getStatus() { - return mStatus; - } - - @NonNull - public String setProject(@NonNull List<IJavaProject> selectedProjects) - throws CoreException { - mModules.clear(); - - // build a list of all projects that must be included. This is in case - // some dependencies have not been included in the selected projects. We also include - // parent projects so that the full multi-project setup is correct. - // Note that if two projects are selected that are not related, both will be added - // in the same multi-project anyway. - try { - for (IJavaProject javaProject : selectedProjects) { - GradleModule module; - - if (javaProject.getProject().hasNature(AdtConstants.NATURE_DEFAULT)) { - module = processAndroidProject(javaProject); - } else { - module = processJavaProject(javaProject); - } - - mOriginalModules.add(module); - } - - Collection<GradleModule> modules = mModules.values(); - computeRootAndPaths(modules); - - return null; - } catch (InternalException e) { - return e.getMessage(); - } - } - - @NonNull - public Collection<GradleModule> getModules() { - return mModules.values(); - } - - public int getModuleCount() { - return mModules.size(); - } - - @Nullable - public IPath getCommonRoot() { - return mCommonRoot; - } - - @Nullable - public GradleModule getModule(IJavaProject javaProject) { - return mModules.get(javaProject); - } - - public boolean isOriginalProject(@NonNull IJavaProject javaProject) { - GradleModule module = mModules.get(javaProject); - return mOriginalModules.contains(module); - } - - @NonNull - public List<GradleModule> getOriginalModules() { - return mOriginalModules; - } - - @Nullable - public List<GradleModule> getShortestDependencyTo(GradleModule module) { - return findModule(module, mOriginalModules); - } - - @Nullable - public List<GradleModule> findModule(GradleModule toFind, GradleModule rootModule) { - if (toFind == rootModule) { - List<GradleModule> list = Lists.newArrayList(); - list.add(toFind); - return list; - } - - List<GradleModule> shortestChain = findModule(toFind, rootModule.getDependencies()); - - if (shortestChain != null) { - shortestChain.add(0, rootModule); - } - - return shortestChain; - } - - @Nullable - public List<GradleModule> findModule(GradleModule toFind, List<GradleModule> modules) { - List<GradleModule> currentChain = null; - - for (GradleModule child : modules) { - List<GradleModule> newChain = findModule(toFind, child); - if (currentChain == null) { - currentChain = newChain; - } else if (newChain != null) { - if (currentChain.size() > newChain.size()) { - currentChain = newChain; - } - } - } - - return currentChain; - } - - @NonNull - private GradleModule processAndroidProject(@NonNull IJavaProject javaProject) - throws InternalException, CoreException { - - // get/create the module - GradleModule module = createModuleOnDemand(javaProject); - if (module.isConfigured()) { - return module; - } - - module.setType(GradleModule.Type.ANDROID); - - ProjectState projectState = Sdk.getProjectState(javaProject.getProject()); - assert projectState != null; - - // add library project dependencies - List<LibraryState> libraryProjects = projectState.getLibraries(); - for (LibraryState libraryState : libraryProjects) { - ProjectState libProjectState = libraryState.getProjectState(); - if (libProjectState != null) { - IJavaProject javaLib = getJavaProject(libProjectState); - if (javaLib != null) { - GradleModule libModule = processAndroidProject(javaLib); - module.addDependency(libModule); - } else { - throw new InternalException(String.format( - "Project %1$s is missing. Needed by %2$s.\n" + - "Make sure all dependencies are opened.", - libraryState.getRelativePath(), - javaProject.getProject().getName())); - } - } else { - throw new InternalException(String.format( - "Project %1$s is missing. Needed by %2$s.\n" + - "Make sure all dependencies are opened.", - libraryState.getRelativePath(), - javaProject.getProject().getName())); - } - } - - // add java project dependencies - List<IJavaProject> javaDepProjects = getReferencedProjects(javaProject); - for (IJavaProject javaDep : javaDepProjects) { - GradleModule libModule = processJavaProject(javaDep); - module.addDependency(libModule); - } - - return module; - } - - @NonNull - private GradleModule processJavaProject(@NonNull IJavaProject javaProject) - throws InternalException, CoreException { - // get/create the module - GradleModule module = createModuleOnDemand(javaProject); - - if (module.isConfigured()) { - return module; - } - - module.setType(GradleModule.Type.JAVA); - - // add java project dependencies - List<IJavaProject> javaDepProjects = getReferencedProjects(javaProject); - for (IJavaProject javaDep : javaDepProjects) { - // Java project should not reference Android project! - if (javaDep.getProject().hasNature(AdtConstants.NATURE_DEFAULT)) { - throw new InternalException(String.format( - "Java project %1$s depends on Android project %2$s!\n" + - "This is not a valid dependency", - javaProject.getProject().getName(), javaDep.getProject().getName())); - } - GradleModule libModule = processJavaProject(javaDep); - module.addDependency(libModule); - } - - return module; - } - - private void computeRootAndPaths(Collection<GradleModule> modules) throws InternalException { - // compute the common root. - mCommonRoot = determineCommonRoot(modules); - - // compute all the relative paths. - for (GradleModule module : modules) { - String path = getGradlePath(module.getJavaProject().getProject().getLocation(), - mCommonRoot); - - module.setPath(path); - } - } - - /** - * Finds the common parent directory shared by this project and all its dependencies. - * If there's only one project, returns the single project's folder. - * @throws InternalException - */ - @NonNull - private static IPath determineCommonRoot(Collection<GradleModule> modules) - throws InternalException { - IPath commonRoot = null; - for (GradleModule module : modules) { - if (commonRoot == null) { - commonRoot = module.getJavaProject().getProject().getLocation(); - } else { - commonRoot = findCommonRoot(commonRoot, - module.getJavaProject().getProject().getLocation()); - } - } - - return commonRoot; - } - - /** - * Converts the given path to be relative to the given root path, and converts it to - * Gradle project notation, such as is used in the settings.gradle file. - */ - @NonNull - private static String getGradlePath(IPath path, IPath root) { - IPath relativePath = path.makeRelativeTo(root); - String relativeString = relativePath.toOSString(); - return ":" + relativeString.replaceAll(Pattern.quote(File.separator), ":"); //$NON-NLS-1$ - } - - /** - * Given two IPaths, finds the parent directory of both of them. - * @throws InternalException - */ - @NonNull - private static IPath findCommonRoot(@NonNull IPath path1, @NonNull IPath path2) - throws InternalException { - if (path1.getDevice() != null && !path1.getDevice().equals(path2.getDevice())) { - throw new InternalException( - "Different modules have been detected on different drives.\n" + - "This prevents finding a common root to all modules."); - } - - IPath result = path1.uptoSegment(0); - - final int count = Math.min(path1.segmentCount(), path2.segmentCount()); - for (int i = 0; i < count; i++) { - if (path1.segment(i).equals(path2.segment(i))) { - result = result.append(Path.SEPARATOR + path2.segment(i)); - } - } - return result; - } - - @Nullable - private IJavaProject getJavaProject(ProjectState projectState) { - try { - return BaseProjectHelper.getJavaProject(projectState.getProject()); - } catch (CoreException e) { - return null; - } - } - - @NonNull - private GradleModule createModuleOnDemand(@NonNull IJavaProject javaProject) { - GradleModule module = mModules.get(javaProject); - if (module == null) { - module = new GradleModule(javaProject); - mModules.put(javaProject, module); - } - - return module; - } - - @NonNull - private static List<IJavaProject> getReferencedProjects(IJavaProject javaProject) - throws JavaModelException, InternalException { - - List<IJavaProject> projects = Lists.newArrayList(); - - IClasspathEntry entries[] = javaProject.getRawClasspath(); - for (IClasspathEntry classpathEntry : entries) { - if (classpathEntry.getContentKind() == IPackageFragmentRoot.K_SOURCE - && classpathEntry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { - // found required project on build path - String subProjectRoot = classpathEntry.getPath().toString(); - IJavaProject subProject = getJavaProject(subProjectRoot); - // is project available in workspace? - if (subProject != null) { - projects.add(subProject); - } else { - throw new InternalException(String.format( - "Project '%s' is missing project dependency '%s' in Eclipse workspace.\n" + - "Make sure all dependencies are opened.", - javaProject.getProject().getName(), - classpathEntry.getPath().toString())); - } - } - } - - return projects; - } - - /** - * Get Java project for given root. - */ - @Nullable - private static IJavaProject getJavaProject(String root) { - IPath path = new Path(root); - if (path.segmentCount() == 1) { - return getJavaProjectByName(root); - } - IResource resource = ResourcesPlugin.getWorkspace().getRoot() - .findMember(path); - if (resource != null && resource.getType() == IResource.PROJECT) { - if (resource.exists()) { - return (IJavaProject) JavaCore.create(resource); - } - } - return null; - } - - /** - * Get Java project from resource. - */ - private static IJavaProject getJavaProjectByName(String name) { - try { - IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(name); - if (project.exists()) { - return JavaCore.create(project); - } - } catch (IllegalArgumentException iae) { - } - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ApplicationInfoPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ApplicationInfoPage.java deleted file mode 100644 index c8325345a..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ApplicationInfoPage.java +++ /dev/null @@ -1,809 +0,0 @@ -/* - * Copyright (C) 2011 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.newproject; - -import com.android.SdkConstants; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener; -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.filesystem.URIUtil; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -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.jdt.core.JavaConventions; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.io.File; -import java.io.FileFilter; -import java.net.URI; - -/** Page where you choose the application name, activity name, and optional test project info */ -public class ApplicationInfoPage extends WizardPage implements SelectionListener, ModifyListener, - ITargetChangeListener { - private static final String JDK_15 = "1.5"; //$NON-NLS-1$ - private final static String DUMMY_PACKAGE = "your.package.namespace"; - - /** Suffix added by default to activity names */ - static final String ACTIVITY_NAME_SUFFIX = "Activity"; //$NON-NLS-1$ - - private final NewProjectWizardState mValues; - - private Text mApplicationText; - private Text mPackageText; - private Text mActivityText; - private Button mCreateActivityCheckbox; - private Combo mSdkCombo; - - private boolean mIgnore; - private Button mCreateTestCheckbox; - private Text mTestProjectNameText; - private Text mTestApplicationText; - private Text mTestPackageText; - private Label mTestProjectNameLabel; - private Label mTestApplicationLabel; - private Label mTestPackageLabel; - - /** - * Create the wizard. - */ - ApplicationInfoPage(NewProjectWizardState values) { - super("appInfo"); //$NON-NLS-1$ - mValues = values; - - setTitle("Application Info"); - setDescription("Configure the new Android Project"); - AdtPlugin.getDefault().addTargetListener(this); - } - - /** - * Create contents of the wizard. - */ - @Override - @SuppressWarnings("unused") // Eclipse marks SWT constructors with side effects as unused - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - container.setLayout(new GridLayout(2, false)); - - Label applicationLabel = new Label(container, SWT.NONE); - applicationLabel.setText("Application Name:"); - - mApplicationText = new Text(container, SWT.BORDER); - mApplicationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mApplicationText.addModifyListener(this); - - Label packageLabel = new Label(container, SWT.NONE); - packageLabel.setText("Package Name:"); - - mPackageText = new Text(container, SWT.BORDER); - mPackageText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mPackageText.addModifyListener(this); - - if (mValues.mode != Mode.TEST) { - mCreateActivityCheckbox = new Button(container, SWT.CHECK); - mCreateActivityCheckbox.setText("Create Activity:"); - mCreateActivityCheckbox.addSelectionListener(this); - - mActivityText = new Text(container, SWT.BORDER); - mActivityText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mActivityText.addModifyListener(this); - } - - Label minSdkLabel = new Label(container, SWT.NONE); - minSdkLabel.setText("Minimum SDK:"); - - mSdkCombo = new Combo(container, SWT.NONE); - GridData gdSdkCombo = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); - gdSdkCombo.widthHint = 200; - mSdkCombo.setLayoutData(gdSdkCombo); - mSdkCombo.addSelectionListener(this); - mSdkCombo.addModifyListener(this); - - onSdkLoaded(); - - setControl(container); - new Label(container, SWT.NONE); - new Label(container, SWT.NONE); - - mCreateTestCheckbox = new Button(container, SWT.CHECK); - mCreateTestCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); - mCreateTestCheckbox.setText("Create a Test Project"); - mCreateTestCheckbox.addSelectionListener(this); - - mTestProjectNameLabel = new Label(container, SWT.NONE); - mTestProjectNameLabel.setText("Test Project Name:"); - - mTestProjectNameText = new Text(container, SWT.BORDER); - mTestProjectNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mTestProjectNameText.addModifyListener(this); - - mTestApplicationLabel = new Label(container, SWT.NONE); - mTestApplicationLabel.setText("Test Application:"); - - mTestApplicationText = new Text(container, SWT.BORDER); - mTestApplicationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mTestApplicationText.addModifyListener(this); - - mTestPackageLabel = new Label(container, SWT.NONE); - mTestPackageLabel.setText("Test Package:"); - - mTestPackageText = new Text(container, SWT.BORDER); - mTestPackageText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mTestPackageText.addModifyListener(this); - } - - /** Controls whether the options for creating a paired test project should be shown */ - private void showTestOptions(boolean visible) { - if (mValues.mode == Mode.SAMPLE) { - visible = false; - } - - mCreateTestCheckbox.setVisible(visible); - mTestProjectNameLabel.setVisible(visible); - mTestProjectNameText.setVisible(visible); - mTestApplicationLabel.setVisible(visible); - mTestApplicationText.setVisible(visible); - mTestPackageLabel.setVisible(visible); - mTestPackageText.setVisible(visible); - } - - /** Controls whether the options for creating a paired test project should be enabled */ - private void enableTestOptions(boolean enabled) { - mTestProjectNameLabel.setEnabled(enabled); - mTestProjectNameText.setEnabled(enabled); - mTestApplicationLabel.setEnabled(enabled); - mTestApplicationText.setEnabled(enabled); - mTestPackageLabel.setEnabled(enabled); - mTestPackageText.setEnabled(enabled); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - - if (visible) { - try { - mIgnore = true; - if (mValues.applicationName != null) { - mApplicationText.setText(mValues.applicationName); - } - if (mValues.packageName != null) { - mPackageText.setText(mValues.packageName); - } else { - mPackageText.setText(DUMMY_PACKAGE); - } - - if (mValues.mode != Mode.TEST) { - mCreateActivityCheckbox.setSelection(mValues.createActivity); - mActivityText.setEnabled(mValues.createActivity); - if (mValues.activityName != null) { - mActivityText.setText(mValues.activityName); - } - } - if (mValues.minSdk != null && mValues.minSdk.length() > 0) { - mSdkCombo.setText(mValues.minSdk); - } - - showTestOptions(mValues.mode == Mode.ANY); - enableTestOptions(mCreateTestCheckbox.getSelection()); - - if (mValues.testProjectName != null) { - mTestProjectNameText.setText(mValues.testProjectName); - } - if (mValues.testApplicationName != null) { - mTestApplicationText.setText(mValues.testApplicationName); - } - if (mValues.testProjectName != null) { - mTestPackageText.setText(mValues.testProjectName); - } - } finally { - mIgnore = false; - } - } - - // Start focus with the package name, since the other fields are typically assigned - // reasonable defaults - mPackageText.setFocus(); - mPackageText.selectAll(); - - validatePage(); - } - - protected void setSdkTargets(IAndroidTarget[] targets, IAndroidTarget target) { - if (targets == null) { - targets = new IAndroidTarget[0]; - } - int selectionIndex = -1; - String[] items = new String[targets.length]; - for (int i = 0, n = targets.length; i < n; i++) { - items[i] = targetLabel(targets[i]); - if (targets[i] == target) { - selectionIndex = i; - } - } - try { - mIgnore = true; - mSdkCombo.setItems(items); - mSdkCombo.setData(targets); - if (selectionIndex != -1) { - mSdkCombo.select(selectionIndex); - } - } finally { - mIgnore = false; - } - } - - private String targetLabel(IAndroidTarget target) { - // In the minimum SDK chooser, show the targets with api number and description, - // such as "11 (Android 3.0)" - return String.format("%1$s (%2$s)", target.getVersion().getApiString(), - target.getFullName()); - } - - @Override - public void dispose() { - AdtPlugin.getDefault().removeTargetListener(this); - super.dispose(); - } - - @Override - public boolean isPageComplete() { - // This page is only needed when creating new projects - if (mValues.useExisting || mValues.mode != Mode.ANY) { - return true; - } - - // Ensure that we reach this page - if (mValues.packageName == null) { - return false; - } - - return super.isPageComplete(); - } - - @Override - public void modifyText(ModifyEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source == mSdkCombo) { - mValues.minSdk = mSdkCombo.getText().trim(); - IAndroidTarget[] targets = (IAndroidTarget[]) mSdkCombo.getData(); - // An editable combo will treat item selection the same way as a user edit, - // so we need to see if the string looks like a labeled version - int index = mSdkCombo.getSelectionIndex(); - if (index != -1) { - if (index >= 0 && index < targets.length) { - IAndroidTarget target = targets[index]; - if (targetLabel(target).equals(mValues.minSdk)) { - mValues.minSdk = target.getVersion().getApiString(); - } - } - } - - // Ensure that we never pick up the (Android x.y) suffix shown in combobox - // for readability - int separator = mValues.minSdk.indexOf(' '); - if (separator != -1) { - mValues.minSdk = mValues.minSdk.substring(0, separator); - } - mValues.minSdkModifiedByUser = true; - mValues.updateSdkTargetToMatchMinSdkVersion(); - } else if (source == mApplicationText) { - mValues.applicationName = mApplicationText.getText().trim(); - mValues.applicationNameModifiedByUser = true; - - if (!mValues.testApplicationNameModified) { - mValues.testApplicationName = suggestTestApplicationName(mValues.applicationName); - try { - mIgnore = true; - mTestApplicationText.setText(mValues.testApplicationName); - } finally { - mIgnore = false; - } - } - - } else if (source == mPackageText) { - mValues.packageName = mPackageText.getText().trim(); - mValues.packageNameModifiedByUser = true; - - if (!mValues.testPackageModified) { - mValues.testPackageName = suggestTestPackage(mValues.packageName); - try { - mIgnore = true; - mTestPackageText.setText(mValues.testPackageName); - } finally { - mIgnore = false; - } - } - } else if (source == mActivityText) { - mValues.activityName = mActivityText.getText().trim(); - mValues.activityNameModifiedByUser = true; - } else if (source == mTestApplicationText) { - mValues.testApplicationName = mTestApplicationText.getText().trim(); - mValues.testApplicationNameModified = true; - } else if (source == mTestPackageText) { - mValues.testPackageName = mTestPackageText.getText().trim(); - mValues.testPackageModified = true; - } else if (source == mTestProjectNameText) { - mValues.testProjectName = mTestProjectNameText.getText().trim(); - mValues.testProjectModified = true; - } - - validatePage(); - } - - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - - if (source == mCreateActivityCheckbox) { - mValues.createActivity = mCreateActivityCheckbox.getSelection(); - mActivityText.setEnabled(mValues.createActivity); - } else if (source == mSdkCombo) { - int index = mSdkCombo.getSelectionIndex(); - IAndroidTarget[] targets = (IAndroidTarget[]) mSdkCombo.getData(); - if (index != -1) { - if (index >= 0 && index < targets.length) { - IAndroidTarget target = targets[index]; - // Even though we are showing the logical version name, we place the - // actual api number as the minimum SDK - mValues.minSdk = target.getVersion().getApiString(); - } - } else { - String text = mSdkCombo.getText(); - boolean found = false; - for (IAndroidTarget target : targets) { - if (targetLabel(target).equals(text)) { - mValues.minSdk = target.getVersion().getApiString(); - found = true; - break; - } - } - if (!found) { - mValues.minSdk = text; - } - } - } else if (source == mCreateTestCheckbox) { - mValues.createPairProject = mCreateTestCheckbox.getSelection(); - enableTestOptions(mValues.createPairProject); - if (mValues.createPairProject) { - if (mValues.testProjectName == null || mValues.testProjectName.length() == 0) { - mValues.testProjectName = suggestTestProjectName(mValues.projectName); - } - if (mValues.testApplicationName == null || - mValues.testApplicationName.length() == 0) { - mValues.testApplicationName = - suggestTestApplicationName(mValues.applicationName); - } - if (mValues.testPackageName == null || mValues.testPackageName.length() == 0) { - mValues.testPackageName = suggestTestPackage(mValues.packageName); - } - - try { - mIgnore = true; - mTestProjectNameText.setText(mValues.testProjectName); - mTestApplicationText.setText(mValues.testApplicationName); - mTestPackageText.setText(mValues.testPackageName); - } finally { - mIgnore = false; - } - } - } - - validatePage(); - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - private void validatePage() { - IStatus status = validatePackage(mValues.packageName); - if (status == null || status.getSeverity() != IStatus.ERROR) { - IStatus validActivity = validateActivity(); - if (validActivity != null) { - status = validActivity; - } - } - if (status == null || status.getSeverity() != IStatus.ERROR) { - IStatus validMinSdk = validateMinSdk(); - if (validMinSdk != null) { - status = validMinSdk; - } - } - - if (status == null || status.getSeverity() != IStatus.ERROR) { - IStatus validSourceFolder = validateSourceFolder(); - if (validSourceFolder != null) { - status = validSourceFolder; - } - } - - // If creating a test project to go along with the main project, also validate - // the additional test project parameters - if (status == null || status.getSeverity() != IStatus.ERROR) { - if (mValues.createPairProject) { - IStatus validTestProject = ProjectNamePage.validateProjectName( - mValues.testProjectName); - if (validTestProject != null) { - status = validTestProject; - } - - if (status == null || status.getSeverity() != IStatus.ERROR) { - IStatus validTestLocation = validateTestProjectLocation(); - if (validTestLocation != null) { - status = validTestLocation; - } - } - - if (status == null || status.getSeverity() != IStatus.ERROR) { - IStatus validTestPackage = validatePackage(mValues.testPackageName); - if (validTestPackage != null) { - status = new Status(validTestPackage.getSeverity(), - AdtPlugin.PLUGIN_ID, - validTestPackage.getMessage() + " (in test package)"); - } - } - - if (status == null || status.getSeverity() != IStatus.ERROR) { - if (mValues.projectName.equals(mValues.testProjectName)) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "The main project name and the test project name must be different."); - } - } - } - } - - // -- update UI & enable finish if there's no error - setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); - if (status != null) { - setMessage(status.getMessage(), - status.getSeverity() == IStatus.ERROR - ? IMessageProvider.ERROR : IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - private IStatus validateTestProjectLocation() { - assert mValues.createPairProject; - - // Validate location - Path path = new Path(mValues.projectLocation.getPath()); - if (!mValues.useExisting) { - if (!mValues.useDefaultLocation) { - // If not using the default value validate the location. - URI uri = URIUtil.toURI(path.toOSString()); - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IProject handle = workspace.getRoot().getProject(mValues.testProjectName); - IStatus locationStatus = workspace.validateProjectLocationURI(handle, uri); - if (!locationStatus.isOK()) { - return locationStatus; - } - // The location is valid as far as Eclipse is concerned (i.e. mostly not - // an existing workspace project.) Check it either doesn't exist or is - // a directory that is empty. - File f = path.toFile(); - if (f.exists() && !f.isDirectory()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "A directory name must be specified."); - } else if (f.isDirectory()) { - // However if the directory exists, we should put a - // warning if it is not empty. We don't put an error - // (we'll ask the user again for confirmation before - // using the directory.) - String[] l = f.list(); - if (l != null && l.length != 0) { - return new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, - "The selected output directory is not empty."); - } - } - } else { - IPath destPath = path.removeLastSegments(1).append(mValues.testProjectName); - File dest = destPath.toFile(); - if (dest.exists()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format( - "There is already a file or directory named \"%1$s\" in the selected location.", - mValues.testProjectName)); - } - } - } - - return null; - } - - private IStatus validateSourceFolder() { - // This check does nothing when creating a new project. - // This check is also useless when no activity is present or created. - mValues.sourceFolder = SdkConstants.FD_SOURCES; - if (!mValues.useExisting || !mValues.createActivity) { - return null; - } - - String osTarget = mValues.activityName; - if (osTarget.indexOf('.') == -1) { - osTarget = mValues.packageName + File.separator + osTarget; - } else if (osTarget.indexOf('.') == 0) { - osTarget = mValues.packageName + osTarget; - } - osTarget = osTarget.replace('.', File.separatorChar) + SdkConstants.DOT_JAVA; - - File projectDir = mValues.projectLocation; - File[] allDirs = projectDir.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.isDirectory(); - } - }); - if (allDirs != null) { - boolean found = false; - for (File f : allDirs) { - Path path = new Path(f.getAbsolutePath()); - File java_activity = path.append(osTarget).toFile(); - if (java_activity.isFile()) { - mValues.sourceFolder = f.getName(); - found = true; - break; - } - } - - if (!found) { - String projectPath = projectDir.getPath(); - if (allDirs.length > 0) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("%1$s can not be found under %2$s.", osTarget, - projectPath)); - } else { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("No source folders can be found in %1$s.", - projectPath)); - } - } - } - - return null; - } - - private IStatus validateMinSdk() { - // Validate min SDK field - // If the min sdk version is empty, it is always accepted. - if (mValues.minSdk == null || mValues.minSdk.length() == 0) { - return null; - } - - IAndroidTarget target = mValues.target; - if (target == null) { - return null; - } - - // If the current target is a preview, explicitly indicate minSdkVersion - // must be set to this target name. - if (target.getVersion().isPreview() && !target.getVersion().equals(mValues.minSdk)) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format( - "The SDK target is a preview. Min SDK Version must be set to '%s'.", - target.getVersion().getCodename())); - } - - if (!target.getVersion().equals(mValues.minSdk)) { - return new Status(target.getVersion().isPreview() ? IStatus.ERROR : IStatus.WARNING, - AdtPlugin.PLUGIN_ID, - "The API level for the selected SDK target does not match the Min SDK Version." - ); - } - - return null; - } - - public static IStatus validatePackage(String packageFieldContents) { - // Validate package - if (packageFieldContents == null || packageFieldContents.length() == 0) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Package name must be specified."); - } else if (packageFieldContents.equals(DUMMY_PACKAGE)) { - // The dummy package name is just a placeholder package (which isn't even valid - // because it contains the reserved Java keyword "package") but we want to - // make the error message say that a proper package should be entered rather than - // what's wrong with this specific package. (And the reason we provide a dummy - // package rather than a blank line is to make it more clear to beginners what - // we're looking for. - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Package name must be specified."); - } - // Check it's a valid package string - IStatus status = JavaConventions.validatePackageName(packageFieldContents, JDK_15, - JDK_15); - if (!status.isOK()) { - return status; - } - - // The Android Activity Manager does not accept packages names with only one - // identifier. Check the package name has at least one dot in them (the previous rule - // validated that if such a dot exist, it's not the first nor last characters of the - // string.) - if (packageFieldContents.indexOf('.') == -1) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Package name must have at least two identifiers."); - } - - return null; - } - - public static IStatus validateClass(String className) { - if (className == null || className.length() == 0) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Class name must be specified."); - } - if (className.indexOf('.') != -1) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Enter just a class name, not a full package name"); - } - return JavaConventions.validateJavaTypeName(className, JDK_15, JDK_15); - } - - private IStatus validateActivity() { - // Validate activity (if creating an activity) - if (!mValues.createActivity) { - return null; - } - - return validateActivity(mValues.activityName); - } - - /** - * Validates the given activity name - * - * @param activityFieldContents the activity name to validate - * @return a status for whether the activity name is valid - */ - public static IStatus validateActivity(String activityFieldContents) { - // Validate activity field - if (activityFieldContents == null || activityFieldContents.length() == 0) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Activity name must be specified."); - } else if (ACTIVITY_NAME_SUFFIX.equals(activityFieldContents)) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Enter a valid activity name"); - } else if (activityFieldContents.contains("..")) { //$NON-NLS-1$ - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Package segments in activity name cannot be empty (..)"); - } - // The activity field can actually contain part of a sub-package name - // or it can start with a dot "." to indicates it comes from the parent package - // name. - String packageName = ""; //$NON-NLS-1$ - int pos = activityFieldContents.lastIndexOf('.'); - if (pos >= 0) { - packageName = activityFieldContents.substring(0, pos); - if (packageName.startsWith(".")) { //$NON-NLS-1$ - packageName = packageName.substring(1); - } - - activityFieldContents = activityFieldContents.substring(pos + 1); - } - - // the activity field can contain a simple java identifier, or a - // package name or one that starts with a dot. So if it starts with a dot, - // ignore this dot -- the rest must look like a package name. - if (activityFieldContents.length() > 0 && activityFieldContents.charAt(0) == '.') { - activityFieldContents = activityFieldContents.substring(1); - } - - // Check it's a valid activity string - IStatus status = JavaConventions.validateTypeVariableName(activityFieldContents, JDK_15, - JDK_15); - if (!status.isOK()) { - return status; - } - - // Check it's a valid package string - if (packageName.length() > 0) { - status = JavaConventions.validatePackageName(packageName, JDK_15, JDK_15); - if (!status.isOK()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - status.getMessage() + " (in the activity name)"); - } - } - - return null; - } - - // ---- Implement ITargetChangeListener ---- - - @Override - public void onSdkLoaded() { - if (mSdkCombo == null) { - return; - } - - // Update the sdk target selector with the new targets - - // get the targets from the sdk - IAndroidTarget[] targets = null; - if (Sdk.getCurrent() != null) { - targets = Sdk.getCurrent().getTargets(); - } - setSdkTargets(targets, mValues.target); - } - - @Override - public void onProjectTargetChange(IProject changedProject) { - // Ignore - } - - @Override - public void onTargetLoaded(IAndroidTarget target) { - // Ignore - } - - public static String suggestTestApplicationName(String applicationName) { - if (applicationName == null) { - applicationName = ""; //$NON-NLS-1$ - } - if (applicationName.indexOf(' ') != -1) { - return applicationName + " Test"; //$NON-NLS-1$ - } else { - return applicationName + "Test"; //$NON-NLS-1$ - } - } - - public static String suggestTestProjectName(String projectName) { - if (projectName == null) { - projectName = ""; //$NON-NLS-1$ - } - if (projectName.length() > 0 && Character.isUpperCase(projectName.charAt(0))) { - return projectName + "Test"; //$NON-NLS-1$ - } else { - return projectName + "-test"; //$NON-NLS-1$ - } - } - - - public static String suggestTestPackage(String packagePath) { - if (packagePath == null) { - packagePath = ""; //$NON-NLS-1$ - } - return packagePath + ".test"; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/FileStoreAdapter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/FileStoreAdapter.java deleted file mode 100755 index 0f4e87e9f..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/FileStoreAdapter.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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.newproject; - -import org.eclipse.core.filesystem.IFileInfo; -import org.eclipse.core.filesystem.IFileStore; -import org.eclipse.core.filesystem.IFileSystem; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; - -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; - -/** - * IFileStore implementation that delegates to the give {@link IFileStore}. - * This makes it easier to just override a single method from a store. - */ -class FileStoreAdapter implements IFileStore { - - private final IFileStore mStore; - - public FileStoreAdapter(IFileStore store) { - mStore = store; - } - - @SuppressWarnings("rawtypes") - @Override - public Object getAdapter(Class adapter) { - return mStore.getAdapter(adapter); - } - - @Override - public IFileInfo[] childInfos(int options, IProgressMonitor monitor) throws CoreException { - return mStore.childInfos(options, monitor); - } - - @Override - public String[] childNames(int options, IProgressMonitor monitor) - throws CoreException { - return mStore.childNames(options, monitor); - } - - @Override - public IFileStore[] childStores(int options, IProgressMonitor monitor) throws CoreException { - return mStore.childStores(options, monitor); - } - - @Override - public void copy(IFileStore destination, int options, IProgressMonitor monitor) - throws CoreException { - mStore.copy(destination, options, monitor); - } - - @Override - public void delete(int options, IProgressMonitor monitor) throws CoreException { - mStore.delete(options, monitor); - } - - @Override - public IFileInfo fetchInfo() { - return mStore.fetchInfo(); - } - - @Override - public IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException { - return mStore.fetchInfo(options, monitor); - } - - @Deprecated - @Override - public IFileStore getChild(IPath path) { - return mStore.getChild(path); - } - - @Override - public IFileStore getFileStore(IPath path) { - return mStore.getFileStore(path); - } - - @Override - public IFileStore getChild(String name) { - return mStore.getChild(name); - } - - @Override - public IFileSystem getFileSystem() { - return mStore.getFileSystem(); - } - - @Override - public String getName() { - return mStore.getName(); - } - - @Override - public IFileStore getParent() { - return mStore.getParent(); - } - - @Override - public boolean isParentOf(IFileStore other) { - return mStore.isParentOf(other); - } - - @Override - public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException { - return mStore.mkdir(options, monitor); - } - - @Override - public void move(IFileStore destination, int options, IProgressMonitor monitor) - throws CoreException { - mStore.move(destination, options, monitor); - } - - @Override - public InputStream openInputStream(int options, IProgressMonitor monitor) - throws CoreException { - return mStore.openInputStream(options, monitor); - } - - @Override - public OutputStream openOutputStream(int options, IProgressMonitor monitor) - throws CoreException { - return mStore.openOutputStream(options, monitor); - } - - @Override - public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) - throws CoreException { - mStore.putInfo(info, options, monitor); - } - - @Override - public File toLocalFile(int options, IProgressMonitor monitor) throws CoreException { - return mStore.toLocalFile(options, monitor); - } - - @Override - public URI toURI() { - return mStore.toURI(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ImportPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ImportPage.java deleted file mode 100644 index 1e02fedae..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ImportPage.java +++ /dev/null @@ -1,512 +0,0 @@ -/* - * 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.newproject; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.tools.lint.detector.api.LintUtils; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.CellLabelProvider; -import org.eclipse.jface.viewers.CheckStateChangedEvent; -import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.ColumnViewer; -import org.eclipse.jface.viewers.EditingSupport; -import org.eclipse.jface.viewers.ICheckStateListener; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.TextCellEditor; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerCell; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.events.TraverseEvent; -import org.eclipse.swt.events.TraverseListener; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkingSet; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** WizardPage for importing Android projects */ -class ImportPage extends WizardPage implements SelectionListener, IStructuredContentProvider, - ICheckStateListener, KeyListener, TraverseListener, ControlListener { - private static final int DIR_COLUMN = 0; - private static final int NAME_COLUMN = 1; - - private final NewProjectWizardState mValues; - private List<ImportedProject> mProjectPaths; - private final IProject[] mExistingProjects; - - private Text mDir; - private Button mBrowseButton; - private Button mCopyCheckBox; - private Button mRefreshButton; - private Button mDeselectAllButton; - private Button mSelectAllButton; - private Table mTable; - private CheckboxTableViewer mCheckboxTableViewer; - private WorkingSetGroup mWorkingSetGroup; - - ImportPage(NewProjectWizardState values) { - super("importPage"); //$NON-NLS-1$ - mValues = values; - setTitle("Import Projects"); - setDescription("Select a directory to search for existing Android projects"); - mWorkingSetGroup = new WorkingSetGroup(); - setWorkingSets(new IWorkingSet[0]); - - // Record all projects such that we can ensure that the project names are unique - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - mExistingProjects = workspaceRoot.getProjects(); - } - - public void init(IStructuredSelection selection, IWorkbenchPart activePart) { - setWorkingSets(WorkingSetHelper.getSelectedWorkingSet(selection, activePart)); - } - - @SuppressWarnings("unused") // SWT constructors have side effects and aren't unused - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - setControl(container); - container.setLayout(new GridLayout(3, false)); - - Label directoryLabel = new Label(container, SWT.NONE); - directoryLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - directoryLabel.setText("Root Directory:"); - - mDir = new Text(container, SWT.BORDER); - mDir.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mDir.addKeyListener(this); - mDir.addTraverseListener(this); - - mBrowseButton = new Button(container, SWT.NONE); - mBrowseButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); - mBrowseButton.setText("Browse..."); - mBrowseButton.addSelectionListener(this); - - Label projectsLabel = new Label(container, SWT.NONE); - projectsLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); - projectsLabel.setText("Projects:"); - - mTable = new Table(container, SWT.CHECK); - mTable.setHeaderVisible(true); - mCheckboxTableViewer = new CheckboxTableViewer(mTable); - - TableViewerColumn dirViewerColumn = new TableViewerColumn(mCheckboxTableViewer, SWT.NONE); - TableColumn dirColumn = dirViewerColumn.getColumn(); - dirColumn.setWidth(200); - dirColumn.setText("Project to Import"); - TableViewerColumn nameViewerColumn = new TableViewerColumn(mCheckboxTableViewer, SWT.NONE); - TableColumn nameColumn = nameViewerColumn.getColumn(); - nameColumn.setWidth(200); - nameColumn.setText("New Project Name"); - nameViewerColumn.setEditingSupport(new ProjectNameEditingSupport(mCheckboxTableViewer)); - - mTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 4)); - mTable.setLinesVisible(true); - mTable.setHeaderVisible(true); - mTable.addSelectionListener(this); - mTable.addControlListener(this); - mCheckboxTableViewer.setContentProvider(this); - mCheckboxTableViewer.setInput(this); - mCheckboxTableViewer.addCheckStateListener(this); - mCheckboxTableViewer.setLabelProvider(new ProjectCellLabelProvider()); - - mSelectAllButton = new Button(container, SWT.NONE); - mSelectAllButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); - mSelectAllButton.setText("Select All"); - mSelectAllButton.addSelectionListener(this); - - mDeselectAllButton = new Button(container, SWT.NONE); - mDeselectAllButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); - mDeselectAllButton.setText("Deselect All"); - mDeselectAllButton.addSelectionListener(this); - - mRefreshButton = new Button(container, SWT.NONE); - mRefreshButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); - mRefreshButton.setText("Refresh"); - mRefreshButton.addSelectionListener(this); - new Label(container, SWT.NONE); - - mCopyCheckBox = new Button(container, SWT.CHECK); - mCopyCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); - mCopyCheckBox.setText("Copy projects into workspace"); - mCopyCheckBox.addSelectionListener(this); - - Composite group = mWorkingSetGroup.createControl(container); - group.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1)); - - updateColumnWidths(); - } - - private void updateColumnWidths() { - Rectangle r = mTable.getClientArea(); - int availableWidth = r.width; - // Add all available size to the first column - for (int i = 1; i < mTable.getColumnCount(); i++) { - TableColumn column = mTable.getColumn(i); - availableWidth -= column.getWidth(); - } - if (availableWidth > 100) { - mTable.getColumn(0).setWidth(availableWidth); - } - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - validatePage(); - } - - private void refresh() { - File root = new File(mDir.getText().trim()); - mProjectPaths = searchForProjects(root); - mCheckboxTableViewer.refresh(); - mCheckboxTableViewer.setAllChecked(true); - - updateValidity(); - validatePage(); - } - - private void updateValidity(){ - List<ImportedProject> selected = new ArrayList<ImportedProject>(); - List<ImportedProject> disabled = new ArrayList<ImportedProject>(); - for (ImportedProject project : mProjectPaths) { - String projectName = project.getProjectName(); - boolean invalid = false; - for (IProject existingProject : mExistingProjects) { - if (projectName.equals(existingProject.getName())) { - invalid = true; - break; - } - } - if (invalid) { - disabled.add(project); - } else { - selected.add(project); - } - } - - mValues.importProjects = selected; - - mCheckboxTableViewer.setGrayedElements(disabled.toArray()); - mCheckboxTableViewer.setCheckedElements(selected.toArray()); - mCheckboxTableViewer.refresh(); - mCheckboxTableViewer.getTable().setFocus(); - } - - private List<ImportedProject> searchForProjects(File dir) { - List<ImportedProject> projects = new ArrayList<ImportedProject>(); - addProjects(dir, projects, dir.getPath().length() + 1); - return projects; - } - - /** Finds all project directories under the given directory */ - private void addProjects(File dir, List<ImportedProject> projects, int prefixLength) { - if (dir.isDirectory()) { - if (LintUtils.isManifestFolder(dir)) { - String relative = dir.getPath(); - if (relative.length() > prefixLength) { - relative = relative.substring(prefixLength); - } - projects.add(new ImportedProject(dir, relative)); - } - - File[] children = dir.listFiles(); - if (children != null) { - for (File child : children) { - addProjects(child, projects, prefixLength); - } - } - } - } - - private void validatePage() { - IStatus status = null; - - // Validate project name -- unless we're creating a sample, in which case - // the user will get a chance to pick the name on the Sample page - if (mProjectPaths == null || mProjectPaths.isEmpty()) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Select a directory to search for existing Android projects"); - } else if (mValues.importProjects == null || mValues.importProjects.isEmpty()) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Select at least one project"); - } else { - for (ImportedProject project : mValues.importProjects) { - if (mCheckboxTableViewer.getGrayed(project)) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("Cannot import %1$s because the project name is in use", - project.getProjectName())); - break; - } else { - status = ProjectNamePage.validateProjectName(project.getProjectName()); - if (status != null && !status.isOK()) { - // Need to insert project name to make it clear which project name - // is in violation - if (mValues.importProjects.size() > 1) { - String message = String.format("%1$s: %2$s", - project.getProjectName(), status.getMessage()); - status = new Status(status.getSeverity(), AdtPlugin.PLUGIN_ID, - message); - } - break; - } else { - status = null; // Don't leave non null status with isOK() == true - } - } - } - } - - // -- update UI & enable finish if there's no error - setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); - if (status != null) { - setMessage(status.getMessage(), - status.getSeverity() == IStatus.ERROR - ? IMessageProvider.ERROR : IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - /** - * Returns the working sets to which the new project should be added. - * - * @return the selected working sets to which the new project should be added - */ - private IWorkingSet[] getWorkingSets() { - return mWorkingSetGroup.getSelectedWorkingSets(); - } - - /** - * Sets the working sets to which the new project should be added. - * - * @param workingSets the initial selected working sets - */ - private void setWorkingSets(IWorkingSet[] workingSets) { - assert workingSets != null; - mWorkingSetGroup.setWorkingSets(workingSets); - } - - @Override - public IWizardPage getNextPage() { - // Sync working set data to the value object, since the WorkingSetGroup - // doesn't let us add listeners to do this lazily - mValues.workingSets = getWorkingSets(); - - return super.getNextPage(); - } - - // ---- Implements SelectionListener ---- - - @Override - public void widgetSelected(SelectionEvent e) { - Object source = e.getSource(); - if (source == mBrowseButton) { - // Choose directory - DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.OPEN); - String path = mDir.getText().trim(); - if (path.length() > 0) { - dialog.setFilterPath(path); - } - String file = dialog.open(); - if (file != null) { - mDir.setText(file); - refresh(); - } - } else if (source == mSelectAllButton) { - mCheckboxTableViewer.setAllChecked(true); - mValues.importProjects = mProjectPaths; - } else if (source == mDeselectAllButton) { - mCheckboxTableViewer.setAllChecked(false); - mValues.importProjects = Collections.emptyList(); - } else if (source == mRefreshButton || source == mDir) { - refresh(); - } else if (source == mCopyCheckBox) { - mValues.copyIntoWorkspace = mCopyCheckBox.getSelection(); - } - - validatePage(); - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - // ---- KeyListener ---- - - @Override - public void keyPressed(KeyEvent e) { - if (e.getSource() == mDir) { - if (e.keyCode == SWT.CR) { - refresh(); - } - } - } - - @Override - public void keyReleased(KeyEvent e) { - } - - // ---- TraverseListener ---- - - @Override - public void keyTraversed(TraverseEvent e) { - // Prevent Return from running through the wizard; return is handled by - // key listener to refresh project list instead - if (SWT.TRAVERSE_RETURN == e.detail) { - e.doit = false; - } - } - - // ---- Implements IStructuredContentProvider ---- - - @Override - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - @Override - public Object[] getElements(Object inputElement) { - return mProjectPaths != null ? mProjectPaths.toArray() : new Object[0]; - } - - // ---- Implements ICheckStateListener ---- - - @Override - public void checkStateChanged(CheckStateChangedEvent event) { - // Try to disable other elements that conflict with this - Object[] checked = mCheckboxTableViewer.getCheckedElements(); - List<ImportedProject> selected = new ArrayList<ImportedProject>(checked.length); - for (Object o : checked) { - if (!mCheckboxTableViewer.getGrayed(o)) { - selected.add((ImportedProject) o); - } - } - mValues.importProjects = selected; - validatePage(); - - mCheckboxTableViewer.update(event.getElement(), null); - } - - // ---- Implements ControlListener ---- - - @Override - public void controlMoved(ControlEvent e) { - } - - @Override - public void controlResized(ControlEvent e) { - updateColumnWidths(); - } - - private final class ProjectCellLabelProvider extends CellLabelProvider { - @Override - public void update(ViewerCell cell) { - Object element = cell.getElement(); - int index = cell.getColumnIndex(); - ImportedProject project = (ImportedProject) element; - - Display display = mTable.getDisplay(); - Color fg; - if (mCheckboxTableViewer.getGrayed(element)) { - fg = display.getSystemColor(SWT.COLOR_DARK_GRAY); - } else { - fg = display.getSystemColor(SWT.COLOR_LIST_FOREGROUND); - } - cell.setForeground(fg); - cell.setBackground(display.getSystemColor(SWT.COLOR_LIST_BACKGROUND)); - - switch (index) { - case DIR_COLUMN: { - // Directory name - cell.setText(project.getRelativePath()); - return; - } - - case NAME_COLUMN: { - // New name - cell.setText(project.getProjectName()); - return; - } - default: - assert false : index; - } - cell.setText(""); - } - } - - /** Editing support for the project name column */ - private class ProjectNameEditingSupport extends EditingSupport { - private ProjectNameEditingSupport(ColumnViewer viewer) { - super(viewer); - } - - @Override - protected void setValue(Object element, Object value) { - ImportedProject project = (ImportedProject) element; - project.setProjectName(value.toString()); - mCheckboxTableViewer.update(element, null); - updateValidity(); - validatePage(); - } - - @Override - protected Object getValue(Object element) { - ImportedProject project = (ImportedProject) element; - return project.getProjectName(); - } - - @Override - protected CellEditor getCellEditor(Object element) { - return new TextCellEditor(mTable); - } - - @Override - protected boolean canEdit(Object element) { - return true; - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ImportProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ImportProjectWizard.java deleted file mode 100644 index 1004fd692..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ImportProjectWizard.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.newproject; - -import static com.android.SdkConstants.FN_PROJECT_PROGUARD_FILE; -import static com.android.SdkConstants.OS_SDK_TOOLS_LIB_FOLDER; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; - -import org.eclipse.jdt.ui.actions.OpenJavaPerspectiveAction; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.ui.INewWizard; -import org.eclipse.ui.IWorkbench; - -import java.io.File; - - -/** - * An "Import Android Project" wizard. - */ -public class ImportProjectWizard extends Wizard implements INewWizard { - private static final String PROJECT_LOGO_LARGE = "icons/android-64.png"; //$NON-NLS-1$ - - private NewProjectWizardState mValues; - private ImportPage mImportPage; - private IStructuredSelection mSelection; - - /** Constructs a new wizard default project wizard */ - public ImportProjectWizard() { - } - - @Override - public void addPages() { - mValues = new NewProjectWizardState(Mode.ANY); - mImportPage = new ImportPage(mValues); - if (mSelection != null) { - mImportPage.init(mSelection, AdtUtils.getActivePart()); - } - addPage(mImportPage); - } - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - mSelection = selection; - - setHelpAvailable(false); // TODO have help - ImageDescriptor desc = AdtPlugin.getImageDescriptor(PROJECT_LOGO_LARGE); - setDefaultPageImageDescriptor(desc); - - // Trigger a check to see if the SDK needs to be reloaded (which will - // invoke onSdkLoaded asynchronously as needed). - AdtPlugin.getDefault().refreshSdk(); - } - - @Override - public boolean performFinish() { - File file = new File(AdtPlugin.getOsSdkFolder(), OS_SDK_TOOLS_LIB_FOLDER + File.separator - + FN_PROJECT_PROGUARD_FILE); - if (!file.exists()) { - AdtPlugin.displayError("Tools Out of Date?", - String.format("It looks like you do not have the latest version of the " - + "SDK Tools installed. Make sure you update via the SDK Manager " - + "first. (Could not find %1$s)", file.getPath())); - return false; - } - - NewProjectCreator creator = new NewProjectCreator(mValues, getContainer()); - if (!(creator.createAndroidProjects())) { - return false; - } - - // Open the default Java Perspective - OpenJavaPerspectiveAction action = new OpenJavaPerspectiveAction(); - action.run(); - return true; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ImportedProject.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ImportedProject.java deleted file mode 100644 index 74af651ca..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ImportedProject.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * 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.newproject; - -import static com.android.SdkConstants.ATTR_NAME; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.common.xml.AndroidManifestParser; -import com.android.ide.common.xml.ManifestData; -import com.android.ide.common.xml.ManifestData.Activity; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.io.FolderWrapper; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.internal.project.ProjectProperties; -import com.android.sdklib.internal.project.ProjectProperties.PropertyType; -import com.google.common.base.Charsets; -import com.google.common.io.Files; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import java.io.File; -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** An Android project to be imported */ -class ImportedProject { - private final File mLocation; - private String mActivityName; - private ManifestData mManifest; - private String mProjectName; - private String mRelativePath; - - ImportedProject(File location, String relativePath) { - super(); - mLocation = location; - mRelativePath = relativePath; - } - - File getLocation() { - return mLocation; - } - - String getRelativePath() { - return mRelativePath; - } - - @Nullable - ManifestData getManifest() { - if (mManifest == null) { - try { - mManifest = AndroidManifestParser.parse(new FolderWrapper(mLocation)); - } catch (SAXException e) { - // Some sort of error in the manifest file: report to the user in a better way? - AdtPlugin.log(e, null); - return null; - } catch (Exception e) { - AdtPlugin.log(e, null); - return null; - } - } - - return mManifest; - } - - @Nullable - public String getActivityName() { - if (mActivityName == null) { - // Compute the project name and the package name from the manifest - ManifestData manifest = getManifest(); - if (manifest != null) { - if (manifest.getLauncherActivity() != null) { - mActivityName = manifest.getLauncherActivity().getName(); - } - if (mActivityName == null || mActivityName.isEmpty()) { - Activity[] activities = manifest.getActivities(); - for (Activity activity : activities) { - mActivityName = activity.getName(); - if (mActivityName != null && !mActivityName.isEmpty()) { - break; - } - } - } - if (mActivityName != null) { - int index = mActivityName.lastIndexOf('.'); - mActivityName = mActivityName.substring(index + 1); - } - } - } - - return mActivityName; - } - - @NonNull - public String getProjectName() { - if (mProjectName == null) { - // Are we importing an Eclipse project? If so just use the existing project name - mProjectName = findEclipseProjectName(); - if (mProjectName != null) { - return mProjectName; - } - - String activityName = getActivityName(); - if (activityName == null || activityName.isEmpty()) { - // I could also look at the build files, say build.xml from ant, and - // try to glean the project name from there - mProjectName = mLocation.getName(); - } else { - // Try to derive it from the activity name: - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IStatus nameStatus = workspace.validateName(activityName, IResource.PROJECT); - if (nameStatus.isOK()) { - mProjectName = activityName; - } else { - // Try to derive it by escaping characters - StringBuilder sb = new StringBuilder(); - for (int i = 0, n = activityName.length(); i < n; i++) { - char c = activityName.charAt(i); - if (c != IPath.DEVICE_SEPARATOR && c != IPath.SEPARATOR && c != '\\') { - sb.append(c); - } - } - if (sb.length() == 0) { - mProjectName = mLocation.getName(); - } else { - mProjectName = sb.toString(); - } - } - } - } - - return mProjectName; - } - - @Nullable - private String findEclipseProjectName() { - File projectFile = new File(mLocation, ".project"); //$NON-NLS-1$ - if (projectFile.exists()) { - String xml; - try { - xml = Files.toString(projectFile, Charsets.UTF_8); - Document doc = DomUtilities.parseDocument(xml, false); - if (doc != null) { - NodeList names = doc.getElementsByTagName(ATTR_NAME); - if (names.getLength() >= 1) { - Node nameElement = names.item(0); - String name = nameElement.getTextContent().trim(); - if (!name.isEmpty()) { - return name; - } - } - } - } catch (IOException e) { - // pass: don't attempt to read project name; must be some sort of unrelated - // file with the same name, perhaps from a different editor or IDE - } - } - - return null; - } - - public void setProjectName(@NonNull String newName) { - mProjectName = newName; - } - - public IAndroidTarget getTarget() { - // Pick a target: - // First try to find the one requested by project.properties - IAndroidTarget[] targets = Sdk.getCurrent().getTargets(); - ProjectProperties properties = ProjectProperties.load(mLocation.getPath(), - PropertyType.PROJECT); - if (properties != null) { - String targetProperty = properties.getProperty(ProjectProperties.PROPERTY_TARGET); - if (targetProperty != null) { - Matcher m = Pattern.compile("android-(.+)").matcher( //$NON-NLS-1$ - targetProperty.trim()); - if (m.matches()) { - String targetName = m.group(1); - int targetLevel; - try { - targetLevel = Integer.parseInt(targetName); - } catch (NumberFormatException nufe) { - // pass - targetLevel = -1; - } - for (IAndroidTarget t : targets) { - AndroidVersion version = t.getVersion(); - if (version.isPreview() && targetName.equals(version.getCodename())) { - return t; - } else if (targetLevel == version.getApiLevel()) { - return t; - } - } - if (targetLevel > 0) { - // If not found, pick the closest one that is higher than the - // api level - IAndroidTarget target = targets[targets.length - 1]; - int targetDelta = target.getVersion().getApiLevel() - targetLevel; - for (IAndroidTarget t : targets) { - int newDelta = t.getVersion().getApiLevel() - targetLevel; - if (newDelta >= 0 && newDelta < targetDelta) { - targetDelta = newDelta; - target = t; - } - } - - return target; - } - } - } - } - - // If not found, pick the closest one to the one requested by the - // project (in project.properties) that is still >= the minSdk version - IAndroidTarget target = targets[targets.length - 1]; - ManifestData manifest = getManifest(); - if (manifest != null) { - int minSdkLevel = manifest.getMinSdkVersion(); - int targetDelta = target.getVersion().getApiLevel() - minSdkLevel; - for (IAndroidTarget t : targets) { - int newDelta = t.getVersion().getApiLevel() - minSdkLevel; - if (newDelta >= 0 && newDelta < targetDelta) { - targetDelta = newDelta; - target = t; - } - } - } - - return target; - } -}
\ No newline at end of file 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 deleted file mode 100644 index d168c7503..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreator.java +++ /dev/null @@ -1,1520 +0,0 @@ -/* - * Copyright (C) 2007 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.newproject; - -import static com.android.SdkConstants.FN_PROJECT_PROPERTIES; -import static com.android.sdklib.internal.project.ProjectProperties.PROPERTY_LIBRARY; - -import static org.eclipse.core.resources.IResource.DEPTH_ZERO; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.annotations.VisibleForTesting; -import com.android.ide.common.res2.ValueXmlHelper; -import com.android.ide.common.xml.ManifestData; -import com.android.ide.common.xml.XmlFormatStyle; -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.editors.formatting.EclipseXmlFormatPreferences; -import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlPrettyPrinter; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.android.ide.eclipse.adt.internal.project.AndroidNature; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; -import com.android.io.StreamException; -import com.android.resources.Density; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.internal.project.ProjectPropertiesWorkingCopy; - -import org.eclipse.core.filesystem.EFS; -import org.eclipse.core.filesystem.IFileInfo; -import org.eclipse.core.filesystem.IFileStore; -import org.eclipse.core.filesystem.IFileSystem; -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceStatus; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.IWorkspaceRunnable; -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.IStatus; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.jdt.core.IAccessRule; -import org.eclipse.jdt.core.IClasspathAttribute; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.operation.IRunnableContext; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.IWorkingSet; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.actions.WorkspaceModifyOperation; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -/** - * The actual project creator invoked from the New Project Wizard - * <p/> - * Note: this class is public so that it can be accessed from unit tests. - * It is however an internal class. Its API may change without notice. - * It should semantically be considered as a private final class. - */ -public class NewProjectCreator { - - private static final String PARAM_SDK_TOOLS_DIR = "ANDROID_SDK_TOOLS"; //$NON-NLS-1$ - private static final String PARAM_ACTIVITY = "ACTIVITY_NAME"; //$NON-NLS-1$ - private static final String PARAM_APPLICATION = "APPLICATION_NAME"; //$NON-NLS-1$ - private static final String PARAM_PACKAGE = "PACKAGE"; //$NON-NLS-1$ - private static final String PARAM_IMPORT_RESOURCE_CLASS = "IMPORT_RESOURCE_CLASS"; //$NON-NLS-1$ - private static final String PARAM_PROJECT = "PROJECT_NAME"; //$NON-NLS-1$ - private static final String PARAM_STRING_NAME = "STRING_NAME"; //$NON-NLS-1$ - private static final String PARAM_STRING_CONTENT = "STRING_CONTENT"; //$NON-NLS-1$ - private static final String PARAM_IS_NEW_PROJECT = "IS_NEW_PROJECT"; //$NON-NLS-1$ - private static final String PARAM_SAMPLE_LOCATION = "SAMPLE_LOCATION"; //$NON-NLS-1$ - private static final String PARAM_SOURCE = "SOURCE"; //$NON-NLS-1$ - private static final String PARAM_SRC_FOLDER = "SRC_FOLDER"; //$NON-NLS-1$ - private static final String PARAM_SDK_TARGET = "SDK_TARGET"; //$NON-NLS-1$ - private static final String PARAM_IS_LIBRARY = "IS_LIBRARY"; //$NON-NLS-1$ - private static final String PARAM_MIN_SDK_VERSION = "MIN_SDK_VERSION"; //$NON-NLS-1$ - // Warning: The expanded string PARAM_TEST_TARGET_PACKAGE must not contain the - // string "PACKAGE" since it collides with the replacement of PARAM_PACKAGE. - private static final String PARAM_TEST_TARGET_PACKAGE = "TEST_TARGET_PCKG"; //$NON-NLS-1$ - private static final String PARAM_TARGET_SELF = "TARGET_SELF"; //$NON-NLS-1$ - private static final String PARAM_TARGET_MAIN = "TARGET_MAIN"; //$NON-NLS-1$ - private static final String PARAM_TARGET_EXISTING = "TARGET_EXISTING"; //$NON-NLS-1$ - private static final String PARAM_REFERENCE_PROJECT = "REFERENCE_PROJECT"; //$NON-NLS-1$ - - private static final String PH_ACTIVITIES = "ACTIVITIES"; //$NON-NLS-1$ - private static final String PH_USES_SDK = "USES-SDK"; //$NON-NLS-1$ - private static final String PH_INTENT_FILTERS = "INTENT_FILTERS"; //$NON-NLS-1$ - private static final String PH_STRINGS = "STRINGS"; //$NON-NLS-1$ - private static final String PH_TEST_USES_LIBRARY = "TEST-USES-LIBRARY"; //$NON-NLS-1$ - private static final String PH_TEST_INSTRUMENTATION = "TEST-INSTRUMENTATION"; //$NON-NLS-1$ - - private static final String BIN_DIRECTORY = - SdkConstants.FD_OUTPUT + AdtConstants.WS_SEP; - private static final String BIN_CLASSES_DIRECTORY = - SdkConstants.FD_OUTPUT + AdtConstants.WS_SEP + - SdkConstants.FD_CLASSES_OUTPUT + AdtConstants.WS_SEP; - private static final String RES_DIRECTORY = - SdkConstants.FD_RESOURCES + AdtConstants.WS_SEP; - private static final String ASSETS_DIRECTORY = - SdkConstants.FD_ASSETS + AdtConstants.WS_SEP; - private static final String DRAWABLE_DIRECTORY = - SdkConstants.FD_RES_DRAWABLE + AdtConstants.WS_SEP; - private static final String DRAWABLE_XHDPI_DIRECTORY = - SdkConstants.FD_RES_DRAWABLE + '-' + Density.XHIGH.getResourceValue() + - AdtConstants.WS_SEP; - private static final String DRAWABLE_HDPI_DIRECTORY = - SdkConstants.FD_RES_DRAWABLE + '-' + Density.HIGH.getResourceValue() + - AdtConstants.WS_SEP; - private static final String DRAWABLE_MDPI_DIRECTORY = - SdkConstants.FD_RES_DRAWABLE + '-' + Density.MEDIUM.getResourceValue() + - AdtConstants.WS_SEP; - private static final String DRAWABLE_LDPI_DIRECTORY = - SdkConstants.FD_RES_DRAWABLE + '-' + Density.LOW.getResourceValue() + - AdtConstants.WS_SEP; - private static final String LAYOUT_DIRECTORY = - SdkConstants.FD_RES_LAYOUT + AdtConstants.WS_SEP; - private static final String VALUES_DIRECTORY = - SdkConstants.FD_RES_VALUES + AdtConstants.WS_SEP; - private static final String GEN_SRC_DIRECTORY = - SdkConstants.FD_GEN_SOURCES + AdtConstants.WS_SEP; - - private static final String TEMPLATES_DIRECTORY = "templates/"; //$NON-NLS-1$ - private static final String TEMPLATE_MANIFEST = TEMPLATES_DIRECTORY - + "AndroidManifest.template"; //$NON-NLS-1$ - private static final String TEMPLATE_ACTIVITIES = TEMPLATES_DIRECTORY - + "activity.template"; //$NON-NLS-1$ - private static final String TEMPLATE_USES_SDK = TEMPLATES_DIRECTORY - + "uses-sdk.template"; //$NON-NLS-1$ - private static final String TEMPLATE_INTENT_LAUNCHER = TEMPLATES_DIRECTORY - + "launcher_intent_filter.template"; //$NON-NLS-1$ - private static final String TEMPLATE_TEST_USES_LIBRARY = TEMPLATES_DIRECTORY - + "test_uses-library.template"; //$NON-NLS-1$ - private static final String TEMPLATE_TEST_INSTRUMENTATION = TEMPLATES_DIRECTORY - + "test_instrumentation.template"; //$NON-NLS-1$ - - - - private static final String TEMPLATE_STRINGS = TEMPLATES_DIRECTORY - + "strings.template"; //$NON-NLS-1$ - private static final String TEMPLATE_STRING = TEMPLATES_DIRECTORY - + "string.template"; //$NON-NLS-1$ - private static final String PROJECT_ICON = "ic_launcher.png"; //$NON-NLS-1$ - private static final String ICON_XHDPI = "ic_launcher_xhdpi.png"; //$NON-NLS-1$ - private static final String ICON_HDPI = "ic_launcher_hdpi.png"; //$NON-NLS-1$ - private static final String ICON_MDPI = "ic_launcher_mdpi.png"; //$NON-NLS-1$ - private static final String ICON_LDPI = "ic_launcher_ldpi.png"; //$NON-NLS-1$ - - private static final String STRINGS_FILE = "strings.xml"; //$NON-NLS-1$ - - private static final String STRING_RSRC_PREFIX = SdkConstants.STRING_PREFIX; - private static final String STRING_APP_NAME = "app_name"; //$NON-NLS-1$ - private static final String STRING_HELLO_WORLD = "hello"; //$NON-NLS-1$ - - private static final String[] DEFAULT_DIRECTORIES = new String[] { - BIN_DIRECTORY, BIN_CLASSES_DIRECTORY, RES_DIRECTORY, ASSETS_DIRECTORY }; - private static final String[] RES_DIRECTORIES = new String[] { - DRAWABLE_DIRECTORY, LAYOUT_DIRECTORY, VALUES_DIRECTORY }; - private static final String[] RES_DENSITY_ENABLED_DIRECTORIES = new String[] { - DRAWABLE_XHDPI_DIRECTORY, - DRAWABLE_HDPI_DIRECTORY, DRAWABLE_MDPI_DIRECTORY, DRAWABLE_LDPI_DIRECTORY, - LAYOUT_DIRECTORY, VALUES_DIRECTORY }; - - private static final String JAVA_ACTIVITY_TEMPLATE = "java_file.template"; //$NON-NLS-1$ - private static final String LAYOUT_TEMPLATE = "layout.template"; //$NON-NLS-1$ - private static final String MAIN_LAYOUT_XML = "main.xml"; //$NON-NLS-1$ - - private final NewProjectWizardState mValues; - private final IRunnableContext mRunnableContext; - - /** - * Creates a new {@linkplain NewProjectCreator} - * @param values the wizard state with initial project parameters - * @param runnableContext the context to run project creation in - */ - public NewProjectCreator(NewProjectWizardState values, IRunnableContext runnableContext) { - mValues = values; - mRunnableContext = runnableContext; - } - - /** - * Before actually creating the project for a new project (as opposed to using an - * existing project), we check if the target location is a directory that either does - * not exist or is empty. - * - * If it's not empty, ask the user for confirmation. - * - * @param destination The destination folder where the new project is to be created. - * @return True if the destination doesn't exist yet or is an empty directory or is - * accepted by the user. - */ - private boolean validateNewProjectLocationIsEmpty(IPath destination) { - File f = new File(destination.toOSString()); - if (f.isDirectory() && f.list().length > 0) { - return AdtPlugin.displayPrompt("New Android Project", - "You are going to create a new Android Project in an existing, non-empty, directory. Are you sure you want to proceed?"); - } - return true; - } - - /** - * Structure that describes all the information needed to create a project. - * This is collected from the pages by {@link NewProjectCreator#createAndroidProjects()} - * and then used by - * {@link NewProjectCreator#createProjectAsync(IProgressMonitor, ProjectInfo, ProjectInfo)}. - */ - private static class ProjectInfo { - private final IProject mProject; - private final IProjectDescription mDescription; - private final Map<String, Object> mParameters; - private final HashMap<String, String> mDictionary; - - public ProjectInfo(IProject project, - IProjectDescription description, - Map<String, Object> parameters, - HashMap<String, String> dictionary) { - mProject = project; - mDescription = description; - mParameters = parameters; - mDictionary = dictionary; - } - - public IProject getProject() { - return mProject; - } - - public IProjectDescription getDescription() { - return mDescription; - } - - public Map<String, Object> getParameters() { - return mParameters; - } - - public HashMap<String, String> getDictionary() { - return mDictionary; - } - } - - /** - * Creates the android project. - * @return True if the project could be created. - */ - public boolean createAndroidProjects() { - if (mValues.importProjects != null && !mValues.importProjects.isEmpty()) { - return importProjects(); - } - - final ProjectInfo mainData = collectMainPageInfo(); - final ProjectInfo testData = collectTestPageInfo(); - - // Create a monitored operation to create the actual project - WorkspaceModifyOperation op = new WorkspaceModifyOperation() { - @Override - protected void execute(IProgressMonitor monitor) throws InvocationTargetException { - createProjectAsync(monitor, mainData, testData, null, true); - } - }; - - // Run the operation in a different thread - runAsyncOperation(op); - return true; - } - - /** - * Creates the a plain Java project without typical android directories or an Android Nature. - * This is intended for use by unit tests and not as a general-purpose Java project creator. - * @return True if the project could be created. - */ - @VisibleForTesting - public boolean createJavaProjects() { - if (mValues.importProjects != null && !mValues.importProjects.isEmpty()) { - return importProjects(); - } - - final ProjectInfo mainData = collectMainPageInfo(); - final ProjectInfo testData = collectTestPageInfo(); - - // Create a monitored operation to create the actual project - WorkspaceModifyOperation op = new WorkspaceModifyOperation() { - @Override - protected void execute(IProgressMonitor monitor) throws InvocationTargetException { - createProjectAsync(monitor, mainData, testData, null, false); - } - }; - - // Run the operation in a different thread - runAsyncOperation(op); - return true; - } - - /** - * Imports a list of projects - */ - private boolean importProjects() { - assert mValues.importProjects != null && !mValues.importProjects.isEmpty(); - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - - final List<ProjectInfo> projectData = new ArrayList<ProjectInfo>(); - for (ImportedProject p : mValues.importProjects) { - - // Compute the project name and the package name from the manifest - ManifestData manifest = p.getManifest(); - if (manifest == null) { - continue; - } - String packageName = manifest.getPackage(); - String projectName = p.getProjectName(); - String minSdk = manifest.getMinSdkVersionString(); - - final IProject project = workspace.getRoot().getProject(projectName); - final IProjectDescription description = - workspace.newProjectDescription(project.getName()); - - final Map<String, Object> parameters = new HashMap<String, Object>(); - parameters.put(PARAM_PROJECT, projectName); - parameters.put(PARAM_PACKAGE, packageName); - parameters.put(PARAM_SDK_TOOLS_DIR, AdtPlugin.getOsSdkToolsFolder()); - parameters.put(PARAM_IS_NEW_PROJECT, Boolean.FALSE); - parameters.put(PARAM_SRC_FOLDER, SdkConstants.FD_SOURCES); - - parameters.put(PARAM_SDK_TARGET, p.getTarget()); - - // TODO: Find out if these end up getting used in the import-path through the code! - parameters.put(PARAM_MIN_SDK_VERSION, minSdk); - parameters.put(PARAM_APPLICATION, STRING_RSRC_PREFIX + STRING_APP_NAME); - final HashMap<String, String> dictionary = new HashMap<String, String>(); - dictionary.put(STRING_APP_NAME, mValues.applicationName); - - if (mValues.copyIntoWorkspace) { - parameters.put(PARAM_SOURCE, p.getLocation()); - - // TODO: Make sure it isn't *already* in the workspace! - //IPath defaultLocation = Platform.getLocation(); - //if ((!mValues.useDefaultLocation || mValues.useExisting) - // && !defaultLocation.isPrefixOf(path)) { - //IPath workspaceLocation = Platform.getLocation().append(projectName); - //description.setLocation(workspaceLocation); - // DON'T SET THE LOCATION: It's IMPLIED and in fact it will generate - // an error if you set it! - } else { - // Create in place - description.setLocation(new Path(p.getLocation().getPath())); - } - - projectData.add(new ProjectInfo(project, description, parameters, dictionary)); - } - - // Create a monitored operation to create the actual project - WorkspaceModifyOperation op = new WorkspaceModifyOperation() { - @Override - protected void execute(IProgressMonitor monitor) throws InvocationTargetException { - createProjectAsync(monitor, null, null, projectData, true); - } - }; - - // Run the operation in a different thread - runAsyncOperation(op); - return true; - } - - /** - * Collects all the parameters needed to create the main project. - * @return A new {@link ProjectInfo} on success. Returns null if the project cannot be - * created because parameters are incorrect or should not be created because there - * is no main page. - */ - private ProjectInfo collectMainPageInfo() { - if (mValues.mode == Mode.TEST) { - return null; - } - - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - final IProject project = workspace.getRoot().getProject(mValues.projectName); - final IProjectDescription description = workspace.newProjectDescription(project.getName()); - - final Map<String, Object> parameters = new HashMap<String, Object>(); - parameters.put(PARAM_PROJECT, mValues.projectName); - parameters.put(PARAM_PACKAGE, mValues.packageName); - parameters.put(PARAM_APPLICATION, STRING_RSRC_PREFIX + STRING_APP_NAME); - parameters.put(PARAM_SDK_TOOLS_DIR, AdtPlugin.getOsSdkToolsFolder()); - parameters.put(PARAM_IS_NEW_PROJECT, mValues.mode == Mode.ANY && !mValues.useExisting); - parameters.put(PARAM_SAMPLE_LOCATION, mValues.chosenSample); - parameters.put(PARAM_SRC_FOLDER, mValues.sourceFolder); - parameters.put(PARAM_SDK_TARGET, mValues.target); - parameters.put(PARAM_MIN_SDK_VERSION, mValues.minSdk); - - if (mValues.createActivity) { - parameters.put(PARAM_ACTIVITY, mValues.activityName); - } - - // create a dictionary of string that will contain name+content. - // we'll put all the strings into values/strings.xml - final HashMap<String, String> dictionary = new HashMap<String, String>(); - dictionary.put(STRING_APP_NAME, mValues.applicationName); - - IPath path = new Path(mValues.projectLocation.getPath()); - IPath defaultLocation = Platform.getLocation(); - if ((!mValues.useDefaultLocation || mValues.useExisting) - && !defaultLocation.isPrefixOf(path)) { - description.setLocation(path); - } - - if (mValues.mode == Mode.ANY && !mValues.useExisting && !mValues.useDefaultLocation && - !validateNewProjectLocationIsEmpty(path)) { - return null; - } - - return new ProjectInfo(project, description, parameters, dictionary); - } - - /** - * Collects all the parameters needed to create the test project. - * - * @return A new {@link ProjectInfo} on success. Returns null if the project cannot be - * created because parameters are incorrect or should not be created because there - * is no test page. - */ - private ProjectInfo collectTestPageInfo() { - if (mValues.mode != Mode.TEST && !mValues.createPairProject) { - return null; - } - - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - String projectName = - mValues.mode == Mode.TEST ? mValues.projectName : mValues.testProjectName; - final IProject project = workspace.getRoot().getProject(projectName); - final IProjectDescription description = workspace.newProjectDescription(project.getName()); - - final Map<String, Object> parameters = new HashMap<String, Object>(); - - String pkg = - mValues.mode == Mode.TEST ? mValues.packageName : mValues.testPackageName; - - parameters.put(PARAM_PACKAGE, pkg); - parameters.put(PARAM_APPLICATION, STRING_RSRC_PREFIX + STRING_APP_NAME); - parameters.put(PARAM_SDK_TOOLS_DIR, AdtPlugin.getOsSdkToolsFolder()); - parameters.put(PARAM_IS_NEW_PROJECT, !mValues.useExisting); - parameters.put(PARAM_SRC_FOLDER, mValues.sourceFolder); - parameters.put(PARAM_SDK_TARGET, mValues.target); - parameters.put(PARAM_MIN_SDK_VERSION, mValues.minSdk); - - // Test-specific parameters - String testedPkg = mValues.createPairProject - ? mValues.packageName : mValues.testTargetPackageName; - if (testedPkg == null) { - assert mValues.testingSelf; - testedPkg = pkg; - } - - parameters.put(PARAM_TEST_TARGET_PACKAGE, testedPkg); - - if (mValues.testingSelf) { - parameters.put(PARAM_TARGET_SELF, true); - } else { - parameters.put(PARAM_TARGET_EXISTING, true); - parameters.put(PARAM_REFERENCE_PROJECT, mValues.testedProject); - } - - if (mValues.createPairProject) { - parameters.put(PARAM_TARGET_MAIN, true); - } - - // create a dictionary of string that will contain name+content. - // we'll put all the strings into values/strings.xml - final HashMap<String, String> dictionary = new HashMap<String, String>(); - dictionary.put(STRING_APP_NAME, mValues.testApplicationName); - - // Use the same logic to determine test project location as in - // ApplicationInfoPage#validateTestProjectLocation - IPath path = new Path(mValues.projectLocation.getPath()); - path = path.removeLastSegments(1).append(mValues.testProjectName); - IPath defaultLocation = Platform.getLocation(); - if ((!mValues.useDefaultLocation || mValues.useExisting) - && !path.equals(defaultLocation)) { - description.setLocation(path); - } - - if (!mValues.useExisting && !mValues.useDefaultLocation && - !validateNewProjectLocationIsEmpty(path)) { - return null; - } - - return new ProjectInfo(project, description, parameters, dictionary); - } - - /** - * Runs the operation in a different thread and display generated - * exceptions. - * - * @param op The asynchronous operation to run. - */ - private void runAsyncOperation(WorkspaceModifyOperation op) { - try { - mRunnableContext.run(true /* fork */, true /* cancelable */, op); - } catch (InvocationTargetException e) { - - AdtPlugin.log(e, "New Project Wizard failed"); - - // The runnable threw an exception - Throwable t = e.getTargetException(); - if (t instanceof CoreException) { - CoreException core = (CoreException) t; - if (core.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) { - // The error indicates the file system is not case sensitive - // and there's a resource with a similar name. - MessageDialog.openError(AdtPlugin.getShell(), - "Error", "Error: Case Variant Exists"); - } else { - ErrorDialog.openError(AdtPlugin.getShell(), - "Error", core.getMessage(), core.getStatus()); - } - } else { - // Some other kind of exception - String msg = t.getMessage(); - Throwable t1 = t; - while (msg == null && t1.getCause() != null) { - msg = t1.getMessage(); - t1 = t1.getCause(); - } - if (msg == null) { - msg = t.toString(); - } - MessageDialog.openError(AdtPlugin.getShell(), "Error", msg); - } - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - /** - * Creates the actual project(s). This is run asynchronously in a different thread. - * - * @param monitor An existing monitor. - * @param mainData Data for main project. Can be null. - * @param isAndroidProject true if the project is to be set up as a full Android project; false - * for a plain Java project. - * @throws InvocationTargetException to wrap any unmanaged exception and - * return it to the calling thread. The method can fail if it fails - * to create or modify the project or if it is canceled by the user. - */ - private void createProjectAsync(IProgressMonitor monitor, - ProjectInfo mainData, - ProjectInfo testData, - List<ProjectInfo> importData, - boolean isAndroidProject) - throws InvocationTargetException { - monitor.beginTask("Create Android Project", 100); - try { - IProject mainProject = null; - - if (mainData != null) { - mainProject = createEclipseProject( - new SubProgressMonitor(monitor, 50), - mainData.getProject(), - mainData.getDescription(), - mainData.getParameters(), - mainData.getDictionary(), - null, - isAndroidProject); - - if (mainProject != null) { - final IJavaProject javaProject = JavaCore.create(mainProject); - Display.getDefault().syncExec(new WorksetAdder(javaProject, - mValues.workingSets)); - } - } - - if (testData != null) { - Map<String, Object> parameters = testData.getParameters(); - if (parameters.containsKey(PARAM_TARGET_MAIN) && mainProject != null) { - parameters.put(PARAM_REFERENCE_PROJECT, mainProject); - } - - IProject testProject = createEclipseProject( - new SubProgressMonitor(monitor, 50), - testData.getProject(), - testData.getDescription(), - parameters, - testData.getDictionary(), - null, - isAndroidProject); - if (testProject != null) { - final IJavaProject javaProject = JavaCore.create(testProject); - Display.getDefault().syncExec(new WorksetAdder(javaProject, - mValues.workingSets)); - } - } - - if (importData != null) { - for (final ProjectInfo data : importData) { - ProjectPopulator projectPopulator = null; - if (mValues.copyIntoWorkspace) { - projectPopulator = new ProjectPopulator() { - @Override - public void populate(IProject project) { - // Copy - IFileSystem fileSystem = EFS.getLocalFileSystem(); - File source = (File) data.getParameters().get(PARAM_SOURCE); - IFileStore sourceDir = new ReadWriteFileStore( - fileSystem.getStore(source.toURI())); - IFileStore destDir = new ReadWriteFileStore( - fileSystem.getStore(AdtUtils.getAbsolutePath(project))); - try { - sourceDir.copy(destDir, EFS.OVERWRITE, null); - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - } - }; - } - IProject project = createEclipseProject( - new SubProgressMonitor(monitor, 50), - data.getProject(), - data.getDescription(), - data.getParameters(), - data.getDictionary(), - projectPopulator, - isAndroidProject); - if (project != null) { - final IJavaProject javaProject = JavaCore.create(project); - Display.getDefault().syncExec(new WorksetAdder(javaProject, - mValues.workingSets)); - ProjectHelper.enforcePreferredCompilerCompliance(javaProject); - } - } - } - } catch (CoreException e) { - throw new InvocationTargetException(e); - } catch (IOException e) { - throw new InvocationTargetException(e); - } catch (StreamException e) { - throw new InvocationTargetException(e); - } finally { - monitor.done(); - } - } - - /** Handler which can write contents into a project */ - public interface ProjectPopulator { - /** - * Add contents into the given project - * - * @param project the project to write into - * @throws InvocationTargetException if anything goes wrong - */ - public void populate(IProject project) throws InvocationTargetException; - } - - /** - * Creates the actual project, sets its nature and adds the required folders - * and files to it. This is run asynchronously in a different thread. - * - * @param monitor An existing monitor. - * @param project The project to create. - * @param description A description of the project. - * @param parameters Template parameters. - * @param dictionary String definition. - * @param isAndroidProject true if the project is to be set up as a full Android project; false - * for a plain Java project. - * @return The project newly created - * @throws StreamException - */ - private IProject createEclipseProject( - @NonNull IProgressMonitor monitor, - @NonNull IProject project, - @NonNull IProjectDescription description, - @NonNull Map<String, Object> parameters, - @Nullable Map<String, String> dictionary, - @Nullable ProjectPopulator projectPopulator, - boolean isAndroidProject) - throws CoreException, IOException, StreamException { - - // get the project target - IAndroidTarget target = (IAndroidTarget) parameters.get(PARAM_SDK_TARGET); - boolean legacy = isAndroidProject && target.getVersion().getApiLevel() < 4; - - // Create project and open it - project.create(description, new SubProgressMonitor(monitor, 10)); - if (monitor.isCanceled()) throw new OperationCanceledException(); - - project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 10)); - - // Add the Java and android nature to the project - AndroidNature.setupProjectNatures(project, monitor, isAndroidProject); - - // Create folders in the project if they don't already exist - addDefaultDirectories(project, AdtConstants.WS_ROOT, DEFAULT_DIRECTORIES, monitor); - String[] sourceFolders; - if (isAndroidProject) { - sourceFolders = new String[] { - (String) parameters.get(PARAM_SRC_FOLDER), - GEN_SRC_DIRECTORY - }; - } else { - sourceFolders = new String[] { - (String) parameters.get(PARAM_SRC_FOLDER) - }; - } - addDefaultDirectories(project, AdtConstants.WS_ROOT, sourceFolders, monitor); - - // Create the resource folders in the project if they don't already exist. - if (legacy) { - addDefaultDirectories(project, RES_DIRECTORY, RES_DIRECTORIES, monitor); - } else { - addDefaultDirectories(project, RES_DIRECTORY, RES_DENSITY_ENABLED_DIRECTORIES, monitor); - } - - if (projectPopulator != null) { - try { - projectPopulator.populate(project); - } catch (InvocationTargetException ite) { - AdtPlugin.log(ite, null); - } - } - - // Setup class path: mark folders as source folders - IJavaProject javaProject = JavaCore.create(project); - setupSourceFolders(javaProject, sourceFolders, monitor); - - if (((Boolean) parameters.get(PARAM_IS_NEW_PROJECT)).booleanValue()) { - // Create files in the project if they don't already exist - addManifest(project, parameters, dictionary, monitor); - - // add the default app icon - addIcon(project, legacy, monitor); - - // Create the default package components - addSampleCode(project, sourceFolders[0], parameters, dictionary, monitor); - - // add the string definition file if needed - if (dictionary != null && dictionary.size() > 0) { - addStringDictionaryFile(project, dictionary, monitor); - } - - // add the default proguard config - File libFolder = new File((String) parameters.get(PARAM_SDK_TOOLS_DIR), - SdkConstants.FD_LIB); - addLocalFile(project, - new File(libFolder, SdkConstants.FN_PROJECT_PROGUARD_FILE), - // Write ProGuard config files with the extension .pro which - // is what is used in the ProGuard documentation and samples - SdkConstants.FN_PROJECT_PROGUARD_FILE, - monitor); - - // Set output location - javaProject.setOutputLocation(project.getFolder(BIN_CLASSES_DIRECTORY).getFullPath(), - monitor); - } - - File sampleDir = (File) parameters.get(PARAM_SAMPLE_LOCATION); - if (sampleDir != null) { - // Copy project - copySampleCode(project, sampleDir, parameters, dictionary, monitor); - } - - // Create the reference to the target project - if (parameters.containsKey(PARAM_REFERENCE_PROJECT)) { - IProject refProject = (IProject) parameters.get(PARAM_REFERENCE_PROJECT); - if (refProject != null) { - IProjectDescription desc = project.getDescription(); - - // Add out reference to the existing project reference. - // We just created a project with no references so we don't need to expand - // the currently-empty current list. - desc.setReferencedProjects(new IProject[] { refProject }); - - project.setDescription(desc, IResource.KEEP_HISTORY, - new SubProgressMonitor(monitor, 10)); - - IClasspathEntry entry = JavaCore.newProjectEntry( - refProject.getFullPath(), //path - new IAccessRule[0], //accessRules - false, //combineAccessRules - new IClasspathAttribute[0], //extraAttributes - false //isExported - - ); - ProjectHelper.addEntryToClasspath(javaProject, entry); - } - } - - if (isAndroidProject) { - Sdk.getCurrent().initProject(project, target); - } - - // Fix the project to make sure all properties are as expected. - // Necessary for existing projects and good for new ones to. - ProjectHelper.fixProject(project); - - Boolean isLibraryProject = (Boolean) parameters.get(PARAM_IS_LIBRARY); - if (isLibraryProject != null && isLibraryProject.booleanValue() - && Sdk.getCurrent() != null && project.isOpen()) { - ProjectState state = Sdk.getProjectState(project); - if (state != null) { - // make a working copy of the properties - ProjectPropertiesWorkingCopy properties = - state.getProperties().makeWorkingCopy(); - - properties.setProperty(PROPERTY_LIBRARY, Boolean.TRUE.toString()); - try { - properties.save(); - IResource projectProp = project.findMember(FN_PROJECT_PROPERTIES); - if (projectProp != null) { - projectProp.refreshLocal(DEPTH_ZERO, new NullProgressMonitor()); - } - } catch (Exception e) { - String msg = String.format( - "Failed to save %1$s for project %2$s", - SdkConstants.FN_PROJECT_PROPERTIES, project.getName()); - AdtPlugin.log(e, msg); - } - } - } - - return project; - } - - /** - * Creates a new project - * - * @param monitor An existing monitor. - * @param project The project to create. - * @param target the build target to associate with the project - * @param projectPopulator a handler for writing the template contents - * @param isLibrary whether this project should be marked as a library project - * @param projectLocation the location to write the project into - * @param workingSets Eclipse working sets, if any, to add the project to - * @throws CoreException if anything goes wrong - */ - public static void create( - @NonNull IProgressMonitor monitor, - @NonNull final IProject project, - @NonNull IAndroidTarget target, - @Nullable final ProjectPopulator projectPopulator, - boolean isLibrary, - @NonNull String projectLocation, - @NonNull final IWorkingSet[] workingSets) - throws CoreException { - final NewProjectCreator creator = new NewProjectCreator(null, null); - - final Map<String, String> dictionary = null; - final Map<String, Object> parameters = new HashMap<String, Object>(); - parameters.put(PARAM_SDK_TARGET, target); - parameters.put(PARAM_SRC_FOLDER, SdkConstants.FD_SOURCES); - parameters.put(PARAM_IS_NEW_PROJECT, false); - parameters.put(PARAM_SAMPLE_LOCATION, null); - parameters.put(PARAM_IS_LIBRARY, isLibrary); - - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - final IProjectDescription description = workspace.newProjectDescription(project.getName()); - - if (projectLocation != null) { - IPath path = new Path(projectLocation); - IPath parent = new Path(path.toFile().getParent()); - IPath workspaceLocation = Platform.getLocation(); - if (!workspaceLocation.equals(parent)) { - description.setLocation(path); - } - } - - IWorkspaceRunnable workspaceRunnable = new IWorkspaceRunnable() { - @Override - public void run(IProgressMonitor submonitor) throws CoreException { - try { - creator.createEclipseProject(submonitor, project, description, parameters, - dictionary, projectPopulator, true); - } catch (IOException e) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Unexpected error while creating project", e)); - } catch (StreamException e) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Unexpected error while creating project", e)); - } - if (workingSets != null && workingSets.length > 0) { - IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); - if (javaProject != null) { - Display.getDefault().syncExec(new WorksetAdder(javaProject, - workingSets)); - } - } - } - }; - - ResourcesPlugin.getWorkspace().run(workspaceRunnable, monitor); - } - - /** - * Adds default directories to the project. - * - * @param project The Java Project to update. - * @param parentFolder The path of the parent folder. Must end with a - * separator. - * @param folders Folders to be added. - * @param monitor An existing monitor. - * @throws CoreException if the method fails to create the directories in - * the project. - */ - private void addDefaultDirectories(IProject project, String parentFolder, - String[] folders, IProgressMonitor monitor) throws CoreException { - for (String name : folders) { - if (name.length() > 0) { - IFolder folder = project.getFolder(parentFolder + name); - if (!folder.exists()) { - folder.create(true /* force */, true /* local */, - new SubProgressMonitor(monitor, 10)); - } - } - } - } - - /** - * Adds the manifest to the project. - * - * @param project The Java Project to update. - * @param parameters Template Parameters. - * @param dictionary String List to be added to a string definition - * file. This map will be filled by this method. - * @param monitor An existing monitor. - * @throws CoreException if the method fails to update the project. - * @throws IOException if the method fails to create the files in the - * project. - */ - private void addManifest(IProject project, Map<String, Object> parameters, - Map<String, String> dictionary, IProgressMonitor monitor) - throws CoreException, IOException { - - // get IFile to the manifest and check if it's not already there. - IFile file = project.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML); - if (!file.exists()) { - - // Read manifest template - String manifestTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_MANIFEST); - - // Replace all keyword parameters - manifestTemplate = replaceParameters(manifestTemplate, parameters); - - if (manifestTemplate == null) { - // Inform the user there will be not manifest. - AdtPlugin.logAndPrintError(null, "Create Project" /*TAG*/, - "Failed to generate the Android manifest. Missing template %s", - TEMPLATE_MANIFEST); - // Abort now, there's no need to continue - return; - } - - if (parameters.containsKey(PARAM_ACTIVITY)) { - // now get the activity template - String activityTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_ACTIVITIES); - - // If the activity name doesn't contain any dot, it's in the form - // "ClassName" and we need to expand it to ".ClassName" in the XML. - String name = (String) parameters.get(PARAM_ACTIVITY); - if (name.indexOf('.') == -1) { - // Duplicate the parameters map to avoid changing the caller - parameters = new HashMap<String, Object>(parameters); - parameters.put(PARAM_ACTIVITY, "." + name); //$NON-NLS-1$ - } - - // Replace all keyword parameters to make main activity. - String activities = replaceParameters(activityTemplate, parameters); - - // set the intent. - String intent = AdtPlugin.readEmbeddedTextFile(TEMPLATE_INTENT_LAUNCHER); - - if (activities != null) { - if (intent != null) { - // set the intent to the main activity - activities = activities.replaceAll(PH_INTENT_FILTERS, intent); - } - - // set the activity(ies) in the manifest - manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, activities); - } - } else { - // remove the activity(ies) from the manifest - manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, ""); //$NON-NLS-1$ - } - - // Handle the case of the test projects - if (parameters.containsKey(PARAM_TEST_TARGET_PACKAGE)) { - // Set the uses-library needed by the test project - String usesLibrary = AdtPlugin.readEmbeddedTextFile(TEMPLATE_TEST_USES_LIBRARY); - if (usesLibrary != null) { - manifestTemplate = manifestTemplate.replaceAll( - PH_TEST_USES_LIBRARY, usesLibrary); - } - - // Set the instrumentation element needed by the test project - String instru = AdtPlugin.readEmbeddedTextFile(TEMPLATE_TEST_INSTRUMENTATION); - if (instru != null) { - manifestTemplate = manifestTemplate.replaceAll( - PH_TEST_INSTRUMENTATION, instru); - } - - // Replace PARAM_TEST_TARGET_PACKAGE itself now - manifestTemplate = replaceParameters(manifestTemplate, parameters); - - } else { - // remove the unused entries - manifestTemplate = manifestTemplate.replaceAll(PH_TEST_USES_LIBRARY, ""); //$NON-NLS-1$ - manifestTemplate = manifestTemplate.replaceAll(PH_TEST_INSTRUMENTATION, ""); //$NON-NLS-1$ - } - - String minSdkVersion = (String) parameters.get(PARAM_MIN_SDK_VERSION); - if (minSdkVersion != null && minSdkVersion.length() > 0) { - String usesSdkTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_USES_SDK); - if (usesSdkTemplate != null) { - String usesSdk = replaceParameters(usesSdkTemplate, parameters); - manifestTemplate = manifestTemplate.replaceAll(PH_USES_SDK, usesSdk); - } - } else { - manifestTemplate = manifestTemplate.replaceAll(PH_USES_SDK, ""); - } - - // Reformat the file according to the user's formatting settings - manifestTemplate = reformat(XmlFormatStyle.MANIFEST, manifestTemplate); - - // Save in the project as UTF-8 - InputStream stream = new ByteArrayInputStream( - manifestTemplate.getBytes("UTF-8")); //$NON-NLS-1$ - file.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); - } - } - - /** - * Adds the string resource file. - * - * @param project The Java Project to update. - * @param strings The list of strings to be added to the string file. - * @param monitor An existing monitor. - * @throws CoreException if the method fails to update the project. - * @throws IOException if the method fails to create the files in the - * project. - */ - private void addStringDictionaryFile(IProject project, - Map<String, String> strings, IProgressMonitor monitor) - throws CoreException, IOException { - - // create the IFile object and check if the file doesn't already exist. - IFile file = project.getFile(RES_DIRECTORY + AdtConstants.WS_SEP - + VALUES_DIRECTORY + AdtConstants.WS_SEP + STRINGS_FILE); - if (!file.exists()) { - // get the Strings.xml template - String stringDefinitionTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_STRINGS); - - // get the template for one string - String stringTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_STRING); - - // get all the string names - Set<String> stringNames = strings.keySet(); - - // loop on it and create the string definitions - StringBuilder stringNodes = new StringBuilder(); - for (String key : stringNames) { - // get the value from the key - String value = strings.get(key); - - // Escape values if necessary - value = ValueXmlHelper.escapeResourceString(value); - - // place them in the template - String stringDef = stringTemplate.replace(PARAM_STRING_NAME, key); - stringDef = stringDef.replace(PARAM_STRING_CONTENT, value); - - // append to the other string - if (stringNodes.length() > 0) { - stringNodes.append('\n'); - } - stringNodes.append(stringDef); - } - - // put the string nodes in the Strings.xml template - stringDefinitionTemplate = stringDefinitionTemplate.replace(PH_STRINGS, - stringNodes.toString()); - - // reformat the file according to the user's formatting settings - stringDefinitionTemplate = reformat(XmlFormatStyle.RESOURCE, stringDefinitionTemplate); - - // write the file as UTF-8 - InputStream stream = new ByteArrayInputStream( - stringDefinitionTemplate.getBytes("UTF-8")); //$NON-NLS-1$ - file.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); - } - } - - /** Reformats the given contents with the current formatting settings */ - private String reformat(XmlFormatStyle style, String contents) { - if (AdtPrefs.getPrefs().getUseCustomXmlFormatter()) { - EclipseXmlFormatPreferences formatPrefs = EclipseXmlFormatPreferences.create(); - return EclipseXmlPrettyPrinter.prettyPrint(contents, formatPrefs, style, - null /*lineSeparator*/); - } else { - return contents; - } - } - - /** - * Adds default application icon to the project. - * - * @param project The Java Project to update. - * @param legacy whether we're running in legacy mode (no density support) - * @param monitor An existing monitor. - * @throws CoreException if the method fails to update the project. - */ - private void addIcon(IProject project, boolean legacy, IProgressMonitor monitor) - throws CoreException { - if (legacy) { // density support - // do medium density icon only, in the default drawable folder. - IFile file = project.getFile(RES_DIRECTORY + AdtConstants.WS_SEP - + DRAWABLE_DIRECTORY + AdtConstants.WS_SEP + PROJECT_ICON); - if (!file.exists()) { - addFile(file, AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON_MDPI), monitor); - } - } else { - // do all 4 icons. - IFile file; - - // extra high density - file = project.getFile(RES_DIRECTORY + AdtConstants.WS_SEP - + DRAWABLE_XHDPI_DIRECTORY + AdtConstants.WS_SEP + PROJECT_ICON); - if (!file.exists()) { - addFile(file, AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON_XHDPI), monitor); - } - - // high density - file = project.getFile(RES_DIRECTORY + AdtConstants.WS_SEP - + DRAWABLE_HDPI_DIRECTORY + AdtConstants.WS_SEP + PROJECT_ICON); - if (!file.exists()) { - addFile(file, AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON_HDPI), monitor); - } - - // medium density - file = project.getFile(RES_DIRECTORY + AdtConstants.WS_SEP - + DRAWABLE_MDPI_DIRECTORY + AdtConstants.WS_SEP + PROJECT_ICON); - if (!file.exists()) { - addFile(file, AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON_MDPI), monitor); - } - - // low density - file = project.getFile(RES_DIRECTORY + AdtConstants.WS_SEP - + DRAWABLE_LDPI_DIRECTORY + AdtConstants.WS_SEP + PROJECT_ICON); - if (!file.exists()) { - addFile(file, AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON_LDPI), monitor); - } - } - } - - /** - * Creates a file from a data source. - * @param dest the file to write - * @param source the content of the file. - * @param monitor the progress monitor - * @throws CoreException - */ - private void addFile(IFile dest, byte[] source, IProgressMonitor monitor) throws CoreException { - if (source != null) { - // Save in the project - InputStream stream = new ByteArrayInputStream(source); - dest.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); - } - } - - /** - * Creates the package folder and copies the sample code in the project. - * - * @param project The Java Project to update. - * @param parameters Template Parameters. - * @param dictionary String List to be added to a string definition - * file. This map will be filled by this method. - * @param monitor An existing monitor. - * @throws CoreException if the method fails to update the project. - * @throws IOException if the method fails to create the files in the - * project. - */ - private void addSampleCode(IProject project, String sourceFolder, - Map<String, Object> parameters, Map<String, String> dictionary, - IProgressMonitor monitor) throws CoreException, IOException { - // create the java package directories. - IFolder pkgFolder = project.getFolder(sourceFolder); - String packageName = (String) parameters.get(PARAM_PACKAGE); - - // The PARAM_ACTIVITY key will be absent if no activity should be created, - // in which case activityName will be null. - String activityName = (String) parameters.get(PARAM_ACTIVITY); - - Map<String, Object> java_activity_parameters = new HashMap<String, Object>(parameters); - java_activity_parameters.put(PARAM_IMPORT_RESOURCE_CLASS, ""); //$NON-NLS-1$ - - if (activityName != null) { - - String resourcePackageClass = null; - - // An activity name can be of the form ".package.Class", ".Class" or FQDN. - // The initial dot is ignored, as it is always added later in the templates. - int lastDotIndex = activityName.lastIndexOf('.'); - - if (lastDotIndex != -1) { - - // Resource class - if (lastDotIndex > 0) { - resourcePackageClass = packageName + '.' + SdkConstants.FN_RESOURCE_BASE; - } - - // Package name - if (activityName.startsWith(".")) { //$NON-NLS-1$ - packageName += activityName.substring(0, lastDotIndex); - } else { - packageName = activityName.substring(0, lastDotIndex); - } - - // Activity Class name - activityName = activityName.substring(lastDotIndex + 1); - } - - java_activity_parameters.put(PARAM_ACTIVITY, activityName); - java_activity_parameters.put(PARAM_PACKAGE, packageName); - if (resourcePackageClass != null) { - String importResourceClass = "\nimport " + resourcePackageClass + ";"; //$NON-NLS-1$ // $NON-NLS-2$ - java_activity_parameters.put(PARAM_IMPORT_RESOURCE_CLASS, importResourceClass); - } - } - - String[] components = packageName.split(AdtConstants.RE_DOT); - for (String component : components) { - pkgFolder = pkgFolder.getFolder(component); - if (!pkgFolder.exists()) { - pkgFolder.create(true /* force */, true /* local */, - new SubProgressMonitor(monitor, 10)); - } - } - - if (activityName != null) { - // create the main activity Java file - String activityJava = activityName + SdkConstants.DOT_JAVA; - IFile file = pkgFolder.getFile(activityJava); - if (!file.exists()) { - copyFile(JAVA_ACTIVITY_TEMPLATE, file, java_activity_parameters, monitor, false); - } - - // create the layout file (if we're creating an - IFolder layoutfolder = project.getFolder(RES_DIRECTORY).getFolder(LAYOUT_DIRECTORY); - file = layoutfolder.getFile(MAIN_LAYOUT_XML); - if (!file.exists()) { - copyFile(LAYOUT_TEMPLATE, file, parameters, monitor, true); - dictionary.put(STRING_HELLO_WORLD, String.format("Hello World, %1$s!", - activityName)); - } - } - } - - private void copySampleCode(IProject project, File sampleDir, - Map<String, Object> parameters, Map<String, String> dictionary, - IProgressMonitor monitor) throws CoreException { - // Copy the sampleDir into the project directory recursively - IFileSystem fileSystem = EFS.getLocalFileSystem(); - IFileStore sourceDir = new ReadWriteFileStore( - fileSystem.getStore(sampleDir.toURI())); - IFileStore destDir = new ReadWriteFileStore( - fileSystem.getStore(AdtUtils.getAbsolutePath(project))); - sourceDir.copy(destDir, EFS.OVERWRITE, null); - } - - /** - * In a sample we never duplicate source files as read-only. - * This creates a store that read files attributes and doesn't set the r-o flag. - */ - private static class ReadWriteFileStore extends FileStoreAdapter { - - public ReadWriteFileStore(IFileStore store) { - super(store); - } - - // Override when reading attributes - @Override - public IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException { - IFileInfo info = super.fetchInfo(options, monitor); - info.setAttribute(EFS.ATTRIBUTE_READ_ONLY, false); - return info; - } - - // Override when writing attributes - @Override - public void putInfo(IFileInfo info, int options, IProgressMonitor storeMonitor) - throws CoreException { - info.setAttribute(EFS.ATTRIBUTE_READ_ONLY, false); - super.putInfo(info, options, storeMonitor); - } - - @Deprecated - @Override - public IFileStore getChild(IPath path) { - IFileStore child = super.getChild(path); - if (!(child instanceof ReadWriteFileStore)) { - child = new ReadWriteFileStore(child); - } - return child; - } - - @Override - public IFileStore getChild(String name) { - return new ReadWriteFileStore(super.getChild(name)); - } - } - - /** - * Adds a file to the root of the project - * @param project the project to add the file to. - * @param destName the name to write the file as - * @param source the file to add. It'll keep the same filename once copied into the project. - * @param monitor the monitor to report progress to - * @throws FileNotFoundException if the file to be added does not exist - * @throws CoreException if writing the file does not work - */ - public static void addLocalFile(IProject project, File source, String destName, - IProgressMonitor monitor) throws FileNotFoundException, CoreException { - IFile dest = project.getFile(destName); - if (dest.exists() == false) { - FileInputStream stream = new FileInputStream(source); - dest.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); - } - } - - /** - * Adds the given folder to the project's class path. - * - * @param javaProject The Java Project to update. - * @param sourceFolders Template Parameters. - * @param monitor An existing monitor. - * @throws JavaModelException if the classpath could not be set. - */ - private void setupSourceFolders(IJavaProject javaProject, String[] sourceFolders, - IProgressMonitor monitor) throws JavaModelException { - IProject project = javaProject.getProject(); - - // get the list of entries. - IClasspathEntry[] entries = javaProject.getRawClasspath(); - - // remove the project as a source folder (This is the default) - entries = removeSourceClasspath(entries, project); - - // add the source folders. - for (String sourceFolder : sourceFolders) { - IFolder srcFolder = project.getFolder(sourceFolder); - - // remove it first in case. - entries = removeSourceClasspath(entries, srcFolder); - entries = ProjectHelper.addEntryToClasspath(entries, - JavaCore.newSourceEntry(srcFolder.getFullPath())); - } - - javaProject.setRawClasspath(entries, new SubProgressMonitor(monitor, 10)); - } - - - /** - * Removes the corresponding source folder from the class path entries if - * found. - * - * @param entries The class path entries to read. A copy will be returned. - * @param folder The parent source folder to remove. - * @return A new class path entries array. - */ - private IClasspathEntry[] removeSourceClasspath(IClasspathEntry[] entries, IContainer folder) { - if (folder == null) { - return entries; - } - IClasspathEntry source = JavaCore.newSourceEntry(folder.getFullPath()); - int n = entries.length; - for (int i = n - 1; i >= 0; i--) { - if (entries[i].equals(source)) { - IClasspathEntry[] newEntries = new IClasspathEntry[n - 1]; - if (i > 0) System.arraycopy(entries, 0, newEntries, 0, i); - if (i < n - 1) System.arraycopy(entries, i + 1, newEntries, i, n - i - 1); - n--; - entries = newEntries; - } - } - return entries; - } - - - /** - * Copies the given file from our resource folder to the new project. - * Expects the file to the US-ASCII or UTF-8 encoded. - * - * @throws CoreException from IFile if failing to create the new file. - * @throws MalformedURLException from URL if failing to interpret the URL. - * @throws FileNotFoundException from RandomAccessFile. - * @throws IOException from RandomAccessFile.length() if can't determine the - * length. - */ - private void copyFile(String resourceFilename, IFile destFile, - Map<String, Object> parameters, IProgressMonitor monitor, boolean reformat) - throws CoreException, IOException { - - // Read existing file. - String template = AdtPlugin.readEmbeddedTextFile( - TEMPLATES_DIRECTORY + resourceFilename); - - // Replace all keyword parameters - template = replaceParameters(template, parameters); - - if (reformat) { - // Guess the formatting style based on the file location - XmlFormatStyle style = EclipseXmlPrettyPrinter - .getForFile(destFile.getProjectRelativePath()); - if (style != null) { - template = reformat(style, template); - } - } - - // Save in the project as UTF-8 - InputStream stream = new ByteArrayInputStream(template.getBytes("UTF-8")); //$NON-NLS-1$ - destFile.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); - } - - /** - * Replaces placeholders found in a string with values. - * - * @param str the string to search for placeholders. - * @param parameters a map of <placeholder, Value> to search for in the string - * @return A new String object with the placeholder replaced by the values. - */ - private String replaceParameters(String str, Map<String, Object> parameters) { - - if (parameters == null) { - AdtPlugin.log(IStatus.ERROR, - "NPW replace parameters: null parameter map. String: '%s'", str); //$NON-NLS-1$ - return str; - } else if (str == null) { - AdtPlugin.log(IStatus.ERROR, - "NPW replace parameters: null template string"); //$NON-NLS-1$ - return str; - } - - for (Entry<String, Object> entry : parameters.entrySet()) { - if (entry != null && entry.getValue() instanceof String) { - Object value = entry.getValue(); - if (value == null) { - AdtPlugin.log(IStatus.ERROR, - "NPW replace parameters: null value for key '%s' in template '%s'", //$NON-NLS-1$ - entry.getKey(), - str); - } else { - str = str.replaceAll(entry.getKey(), (String) value); - } - } - } - - return str; - } - - private static class WorksetAdder implements Runnable { - private final IJavaProject mProject; - private final IWorkingSet[] mWorkingSets; - - private WorksetAdder(IJavaProject project, IWorkingSet[] workingSets) { - mProject = project; - mWorkingSets = workingSets; - } - - @Override - public void run() { - if (mWorkingSets.length > 0 && mProject != null - && mProject.exists()) { - PlatformUI.getWorkbench().getWorkingSetManager() - .addToWorkingSets(mProject, mWorkingSets); - } - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java deleted file mode 100644 index ff03b338f..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2011 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.newproject; - -import static com.android.SdkConstants.FN_PROJECT_PROGUARD_FILE; -import static com.android.SdkConstants.OS_SDK_TOOLS_LIB_FOLDER; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; - -import org.eclipse.jdt.ui.actions.OpenJavaPerspectiveAction; -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.ui.IWorkbench; - -import java.io.File; - - -/** - * A "New Android Project" Wizard. - * <p/> - * Note: this class is public so that it can be accessed from unit tests. - * It is however an internal class. Its API may change without notice. - * It should semantically be considered as a private final class. - * <p/> - * Do not derive from this class. - */ -public class NewProjectWizard extends Wizard implements INewWizard { - private static final String PROJECT_LOGO_LARGE = "icons/android-64.png"; //$NON-NLS-1$ - - private NewProjectWizardState mValues; - private ProjectNamePage mNamePage; - private SdkSelectionPage mSdkPage; - private SampleSelectionPage mSamplePage; - private ApplicationInfoPage mPropertiesPage; - private final Mode mMode; - private IStructuredSelection mSelection; - - /** Constructs a new wizard default project wizard */ - public NewProjectWizard() { - this(Mode.ANY); - } - - protected NewProjectWizard(Mode mode) { - mMode = mode; - switch (mMode) { - case SAMPLE: - setWindowTitle("New Android Sample Project"); - break; - case TEST: - setWindowTitle("New Android Test Project"); - break; - default: - setWindowTitle("New Android Project"); - break; - } - } - - @Override - public void addPages() { - mValues = new NewProjectWizardState(mMode); - - if (mMode != Mode.SAMPLE) { - mNamePage = new ProjectNamePage(mValues); - - if (mSelection != null) { - mNamePage.init(mSelection, AdtUtils.getActivePart()); - } - - addPage(mNamePage); - } - - if (mMode == Mode.TEST) { - addPage(new TestTargetPage(mValues)); - } - - mSdkPage = new SdkSelectionPage(mValues); - addPage(mSdkPage); - - if (mMode != Mode.TEST) { - // Sample projects can be created when entering the new/existing wizard, or - // the sample wizard - mSamplePage = new SampleSelectionPage(mValues); - addPage(mSamplePage); - } - - if (mMode != Mode.SAMPLE) { - // Project properties are entered in all project types except sample projects - mPropertiesPage = new ApplicationInfoPage(mValues); - addPage(mPropertiesPage); - } - } - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - mSelection = selection; - - setHelpAvailable(false); // TODO have help - ImageDescriptor desc = AdtPlugin.getImageDescriptor(PROJECT_LOGO_LARGE); - setDefaultPageImageDescriptor(desc); - - // Trigger a check to see if the SDK needs to be reloaded (which will - // invoke onSdkLoaded asynchronously as needed). - AdtPlugin.getDefault().refreshSdk(); - } - - @Override - public boolean performFinish() { - File file = new File(AdtPlugin.getOsSdkFolder(), OS_SDK_TOOLS_LIB_FOLDER + File.separator - + FN_PROJECT_PROGUARD_FILE); - if (!file.exists()) { - AdtPlugin.displayError("Tools Out of Date?", - String.format("It looks like you do not have the latest version of the " - + "SDK Tools installed. Make sure you update via the SDK Manager " - + "first. (Could not find %1$s)", file.getPath())); - return false; - } - - NewProjectCreator creator = new NewProjectCreator(mValues, getContainer()); - if (!(creator.createAndroidProjects())) { - return false; - } - - // Open the default Java Perspective - OpenJavaPerspectiveAction action = new OpenJavaPerspectiveAction(); - action.run(); - return true; - } - - @Override - public IWizardPage getNextPage(IWizardPage page) { - if (page == mNamePage) { - // Skip the test target selection page unless creating a test project - if (mValues.mode != Mode.TEST) { - return mSdkPage; - } - } else if (page == mSdkPage) { - if (mValues.mode == Mode.SAMPLE) { - return mSamplePage; - } else if (mValues.mode != Mode.TEST) { - return mPropertiesPage; - } else { - // Done with wizard when creating from existing or creating test projects - return null; - } - } else if (page == mSamplePage) { - // Nothing more to be entered for samples - return null; - } - - return super.getNextPage(page); - } - - /** - * Returns the package name currently set by the wizard - * - * @return the current package name, or null - */ - public String getPackageName() { - return mValues.packageName; - } - - // TBD: Call setDialogSettings etc to store persistent state between wizard invocations. -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizardState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizardState.java deleted file mode 100644 index 06c0300b7..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizardState.java +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright (C) 2011 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.newproject; - -import com.android.SdkConstants; -import com.android.annotations.Nullable; -import com.android.ide.common.xml.ManifestData; -import com.android.ide.common.xml.ManifestData.Activity; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.internal.project.ProjectProperties; -import com.android.sdklib.internal.project.ProjectProperties.PropertyType; -import com.android.utils.Pair; -import com.android.xml.AndroidManifest; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.ui.IWorkingSet; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -/** - * The {@link NewProjectWizardState} holds the state used by the various pages - * in the {@link NewProjectWizard} and its variations, and it can also be used - * to pass project information to the {@link NewProjectCreator}. - */ -public class NewProjectWizardState { - /** The mode to run the wizard in: creating test, or sample, or plain project */ - public Mode mode; - - /** - * If true, the project should be created from an existing codebase (pointed - * to by the {@link #projectLocation} or in the case of sample projects, the - * {@link #chosenSample}. Otherwise, create a brand new project from scratch. - */ - public boolean useExisting; - - /** - * Whether new projects should be created into the default project location - * (e.g. in the Eclipse workspace) or not - */ - public boolean useDefaultLocation = true; - - /** The build target SDK */ - public IAndroidTarget target; - /** True if the user has manually modified the target */ - public boolean targetModifiedByUser; - - /** The location to store projects into */ - public File projectLocation = new File(Platform.getLocation().toOSString()); - /** True if the project location name has been manually edited by the user */ - public boolean projectLocationModifiedByUser; - - /** The name of the project */ - public String projectName = ""; //$NON-NLS-1$ - /** True if the project name has been manually edited by the user */ - public boolean projectNameModifiedByUser; - - /** The application name */ - public String applicationName; - /** True if the application name has been manually edited by the user */ - public boolean applicationNameModifiedByUser; - - /** The package path */ - public String packageName; - /** True if the package name has been manually edited by the user */ - public boolean packageNameModifiedByUser; - - /** True if a new activity should be created */ - public boolean createActivity; - - /** The name of the new activity to be created */ - public String activityName; - /** True if the activity name has been manually edited by the user */ - public boolean activityNameModifiedByUser; - - /** The minimum SDK version to use with the project (may be null or blank) */ - public String minSdk; - /** True if the minimum SDK version has been manually edited by the user */ - public boolean minSdkModifiedByUser; - /** - * A list of paths to each of the available samples for the current SDK. - * The pair is (String: sample display name => File: sample directory). - * Note we want a list, not a map since we might have duplicates. - * */ - public List<Pair<String, File>> samples = new ArrayList<Pair<String, File>>(); - /** Path to the currently chosen sample */ - public File chosenSample; - - /** The name of the source folder, relative to the project root */ - public String sourceFolder = SdkConstants.FD_SOURCES; - /** The set of chosen working sets to use when creating the project */ - public IWorkingSet[] workingSets = new IWorkingSet[0]; - - /** - * A reference to a different project that the current test project will be - * testing. - */ - public IProject testedProject; - /** - * If true, this test project should be testing itself, otherwise it will be - * testing the project pointed to by {@link #testedProject}. - */ - public boolean testingSelf; - - // NOTE: These apply only to creating paired projects; when isTest is true - // we're using - // the normal fields above - /** - * If true, create a test project along with this plain project which will - * be testing the plain project. (This flag only applies when creating - * normal projects.) - */ - public boolean createPairProject; - /** - * The application name of the test application (only applies when - * {@link #createPairProject} is true) - */ - public String testApplicationName; - /** - * True if the testing application name has been modified by the user (only - * applies when {@link #createPairProject} is true) - */ - public boolean testApplicationNameModified; - /** - * The package name of the test application (only applies when - * {@link #createPairProject} is true) - */ - public String testPackageName; - /** - * True if the testing package name has been modified by the user (only - * applies when {@link #createPairProject} is true) - */ - public boolean testPackageModified; - /** - * The project name of the test project (only applies when - * {@link #createPairProject} is true) - */ - public String testProjectName; - /** - * True if the testing project name has been modified by the user (only - * applies when {@link #createPairProject} is true) - */ - public boolean testProjectModified; - /** Package name of the tested app */ - public String testTargetPackageName; - - /** - * Copy project into workspace? This flag only applies when importing - * projects (creating projects from existing source) - */ - public boolean copyIntoWorkspace; - - /** - * List of projects to be imported. Null if not importing projects. - */ - @Nullable - public List<ImportedProject> importProjects; - - /** - * Creates a new {@link NewProjectWizardState} - * - * @param mode the mode to run the wizard in - */ - public NewProjectWizardState(Mode mode) { - this.mode = mode; - if (mode == Mode.SAMPLE) { - useExisting = true; - } else if (mode == Mode.TEST) { - createActivity = false; - } - } - - /** - * Extract information (package name, application name, minimum SDK etc) from - * the given Android project. - * - * @param path the path to the project to extract information from - */ - public void extractFromAndroidManifest(Path path) { - String osPath = path.append(SdkConstants.FN_ANDROID_MANIFEST_XML).toOSString(); - if (!(new File(osPath).exists())) { - return; - } - - ManifestData manifestData = AndroidManifestHelper.parseForData(osPath); - if (manifestData == null) { - return; - } - - String newPackageName = null; - Activity activity = null; - String newActivityName = null; - String minSdkVersion = null; - try { - newPackageName = manifestData.getPackage(); - minSdkVersion = manifestData.getMinSdkVersionString(); - - // try to get the first launcher activity. If none, just take the first activity. - activity = manifestData.getLauncherActivity(); - if (activity == null) { - Activity[] activities = manifestData.getActivities(); - if (activities != null && activities.length > 0) { - activity = activities[0]; - } - } - } catch (Exception e) { - // ignore exceptions - } - - if (newPackageName != null && newPackageName.length() > 0) { - packageName = newPackageName; - } - - if (activity != null) { - newActivityName = AndroidManifest.extractActivityName(activity.getName(), - newPackageName); - } - - if (newActivityName != null && newActivityName.length() > 0) { - activityName = newActivityName; - // we are "importing" an existing activity, not creating a new one - createActivity = false; - - // If project name and application names are empty, use the activity - // name as a default. If the activity name has dots, it's a part of a - // package specification and only the last identifier must be used. - if (newActivityName.indexOf('.') != -1) { - String[] ids = newActivityName.split(AdtConstants.RE_DOT); - newActivityName = ids[ids.length - 1]; - } - if (projectName == null || projectName.length() == 0 || - !projectNameModifiedByUser) { - projectName = newActivityName; - projectNameModifiedByUser = false; - } - if (applicationName == null || applicationName.length() == 0 || - !applicationNameModifiedByUser) { - applicationNameModifiedByUser = false; - applicationName = newActivityName; - } - } else { - activityName = ""; //$NON-NLS-1$ - - // There is no activity name to use to fill in the project and application - // name. However if there's a package name, we can use this as a base. - if (newPackageName != null && newPackageName.length() > 0) { - // Package name is a java identifier, so it's most suitable for - // an application name. - - if (applicationName == null || applicationName.length() == 0 || - !applicationNameModifiedByUser) { - applicationName = newPackageName; - } - - // For the project name, remove any dots - newPackageName = newPackageName.replace('.', '_'); - if (projectName == null || projectName.length() == 0 || - !projectNameModifiedByUser) { - projectName = newPackageName; - } - - } - } - - if (mode == Mode.ANY && useExisting) { - updateSdkTargetToMatchProject(path.toFile()); - } - - minSdk = minSdkVersion; - minSdkModifiedByUser = false; - } - - /** - * Try to find an SDK Target that matches the current MinSdkVersion. - * - * There can be multiple targets with the same sdk api version, so don't change - * it if it's already at the right version. Otherwise pick the first target - * that matches. - */ - public void updateSdkTargetToMatchMinSdkVersion() { - IAndroidTarget currentTarget = target; - if (currentTarget != null && currentTarget.getVersion().equals(minSdk)) { - return; - } - - Sdk sdk = Sdk.getCurrent(); - if (sdk != null) { - IAndroidTarget[] targets = sdk.getTargets(); - for (IAndroidTarget t : targets) { - if (t.getVersion().equals(minSdk)) { - target = t; - return; - } - } - } - } - - /** - * Updates the SDK to reflect the SDK required by the project at the given - * location - * - * @param location the location of the project - */ - public void updateSdkTargetToMatchProject(File location) { - // Select the target matching the manifest's sdk or build properties, if any - IAndroidTarget foundTarget = null; - // This is the target currently in the UI - IAndroidTarget currentTarget = target; - String projectPath = location.getPath(); - - // If there's a current target defined, we do not allow to change it when - // operating in the create-from-sample mode -- since the available sample list - // is tied to the current target, so changing it would invalidate the project we're - // trying to load in the first place. - if (!targetModifiedByUser) { - ProjectProperties p = ProjectProperties.load(projectPath, - PropertyType.PROJECT); - if (p != null) { - String v = p.getProperty(ProjectProperties.PROPERTY_TARGET); - IAndroidTarget desiredTarget = Sdk.getCurrent().getTargetFromHashString(v); - // We can change the current target if: - // - we found a new desired target - // - there is no current target - // - or the current target can't run the desired target - if (desiredTarget != null && - (currentTarget == null || !desiredTarget.canRunOn(currentTarget))) { - foundTarget = desiredTarget; - } - } - - Sdk sdk = Sdk.getCurrent(); - IAndroidTarget[] targets = null; - if (sdk != null) { - targets = sdk.getTargets(); - } - if (targets == null) { - targets = new IAndroidTarget[0]; - } - - if (foundTarget == null && minSdk != null) { - // Otherwise try to match the requested min-sdk-version if we find an - // exact match, regardless of the currently selected target. - for (IAndroidTarget existingTarget : targets) { - if (existingTarget != null && - existingTarget.getVersion().equals(minSdk)) { - foundTarget = existingTarget; - break; - } - } - } - - if (foundTarget == null) { - // Or last attempt, try to match a sample project location and use it - // if we find an exact match, regardless of the currently selected target. - for (IAndroidTarget existingTarget : targets) { - if (existingTarget != null && - projectPath.startsWith(existingTarget.getLocation())) { - foundTarget = existingTarget; - break; - } - } - } - } - - if (foundTarget != null) { - target = foundTarget; - } - } - - /** - * Type of project being offered/created by the wizard - */ - public enum Mode { - /** Create a sample project. Testing options are not presented. */ - SAMPLE, - - /** - * Create a test project, either testing itself or some other project. - * Note that even if in the {@link #ANY} mode, a test project can be - * created as a *paired* project with the main project, so this flag - * only means that we are creating *just* a test project - */ - TEST, - - /** - * Create an Android project, which can be a plain project, optionally - * with a paired test project, or a sample project (the first page - * contains toggles for choosing which - */ - ANY; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewSampleProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewSampleProjectWizard.java deleted file mode 100644 index 6b6a4c29e..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewSampleProjectWizard.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2011 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.newproject; - -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; - -/** - * A "New Sample Android Project" Wizard. - * <p/> - * This displays the new project wizard pre-configured for samples only. - */ -public class NewSampleProjectWizard extends NewProjectWizard { - /** - * Creates a new wizard for creating a sample Android project - */ - public NewSampleProjectWizard() { - super(Mode.SAMPLE); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectWizard.java deleted file mode 100644 index e0959f4db..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectWizard.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2011 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.newproject; - -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; - -/** - * A "New Test Android Project" Wizard. - * <p/> - * This is really the {@link NewProjectWizard} that only displays the "test project" pages. - */ -public class NewTestProjectWizard extends NewProjectWizard { - /** - * Creates a new wizard for creating an Android Test Project - */ - public NewTestProjectWizard() { - super(Mode.TEST); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java deleted file mode 100644 index d04ea897f..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java +++ /dev/null @@ -1,606 +0,0 @@ -/* - * Copyright (C) 2011 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.newproject; - -import static com.android.SdkConstants.FN_PROJECT_PROGUARD_FILE; -import static com.android.SdkConstants.OS_SDK_TOOLS_LIB_FOLDER; -import static com.android.ide.eclipse.adt.AdtUtils.capitalize; -import static com.android.ide.eclipse.adt.internal.wizards.newproject.ApplicationInfoPage.ACTIVITY_NAME_SUFFIX; -import static com.android.utils.SdkUtils.stripWhitespace; - -import com.android.SdkConstants; -import com.android.ide.common.xml.ManifestData; -import com.android.ide.common.xml.ManifestData.Activity; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.VersionCheck; -import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; - -import org.eclipse.core.filesystem.URIUtil; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.osgi.util.TextProcessor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkingSet; - -import java.io.File; -import java.net.URI; -import java.util.Locale; - -/** - * Initial page shown when creating projects which asks for the project name, - * the the location of the project, working sets, etc. - */ -public class ProjectNamePage extends WizardPage implements SelectionListener, ModifyListener { - private final NewProjectWizardState mValues; - /** Flag used when setting button/text state manually to ignore listener updates */ - private boolean mIgnore; - /** Last user-browsed location, static so that it be remembered for the whole session */ - private static String sCustomLocationOsPath = ""; //$NON-NLS-1$ - private static boolean sAutoComputeCustomLocation = true; - - private Text mProjectNameText; - private Text mLocationText; - private Button mCreateSampleRadioButton; - private Button mCreateNewButton; - private Button mUseDefaultCheckBox; - private Button mBrowseButton; - private Label mLocationLabel; - private WorkingSetGroup mWorkingSetGroup; - /** - * Whether we've made sure the Tools are up to date (enough that all the - * resources required by the New Project wizard are present -- we don't - * necessarily check for newer versions than that here; that's done by - * {@link VersionCheck}, though that check doesn't <b>enforce</b> an update - * since it needs to allow the user to proceed to access the SDK manager - * etc.) - */ - private boolean mCheckedSdkUptodate; - - /** - * Create the wizard. - * @param values current wizard state - */ - ProjectNamePage(NewProjectWizardState values) { - super("projectNamePage"); //$NON-NLS-1$ - mValues = values; - - setTitle("Create Android Project"); - setDescription("Select project name and type of project"); - mWorkingSetGroup = new WorkingSetGroup(); - setWorkingSets(new IWorkingSet[0]); - } - - void init(IStructuredSelection selection, IWorkbenchPart activePart) { - setWorkingSets(WorkingSetHelper.getSelectedWorkingSet(selection, activePart)); - } - - /** - * Create contents of the wizard. - * @param parent the parent to add the page to - */ - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - container.setLayout(new GridLayout(3, false)); - - Label nameLabel = new Label(container, SWT.NONE); - nameLabel.setText("Project Name:"); - - mProjectNameText = new Text(container, SWT.BORDER); - mProjectNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); - mProjectNameText.addModifyListener(this); - - if (mValues.mode != Mode.TEST) { - mCreateNewButton = new Button(container, SWT.RADIO); - mCreateNewButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); - mCreateNewButton.setText("Create new project in workspace"); - mCreateNewButton.addSelectionListener(this); - - // TBD: Should we hide this completely, and make samples something you only invoke - // from the "New Sample Project" wizard? - mCreateSampleRadioButton = new Button(container, SWT.RADIO); - mCreateSampleRadioButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, - 3, 1)); - mCreateSampleRadioButton.setText("Create project from existing sample"); - mCreateSampleRadioButton.addSelectionListener(this); - } - - Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL); - separator.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1)); - - mUseDefaultCheckBox = new Button(container, SWT.CHECK); - mUseDefaultCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); - mUseDefaultCheckBox.setText("Use default location"); - mUseDefaultCheckBox.addSelectionListener(this); - - mLocationLabel = new Label(container, SWT.NONE); - mLocationLabel.setText("Location:"); - - mLocationText = new Text(container, SWT.BORDER); - mLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mLocationText.addModifyListener(this); - - mBrowseButton = new Button(container, SWT.NONE); - mBrowseButton.setText("Browse..."); - mBrowseButton.addSelectionListener(this); - - Composite group = mWorkingSetGroup.createControl(container); - group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1)); - - setControl(container); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - - if (visible) { - try { - mIgnore = true; - if (mValues.projectName != null) { - mProjectNameText.setText(mValues.projectName); - mProjectNameText.setFocus(); - } - if (mValues.mode == Mode.ANY || mValues.mode == Mode.TEST) { - if (mValues.useExisting) { - assert false; // This is now handled by the separate import wizard - } else if (mCreateNewButton != null) { - mCreateNewButton.setSelection(true); - } - } else if (mValues.mode == Mode.SAMPLE) { - mCreateSampleRadioButton.setSelection(true); - } - if (mValues.projectLocation != null) { - mLocationText.setText(mValues.projectLocation.getPath()); - } - mUseDefaultCheckBox.setSelection(mValues.useDefaultLocation); - updateLocationState(); - } finally { - mIgnore = false; - } - } - - validatePage(); - } - - @Override - public void modifyText(ModifyEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - - if (source == mProjectNameText) { - onProjectFieldModified(); - if (!mValues.useDefaultLocation && !mValues.projectLocationModifiedByUser) { - updateLocationPathField(null); - } - } else if (source == mLocationText) { - mValues.projectLocationModifiedByUser = true; - if (!mValues.useDefaultLocation) { - File f = new File(mLocationText.getText().trim()); - mValues.projectLocation = f; - if (f.exists() && f.isDirectory() && !f.equals(mValues.projectLocation)) { - updateLocationPathField(mValues.projectLocation.getPath()); - } - } - } - - validatePage(); - } - - private void onProjectFieldModified() { - mValues.projectName = mProjectNameText.getText().trim(); - mValues.projectNameModifiedByUser = true; - - if (!mValues.applicationNameModifiedByUser) { - mValues.applicationName = capitalize(mValues.projectName); - if (!mValues.testApplicationNameModified) { - mValues.testApplicationName = - ApplicationInfoPage.suggestTestApplicationName(mValues.applicationName); - } - } - if (!mValues.activityNameModifiedByUser) { - String name = capitalize(mValues.projectName); - mValues.activityName = stripWhitespace(name) + ACTIVITY_NAME_SUFFIX; - } - if (!mValues.testProjectModified) { - mValues.testProjectName = - ApplicationInfoPage.suggestTestProjectName(mValues.projectName); - } - if (!mValues.projectLocationModifiedByUser) { - updateLocationPathField(null); - } - } - - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - - if (source == mCreateNewButton && mCreateNewButton != null - && mCreateNewButton.getSelection()) { - mValues.useExisting = false; - if (mValues.mode == Mode.SAMPLE) { - // Only reset the mode if we're toggling from sample back to create new - // or create existing. We can only come to the sample state when we're in - // ANY mode. (In particular, we don't want to switch to ANY if you're - // in test mode. - mValues.mode = Mode.ANY; - } - updateLocationState(); - } else if (source == mCreateSampleRadioButton && mCreateSampleRadioButton.getSelection()) { - mValues.useExisting = true; - mValues.useDefaultLocation = true; - if (!mUseDefaultCheckBox.getSelection()) { - try { - mIgnore = true; - mUseDefaultCheckBox.setSelection(true); - } finally { - mIgnore = false; - } - } - mValues.mode = Mode.SAMPLE; - updateLocationState(); - } else if (source == mUseDefaultCheckBox) { - mValues.useDefaultLocation = mUseDefaultCheckBox.getSelection(); - updateLocationState(); - } else if (source == mBrowseButton) { - onOpenDirectoryBrowser(); - } - - validatePage(); - } - - /** - * Enables or disable the location widgets depending on the user selection: - * the location path is enabled when using the "existing source" mode (i.e. not new project) - * or in new project mode with the "use default location" turned off. - */ - private void updateLocationState() { - boolean isNewProject = !mValues.useExisting; - boolean isCreateFromSample = mValues.mode == Mode.SAMPLE; - boolean useDefault = mValues.useDefaultLocation && !isCreateFromSample; - boolean locationEnabled = (!isNewProject || !useDefault) && !isCreateFromSample; - - mUseDefaultCheckBox.setEnabled(isNewProject); - mLocationLabel.setEnabled(locationEnabled); - mLocationText.setEnabled(locationEnabled); - mBrowseButton.setEnabled(locationEnabled); - - updateLocationPathField(null); - } - - /** - * Display a directory browser and update the location path field with the selected path - */ - private void onOpenDirectoryBrowser() { - - String existingDir = mLocationText.getText().trim(); - - // Disable the path if it doesn't exist - if (existingDir.length() == 0) { - existingDir = null; - } else { - File f = new File(existingDir); - if (!f.exists()) { - existingDir = null; - } - } - - DirectoryDialog directoryDialog = new DirectoryDialog(mLocationText.getShell()); - directoryDialog.setMessage("Browse for folder"); - directoryDialog.setFilterPath(existingDir); - String dir = directoryDialog.open(); - - if (dir != null) { - updateLocationPathField(dir); - validatePage(); - } - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - /** - * Returns the working sets to which the new project should be added. - * - * @return the selected working sets to which the new project should be added - */ - private IWorkingSet[] getWorkingSets() { - return mWorkingSetGroup.getSelectedWorkingSets(); - } - - /** - * Sets the working sets to which the new project should be added. - * - * @param workingSets the initial selected working sets - */ - private void setWorkingSets(IWorkingSet[] workingSets) { - assert workingSets != null; - mWorkingSetGroup.setWorkingSets(workingSets); - } - - /** - * Updates the location directory path field. - * <br/> - * When custom user selection is enabled, use the absDir argument if not null and also - * save it internally. If absDir is null, restore the last saved absDir. This allows the - * user selection to be remembered when the user switches from default to custom. - * <br/> - * When custom user selection is disabled, use the workspace default location with the - * current project name. This does not change the internally cached absDir. - * - * @param absDir A new absolute directory path or null to use the default. - */ - private void updateLocationPathField(String absDir) { - boolean isNewProject = !mValues.useExisting || mValues.mode == Mode.SAMPLE; - boolean useDefault = mValues.useDefaultLocation; - boolean customLocation = !isNewProject || !useDefault; - - if (!mIgnore) { - try { - mIgnore = true; - if (customLocation) { - if (absDir != null) { - // We get here if the user selected a directory with the "Browse" button. - // Disable auto-compute of the custom location unless the user selected - // the exact same path. - sAutoComputeCustomLocation = sAutoComputeCustomLocation && - absDir.equals(sCustomLocationOsPath); - sCustomLocationOsPath = TextProcessor.process(absDir); - } else if (sAutoComputeCustomLocation || - (!isNewProject && !new File(sCustomLocationOsPath).isDirectory())) { - // As a default import location, just suggest the home directory; the user - // needs to point to a project to import. - // TODO: Open file chooser automatically? - sCustomLocationOsPath = System.getProperty("user.home"); //$NON-NLS-1$ - } - if (!mLocationText.getText().equals(sCustomLocationOsPath)) { - mLocationText.setText(sCustomLocationOsPath); - mValues.projectLocation = new File(sCustomLocationOsPath); - } - } else { - String value = Platform.getLocation().append(mValues.projectName).toString(); - value = TextProcessor.process(value); - if (!mLocationText.getText().equals(value)) { - mLocationText.setText(value); - mValues.projectLocation = new File(value); - } - } - } finally { - mIgnore = false; - } - } - - if (mValues.useExisting && mValues.projectLocation != null - && mValues.projectLocation.exists() && mValues.mode != Mode.SAMPLE) { - mValues.extractFromAndroidManifest(new Path(mValues.projectLocation.getPath())); - if (!mValues.projectNameModifiedByUser && mValues.projectName != null) { - try { - mIgnore = true; - mProjectNameText.setText(mValues.projectName); - } finally { - mIgnore = false; - } - } - } - } - - private void validatePage() { - IStatus status = null; - - // Validate project name -- unless we're creating a sample, in which case - // the user will get a chance to pick the name on the Sample page - if (mValues.mode != Mode.SAMPLE) { - status = validateProjectName(mValues.projectName); - } - - if (status == null || status.getSeverity() != IStatus.ERROR) { - IStatus validLocation = validateLocation(); - if (validLocation != null) { - status = validLocation; - } - } - - if (!mCheckedSdkUptodate) { - // Ensure that we have a recent enough version of the Tools that the right templates - // are available - File file = new File(AdtPlugin.getOsSdkFolder(), OS_SDK_TOOLS_LIB_FOLDER - + File.separator + FN_PROJECT_PROGUARD_FILE); - if (!file.exists()) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("You do not have the latest version of the " - + "SDK Tools installed: Please update. (Missing %1$s)", file.getPath())); - } else { - mCheckedSdkUptodate = true; - } - } - - // -- update UI & enable finish if there's no error - setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); - if (status != null) { - setMessage(status.getMessage(), - status.getSeverity() == IStatus.ERROR - ? IMessageProvider.ERROR : IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - private IStatus validateLocation() { - if (mValues.mode == Mode.SAMPLE) { - // Samples are always created in the default directory - return null; - } - - // Validate location - Path path = new Path(mValues.projectLocation.getPath()); - if (!mValues.useExisting) { - if (!mValues.useDefaultLocation) { - // If not using the default value validate the location. - URI uri = URIUtil.toURI(path.toOSString()); - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IProject handle = workspace.getRoot().getProject(mValues.projectName); - IStatus locationStatus = workspace.validateProjectLocationURI(handle, uri); - if (!locationStatus.isOK()) { - return locationStatus; - } - // The location is valid as far as Eclipse is concerned (i.e. mostly not - // an existing workspace project.) Check it either doesn't exist or is - // a directory that is empty. - File f = path.toFile(); - if (f.exists() && !f.isDirectory()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "A directory name must be specified."); - } else if (f.isDirectory()) { - // However if the directory exists, we should put a - // warning if it is not empty. We don't put an error - // (we'll ask the user again for confirmation before - // using the directory.) - String[] l = f.list(); - if (l != null && l.length != 0) { - return new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, - "The selected output directory is not empty."); - } - } - } else { - // Otherwise validate the path string is not empty - if (mValues.projectLocation.getPath().length() == 0) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "A directory name must be specified."); - } - File dest = path.toFile(); - if (dest.exists()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format( - "There is already a file or directory named \"%1$s\" in the selected location.", - mValues.projectName)); - } - } - } else { - // Must be an existing directory - File f = path.toFile(); - if (!f.isDirectory()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "An existing directory name must be specified."); - } - - // Check there's an android manifest in the directory - String osPath = path.append(SdkConstants.FN_ANDROID_MANIFEST_XML).toOSString(); - File manifestFile = new File(osPath); - if (!manifestFile.isFile()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format( - "Choose a valid Android code directory\n" + - "(%1$s not found in %2$s.)", - SdkConstants.FN_ANDROID_MANIFEST_XML, f.getName())); - } - - // Parse it and check the important fields. - ManifestData manifestData = AndroidManifestHelper.parseForData(osPath); - if (manifestData == null) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("File %1$s could not be parsed.", osPath)); - } - String packageName = manifestData.getPackage(); - if (packageName == null || packageName.length() == 0) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("No package name defined in %1$s.", osPath)); - } - Activity[] activities = manifestData.getActivities(); - if (activities == null || activities.length == 0) { - // This is acceptable now as long as no activity needs to be - // created - if (mValues.createActivity) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("No activity name defined in %1$s.", osPath)); - } - } - - // If there's already a .project, tell the user to use import instead. - if (path.append(".project").toFile().exists()) { //$NON-NLS-1$ - return new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, - "An Eclipse project already exists in this directory.\n" + - "Consider using File > Import > Existing Project instead."); - } - } - - return null; - } - - public static IStatus validateProjectName(String projectName) { - if (projectName == null || projectName.length() == 0) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Project name must be specified"); - } else { - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IStatus nameStatus = workspace.validateName(projectName, IResource.PROJECT); - if (!nameStatus.isOK()) { - return nameStatus; - } else { - // Note: the case-sensitiveness of the project name matters and can cause a - // conflict *later* when creating the project resource, so let's check it now. - for (IProject existingProj : workspace.getRoot().getProjects()) { - if (projectName.equalsIgnoreCase(existingProj.getName())) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "A project with that name already exists in the workspace"); - } - } - } - } - - return null; - } - - @Override - public IWizardPage getNextPage() { - // Sync working set data to the value object, since the WorkingSetGroup - // doesn't let us add listeners to do this lazily - mValues.workingSets = getWorkingSets(); - - return super.getNextPage(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/SampleSelectionPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/SampleSelectionPage.java deleted file mode 100644 index 197247083..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/SampleSelectionPage.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2011 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.newproject; - -import com.android.SdkConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; -import com.android.sdklib.IAndroidTarget; -import com.android.utils.Pair; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.IBaseLabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.Text; - -import java.io.File; - -/** Page where the user can select a sample to "instantiate" */ -class SampleSelectionPage extends WizardPage implements SelectionListener, ModifyListener { - private final NewProjectWizardState mValues; - private boolean mIgnore; - - private Table mTable; - private TableViewer mTableViewer; - private IAndroidTarget mCurrentSamplesTarget; - private Text mSampleProjectName; - - /** - * Create the wizard. - */ - SampleSelectionPage(NewProjectWizardState values) { - super("samplePage"); //$NON-NLS-1$ - setTitle("Select Sample"); - setDescription("Select which sample to create"); - mValues = values; - } - - /** - * Create contents of the wizard. - */ - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - container.setLayout(new GridLayout(2, false)); - - mTableViewer = new TableViewer(container, SWT.BORDER | SWT.FULL_SELECTION); - mTable = mTableViewer.getTable(); - GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1); - gridData.heightHint = 300; - mTable.setLayoutData(gridData); - mTable.addSelectionListener(this); - - setControl(container); - - Label projectLabel = new Label(container, SWT.NONE); - projectLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - projectLabel.setText("Project Name:"); - - mSampleProjectName = new Text(container, SWT.BORDER); - mSampleProjectName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - mSampleProjectName.addModifyListener(this); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - - if (visible) { - if (mValues.projectName != null) { - try { - mIgnore = true; - mSampleProjectName.setText(mValues.projectName); - } finally { - mIgnore = false; - } - } - - // Update samples list if the SDK target has changed (or if it hasn't yet - // been populated) - if (mCurrentSamplesTarget != mValues.target) { - mCurrentSamplesTarget = mValues.target; - updateSamples(); - } - - validatePage(); - } - } - - private void updateSamples() { - IBaseLabelProvider labelProvider = new ColumnLabelProvider() { - @Override - public Image getImage(Object element) { - return AdtPlugin.getAndroidLogo(); - } - - @Override - public String getText(Object element) { - if (element instanceof Pair<?, ?>) { - Object name = ((Pair<?, ?>) element).getFirst(); - return name.toString(); - } - return element.toString(); // Fallback. Should not happen. - } - }; - - mTableViewer.setContentProvider(new ArrayContentProvider()); - mTableViewer.setLabelProvider(labelProvider); - - if (mValues.samples != null && mValues.samples.size() > 0) { - Object[] samples = mValues.samples.toArray(); - mTableViewer.setInput(samples); - - mTable.select(0); - selectSample(mValues.samples.get(0).getSecond()); - extractNamesFromAndroidManifest(); - } - } - - private void selectSample(File sample) { - mValues.chosenSample = sample; - if (sample != null && !mValues.projectNameModifiedByUser) { - mValues.projectName = sample.getName(); - if (SdkConstants.FD_SAMPLE.equals(mValues.projectName) && - sample.getParentFile() != null) { - mValues.projectName = sample.getParentFile().getName() + '_' + mValues.projectName; - } - try { - mIgnore = true; - mSampleProjectName.setText(mValues.projectName); - } finally { - mIgnore = false; - } - updatedProjectName(); - } - } - - @SuppressWarnings("unchecked") - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - if (e.getSource() == mTable) { - extractNamesFromAndroidManifest(); - int index = mTable.getSelectionIndex(); - if (index >= 0) { - Object[] roots = (Object[]) mTableViewer.getInput(); - selectSample(((Pair<String, File>) roots[index]).getSecond()); - } else { - selectSample(null); - } - } else { - assert false : e.getSource(); - } - - validatePage(); - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - @Override - public void modifyText(ModifyEvent e) { - if (mIgnore) { - return; - } - - if (e.getSource() == mSampleProjectName) { - mValues.projectName = mSampleProjectName.getText().trim(); - mValues.projectNameModifiedByUser = true; - updatedProjectName(); - } - - validatePage(); - } - - private void updatedProjectName() { - if (mValues.useDefaultLocation) { - mValues.projectLocation = Platform.getLocation().toFile(); - } - } - - /** - * A sample was selected. Update the location field, manifest and validate. - * Extract names from an android manifest. - * This is done only if the user selected the "use existing source" and a manifest xml file - * can actually be found in the custom user directory. - */ - private void extractNamesFromAndroidManifest() { - if (mValues.chosenSample == null || !mValues.chosenSample.isDirectory()) { - return; - } - - Path path = new Path(mValues.chosenSample.getPath()); - mValues.extractFromAndroidManifest(path); - } - - @Override - public boolean isPageComplete() { - if (mValues.mode != Mode.SAMPLE) { - return true; - } - - // Ensure that when creating samples, the Finish button isn't enabled until - // the user has reached and completed this page - if (mValues.chosenSample == null) { - return false; - } - - return super.isPageComplete(); - } - - private void validatePage() { - IStatus status = null; - if (mValues.samples == null || mValues.samples.size() == 0) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "The chosen SDK does not contain any samples"); - } else if (mValues.chosenSample == null) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Choose a sample"); - } else if (!mValues.chosenSample.exists()) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("Sample does not exist: %1$s", mValues.chosenSample.getPath())); - } else { - status = ProjectNamePage.validateProjectName(mValues.projectName); - } - - // -- update UI & enable finish if there's no error - setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); - if (status != null) { - setMessage(status.getMessage(), - status.getSeverity() == IStatus.ERROR - ? IMessageProvider.ERROR : IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/SdkSelectionPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/SdkSelectionPage.java deleted file mode 100644 index 6cafcf057..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/SdkSelectionPage.java +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Copyright (C) 2011 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.newproject; - -import com.android.SdkConstants; -import com.android.annotations.Nullable; -import com.android.ide.common.sdk.LoadStatus; -import com.android.ide.common.xml.AndroidManifestParser; -import com.android.ide.common.xml.ManifestData; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener; -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; -import com.android.io.FileWrapper; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkManager; -import com.android.sdkuilib.internal.widgets.SdkTargetSelector; -import com.android.utils.NullLogger; -import com.android.utils.Pair; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Group; - -import java.io.File; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Pattern; - -/** A page in the New Project wizard where you select the target SDK */ -class SdkSelectionPage extends WizardPage implements ITargetChangeListener { - private final NewProjectWizardState mValues; - private boolean mIgnore; - private SdkTargetSelector mSdkTargetSelector; - - /** - * Create the wizard. - */ - SdkSelectionPage(NewProjectWizardState values) { - super("sdkSelection"); //$NON-NLS-1$ - mValues = values; - - setTitle("Select Build Target"); - AdtPlugin.getDefault().addTargetListener(this); - } - - @Override - public void dispose() { - AdtPlugin.getDefault().removeTargetListener(this); - super.dispose(); - } - - /** - * Create contents of the wizard. - */ - @Override - public void createControl(Composite parent) { - Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); - // Layout has 1 column - group.setLayout(new GridLayout()); - group.setLayoutData(new GridData(GridData.FILL_BOTH)); - group.setFont(parent.getFont()); - group.setText("Build Target"); - - // The selector is created without targets. They are added below in the change listener. - mSdkTargetSelector = new SdkTargetSelector(group, null); - - mSdkTargetSelector.setSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - mValues.target = mSdkTargetSelector.getSelected(); - mValues.targetModifiedByUser = true; - onSdkTargetModified(); - validatePage(); - } - }); - - onSdkLoaded(); - - setControl(group); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - if (mValues.mode == Mode.SAMPLE) { - setDescription("Choose an SDK to select a sample from"); - } else { - setDescription("Choose an SDK to target"); - } - try { - mIgnore = true; - if (mValues.target != null) { - mSdkTargetSelector.setSelection(mValues.target); - } - } finally { - mIgnore = false; - } - - validatePage(); - } - - @Override - public boolean isPageComplete() { - // Ensure that the Finish button isn't enabled until - // the user has reached and completed this page - if (mValues.target == null) { - return false; - } - - return super.isPageComplete(); - } - - /** - * Called when an SDK target is modified. - * - * Also changes the minSdkVersion field to reflect the sdk api level that has - * just been selected. - */ - private void onSdkTargetModified() { - if (mIgnore) { - return; - } - - IAndroidTarget target = mValues.target; - - // Update the minimum SDK text field? - // We do if one of two conditions are met: - if (target != null) { - boolean setMinSdk = false; - AndroidVersion version = target.getVersion(); - int apiLevel = version.getApiLevel(); - // 1. Has the user not manually edited the SDK field yet? If so, keep - // updating it to the selected value. - if (!mValues.minSdkModifiedByUser) { - setMinSdk = true; - } else { - // 2. Is the API level set to a higher level than the newly selected - // target SDK? If so, change it down to the new lower value. - String s = mValues.minSdk; - if (s.length() > 0) { - try { - int currentApi = Integer.parseInt(s); - if (currentApi > apiLevel) { - setMinSdk = true; - } - } catch (NumberFormatException nfe) { - // User may have typed something invalid -- ignore - } - } - } - if (setMinSdk) { - String minSdk; - if (version.isPreview()) { - minSdk = version.getCodename(); - } else { - minSdk = Integer.toString(apiLevel); - } - mValues.minSdk = minSdk; - } - } - - loadSamplesForTarget(target); - } - - /** - * Updates the list of all samples for the given target SDK. - * The list is stored in mSamplesPaths as absolute directory paths. - * The combo is recreated to match this. - */ - private void loadSamplesForTarget(IAndroidTarget target) { - // Keep the name of the old selection (if there were any samples) - File previouslyChosenSample = mValues.chosenSample; - - mValues.samples.clear(); - mValues.chosenSample = null; - - if (target != null) { - // Get the sample root path and recompute the list of samples - String samplesRootPath = target.getPath(IAndroidTarget.SAMPLES); - - File root = new File(samplesRootPath); - findSamplesManifests(root, root, null, null, mValues.samples); - - Sdk sdk = Sdk.getCurrent(); - if (sdk != null) { - // Parse the extras to see if we can find samples that are - // compatible with the selected target API. - // First we need an SdkManager that suppresses all output. - SdkManager sdkman = sdk.getNewSdkManager(NullLogger.getLogger()); - - Map<File, String> extras = sdkman.getExtraSamples(); - for (Entry<File, String> entry : extras.entrySet()) { - File path = entry.getKey(); - String name = entry.getValue(); - - // Case where the sample is at the root of the directory and not - // in a per-sample sub-directory. - if (path.getName().equals(SdkConstants.FD_SAMPLE)) { - findSampleManifestInDir( - path, path, name, target.getVersion(), mValues.samples); - } - - // Scan sub-directories - findSamplesManifests( - path, path, name, target.getVersion(), mValues.samples); - } - } - - if (mValues.samples.isEmpty()) { - return; - } else { - Collections.sort(mValues.samples, new Comparator<Pair<String, File>>() { - @Override - public int compare(Pair<String, File> o1, Pair<String, File> o2) { - // Compare the display name of the sample - return o1.getFirst().compareTo(o2.getFirst()); - } - }); - } - - // Try to find the old selection. - if (previouslyChosenSample != null) { - String previouslyChosenName = previouslyChosenSample.getName(); - for (int i = 0, n = mValues.samples.size(); i < n; i++) { - File file = mValues.samples.get(i).getSecond(); - if (file.getName().equals(previouslyChosenName)) { - mValues.chosenSample = file; - break; - } - } - } - } - } - - /** - * Recursively find potential sample directories under the given directory. - * Actually lists any directory that contains an android manifest. - * Paths found are added the samplesPaths list. - * - * @param rootDir The "samples" root directory. Doesn't change during recursion. - * @param currDir The directory being scanned. Caller must initially set it to {@code rootDir}. - * @param extraName Optional name appended to the samples display name. Typically used to - * indicate a sample comes from a given extra package. - * @param targetVersion Optional target version filter. If non null, only samples that are - * compatible with the given target will be listed. - * @param samplesPaths A non-null list filled by this method with all samples found. The - * pair is (String: sample display name => File: sample directory). - */ - private void findSamplesManifests( - File rootDir, - File currDir, - @Nullable String extraName, - @Nullable AndroidVersion targetVersion, - List<Pair<String, File>> samplesPaths) { - if (!currDir.isDirectory()) { - return; - } - - for (File f : currDir.listFiles()) { - if (f.isDirectory()) { - findSampleManifestInDir(f, rootDir, extraName, targetVersion, samplesPaths); - - // Recurse in the project, to find embedded tests sub-projects - // We can however skip this recursion for known android sub-dirs that - // can't have projects, namely for sources, assets and resources. - String leaf = f.getName(); - if (!SdkConstants.FD_SOURCES.equals(leaf) && - !SdkConstants.FD_ASSETS.equals(leaf) && - !SdkConstants.FD_RES.equals(leaf)) { - findSamplesManifests(rootDir, f, extraName, targetVersion, samplesPaths); - } - } - } - } - - private void findSampleManifestInDir( - File sampleDir, - File rootDir, - String extraName, - AndroidVersion targetVersion, - List<Pair<String, File>> samplesPaths) { - // Assume this is a sample if it contains an android manifest. - File manifestFile = new File(sampleDir, SdkConstants.FN_ANDROID_MANIFEST_XML); - if (manifestFile.isFile()) { - try { - ManifestData data = - AndroidManifestParser.parse(new FileWrapper(manifestFile)); - if (data != null) { - boolean accept = false; - if (targetVersion == null) { - accept = true; - } else if (targetVersion != null) { - int i = data.getMinSdkVersion(); - if (i != ManifestData.MIN_SDK_CODENAME) { - accept = i <= targetVersion.getApiLevel(); - } else { - String s = data.getMinSdkVersionString(); - if (s != null) { - accept = s.equals(targetVersion.getCodename()); - } - } - } - - if (accept) { - String name = getSampleDisplayName(extraName, rootDir, sampleDir); - samplesPaths.add(Pair.of(name, sampleDir)); - } - } - } catch (Exception e) { - // Ignore. Don't use a sample which manifest doesn't parse correctly. - AdtPlugin.log(IStatus.INFO, - "NPW ignoring malformed manifest %s", //$NON-NLS-1$ - manifestFile.getAbsolutePath()); - } - } - } - - /** - * Compute the sample name compared to its root directory. - */ - private String getSampleDisplayName(String extraName, File rootDir, File sampleDir) { - String name = null; - if (!rootDir.equals(sampleDir)) { - String path = sampleDir.getPath(); - int n = rootDir.getPath().length(); - if (path.length() > n) { - path = path.substring(n); - if (path.charAt(0) == File.separatorChar) { - path = path.substring(1); - } - if (path.endsWith(File.separator)) { - path = path.substring(0, path.length() - 1); - } - name = path.replaceAll(Pattern.quote(File.separator), " > "); //$NON-NLS-1$ - } - } - if (name == null && - rootDir.equals(sampleDir) && - sampleDir.getName().equals(SdkConstants.FD_SAMPLE) && - extraName != null) { - // This is an old-style extra with one single sample directory. Just use the - // extra's name as the same name. - return extraName; - } - if (name == null) { - // Otherwise try to use the sample's directory name as the sample name. - while (sampleDir != null && - (name == null || - SdkConstants.FD_SAMPLE.equals(name) || - SdkConstants.FD_SAMPLES.equals(name))) { - name = sampleDir.getName(); - sampleDir = sampleDir.getParentFile(); - } - } - if (name == null) { - if (extraName != null) { - // In the unlikely case nothing worked and we have an extra name, use that. - return extraName; - } else { - name = "Sample"; // fallback name... should not happen. //$NON-NLS-1$ - } - } - if (extraName != null) { - name = name + " [" + extraName + ']'; //$NON-NLS-1$ - } - - return name; - } - - private void validatePage() { - String error = null; - - if (AdtPlugin.getDefault().getSdkLoadStatus() == LoadStatus.LOADING) { - error = "The SDK is still loading; please wait."; - } - - if (error == null && mValues.target == null) { - error = "An SDK Target must be specified."; - } - - if (error == null && mValues.mode == Mode.SAMPLE) { - // Make sure this SDK target contains samples - if (mValues.samples == null || mValues.samples.size() == 0) { - error = "This target has no samples. Please select another target."; - } - } - - // -- update UI & enable finish if there's no error - setPageComplete(error == null); - if (error != null) { - setMessage(error, IMessageProvider.ERROR); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - // ---- Implements ITargetChangeListener ---- - @Override - public void onSdkLoaded() { - if (mSdkTargetSelector == null) { - return; - } - - // Update the sdk target selector with the new targets - - // get the targets from the sdk - IAndroidTarget[] targets = null; - if (Sdk.getCurrent() != null) { - targets = Sdk.getCurrent().getTargets(); - } - mSdkTargetSelector.setTargets(targets); - - // If there's only one target, select it. - // This will invoke the selection listener on the selector defined above. - if (targets != null && targets.length == 1) { - mValues.target = targets[0]; - mSdkTargetSelector.setSelection(mValues.target); - onSdkTargetModified(); - } else if (targets != null) { - // Pick the highest available platform by default (see issue #17505 - // for related discussion.) - IAndroidTarget initialTarget = null; - for (IAndroidTarget target : targets) { - if (target.isPlatform() - && !target.getVersion().isPreview() - && (initialTarget == null || - target.getVersion().getApiLevel() > - initialTarget.getVersion().getApiLevel())) { - initialTarget = target; - } - } - if (initialTarget != null) { - mValues.target = initialTarget; - try { - mIgnore = true; - mSdkTargetSelector.setSelection(mValues.target); - } finally { - mIgnore = false; - } - onSdkTargetModified(); - } - } - - validatePage(); - } - - @Override - public void onProjectTargetChange(IProject changedProject) { - // Ignore - } - - @Override - public void onTargetLoaded(IAndroidTarget target) { - // Ignore - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/TestTargetPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/TestTargetPage.java deleted file mode 100644 index f1c188ae9..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/TestTargetPage.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 2011 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.newproject; - -import com.android.ide.common.xml.ManifestData; -import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.ui.JavaElementLabelProvider; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.dialogs.FilteredList; - -/** - * Page shown when creating a test project which lets you choose between testing - * yourself and testing a different project - */ -class TestTargetPage extends WizardPage implements SelectionListener { - private final NewProjectWizardState mValues; - /** Flag used when setting button/text state manually to ignore listener updates */ - private boolean mIgnore; - private String mLastExistingPackageName; - - private Button mCurrentRadioButton; - private Button mExistingRadioButton; - private FilteredList mProjectList; - private boolean mPageShown; - - /** - * Create the wizard. - */ - TestTargetPage(NewProjectWizardState values) { - super("testTargetPage"); //$NON-NLS-1$ - setTitle("Select Test Target"); - setDescription("Choose a project to test"); - mValues = values; - } - - /** - * Create contents of the wizard. - */ - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - - setControl(container); - container.setLayout(new GridLayout(2, false)); - - mCurrentRadioButton = new Button(container, SWT.RADIO); - mCurrentRadioButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); - mCurrentRadioButton.setText("This project"); - mCurrentRadioButton.addSelectionListener(this); - - mExistingRadioButton = new Button(container, SWT.RADIO); - mExistingRadioButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); - mExistingRadioButton.setText("An existing Android project:"); - mExistingRadioButton.addSelectionListener(this); - - ILabelProvider labelProvider = new JavaElementLabelProvider( - JavaElementLabelProvider.SHOW_DEFAULT); - mProjectList = new FilteredList(container, - SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.SINGLE, labelProvider, - true /*ignoreCase*/, false /*allowDuplicates*/, true /* matchEmptyString*/); - mProjectList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); - mProjectList.addSelectionListener(this); - } - - private void initializeList() { - ProjectChooserHelper helper = new ProjectChooserHelper(getShell(), null /*filter*/); - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - IJavaModel javaModel = JavaCore.create(workspaceRoot); - IJavaProject[] androidProjects = helper.getAndroidProjects(javaModel); - mProjectList.setElements(androidProjects); - if (mValues.testedProject != null) { - for (IJavaProject project : androidProjects) { - if (project.getProject() == mValues.testedProject) { - mProjectList.setSelection(new Object[] { project }); - break; - } - } - } else { - // No initial selection: force the user to choose - mProjectList.setSelection(new int[0]); - } - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - mPageShown = true; - - if (visible) { - try { - mIgnore = true; - mCurrentRadioButton.setSelection(mValues.testingSelf); - mExistingRadioButton.setSelection(!mValues.testingSelf); - mProjectList.setEnabled(!mValues.testingSelf); - - if (mProjectList.isEmpty()) { - initializeList(); - } - if (!mValues.testingSelf) { - mProjectList.setFocus(); - IProject project = getSelectedProject(); - if (project != null) { - // The FilteredList seems to -insist- on selecting the first item - // in the list, even when the selection is explicitly set to an empty - // array. This means the user is looking at a selection, so we need - // to also go ahead and select this item in the model such that the - // two agree, even if we would have preferred to have no initial - // selection. - mValues.testedProject = project; - } - } - } finally { - mIgnore = false; - } - } - - validatePage(); - } - - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source == mExistingRadioButton) { - mProjectList.setEnabled(true); - mValues.testingSelf = false; - setExistingProject(getSelectedProject()); - mProjectList.setFocus(); - } else if (source == mCurrentRadioButton) { - mProjectList.setEnabled(false); - mValues.testingSelf = true; - mValues.testedProject = null; - } else { - // The event must be from the project list, which unfortunately doesn't - // pass itself as the selection event, it passes a reference to some internal - // table widget that it uses, so we check for this case last - IProject project = getSelectedProject(); - if (project != mValues.testedProject) { - setExistingProject(project); - } - } - - validatePage(); - } - - private IProject getSelectedProject() { - Object[] selection = mProjectList.getSelection(); - IProject project = selection != null && selection.length == 1 - ? ((IJavaProject) selection[0]).getProject() : null; - return project; - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - private void setExistingProject(IProject project) { - mValues.testedProject = project; - - // Try to update the application, package, sdk target and minSdkVersion accordingly - if (project != null && - (!mValues.applicationNameModifiedByUser || - !mValues.packageNameModifiedByUser || - !mValues.targetModifiedByUser || - !mValues.minSdkModifiedByUser)) { - ManifestData manifestData = AndroidManifestHelper.parseForData(project); - if (manifestData != null) { - String appName = String.format("%1$sTest", project.getName()); - String packageName = manifestData.getPackage(); - String minSdkVersion = manifestData.getMinSdkVersionString(); - IAndroidTarget sdkTarget = null; - if (Sdk.getCurrent() != null) { - sdkTarget = Sdk.getCurrent().getTarget(project); - } - - if (packageName == null) { - packageName = ""; //$NON-NLS-1$ - } - mLastExistingPackageName = packageName; - - if (!mValues.projectNameModifiedByUser) { - mValues.projectName = appName; - } - - if (!mValues.applicationNameModifiedByUser) { - mValues.applicationName = appName; - } - - if (!mValues.packageNameModifiedByUser) { - packageName += ".test"; //$NON-NLS-1$ - mValues.packageName = packageName; - } - - if (!mValues.targetModifiedByUser && sdkTarget != null) { - mValues.target = sdkTarget; - } - - if (!mValues.minSdkModifiedByUser) { - if (minSdkVersion != null || sdkTarget != null) { - mValues.minSdk = minSdkVersion; - } - if (sdkTarget == null) { - mValues.updateSdkTargetToMatchMinSdkVersion(); - } - } - } - } - - updateTestTargetPackageField(mLastExistingPackageName); - } - - /** - * Updates the test target package name - * - * When using the "self-test" option, the packageName argument is ignored and the - * current value from the project package is used. - * - * Otherwise the packageName is used if it is not null. - */ - private void updateTestTargetPackageField(String packageName) { - if (mValues.testingSelf) { - mValues.testTargetPackageName = mValues.packageName; - } else if (packageName != null) { - mValues.testTargetPackageName = packageName; - } - } - - @Override - public boolean isPageComplete() { - // Ensure that the user sees the page and makes a selection - if (!mPageShown) { - return false; - } - - return super.isPageComplete(); - } - - private void validatePage() { - String error = null; - - if (!mValues.testingSelf) { - if (mValues.testedProject == null) { - error = "Please select an existing Android project as a test target."; - } else if (mValues.projectName.equals(mValues.testedProject.getName())) { - error = "The main project name and the test project name must be different."; - } - } - - // -- update UI & enable finish if there's no error - setPageComplete(error == null); - if (error != null) { - setMessage(error, IMessageProvider.ERROR); - } else { - setErrorMessage(null); - setMessage(null); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/WorkingSetGroup.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/WorkingSetGroup.java deleted file mode 100644 index fb33a08b4..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/WorkingSetGroup.java +++ /dev/null @@ -1,109 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.android.ide.eclipse.adt.internal.wizards.newproject; - -import org.eclipse.jdt.internal.ui.JavaPlugin; -import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; -import org.eclipse.jdt.internal.ui.workingsets.IWorkingSetIDs; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Group; -import org.eclipse.ui.IWorkingSet; -import org.eclipse.ui.dialogs.WorkingSetConfigurationBlock; - -/** - * Copied from - * org.eclipse.jdt.ui.wizards.NewJavaProjectWizardPageOne$WorkingSetGroup - * - * Creates the working set group with controls that allow - * the selection of working sets - */ -@SuppressWarnings("restriction") -public class WorkingSetGroup { - - private WorkingSetConfigurationBlock fWorkingSetBlock; - private Button mEnableButton; - - public WorkingSetGroup() { - String[] workingSetIds = new String[] { - IWorkingSetIDs.JAVA, IWorkingSetIDs.RESOURCE - }; - fWorkingSetBlock = new WorkingSetConfigurationBlock(workingSetIds, JavaPlugin.getDefault() - .getDialogSettings()); - } - - public Composite createControl(Composite composite) { - Group workingSetGroup = new Group(composite, SWT.NONE); - workingSetGroup.setFont(composite.getFont()); - workingSetGroup.setText(NewWizardMessages.NewJavaProjectWizardPageOne_WorkingSets_group); - workingSetGroup.setLayout(new GridLayout(1, false)); - - fWorkingSetBlock.createContent(workingSetGroup); - - // WorkingSetGroup is implemented in such a way that the checkbox it contains - // can only be programmatically set if there's an existing working set associated - // *before* we construct the control. However the control is created when the - // wizard is opened, not when the page is first shown. - // - // One choice is to duplicate the class in our project. - // Or find the checkbox we want and trigger it manually. - mEnableButton = findCheckbox(workingSetGroup); - - return workingSetGroup; - } - - public void setWorkingSets(IWorkingSet[] workingSets) { - fWorkingSetBlock.setWorkingSets(workingSets); - } - - public IWorkingSet[] getSelectedWorkingSets() { - try { - return fWorkingSetBlock.getSelectedWorkingSets(); - } catch (Throwable t) { - // Test scenarios; no UI is created, which the fWorkingSetBlock assumes - // (it dereferences the enabledButton) - return new IWorkingSet[0]; - } - } - - public boolean isChecked() { - return mEnableButton == null ? false : mEnableButton.getSelection(); - } - - public void setChecked(boolean state) { - if (mEnableButton != null) { - mEnableButton.setSelection(state); - } - } - - /** - * Finds the first button of style Checkbox in the given parent composite. - * Returns null if not found. - */ - private Button findCheckbox(Composite parent) { - for (Control control : parent.getChildren()) { - if (control instanceof Button && (control.getStyle() & SWT.CHECK) == SWT.CHECK) { - return (Button) control; - } else if (control instanceof Composite) { - Button found = findCheckbox((Composite) control); - if (found != null) { - return found; - } - } - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/WorkingSetHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/WorkingSetHelper.java deleted file mode 100755 index 428bfd331..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/WorkingSetHelper.java +++ /dev/null @@ -1,130 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package com.android.ide.eclipse.adt.internal.wizards.newproject; - -import org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart; -import org.eclipse.jdt.internal.ui.workingsets.IWorkingSetIDs; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITreeSelection; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkingSet; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * This class contains a helper method to deal with working sets. - * <p/> - * Copied from org.eclipse.jdt.ui.wizards.NewJavaProjectWizardPageOne - */ -@SuppressWarnings("restriction") -public final class WorkingSetHelper { - - private static final IWorkingSet[] EMPTY_WORKING_SET_ARRAY = new IWorkingSet[0]; - - /** This class is never instantiated. */ - private WorkingSetHelper() { - } - - public static IWorkingSet[] getSelectedWorkingSet(IStructuredSelection selection, - IWorkbenchPart activePart) { - IWorkingSet[] selected= getSelectedWorkingSet(selection); - if (selected != null && selected.length > 0) { - for (int i= 0; i < selected.length; i++) { - if (!isValidWorkingSet(selected[i])) - return EMPTY_WORKING_SET_ARRAY; - } - return selected; - } - - if (!(activePart instanceof PackageExplorerPart)) - return EMPTY_WORKING_SET_ARRAY; - - PackageExplorerPart explorerPart= (PackageExplorerPart) activePart; - if (explorerPart.getRootMode() == PackageExplorerPart.PROJECTS_AS_ROOTS) { - //Get active filter - IWorkingSet filterWorkingSet= explorerPart.getFilterWorkingSet(); - if (filterWorkingSet == null) - return EMPTY_WORKING_SET_ARRAY; - - if (!isValidWorkingSet(filterWorkingSet)) - return EMPTY_WORKING_SET_ARRAY; - - return new IWorkingSet[] {filterWorkingSet}; - } else { - //If we have been gone into a working set return the working set - Object input= explorerPart.getViewPartInput(); - if (!(input instanceof IWorkingSet)) - return EMPTY_WORKING_SET_ARRAY; - - IWorkingSet workingSet= (IWorkingSet)input; - if (!isValidWorkingSet(workingSet)) - return EMPTY_WORKING_SET_ARRAY; - - return new IWorkingSet[] {workingSet}; - } - } - - private static IWorkingSet[] getSelectedWorkingSet(IStructuredSelection selection) { - if (!(selection instanceof ITreeSelection)) - return EMPTY_WORKING_SET_ARRAY; - - ITreeSelection treeSelection= (ITreeSelection) selection; - if (treeSelection.isEmpty()) - return EMPTY_WORKING_SET_ARRAY; - - List<?> elements = treeSelection.toList(); - if (elements.size() == 1) { - Object element= elements.get(0); - TreePath[] paths= treeSelection.getPathsFor(element); - if (paths.length != 1) - return EMPTY_WORKING_SET_ARRAY; - - TreePath path= paths[0]; - if (path.getSegmentCount() == 0) - return EMPTY_WORKING_SET_ARRAY; - - Object candidate= path.getSegment(0); - if (!(candidate instanceof IWorkingSet)) - return EMPTY_WORKING_SET_ARRAY; - - IWorkingSet workingSetCandidate= (IWorkingSet) candidate; - if (isValidWorkingSet(workingSetCandidate)) - return new IWorkingSet[] { workingSetCandidate }; - - return EMPTY_WORKING_SET_ARRAY; - } - - ArrayList<Object> result = new ArrayList<Object>(); - for (Iterator<?> iterator = elements.iterator(); iterator.hasNext();) { - Object element= iterator.next(); - if (element instanceof IWorkingSet && isValidWorkingSet((IWorkingSet) element)) { - result.add(element); - } - } - return result.toArray(new IWorkingSet[result.size()]); - } - - - private static boolean isValidWorkingSet(IWorkingSet workingSet) { - String id= workingSet.getId(); - if (!IWorkingSetIDs.JAVA.equals(id) && !IWorkingSetIDs.RESOURCE.equals(id)) - return false; - - if (workingSet.isAggregateWorkingSet()) - return false; - - return true; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/AddTranslationDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/AddTranslationDialog.java deleted file mode 100644 index 0301b80fe..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/AddTranslationDialog.java +++ /dev/null @@ -1,653 +0,0 @@ -/* - * 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.newxmlfile; - -import static com.android.SdkConstants.FD_RES; -import static com.android.SdkConstants.FD_RES_VALUES; -import static com.android.SdkConstants.RES_QUALIFIER_SEP; - -import com.android.ide.common.rendering.api.ResourceValue; -import com.android.ide.common.res2.ValueXmlHelper; -import com.android.ide.common.resources.LocaleManager; -import com.android.ide.common.resources.ResourceItem; -import com.android.ide.common.resources.configuration.FolderConfiguration; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.editors.layout.configuration.FlagManager; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewManager; -import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; -import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; -import com.android.resources.ResourceType; -import com.google.common.base.Charsets; -import com.google.common.collect.Maps; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.CellLabelProvider; -import org.eclipse.jface.viewers.ColumnViewer; -import org.eclipse.jface.viewers.EditingSupport; -import org.eclipse.jface.viewers.IBaseLabelProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.TextCellEditor; -import org.eclipse.jface.viewers.ViewerCell; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.events.TraverseEvent; -import org.eclipse.swt.events.TraverseListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PlatformUI; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedSet; - -/** - * Dialog which adds a new translation to the project - */ -public class AddTranslationDialog extends Dialog implements ControlListener, SelectionListener, - TraverseListener { - private static final int KEY_COLUMN = 0; - private static final int DEFAULT_TRANSLATION_COLUMN = 1; - private static final int NEW_TRANSLATION_COLUMN = 2; - private final FolderConfiguration mConfiguration = new FolderConfiguration(); - private final IProject mProject; - private String mTarget; - private boolean mIgnore; - private Map<String, String> mTranslations; - private Set<String> mExistingLanguages; - private String mSelectedLanguage; - private String mSelectedRegion; - - private Table mTable; - private Combo mLanguageCombo; - private Combo mRegionCombo; - private ImageControl mFlag; - private Label mFile; - private Button mOkButton; - private Composite mErrorPanel; - private Label mErrorLabel; - private MyTableViewer mTableViewer; - - /** - * Creates the dialog. - * @param parentShell the parent shell - * @param project the project to add translations into - */ - public AddTranslationDialog(Shell parentShell, IProject project) { - super(parentShell); - setShellStyle(SWT.CLOSE | SWT.RESIZE | SWT.TITLE); - mProject = project; - } - - @Override - protected Control createDialogArea(Composite parent) { - Composite container = (Composite) super.createDialogArea(parent); - GridLayout gl_container = new GridLayout(6, false); - gl_container.horizontalSpacing = 0; - container.setLayout(gl_container); - - Label languageLabel = new Label(container, SWT.NONE); - languageLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - languageLabel.setText("Language:"); - mLanguageCombo = new Combo(container, SWT.READ_ONLY); - GridData gd_mLanguageCombo = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); - gd_mLanguageCombo.widthHint = 150; - mLanguageCombo.setLayoutData(gd_mLanguageCombo); - - Label regionLabel = new Label(container, SWT.NONE); - GridData gd_regionLabel = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1); - gd_regionLabel.horizontalIndent = 10; - regionLabel.setLayoutData(gd_regionLabel); - regionLabel.setText("Region:"); - mRegionCombo = new Combo(container, SWT.READ_ONLY); - GridData gd_mRegionCombo = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); - gd_mRegionCombo.widthHint = 150; - mRegionCombo.setLayoutData(gd_mRegionCombo); - mRegionCombo.setEnabled(false); - - mFlag = new ImageControl(container, SWT.NONE, null); - mFlag.setDisposeImage(false); - GridData gd_mFlag = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); - gd_mFlag.exclude = true; - gd_mFlag.widthHint = 32; - gd_mFlag.horizontalIndent = 3; - mFlag.setLayoutData(gd_mFlag); - - mFile = new Label(container, SWT.NONE); - mFile.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - - mTableViewer = new MyTableViewer(container, SWT.BORDER | SWT.FULL_SELECTION); - mTable = mTableViewer.getTable(); - mTable.setEnabled(false); - mTable.setLinesVisible(true); - mTable.setHeaderVisible(true); - mTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 6, 2)); - mTable.addControlListener(this); - mTable.addTraverseListener(this); - // If you have difficulty opening up this form in WindowBuilder and it complains about - // the next line, change the type of the mTableViewer field and the above - // constructor call from MyTableViewer to TableViewer - TableViewerColumn keyViewerColumn = new TableViewerColumn(mTableViewer, SWT.NONE); - TableColumn keyColumn = keyViewerColumn.getColumn(); - keyColumn.setWidth(100); - keyColumn.setText("Key"); - TableViewerColumn defaultViewerColumn = new TableViewerColumn(mTableViewer, SWT.NONE); - TableColumn defaultColumn = defaultViewerColumn.getColumn(); - defaultColumn.setWidth(200); - defaultColumn.setText("Default"); - TableViewerColumn translationViewerColumn = new TableViewerColumn(mTableViewer, SWT.NONE); - TableColumn translationColumn = translationViewerColumn.getColumn(); - translationColumn.setWidth(200); - translationColumn.setText("New Translation"); - - mErrorPanel = new Composite(container, SWT.NONE); - GridData gd_mErrorLabel = new GridData(SWT.FILL, SWT.CENTER, false, false, 6, 1); - gd_mErrorLabel.exclude = true; - mErrorPanel.setLayoutData(gd_mErrorLabel); - - translationViewerColumn.setEditingSupport(new TranslationEditingSupport(mTableViewer)); - - fillLanguages(); - fillRegions(); - fillStrings(); - updateColumnWidths(); - validatePage(); - - mLanguageCombo.addSelectionListener(this); - mRegionCombo.addSelectionListener(this); - - return container; - } - - /** Populates the table with keys and default strings */ - private void fillStrings() { - ResourceManager manager = ResourceManager.getInstance(); - ProjectResources resources = manager.getProjectResources(mProject); - mExistingLanguages = resources.getLanguages(); - - Collection<ResourceItem> items = resources.getResourceItemsOfType(ResourceType.STRING); - - ResourceItem[] array = items.toArray(new ResourceItem[items.size()]); - Arrays.sort(array); - - // TODO: Read in the actual XML files providing the default keys here - // (they can be obtained via ResourceItem.getSourceFileList()) - // such that we can read all the attributes associated with each - // item, and if it defines translatable=false, or the filename is - // donottranslate.xml, we can ignore it, and in other cases just - // duplicate all the attributes (such as "formatted=true", or other - // local conventions such as "product=tablet", or "msgid="123123123", - // etc.) - - mTranslations = Maps.newHashMapWithExpectedSize(items.size()); - IBaseLabelProvider labelProvider = new CellLabelProvider() { - @Override - public void update(ViewerCell cell) { - Object element = cell.getElement(); - int index = cell.getColumnIndex(); - ResourceItem item = (ResourceItem) element; - switch (index) { - case KEY_COLUMN: { - // Key - cell.setText(item.getName()); - return; - } - case DEFAULT_TRANSLATION_COLUMN: { - // Default translation - ResourceValue value = item.getResourceValue(ResourceType.STRING, - mConfiguration, false); - - if (value != null) { - cell.setText(value.getValue()); - return; - } - break; - } - case NEW_TRANSLATION_COLUMN: { - // New translation - String translation = mTranslations.get(item.getName()); - if (translation != null) { - cell.setText(translation); - return; - } - break; - } - default: - assert false : index; - } - cell.setText(""); - } - }; - - mTableViewer.setLabelProvider(labelProvider); - mTableViewer.setContentProvider(new ArrayContentProvider()); - mTableViewer.setInput(array); - } - - /** Populate the languages dropdown */ - private void fillLanguages() { - List<String> languageCodes = LocaleManager.getLanguageCodes(); - List<String> labels = new ArrayList<String>(); - for (String code : languageCodes) { - labels.add(code + ": " + LocaleManager.getLanguageName(code)); //$NON-NLS-1$ - } - Collections.sort(labels); - labels.add(0, "(Select)"); - mLanguageCombo.setItems(labels.toArray(new String[labels.size()])); - mLanguageCombo.select(0); - } - - /** Populate the regions dropdown */ - private void fillRegions() { - // TODO: When you switch languages, offer some "default" usable options. For example, - // when you choose English, offer the countries that use English, and so on. Unfortunately - // we don't have good data about this, we'd just need to hardcode a few common cases. - List<String> regionCodes = LocaleManager.getRegionCodes(); - List<String> labels = new ArrayList<String>(); - for (String code : regionCodes) { - labels.add(code + ": " + LocaleManager.getRegionName(code)); //$NON-NLS-1$ - } - Collections.sort(labels); - labels.add(0, "Any"); - mRegionCombo.setItems(labels.toArray(new String[labels.size()])); - mRegionCombo.select(0); - } - - /** React to resizing by distributing the space evenly between the last two columns */ - private void updateColumnWidths() { - Rectangle r = mTable.getClientArea(); - int availableWidth = r.width; - // Distribute all available space to the last two columns - int columnCount = mTable.getColumnCount(); - for (int i = 0; i < columnCount; i++) { - TableColumn column = mTable.getColumn(i); - availableWidth -= column.getWidth(); - } - if (availableWidth != 0) { - TableColumn column = mTable.getColumn(DEFAULT_TRANSLATION_COLUMN); - column.setWidth(column.getWidth() + availableWidth / 2); - column = mTable.getColumn(NEW_TRANSLATION_COLUMN); - column.setWidth(column.getWidth() + availableWidth / 2 + availableWidth % 2); - } - } - - @Override - protected void createButtonsForButtonBar(Composite parent) { - mOkButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, - // Don't make the OK button default as in most dialogs, since when you press - // Return thinking you might edit a value it dismisses the dialog instead - false); - createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); - mOkButton.setEnabled(false); - - validatePage(); - } - - /** - * Return the initial size of the dialog. - */ - @Override - protected Point getInitialSize() { - return new Point(800, 600); - } - - private void updateTarget() { - if (mSelectedLanguage == null) { - mTarget = null; - mFile.setText(""); - } else { - String folder = FD_RES + '/' + FD_RES_VALUES + RES_QUALIFIER_SEP + mSelectedLanguage; - if (mSelectedRegion != null) { - folder = folder + RES_QUALIFIER_SEP + 'r' + mSelectedRegion; - } - mTarget = folder + "/strings.xml"; //$NON-NLS-1$ - mFile.setText(String.format("Creating %1$s", mTarget)); - } - } - - private void updateFlag() { - if (mSelectedLanguage == null) { - // Nothing selected - ((GridData) mFlag.getLayoutData()).exclude = true; - } else { - FlagManager manager = FlagManager.get(); - Image flag = manager.getFlag(mSelectedLanguage, mSelectedRegion); - if (flag != null) { - ((GridData) mFlag.getLayoutData()).exclude = false; - mFlag.setImage(flag); - } - } - - mFlag.getParent().layout(true); - mFlag.getParent().redraw(); - } - - /** Actually create the new translation file and write it to disk */ - private void createTranslation() { - List<String> keys = new ArrayList<String>(mTranslations.keySet()); - Collections.sort(keys); - - StringBuilder sb = new StringBuilder(keys.size() * 120); - sb.append("<resources>\n\n"); //$NON-NLS-1$ - for (String key : keys) { - String value = mTranslations.get(key); - if (value == null || value.trim().isEmpty()) { - continue; - } - sb.append(" <string name=\""); //$NON-NLS-1$ - sb.append(key); - sb.append("\">"); //$NON-NLS-1$ - sb.append(ValueXmlHelper.escapeResourceString(value)); - sb.append("</string>\n"); //$NON-NLS-1$ - } - sb.append("\n</resources>"); //$NON-NLS-1$ - - IFile file = mProject.getFile(mTarget); - - try { - IContainer parent = file.getParent(); - AdtUtils.ensureExists(parent); - InputStream source = new ByteArrayInputStream(sb.toString().getBytes(Charsets.UTF_8)); - file.create(source, true, new NullProgressMonitor()); - AdtPlugin.openFile(file, null, true /*showEditorTab*/); - - // Ensure that the project resources updates itself to notice the new language. - // In theory, this shouldn't be necessary. - ResourceManager manager = ResourceManager.getInstance(); - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - IFolder folder = root.getFolder(parent.getFullPath()); - manager.getResourceFolder(folder); - RenderPreviewManager.bumpRevision(); - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - } - - private void validatePage() { - if (mOkButton == null) { // Early initialization - return; - } - - String message = null; - - if (mSelectedLanguage == null) { - message = "Select a language"; - } else if (mExistingLanguages.contains(mSelectedLanguage)) { - if (mSelectedRegion == null) { - message = String.format("%1$s is already translated in this project", - LocaleManager.getLanguageName(mSelectedLanguage)); - } else { - ResourceManager manager = ResourceManager.getInstance(); - ProjectResources resources = manager.getProjectResources(mProject); - SortedSet<String> regions = resources.getRegions(mSelectedLanguage); - if (regions.contains(mSelectedRegion)) { - message = String.format("%1$s (%2$s) is already translated in this project", - LocaleManager.getLanguageName(mSelectedLanguage), - LocaleManager.getRegionName(mSelectedRegion)); - } - } - } else { - // Require all strings to be translated? No, some of these may not - // be translatable (e.g. translatable=false, defined in donottranslate.xml, etc.) - //int missing = mTable.getItemCount() - mTranslations.values().size(); - //if (missing > 0) { - // message = String.format("Missing %1$d translations", missing); - //} - } - - boolean valid = message == null; - mTable.setEnabled(message == null); - mOkButton.setEnabled(valid); - showError(message); - } - - private void showError(String error) { - GridData data = (GridData) mErrorPanel.getLayoutData(); - - boolean show = error != null; - if (show == data.exclude) { - if (show) { - if (mErrorLabel == null) { - mErrorPanel.setLayout(new GridLayout(2, false)); - IWorkbench workbench = PlatformUI.getWorkbench(); - ISharedImages sharedImages = workbench.getSharedImages(); - String iconName = ISharedImages.IMG_OBJS_ERROR_TSK; - Image image = sharedImages.getImage(iconName); - @SuppressWarnings("unused") - ImageControl icon = new ImageControl(mErrorPanel, SWT.NONE, image); - - mErrorLabel = new Label(mErrorPanel, SWT.NONE); - mErrorLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, - 1, 1)); - } - mErrorLabel.setText(error); - } - data.exclude = !show; - mErrorPanel.getParent().layout(true); - } - } - - @Override - protected void okPressed() { - mTableViewer.applyEditorValue(); - - super.okPressed(); - createTranslation(); - } - - // ---- Implements ControlListener ---- - - @Override - public void controlMoved(ControlEvent e) { - } - - @Override - public void controlResized(ControlEvent e) { - if (mIgnore) { - return; - } - - updateColumnWidths(); - } - - // ---- Implements SelectionListener ---- - - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source == mLanguageCombo) { - try { - mIgnore = true; - mRegionCombo.select(0); - mSelectedRegion = null; - } finally { - mIgnore = false; - } - - int languageIndex = mLanguageCombo.getSelectionIndex(); - if (languageIndex == 0) { - mSelectedLanguage = null; - mRegionCombo.setEnabled(false); - } else { - // This depends on the label format - mSelectedLanguage = mLanguageCombo.getItem(languageIndex).substring(0, 2); - mRegionCombo.setEnabled(true); - } - - updateTarget(); - updateFlag(); - } else if (source == mRegionCombo) { - int regionIndex = mRegionCombo.getSelectionIndex(); - if (regionIndex == 0) { - mSelectedRegion = null; - } else { - mSelectedRegion = mRegionCombo.getItem(regionIndex).substring(0, 2); - } - - updateTarget(); - updateFlag(); - } - - try { - mIgnore = true; - validatePage(); - } finally { - mIgnore = false; - } - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - // ---- TraverseListener ---- - - @Override - public void keyTraversed(TraverseEvent e) { - // If you press Return and we're not cell editing, start editing the current row - if (e.detail == SWT.TRAVERSE_RETURN && !mTableViewer.isCellEditorActive()) { - int index = mTable.getSelectionIndex(); - if (index != -1) { - Object next = mTable.getItem(index).getData(); - mTableViewer.editElement(next, NEW_TRANSLATION_COLUMN); - } - } - } - - /** Editing support for the translation column */ - private class TranslationEditingSupport extends EditingSupport { - /** - * When true, setValue is being called as part of a default action - * (e.g. Return), not due to focus loss - */ - private boolean mDefaultAction; - - private TranslationEditingSupport(ColumnViewer viewer) { - super(viewer); - } - - @Override - protected void setValue(Object element, Object value) { - ResourceItem item = (ResourceItem) element; - mTranslations.put(item.getName(), value.toString()); - mTableViewer.update(element, null); - validatePage(); - - // If the user is pressing Return to finish editing a value (which is - // not the only way this method can get called - for example, if you click - // outside the cell while editing, the focus loss will also result in - // this method getting called), then mDefaultAction is true, and we automatically - // start editing the next row. - if (mDefaultAction) { - mTable.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - if (!mTable.isDisposed() && !mTableViewer.isCellEditorActive()) { - int index = mTable.getSelectionIndex(); - if (index != -1 && index < mTable.getItemCount() - 1) { - Object next = mTable.getItem(index + 1).getData(); - mTableViewer.editElement(next, NEW_TRANSLATION_COLUMN); - } - } - } - }); - } - } - - @Override - protected Object getValue(Object element) { - ResourceItem item = (ResourceItem) element; - String value = mTranslations.get(item.getName()); - if (value == null) { - return ""; - } - return value; - } - - @Override - protected CellEditor getCellEditor(Object element) { - return new TextCellEditor(mTable) { - @Override - protected void handleDefaultSelection(SelectionEvent event) { - try { - mDefaultAction = true; - super.handleDefaultSelection(event); - } finally { - mDefaultAction = false; - } - } - }; - } - - @Override - protected boolean canEdit(Object element) { - return true; - } - } - - private class MyTableViewer extends TableViewer { - public MyTableViewer(Composite parent, int style) { - super(parent, style); - } - - // Make this public so we can call it to ensure values are applied before the dialog - // is dismissed in {@link #okPressed} - @Override - public void applyEditorValue() { - super.applyEditorValue(); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/ChooseConfigurationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/ChooseConfigurationPage.java deleted file mode 100644 index 1d6467e64..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/ChooseConfigurationPage.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (C) 2011 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.newxmlfile; - -import com.android.SdkConstants; -import com.android.ide.common.resources.configuration.ResourceQualifier; -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector; -import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.ConfigurationState; -import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.SelectorMode; -import com.android.ide.eclipse.adt.internal.wizards.newxmlfile.NewXmlFileCreationPage.TypeInfo; -import com.android.ide.eclipse.adt.internal.wizards.newxmlfile.NewXmlFileWizard.Values; - -import org.eclipse.core.resources.IFile; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -/** - * Second page of the {@link NewXmlFileWizard}. - * <p> - * This page is used for choosing the current configuration or specific resource - * folder. - */ -public class ChooseConfigurationPage extends WizardPage { - private Values mValues; - private Text mWsFolderPathTextField; - private ConfigurationSelector mConfigSelector; - private boolean mInternalWsFolderPathUpdate; - private boolean mInternalConfigSelectorUpdate; - - /** Absolute destination folder root, e.g. "/res/" */ - static final String RES_FOLDER_ABS = AdtConstants.WS_RESOURCES + AdtConstants.WS_SEP; - /** Relative destination folder root, e.g. "res/" */ - static final String RES_FOLDER_REL = SdkConstants.FD_RESOURCES + AdtConstants.WS_SEP; - - /** - * Create the wizard. - * - * @param values value object holding current wizard state - */ - public ChooseConfigurationPage(NewXmlFileWizard.Values values) { - super("chooseConfig"); - mValues = values; - setTitle("Choose Configuration Folder"); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - if (visible) { - if (mValues.folderPath != null) { - mWsFolderPathTextField.setText(mValues.folderPath); - } - } - } - - @Override - public void createControl(Composite parent) { - // This UI is maintained with WindowBuilder. - - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayout(new GridLayout(2, false /* makeColumnsEqualWidth */)); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - - // label before configuration selector - Label label = new Label(composite, SWT.NONE); - label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); - label.setText("Optional: Choose a specific configuration to limit the XML to:"); - - // configuration selector - mConfigSelector = new ConfigurationSelector(composite, SelectorMode.DEFAULT); - GridData gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL); - gd.verticalAlignment = SWT.FILL; - gd.horizontalAlignment = SWT.FILL; - gd.horizontalSpan = 2; - gd.heightHint = ConfigurationSelector.HEIGHT_HINT; - mConfigSelector.setLayoutData(gd); - mConfigSelector.setOnChangeListener(new ConfigurationChangeListener()); - - // Folder name: [text] - String tooltip = "The folder where the file will be generated, relative to the project."; - - Label separator = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL); - GridData gdSeparator = new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1); - gdSeparator.heightHint = 10; - separator.setLayoutData(gdSeparator); - Label folderLabel = new Label(composite, SWT.NONE); - folderLabel.setText("Folder:"); - folderLabel.setToolTipText(tooltip); - - mWsFolderPathTextField = new Text(composite, SWT.BORDER); - mWsFolderPathTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mWsFolderPathTextField.setToolTipText(tooltip); - mWsFolderPathTextField.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - onWsFolderPathUpdated(); - } - }); - - setControl(composite); - - mConfigSelector.setConfiguration(mValues.configuration); - } - - /** - * Callback called when the Folder text field is changed, either programmatically - * or by the user. - */ - private void onWsFolderPathUpdated() { - if (mInternalWsFolderPathUpdate) { - return; - } - - String wsFolderPath = mWsFolderPathTextField.getText(); - - // This is a custom path, we need to sanitize it. - // First it should start with "/res/". Then we need to make sure there are no - // relative paths, things like "../" or "./" or even "//". - wsFolderPath = wsFolderPath.replaceAll("/+\\.\\./+|/+\\./+|//+|\\\\+|^/+", "/"); //$NON-NLS-1$ //$NON-NLS-2$ - wsFolderPath = wsFolderPath.replaceAll("^\\.\\./+|^\\./+", ""); //$NON-NLS-1$ //$NON-NLS-2$ - wsFolderPath = wsFolderPath.replaceAll("/+\\.\\.$|/+\\.$|/+$", ""); //$NON-NLS-1$ //$NON-NLS-2$ - - // We get "res/foo" from selections relative to the project when we want a "/res/foo" path. - if (wsFolderPath.startsWith(RES_FOLDER_REL)) { - wsFolderPath = RES_FOLDER_ABS + wsFolderPath.substring(RES_FOLDER_REL.length()); - - mInternalWsFolderPathUpdate = true; - mWsFolderPathTextField.setText(wsFolderPath); - mInternalWsFolderPathUpdate = false; - } - - mValues.folderPath = wsFolderPath; - - if (wsFolderPath.startsWith(RES_FOLDER_ABS)) { - wsFolderPath = wsFolderPath.substring(RES_FOLDER_ABS.length()); - - int pos = wsFolderPath.indexOf(AdtConstants.WS_SEP_CHAR); - if (pos >= 0) { - wsFolderPath = wsFolderPath.substring(0, pos); - } - - String[] folderSegments = wsFolderPath.split(SdkConstants.RES_QUALIFIER_SEP); - - if (folderSegments.length > 0) { - String folderName = folderSegments[0]; - - // update config selector - mInternalConfigSelectorUpdate = true; - mConfigSelector.setConfiguration(folderSegments); - mInternalConfigSelectorUpdate = false; - - IWizardPage previous = ((NewXmlFileWizard) getWizard()).getPreviousPage(this); - if (previous instanceof NewXmlFileCreationPage) { - NewXmlFileCreationPage p = (NewXmlFileCreationPage) previous; - p.selectTypeFromFolder(folderName); - } - } - } - - validatePage(); - } - - /** - * Callback called when the configuration has changed in the {@link ConfigurationSelector}. - */ - private class ConfigurationChangeListener implements Runnable { - @Override - public void run() { - if (mInternalConfigSelectorUpdate) { - return; - } - - resetFolderPath(true /*validate*/); - } - } - - /** - * Reset the current Folder path based on the UI selection - * @param validate if true, force a call to {@link #validatePage()}. - */ - private void resetFolderPath(boolean validate) { - TypeInfo type = mValues.type; - if (type != null) { - mConfigSelector.getConfiguration(mValues.configuration); - StringBuilder sb = new StringBuilder(RES_FOLDER_ABS); - sb.append(mValues.configuration.getFolderName(type.getResFolderType())); - - mInternalWsFolderPathUpdate = true; - String newPath = sb.toString(); - mValues.folderPath = newPath; - mWsFolderPathTextField.setText(newPath); - mInternalWsFolderPathUpdate = false; - - if (validate) { - validatePage(); - } - } - } - - /** - * Returns the destination folder path relative to the project or an empty string. - * - * @return the currently edited folder - */ - public String getWsFolderPath() { - return mWsFolderPathTextField == null ? "" : mWsFolderPathTextField.getText(); //$NON-NLS-1$ - } - - /** - * Validates the fields, displays errors and warnings. - * Enables the finish button if there are no errors. - */ - private void validatePage() { - String error = null; - String warning = null; - - // -- validate folder configuration - if (error == null) { - ConfigurationState state = mConfigSelector.getState(); - if (state == ConfigurationState.INVALID_CONFIG) { - ResourceQualifier qual = mConfigSelector.getInvalidQualifier(); - if (qual != null) { - error = - String.format("The qualifier '%1$s' is invalid in the folder configuration.", - qual.getName()); - } - } else if (state == ConfigurationState.REGION_WITHOUT_LANGUAGE) { - error = "The Region qualifier requires the Language qualifier."; - } - } - - // -- validate generated path - if (error == null) { - String wsFolderPath = getWsFolderPath(); - if (!wsFolderPath.startsWith(RES_FOLDER_ABS)) { - error = String.format("Target folder must start with %1$s.", RES_FOLDER_ABS); - } - } - - // -- validate destination file doesn't exist - if (error == null) { - IFile file = mValues.getDestinationFile(); - if (file != null && file.exists()) { - warning = "The destination file already exists"; - } - } - - // -- update UI & enable finish if there's no error - setPageComplete(error == null); - if (error != null) { - setMessage(error, IMessageProvider.ERROR); - } else if (warning != null) { - setMessage(warning, IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java deleted file mode 100644 index 28fb8c032..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java +++ /dev/null @@ -1,1163 +0,0 @@ -/* - * Copyright (C) 2008 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.newxmlfile; - -import static com.android.SdkConstants.DOT_XML; -import static com.android.SdkConstants.HORIZONTAL_SCROLL_VIEW; -import static com.android.SdkConstants.LINEAR_LAYOUT; -import static com.android.SdkConstants.RES_QUALIFIER_SEP; -import static com.android.SdkConstants.SCROLL_VIEW; -import static com.android.SdkConstants.VALUE_FILL_PARENT; -import static com.android.SdkConstants.VALUE_MATCH_PARENT; -import static com.android.ide.eclipse.adt.AdtConstants.WS_SEP_CHAR; -import static com.android.ide.eclipse.adt.internal.wizards.newxmlfile.ChooseConfigurationPage.RES_FOLDER_ABS; - -import com.android.SdkConstants; -import com.android.ide.common.resources.configuration.FolderConfiguration; -import com.android.ide.common.resources.configuration.ResourceQualifier; -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.editors.AndroidXmlEditor; -import com.android.ide.eclipse.adt.internal.editors.IconFactory; -import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor; -import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.ProjectCombo; -import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator; -import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.sdk.Sdk.TargetChangeListener; -import com.android.resources.ResourceFolderType; -import com.android.sdklib.IAndroidTarget; -import com.android.utils.Pair; -import com.android.utils.SdkUtils; - -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.IAdaptable; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.IBaseLabelProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.part.FileEditorInput; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; - -/** - * This is the first page of the {@link NewXmlFileWizard} which provides the ability to create - * skeleton XML resources files for Android projects. - * <p/> - * This page is used to select the project, resource type and file name. - */ -class NewXmlFileCreationPage extends WizardPage { - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - // Ensure the initial focus is in the Name field; you usually don't need - // to edit the default text field (the project name) - if (visible && mFileNameTextField != null) { - mFileNameTextField.setFocus(); - } - - validatePage(); - } - - /** - * Information on one type of resource that can be created (e.g. menu, pref, layout, etc.) - */ - static class TypeInfo { - private final String mUiName; - private final ResourceFolderType mResFolderType; - private final String mTooltip; - private final Object mRootSeed; - private ArrayList<String> mRoots = new ArrayList<String>(); - private final String mXmlns; - private final String mDefaultAttrs; - private final String mDefaultRoot; - private final int mTargetApiLevel; - - public TypeInfo(String uiName, - String tooltip, - ResourceFolderType resFolderType, - Object rootSeed, - String defaultRoot, - String xmlns, - String defaultAttrs, - int targetApiLevel) { - mUiName = uiName; - mResFolderType = resFolderType; - mTooltip = tooltip; - mRootSeed = rootSeed; - mDefaultRoot = defaultRoot; - mXmlns = xmlns; - mDefaultAttrs = defaultAttrs; - mTargetApiLevel = targetApiLevel; - } - - /** Returns the UI name for the resource type. Unique. Never null. */ - String getUiName() { - return mUiName; - } - - /** Returns the tooltip for the resource type. Can be null. */ - String getTooltip() { - return mTooltip; - } - - /** - * Returns the name of the {@link ResourceFolderType}. - * Never null but not necessarily unique, - * e.g. two types use {@link ResourceFolderType#XML}. - */ - String getResFolderName() { - return mResFolderType.getName(); - } - - /** - * Returns the matching {@link ResourceFolderType}. - * Never null but not necessarily unique, - * e.g. two types use {@link ResourceFolderType#XML}. - */ - ResourceFolderType getResFolderType() { - return mResFolderType; - } - - /** - * Returns the seed used to fill the root element values. - * The seed might be either a String, a String array, an {@link ElementDescriptor}, - * a {@link DocumentDescriptor} or null. - */ - Object getRootSeed() { - return mRootSeed; - } - - /** - * Returns the default root element that should be selected by default. Can be - * null. - * - * @param project the associated project, or null if not known - */ - String getDefaultRoot(IProject project) { - return mDefaultRoot; - } - - /** - * Returns the list of all possible root elements for the resource type. - * This can be an empty ArrayList but not null. - * <p/> - * TODO: the root list SHOULD depend on the currently selected project, to include - * custom classes. - */ - ArrayList<String> getRoots() { - return mRoots; - } - - /** - * If the generated resource XML file requires an "android" XMLNS, this should be set - * to {@link SdkConstants#NS_RESOURCES}. When it is null, no XMLNS is generated. - */ - String getXmlns() { - return mXmlns; - } - - /** - * When not null, this represent extra attributes that must be specified in the - * root element of the generated XML file. When null, no extra attributes are inserted. - * - * @param project the project to get the attributes for - * @param root the selected root element string, never null - */ - String getDefaultAttrs(IProject project, String root) { - return mDefaultAttrs; - } - - /** - * When not null, represents an extra string that should be written inside - * the element when constructed - * - * @param project the project to get the child content for - * @param root the chosen root element - * @return a string to be written inside the root element, or null if nothing - */ - String getChild(IProject project, String root) { - return null; - } - - /** - * The minimum API level required by the current SDK target to support this feature. - * - * @return the minimum API level - */ - public int getTargetApiLevel() { - return mTargetApiLevel; - } - } - - /** - * TypeInfo, information for each "type" of file that can be created. - */ - private static final TypeInfo[] sTypes = { - new TypeInfo( - "Layout", // UI name - "An XML file that describes a screen layout.", // tooltip - ResourceFolderType.LAYOUT, // folder type - AndroidTargetData.DESCRIPTOR_LAYOUT, // root seed - LINEAR_LAYOUT, // default root - SdkConstants.NS_RESOURCES, // xmlns - "", // not used, see below - 1 // target API level - ) { - - @Override - String getDefaultRoot(IProject project) { - // TODO: Use GridLayout by default for new SDKs - // (when we've ironed out all the usability issues) - //Sdk currentSdk = Sdk.getCurrent(); - //if (project != null && currentSdk != null) { - // IAndroidTarget target = currentSdk.getTarget(project); - // // fill_parent was renamed match_parent in API level 8 - // if (target != null && target.getVersion().getApiLevel() >= 13) { - // return GRID_LAYOUT; - // } - //} - - return LINEAR_LAYOUT; - }; - - // The default attributes must be determined dynamically since whether - // we use match_parent or fill_parent depends on the API level of the - // project - @Override - String getDefaultAttrs(IProject project, String root) { - Sdk currentSdk = Sdk.getCurrent(); - String fill = VALUE_FILL_PARENT; - if (currentSdk != null) { - IAndroidTarget target = currentSdk.getTarget(project); - // fill_parent was renamed match_parent in API level 8 - if (target != null && target.getVersion().getApiLevel() >= 8) { - fill = VALUE_MATCH_PARENT; - } - } - - // Only set "vertical" orientation of LinearLayouts by default; - // for GridLayouts for example we want to rely on the real default - // of the layout - String size = String.format( - "android:layout_width=\"%1$s\"\n" //$NON-NLS-1$ - + "android:layout_height=\"%2$s\"", //$NON-NLS-1$ - fill, fill); - if (LINEAR_LAYOUT.equals(root)) { - return "android:orientation=\"vertical\"\n" + size; //$NON-NLS-1$ - } else { - return size; - } - } - - @Override - String getChild(IProject project, String root) { - // Create vertical linear layouts inside new scroll views - if (SCROLL_VIEW.equals(root) || HORIZONTAL_SCROLL_VIEW.equals(root)) { - return " <LinearLayout " //$NON-NLS-1$ - + getDefaultAttrs(project, root).replace('\n', ' ') - + " android:orientation=\"vertical\"" //$NON-NLS-1$ - + "></LinearLayout>\n"; //$NON-NLS-1$ - } - return null; - } - }, - new TypeInfo("Values", // UI name - "An XML file with simple values: colors, strings, dimensions, etc.", // tooltip - ResourceFolderType.VALUES, // folder type - SdkConstants.TAG_RESOURCES, // root seed - null, // default root - null, // xmlns - null, // default attributes - 1 // target API level - ), - new TypeInfo("Drawable", // UI name - "An XML file that describes a drawable.", // tooltip - ResourceFolderType.DRAWABLE, // folder type - AndroidTargetData.DESCRIPTOR_DRAWABLE, // root seed - null, // default root - SdkConstants.NS_RESOURCES, // xmlns - null, // default attributes - 1 // target API level - ), - new TypeInfo("Menu", // UI name - "An XML file that describes an menu.", // tooltip - ResourceFolderType.MENU, // folder type - SdkConstants.TAG_MENU, // root seed - null, // default root - SdkConstants.NS_RESOURCES, // xmlns - null, // default attributes - 1 // target API level - ), - new TypeInfo("Color List", // UI name - "An XML file that describes a color state list.", // tooltip - ResourceFolderType.COLOR, // folder type - AndroidTargetData.DESCRIPTOR_COLOR, // root seed - "selector", //$NON-NLS-1$ // default root - SdkConstants.NS_RESOURCES, // xmlns - null, // default attributes - 1 // target API level - ), - new TypeInfo("Property Animation", // UI name - "An XML file that describes a property animation", // tooltip - ResourceFolderType.ANIMATOR, // folder type - AndroidTargetData.DESCRIPTOR_ANIMATOR, // root seed - "set", //$NON-NLS-1$ // default root - SdkConstants.NS_RESOURCES, // xmlns - null, // default attributes - 11 // target API level - ), - new TypeInfo("Tween Animation", // UI name - "An XML file that describes a tween animation.", // tooltip - ResourceFolderType.ANIM, // folder type - AndroidTargetData.DESCRIPTOR_ANIM, // root seed - "set", //$NON-NLS-1$ // default root - null, // xmlns - null, // default attributes - 1 // target API level - ), - new TypeInfo("AppWidget Provider", // UI name - "An XML file that describes a widget provider.", // tooltip - ResourceFolderType.XML, // folder type - AndroidTargetData.DESCRIPTOR_APPWIDGET_PROVIDER, // root seed - null, // default root - SdkConstants.NS_RESOURCES, // xmlns - null, // default attributes - 3 // target API level - ), - new TypeInfo("Preference", // UI name - "An XML file that describes preferences.", // tooltip - ResourceFolderType.XML, // folder type - AndroidTargetData.DESCRIPTOR_PREFERENCES, // root seed - SdkConstants.CLASS_NAME_PREFERENCE_SCREEN, // default root - SdkConstants.NS_RESOURCES, // xmlns - null, // default attributes - 1 // target API level - ), - new TypeInfo("Searchable", // UI name - "An XML file that describes a searchable.", // tooltip - ResourceFolderType.XML, // folder type - AndroidTargetData.DESCRIPTOR_SEARCHABLE, // root seed - null, // default root - SdkConstants.NS_RESOURCES, // xmlns - null, // default attributes - 1 // target API level - ), - // Still missing: Interpolator, Raw and Mipmap. Raw should probably never be in - // this menu since it's not often used for creating XML files. - }; - - private NewXmlFileWizard.Values mValues; - private ProjectCombo mProjectButton; - private Text mFileNameTextField; - private Combo mTypeCombo; - private IStructuredSelection mInitialSelection; - private ResourceFolderType mInitialFolderType; - private boolean mInternalTypeUpdate; - private TargetChangeListener mSdkTargetChangeListener; - private Table mRootTable; - private TableViewer mRootTableViewer; - - // --- UI creation --- - - /** - * Constructs a new {@link NewXmlFileCreationPage}. - * <p/> - * Called by {@link NewXmlFileWizard#createMainPage}. - */ - protected NewXmlFileCreationPage(String pageName, NewXmlFileWizard.Values values) { - super(pageName); - mValues = values; - setPageComplete(false); - } - - public void setInitialSelection(IStructuredSelection initialSelection) { - mInitialSelection = initialSelection; - } - - public void setInitialFolderType(ResourceFolderType initialType) { - mInitialFolderType = initialType; - } - - /** - * Called by the parent Wizard to create the UI for this Wizard Page. - * - * {@inheritDoc} - * - * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) - */ - @Override - @SuppressWarnings("unused") // SWT constructors have side effects, they aren't unused - public void createControl(Composite parent) { - // This UI is maintained with WindowBuilder. - - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayout(new GridLayout(2, false /*makeColumnsEqualWidth*/)); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - - // label before type radios - Label typeLabel = new Label(composite, SWT.NONE); - typeLabel.setText("Resource Type:"); - - mTypeCombo = new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY); - mTypeCombo.setToolTipText("What type of resource would you like to create?"); - mTypeCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - if (mInitialFolderType != null) { - mTypeCombo.setEnabled(false); - } - mTypeCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - TypeInfo type = getSelectedType(); - if (type != null) { - onSelectType(type); - } - } - }); - - // separator - Label separator = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL); - GridData gd2 = new GridData(GridData.GRAB_HORIZONTAL); - gd2.horizontalAlignment = SWT.FILL; - gd2.horizontalSpan = 2; - separator.setLayoutData(gd2); - - // Project: [button] - String tooltip = "The Android Project where the new resource file will be created."; - Label projectLabel = new Label(composite, SWT.NONE); - projectLabel.setText("Project:"); - projectLabel.setToolTipText(tooltip); - - ProjectChooserHelper helper = - new ProjectChooserHelper(getShell(), null /* filter */); - - mProjectButton = new ProjectCombo(helper, composite, mValues.project); - mProjectButton.setToolTipText(tooltip); - mProjectButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mProjectButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - IProject project = mProjectButton.getSelectedProject(); - if (project != mValues.project) { - changeProject(project); - } - }; - }); - - // Filename: [text] - Label fileLabel = new Label(composite, SWT.NONE); - fileLabel.setText("File:"); - fileLabel.setToolTipText("The name of the resource file to create."); - - mFileNameTextField = new Text(composite, SWT.BORDER); - mFileNameTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mFileNameTextField.setToolTipText(tooltip); - mFileNameTextField.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - mValues.name = mFileNameTextField.getText(); - validatePage(); - } - }); - - // separator - Label rootSeparator = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL); - GridData gd = new GridData(GridData.GRAB_HORIZONTAL); - gd.horizontalAlignment = SWT.FILL; - gd.horizontalSpan = 2; - rootSeparator.setLayoutData(gd); - - // Root Element: - // [TableViewer] - Label rootLabel = new Label(composite, SWT.NONE); - rootLabel.setText("Root Element:"); - new Label(composite, SWT.NONE); - - mRootTableViewer = new TableViewer(composite, SWT.BORDER | SWT.FULL_SELECTION); - mRootTable = mRootTableViewer.getTable(); - GridData tableGridData = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1); - tableGridData.heightHint = 200; - mRootTable.setLayoutData(tableGridData); - - setControl(composite); - - // Update state the first time - setErrorMessage(null); - setMessage(null); - - initializeFromSelection(mInitialSelection); - updateAvailableTypes(); - initializeFromFixedType(); - initializeRootValues(); - installTargetChangeListener(); - - initialSelectType(); - validatePage(); - } - - private void initialSelectType() { - TypeInfo[] types = (TypeInfo[]) mTypeCombo.getData(); - int typeIndex = getTypeComboIndex(mValues.type); - if (typeIndex == -1) { - typeIndex = 0; - } else { - assert mValues.type == types[typeIndex]; - } - mTypeCombo.select(typeIndex); - onSelectType(types[typeIndex]); - updateRootCombo(types[typeIndex]); - } - - private void installTargetChangeListener() { - mSdkTargetChangeListener = new TargetChangeListener() { - @Override - public IProject getProject() { - return mValues.project; - } - - @Override - public void reload() { - if (mValues.project != null) { - changeProject(mValues.project); - } - } - }; - - AdtPlugin.getDefault().addTargetListener(mSdkTargetChangeListener); - } - - @Override - public void dispose() { - - if (mSdkTargetChangeListener != null) { - AdtPlugin.getDefault().removeTargetListener(mSdkTargetChangeListener); - mSdkTargetChangeListener = null; - } - - super.dispose(); - } - - /** - * Returns the selected root element string, if any. - * - * @return The selected root element string or null. - */ - public String getRootElement() { - int index = mRootTable.getSelectionIndex(); - if (index >= 0) { - Object[] roots = (Object[]) mRootTableViewer.getInput(); - return roots[index].toString(); - } - return null; - } - - /** - * Called by {@link NewXmlFileWizard} to initialize the page with the selection - * received by the wizard -- typically the current user workbench selection. - * <p/> - * Things we expect to find out from the selection: - * <ul> - * <li>The project name, valid if it's an android nature.</li> - * <li>The current folder, valid if it's a folder under /res</li> - * <li>An existing filename, in which case the user will be asked whether to override it.</li> - * </ul> - * <p/> - * The selection can also be set to a {@link Pair} of {@link IProject} and a workspace - * resource path (where the resource path does not have to exist yet, such as res/anim/). - * - * @param selection The selection when the wizard was initiated. - */ - private boolean initializeFromSelection(IStructuredSelection selection) { - if (selection == null) { - return false; - } - - // Find the best match in the element list. In case there are multiple selected elements - // select the one that provides the most information and assign them a score, - // e.g. project=1 + folder=2 + file=4. - IProject targetProject = null; - String targetWsFolderPath = null; - String targetFileName = null; - int targetScore = 0; - for (Object element : selection.toList()) { - if (element instanceof IAdaptable) { - IResource res = (IResource) ((IAdaptable) element).getAdapter(IResource.class); - IProject project = res != null ? res.getProject() : null; - - // Is this an Android project? - try { - if (project == null || !project.hasNature(AdtConstants.NATURE_DEFAULT)) { - continue; - } - } catch (CoreException e) { - // checking the nature failed, ignore this resource - continue; - } - - int score = 1; // we have a valid project at least - - IPath wsFolderPath = null; - String fileName = null; - assert res != null; // Eclipse incorrectly thinks res could be null, so tell it no - if (res.getType() == IResource.FOLDER) { - wsFolderPath = res.getProjectRelativePath(); - } else if (res.getType() == IResource.FILE) { - if (SdkUtils.endsWithIgnoreCase(res.getName(), DOT_XML)) { - fileName = res.getName(); - } - wsFolderPath = res.getParent().getProjectRelativePath(); - } - - // Disregard this folder selection if it doesn't point to /res/something - if (wsFolderPath != null && - wsFolderPath.segmentCount() > 1 && - SdkConstants.FD_RESOURCES.equals(wsFolderPath.segment(0))) { - score += 2; - } else { - wsFolderPath = null; - fileName = null; - } - - score += fileName != null ? 4 : 0; - - if (score > targetScore) { - targetScore = score; - targetProject = project; - targetWsFolderPath = wsFolderPath != null ? wsFolderPath.toString() : null; - targetFileName = fileName; - } - } else if (element instanceof Pair<?,?>) { - // Pair of Project/String - @SuppressWarnings("unchecked") - Pair<IProject,String> pair = (Pair<IProject,String>)element; - targetScore = 1; - targetProject = pair.getFirst(); - targetWsFolderPath = pair.getSecond(); - targetFileName = ""; - } - } - - if (targetProject == null) { - // Try to figure out the project from the active editor - IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - if (window != null) { - IWorkbenchPage page = window.getActivePage(); - if (page != null) { - IEditorPart activeEditor = page.getActiveEditor(); - if (activeEditor instanceof AndroidXmlEditor) { - Object input = ((AndroidXmlEditor) activeEditor).getEditorInput(); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput) input; - targetScore = 1; - IFile file = fileInput.getFile(); - targetProject = file.getProject(); - IPath path = file.getParent().getProjectRelativePath(); - targetWsFolderPath = path != null ? path.toString() : null; - } - } - } - } - } - - if (targetProject == null) { - // If we didn't find a default project based on the selection, check how many - // open Android projects we can find in the current workspace. If there's only - // one, we'll just select it by default. - IJavaProject[] projects = AdtUtils.getOpenAndroidProjects(); - if (projects != null && projects.length == 1) { - targetScore = 1; - targetProject = projects[0].getProject(); - } - } - - // Now set the UI accordingly - if (targetScore > 0) { - mValues.project = targetProject; - mValues.folderPath = targetWsFolderPath; - mProjectButton.setSelectedProject(targetProject); - mFileNameTextField.setText(targetFileName != null ? targetFileName : ""); //$NON-NLS-1$ - - // If the current selection context corresponds to a specific file type, - // select it. - if (targetWsFolderPath != null) { - int pos = targetWsFolderPath.lastIndexOf(WS_SEP_CHAR); - if (pos >= 0) { - targetWsFolderPath = targetWsFolderPath.substring(pos + 1); - } - String[] folderSegments = targetWsFolderPath.split(RES_QUALIFIER_SEP); - if (folderSegments.length > 0) { - mValues.configuration = FolderConfiguration.getConfig(folderSegments); - String folderName = folderSegments[0]; - selectTypeFromFolder(folderName); - } - } - } - - return true; - } - - private void initializeFromFixedType() { - if (mInitialFolderType != null) { - for (TypeInfo type : sTypes) { - if (type.getResFolderType() == mInitialFolderType) { - mValues.type = type; - updateFolderPath(type); - break; - } - } - } - } - - /** - * Given a folder name, such as "drawable", select the corresponding type in - * the dropdown. - */ - void selectTypeFromFolder(String folderName) { - List<TypeInfo> matches = new ArrayList<TypeInfo>(); - boolean selected = false; - - TypeInfo selectedType = getSelectedType(); - for (TypeInfo type : sTypes) { - if (type.getResFolderName().equals(folderName)) { - matches.add(type); - selected |= type == selectedType; - } - } - - if (matches.size() == 1) { - // If there's only one match, select it if it's not already selected - if (!selected) { - selectType(matches.get(0)); - } - } else if (matches.size() > 1) { - // There are multiple type candidates for this folder. This can happen - // for /res/xml for example. Check to see if one of them is currently - // selected. If yes, leave the selection unchanged. If not, deselect all type. - if (!selected) { - selectType(null); - } - } else { - // Nothing valid was selected. - selectType(null); - } - } - - /** - * Initialize the root values of the type infos based on the current framework values. - */ - private void initializeRootValues() { - IProject project = mValues.project; - for (TypeInfo type : sTypes) { - // Clear all the roots for this type - ArrayList<String> roots = type.getRoots(); - if (roots.size() > 0) { - roots.clear(); - } - - // depending of the type of the seed, initialize the root in different ways - Object rootSeed = type.getRootSeed(); - - if (rootSeed instanceof String) { - // The seed is a single string, Add it as-is. - roots.add((String) rootSeed); - } else if (rootSeed instanceof String[]) { - // The seed is an array of strings. Add them as-is. - for (String value : (String[]) rootSeed) { - roots.add(value); - } - } else if (rootSeed instanceof Integer && project != null) { - // The seed is a descriptor reference defined in AndroidTargetData.DESCRIPTOR_* - // In this case add all the children element descriptors defined, recursively, - // and avoid infinite recursion by keeping track of what has already been added. - - // Note: if project is null, the root list will be empty since it has been - // cleared above. - - // get the AndroidTargetData from the project - IAndroidTarget target = null; - AndroidTargetData data = null; - - target = Sdk.getCurrent().getTarget(project); - if (target == null) { - // A project should have a target. The target can be missing if the project - // is an old project for which a target hasn't been affected or if the - // target no longer exists in this SDK. Simply log the error and dismiss. - - AdtPlugin.log(IStatus.INFO, - "NewXmlFile wizard: no platform target for project %s", //$NON-NLS-1$ - project.getName()); - continue; - } else { - data = Sdk.getCurrent().getTargetData(target); - - if (data == null) { - // We should have both a target and its data. - // However if the wizard is invoked whilst the platform is still being - // loaded we can end up in a weird case where we have a target but it - // doesn't have any data yet. - // Lets log a warning and silently ignore this root. - - AdtPlugin.log(IStatus.INFO, - "NewXmlFile wizard: no data for target %s, project %s", //$NON-NLS-1$ - target.getName(), project.getName()); - continue; - } - } - - IDescriptorProvider provider = data.getDescriptorProvider((Integer)rootSeed); - ElementDescriptor descriptor = provider.getDescriptor(); - if (descriptor != null) { - HashSet<ElementDescriptor> visited = new HashSet<ElementDescriptor>(); - initRootElementDescriptor(roots, descriptor, visited); - } - - // Sort alphabetically. - Collections.sort(roots); - } - } - } - - /** - * Helper method to recursively insert all XML names for the given {@link ElementDescriptor} - * into the roots array list. Keeps track of visited nodes to avoid infinite recursion. - * Also avoids inserting the top {@link DocumentDescriptor} which is generally synthetic - * and not a valid root element. - */ - private void initRootElementDescriptor(ArrayList<String> roots, - ElementDescriptor desc, HashSet<ElementDescriptor> visited) { - if (!(desc instanceof DocumentDescriptor)) { - String xmlName = desc.getXmlName(); - if (xmlName != null && xmlName.length() > 0) { - roots.add(xmlName); - } - } - - visited.add(desc); - - for (ElementDescriptor child : desc.getChildren()) { - if (!visited.contains(child)) { - initRootElementDescriptor(roots, child, visited); - } - } - } - - /** - * Changes mProject to the given new project and update the UI accordingly. - * <p/> - * Note that this does not check if the new project is the same as the current one - * on purpose, which allows a project to be updated when its target has changed or - * when targets are loaded in the background. - */ - private void changeProject(IProject newProject) { - mValues.project = newProject; - - // enable types based on new API level - updateAvailableTypes(); - initialSelectType(); - - // update the folder name based on API level - updateFolderPath(mValues.type); - - // update the Type with the new descriptors. - initializeRootValues(); - - // update the combo - updateRootCombo(mValues.type); - - validatePage(); - } - - private void onSelectType(TypeInfo type) { - // Do nothing if this is an internal modification or if the widget has been - // deselected. - if (mInternalTypeUpdate) { - return; - } - - mValues.type = type; - - if (type == null) { - return; - } - - // update the combo - updateRootCombo(type); - - // update the folder path - updateFolderPath(type); - - validatePage(); - } - - /** Updates the selected type in the type dropdown control */ - private void setSelectedType(TypeInfo type) { - TypeInfo[] types = (TypeInfo[]) mTypeCombo.getData(); - if (types != null) { - for (int i = 0, n = types.length; i < n; i++) { - if (types[i] == type) { - mTypeCombo.select(i); - break; - } - } - } - } - - /** Returns the selected type in the type dropdown control */ - private TypeInfo getSelectedType() { - int index = mTypeCombo.getSelectionIndex(); - if (index != -1) { - TypeInfo[] types = (TypeInfo[]) mTypeCombo.getData(); - return types[index]; - } - - return null; - } - - /** Returns the selected index in the type dropdown control */ - private int getTypeComboIndex(TypeInfo type) { - TypeInfo[] types = (TypeInfo[]) mTypeCombo.getData(); - for (int i = 0, n = types.length; i < n; i++) { - if (type == types[i]) { - return i; - } - } - - return -1; - } - - /** Updates the folder path to reflect the given type */ - private void updateFolderPath(TypeInfo type) { - String wsFolderPath = mValues.folderPath; - String newPath = null; - FolderConfiguration config = mValues.configuration; - ResourceQualifier qual = config.getInvalidQualifier(); - if (qual == null) { - // The configuration is valid. Reformat the folder path using the canonical - // value from the configuration. - newPath = RES_FOLDER_ABS + config.getFolderName(type.getResFolderType()); - } else { - // The configuration is invalid. We still update the path but this time - // do it manually on the string. - if (wsFolderPath.startsWith(RES_FOLDER_ABS)) { - wsFolderPath = wsFolderPath.replaceFirst( - "^(" + RES_FOLDER_ABS +")[^-]*(.*)", //$NON-NLS-1$ //$NON-NLS-2$ - "\\1" + type.getResFolderName() + "\\2"); //$NON-NLS-1$ //$NON-NLS-2$ - } else { - newPath = RES_FOLDER_ABS + config.getFolderName(type.getResFolderType()); - } - } - - if (newPath != null && !newPath.equals(wsFolderPath)) { - mValues.folderPath = newPath; - } - } - - /** - * Helper method that fills the values of the "root element" combo box based - * on the currently selected type radio button. Also disables the combo is there's - * only one choice. Always select the first root element for the given type. - * - * @param type The currently selected {@link TypeInfo}, or null - */ - private void updateRootCombo(TypeInfo type) { - IBaseLabelProvider labelProvider = new ColumnLabelProvider() { - @Override - public Image getImage(Object element) { - return IconFactory.getInstance().getIcon(element.toString()); - } - }; - mRootTableViewer.setContentProvider(new ArrayContentProvider()); - mRootTableViewer.setLabelProvider(labelProvider); - - if (type != null) { - // get the list of roots. The list can be empty but not null. - ArrayList<String> roots = type.getRoots(); - mRootTableViewer.setInput(roots.toArray()); - - int index = 0; // default is to select the first one - String defaultRoot = type.getDefaultRoot(mValues.project); - if (defaultRoot != null) { - index = roots.indexOf(defaultRoot); - } - mRootTable.select(index < 0 ? 0 : index); - mRootTable.showSelection(); - } - } - - /** - * Helper method to select the current type in the type dropdown - * - * @param type The TypeInfo matching the radio button to selected or null to deselect them all. - */ - private void selectType(TypeInfo type) { - mInternalTypeUpdate = true; - mValues.type = type; - if (type == null) { - if (mTypeCombo.getSelectionIndex() != -1) { - mTypeCombo.deselect(mTypeCombo.getSelectionIndex()); - } - } else { - setSelectedType(type); - } - updateRootCombo(type); - mInternalTypeUpdate = false; - } - - /** - * Add the available types in the type combobox, based on whether they are available - * for the current SDK. - * <p/> - * A type is available either if: - * - if mProject is null, API level 1 is considered valid - * - if mProject is !null, the project->target->API must be >= to the type's API level. - */ - private void updateAvailableTypes() { - IProject project = mValues.project; - IAndroidTarget target = project != null ? Sdk.getCurrent().getTarget(project) : null; - int currentApiLevel = 1; - if (target != null) { - currentApiLevel = target.getVersion().getApiLevel(); - } - - List<String> items = new ArrayList<String>(sTypes.length); - List<TypeInfo> types = new ArrayList<TypeInfo>(sTypes.length); - for (int i = 0, n = sTypes.length; i < n; i++) { - TypeInfo type = sTypes[i]; - if (type.getTargetApiLevel() <= currentApiLevel) { - items.add(type.getUiName()); - types.add(type); - } - } - mTypeCombo.setItems(items.toArray(new String[items.size()])); - mTypeCombo.setData(types.toArray(new TypeInfo[types.size()])); - } - - /** - * Validates the fields, displays errors and warnings. - * Enables the finish button if there are no errors. - */ - private void validatePage() { - String error = null; - String warning = null; - - // -- validate type - TypeInfo type = mValues.type; - if (error == null) { - if (type == null) { - error = "One of the types must be selected (e.g. layout, values, etc.)"; - } - } - - // -- validate project - if (mValues.project == null) { - error = "Please select an Android project."; - } - - // -- validate type API level - if (error == null) { - IAndroidTarget target = Sdk.getCurrent().getTarget(mValues.project); - int currentApiLevel = 1; - if (target != null) { - currentApiLevel = target.getVersion().getApiLevel(); - } - - assert type != null; - if (type.getTargetApiLevel() > currentApiLevel) { - error = "The API level of the selected type (e.g. AppWidget, etc.) is not " + - "compatible with the API level of the project."; - } - } - - // -- validate filename - if (error == null) { - String fileName = mValues.getFileName(); - assert type != null; - ResourceFolderType folderType = type.getResFolderType(); - error = ResourceNameValidator.create(true, folderType).isValid(fileName); - } - - // -- validate destination file doesn't exist - if (error == null) { - IFile file = mValues.getDestinationFile(); - if (file != null && file.exists()) { - warning = "The destination file already exists"; - } - } - - // -- update UI & enable finish if there's no error - setPageComplete(error == null); - if (error != null) { - setMessage(error, IMessageProvider.ERROR); - } else if (warning != null) { - setMessage(warning, IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - /** - * Returns the {@link TypeInfo} for the given {@link ResourceFolderType}, or null if - * not found - * - * @param folderType the {@link ResourceFolderType} to look for - * @return the corresponding {@link TypeInfo} - */ - static TypeInfo getTypeInfo(ResourceFolderType folderType) { - for (TypeInfo typeInfo : sTypes) { - if (typeInfo.getResFolderType() == folderType) { - return typeInfo; - } - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java deleted file mode 100644 index 16cd7b355..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2008 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.newxmlfile; - -import static com.android.SdkConstants.FQCN_GRID_LAYOUT; -import static com.android.SdkConstants.GRID_LAYOUT; - -import com.android.SdkConstants; -import com.android.ide.common.resources.configuration.FolderConfiguration; -import com.android.ide.common.xml.XmlFormatStyle; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; -import com.android.ide.eclipse.adt.internal.editors.IconFactory; -import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlFormatPreferences; -import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlPrettyPrinter; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewManager; -import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.android.ide.eclipse.adt.internal.project.SupportLibraryHelper; -import com.android.ide.eclipse.adt.internal.wizards.newxmlfile.NewXmlFileCreationPage.TypeInfo; -import com.android.resources.ResourceFolderType; -import com.android.utils.Pair; - -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.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.Region; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.INewWizard; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PartInitException; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; - -/** - * The "New Android XML File Wizard" provides the ability to create skeleton XML - * resources files for Android projects. - * <p/> - * The wizard has one page, {@link NewXmlFileCreationPage}, used to select the project, - * the resource folder, resource type and file name. It then creates the XML file. - */ -public class NewXmlFileWizard extends Wizard implements INewWizard { - /** The XML header to write at the top of the XML file */ - public static final String XML_HEADER_LINE = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; //$NON-NLS-1$ - - private static final String PROJECT_LOGO_LARGE = "android-64"; //$NON-NLS-1$ - - protected static final String MAIN_PAGE_NAME = "newAndroidXmlFilePage"; //$NON-NLS-1$ - - private NewXmlFileCreationPage mMainPage; - private ChooseConfigurationPage mConfigPage; - private Values mValues; - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - setHelpAvailable(false); // TODO have help - setWindowTitle("New Android XML File"); - setImageDescriptor(); - - mValues = new Values(); - mMainPage = createMainPage(mValues); - mMainPage.setTitle("New Android XML File"); - mMainPage.setDescription("Creates a new Android XML file."); - mMainPage.setInitialSelection(selection); - - mConfigPage = new ChooseConfigurationPage(mValues); - - // Trigger a check to see if the SDK needs to be reloaded (which will - // invoke onSdkLoaded asynchronously as needed). - AdtPlugin.getDefault().refreshSdk(); - } - - /** - * Creates the wizard page. - * <p/> - * Please do NOT override this method. - * <p/> - * This is protected so that it can be overridden by unit tests. - * However the contract of this class is private and NO ATTEMPT will be made - * to maintain compatibility between different versions of the plugin. - */ - protected NewXmlFileCreationPage createMainPage(NewXmlFileWizard.Values values) { - return new NewXmlFileCreationPage(MAIN_PAGE_NAME, values); - } - - // -- Methods inherited from org.eclipse.jface.wizard.Wizard -- - // - // The Wizard class implements most defaults and boilerplate code needed by - // IWizard - - /** - * Adds pages to this wizard. - */ - @Override - public void addPages() { - addPage(mMainPage); - addPage(mConfigPage); - - } - - /** - * Performs any actions appropriate in response to the user having pressed - * the Finish button, or refuse if finishing now is not permitted: here, it - * actually creates the workspace project and then switch to the Java - * perspective. - * - * @return True - */ - @Override - public boolean performFinish() { - final Pair<IFile, IRegion> created = createXmlFile(); - if (created == null) { - return false; - } else { - // Open the file - // This has to be delayed in order for focus handling to work correctly - AdtPlugin.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - IFile file = created.getFirst(); - IRegion region = created.getSecond(); - try { - IEditorPart editor = AdtPlugin.openFile(file, null, - false /*showEditorTab*/); - if (editor instanceof AndroidXmlEditor) { - final AndroidXmlEditor xmlEditor = (AndroidXmlEditor)editor; - if (!xmlEditor.hasMultiplePages()) { - xmlEditor.show(region.getOffset(), region.getLength(), - true /* showEditorTab */); - } - } - } catch (PartInitException e) { - AdtPlugin.log(e, "Failed to create %1$s: missing type", //$NON-NLS-1$ - file.getFullPath().toString()); - } - }}); - - return true; - } - } - - // -- Custom Methods -- - - private Pair<IFile, IRegion> createXmlFile() { - IFile file = mValues.getDestinationFile(); - TypeInfo type = mValues.type; - if (type == null) { - // this is not expected to happen - String name = file.getFullPath().toString(); - AdtPlugin.log(IStatus.ERROR, "Failed to create %1$s: missing type", name); //$NON-NLS-1$ - return null; - } - String xmlns = type.getXmlns(); - String root = mMainPage.getRootElement(); - if (root == null) { - // this is not expected to happen - AdtPlugin.log(IStatus.ERROR, "Failed to create %1$s: missing root element", //$NON-NLS-1$ - file.toString()); - return null; - } - - String attrs = type.getDefaultAttrs(mValues.project, root); - String child = type.getChild(mValues.project, root); - return createXmlFile(file, xmlns, root, attrs, child, type.getResFolderType()); - } - - /** Creates a new file using the given root element, namespace and root attributes */ - private static Pair<IFile, IRegion> createXmlFile(IFile file, String xmlns, - String root, String rootAttributes, String child, ResourceFolderType folderType) { - String name = file.getFullPath().toString(); - boolean need_delete = false; - - if (file.exists()) { - if (!AdtPlugin.displayPrompt("New Android XML File", - String.format("Do you want to overwrite the file %1$s ?", name))) { - // abort if user selects cancel. - return null; - } - need_delete = true; - } else { - AdtUtils.createWsParentDirectory(file.getParent()); - } - - StringBuilder sb = new StringBuilder(XML_HEADER_LINE); - - if (folderType == ResourceFolderType.LAYOUT && root.equals(GRID_LAYOUT)) { - IProject project = file.getParent().getProject(); - int minSdk = ManifestInfo.get(project).getMinSdkVersion(); - if (minSdk < 14) { - root = SupportLibraryHelper.getTagFor(project, FQCN_GRID_LAYOUT); - if (root.equals(FQCN_GRID_LAYOUT)) { - root = GRID_LAYOUT; - } - } - } - - sb.append('<').append(root); - if (xmlns != null) { - sb.append('\n').append(" xmlns:android=\"").append(xmlns).append('"'); //$NON-NLS-1$ - } - - if (rootAttributes != null) { - sb.append("\n "); //$NON-NLS-1$ - sb.append(rootAttributes.replace("\n", "\n ")); //$NON-NLS-1$ //$NON-NLS-2$ - } - - sb.append(">\n"); //$NON-NLS-1$ - - if (child != null) { - sb.append(child); - } - - boolean autoFormat = AdtPrefs.getPrefs().getUseCustomXmlFormatter(); - - // Insert an indented caret. Since the markup here will be reformatted, we need to - // insert text tokens that the formatter will preserve, which we can then turn back - // into indentation and a caret offset: - final String indentToken = "${indent}"; //$NON-NLS-1$ - final String caretToken = "${caret}"; //$NON-NLS-1$ - sb.append(indentToken); - sb.append(caretToken); - if (!autoFormat) { - sb.append('\n'); - } - - sb.append("</").append(root).append(">\n"); //$NON-NLS-1$ //$NON-NLS-2$ - - EclipseXmlFormatPreferences formatPrefs = EclipseXmlFormatPreferences.create(); - String fileContents; - if (!autoFormat) { - fileContents = sb.toString(); - } else { - XmlFormatStyle style = EclipseXmlPrettyPrinter.getForFolderType(folderType); - fileContents = EclipseXmlPrettyPrinter.prettyPrint(sb.toString(), formatPrefs, - style, null /*lineSeparator*/); - } - - // Remove marker tokens and replace them with whitespace - fileContents = fileContents.replace(indentToken, formatPrefs.getOneIndentUnit()); - int caretOffset = fileContents.indexOf(caretToken); - if (caretOffset != -1) { - fileContents = fileContents.replace(caretToken, ""); //$NON-NLS-1$ - } - - String error = null; - try { - byte[] buf = fileContents.getBytes("UTF8"); //$NON-NLS-1$ - InputStream stream = new ByteArrayInputStream(buf); - if (need_delete) { - file.delete(IResource.KEEP_HISTORY | IResource.FORCE, null /*monitor*/); - } - file.create(stream, true /*force*/, null /*progress*/); - IRegion region = caretOffset != -1 ? new Region(caretOffset, 0) : null; - - // If you introduced a new locale, or new screen variations etc, ensure that - // the list of render previews is updated if necessary - if (file.getParent().getName().indexOf('-') != -1 - && (folderType == ResourceFolderType.LAYOUT - || folderType == ResourceFolderType.VALUES)) { - RenderPreviewManager.bumpRevision(); - } - - return Pair.of(file, region); - } catch (UnsupportedEncodingException e) { - error = e.getMessage(); - } catch (CoreException e) { - error = e.getMessage(); - } - - error = String.format("Failed to generate %1$s: %2$s", name, error); - AdtPlugin.displayError("New Android XML File", error); - return null; - } - - /** - * Returns true if the New XML Wizard can create new files of the given - * {@link ResourceFolderType} - * - * @param folderType the folder type to create a file for - * @return true if this wizard can create new files for the given folder type - */ - public static boolean canCreateXmlFile(ResourceFolderType folderType) { - TypeInfo typeInfo = NewXmlFileCreationPage.getTypeInfo(folderType); - return typeInfo != null && (typeInfo.getDefaultRoot(null /*project*/) != null || - typeInfo.getRootSeed() instanceof String); - } - - /** - * Creates a new XML file using the template according to the given folder type - * - * @param project the project to create the file in - * @param file the file to be created - * @param folderType the type of folder to look up a template for - * @return the created file - */ - public static Pair<IFile, IRegion> createXmlFile(IProject project, IFile file, - ResourceFolderType folderType) { - TypeInfo type = NewXmlFileCreationPage.getTypeInfo(folderType); - String xmlns = type.getXmlns(); - String root = type.getDefaultRoot(project); - if (root == null) { - root = type.getRootSeed().toString(); - } - String attrs = type.getDefaultAttrs(project, root); - return createXmlFile(file, xmlns, root, attrs, null, folderType); - } - - /** - * Returns an image descriptor for the wizard logo. - */ - private void setImageDescriptor() { - ImageDescriptor desc = IconFactory.getInstance().getImageDescriptor(PROJECT_LOGO_LARGE); - setDefaultPageImageDescriptor(desc); - } - - /** - * Specific New XML File wizard tied to the {@link ResourceFolderType#LAYOUT} type - */ - public static class NewLayoutWizard extends NewXmlFileWizard { - /** Creates a new {@link NewLayoutWizard} */ - public NewLayoutWizard() { - } - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - super.init(workbench, selection); - setWindowTitle("New Android Layout XML File"); - super.mMainPage.setTitle("New Android Layout XML File"); - super.mMainPage.setDescription("Creates a new Android Layout XML file."); - super.mMainPage.setInitialFolderType(ResourceFolderType.LAYOUT); - } - } - - /** - * Specific New XML File wizard tied to the {@link ResourceFolderType#VALUES} type - */ - public static class NewValuesWizard extends NewXmlFileWizard { - /** Creates a new {@link NewValuesWizard} */ - public NewValuesWizard() { - } - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - super.init(workbench, selection); - setWindowTitle("New Android Values XML File"); - super.mMainPage.setTitle("New Android Values XML File"); - super.mMainPage.setDescription("Creates a new Android Values XML file."); - super.mMainPage.setInitialFolderType(ResourceFolderType.VALUES); - } - } - - /** Value object which holds the current state of the wizard pages */ - public static class Values { - /** The currently selected project, or null */ - public IProject project; - /** The root name of the XML file to create, or null */ - public String name; - /** The type of XML file to create */ - public TypeInfo type; - /** The path within the project to create the new file in */ - public String folderPath; - /** The currently chosen configuration */ - public FolderConfiguration configuration = new FolderConfiguration(); - - /** - * Returns the destination filename or an empty string. - * - * @return the filename, never null. - */ - public String getFileName() { - String fileName; - if (name == null) { - fileName = ""; //$NON-NLS-1$ - } else { - fileName = name.trim(); - if (fileName.length() > 0 && fileName.indexOf('.') == -1) { - fileName = fileName + SdkConstants.DOT_XML; - } - } - - return fileName; - } - - /** - * Returns a {@link IFile} for the destination file. - * <p/> - * Returns null if the project, filename or folder are invalid and the - * destination file cannot be determined. - * <p/> - * The {@link IFile} is a resource. There might or might not be an - * actual real file. - * - * @return an {@link IFile} for the destination file - */ - public IFile getDestinationFile() { - String fileName = getFileName(); - if (project != null && folderPath != null && folderPath.length() > 0 - && fileName.length() > 0) { - IPath dest = new Path(folderPath).append(fileName); - IFile file = project.getFile(dest); - return file; - } - return null; - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ActivityPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ActivityPage.java deleted file mode 100644 index ba4aedc8a..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ActivityPage.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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 com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.CATEGORY_ACTIVITIES; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.CATEGORY_OTHER; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.IS_LAUNCHER; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_PADDING; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_WIDTH; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl; -import com.google.common.collect.Lists; -import com.google.common.io.Files; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.List; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; - -class ActivityPage extends WizardPage implements SelectionListener { - private final NewProjectWizardState mValues; - private List mList; - private Button mCreateToggle; - private java.util.List<File> mTemplates; - - private boolean mIgnore; - private boolean mShown; - private ImageControl mPreview; - private Image mPreviewImage; - private boolean mDisposePreviewImage; - private Label mHeading; - private Label mDescription; - private boolean mOnlyActivities; - private boolean mAskCreate; - private boolean mLauncherActivitiesOnly; - - /** - * Create the wizard. - */ - ActivityPage(NewProjectWizardState values, boolean onlyActivities, boolean askCreate) { - super("activityPage"); //$NON-NLS-1$ - mValues = values; - mOnlyActivities = onlyActivities; - mAskCreate = askCreate; - - if (onlyActivities) { - setTitle("Create Activity"); - } else { - setTitle("Create Android Object"); - } - if (onlyActivities && askCreate) { - setDescription( - "Select whether to create an activity, and if so, what kind of activity."); - } else { - setDescription("Select which template to use"); - } - } - - /** Sets whether the activity page should only offer launcher activities */ - void setLauncherActivitiesOnly(boolean launcherActivitiesOnly) { - mLauncherActivitiesOnly = launcherActivitiesOnly; - } - - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - setControl(container); - } - - @SuppressWarnings("unused") // SWT constructors have side effects and aren't unused - private void onEnter() { - Composite container = (Composite) getControl(); - container.setLayout(new GridLayout(3, false)); - - if (mAskCreate) { - mCreateToggle = new Button(container, SWT.CHECK); - mCreateToggle.setSelection(true); - mCreateToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); - mCreateToggle.setText("Create Activity"); - mCreateToggle.addSelectionListener(this); - } - - mList = new List(container, SWT.BORDER | SWT.V_SCROLL); - mList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); - - - TemplateManager manager = mValues.template.getManager(); - java.util.List<File> templates = manager.getTemplates(CATEGORY_ACTIVITIES); - - if (!mOnlyActivities) { - templates.addAll(manager.getTemplates(CATEGORY_OTHER)); - } - java.util.List<String> names = new ArrayList<String>(templates.size()); - File current = mValues.activityValues.getTemplateLocation(); - mTemplates = Lists.newArrayListWithExpectedSize(templates.size()); - int index = -1; - for (int i = 0, n = templates.size(); i < n; i++) { - File template = templates.get(i); - TemplateMetadata metadata = manager.getTemplate(template); - if (metadata == null) { - continue; - } - if (mLauncherActivitiesOnly) { - Parameter parameter = metadata.getParameter(IS_LAUNCHER); - if (parameter == null) { - continue; - } - } - mTemplates.add(template); - names.add(metadata.getTitle()); - if (template.equals(current)) { - index = names.size(); - } - } - String[] items = names.toArray(new String[names.size()]); - mList.setItems(items); - if (index == -1 && !mTemplates.isEmpty()) { - mValues.activityValues.setTemplateLocation(mTemplates.get(0)); - index = 0; - } - if (index >= 0) { - mList.setSelection(index); - mList.addSelectionListener(this); - } - - // Preview - mPreview = new ImageControl(container, SWT.NONE, null); - mPreview.setDisposeImage(false); // Handled manually in this class - GridData gd_mImage = new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1); - gd_mImage.widthHint = PREVIEW_WIDTH + 2 * PREVIEW_PADDING; - mPreview.setLayoutData(gd_mImage); - new Label(container, SWT.NONE); - - mHeading = new Label(container, SWT.NONE); - mHeading.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); - new Label(container, SWT.NONE); - - mDescription = new Label(container, SWT.WRAP); - mDescription.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); - - Font font = JFaceResources.getFontRegistry().getBold(JFaceResources.BANNER_FONT); - if (font != null) { - mHeading.setFont(font); - } - - updatePreview(); - } - - private void updatePreview() { - Image oldImage = mPreviewImage; - boolean dispose = mDisposePreviewImage; - mPreviewImage = null; - - String title = ""; - String description = ""; - TemplateHandler handler = mValues.activityValues.getTemplateHandler(); - TemplateMetadata template = handler.getTemplate(); - if (template != null) { - String thumb = template.getThumbnailPath(); - if (thumb != null && !thumb.isEmpty()) { - File file = new File(mValues.activityValues.getTemplateLocation(), - thumb.replace('/', File.separatorChar)); - if (file != null) { - try { - byte[] bytes = Files.toByteArray(file); - ByteArrayInputStream input = new ByteArrayInputStream(bytes); - mPreviewImage = new Image(getControl().getDisplay(), input); - mDisposePreviewImage = true; - input.close(); - } catch (IOException e) { - AdtPlugin.log(e, null); - } - } - } else { - // Fallback icon - mDisposePreviewImage = false; - mPreviewImage = TemplateMetadata.getDefaultTemplateIcon(); - } - title = template.getTitle(); - description = template.getDescription(); - } - - mHeading.setText(title); - mDescription.setText(description); - mPreview.setImage(mPreviewImage); - mPreview.fitToWidth(PREVIEW_WIDTH); - - if (oldImage != null && dispose) { - oldImage.dispose(); - } - - Composite parent = (Composite) getControl(); - parent.layout(true, true); - parent.redraw(); - } - - @Override - public void dispose() { - super.dispose(); - - if (mPreviewImage != null && mDisposePreviewImage) { - mDisposePreviewImage = false; - mPreviewImage.dispose(); - mPreviewImage = null; - } - } - - @Override - public void setVisible(boolean visible) { - if (visible && !mShown) { - onEnter(); - } - - super.setVisible(visible); - - if (visible) { - mShown = true; - if (mAskCreate) { - try { - mIgnore = true; - mCreateToggle.setSelection(mValues.createActivity); - } finally { - mIgnore = false; - } - } - } - - validatePage(); - } - - - private void validatePage() { - IStatus status = null; - - if (mValues.createActivity) { - if (mList.getSelectionCount() < 1) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Select an activity type"); - } else { - TemplateHandler templateHandler = mValues.activityValues.getTemplateHandler(); - status = templateHandler.validateTemplate(mValues.minSdkLevel, - mValues.getBuildApi()); - } - } - - setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); - if (status != null) { - setMessage(status.getMessage(), - status.getSeverity() == IStatus.ERROR - ? IMessageProvider.ERROR : IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - @Override - public boolean isPageComplete() { - // Ensure that the Finish button isn't enabled until - // the user has reached and completed this page - if (!mShown && mValues.createActivity) { - return false; - } - - return super.isPageComplete(); - } - - // ---- Implements SelectionListener ---- - - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source == mCreateToggle) { - mValues.createActivity = mCreateToggle.getSelection(); - mList.setEnabled(mValues.createActivity); - } else if (source == mList) { - int index = mList.getSelectionIndex(); - if (index >= 0 && index < mTemplates.size()) { - File template = mTemplates.get(index); - mValues.activityValues.setTemplateLocation(template); - updatePreview(); - } - } - - validatePage(); - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } -} 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 deleted file mode 100644 index 3b41c36c2..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/CreateFileChange.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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/FmActivityToLayoutMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmActivityToLayoutMethod.java deleted file mode 100644 index fbd50e986..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmActivityToLayoutMethod.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectPage.ACTIVITY_NAME_SUFFIX; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectPage.LAYOUT_NAME_PREFIX; - -import com.android.ide.eclipse.adt.AdtUtils; - -import freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Method invoked by FreeMarker to convert an Activity class name into - * a suitable layout name. - */ -public class FmActivityToLayoutMethod implements TemplateMethodModel { - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - - String activityName = args.get(0).toString(); - - if (activityName.isEmpty()) { - return new SimpleScalar(""); - } - - // Strip off the end portion of the activity name. The user might be typing - // the activity name such that only a portion has been entered so far (e.g. - // "MainActivi") and we want to chop off that portion too such that we don't - // offer a layout name partially containing the activity suffix (e.g. "main_activi"). - int suffixStart = activityName.lastIndexOf(ACTIVITY_NAME_SUFFIX.charAt(0)); - if (suffixStart != -1 && activityName.regionMatches(suffixStart, ACTIVITY_NAME_SUFFIX, 0, - activityName.length() - suffixStart)) { - activityName = activityName.substring(0, suffixStart); - } - assert !activityName.endsWith(ACTIVITY_NAME_SUFFIX) : activityName; - - // Convert CamelCase convention used in activity class names to underlined convention - // used in layout name: - String name = LAYOUT_NAME_PREFIX + AdtUtils.camelCaseToUnderlines(activityName); - - return new SimpleScalar(name); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmCamelCaseToUnderscoreMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmCamelCaseToUnderscoreMethod.java deleted file mode 100644 index b85576577..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmCamelCaseToUnderscoreMethod.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.ide.eclipse.adt.AdtUtils; - -import freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Method invoked by FreeMarker to convert an underscore name into a CamelCase name. - */ -public class FmCamelCaseToUnderscoreMethod implements TemplateMethodModel { - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - return new SimpleScalar(AdtUtils.camelCaseToUnderlines(args.get(0).toString())); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmClassNameToResourceMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmClassNameToResourceMethod.java deleted file mode 100644 index 366de9afa..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmClassNameToResourceMethod.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectPage.ACTIVITY_NAME_SUFFIX; - -import com.android.ide.eclipse.adt.AdtUtils; - -import freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Similar to {@link FmCamelCaseToUnderscoreMethod}, but strips off common class - * suffixes such as "Activity", "Fragment", etc. - */ -public class FmClassNameToResourceMethod implements TemplateMethodModel { - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - - String name = args.get(0).toString(); - - if (name.isEmpty()) { - return new SimpleScalar(""); - } - - name = stripSuffix(name, ACTIVITY_NAME_SUFFIX); - name = stripSuffix(name, "Fragment"); //$NON-NLS-1$ - name = stripSuffix(name, "Service"); //$NON-NLS-1$ - name = stripSuffix(name, "Provider"); //$NON-NLS-1$ - - return new SimpleScalar(AdtUtils.camelCaseToUnderlines(name)); - } - - // Strip off the end portion of the activity name. The user might be typing - // the activity name such that only a portion has been entered so far (e.g. - // "MainActivi") and we want to chop off that portion too such that we don't - private static String stripSuffix(String name, String suffix) { - int suffixStart = name.lastIndexOf(suffix.charAt(0)); - if (suffixStart != -1 && name.regionMatches(suffixStart, suffix, 0, - name.length() - suffixStart)) { - name = name.substring(0, suffixStart); - } - assert !name.endsWith(suffix) : name; - - return name; - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlAttributeMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlAttributeMethod.java deleted file mode 100644 index 21f33b8d7..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlAttributeMethod.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.utils.XmlUtils; - -import freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Method invoked by FreeMarker to escape a string such that it can be used - * as an XML attribute (escaping ', ", & and <). - */ -public class FmEscapeXmlAttributeMethod implements TemplateMethodModel { - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - String string = args.get(0).toString(); - return new SimpleScalar(XmlUtils.toXmlAttributeValue(string)); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlStringMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlStringMethod.java deleted file mode 100644 index 2255653a7..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlStringMethod.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.ide.common.res2.ValueXmlHelper; - -import freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Method invoked by FreeMarker to escape a string such that it can be placed - * as text in a string resource file. - * This is similar to {@link FmEscapeXmlTextMethod}, but in addition to escaping - * < and & it also escapes characters such as quotes necessary for Android - *{@code <string>} elements. - */ -public class FmEscapeXmlStringMethod implements TemplateMethodModel { - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - String string = args.get(0).toString(); - return new SimpleScalar(ValueXmlHelper.escapeResourceString(string)); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlTextMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlTextMethod.java deleted file mode 100644 index 55a4bc8ab..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlTextMethod.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.utils.XmlUtils; - -import freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Method invoked by FreeMarker to escape a string such that it can be used - * as XML text (escaping < and &, but not ' and " etc). - */ -public class FmEscapeXmlTextMethod implements TemplateMethodModel { - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - String string = args.get(0).toString(); - return new SimpleScalar(XmlUtils.toXmlTextValue(string)); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java deleted file mode 100644 index 09fa81c57..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Method invoked by FreeMarker to extract letters from a string; this will remove - * any whitespace, punctuation and digits. - */ -public class FmExtractLettersMethod implements TemplateMethodModel { - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - String string = args.get(0).toString(); - StringBuilder sb = new StringBuilder(string.length()); - for (int i = 0, n = string.length(); i < n; i++) { - char c = string.charAt(i); - if (Character.isLetter(c)) { - sb.append(c); - } - } - return new SimpleScalar(sb.toString()); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmLayoutToActivityMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmLayoutToActivityMethod.java deleted file mode 100644 index 6514959f7..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmLayoutToActivityMethod.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 com.android.ide.eclipse.adt.AdtUtils.extractClassName; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectPage.ACTIVITY_NAME_SUFFIX; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectPage.LAYOUT_NAME_PREFIX; - -import com.android.ide.eclipse.adt.AdtUtils; - -import freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Method invoked by FreeMarker to convert a layout name into an appropriate - * Activity class. - */ -public class FmLayoutToActivityMethod implements TemplateMethodModel { - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - - String name = args.get(0).toString(); - - // Strip off the beginning portion of the layout name. The user might be typing - // the activity name such that only a portion has been entered so far (e.g. - // "MainActivi") and we want to chop off that portion too such that we don't - // offer a layout name partially containing the activity suffix (e.g. "main_activi"). - if (name.startsWith(LAYOUT_NAME_PREFIX)) { - name = name.substring(LAYOUT_NAME_PREFIX.length()); - } - - name = AdtUtils.underlinesToCamelCase(name); - String className = extractClassName(name); - if (className == null) { - className = "My"; - } - String activityName = className + ACTIVITY_NAME_SUFFIX; - - return new SimpleScalar(activityName); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmSlashedPackageNameMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmSlashedPackageNameMethod.java deleted file mode 100644 index 60a6531e6..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmSlashedPackageNameMethod.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Method invoked by FreeMarker to convert a package name (foo.bar) into - * a slashed path (foo/bar) - */ -public class FmSlashedPackageNameMethod implements TemplateMethodModel { - - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - - return new SimpleScalar(args.get(0).toString().replace('.', '/')); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmUnderscoreToCamelCaseMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmUnderscoreToCamelCaseMethod.java deleted file mode 100644 index 26d4fadb4..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmUnderscoreToCamelCaseMethod.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.ide.eclipse.adt.AdtUtils; - -import freemarker.template.SimpleScalar; -import freemarker.template.TemplateMethodModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; - -import java.util.List; - -/** - * Method invoked by FreeMarker to convert a CamelCase word into - * underscore_names. - */ -public class FmUnderscoreToCamelCaseMethod implements TemplateMethodModel { - @Override - public TemplateModel exec(List args) throws TemplateModelException { - if (args.size() != 1) { - throw new TemplateModelException("Wrong arguments"); - } - return new SimpleScalar(AdtUtils.underlinesToCamelCase(args.get(0).toString())); - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/InstallDependencyPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/InstallDependencyPage.java deleted file mode 100644 index d806e7970..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/InstallDependencyPage.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * 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.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.actions.AddSupportJarAction; -import com.android.utils.Pair; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.wizard.IWizard; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Link; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.browser.IWebBrowser; - -import java.io.File; -import java.net.URL; -import java.util.List; - -class InstallDependencyPage extends WizardPage implements SelectionListener { - /** - * The compatibility library. This is the only library the templates - * currently support. The appearance of any other dependency in this - * template will be flagged as a validation error (and the user encouraged - * to upgrade to a newer ADT - */ - static final String SUPPORT_LIBRARY_NAME = "android-support-v4"; //$NON-NLS-1$ - - /** URL containing more info */ - private static final String URL = - "http://developer.android.com/tools/extras/support-library.html"; //$NON-NLS-1$ - - private Button mCheckButton; - private Button mInstallButton; - private Link mLink; - private TemplateMetadata mTemplate; - - InstallDependencyPage() { - super("dependency"); //$NON-NLS-1$ - setTitle("Install Dependencies"); - } - - void setTemplate(TemplateMetadata template) { - if (template != mTemplate) { - mTemplate = template; - if (getControl() != null) { - validatePage(); - } - } - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - if (visible) { - updateVersionLabels(); - validatePage(); - } - } - - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - setControl(container); - container.setLayout(new GridLayout(2, false)); - // Remaining contents are created lazily, since this page is always added to - // the page list, but typically not shown - - Label dependLabel = new Label(container, SWT.WRAP); - GridData gd_dependLabel = new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1); - gd_dependLabel.widthHint = NewTemplatePage.WIZARD_PAGE_WIDTH - 50; - dependLabel.setLayoutData(gd_dependLabel); - dependLabel.setText("This template depends on the Android Support library, which is " + - "either not installed, or the template depends on a more recent version than " + - "the one you have installed."); - - mLink = new Link(container, SWT.NONE); - mLink.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1)); - mLink.setText("<a href=\"" + URL + "\">" + URL + "</a>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - mLink.addSelectionListener(this); - - Label lblNewLabel_1 = new Label(container, SWT.NONE); - lblNewLabel_1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); - - requiredLabel = new Label(container, SWT.NONE); - requiredLabel.setText("Required version:"); - - mRequiredVersion = new Label(container, SWT.NONE); - mRequiredVersion.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); - - installedLabel = new Label(container, SWT.NONE); - installedLabel.setText("Installed version:"); - - mInstalledVersion = new Label(container, SWT.NONE); - mInstalledVersion.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); - - Label lblNewLabel = new Label(container, SWT.NONE); - lblNewLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); - - Label descLabel = new Label(container, SWT.WRAP); - GridData gd_descLabel = new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1); - gd_descLabel.widthHint = 550; - descLabel.setLayoutData(gd_descLabel); - descLabel.setText( - "You can install or upgrade it by clicking the Install button below, or " + - "alternatively, you can install it outside of Eclipse with the SDK Manager, " + - "then click on \"Check Again\" to proceed."); - - mInstallButton = new Button(container, SWT.NONE); - mInstallButton.setText("Install/Upgrade"); - mInstallButton.addSelectionListener(this); - - mCheckButton = new Button(container, SWT.NONE); - mCheckButton.setText("Check Again"); - mCheckButton.addSelectionListener(this); - - mInstallButton.setFocus(); - } - - private void showNextPage() { - validatePage(); - if (isPageComplete()) { - // Finish button will be enabled now - mInstallButton.setEnabled(false); - mCheckButton.setEnabled(false); - - IWizard wizard = getWizard(); - IWizardPage next = wizard.getNextPage(this); - if (next != null) { - wizard.getContainer().showPage(next); - } - } - } - - @Override - public boolean isPageComplete() { - if (mTemplate == null) { - return true; - } - - return super.isPageComplete() && isInstalled(); - } - - private boolean isInstalled() { - return isInstalled(mTemplate.getDependencies()); - } - - static String sCachedName; - static int sCachedVersion; - private Label requiredLabel; - private Label installedLabel; - private Label mRequiredVersion; - private Label mInstalledVersion; - - public static boolean isInstalled(List<Pair<String, Integer>> dependencies) { - for (Pair<String, Integer> dependency : dependencies) { - String name = dependency.getFirst(); - int required = dependency.getSecond(); - - int installed = -1; - if (SUPPORT_LIBRARY_NAME.equals(name)) { - installed = getInstalledSupportLibVersion(); - } - - if (installed == -1) { - return false; - } - if (required > installed) { - return false; - } - } - - return true; - } - - private static int getInstalledSupportLibVersion() { - if (SUPPORT_LIBRARY_NAME.equals(sCachedName)) { - return sCachedVersion; - } else { - int version = AddSupportJarAction.getInstalledRevision(); - sCachedName = SUPPORT_LIBRARY_NAME; - sCachedVersion = version; - return version; - } - } - - private void updateVersionLabels() { - int version = getInstalledSupportLibVersion(); - if (version == -1) { - mInstalledVersion.setText("Not installed"); - } else { - mInstalledVersion.setText(Integer.toString(version)); - } - - if (mTemplate != null) { - for (Pair<String, Integer> dependency : mTemplate.getDependencies()) { - String name = dependency.getFirst(); - if (name.equals(SUPPORT_LIBRARY_NAME)) { - int required = dependency.getSecond(); - mRequiredVersion.setText(Integer.toString(required)); - break; - } - } - } - } - - private void validatePage() { - if (mTemplate == null) { - return; - } - - IStatus status = null; - - List<Pair<String, Integer>> dependencies = mTemplate.getDependencies(); - if (dependencies.size() > 1 || dependencies.size() == 1 - && !dependencies.get(0).getFirst().equals(SUPPORT_LIBRARY_NAME)) { - status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, - "Unsupported template dependency: Upgrade your Android Eclipse plugin"); - } - - setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); - if (status != null) { - setMessage(status.getMessage(), - status.getSeverity() == IStatus.ERROR - ? IMessageProvider.ERROR : IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - // ---- Implements SelectionListener ---- - - @Override - public void widgetSelected(SelectionEvent e) { - Object source = e.getSource(); - if (source == mCheckButton) { - sCachedName = null; - if (isInstalled()) { - showNextPage(); - } - updateVersionLabels(); - } else if (source == mInstallButton) { - sCachedName = null; - for (Pair<String, Integer> dependency : mTemplate.getDependencies()) { - String name = dependency.getFirst(); - if (SUPPORT_LIBRARY_NAME.equals(name)) { - int version = dependency.getSecond(); - File installed = AddSupportJarAction.installSupport(version); - if (installed != null) { - showNextPage(); - } - updateVersionLabels(); - } - } - } else if (source == mLink) { - try { - IWorkbench workbench = PlatformUI.getWorkbench(); - IWebBrowser browser = workbench.getBrowserSupport().getExternalBrowser(); - browser.openURL(new URL(URL)); - } catch (Exception ex) { - String message = String.format("Could not open browser. Vist\n%1$s\ninstead.", - URL); - MessageDialog.openError(getShell(), "Browser Error", message); - } - } - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } -} 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 deleted file mode 100644 index b33d65bb7..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewActivityWizard.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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 com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_BUILD_API; -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 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 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.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.ltk.core.refactoring.Change; -import org.eclipse.ltk.core.refactoring.CompositeChange; -import org.eclipse.ui.IWorkbench; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.Set; - -/** - * Wizard for creating new activities. This is a hybrid between a New Project - * Wizard and a New Template Wizard: it has the "Activity selector" page from - * the New Project Wizard, which is used to dynamically select a wizard for the - * second page, but beyond that it runs the normal template wizard when it comes - * time to create the template. - */ -public class NewActivityWizard extends TemplateWizard { - private NewTemplatePage mTemplatePage; - private ActivityPage mActivityPage; - private NewProjectWizardState mValues; - private NewTemplateWizardState mActivityValues; - protected boolean mOnlyActivities; - - /** Creates a new {@link NewActivityWizard} */ - public NewActivityWizard() { - mOnlyActivities = true; - } - - @Override - protected boolean shouldAddIconPage() { - return mActivityValues.getIconState() != null; - } - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - super.init(workbench, selection); - - setWindowTitle(mOnlyActivities ? "New Activity" : "New Android Object"); - - mValues = new NewProjectWizardState(); - mActivityPage = new ActivityPage(mValues, mOnlyActivities, false); - - mActivityValues = mValues.activityValues; - List<IProject> projects = AdtUtils.getSelectedProjects(selection); - if (projects.size() == 1) { - mActivityValues.project = projects.get(0); - } - } - - @Override - public void addPages() { - super.addPages(); - addPage(mActivityPage); - } - - @Override - public IWizardPage getNextPage(IWizardPage page) { - if (page == mActivityPage) { - if (mTemplatePage == null) { - Set<String> hidden = mActivityValues.hidden; - hidden.add(ATTR_PACKAGE_NAME); - hidden.add(ATTR_MIN_API); - hidden.add(ATTR_MIN_API_LEVEL); - hidden.add(ATTR_TARGET_API); - hidden.add(ATTR_BUILD_API); - - mTemplatePage = new NewTemplatePage(mActivityValues, true); - addPage(mTemplatePage); - } - return mTemplatePage; - } else if (page == mTemplatePage && shouldAddIconPage()) { - WizardPage iconPage = getIconPage(mActivityValues.getIconState()); - mActivityValues.updateIconState(mTemplatePage.getEvaluator()); - return iconPage; - } else if (page == mTemplatePage - || shouldAddIconPage() && page == getIconPage(mActivityValues.getIconState())) { - TemplateMetadata template = mActivityValues.getTemplateHandler().getTemplate(); - if (template != null) { - if (InstallDependencyPage.isInstalled(template.getDependencies())) { - return getPreviewPage(mActivityValues); - } else { - return getDependencyPage(template, true); - } - } - } else { - TemplateMetadata template = mActivityValues.getTemplateHandler().getTemplate(); - if (template != null && page == getDependencyPage(template, false)) { - return getPreviewPage(mActivityValues); - } - } - - return super.getNextPage(page); - } - - @Override - public boolean canFinish() { - // Deal with lazy creation of some pages: these may not be in the page-list yet - // since they are constructed lazily, so consider that option here. - if (mTemplatePage == null || !mTemplatePage.isPageComplete()) { - return false; - } - - return super.canFinish(); - } - - @Override - public boolean performFinish(IProgressMonitor monitor) throws InvocationTargetException { - boolean success = super.performFinish(monitor); - - if (success) { - List<Runnable> finalizingTasks = getFinalizingActions(); - for (Runnable r : finalizingTasks) { - r.run(); - } - return true; - } - return false; - } - - @Override - @NonNull - protected IProject getProject() { - return mActivityValues.project; - } - - @Override - @NonNull - protected List<String> getFilesToOpen() { - TemplateHandler activityTemplate = mActivityValues.getTemplateHandler(); - return activityTemplate.getFilesToOpen(); - } - - @Override - @NonNull - protected List<Runnable> getFinalizingActions() { - TemplateHandler activityTemplate = mActivityValues.getTemplateHandler(); - return activityTemplate.getFinalizingActions(); - } - - @Override - protected List<Change> computeChanges() { - return mActivityValues.computeChanges(); - } - - /** Wizard for creating other Android components */ - public static class OtherWizard extends NewActivityWizard { - /** Create new {@link OtherWizard} */ - public OtherWizard() { - mOnlyActivities = false; - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectPage.java deleted file mode 100644 index 14f59c00d..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectPage.java +++ /dev/null @@ -1,931 +0,0 @@ -/* - * 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 com.android.SdkConstants.ATTR_ID; -import static com.android.ide.eclipse.adt.AdtUtils.extractClassName; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewTemplatePage.WIZARD_PAGE_WIDTH; - -import com.android.annotations.Nullable; -import com.android.sdklib.SdkVersionInfo; -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.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.wizards.newproject.ApplicationInfoPage; -import com.android.ide.eclipse.adt.internal.wizards.newproject.ProjectNamePage; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.IAndroidTarget; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.fieldassist.ControlDecoration; -import org.eclipse.jface.fieldassist.FieldDecoration; -import org.eclipse.jface.fieldassist.FieldDecorationRegistry; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * First wizard page in the "New Project From Template" wizard - */ -public class NewProjectPage extends WizardPage - implements ModifyListener, SelectionListener, FocusListener { - private static final int FIELD_WIDTH = 300; - private static final String SAMPLE_PACKAGE_PREFIX = "com.example."; //$NON-NLS-1$ - /** Suffix added by default to activity names */ - static final String ACTIVITY_NAME_SUFFIX = "Activity"; //$NON-NLS-1$ - /** Prefix added to default layout names */ - static final String LAYOUT_NAME_PREFIX = "activity_"; //$NON-NLS-1$ - private static final int INITIAL_MIN_SDK = 8; - - private final NewProjectWizardState mValues; - private Map<String, Integer> mMinNameToApi; - private Parameter mThemeParameter; - private Combo mThemeCombo; - - private Text mProjectText; - private Text mPackageText; - private Text mApplicationText; - private Combo mMinSdkCombo; - private Combo mTargetSdkCombo; - private Combo mBuildSdkCombo; - private Label mHelpIcon; - private Label mTipLabel; - - private boolean mIgnore; - private ControlDecoration mApplicationDec; - private ControlDecoration mProjectDec; - private ControlDecoration mPackageDec; - private ControlDecoration mBuildTargetDec; - private ControlDecoration mMinSdkDec; - private ControlDecoration mTargetSdkDec; - private ControlDecoration mThemeDec; - - NewProjectPage(NewProjectWizardState values) { - super("newAndroidApp"); //$NON-NLS-1$ - mValues = values; - setTitle("New Android Application"); - setDescription("Creates a new Android Application"); - } - - @SuppressWarnings("unused") // SWT constructors have side effects and aren't unused - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - setControl(container); - GridLayout gl_container = new GridLayout(4, false); - gl_container.horizontalSpacing = 10; - container.setLayout(gl_container); - - Label applicationLabel = new Label(container, SWT.NONE); - applicationLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); - applicationLabel.setText("Application Name:"); - - mApplicationText = new Text(container, SWT.BORDER); - GridData gdApplicationText = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1); - gdApplicationText.widthHint = FIELD_WIDTH; - mApplicationText.setLayoutData(gdApplicationText); - mApplicationText.addModifyListener(this); - mApplicationText.addFocusListener(this); - mApplicationDec = createFieldDecoration(mApplicationText, - "The application name is shown in the Play Store, as well as in the " + - "Manage Application list in Settings."); - - Label projectLabel = new Label(container, SWT.NONE); - projectLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); - projectLabel.setText("Project Name:"); - mProjectText = new Text(container, SWT.BORDER); - GridData gdProjectText = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1); - gdProjectText.widthHint = FIELD_WIDTH; - mProjectText.setLayoutData(gdProjectText); - mProjectText.addModifyListener(this); - mProjectText.addFocusListener(this); - mProjectDec = createFieldDecoration(mProjectText, - "The project name is only used by Eclipse, but must be unique within the " + - "workspace. This can typically be the same as the application name."); - - Label packageLabel = new Label(container, SWT.NONE); - packageLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); - packageLabel.setText("Package Name:"); - - mPackageText = new Text(container, SWT.BORDER); - GridData gdPackageText = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1); - gdPackageText.widthHint = FIELD_WIDTH; - mPackageText.setLayoutData(gdPackageText); - mPackageText.addModifyListener(this); - mPackageText.addFocusListener(this); - mPackageDec = createFieldDecoration(mPackageText, - "The package name must be a unique identifier for your application.\n" + - "It is typically not shown to users, but it *must* stay the same " + - "for the lifetime of your application; it is how multiple versions " + - "of the same application are considered the \"same app\".\nThis is " + - "typically the reverse domain name of your organization plus one or " + - "more application identifiers, and it must be a valid Java package " + - "name."); - new Label(container, SWT.NONE); - - new Label(container, SWT.NONE); - new Label(container, SWT.NONE); - new Label(container, SWT.NONE); - - // Min SDK - - Label minSdkLabel = new Label(container, SWT.NONE); - minSdkLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); - minSdkLabel.setText("Minimum Required SDK:"); - - mMinSdkCombo = new Combo(container, SWT.READ_ONLY); - GridData gdMinSdkCombo = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); - gdMinSdkCombo.widthHint = FIELD_WIDTH; - mMinSdkCombo.setLayoutData(gdMinSdkCombo); - - // Pick most recent platform - IAndroidTarget[] targets = getCompilationTargets(); - mMinNameToApi = Maps.newHashMap(); - List<String> targetLabels = new ArrayList<String>(targets.length); - for (IAndroidTarget target : targets) { - String targetLabel; - if (target.isPlatform() - && target.getVersion().getApiLevel() <= AdtUtils.getHighestKnownApiLevel()) { - targetLabel = AdtUtils.getAndroidName(target.getVersion().getApiLevel()); - } else { - targetLabel = AdtUtils.getTargetLabel(target); - } - targetLabels.add(targetLabel); - mMinNameToApi.put(targetLabel, target.getVersion().getApiLevel()); - } - - List<String> codeNames = Lists.newArrayList(); - int buildTargetIndex = -1; - for (int i = 0, n = targets.length; i < n; i++) { - IAndroidTarget target = targets[i]; - AndroidVersion version = target.getVersion(); - int apiLevel = version.getApiLevel(); - if (version.isPreview()) { - String codeName = version.getCodename(); - String targetLabel = codeName + " Preview"; - codeNames.add(targetLabel); - mMinNameToApi.put(targetLabel, apiLevel); - } else if (target.isPlatform() - && (mValues.target == null || - apiLevel > mValues.target.getVersion().getApiLevel())) { - mValues.target = target; - buildTargetIndex = i; - } - } - List<String> labels = new ArrayList<String>(24); - for (String label : AdtUtils.getKnownVersions()) { - labels.add(label); - } - assert labels.size() >= 15; // *Known* versions to ADT, not installed/available versions - for (String codeName : codeNames) { - labels.add(codeName); - } - String[] versions = labels.toArray(new String[labels.size()]); - mMinSdkCombo.setItems(versions); - if (mValues.target != null && mValues.target.getVersion().isPreview()) { - mValues.minSdk = mValues.target.getVersion().getCodename(); - mMinSdkCombo.setText(mValues.minSdk); - mValues.iconState.minSdk = mValues.target.getVersion().getApiLevel(); - mValues.minSdkLevel = mValues.iconState.minSdk; - } else { - mMinSdkCombo.select(INITIAL_MIN_SDK - 1); - mValues.minSdk = Integer.toString(INITIAL_MIN_SDK); - mValues.minSdkLevel = INITIAL_MIN_SDK; - mValues.iconState.minSdk = INITIAL_MIN_SDK; - } - mMinSdkCombo.addSelectionListener(this); - mMinSdkCombo.addFocusListener(this); - mMinSdkDec = createFieldDecoration(mMinSdkCombo, - "Choose the lowest version of Android that your application will support. Lower " + - "API levels target more devices, but means fewer features are available. By " + - "targeting API 8 and later, you reach approximately 95% of the market."); - new Label(container, SWT.NONE); - - // Target SDK - Label targetSdkLabel = new Label(container, SWT.NONE); - targetSdkLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); - targetSdkLabel.setText("Target SDK:"); - - mTargetSdkCombo = new Combo(container, SWT.READ_ONLY); - GridData gdTargetSdkCombo = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); - gdTargetSdkCombo.widthHint = FIELD_WIDTH; - mTargetSdkCombo.setLayoutData(gdTargetSdkCombo); - - mTargetSdkCombo.setItems(versions); - mTargetSdkCombo.select(mValues.targetSdkLevel - 1); - - mTargetSdkCombo.addSelectionListener(this); - mTargetSdkCombo.addFocusListener(this); - mTargetSdkDec = createFieldDecoration(mTargetSdkCombo, - "Choose the highest API level that the application is known to work with. " + - "This attribute informs the system that you have tested against the target " + - "version and the system should not enable any compatibility behaviors to " + - "maintain your app's forward-compatibility with the target version. " + - "The application is still able to run on older versions " + - "(down to minSdkVersion). Your application may look dated if you are not " + - "targeting the current version."); - new Label(container, SWT.NONE); - - // Build Version - - Label buildSdkLabel = new Label(container, SWT.NONE); - buildSdkLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); - buildSdkLabel.setText("Compile With:"); - - mBuildSdkCombo = new Combo(container, SWT.READ_ONLY); - GridData gdBuildSdkCombo = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); - gdBuildSdkCombo.widthHint = FIELD_WIDTH; - mBuildSdkCombo.setLayoutData(gdBuildSdkCombo); - mBuildSdkCombo.setData(targets); - mBuildSdkCombo.setItems(targetLabels.toArray(new String[targetLabels.size()])); - if (buildTargetIndex != -1) { - mBuildSdkCombo.select(buildTargetIndex); - } - - mBuildSdkCombo.addSelectionListener(this); - mBuildSdkCombo.addFocusListener(this); - mBuildTargetDec = createFieldDecoration(mBuildSdkCombo, - "Choose a target API to compile your code against, from your installed SDKs. " + - "This is typically the most recent version, or the first version that supports " + - "all the APIs you want to directly access without reflection."); - new Label(container, SWT.NONE); - - TemplateMetadata metadata = mValues.template.getTemplate(); - if (metadata != null) { - mThemeParameter = metadata.getParameter("baseTheme"); //$NON-NLS-1$ - if (mThemeParameter != null && mThemeParameter.element != null) { - Label themeLabel = new Label(container, SWT.NONE); - themeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); - themeLabel.setText("Theme:"); - - mThemeCombo = NewTemplatePage.createOptionCombo(mThemeParameter, container, - mValues.parameters, this, this); - GridData gdThemeCombo = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); - gdThemeCombo.widthHint = FIELD_WIDTH; - mThemeCombo.setLayoutData(gdThemeCombo); - new Label(container, SWT.NONE); - - mThemeDec = createFieldDecoration(mThemeCombo, - "Choose the base theme to use for the application"); - } - } - - new Label(container, SWT.NONE); - new Label(container, SWT.NONE); - new Label(container, SWT.NONE); - new Label(container, SWT.NONE); - - Label label = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL); - label.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 4, 1)); - - mHelpIcon = new Label(container, SWT.NONE); - mHelpIcon.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false, 1, 1)); - Image icon = IconFactory.getInstance().getIcon("quickfix"); - mHelpIcon.setImage(icon); - mHelpIcon.setVisible(false); - - mTipLabel = new Label(container, SWT.WRAP); - mTipLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); - - // Reserve space for 4 lines - mTipLabel.setText("\n\n\n\n"); //$NON-NLS-1$ - - // Reserve enough width to accommodate the various wizard pages up front - // (since they are created lazily, and we don't want the wizard to dynamically - // resize itself for small size adjustments as each successive page is slightly - // larger) - Label dummy = new Label(container, SWT.NONE); - GridData data = new GridData(); - data.horizontalSpan = 4; - data.widthHint = WIZARD_PAGE_WIDTH; - dummy.setLayoutData(data); - } - - /** - * Updates the theme selection such that it's valid for the current build - * and min sdk targets. Also runs {@link #validatePage} in case no valid entry was found. - * Does nothing if called on a template that does not supply a theme. - */ - void updateTheme() { - if (mThemeParameter != null) { - // Pick the highest theme version that works for the current SDK level - Parameter parameter = NewTemplatePage.getParameter(mThemeCombo); - assert parameter == mThemeParameter; - if (parameter != null) { - String[] optionIds = (String[]) mThemeCombo.getData(ATTR_ID); - for (int index = optionIds.length - 1; index >= 0; index--) { - IStatus status = NewTemplatePage.validateCombo(null, mThemeParameter, - index, mValues.minSdkLevel, mValues.getBuildApi()); - if (status == null || status.isOK()) { - String optionId = optionIds[index]; - parameter.value = optionId; - parameter.edited = optionId != null && !optionId.toString().isEmpty(); - mValues.parameters.put(parameter.id, optionId); - try { - mIgnore = true; - mThemeCombo.select(index); - } finally { - mIgnore = false; - } - break; - } - } - } - - validatePage(); - } - } - - private IAndroidTarget[] getCompilationTargets() { - Sdk current = Sdk.getCurrent(); - if (current == null) { - return new IAndroidTarget[0]; - } - IAndroidTarget[] targets = current.getTargets(); - List<IAndroidTarget> list = new ArrayList<IAndroidTarget>(); - - for (IAndroidTarget target : targets) { - if (target.isPlatform() == false && - (target.getOptionalLibraries() == null || - target.getOptionalLibraries().length == 0)) { - continue; - } - list.add(target); - } - - return list.toArray(new IAndroidTarget[list.size()]); - } - - private ControlDecoration createFieldDecoration(Control control, String description) { - ControlDecoration dec = new ControlDecoration(control, SWT.LEFT); - dec.setMarginWidth(2); - FieldDecoration errorFieldIndicator = FieldDecorationRegistry.getDefault(). - getFieldDecoration(FieldDecorationRegistry.DEC_INFORMATION); - dec.setImage(errorFieldIndicator.getImage()); - dec.setDescriptionText(description); - control.setToolTipText(description); - - return dec; - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - - // DURING DEVELOPMENT ONLY - //if (assertionsEnabled()) { - // String uniqueProjectName = AdtUtils.getUniqueProjectName("Test", ""); - // mProjectText.setText(uniqueProjectName); - // mPackageText.setText("test.pkg"); - //} - - validatePage(); - } - - // ---- Implements ModifyListener ---- - - @Override - public void modifyText(ModifyEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source == mProjectText) { - mValues.projectName = mProjectText.getText(); - updateProjectLocation(mValues.projectName); - mValues.projectModified = true; - - try { - mIgnore = true; - if (!mValues.applicationModified) { - mValues.applicationName = mValues.projectName; - mApplicationText.setText(mValues.projectName); - } - updateActivityNames(mValues.projectName); - } finally { - mIgnore = false; - } - suggestPackage(mValues.projectName); - } else if (source == mPackageText) { - mValues.packageName = mPackageText.getText(); - mValues.packageModified = true; - } else if (source == mApplicationText) { - mValues.applicationName = mApplicationText.getText(); - mValues.applicationModified = true; - - try { - mIgnore = true; - if (!mValues.projectModified) { - mValues.projectName = appNameToProjectName(mValues.applicationName); - mProjectText.setText(mValues.projectName); - updateProjectLocation(mValues.projectName); - } - updateActivityNames(mValues.applicationName); - } finally { - mIgnore = false; - } - suggestPackage(mValues.applicationName); - } - - validatePage(); - } - - private String appNameToProjectName(String appName) { - // Strip out whitespace (and capitalize subsequent words where spaces were removed - boolean upcaseNext = false; - StringBuilder sb = new StringBuilder(appName.length()); - for (int i = 0, n = appName.length(); i < n; i++) { - char c = appName.charAt(i); - if (c == ' ') { - upcaseNext = true; - } else if (upcaseNext) { - sb.append(Character.toUpperCase(c)); - upcaseNext = false; - } else { - sb.append(c); - } - } - - appName = sb.toString().trim(); - - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IStatus nameStatus = workspace.validateName(appName, IResource.PROJECT); - if (nameStatus.isOK()) { - return appName; - } - - sb = new StringBuilder(appName.length()); - for (int i = 0, n = appName.length(); i < n; i++) { - char c = appName.charAt(i); - if (Character.isLetterOrDigit(c) || c == '.' || c == '-') { - sb.append(c); - } - } - - return sb.toString().trim(); - } - - /** If the project should be created in the workspace, then update the project location - * based on the project name. */ - private void updateProjectLocation(String projectName) { - if (projectName == null) { - projectName = ""; - } - - if (mValues.useDefaultLocation) { - IPath workspace = Platform.getLocation(); - String projectLocation = workspace.append(projectName).toOSString(); - mValues.projectLocation = projectLocation; - } - } - - private void updateActivityNames(String name) { - try { - mIgnore = true; - if (!mValues.activityNameModified) { - mValues.activityName = extractClassName(name) + ACTIVITY_NAME_SUFFIX; - } - if (!mValues.activityTitleModified) { - mValues.activityTitle = name; - } - } finally { - mIgnore = false; - } - } - - // ---- Implements SelectionListener ---- - - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source == mMinSdkCombo) { - mValues.minSdk = getSelectedMinSdk(); - Integer minSdk = mMinNameToApi.get(mValues.minSdk); - if (minSdk == null) { - try { - minSdk = Integer.parseInt(mValues.minSdk); - } catch (NumberFormatException nufe) { - // If not a number, then the string is a codename, so treat it - // as a preview version. - minSdk = SdkVersionInfo.HIGHEST_KNOWN_API + 1; - } - } - mValues.iconState.minSdk = minSdk.intValue(); - mValues.minSdkLevel = minSdk.intValue(); - - // If higher than build target, adjust build target - if (mValues.minSdkLevel > mValues.getBuildApi()) { - // Try to find a build target with an adequate build API - IAndroidTarget[] targets = (IAndroidTarget[]) mBuildSdkCombo.getData(); - IAndroidTarget best = null; - int bestApi = Integer.MAX_VALUE; - int bestTargetIndex = -1; - for (int i = 0; i < targets.length; i++) { - IAndroidTarget target = targets[i]; - if (!target.isPlatform()) { - continue; - } - int api = target.getVersion().getApiLevel(); - if (api >= mValues.minSdkLevel && api < bestApi) { - best = target; - bestApi = api; - bestTargetIndex = i; - } - } - - if (best != null) { - assert bestTargetIndex != -1; - mValues.target = best; - try { - mIgnore = true; - mBuildSdkCombo.select(bestTargetIndex); - } finally { - mIgnore = false; - } - } - } - - // If higher than targetSdkVersion, adjust targetSdkVersion - if (mValues.minSdkLevel > mValues.targetSdkLevel) { - mValues.targetSdkLevel = mValues.minSdkLevel; - try { - mIgnore = true; - setSelectedTargetSdk(mValues.targetSdkLevel); - } finally { - mIgnore = false; - } - } - } else if (source == mBuildSdkCombo) { - mValues.target = getSelectedBuildTarget(); - - // If lower than min sdk target, adjust min sdk target - if (mValues.target.getVersion().isPreview()) { - mValues.minSdk = mValues.target.getVersion().getCodename(); - try { - mIgnore = true; - mMinSdkCombo.setText(mValues.minSdk); - } finally { - mIgnore = false; - } - } else { - String minSdk = mValues.minSdk; - int buildApiLevel = mValues.target.getVersion().getApiLevel(); - if (minSdk != null && !minSdk.isEmpty() - && Character.isDigit(minSdk.charAt(0)) - && buildApiLevel < Integer.parseInt(minSdk)) { - mValues.minSdk = Integer.toString(buildApiLevel); - try { - mIgnore = true; - setSelectedMinSdk(buildApiLevel); - } finally { - mIgnore = false; - } - } - } - } else if (source == mTargetSdkCombo) { - mValues.targetSdkLevel = getSelectedTargetSdk(); - } - - validatePage(); - } - - private String getSelectedMinSdk() { - // If you're using a preview build, such as android-JellyBean, you have - // to use the codename, e.g. JellyBean, as the minimum SDK as well. - IAndroidTarget buildTarget = getSelectedBuildTarget(); - if (buildTarget != null && buildTarget.getVersion().isPreview()) { - return buildTarget.getVersion().getCodename(); - } - - // +1: First API level (at index 0) is 1 - return Integer.toString(mMinSdkCombo.getSelectionIndex() + 1); - } - - private int getSelectedTargetSdk() { - // +1: First API level (at index 0) is 1 - return mTargetSdkCombo.getSelectionIndex() + 1; - } - - private void setSelectedMinSdk(int api) { - mMinSdkCombo.select(api - 1); // -1: First API level (at index 0) is 1 - } - - private void setSelectedTargetSdk(int api) { - mTargetSdkCombo.select(api - 1); // -1: First API level (at index 0) is 1 - } - - @Nullable - private IAndroidTarget getSelectedBuildTarget() { - IAndroidTarget[] targets = (IAndroidTarget[]) mBuildSdkCombo.getData(); - int index = mBuildSdkCombo.getSelectionIndex(); - if (index >= 0 && index < targets.length) { - return targets[index]; - } else { - return null; - } - } - - private void suggestPackage(String original) { - if (!mValues.packageModified) { - // Create default package name - StringBuilder sb = new StringBuilder(); - sb.append(SAMPLE_PACKAGE_PREFIX); - appendPackage(sb, original); - - String pkg = sb.toString(); - if (pkg.endsWith(".")) { //$NON-NLS-1$ - pkg = pkg.substring(0, pkg.length() - 1); - } - mValues.packageName = pkg; - try { - mIgnore = true; - mPackageText.setText(mValues.packageName); - } finally { - mIgnore = false; - } - } - } - - private static void appendPackage(StringBuilder sb, String string) { - for (int i = 0, n = string.length(); i < n; i++) { - char c = string.charAt(i); - if (i == 0 && Character.isJavaIdentifierStart(c) - || i != 0 && Character.isJavaIdentifierPart(c)) { - sb.append(Character.toLowerCase(c)); - } else if ((c == '.') - && (sb.length() > 0 && sb.charAt(sb.length() - 1) != '.')) { - sb.append('.'); - } else if (c == '-') { - sb.append('_'); - } - } - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - // ---- Implements FocusListener ---- - - @Override - public void focusGained(FocusEvent e) { - Object source = e.getSource(); - String tip = ""; - if (source == mApplicationText) { - tip = mApplicationDec.getDescriptionText(); - } else if (source == mProjectText) { - tip = mProjectDec.getDescriptionText(); - } else if (source == mBuildSdkCombo) { - tip = mBuildTargetDec.getDescriptionText(); - } else if (source == mMinSdkCombo) { - tip = mMinSdkDec.getDescriptionText(); - } else if (source == mPackageText) { - tip = mPackageDec.getDescriptionText(); - if (mPackageText.getText().startsWith(SAMPLE_PACKAGE_PREFIX)) { - int length = SAMPLE_PACKAGE_PREFIX.length(); - if (mPackageText.getText().length() > length - && SAMPLE_PACKAGE_PREFIX.endsWith(".")) { //$NON-NLS-1$ - length--; - } - mPackageText.setSelection(0, length); - } - } else if (source == mTargetSdkCombo) { - tip = mTargetSdkDec.getDescriptionText(); - } else if (source == mThemeCombo) { - tip = mThemeDec.getDescriptionText(); - } - mTipLabel.setText(tip); - mHelpIcon.setVisible(tip.length() > 0); - } - - @Override - public void focusLost(FocusEvent e) { - mTipLabel.setText(""); - mHelpIcon.setVisible(false); - } - - // Validation - - private void validatePage() { - IStatus status = mValues.template.validateTemplate(mValues.minSdkLevel, - mValues.getBuildApi()); - if (status != null && !status.isOK()) { - updateDecorator(mApplicationDec, null, true); - updateDecorator(mPackageDec, null, true); - updateDecorator(mProjectDec, null, true); - updateDecorator(mThemeDec, null, true); - /* These never get marked with errors: - updateDecorator(mBuildTargetDec, null, true); - updateDecorator(mMinSdkDec, null, true); - updateDecorator(mTargetSdkDec, null, true); - */ - } else { - IStatus appStatus = validateAppName(); - if (appStatus != null && (status == null - || appStatus.getSeverity() > status.getSeverity())) { - status = appStatus; - } - - IStatus projectStatus = validateProjectName(); - if (projectStatus != null && (status == null - || projectStatus.getSeverity() > status.getSeverity())) { - status = projectStatus; - } - - IStatus packageStatus = validatePackageName(); - if (packageStatus != null && (status == null - || packageStatus.getSeverity() > status.getSeverity())) { - status = packageStatus; - } - - IStatus locationStatus = ProjectContentsPage.validateLocationInWorkspace(mValues); - if (locationStatus != null && (status == null - || locationStatus.getSeverity() > status.getSeverity())) { - status = locationStatus; - } - - if (status == null || status.getSeverity() != IStatus.ERROR) { - if (mValues.target == null) { - status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, - "Select an Android build target version"); - } - } - - if (status == null || status.getSeverity() != IStatus.ERROR) { - if (mValues.minSdk == null || mValues.minSdk.isEmpty()) { - status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, - "Select a minimum SDK version"); - } else { - AndroidVersion version = mValues.target.getVersion(); - if (version.isPreview()) { - if (version.getCodename().equals(mValues.minSdk) == false) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Preview platforms require the min SDK version to match their codenames."); - } - } else if (mValues.target.getVersion().compareTo( - mValues.minSdkLevel, - version.isPreview() ? mValues.minSdk : null) < 0) { - status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, - "The minimum SDK version is higher than the build target version"); - } - if (status == null || status.getSeverity() != IStatus.ERROR) { - if (mValues.targetSdkLevel < mValues.minSdkLevel) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "The target SDK version should be at least as high as the minimum SDK version"); - } - } - } - } - - IStatus themeStatus = validateTheme(); - if (themeStatus != null && (status == null - || themeStatus.getSeverity() > status.getSeverity())) { - status = themeStatus; - } - } - - setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); - if (status != null) { - setMessage(status.getMessage(), - status.getSeverity() == IStatus.ERROR - ? IMessageProvider.ERROR : IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - private IStatus validateAppName() { - String appName = mValues.applicationName; - IStatus status = null; - if (appName == null || appName.isEmpty()) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Enter an application name (shown in launcher)"); - } else if (Character.isLowerCase(mValues.applicationName.charAt(0))) { - status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, - "The application name for most apps begins with an uppercase letter"); - } - - updateDecorator(mApplicationDec, status, true); - - return status; - } - - private IStatus validateProjectName() { - IStatus status = ProjectNamePage.validateProjectName(mValues.projectName); - updateDecorator(mProjectDec, status, true); - - return status; - } - - private IStatus validatePackageName() { - IStatus status; - if (mValues.packageName == null || mValues.packageName.startsWith(SAMPLE_PACKAGE_PREFIX)) { - if (mValues.packageName != null - && !mValues.packageName.equals(SAMPLE_PACKAGE_PREFIX)) { - status = ApplicationInfoPage.validatePackage(mValues.packageName); - if (status == null || status.isOK()) { - status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, - String.format("The prefix '%1$s' is meant as a placeholder and should " + - "not be used", SAMPLE_PACKAGE_PREFIX)); - } - } else { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Package name must be specified."); - } - } else { - status = ApplicationInfoPage.validatePackage(mValues.packageName); - } - - updateDecorator(mPackageDec, status, true); - - return status; - } - - private IStatus validateTheme() { - IStatus status = null; - - if (mThemeParameter != null) { - status = NewTemplatePage.validateCombo(null, mThemeParameter, - mThemeCombo.getSelectionIndex(), mValues.minSdkLevel, - mValues.getBuildApi()); - - updateDecorator(mThemeDec, status, true); - } - - return status; - } - - private void updateDecorator(ControlDecoration decorator, IStatus status, boolean hasInfo) { - if (hasInfo) { - int severity = status != null ? status.getSeverity() : IStatus.OK; - setDecoratorType(decorator, severity); - } else { - if (status == null || status.isOK()) { - decorator.hide(); - } else { - decorator.show(); - } - } - } - - private void setDecoratorType(ControlDecoration decorator, int severity) { - String id; - if (severity == IStatus.ERROR) { - id = FieldDecorationRegistry.DEC_ERROR; - } else if (severity == IStatus.WARNING) { - id = FieldDecorationRegistry.DEC_WARNING; - } else { - id = FieldDecorationRegistry.DEC_INFORMATION; - } - FieldDecoration errorFieldIndicator = FieldDecorationRegistry.getDefault(). - getFieldDecoration(id); - decorator.setImage(errorFieldIndicator.getImage()); - } -} 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 deleted file mode 100644 index d350a00dd..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java +++ /dev/null @@ -1,456 +0,0 @@ -/* - * 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.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.VisibleForTesting; -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.actions.AddSupportJarAction; -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.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectHelper; -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreator; -import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreator.ProjectPopulator; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.ltk.core.refactoring.Change; -import org.eclipse.ltk.core.refactoring.CompositeChange; -import org.eclipse.swt.graphics.RGB; -import org.eclipse.ui.IWorkbench; - -import java.io.File; -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Wizard for creating new projects - */ -public class NewProjectWizard extends TemplateWizard { - private static final String PARENT_ACTIVITY_CLASS = "parentActivityClass"; //$NON-NLS-1$ - private static final String ACTIVITY_TITLE = "activityTitle"; //$NON-NLS-1$ - static final String IS_LAUNCHER = "isLauncher"; //$NON-NLS-1$ - static final String IS_NEW_PROJECT = "isNewProject"; //$NON-NLS-1$ - static final String IS_LIBRARY_PROJECT = "isLibraryProject"; //$NON-NLS-1$ - 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_BUILD_API = "minBuildApi"; //$NON-NLS-1$ - static final String ATTR_BUILD_API = "buildApi"; //$NON-NLS-1$ - static final String ATTR_REVISION = "revision"; //$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$ - static final String CATEGORY_PROJECTS = "projects"; //$NON-NLS-1$ - static final String CATEGORY_ACTIVITIES = "activities"; //$NON-NLS-1$ - static final String CATEGORY_OTHER = "other"; //$NON-NLS-1$ - static final String ATTR_APP_COMPAT = "appCompat"; //$NON-NLS-1$ - /** - * Reserved file name for the launcher icon, resolves to the xhdpi version - * - * @see CreateAssetSetWizardState#getImage - */ - public static final String DEFAULT_LAUNCHER_ICON = "launcher_icon"; //$NON-NLS-1$ - - private NewProjectPage mMainPage; - private ProjectContentsPage mContentsPage; - private ActivityPage mActivityPage; - private NewTemplatePage mTemplatePage; - private NewProjectWizardState mValues; - /** The project being created */ - private IProject mProject; - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - super.init(workbench, selection); - - setWindowTitle("New Android Application"); - - mValues = new NewProjectWizardState(); - mMainPage = new NewProjectPage(mValues); - mContentsPage = new ProjectContentsPage(mValues); - mContentsPage.init(selection, AdtUtils.getActivePart()); - mActivityPage = new ActivityPage(mValues, true, true); - mActivityPage.setLauncherActivitiesOnly(true); - } - - @Override - public void addPages() { - super.addPages(); - addPage(mMainPage); - addPage(mContentsPage); - addPage(mActivityPage); - } - - @Override - public IWizardPage getNextPage(IWizardPage page) { - if (page == mMainPage) { - return mContentsPage; - } - - if (page == mContentsPage) { - if (mValues.createIcon) { - // Bundle asset studio wizard to create the launcher icon - CreateAssetSetWizardState iconState = mValues.iconState; - iconState.type = AssetType.LAUNCHER; - iconState.outputName = "ic_launcher"; //$NON-NLS-1$ - iconState.background = new RGB(0xff, 0xff, 0xff); - iconState.foreground = new RGB(0x33, 0xb6, 0xea); - iconState.trim = true; - - // ADT 20: White icon with blue shape - //iconState.shape = GraphicGenerator.Shape.CIRCLE; - //iconState.sourceType = CreateAssetSetWizardState.SourceType.CLIPART; - //iconState.clipartName = "user.png"; //$NON-NLS-1$ - //iconState.padding = 10; - - // ADT 21: Use the platform packaging icon, but allow user to customize it - iconState.sourceType = CreateAssetSetWizardState.SourceType.IMAGE; - iconState.imagePath = new File(DEFAULT_LAUNCHER_ICON); - iconState.shape = GraphicGenerator.Shape.NONE; - iconState.padding = 0; - - WizardPage p = getIconPage(mValues.iconState); - p.setTitle("Configure Launcher Icon"); - return p; - } else { - if (mValues.createActivity) { - return mActivityPage; - } else { - return null; - } - } - } - - if (page == mIconPage) { - return mActivityPage; - } - - if (page == mActivityPage && mValues.createActivity) { - if (mTemplatePage == null) { - NewTemplateWizardState activityValues = mValues.activityValues; - - // Initialize the *default* activity name based on what we've derived - // from the project name - activityValues.defaults.put("activityName", mValues.activityName); - - // Hide those parameters that the template requires but that we don't want to - // ask the users about, since we will supply these values from the rest - // of the new project wizard. - Set<String> hidden = activityValues.hidden; - hidden.add(ATTR_PACKAGE_NAME); - hidden.add(ATTR_APP_TITLE); - hidden.add(ATTR_MIN_API); - hidden.add(ATTR_MIN_API_LEVEL); - hidden.add(ATTR_TARGET_API); - hidden.add(ATTR_BUILD_API); - hidden.add(IS_LAUNCHER); - // Don't ask about hierarchical parent activities in new projects where there - // can't possibly be any - hidden.add(PARENT_ACTIVITY_CLASS); - hidden.add(ACTIVITY_TITLE); // Not used for the first activity in the project - - mTemplatePage = new NewTemplatePage(activityValues, false); - addPage(mTemplatePage); - } - mTemplatePage.setCustomMinSdk(mValues.minSdkLevel, mValues.getBuildApi()); - return mTemplatePage; - } - - if (page == mTemplatePage) { - TemplateMetadata template = mValues.activityValues.getTemplateHandler().getTemplate(); - if (template != null - && !InstallDependencyPage.isInstalled(template.getDependencies())) { - return getDependencyPage(template, true); - } - } - - if (page == mTemplatePage || !mValues.createActivity && page == mActivityPage - || page == getDependencyPage(null, false)) { - return null; - } - - return super.getNextPage(page); - } - - @Override - public boolean canFinish() { - // Deal with lazy creation of some pages: these may not be in the page-list yet - // since they are constructed lazily, so consider that option here. - if (mValues.createIcon && (mIconPage == null || !mIconPage.isPageComplete())) { - return false; - } - if (mValues.createActivity && (mTemplatePage == null || !mTemplatePage.isPageComplete())) { - return false; - } - - // Override super behavior (which just calls isPageComplete() on each of the pages) - // to special case the template and icon pages since we want to skip them if - // the appropriate flags are not set. - for (IWizardPage page : getPages()) { - if (page == mTemplatePage && !mValues.createActivity) { - continue; - } - if (page == mIconPage && !mValues.createIcon) { - continue; - } - if (!page.isPageComplete()) { - return false; - } - } - - return true; - } - - @Override - @NonNull - protected IProject getProject() { - return mProject; - } - - @Override - @NonNull - protected List<String> getFilesToOpen() { - return mValues.template.getFilesToOpen(); - } - - @VisibleForTesting - NewProjectWizardState getValues() { - return mValues; - } - - @VisibleForTesting - void setValues(NewProjectWizardState values) { - mValues = values; - } - - @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); - TemplateHandler.addDirectoryParameters(paramMap, getProject()); - // We don't know at this point whether the activity is going to need - // AppCompat so we just assume that it will. - if (mValues.createActivity && mValues.minSdkLevel < 14) { - paramMap.put(ATTR_APP_COMPAT, true); - getFinalizingActions().add(new Runnable() { - @Override - public void run() { - AddSupportJarAction.installAppCompatLibrary(mProject, true); - } - }); - } - - return template.render(mProject, paramMap); - } - - @Override - protected boolean performFinish(final IProgressMonitor monitor) - throws InvocationTargetException { - try { - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - String name = mValues.projectName; - mProject = root.getProject(name); - - 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. - template.setBackupMergedFiles(false); - - ProjectPopulator projectPopulator = new ProjectPopulator() { - @Override - 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 == mProject; - NewProjectCreator.addLocalFile(project, - new File(libFolder, SdkConstants.FN_PROJECT_PROGUARD_FILE), - // Write ProGuard config files with the extension .pro which - // is what is used in the ProGuard documentation and samples - SdkConstants.FN_PROJECT_PROGUARD_FILE, - new NullProgressMonitor()); - } catch (Exception e) { - AdtPlugin.log(e, null); - } - - try { - mProject.refreshLocal(DEPTH_INFINITE, new NullProgressMonitor()); - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - - // 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) { // TODO: Set progress - generateIcons(mProject); - } - - // Render the embedded activity template template - if (mValues.createActivity) { - 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); - } - } - }; - - NewProjectCreator.create(monitor, mProject, mValues.target, projectPopulator, - mValues.isLibrary, mValues.projectLocation, mValues.workingSets); - - // For new projects, ensure that we're actually using the preferred compliance, - // not just the default one - IJavaProject javaProject = BaseProjectHelper.getJavaProject(mProject); - if (javaProject != null) { - ProjectHelper.enforcePreferredCompilerCompliance(javaProject); - } - - try { - mProject.refreshLocal(DEPTH_INFINITE, new NullProgressMonitor()); - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - - List<Runnable> finalizingTasks = getFinalizingActions(); - for (Runnable r : finalizingTasks) { - r.run(); - } - - return true; - } catch (Exception ioe) { - AdtPlugin.log(ioe, null); - return false; - } - } - - /** - * Generate custom icons into the project based on the asset studio wizard state - */ - private void generateIcons(final IProject newProject) { - // Generate the custom icons - assert mValues.createIcon; - ConfigureAssetSetPage.generateIcons(newProject, mValues.iconState, false, mIconPage); - } - - /** - * Generate the activity: Pre-populate information about the project the - * activity needs but that we don't need to ask about when creating a new - * project - */ - private void generateActivity(TemplateHandler projectTemplate, IProject project, - IProgressMonitor monitor) throws InvocationTargetException { - assert mValues.createActivity; - NewTemplateWizardState activityValues = mValues.activityValues; - Map<String, Object> parameters = activityValues.parameters; - - addProjectInfo(parameters); - - parameters.put(IS_NEW_PROJECT, true); - parameters.put(IS_LIBRARY_PROJECT, mValues.isLibrary); - // Ensure that activities created as part of a new project are marked as - // launcher activities - parameters.put(IS_LAUNCHER, true); - TemplateHandler.addDirectoryParameters(parameters, project); - - TemplateHandler activityTemplate = activityValues.getTemplateHandler(); - activityTemplate.setBackupMergedFiles(false); - 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(); - projectTemplate.getFilesToOpen().addAll(filesToOpen); - - List<Runnable> finalizingActions = activityTemplate.getFinalizingActions(); - projectTemplate.getFinalizingActions().addAll(finalizingActions); - } - - 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, mValues.targetSdkLevel); - parameters.put(ATTR_BUILD_API, mValues.target.getVersion().getApiLevel()); - parameters.put(ATTR_COPY_ICONS, !mValues.createIcon); - parameters.putAll(mValues.parameters); - } - - @Override - @NonNull - protected List<Runnable> getFinalizingActions() { - return mValues.template.getFinalizingActions(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizardState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizardState.java deleted file mode 100644 index 9cd3a6dcf..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizardState.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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 com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.CATEGORY_PROJECTS; - -import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.ui.IWorkingSet; - -import java.util.HashMap; -import java.util.Map; - -/** - * Value object which holds the current state of the wizard pages for the - * {@link NewProjectWizard} - */ -public class NewProjectWizardState { - /** Creates a new {@link NewProjectWizardState} */ - public NewProjectWizardState() { - template = TemplateHandler.createFromName(CATEGORY_PROJECTS, - "NewAndroidApplication"); //$NON-NLS-1$ - } - - /** The template handler instantiating the project */ - public final TemplateHandler template; - - /** The name of the project */ - public String projectName; - - /** The derived name of the activity, if any */ - public String activityName; - - /** The derived title of the activity, if any */ - public String activityTitle; - - /** The application name */ - public String applicationName; - - /** The package name */ - public String packageName; - - /** Whether the project name has been edited by the user */ - public boolean projectModified; - - /** Whether the package name has been edited by the user */ - public boolean packageModified; - - /** Whether the activity name has been edited by the user */ - public boolean activityNameModified; - - /** Whether the activity title has been edited by the user */ - public boolean activityTitleModified; - - /** Whether the application name has been edited by the user */ - public boolean applicationModified; - - /** The compilation target to use for this project */ - public IAndroidTarget target; - - /** The minimum SDK API level, as a string (if the API is a preview release with a codename) */ - public String minSdk; - - /** The minimum SDK API level to use */ - public int minSdkLevel; - - /** The target SDK level */ - public int targetSdkLevel = AdtUtils.getHighestKnownApiLevel(); - - /** Whether this project should be marked as a library project */ - public boolean isLibrary; - - /** Whether to create an activity (if so, the activity state is stored in - * {@link #activityValues}) */ - public boolean createActivity = true; - - /** Whether a custom icon should be created instead of just reusing the default (if so, - * the icon wizard state is stored in {@link #iconState}) */ - public boolean createIcon = true; - - // Delegated wizards - - /** State for the asset studio wizard, used to create custom icons */ - public CreateAssetSetWizardState iconState = new CreateAssetSetWizardState(); - - /** State for the template wizard, used to embed an activity template */ - public NewTemplateWizardState activityValues = new NewTemplateWizardState(); - - /** Whether a custom location should be used */ - public boolean useDefaultLocation = true; - - /** Folder where the project should be created. */ - public String projectLocation; - - /** Configured parameters, by id */ - public final Map<String, Object> parameters = new HashMap<String, Object>(); - - /** The set of chosen working sets to use when creating the project */ - public IWorkingSet[] workingSets = new IWorkingSet[0]; - - /** - * Returns the build target API level - * - * @return the build target API level - */ - public int getBuildApi() { - return target != null ? target.getVersion().getApiLevel() : minSdkLevel; - } -} 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 deleted file mode 100644 index 57cf5c824..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java +++ /dev/null @@ -1,946 +0,0 @@ -/* - * 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 com.android.SdkConstants.CLASS_ACTIVITY; -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_BUILD_API; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_DEFAULT; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_ID; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_NAME; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_PADDING; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_WIDTH; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.editors.IconFactory; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper; -import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.ProjectCombo; -import com.android.ide.eclipse.adt.internal.wizards.templates.Parameter.Constraint; -import com.android.ide.eclipse.adt.internal.wizards.templates.Parameter.Type; -import com.android.tools.lint.detector.api.LintUtils; -import com.google.common.collect.Lists; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.core.Flags; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.search.IJavaSearchScope; -import org.eclipse.jdt.core.search.SearchEngine; -import org.eclipse.jdt.ui.IJavaElementSearchConstants; -import org.eclipse.jdt.ui.JavaUI; -import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension; -import org.eclipse.jdt.ui.dialogs.ITypeInfoRequestor; -import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.IInputValidator; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.dialogs.ProgressMonitorDialog; -import org.eclipse.jface.fieldassist.ControlDecoration; -import org.eclipse.jface.fieldassist.FieldDecoration; -import org.eclipse.jface.fieldassist.FieldDecorationRegistry; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.dialogs.SelectionDialog; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import java.io.ByteArrayInputStream; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * First wizard page in the "New Project From Template" wizard (which is parameterized - * via template.xml files) - */ -public class NewTemplatePage extends WizardPage - implements ModifyListener, SelectionListener, FocusListener { - /** The default width to use for the wizard page */ - static final int WIZARD_PAGE_WIDTH = 600; - - private final NewTemplateWizardState mValues; - private final boolean mChooseProject; - private int mCustomMinSdk = -1; - private int mCustomBuildApi = -1; - private boolean mIgnore; - private boolean mShown; - private Control mFirst; - // TODO: Move decorators to the Parameter objects? - private Map<String, ControlDecoration> mDecorations = new HashMap<String, ControlDecoration>(); - private Label mHelpIcon; - private Label mTipLabel; - private ImageControl mPreview; - private Image mPreviewImage; - private boolean mDisposePreviewImage; - private ProjectCombo mProjectButton; - private StringEvaluator mEvaluator; - - private TemplateMetadata mShowingTemplate; - - /** - * Creates a new {@link NewTemplatePage} - * - * @param values the wizard state - * @param chooseProject whether the wizard should present a project chooser, - * and update {@code values}' project field - */ - NewTemplatePage(NewTemplateWizardState values, boolean chooseProject) { - super("newTemplatePage"); //$NON-NLS-1$ - mValues = values; - mChooseProject = chooseProject; - } - - /** - * @param minSdk a minimum SDK to use, provided chooseProject is false. If - * it is true, then the minimum SDK used for validation will be - * the one of the project - * @param buildApi the build API to use - */ - void setCustomMinSdk(int minSdk, int buildApi) { - assert !mChooseProject; - //assert buildApi >= minSdk; - mCustomMinSdk = minSdk; - mCustomBuildApi = buildApi; - } - - @Override - public void createControl(Composite parent2) { - Composite parent = new Composite(parent2, SWT.NULL); - setControl(parent); - GridLayout parentLayout = new GridLayout(3, false); - parentLayout.verticalSpacing = 0; - parentLayout.marginWidth = 0; - parentLayout.marginHeight = 0; - parentLayout.horizontalSpacing = 0; - parent.setLayout(parentLayout); - - // Reserve enough width (since the panel is created lazily later) - Label label = new Label(parent, SWT.NONE); - GridData data = new GridData(); - data.widthHint = WIZARD_PAGE_WIDTH; - label.setLayoutData(data); - } - - @SuppressWarnings("unused") // SWT constructors have side effects and aren't unused - private void onEnter() { - TemplateMetadata template = mValues.getTemplateHandler().getTemplate(); - if (template == mShowingTemplate) { - return; - } - mShowingTemplate = template; - - Composite parent = (Composite) getControl(); - - Control[] children = parent.getChildren(); - if (children.length > 0) { - for (Control c : parent.getChildren()) { - c.dispose(); - } - for (ControlDecoration decoration : mDecorations.values()) { - decoration.dispose(); - } - mDecorations.clear(); - } - - Composite container = new Composite(parent, SWT.NULL); - container.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); - GridLayout gl_container = new GridLayout(3, false); - gl_container.horizontalSpacing = 10; - container.setLayout(gl_container); - - if (mChooseProject) { - // Project: [button] - String tooltip = "The Android Project where the new resource will be created."; - Label projectLabel = new Label(container, SWT.NONE); - projectLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - projectLabel.setText("Project:"); - projectLabel.setToolTipText(tooltip); - - ProjectChooserHelper helper = - new ProjectChooserHelper(getShell(), null /* filter */); - mProjectButton = new ProjectCombo(helper, container, mValues.project); - mProjectButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); - mProjectButton.setToolTipText(tooltip); - mProjectButton.addSelectionListener(this); - - //Label projectSeparator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL); - //projectSeparator.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1)); - } - - // Add parameters - mFirst = null; - String thumb = null; - if (template != null) { - thumb = template.getThumbnailPath(); - String title = template.getTitle(); - if (title != null && !title.isEmpty()) { - setTitle(title); - } - String description = template.getDescription(); - if (description != null && !description.isEmpty()) { - setDescription(description); - } - - Map<String, String> defaults = mValues.defaults; - Set<String> seen = null; - if (LintUtils.assertionsEnabled()) { - seen = new HashSet<String>(); - } - - List<Parameter> parameters = template.getParameters(); - for (Parameter parameter : parameters) { - Parameter.Type type = parameter.type; - - if (type == Parameter.Type.SEPARATOR) { - Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL); - separator.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1)); - continue; - } - - String id = parameter.id; - assert id != null && !id.isEmpty() : ATTR_ID; - Object value = defaults.get(id); - if (value == null) { - value = parameter.value; - } - - String name = parameter.name; - String help = parameter.help; - - // Required - assert name != null && !name.isEmpty() : ATTR_NAME; - // Ensure id's are unique: - assert seen != null && seen.add(id) : id; - - // Skip attributes that were already provided by the surrounding - // context. For example, when adding into an existing project, - // provide the minimum SDK automatically from the project. - if (mValues.hidden != null && mValues.hidden.contains(id)) { - continue; - } - - switch (type) { - case STRING: { - // TODO: Look at the constraints to add validators here - // TODO: If I type.equals("layout") add resource validator for layout - // names - // TODO: If I type.equals("class") make class validator - - // TODO: Handle package and id better later - Label label = new Label(container, SWT.NONE); - label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, - 1, 1)); - label.setText(name); - - Text text = new Text(container, SWT.BORDER); - text.setData(parameter); - parameter.control = text; - - if (parameter.constraints.contains(Constraint.EXISTS)) { - text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, - 1, 1)); - - Button button = new Button(container, SWT.FLAT); - button.setData(parameter); - button.setText("..."); - button.addSelectionListener(this); - } else { - text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, - 2, 1)); - } - - boolean hasValue = false; - if (value instanceof String) { - String stringValue = (String) value; - hasValue = !stringValue.isEmpty(); - text.setText(stringValue); - mValues.parameters.put(id, value); - } - - if (!hasValue) { - if (parameter.constraints.contains(Constraint.EMPTY)) { - text.setMessage("Optional"); - } else if (parameter.constraints.contains(Constraint.NONEMPTY)) { - text.setMessage("Required"); - } - } - - text.addModifyListener(this); - text.addFocusListener(this); - - if (mFirst == null) { - mFirst = text; - } - - if (help != null && !help.isEmpty()) { - text.setToolTipText(help); - ControlDecoration decoration = createFieldDecoration(id, text, help); - } - break; - } - case BOOLEAN: { - Label label = new Label(container, SWT.NONE); - label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, - 1, 1)); - - Button checkBox = new Button(container, SWT.CHECK); - checkBox.setText(name); - checkBox.setData(parameter); - parameter.control = checkBox; - checkBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, - 2, 1)); - - if (value instanceof Boolean) { - Boolean selected = (Boolean) value; - checkBox.setSelection(selected); - mValues.parameters.put(id, value); - } - - checkBox.addSelectionListener(this); - checkBox.addFocusListener(this); - - if (mFirst == null) { - mFirst = checkBox; - } - - if (help != null && !help.isEmpty()) { - checkBox.setToolTipText(help); - ControlDecoration decoration = createFieldDecoration(id, checkBox, - help); - } - break; - } - case ENUM: { - Label label = new Label(container, SWT.NONE); - label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, - 1, 1)); - label.setText(name); - - Combo combo = createOptionCombo(parameter, container, mValues.parameters, - this, this); - combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, - 2, 1)); - - if (mFirst == null) { - mFirst = combo; - } - - if (help != null && !help.isEmpty()) { - ControlDecoration decoration = createFieldDecoration(id, combo, help); - } - break; - } - case SEPARATOR: - // Already handled above - assert false : type; - break; - default: - assert false : type; - } - } - } - - // Preview - mPreview = new ImageControl(parent, SWT.NONE, null); - mPreview.setDisposeImage(false); // Handled manually in this class - GridData gd_mImage = new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1); - gd_mImage.widthHint = PREVIEW_WIDTH + 2 * PREVIEW_PADDING; - mPreview.setLayoutData(gd_mImage); - - Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); - GridData separatorData = new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1); - separatorData.heightHint = 16; - separator.setLayoutData(separatorData); - - // Generic help - mHelpIcon = new Label(parent, SWT.NONE); - mHelpIcon.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false, 1, 1)); - Image icon = IconFactory.getInstance().getIcon("quickfix"); - mHelpIcon.setImage(icon); - mHelpIcon.setVisible(false); - mTipLabel = new Label(parent, SWT.WRAP); - mTipLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); - - setPreview(thumb); - - parent.layout(true, true); - // TODO: This is a workaround for the fact that (at least on OSX) you end up - // with some visual artifacts from the control decorations in the upper left corner - // (outside the parent widget itself) from the initial control decoration placement - // prior to layout. Therefore, perform a redraw. A better solution would be to - // delay creation of the control decorations until layout has been performed. - // Let's do that soon. - parent.getParent().redraw(); - } - - @NonNull - static Combo createOptionCombo( - @NonNull Parameter parameter, - @NonNull Composite container, - @NonNull Map<String, Object> valueMap, - @NonNull SelectionListener selectionListener, - @NonNull FocusListener focusListener) { - Combo combo = new Combo(container, SWT.READ_ONLY); - - List<Element> options = parameter.getOptions(); - assert options.size() > 0; - int selected = 0; - List<String> ids = Lists.newArrayList(); - List<Integer> minSdks = Lists.newArrayList(); - List<Integer> minBuildApis = Lists.newArrayList(); - List<String> labels = Lists.newArrayList(); - for (int i = 0, n = options.size(); i < n; i++) { - Element option = options.get(i); - String optionId = option.getAttribute(ATTR_ID); - assert optionId != null && !optionId.isEmpty() : ATTR_ID; - String isDefault = option.getAttribute(ATTR_DEFAULT); - if (isDefault != null && !isDefault.isEmpty() && - Boolean.valueOf(isDefault)) { - selected = i; - } - NodeList childNodes = option.getChildNodes(); - assert childNodes.getLength() == 1 && - childNodes.item(0).getNodeType() == Node.TEXT_NODE; - String optionLabel = childNodes.item(0).getNodeValue().trim(); - - String minApiString = option.getAttribute(ATTR_MIN_API); - int minSdk = 1; - if (minApiString != null && !minApiString.isEmpty()) { - try { - minSdk = Integer.parseInt(minApiString); - } catch (NumberFormatException nufe) { - // Templates aren't allowed to contain codenames, should - // always be an integer - AdtPlugin.log(nufe, null); - minSdk = 1; - } - } - String minBuildApiString = option.getAttribute(ATTR_MIN_BUILD_API); - int minBuildApi = 1; - if (minBuildApiString != null && !minBuildApiString.isEmpty()) { - try { - minBuildApi = Integer.parseInt(minBuildApiString); - } catch (NumberFormatException nufe) { - // Templates aren't allowed to contain codenames, should - // always be an integer - AdtPlugin.log(nufe, null); - minBuildApi = 1; - } - } - minSdks.add(minSdk); - minBuildApis.add(minBuildApi); - ids.add(optionId); - labels.add(optionLabel); - } - combo.setData(parameter); - parameter.control = combo; - combo.setData(ATTR_ID, ids.toArray(new String[ids.size()])); - combo.setData(ATTR_MIN_API, minSdks.toArray(new Integer[minSdks.size()])); - combo.setData(ATTR_MIN_BUILD_API, minBuildApis.toArray( - new Integer[minBuildApis.size()])); - assert labels.size() > 0; - combo.setItems(labels.toArray(new String[labels.size()])); - combo.select(selected); - - combo.addSelectionListener(selectionListener); - combo.addFocusListener(focusListener); - - valueMap.put(parameter.id, ids.get(selected)); - - if (parameter.help != null && !parameter.help.isEmpty()) { - combo.setToolTipText(parameter.help); - } - - return combo; - } - - private void setPreview(String thumb) { - Image oldImage = mPreviewImage; - boolean dispose = mDisposePreviewImage; - mPreviewImage = null; - - if (thumb == null || thumb.isEmpty()) { - mPreviewImage = TemplateMetadata.getDefaultTemplateIcon(); - mDisposePreviewImage = false; - } else { - byte[] data = mValues.getTemplateHandler().readTemplateResource(thumb); - if (data != null) { - try { - mPreviewImage = new Image(getControl().getDisplay(), - new ByteArrayInputStream(data)); - mDisposePreviewImage = true; - } catch (Exception e) { - AdtPlugin.log(e, null); - } - } - if (mPreviewImage == null) { - return; - } - } - - mPreview.setImage(mPreviewImage); - mPreview.fitToWidth(PREVIEW_WIDTH); - - if (oldImage != null && dispose) { - oldImage.dispose(); - } - } - - @Override - public void dispose() { - super.dispose(); - - if (mPreviewImage != null && mDisposePreviewImage) { - mDisposePreviewImage = false; - mPreviewImage.dispose(); - mPreviewImage = null; - } - } - - private ControlDecoration createFieldDecoration(String id, Control control, - String description) { - ControlDecoration decoration = new ControlDecoration(control, SWT.LEFT); - decoration.setMarginWidth(2); - FieldDecoration errorFieldIndicator = FieldDecorationRegistry.getDefault(). - getFieldDecoration(FieldDecorationRegistry.DEC_INFORMATION); - decoration.setImage(errorFieldIndicator.getImage()); - decoration.setDescriptionText(description); - control.setToolTipText(description); - mDecorations.put(id, decoration); - - return decoration; - } - - @Override - public boolean isPageComplete() { - // Force user to reach this page before hitting Finish - return mShown && super.isPageComplete(); - } - - @Override - public void setVisible(boolean visible) { - if (visible) { - onEnter(); - } - - super.setVisible(visible); - - if (mFirst != null) { - mFirst.setFocus(); - } - - if (visible) { - mShown = true; - } - - validatePage(); - } - - /** Returns the parameter associated with the given control */ - @Nullable - static Parameter getParameter(Control control) { - return (Parameter) control.getData(); - } - - /** - * Returns the current string evaluator, if any - * - * @return the evaluator or null - */ - @Nullable - public StringEvaluator getEvaluator() { - return mEvaluator; - } - - // ---- Validation ---- - - private void validatePage() { - int minSdk = getMinSdk(); - int buildApi = getBuildApi(); - IStatus status = mValues.getTemplateHandler().validateTemplate(minSdk, buildApi); - - if (status == null || status.isOK()) { - if (mChooseProject && mValues.project == null) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Please select an Android project."); - } - } - - for (Parameter parameter : mShowingTemplate.getParameters()) { - if (parameter.type == Parameter.Type.SEPARATOR) { - continue; - } - IInputValidator validator = parameter.getValidator(mValues.project); - if (validator != null) { - ControlDecoration decoration = mDecorations.get(parameter.id); - String value = parameter.value == null ? "" : parameter.value.toString(); - String error = validator.isValid(value); - if (error != null) { - IStatus s = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, error); - if (decoration != null) { - updateDecorator(decoration, s, parameter.help); - } - if (status == null || status.isOK()) { - status = s; - } - } else if (decoration != null) { - updateDecorator(decoration, null, parameter.help); - } - } - - if (status == null || status.isOK()) { - if (parameter.control instanceof Combo) { - status = validateCombo(status, parameter, minSdk, buildApi); - } - } - } - - setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); - if (status != null) { - setMessage(status.getMessage(), - status.getSeverity() == IStatus.ERROR - ? IMessageProvider.ERROR : IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - /** Validates the given combo */ - static IStatus validateCombo(IStatus status, Parameter parameter, int minSdk, int buildApi) { - Combo combo = (Combo) parameter.control; - int index = combo.getSelectionIndex(); - return validateCombo(status, parameter, index, minSdk, buildApi); - } - - /** Validates the given combo assuming the value at the given index is chosen */ - static IStatus validateCombo(IStatus status, Parameter parameter, int index, - int minSdk, int buildApi) { - Combo combo = (Combo) parameter.control; - Integer[] optionIds = (Integer[]) combo.getData(ATTR_MIN_API); - // Check minSdk - if (index != -1 && index < optionIds.length) { - Integer requiredMinSdk = optionIds[index]; - if (requiredMinSdk > minSdk) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format( - "%1$s \"%2$s\" requires a minimum SDK version of at " + - "least %3$d, and the current min version is %4$d", - parameter.name, combo.getItems()[index], requiredMinSdk, minSdk)); - } - } - - // Check minimum build target - optionIds = (Integer[]) combo.getData(ATTR_MIN_BUILD_API); - if (index != -1 && index < optionIds.length) { - Integer requiredBuildApi = optionIds[index]; - if (requiredBuildApi > buildApi) { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format( - "%1$s \"%2$s\" requires a build target API version of at " + - "least %3$d, and the current version is %4$d", - parameter.name, combo.getItems()[index], requiredBuildApi, buildApi)); - } - } - return status; - } - - private int getMinSdk() { - return mChooseProject ? mValues.getMinSdk() : mCustomMinSdk; - } - - private int getBuildApi() { - return mChooseProject ? mValues.getBuildApi() : mCustomBuildApi; - } - - private void updateDecorator(ControlDecoration decorator, IStatus status, String help) { - if (help != null && !help.isEmpty()) { - decorator.setDescriptionText(status != null ? status.getMessage() : help); - - int severity = status != null ? status.getSeverity() : IStatus.OK; - String id; - if (severity == IStatus.ERROR) { - id = FieldDecorationRegistry.DEC_ERROR; - } else if (severity == IStatus.WARNING) { - id = FieldDecorationRegistry.DEC_WARNING; - } else { - id = FieldDecorationRegistry.DEC_INFORMATION; - } - FieldDecoration errorFieldIndicator = FieldDecorationRegistry.getDefault(). - getFieldDecoration(id); - decorator.setImage(errorFieldIndicator.getImage()); - } else { - if (status == null || status.isOK()) { - decorator.hide(); - } else { - decorator.show(); - } - } - } - - // ---- Implements ModifyListener ---- - - @Override - public void modifyText(ModifyEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source instanceof Text) { - Text text = (Text) source; - editParameter(text, text.getText().trim()); - } - - validatePage(); - } - - // ---- Implements SelectionListener ---- - - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source == mProjectButton) { - mValues.project = mProjectButton.getSelectedProject(); - } else if (source instanceof Combo) { - Combo combo = (Combo) source; - String[] optionIds = (String[]) combo.getData(ATTR_ID); - int index = combo.getSelectionIndex(); - if (index != -1 && index < optionIds.length) { - String optionId = optionIds[index]; - editParameter(combo, optionId); - TemplateMetadata template = mValues.getTemplateHandler().getTemplate(); - if (template != null) { - setPreview(template.getThumbnailPath()); - } - } - } else if (source instanceof Button) { - Button button = (Button) source; - Parameter parameter = (Parameter) button.getData(); - if (parameter.type == Type.BOOLEAN) { - // Checkbox parameter - editParameter(button, button.getSelection()); - - TemplateMetadata template = mValues.getTemplateHandler().getTemplate(); - if (template != null) { - setPreview(template.getThumbnailPath()); - } - } else { - // Choose button for some other parameter, usually a text - String activity = chooseActivity(); - if (activity != null) { - setValue(parameter, activity); - } - } - } - - validatePage(); - } - - private String chooseActivity() { - try { - // Compute a search scope: We need to merge all the subclasses - // android.app.Fragment and android.support.v4.app.Fragment - IJavaSearchScope scope = SearchEngine.createWorkspaceScope(); - IProject project = mValues.project; - IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); - IType activityType = null; - - if (javaProject != null) { - activityType = javaProject.findType(CLASS_ACTIVITY); - } - if (activityType == null) { - IJavaProject[] projects = BaseProjectHelper.getAndroidProjects(null); - for (IJavaProject p : projects) { - activityType = p.findType(CLASS_ACTIVITY); - if (activityType != null) { - break; - } - } - } - if (activityType != null) { - NullProgressMonitor monitor = new NullProgressMonitor(); - ITypeHierarchy hierarchy = activityType.newTypeHierarchy(monitor); - IType[] classes = hierarchy.getAllSubtypes(activityType); - scope = SearchEngine.createJavaSearchScope(classes, IJavaSearchScope.SOURCES); - } - - Shell parent = AdtPlugin.getShell(); - final SelectionDialog dialog = JavaUI.createTypeDialog( - parent, - new ProgressMonitorDialog(parent), - scope, - IJavaElementSearchConstants.CONSIDER_CLASSES, false, - // Use ? as a default filter to fill dialog with matches - "?", //$NON-NLS-1$ - new TypeSelectionExtension() { - @Override - public ITypeInfoFilterExtension getFilterExtension() { - return new ITypeInfoFilterExtension() { - @Override - public boolean select(ITypeInfoRequestor typeInfoRequestor) { - int modifiers = typeInfoRequestor.getModifiers(); - if (!Flags.isPublic(modifiers) - || Flags.isInterface(modifiers) - || Flags.isEnum(modifiers)) { - return false; - } - return true; - } - }; - } - }); - - dialog.setTitle("Choose Activity Class"); - dialog.setMessage("Select an Activity class (? = any character, * = any string):"); - if (dialog.open() == IDialogConstants.CANCEL_ID) { - return null; - } - - Object[] types = dialog.getResult(); - if (types != null && types.length > 0) { - return ((IType) types[0]).getFullyQualifiedName(); - } - } catch (JavaModelException e) { - AdtPlugin.log(e, null); - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - return null; - } - - private void editParameter(Control control, Object value) { - Parameter parameter = getParameter(control); - if (parameter != null) { - String id = parameter.id; - parameter.value = value; - parameter.edited = value != null && !value.toString().isEmpty(); - mValues.parameters.put(id, value); - - // Update dependent variables, if any - List<Parameter> parameters = mShowingTemplate.getParameters(); - for (Parameter p : parameters) { - if (p == parameter || p.suggest == null || p.edited || - p.type == Parameter.Type.SEPARATOR) { - continue; - } - if (!p.suggest.contains(id)) { - continue; - } - - try { - if (mEvaluator == null) { - mEvaluator = new StringEvaluator(); - } - String updated = mEvaluator.evaluate(p.suggest, parameters); - if (updated != null && !updated.equals(p.value)) { - setValue(p, updated); - } - } catch (Throwable t) { - // Pass: Ignore updating if something wrong happens - t.printStackTrace(); // during development only - } - } - } - } - - private void setValue(Parameter p, String value) { - p.value = value; - mValues.parameters.put(p.id, value); - - // Update form widgets - boolean prevIgnore = mIgnore; - try { - mIgnore = true; - if (p.control instanceof Text) { - ((Text) p.control).setText(value); - } else if (p.control instanceof Button) { - // TODO: Handle - } else if (p.control instanceof Combo) { - // TODO: Handle - } else if (p.control != null) { - assert false : p.control; - } - } finally { - mIgnore = prevIgnore; - } - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - // ---- Implements FocusListener ---- - - @Override - public void focusGained(FocusEvent e) { - Object source = e.getSource(); - String tip = ""; - - if (source instanceof Control) { - Control control = (Control) source; - Parameter parameter = getParameter(control); - if (parameter != null) { - ControlDecoration decoration = mDecorations.get(parameter.id); - if (decoration != null) { - tip = decoration.getDescriptionText(); - } - } - } - - mTipLabel.setText(tip); - mHelpIcon.setVisible(tip.length() > 0); - } - - @Override - public void focusLost(FocusEvent e) { - mTipLabel.setText(""); - mHelpIcon.setVisible(false); - } -} 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 deleted file mode 100644 index 99814f731..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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 com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_BUILD_API; -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 com.android.annotations.NonNull; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; -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.Set; - -/** - * Template wizard which creates parameterized templates - */ -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$ - - protected NewTemplatePage mMainPage; - protected NewTemplateWizardState mValues; - private final String mTemplateName; - - NewTemplateWizard(String templateName) { - mTemplateName = templateName; - } - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - super.init(workbench, selection); - - mValues = new NewTemplateWizardState(); - - File template = TemplateManager.getTemplateLocation(mTemplateName); - if (template != null) { - mValues.setTemplateLocation(template); - } - hideBuiltinParameters(); - - List<IProject> projects = AdtUtils.getSelectedProjects(selection); - if (projects.size() == 1) { - mValues.project = projects.get(0); - } - - mMainPage = new NewTemplatePage(mValues, true); - } - - @Override - protected boolean shouldAddIconPage() { - return mValues.getIconState() != null; - } - - /** - * Hide those parameters that the template requires but that we don't want - * to ask the users about, since we can derive it from the target project - * the template is written into. - */ - protected void hideBuiltinParameters() { - Set<String> hidden = mValues.hidden; - hidden.add(ATTR_PACKAGE_NAME); - hidden.add(ATTR_MIN_API); - hidden.add(ATTR_MIN_API_LEVEL); - hidden.add(ATTR_TARGET_API); - hidden.add(ATTR_BUILD_API); - } - - @Override - public void addPages() { - super.addPages(); - addPage(mMainPage); - } - - @Override - public IWizardPage getNextPage(IWizardPage page) { - TemplateMetadata template = mValues.getTemplateHandler().getTemplate(); - - if (page == mMainPage && shouldAddIconPage()) { - WizardPage iconPage = getIconPage(mValues.getIconState()); - mValues.updateIconState(mMainPage.getEvaluator()); - return iconPage; - } else if (page == mMainPage - || shouldAddIconPage() && page == getIconPage(mValues.getIconState())) { - if (template != null) { - if (InstallDependencyPage.isInstalled(template.getDependencies())) { - return getPreviewPage(mValues); - } else { - return getDependencyPage(template, true); - } - } - } else if (page == getDependencyPage(template, false)) { - return getPreviewPage(mValues); - } - - return super.getNextPage(page); - } - - @Override - @NonNull - protected IProject getProject() { - return mValues.project; - } - - @Override - @NonNull - protected List<String> getFilesToOpen() { - TemplateHandler activityTemplate = mValues.getTemplateHandler(); - return activityTemplate.getFilesToOpen(); - } - - @Override - @NonNull - protected List<Runnable> getFinalizingActions() { - TemplateHandler activityTemplate = mValues.getTemplateHandler(); - return activityTemplate.getFinalizingActions(); - } - - @Override - protected List<Change> computeChanges() { - return mValues.computeChanges(); - } - - /** - * Opens the given set of files (as relative paths within a given project - * - * @param project the project containing the paths - * @param relativePaths the paths to files to open - * @param mWorkbench the workbench to open the files in - */ - public static void openFiles( - @NonNull final IProject project, - @NonNull final List<String> relativePaths, - @NonNull final IWorkbench mWorkbench) { - if (!relativePaths.isEmpty()) { - // This has to be delayed in order for focus handling to work correctly - AdtPlugin.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - for (String path : relativePaths) { - IResource resource = project.findMember(path); - if (resource != null) { - if (resource instanceof IFile) { - try { - AdtPlugin.openFile((IFile) resource, null, false); - } catch (PartInitException e) { - AdtPlugin.log(e, "Failed to open %1$s", //$NON-NLS-1$ - resource.getFullPath().toString()); - } - } - boolean isLast = relativePaths.size() == 1 || - path.equals(relativePaths.get(relativePaths.size() - 1)); - if (isLast) { - BasicNewResourceWizard.selectAndReveal(resource, - mWorkbench.getActiveWorkbenchWindow()); - } - } - } - } - }); - } - } - - /** - * Specific New Custom View wizard - */ - public static class NewCustomViewWizard extends NewTemplateWizard { - /** Creates a new {@link NewCustomViewWizard} */ - public NewCustomViewWizard() { - super(CUSTOM_VIEW); - } - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - super.init(workbench, selection); - setWindowTitle("New Custom View"); - super.mMainPage.setTitle("New Custom View"); - super.mMainPage.setDescription("Creates a new custom view"); - } - } -} 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 deleted file mode 100644 index 2c97003f2..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * 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 com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_BUILD_API; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_COPY_ICONS; -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.NewProjectWizard.IS_LIBRARY_PROJECT; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.IS_NEW_PROJECT; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewTemplateWizard.BLANK_ACTIVITY; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -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.manifest.ManifestInfo; -import com.android.ide.eclipse.adt.internal.sdk.ProjectState; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.ltk.core.refactoring.Change; -import org.eclipse.ltk.core.refactoring.NullChange; - -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; - -/** - * Value object which holds the current state of the wizard pages for the - * {@link NewTemplateWizard} - */ -public class NewTemplateWizardState { - /** Template handler responsible for instantiating templates and reading resources */ - private TemplateHandler mTemplateHandler; - - /** Configured parameters, by id */ - public final Map<String, Object> parameters = new HashMap<String, Object>(); - - /** Configured defaults for the parameters, by id */ - public final Map<String, String> defaults = new HashMap<String, String>(); - - /** Ids for parameters which should be hidden (because the client wizard already - * has information for these parameters) */ - public final Set<String> hidden = new HashSet<String>(); - - /** - * The chosen project (which may be null if the wizard page is being - * embedded in the new project wizard) - */ - public IProject project; - - /** The minimum API level to use for this template */ - public int minSdkLevel; - - /** Location of the template being created */ - private File mTemplateLocation; - - /** - * State for the asset studio wizard, used to create custom icons provided - * the icon requests it with an {@code <icons>} element - */ - private CreateAssetSetWizardState mIconState; - - /** - * Create a new state object for use by the {@link NewTemplatePage} - */ - public NewTemplateWizardState() { - parameters.put(IS_NEW_PROJECT, false); - } - - @NonNull - TemplateHandler getTemplateHandler() { - if (mTemplateHandler == null) { - File inputPath; - if (mTemplateLocation != null) { - inputPath = mTemplateLocation; - } else { - // Default - inputPath = TemplateManager.getTemplateLocation(BLANK_ACTIVITY); - } - mTemplateHandler = TemplateHandler.createFromPath(inputPath); - } - - return mTemplateHandler; - } - - /** Sets the current template */ - void setTemplateLocation(File file) { - if (!file.equals(mTemplateLocation)) { - mTemplateLocation = file; - mTemplateHandler = null; - } - } - - /** Returns the current template */ - File getTemplateLocation() { - return mTemplateLocation; - } - - /** Returns the min SDK version to use */ - int getMinSdk() { - if (project == null) { - return -1; - } - ManifestInfo manifest = ManifestInfo.get(project); - return manifest.getMinSdkVersion(); - } - - /** Returns the build API version to use */ - int getBuildApi() { - if (project == null) { - return -1; - } - IAndroidTarget target = Sdk.getCurrent().getTarget(project); - if (target != null) { - return target.getVersion().getApiLevel(); - } - - return getMinSdk(); - } - - /** 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.getMinSdkName()); - parameters.put(ATTR_MIN_API_LEVEL, manifest.getMinSdkVersion()); - parameters.put(ATTR_TARGET_API, manifest.getTargetSdkVersion()); - parameters.put(ATTR_BUILD_API, getBuildApi()); - parameters.put(ATTR_COPY_ICONS, mIconState == null); - ProjectState projectState = Sdk.getProjectState(project); - parameters.put(IS_LIBRARY_PROJECT, - projectState != null ? projectState.isLibrary() : false); - - TemplateHandler.addDirectoryParameters(parameters, project); - - List<Change> changes = getTemplateHandler().render(project, parameters); - - if (mIconState != null) { - String title = String.format("Generate icons (res/drawable-<density>/%1$s.png)", - mIconState.outputName); - changes.add(new NullChange(title) { - @Override - public Change perform(IProgressMonitor pm) throws CoreException { - ConfigureAssetSetPage.generateIcons(mIconState.project, - mIconState, false, null); - - // Not undoable: just return null instead of an undo-change. - return null; - } - }); - - } - - return changes; - } - - @NonNull - CreateAssetSetWizardState getIconState() { - if (mIconState == null) { - TemplateHandler handler = getTemplateHandler(); - if (handler != null) { - TemplateMetadata template = handler.getTemplate(); - if (template != null) { - mIconState = template.getIconState(project); - } - } - } - - return mIconState; - } - - /** - * Updates the icon state, such as the output name, based on other parameter settings - * @param evaluator the string evaluator, or null if none exists - */ - public void updateIconState(@Nullable StringEvaluator evaluator) { - TemplateMetadata template = getTemplateHandler().getTemplate(); - if (template != null) { - if (evaluator == null) { - evaluator = new StringEvaluator(); - } - template.updateIconName(template.getParameters(), evaluator); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java deleted file mode 100644 index 3139451c7..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java +++ /dev/null @@ -1,417 +0,0 @@ -/* - * 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 com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_PACKAGE_NAME; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_CONSTRAINTS; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_DEFAULT; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_HELP; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_ID; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_NAME; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_SUGGEST; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; -import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator; -import com.android.ide.eclipse.adt.internal.wizards.newproject.ApplicationInfoPage; -import com.android.resources.ResourceFolderType; -import com.android.resources.ResourceType; -import com.google.common.base.Splitter; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IType; -import org.eclipse.jface.dialogs.IInputValidator; -import org.eclipse.jface.fieldassist.ControlDecoration; -import org.eclipse.swt.widgets.Control; -import org.w3c.dom.Element; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Locale; - -/** - * A template parameter editable and edited by the user. - * <p> - * Note that this class encapsulates not just the metadata provided by the - * template, but the actual editing operation of that template in the wizard: it - * also captures current values, a reference to the editing widget (such that - * related widgets can be updated when one value depends on another etc) - */ -class Parameter { - enum Type { - STRING, - BOOLEAN, - ENUM, - SEPARATOR; - // TODO: Numbers? - - public static Type get(String name) { - try { - return Type.valueOf(name.toUpperCase(Locale.US)); - } catch (IllegalArgumentException e) { - AdtPlugin.printErrorToConsole("Unexpected template type '" + name + "'"); - AdtPlugin.printErrorToConsole("Expected one of :"); - for (Type s : Type.values()) { - AdtPlugin.printErrorToConsole(" " + s.name().toLowerCase(Locale.US)); - } - } - - return STRING; - } - } - - /** - * Constraints that can be applied to a parameter which helps the UI add a - * validator etc for user input. These are typically combined into a set - * of constraints via an EnumSet. - */ - enum Constraint { - /** - * This value must be unique. This constraint usually only makes sense - * when other constraints are specified, such as {@link #LAYOUT}, which - * means that the parameter should designate a name that does not - * represent an existing layout resource name - */ - UNIQUE, - - /** - * This value must already exist. This constraint usually only makes sense - * when other constraints are specified, such as {@link #LAYOUT}, which - * means that the parameter should designate a name that already exists as - * a resource name. - */ - EXISTS, - - /** The associated value must not be empty */ - NONEMPTY, - - /** The associated value is allowed to be empty */ - EMPTY, - - /** The associated value should represent a fully qualified activity class name */ - ACTIVITY, - - /** The associated value should represent an API level */ - APILEVEL, - - /** The associated value should represent a valid class name */ - CLASS, - - /** The associated value should represent a valid package name */ - PACKAGE, - - /** The associated value should represent a valid layout resource name */ - LAYOUT, - - /** The associated value should represent a valid drawable resource name */ - DRAWABLE, - - /** The associated value should represent a valid id resource name */ - ID, - - /** The associated value should represent a valid string resource name */ - STRING; - - public static Constraint get(String name) { - try { - return Constraint.valueOf(name.toUpperCase(Locale.US)); - } catch (IllegalArgumentException e) { - AdtPlugin.printErrorToConsole("Unexpected template constraint '" + name + "'"); - if (name.indexOf(',') != -1) { - AdtPlugin.printErrorToConsole("Use | to separate constraints"); - } else { - AdtPlugin.printErrorToConsole("Expected one of :"); - for (Constraint s : Constraint.values()) { - AdtPlugin.printErrorToConsole(" " + s.name().toLowerCase(Locale.US)); - } - } - } - - return NONEMPTY; - } - } - - /** The template defining the parameter */ - public final TemplateMetadata template; - - /** The type of parameter */ - @NonNull - public final Type type; - - /** The unique id of the parameter (not displayed to the user) */ - @Nullable - public final String id; - - /** The display name for this parameter */ - @Nullable - public final String name; - - /** - * The initial value for this parameter (see also {@link #suggest} for more - * dynamic defaults - */ - @Nullable - public final String initial; - - /** - * A template expression using other template parameters for producing a - * default value based on other edited parameters, if possible. - */ - @Nullable - public final String suggest; - - /** Help for the parameter, if any */ - @Nullable - public final String help; - - /** The currently edited value */ - @Nullable - public Object value; - - /** The control showing this value */ - @Nullable - public Control control; - - /** The decoration associated with the control */ - @Nullable - public ControlDecoration decoration; - - /** Whether the parameter has been edited */ - public boolean edited; - - /** The element defining this parameter */ - @NonNull - public final Element element; - - /** The constraints applicable for this parameter */ - @NonNull - public final EnumSet<Constraint> constraints; - - /** The validator, if any, for this field */ - private IInputValidator mValidator; - - /** True if this field has no validator */ - private boolean mNoValidator; - - /** Project associated with this validator */ - private IProject mValidatorProject; - - Parameter(@NonNull TemplateMetadata template, @NonNull Element parameter) { - this.template = template; - element = parameter; - - String typeName = parameter.getAttribute(TemplateHandler.ATTR_TYPE); - assert typeName != null && !typeName.isEmpty() : TemplateHandler.ATTR_TYPE; - type = Type.get(typeName); - - id = parameter.getAttribute(ATTR_ID); - initial = parameter.getAttribute(ATTR_DEFAULT); - suggest = parameter.getAttribute(ATTR_SUGGEST); - name = parameter.getAttribute(ATTR_NAME); - help = parameter.getAttribute(ATTR_HELP); - String constraintString = parameter.getAttribute(ATTR_CONSTRAINTS); - if (constraintString != null && !constraintString.isEmpty()) { - EnumSet<Constraint> constraintSet = null; - for (String s : Splitter.on('|').omitEmptyStrings().split(constraintString)) { - Constraint constraint = Constraint.get(s); - if (constraintSet == null) { - constraintSet = EnumSet.of(constraint); - } else { - constraintSet = EnumSet.copyOf(constraintSet); - constraintSet.add(constraint); - } - } - constraints = constraintSet; - } else { - constraints = EnumSet.noneOf(Constraint.class); - } - - if (initial != null && !initial.isEmpty() && type == Type.BOOLEAN) { - value = Boolean.valueOf(initial); - } else { - value = initial; - } - } - - Parameter( - @NonNull TemplateMetadata template, - @NonNull Type type, - @NonNull String id, - @NonNull String initialValue) { - this.template = template; - this.type = type; - this.id = id; - this.value = initialValue; - element = null; - initial = null; - suggest = null; - name = id; - help = null; - constraints = EnumSet.noneOf(Constraint.class); - } - - List<Element> getOptions() { - if (element != null) { - return DomUtilities.getChildren(element); - } else { - return Collections.emptyList(); - } - } - - @Nullable - public IInputValidator getValidator(@Nullable final IProject project) { - if (mNoValidator) { - return null; - } - - if (project != mValidatorProject) { - // Force update of validators if the project changes, since the validators - // are often tied to project metadata (for example, the resource name validators - // which look for name conflicts) - mValidator = null; - mValidatorProject = project; - } - - if (mValidator == null) { - if (constraints.contains(Constraint.LAYOUT)) { - if (project != null && constraints.contains(Constraint.UNIQUE)) { - mValidator = ResourceNameValidator.create(false, project, ResourceType.LAYOUT); - } else { - mValidator = ResourceNameValidator.create(false, ResourceFolderType.LAYOUT); - } - return mValidator; - } else if (constraints.contains(Constraint.STRING)) { - if (project != null && constraints.contains(Constraint.UNIQUE)) { - mValidator = ResourceNameValidator.create(false, project, ResourceType.STRING); - } else { - mValidator = ResourceNameValidator.create(false, ResourceFolderType.VALUES); - } - return mValidator; - } else if (constraints.contains(Constraint.ID)) { - if (project != null && constraints.contains(Constraint.UNIQUE)) { - mValidator = ResourceNameValidator.create(false, project, ResourceType.ID); - } else { - mValidator = ResourceNameValidator.create(false, ResourceFolderType.VALUES); - } - return mValidator; - } else if (constraints.contains(Constraint.DRAWABLE)) { - if (project != null && constraints.contains(Constraint.UNIQUE)) { - mValidator = ResourceNameValidator.create(false, project, - ResourceType.DRAWABLE); - } else { - mValidator = ResourceNameValidator.create(false, ResourceFolderType.DRAWABLE); - } - return mValidator; - } else if (constraints.contains(Constraint.PACKAGE) - || constraints.contains(Constraint.CLASS) - || constraints.contains(Constraint.ACTIVITY)) { - mValidator = new IInputValidator() { - @Override - public String isValid(String newText) { - newText = newText.trim(); - if (newText.isEmpty()) { - if (constraints.contains(Constraint.EMPTY)) { - return null; - } else if (constraints.contains(Constraint.NONEMPTY)) { - return String.format("Enter a value for %1$s", name); - } else { - // Compatibility mode: older templates might not specify; - // in that case, accept empty - if (!"activityClass".equals(id)) { //$NON-NLS-1$ - return null; - } - } - } - IStatus status; - if (constraints.contains(Constraint.ACTIVITY)) { - status = ApplicationInfoPage.validateActivity(newText); - } else if (constraints.contains(Constraint.PACKAGE)) { - status = ApplicationInfoPage.validatePackage(newText); - } else { - assert constraints.contains(Constraint.CLASS); - status = ApplicationInfoPage.validateClass(newText); - } - if (status != null && !status.isOK()) { - return status.getMessage(); - } - - // Uniqueness - if (project != null && constraints.contains(Constraint.UNIQUE)) { - try { - // Determine the package. - // If there is a package info - - IJavaProject p = BaseProjectHelper.getJavaProject(project); - if (p != null) { - String fqcn = newText; - if (fqcn.indexOf('.') == -1) { - String pkg = null; - Parameter parameter = template.getParameter( - ATTR_PACKAGE_NAME); - if (parameter != null && parameter.value != null) { - pkg = parameter.value.toString(); - } else { - pkg = ManifestInfo.get(project).getPackage(); - } - fqcn = pkg.isEmpty() ? newText : pkg + '.' + newText; - } - - IType t = p.findType(fqcn); - if (t != null && t.exists()) { - return String.format("%1$s already exists", newText); - } - } - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - } - - return null; - } - }; - return mValidator; - } else if (constraints.contains(Constraint.NONEMPTY)) { - mValidator = new IInputValidator() { - @Override - public String isValid(String newText) { - if (newText.trim().isEmpty()) { - return String.format("Enter a value for %1$s", name); - } - - return null; - } - }; - return mValidator; - } - - // TODO: Handle EXISTS, APILEVEL (which is currently handled manually in the - // new project wizard, and never actually input by the user in a templated - // wizard) - - mNoValidator = true; - } - - return mValidator; - } -}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ProjectContentsPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ProjectContentsPage.java deleted file mode 100644 index 7d7881fcf..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ProjectContentsPage.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * 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.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.wizards.newproject.WorkingSetGroup; -import com.android.ide.eclipse.adt.internal.wizards.newproject.WorkingSetHelper; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkingSet; - -import java.io.File; - -/** - * Second wizard page in the "New Project From Template" wizard - */ -public class ProjectContentsPage extends WizardPage - implements ModifyListener, SelectionListener, FocusListener { - - private final NewProjectWizardState mValues; - - private boolean mIgnore; - private Button mCustomIconToggle; - private Button mLibraryToggle; - - private Button mUseDefaultLocationToggle; - private Label mLocationLabel; - private Text mLocationText; - private Button mChooseLocationButton; - private static String sLastProjectLocation = System.getProperty("user.home"); //$NON-NLS-1$ - private Button mCreateActivityToggle; - private WorkingSetGroup mWorkingSetGroup; - - ProjectContentsPage(NewProjectWizardState values) { - super("newAndroidApp"); //$NON-NLS-1$ - mValues = values; - setTitle("New Android Application"); - setDescription("Configure Project"); - - mWorkingSetGroup = new WorkingSetGroup(); - setWorkingSets(new IWorkingSet[0]); - } - - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - setControl(container); - GridLayout gl_container = new GridLayout(4, false); - gl_container.horizontalSpacing = 10; - container.setLayout(gl_container); - - mCustomIconToggle = new Button(container, SWT.CHECK); - mCustomIconToggle.setSelection(true); - mCustomIconToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); - mCustomIconToggle.setText("Create custom launcher icon"); - mCustomIconToggle.setSelection(mValues.createIcon); - mCustomIconToggle.addSelectionListener(this); - - mCreateActivityToggle = new Button(container, SWT.CHECK); - mCreateActivityToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, - 4, 1)); - mCreateActivityToggle.setText("Create activity"); - mCreateActivityToggle.setSelection(mValues.createActivity); - mCreateActivityToggle.addSelectionListener(this); - - new Label(container, SWT.NONE).setLayoutData( - new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); - - mLibraryToggle = new Button(container, SWT.CHECK); - mLibraryToggle.setSelection(true); - mLibraryToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); - mLibraryToggle.setText("Mark this project as a library"); - mLibraryToggle.setSelection(mValues.isLibrary); - mLibraryToggle.addSelectionListener(this); - - // Blank line - new Label(container, SWT.NONE).setLayoutData( - new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); - - mUseDefaultLocationToggle = new Button(container, SWT.CHECK); - mUseDefaultLocationToggle.setLayoutData( - new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); - mUseDefaultLocationToggle.setText("Create Project in Workspace"); - mUseDefaultLocationToggle.addSelectionListener(this); - - mLocationLabel = new Label(container, SWT.NONE); - mLocationLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - mLocationLabel.setText("Location:"); - - mLocationText = new Text(container, SWT.BORDER); - mLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); - mLocationText.addModifyListener(this); - - mChooseLocationButton = new Button(container, SWT.NONE); - mChooseLocationButton.setText("Browse..."); - mChooseLocationButton.addSelectionListener(this); - mChooseLocationButton.setEnabled(false); - setUseCustomLocation(!mValues.useDefaultLocation); - - new Label(container, SWT.NONE).setLayoutData( - new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); - - Composite group = mWorkingSetGroup.createControl(container); - group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 4, 1)); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - - if (visible) { - try { - mIgnore = true; - mUseDefaultLocationToggle.setSelection(mValues.useDefaultLocation); - mLocationText.setText(mValues.projectLocation); - } finally { - mIgnore = false; - } - } - - validatePage(); - } - - private void setUseCustomLocation(boolean en) { - mValues.useDefaultLocation = !en; - mUseDefaultLocationToggle.setSelection(!en); - if (!en) { - updateProjectLocation(mValues.projectName); - } - - mLocationLabel.setEnabled(en); - mLocationText.setEnabled(en); - mChooseLocationButton.setEnabled(en); - } - - void init(IStructuredSelection selection, IWorkbenchPart activePart) { - setWorkingSets(WorkingSetHelper.getSelectedWorkingSet(selection, activePart)); - } - - /** - * Returns the working sets to which the new project should be added. - * - * @return the selected working sets to which the new project should be added - */ - private IWorkingSet[] getWorkingSets() { - return mWorkingSetGroup.getSelectedWorkingSets(); - } - - /** - * Sets the working sets to which the new project should be added. - * - * @param workingSets the initial selected working sets - */ - private void setWorkingSets(IWorkingSet[] workingSets) { - assert workingSets != null; - mWorkingSetGroup.setWorkingSets(workingSets); - } - - @Override - public IWizardPage getNextPage() { - // Sync working set data to the value object, since the WorkingSetGroup - // doesn't let us add listeners to do this lazily - mValues.workingSets = getWorkingSets(); - - return super.getNextPage(); - } - - // ---- Implements ModifyListener ---- - - @Override - public void modifyText(ModifyEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source == mLocationText) { - mValues.projectLocation = mLocationText.getText().trim(); - } - - validatePage(); - } - - - /** If the project should be created in the workspace, then update the project location - * based on the project name. */ - private void updateProjectLocation(String projectName) { - if (projectName == null) { - projectName = ""; - } - - boolean useDefaultLocation = mUseDefaultLocationToggle.getSelection(); - - if (useDefaultLocation) { - IPath workspace = Platform.getLocation(); - String projectLocation = workspace.append(projectName).toOSString(); - mLocationText.setText(projectLocation); - mValues.projectLocation = projectLocation; - } - } - - // ---- Implements SelectionListener ---- - - @Override - public void widgetSelected(SelectionEvent e) { - if (mIgnore) { - return; - } - - Object source = e.getSource(); - if (source == mCustomIconToggle) { - mValues.createIcon = mCustomIconToggle.getSelection(); - } else if (source == mLibraryToggle) { - mValues.isLibrary = mLibraryToggle.getSelection(); - } else if (source == mCreateActivityToggle) { - mValues.createActivity = mCreateActivityToggle.getSelection(); - } else if (source == mUseDefaultLocationToggle) { - boolean useDefault = mUseDefaultLocationToggle.getSelection(); - setUseCustomLocation(!useDefault); - } else if (source == mChooseLocationButton) { - String dir = promptUserForLocation(getShell()); - if (dir != null) { - mLocationText.setText(dir); - mValues.projectLocation = dir; - } - } - - validatePage(); - } - - private String promptUserForLocation(Shell shell) { - DirectoryDialog dd = new DirectoryDialog(getShell()); - dd.setMessage("Select folder where project should be created"); - - String curLocation = mLocationText.getText().trim(); - if (!curLocation.isEmpty()) { - dd.setFilterPath(curLocation); - } else if (sLastProjectLocation != null) { - dd.setFilterPath(sLastProjectLocation); - } - - String dir = dd.open(); - if (dir != null) { - sLastProjectLocation = dir; - } - - return dir; - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - - // ---- Implements FocusListener ---- - - @Override - public void focusGained(FocusEvent e) { - } - - @Override - public void focusLost(FocusEvent e) { - } - - // Validation - - void validatePage() { - IStatus status = validateProjectLocation(); - - setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); - if (status != null) { - setMessage(status.getMessage(), - status.getSeverity() == IStatus.ERROR - ? IMessageProvider.ERROR : IMessageProvider.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - - static IStatus validateLocationInWorkspace(NewProjectWizardState values) { - if (values.useDefaultLocation) { - return null; - } - - // Validate location - if (values.projectName != null) { - File dest = Platform.getLocation().append(values.projectName).toFile(); - if (dest.exists()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format( - "There is already a file or directory named \"%1$s\" in the selected location.", - values.projectName)); - } - } - - return null; - } - - private IStatus validateProjectLocation() { - if (mValues.useDefaultLocation) { - return validateLocationInWorkspace(mValues); - } - - String location = mLocationText.getText(); - if (location.trim().isEmpty()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Provide a valid file system location where the project should be created."); - } - - File f = new File(location); - if (f.exists()) { - if (!f.isDirectory()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("'%s' is not a valid folder.", location)); - } - - File[] children = f.listFiles(); - if (children != null && children.length > 0) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("Folder '%s' is not empty.", location)); - } - } - - // if the folder doesn't exist, then make sure that the parent - // exists and is a writable folder - File parent = f.getParentFile(); - if (!parent.exists()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("Folder '%s' does not exist.", parent.getName())); - } - - if (!parent.isDirectory()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("'%s' is not a folder.", parent.getName())); - } - - if (!parent.canWrite()) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("'%s' is not writeable.", parent.getName())); - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/StringEvaluator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/StringEvaluator.java deleted file mode 100644 index c1c8073c0..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/StringEvaluator.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 com.android.tools.lint.detector.api.LintUtils.assertionsEnabled; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtPlugin; - -import freemarker.cache.TemplateLoader; -import freemarker.template.Configuration; -import freemarker.template.DefaultObjectWrapper; -import freemarker.template.Template; - -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.List; -import java.util.Map; - -/** - * A template handler which can evaluate simple strings. Used to evaluate - * parameter constraints during UI wizard value editing. - * <p> - * Unlike the more general {@link TemplateHandler} which is used to instantiate - * full template files (from resources, merging into existing files etc) this - * evaluator supports only simple strings, referencing only values from the - * provided map (and builtin functions). - */ -class StringEvaluator implements TemplateLoader { - private Map<String, Object> mParameters; - private Configuration mFreemarker; - private String mCurrentExpression; - - StringEvaluator() { - mParameters = TemplateHandler.createBuiltinMap(); - - mFreemarker = new Configuration(); - mFreemarker.setObjectWrapper(new DefaultObjectWrapper()); - mFreemarker.setTemplateLoader(this); - } - - /** Evaluates the given expression, with the given set of parameters */ - @Nullable - String evaluate(@NonNull String expression, @NonNull List<Parameter> parameters) { - // Render the instruction list template. - for (Parameter parameter : parameters) { - mParameters.put(parameter.id, parameter.value); - } - try { - mCurrentExpression = expression; - Template inputsTemplate = mFreemarker.getTemplate(expression); - StringWriter out = new StringWriter(); - inputsTemplate.process(mParameters, out); - out.flush(); - return out.toString(); - } catch (Exception e) { - if (assertionsEnabled()) { - AdtPlugin.log(e, null); - } - return null; - } - } - - // ---- Implements TemplateLoader ---- - - @Override - public Object findTemplateSource(String name) throws IOException { - return mCurrentExpression; - } - - @Override - public long getLastModified(Object templateSource) { - return 0; - } - - @Override - public Reader getReader(Object templateSource, String encoding) throws IOException { - return new StringReader(mCurrentExpression); - } - - @Override - public void closeTemplateSource(Object templateSource) throws IOException { - } -} 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 deleted file mode 100644 index 8e11841b4..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java +++ /dev/null @@ -1,1239 +0,0 @@ -/* - * 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 com.android.SdkConstants.ATTR_PACKAGE; -import static com.android.SdkConstants.DOT_AIDL; -import static com.android.SdkConstants.DOT_FTL; -import static com.android.SdkConstants.DOT_JAVA; -import static com.android.SdkConstants.DOT_RS; -import static com.android.SdkConstants.DOT_SVG; -import static com.android.SdkConstants.DOT_TXT; -import static com.android.SdkConstants.DOT_XML; -import static com.android.SdkConstants.EXT_XML; -import static com.android.SdkConstants.FD_NATIVE_LIBS; -import static com.android.SdkConstants.XMLNS_PREFIX; -import static com.android.ide.eclipse.adt.internal.wizards.templates.InstallDependencyPage.SUPPORT_LIBRARY_NAME; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateManager.getTemplateRootFolder; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.annotations.VisibleForTesting; -import com.android.ide.common.xml.XmlFormatStyle; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.actions.AddSupportJarAction; -import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlFormatPreferences; -import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlPrettyPrinter; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.sdk.AdtManifestMergeCallback; -import com.android.manifmerger.ManifestMerger; -import com.android.manifmerger.MergerLog; -import com.android.resources.ResourceFolderType; -import com.android.utils.SdkUtils; -import com.google.common.base.Charsets; -import com.google.common.collect.Lists; -import com.google.common.io.Files; - -import freemarker.cache.TemplateLoader; -import freemarker.template.Configuration; -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.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.ToolFactory; -import org.eclipse.jdt.core.formatter.CodeFormatter; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -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.eclipse.text.edits.TextEdit; -import org.osgi.framework.Constants; -import org.osgi.framework.Version; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringWriter; -import java.io.Writer; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * Handler which manages instantiating FreeMarker templates, copying resources - * and merging into existing files - */ -class TemplateHandler { - /** Highest supported format; templates with a higher number will be skipped - * <p> - * <ul> - * <li> 1: Initial format, supported by ADT 20 and up. - * <li> 2: ADT 21 and up. Boolean variables that have a default value and are not - * edited by the user would end up as strings in ADT 20; now they are always - * proper Booleans. Templates which rely on this should specify format >= 2. - * <li> 3: The wizard infrastructure passes the {@code isNewProject} boolean variable - * to indicate whether a wizard is created as part of a new blank project - * <li> 4: The templates now specify dependencies in the recipe file. - * </ul> - */ - static final int CURRENT_FORMAT = 4; - - /** - * Special marker indicating that this path refers to the special shared - * resource directory rather than being somewhere inside the root/ directory - * where all template specific resources are found - */ - private static final String VALUE_TEMPLATE_DIR = "$TEMPLATEDIR"; //$NON-NLS-1$ - - /** - * Directory within the template which contains the resources referenced - * from the template.xml file - */ - private static final String DATA_ROOT = "root"; //$NON-NLS-1$ - - /** - * Shared resource directory containing common resources shared among - * multiple templates - */ - private static final String RESOURCE_ROOT = "resources"; //$NON-NLS-1$ - - /** Reserved filename which describes each template */ - static final String TEMPLATE_XML = "template.xml"; //$NON-NLS-1$ - - // Various tags and attributes used in the template metadata files - template.xml, - // globals.xml.ftl, recipe.xml.ftl, etc. - - static final String TAG_MERGE = "merge"; //$NON-NLS-1$ - static final String TAG_EXECUTE = "execute"; //$NON-NLS-1$ - static final String TAG_GLOBALS = "globals"; //$NON-NLS-1$ - static final String TAG_GLOBAL = "global"; //$NON-NLS-1$ - static final String TAG_PARAMETER = "parameter"; //$NON-NLS-1$ - static final String TAG_COPY = "copy"; //$NON-NLS-1$ - static final String TAG_INSTANTIATE = "instantiate"; //$NON-NLS-1$ - static final String TAG_OPEN = "open"; //$NON-NLS-1$ - static final String TAG_THUMB = "thumb"; //$NON-NLS-1$ - static final String TAG_THUMBS = "thumbs"; //$NON-NLS-1$ - static final String TAG_DEPENDENCY = "dependency"; //$NON-NLS-1$ - static final String TAG_ICONS = "icons"; //$NON-NLS-1$ - static final String TAG_FORMFACTOR = "formfactor"; //$NON-NLS-1$ - static final String TAG_CATEGORY = "category"; //$NON-NLS-1$ - static final String ATTR_FORMAT = "format"; //$NON-NLS-1$ - static final String ATTR_REVISION = "revision"; //$NON-NLS-1$ - static final String ATTR_VALUE = "value"; //$NON-NLS-1$ - static final String ATTR_DEFAULT = "default"; //$NON-NLS-1$ - static final String ATTR_SUGGEST = "suggest"; //$NON-NLS-1$ - static final String ATTR_ID = "id"; //$NON-NLS-1$ - static final String ATTR_NAME = "name"; //$NON-NLS-1$ - static final String ATTR_DESCRIPTION = "description";//$NON-NLS-1$ - static final String ATTR_TYPE = "type"; //$NON-NLS-1$ - static final String ATTR_HELP = "help"; //$NON-NLS-1$ - static final String ATTR_FILE = "file"; //$NON-NLS-1$ - static final String ATTR_TO = "to"; //$NON-NLS-1$ - static final String ATTR_FROM = "from"; //$NON-NLS-1$ - static final String ATTR_CONSTRAINTS = "constraints";//$NON-NLS-1$ - static final String ATTR_BACKGROUND = "background"; //$NON-NLS-1$ - static final String ATTR_FOREGROUND = "foreground"; //$NON-NLS-1$ - static final String ATTR_SHAPE = "shape"; //$NON-NLS-1$ - static final String ATTR_TRIM = "trim"; //$NON-NLS-1$ - static final String ATTR_PADDING = "padding"; //$NON-NLS-1$ - static final String ATTR_SOURCE_TYPE = "source"; //$NON-NLS-1$ - static final String ATTR_CLIPART_NAME = "clipartName";//$NON-NLS-1$ - static final String ATTR_TEXT = "text"; //$NON-NLS-1$ - static final String ATTR_SRC_DIR = "srcDir"; //$NON-NLS-1$ - static final String ATTR_SRC_OUT = "srcOut"; //$NON-NLS-1$ - static final String ATTR_RES_DIR = "resDir"; //$NON-NLS-1$ - static final String ATTR_RES_OUT = "resOut"; //$NON-NLS-1$ - static final String ATTR_MANIFEST_DIR = "manifestDir";//$NON-NLS-1$ - static final String ATTR_MANIFEST_OUT = "manifestOut";//$NON-NLS-1$ - static final String ATTR_PROJECT_DIR = "projectDir"; //$NON-NLS-1$ - static final String ATTR_PROJECT_OUT = "projectOut"; //$NON-NLS-1$ - static final String ATTR_MAVEN_URL = "mavenUrl"; //$NON-NLS-1$ - static final String ATTR_DEBUG_KEYSTORE_SHA1 = - "debugKeystoreSha1"; //$NON-NLS-1$ - - static final String CATEGORY_ACTIVITIES = "activities";//$NON-NLS-1$ - static final String CATEGORY_PROJECTS = "projects"; //$NON-NLS-1$ - static final String CATEGORY_OTHER = "other"; //$NON-NLS-1$ - - static final String MAVEN_SUPPORT_V4 = "support-v4"; //$NON-NLS-1$ - static final String MAVEN_SUPPORT_V13 = "support-v13"; //$NON-NLS-1$ - static final String MAVEN_APPCOMPAT = "appcompat-v7"; //$NON-NLS-1$ - - /** Default padding to apply in wizards around the thumbnail preview images */ - static final int PREVIEW_PADDING = 10; - - /** Default width to scale thumbnail preview images in wizards to */ - static final int PREVIEW_WIDTH = 200; - - /** - * List of files to open after the wizard has been created (these are - * identified by {@link #TAG_OPEN} elements in the recipe file - */ - private final List<String> mOpen = Lists.newArrayList(); - - /** - * List of actions to perform after the wizard has finished. - */ - protected List<Runnable> mFinalizingActions = Lists.newArrayList(); - - /** Path to the directory containing the templates */ - @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; - - /** Agree to all file-overwrites from now on? */ - private boolean mYesToAll = false; - - /** Is writing the template cancelled? */ - private boolean mNoToAll = false; - - /** - * Should files that we merge contents into be backed up? If yes, will - * create emacs-style tilde-file backups (filename.xml~) - */ - private boolean mBackupMergedFiles = true; - - /** - * Template metadata - */ - private TemplateMetadata mTemplate; - - private final TemplateManager mManager; - - /** Creates a new {@link TemplateHandler} for the given root path */ - static TemplateHandler createFromPath(File rootPath) { - return new TemplateHandler(rootPath, new TemplateManager()); - } - - /** Creates a new {@link TemplateHandler} for the template name, which should - * be relative to the templates directory */ - static TemplateHandler createFromName(String category, String name) { - TemplateManager manager = new TemplateManager(); - - // Use the TemplateManager iteration which should merge contents between the - // extras/templates/ and tools/templates folders and pick the most recent version - List<File> templates = manager.getTemplates(category); - for (File file : templates) { - if (file.getName().equals(name) && category.equals(file.getParentFile().getName())) { - return new TemplateHandler(file, manager); - } - } - - return new TemplateHandler(new File(getTemplateRootFolder(), - category + File.separator + name), manager); - } - - private TemplateHandler(File rootPath, TemplateManager manager) { - mRootPath = rootPath; - mManager = manager; - mLoader = new MyTemplateLoader(); - mLoader.setPrefix(mRootPath.getPath()); - } - - public TemplateManager getManager() { - return mManager; - } - - public void setBackupMergedFiles(boolean backupMergedFiles) { - mBackupMergedFiles = backupMergedFiles; - } - - @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); - Configuration freemarker = new Configuration(); - freemarker.setObjectWrapper(new DefaultObjectWrapper()); - freemarker.setTemplateLoader(mLoader); - - 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) { - final Map<String, Object> paramMap = createBuiltinMap(); - - // Wizard parameters supplied by user, specific to this template - paramMap.putAll(args); - - return paramMap; - } - - /** Data model for the templates */ - static Map<String, Object> createBuiltinMap() { - // Create the data model. - final Map<String, Object> paramMap = new HashMap<String, Object>(); - - // Builtin conversion methods - paramMap.put("slashedPackageName", new FmSlashedPackageNameMethod()); //$NON-NLS-1$ - paramMap.put("camelCaseToUnderscore", new FmCamelCaseToUnderscoreMethod()); //$NON-NLS-1$ - paramMap.put("underscoreToCamelCase", new FmUnderscoreToCamelCaseMethod()); //$NON-NLS-1$ - paramMap.put("activityToLayout", new FmActivityToLayoutMethod()); //$NON-NLS-1$ - paramMap.put("layoutToActivity", new FmLayoutToActivityMethod()); //$NON-NLS-1$ - paramMap.put("classToResource", new FmClassNameToResourceMethod()); //$NON-NLS-1$ - paramMap.put("escapeXmlAttribute", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ - paramMap.put("escapeXmlText", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ - paramMap.put("escapeXmlString", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ - paramMap.put("extractLetters", new FmExtractLettersMethod()); //$NON-NLS-1$ - - // This should be handled better: perhaps declared "required packages" as part of the - // inputs? (It would be better if we could conditionally disable template based - // on availability) - Map<String, String> builtin = new HashMap<String, String>(); - builtin.put("templatesRes", VALUE_TEMPLATE_DIR); //$NON-NLS-1$ - paramMap.put("android", builtin); //$NON-NLS-1$ - - return paramMap; - } - - static void addDirectoryParameters(Map<String, Object> parameters, IProject project) { - IPath srcDir = project.getFile(SdkConstants.SRC_FOLDER).getProjectRelativePath(); - parameters.put(ATTR_SRC_DIR, srcDir.toString()); - - IPath resDir = project.getFile(SdkConstants.RES_FOLDER).getProjectRelativePath(); - parameters.put(ATTR_RES_DIR, resDir.toString()); - - IPath manifestDir = project.getProjectRelativePath(); - parameters.put(ATTR_MANIFEST_DIR, manifestDir.toString()); - parameters.put(ATTR_MANIFEST_OUT, manifestDir.toString()); - - parameters.put(ATTR_PROJECT_DIR, manifestDir.toString()); - parameters.put(ATTR_PROJECT_OUT, manifestDir.toString()); - - parameters.put(ATTR_DEBUG_KEYSTORE_SHA1, ""); - } - - @Nullable - public TemplateMetadata getTemplate() { - if (mTemplate == null) { - mTemplate = mManager.getTemplate(mRootPath); - } - - return mTemplate; - } - - @NonNull - public String getResourcePath(String templateName) { - return new File(mRootPath.getPath(), templateName).getPath(); - } - - /** - * Load a text resource for the given relative path within the template - * - * @param relativePath relative path within the template - * @return the string contents of the template text file - */ - @Nullable - public String readTemplateTextResource(@NonNull String relativePath) { - try { - return Files.toString(new File(mRootPath, - relativePath.replace('/', File.separatorChar)), Charsets.UTF_8); - } catch (IOException e) { - AdtPlugin.log(e, null); - return null; - } - } - - @Nullable - public String readTemplateTextResource(@NonNull File file) { - assert file.isAbsolute(); - try { - return Files.toString(file, Charsets.UTF_8); - } catch (IOException e) { - AdtPlugin.log(e, null); - return null; - } - } - - /** - * Reads the contents of a resource - * - * @param relativePath the path relative to the template directory - * @return the binary data read from the file - */ - @Nullable - public byte[] readTemplateResource(@NonNull String relativePath) { - try { - return Files.toByteArray(new File(mRootPath, relativePath)); - } catch (IOException e) { - AdtPlugin.log(e, null); - return null; - } - } - - /** - * Most recent thrown exception during template instantiation. This should - * basically always be null. Used by unit tests to see if any template - * instantiation recorded a failure. - */ - @VisibleForTesting - public static Exception sMostRecentException; - - /** Read the given FreeMarker file and process the variable definitions */ - private void processVariables(final Configuration freemarker, - String file, final Map<String, Object> paramMap) { - try { - String xml; - if (file.endsWith(DOT_XML)) { - // Just read the file - xml = readTemplateTextResource(file); - if (xml == null) { - return; - } - } else { - mLoader.setTemplateFile(new File(mRootPath, file)); - Template inputsTemplate = freemarker.getTemplate(file); - StringWriter out = new StringWriter(); - inputsTemplate.process(paramMap, out); - out.flush(); - xml = out.toString(); - } - - SAXParserFactory factory = SAXParserFactory.newInstance(); - SAXParser saxParser = factory.newSAXParser(); - saxParser.parse(new ByteArrayInputStream(xml.getBytes()), new DefaultHandler() { - @Override - public void startElement(String uri, String localName, String name, - Attributes attributes) - throws SAXException { - if (TAG_PARAMETER.equals(name)) { - String id = attributes.getValue(ATTR_ID); - if (!paramMap.containsKey(id)) { - String value = attributes.getValue(ATTR_DEFAULT); - Object mapValue = value; - if (value != null && !value.isEmpty()) { - String type = attributes.getValue(ATTR_TYPE); - if ("boolean".equals(type)) { //$NON-NLS-1$ - mapValue = Boolean.valueOf(value); - } - } - paramMap.put(id, mapValue); - } - } else if (TAG_GLOBAL.equals(name)) { - String id = attributes.getValue(ATTR_ID); - if (!paramMap.containsKey(id)) { - paramMap.put(id, TypedVariable.parseGlobal(attributes)); - } - } else if (TAG_GLOBALS.equals(name)) { - // Handle evaluation of variables - String path = attributes.getValue(ATTR_FILE); - if (path != null) { - 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); - } - } else if (TAG_DEPENDENCY.equals(name)) { - String dependencyName = attributes.getValue(ATTR_NAME); - if (dependencyName.equals(SUPPORT_LIBRARY_NAME)) { - // We assume the revision requirement has been satisfied - // by the wizard - File path = AddSupportJarAction.getSupportJarFile(); - if (path != null) { - IPath to = getTargetPath(FD_NATIVE_LIBS +'/' + path.getName()); - try { - copy(path, to); - } catch (IOException ioe) { - AdtPlugin.log(ioe, null); - } - } - } - } else if (!name.equals("template") && !name.equals(TAG_CATEGORY) && - !name.equals(TAG_FORMFACTOR) && !name.equals("option") && - !name.equals(TAG_THUMBS) && !name.equals(TAG_THUMB) && - !name.equals(TAG_ICONS)) { - System.err.println("WARNING: Unknown template directive " + name); - } - } - }); - } catch (Exception e) { - sMostRecentException = e; - AdtPlugin.log(e, null); - } - } - - @SuppressWarnings("unused") - private boolean canOverwrite(File file) { - 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, - String.format( - "%1$s already exists.\nWould you like to replace it?", - file.getPath()), - MessageDialog.QUESTION, new String[] { - // Yes will be moved to the end because it's the default - "Yes", "No", "Cancel", "Yes to All" - }, 0); - int result = dialog.open(); - switch (result) { - case 0: - // Yes - break; - case 3: - // Yes to all - mYesToAll = true; - break; - case 1: - // No - return false; - case SWT.DEFAULT: - case 2: - // Cancel - mNoToAll = true; - return false; - } - } - - if (mBackupMergedFiles) { - return makeBackup(file); - } else { - return file.delete(); - } - } - - return true; - } - - /** Executes the given recipe file: copying, merging, instantiating, opening files etc */ - private void execute( - final Configuration freemarker, - String file, - final Map<String, Object> paramMap) { - try { - mLoader.setTemplateFile(new File(mRootPath, file)); - Template freemarkerTemplate = freemarker.getTemplate(file); - - StringWriter out = new StringWriter(); - freemarkerTemplate.process(paramMap, out); - out.flush(); - String xml = out.toString(); - - // Parse and execute the resulting instruction list. - SAXParserFactory factory = SAXParserFactory.newInstance(); - SAXParser saxParser = factory.newSAXParser(); - - saxParser.parse(new ByteArrayInputStream(xml.getBytes()), - new DefaultHandler() { - @Override - public void startElement(String uri, String localName, String name, - Attributes attributes) - throws SAXException { - if (mNoToAll) { - return; - } - - try { - boolean instantiate = TAG_INSTANTIATE.equals(name); - if (TAG_COPY.equals(name) || instantiate) { - String fromPath = attributes.getValue(ATTR_FROM); - String toPath = attributes.getValue(ATTR_TO); - if (toPath == null || toPath.isEmpty()) { - toPath = attributes.getValue(ATTR_FROM); - toPath = AdtUtils.stripSuffix(toPath, DOT_FTL); - } - IPath to = getTargetPath(toPath); - if (instantiate) { - instantiate(freemarker, paramMap, fromPath, to); - } else { - copyTemplateResource(fromPath, to); - } - } else if (TAG_MERGE.equals(name)) { - String fromPath = attributes.getValue(ATTR_FROM); - String toPath = attributes.getValue(ATTR_TO); - if (toPath == null || toPath.isEmpty()) { - toPath = attributes.getValue(ATTR_FROM); - toPath = AdtUtils.stripSuffix(toPath, DOT_FTL); - } - // Resources in template.xml are located within root/ - IPath to = getTargetPath(toPath); - merge(freemarker, paramMap, fromPath, to); - } else if (name.equals(TAG_OPEN)) { - // The relative path here is within the output directory: - String relativePath = attributes.getValue(ATTR_FILE); - if (relativePath != null && !relativePath.isEmpty()) { - mOpen.add(relativePath); - } - } else if (TAG_DEPENDENCY.equals(name)) { - String dependencyUrl = attributes.getValue(ATTR_MAVEN_URL); - File path; - if (dependencyUrl.contains(MAVEN_SUPPORT_V4)) { - // We assume the revision requirement has been satisfied - // by the wizard - path = AddSupportJarAction.getSupportJarFile(); - } else if (dependencyUrl.contains(MAVEN_SUPPORT_V13)) { - path = AddSupportJarAction.getSupport13JarFile(); - } else if (dependencyUrl.contains(MAVEN_APPCOMPAT)) { - path = null; - mFinalizingActions.add(new Runnable() { - @Override - public void run() { - AddSupportJarAction.installAppCompatLibrary(mProject, true); - } - }); - } else { - path = null; - System.err.println("WARNING: Unknown dependency type"); - } - - if (path != null) { - IPath to = getTargetPath(FD_NATIVE_LIBS +'/' + path.getName()); - try { - copy(path, to); - } catch (IOException ioe) { - AdtPlugin.log(ioe, null); - } - } - } else if (!name.equals("recipe") && !name.equals(TAG_DEPENDENCY)) { //$NON-NLS-1$ - System.err.println("WARNING: Unknown template directive " + name); - } - } catch (Exception e) { - sMostRecentException = e; - AdtPlugin.log(e, null); - } - } - }); - - } catch (Exception e) { - sMostRecentException = e; - AdtPlugin.log(e, null); - } - } - - @NonNull - private File getFullPath(@NonNull String fromPath) { - if (fromPath.startsWith(VALUE_TEMPLATE_DIR)) { - return new File(getTemplateRootFolder(), RESOURCE_ROOT + File.separator - + fromPath.substring(VALUE_TEMPLATE_DIR.length() + 1).replace('/', - File.separatorChar)); - } - 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 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, toPath); - } else { - copyTemplateResource(relativeFrom, toPath); - } - return; - } - - if (!to.getFileExtension().equals(EXT_XML)) { - throw new RuntimeException("Only XML files can be merged at this point: " + to); - } - - String xml = null; - File from = getFullPath(relativeFrom); - if (relativeFrom.endsWith(DOT_FTL)) { - // Perform template substitution of the template prior to merging - mLoader.setTemplateFile(from); - Template template = freemarker.getTemplate(from.getName()); - Writer out = new StringWriter(); - template.process(paramMap, out); - out.flush(); - xml = out.toString(); - } else { - xml = readTemplateTextResource(from); - if (xml == null) { - return; - } - } - - Document currentDocument = DomUtilities.parseStructuredDocument(currentXml); - assert currentDocument != null : currentXml; - Document fragment = DomUtilities.parseStructuredDocument(xml); - assert fragment != null : xml; - - XmlFormatStyle formatStyle = XmlFormatStyle.MANIFEST; - boolean modified; - boolean ok; - String fileName = to.getName(); - if (fileName.equals(SdkConstants.FN_ANDROID_MANIFEST_XML)) { - modified = ok = mergeManifest(currentDocument, fragment); - } else { - // Merge plain XML files - String parentFolderName = to.getParent().getName(); - ResourceFolderType folderType = ResourceFolderType.getFolderType(parentFolderName); - if (folderType != null) { - formatStyle = EclipseXmlPrettyPrinter.getForFile(toPath); - } else { - formatStyle = XmlFormatStyle.FILE; - } - - modified = mergeResourceFile(currentDocument, fragment, folderType, paramMap); - ok = true; - } - - // Finally write out the merged file (formatting etc) - String contents = null; - if (ok) { - if (modified) { - contents = EclipseXmlPrettyPrinter.prettyPrint(currentDocument, - EclipseXmlFormatPreferences.create(), formatStyle, null, - currentXml.endsWith("\n")); //$NON-NLS-1$ - } - } else { - // Just insert into file along with comment, using the "standard" conflict - // syntax that many tools and editors recognize. - String sep = SdkUtils.getLineSeparator(); - contents = - "<<<<<<< Original" + sep - + currentXml + sep - + "=======" + sep - + xml - + ">>>>>>> Added" + sep; - } - - 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(SdkConstants.EXT_XML); - mMergeChanges.add(change); - } - } - - /** Merges the given resource file contents into the given resource file - * @param paramMap */ - private static boolean mergeResourceFile(Document currentDocument, Document fragment, - ResourceFolderType folderType, Map<String, Object> paramMap) { - boolean modified = false; - - // Copy namespace declarations - NamedNodeMap attributes = fragment.getDocumentElement().getAttributes(); - if (attributes != null) { - for (int i = 0, n = attributes.getLength(); i < n; i++) { - Attr attribute = (Attr) attributes.item(i); - if (attribute.getName().startsWith(XMLNS_PREFIX)) { - currentDocument.getDocumentElement().setAttribute(attribute.getName(), - attribute.getValue()); - } - } - } - - // For layouts for example, I want to *append* inside the root all the - // contents of the new file. - // But for resources for example, I want to combine elements which specify - // the same name or id attribute. - // For elements like manifest files we need to insert stuff at the right - // location in a nested way (activities in the application element etc) - // but that doesn't happen for the other file types. - Element root = fragment.getDocumentElement(); - NodeList children = root.getChildNodes(); - List<Node> nodes = new ArrayList<Node>(children.getLength()); - for (int i = children.getLength() - 1; i >= 0; i--) { - Node child = children.item(i); - nodes.add(child); - root.removeChild(child); - } - Collections.reverse(nodes); - - root = currentDocument.getDocumentElement(); - - if (folderType == ResourceFolderType.VALUES) { - // Try to merge items of the same name - Map<String, Node> old = new HashMap<String, Node>(); - NodeList newSiblings = root.getChildNodes(); - for (int i = newSiblings.getLength() - 1; i >= 0; i--) { - Node child = newSiblings.item(i); - if (child.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) child; - String name = getResourceId(element); - if (name != null) { - old.put(name, element); - } - } - } - - for (Node node : nodes) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) node; - String name = getResourceId(element); - Node replace = name != null ? old.get(name) : null; - if (replace != null) { - // There is an existing item with the same id: just replace it - // ACTUALLY -- let's NOT change it. - // Let's say you've used the activity wizard once, and it - // emits some configuration parameter as a resource that - // it depends on, say "padding". Then the user goes and - // tweaks the padding to some other number. - // Now running the wizard a *second* time for some new activity, - // we should NOT go and set the value back to the template's - // default! - //root.replaceChild(node, replace); - - // ... ON THE OTHER HAND... What if it's a parameter class - // (where the template rewrites a common attribute). Here it's - // really confusing if the new parameter is not set. This is - // really an error in the template, since we shouldn't have conflicts - // like that, but we need to do something to help track this down. - AdtPlugin.log(null, - "Warning: Ignoring name conflict in resource file for name %1$s", - name); - } else { - root.appendChild(node); - modified = true; - } - } - } - } else { - // In other file types, such as layouts, just append all the new content - // at the end. - for (Node node : nodes) { - root.appendChild(node); - modified = true; - } - } - return modified; - } - - /** Merges the given manifest fragment into the given manifest file */ - private static boolean mergeManifest(Document currentManifest, Document fragment) { - // TODO change MergerLog.wrapSdkLog by a custom IMergerLog that will create - // and maintain error markers. - - // Transfer package element from manifest to merged in root; required by - // manifest merger - Element fragmentRoot = fragment.getDocumentElement(); - Element manifestRoot = currentManifest.getDocumentElement(); - if (fragmentRoot == null || manifestRoot == null) { - return false; - } - String pkg = fragmentRoot.getAttribute(ATTR_PACKAGE); - if (pkg == null || pkg.isEmpty()) { - pkg = manifestRoot.getAttribute(ATTR_PACKAGE); - if (pkg != null && !pkg.isEmpty()) { - fragmentRoot.setAttribute(ATTR_PACKAGE, pkg); - } - } - - ManifestMerger merger = new ManifestMerger( - MergerLog.wrapSdkLog(AdtPlugin.getDefault()), - new AdtManifestMergeCallback()).setExtractPackagePrefix(true); - return currentManifest != null && - fragment != null && - merger.process(currentManifest, fragment); - } - - /** - * Makes a backup of the given file, if it exists, by renaming it to name~ - * (and removing an old name~ file if it exists) - */ - private static boolean makeBackup(File file) { - if (!file.exists()) { - return true; - } - if (file.isDirectory()) { - return false; - } - - File backupFile = new File(file.getParentFile(), file.getName() + '~'); - if (backupFile.exists()) { - backupFile.delete(); - } - return file.renameTo(backupFile); - } - - private static String getResourceId(Element element) { - String name = element.getAttribute(ATTR_NAME); - if (name == null) { - name = element.getAttribute(ATTR_ID); - } - - return name; - } - - /** Instantiates the given template file into the given output file */ - private void instantiate( - @NonNull final Configuration freemarker, - @NonNull final Map<String, Object> paramMap, - @NonNull String relativeFrom, - @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 - copyTemplateResource(relativeFrom, to); - } else { - File from = getFullPath(relativeFrom); - mLoader.setTemplateFile(from); - Template template = freemarker.getTemplate(from.getName()); - Writer out = new StringWriter(1024); - template.process(paramMap, out); - out.flush(); - String contents = out.toString(); - - contents = format(mProject, contents, to); - IFile targetFile = getTargetFile(to); - TextFileChange change = createNewFileChange(targetFile); - MultiTextEdit rootEdit = new MultiTextEdit(); - rootEdit.addChild(new InsertEdit(0, contents)); - change.setEdit(rootEdit); - mTextChanges.add(change); - } - } - - private static String format(IProject project, String contents, IPath to) { - String name = to.lastSegment(); - if (name.endsWith(DOT_XML)) { - XmlFormatStyle formatStyle = EclipseXmlPrettyPrinter.getForFile(to); - EclipseXmlFormatPreferences prefs = EclipseXmlFormatPreferences.create(); - return EclipseXmlPrettyPrinter.prettyPrint(contents, prefs, formatStyle, null); - } else if (name.endsWith(DOT_JAVA)) { - Map<?, ?> options = null; - if (project != null && project.isAccessible()) { - try { - IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); - if (javaProject != null) { - options = javaProject.getOptions(true); - } - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - } - if (options == null) { - options = JavaCore.getOptions(); - } - - CodeFormatter formatter = ToolFactory.createCodeFormatter(options); - - try { - IDocument doc = new org.eclipse.jface.text.Document(); - // format the file (the meat and potatoes) - doc.set(contents); - TextEdit edit = formatter.format( - CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, - contents, 0, contents.length(), 0, null); - if (edit != null) { - edit.apply(doc); - } - - return doc.get(); - } catch (Exception e) { - AdtPlugin.log(e, null); - } - } - - return contents; - } - - private static TextFileChange createNewFileChange(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) { - @Override - protected IDocument acquireDocument(IProgressMonitor pm) throws CoreException { - IDocument document = super.acquireDocument(pm); - - // In our case, we know we *always* use this TextFileChange - // to *create* files, we're not appending to existing files. - // However, due to the following bug we can end up with cached - // contents of previously deleted files that happened to have the - // same file name: - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=390402 - // Therefore, as a workaround, wipe out the cached contents here - if (document.getLength() > 0) { - try { - document.replace(0, document.getLength(), ""); - } catch (BadLocationException e) { - // pass - } - } - - return document; - } - }; - change.setTextType(fileName.substring(fileName.lastIndexOf('.') + 1)); - return change; - } - - /** - * Returns the list of files to open when the template has been created - * - * @return the list of files to open - */ - @NonNull - public List<String> getFilesToOpen() { - return mOpen; - } - - /** - * Returns the list of actions to perform when the template has been created - * - * @return the list of actions to perform - */ - @NonNull - public List<Runnable> getFinalizingActions() { - return mFinalizingActions; - } - - /** Copy a template resource */ - private final void copyTemplateResource( - @NonNull String relativeFrom, - @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 IFile dest) { - assert dest.exists(); - byte[] existing = AdtUtils.readData(dest); - return Arrays.equals(existing, data); - } - - /** - * Copies the given source file into the given destination file (where the - * source is allowed to be a directory, in which case the whole directory is - * copied recursively) - */ - 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, path.append(child.getName())); - } - } - } else { - IResource dest = mProject.getFile(path); - if (dest.exists() && !(dest instanceof IFile)) {// Don't attempt to overwrite a folder - assert false : dest.getClass().getName(); - 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; - } - } - - 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); - newFile = format(mProject, newFile, path); - - TextFileChange addFile = createNewFileChange(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)); - } - } - } - - /** - * A custom {@link TemplateLoader} which locates and provides templates - * within the plugin .jar file - */ - private static final class MyTemplateLoader implements TemplateLoader { - private String mPrefix; - - public void setPrefix(String prefix) { - mPrefix = prefix; - } - - public void setTemplateFile(File file) { - setTemplateParent(file.getParentFile()); - } - - public void setTemplateParent(File parent) { - mPrefix = parent.getPath(); - } - - @Override - public Reader getReader(Object templateSource, String encoding) throws IOException { - URL url = (URL) templateSource; - return new InputStreamReader(url.openStream(), encoding); - } - - @Override - public long getLastModified(Object templateSource) { - return 0; - } - - @Override - public Object findTemplateSource(String name) throws IOException { - String path = mPrefix != null ? mPrefix + '/' + name : name; - File file = new File(path); - if (file.exists()) { - return file.toURI().toURL(); - } - return null; - } - - @Override - public void closeTemplateSource(Object templateSource) throws IOException { - } - } - - /** - * Validates this template to make sure it's supported - * @param currentMinSdk the minimum SDK in the project, or -1 or 0 if unknown (e.g. codename) - * @param buildApi the build API, or -1 or 0 if unknown (e.g. codename) - * - * @return a status object with the error, or null if there is no problem - */ - @SuppressWarnings("cast") // In Eclipse 3.6.2 cast below is needed - @Nullable - public IStatus validateTemplate(int currentMinSdk, int buildApi) { - TemplateMetadata template = getTemplate(); - if (template == null) { - return null; - } - if (!template.isSupported()) { - String versionString = (String) AdtPlugin.getDefault().getBundle().getHeaders().get( - Constants.BUNDLE_VERSION); - Version version = new Version(versionString); - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("This template requires a more recent version of the " + - "Android Eclipse plugin. Please update from version %1$d.%2$d.%3$d.", - version.getMajor(), version.getMinor(), version.getMicro())); - } - int templateMinSdk = template.getMinSdk(); - if (templateMinSdk > currentMinSdk && currentMinSdk >= 1) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("This template requires a minimum SDK version of at " + - "least %1$d, and the current min version is %2$d", - templateMinSdk, currentMinSdk)); - } - int templateMinBuildApi = template.getMinBuildApi(); - if (templateMinBuildApi > buildApi && buildApi >= 1) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("This template requires a build target API version of at " + - "least %1$d, and the current version is %2$d", - templateMinBuildApi, buildApi)); - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateManager.java deleted file mode 100644 index 30dd09e31..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateManager.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * 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 com.android.SdkConstants.FD_EXTRAS; -import static com.android.SdkConstants.FD_TEMPLATES; -import static com.android.SdkConstants.FD_TOOLS; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TEMPLATE_XML; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.google.common.base.Charsets; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.io.Files; - -import org.w3c.dom.Document; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** Handles locating templates and providing template metadata */ -public class TemplateManager { - private static final Set<String> EXCLUDED_CATEGORIES = Sets.newHashSet("Folder", "Google"); - private static final Set<String> EXCLUDED_FORMFACTORS = Sets.newHashSet("Wear", "TV"); - - TemplateManager() { - } - - /** @return the root folder containing templates */ - @Nullable - public static File getTemplateRootFolder() { - String location = AdtPrefs.getPrefs().getOsSdkFolder(); - if (location != null) { - File folder = new File(location, FD_TOOLS + File.separator + FD_TEMPLATES); - if (folder.isDirectory()) { - return folder; - } - } - - return null; - } - - /** @return the root folder containing extra templates */ - @NonNull - public static List<File> getExtraTemplateRootFolders() { - List<File> folders = new ArrayList<File>(); - String location = AdtPrefs.getPrefs().getOsSdkFolder(); - if (location != null) { - File extras = new File(location, FD_EXTRAS); - if (extras.isDirectory()) { - for (File vendor : AdtUtils.listFiles(extras)) { - if (!vendor.isDirectory()) { - continue; - } - for (File pkg : AdtUtils.listFiles(vendor)) { - if (pkg.isDirectory()) { - File folder = new File(pkg, FD_TEMPLATES); - if (folder.isDirectory()) { - folders.add(folder); - } - } - } - } - - // Legacy - File folder = new File(extras, FD_TEMPLATES); - if (folder.isDirectory()) { - folders.add(folder); - } - } - } - - return folders; - } - - /** - * Returns a template file under the given root, if it exists - * - * @param root the root folder - * @param relativePath the relative path - * @return a template file under the given root, if it exists - */ - @Nullable - public static File getTemplateLocation(@NonNull File root, @NonNull String relativePath) { - File templateRoot = getTemplateRootFolder(); - if (templateRoot != null) { - String rootPath = root.getPath(); - File templateFile = new File(templateRoot, - rootPath.replace('/', File.separatorChar) + File.separator - + relativePath.replace('/', File.separatorChar)); - if (templateFile.exists()) { - return templateFile; - } - } - - return null; - } - - /** - * Returns a template file under one of the available roots, if it exists - * - * @param relativePath the relative path - * @return a template file under one of the available roots, if it exists - */ - @Nullable - public static File getTemplateLocation(@NonNull String relativePath) { - File templateRoot = getTemplateRootFolder(); - if (templateRoot != null) { - File templateFile = new File(templateRoot, - relativePath.replace('/', File.separatorChar)); - if (templateFile.exists()) { - return templateFile; - } - } - - return null; - - } - - /** - * Returns all the templates with the given prefix - * - * @param folder the folder prefix - * @return the available templates - */ - @NonNull - List<File> getTemplates(@NonNull String folder) { - List<File> templates = new ArrayList<File>(); - Map<String, File> templateNames = Maps.newHashMap(); - File root = getTemplateRootFolder(); - if (root != null) { - File[] files = new File(root, folder).listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { // Avoid .DS_Store etc - templates.add(file); - templateNames.put(file.getName(), file); - } - } - } - } - - // Add in templates from extras/ as well. - for (File extra : getExtraTemplateRootFolders()) { - File[] files = new File(extra, folder).listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - File replaces = templateNames.get(file.getName()); - if (replaces != null) { - int compare = compareTemplates(replaces, file); - if (compare > 0) { - int index = templates.indexOf(replaces); - if (index != -1) { - templates.set(index, file); - } else { - templates.add(file); - } - } - } else { - templates.add(file); - } - } - } - } - } - - // Sort by file name (not path as is File's default) - if (templates.size() > 1) { - Collections.sort(templates, new Comparator<File>() { - @Override - public int compare(File file1, File file2) { - return file1.getName().compareTo(file2.getName()); - } - }); - } - - return templates; - } - - /** - * Compare two files, and return the one with the HIGHEST revision, and if - * the same, most recently modified - */ - private int compareTemplates(File file1, File file2) { - TemplateMetadata template1 = getTemplate(file1); - TemplateMetadata template2 = getTemplate(file2); - - if (template1 == null) { - return 1; - } else if (template2 == null) { - return -1; - } else { - int delta = template2.getRevision() - template1.getRevision(); - if (delta == 0) { - delta = (int) (file2.lastModified() - file1.lastModified()); - } - return delta; - } - } - - /** Cache for {@link #getTemplate()} */ - private Map<File, TemplateMetadata> mTemplateMap; - - @Nullable - TemplateMetadata getTemplate(File templateDir) { - if (mTemplateMap != null) { - TemplateMetadata metadata = mTemplateMap.get(templateDir); - if (metadata != null) { - return metadata; - } - } else { - mTemplateMap = Maps.newHashMap(); - } - - try { - File templateFile = new File(templateDir, TEMPLATE_XML); - if (templateFile.isFile()) { - String xml = Files.toString(templateFile, Charsets.UTF_8); - Document doc = DomUtilities.parseDocument(xml, true); - if (doc != null && doc.getDocumentElement() != null) { - TemplateMetadata metadata = new TemplateMetadata(doc); - if (EXCLUDED_CATEGORIES.contains(metadata.getCategory()) || - EXCLUDED_FORMFACTORS.contains(metadata.getFormFactor())) { - return null; - } - mTemplateMap.put(templateDir, metadata); - return metadata; - } - } - } catch (IOException e) { - AdtPlugin.log(e, null); - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java deleted file mode 100644 index 4ce7d74c2..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java +++ /dev/null @@ -1,468 +0,0 @@ -/* - * 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 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_BUILD_API; -import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_REVISION; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_BACKGROUND; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_CLIPART_NAME; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_DESCRIPTION; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_FOREGROUND; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_FORMAT; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_NAME; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_PADDING; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_SHAPE; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_SOURCE_TYPE; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_TEXT; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_TRIM; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_TYPE; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_VALUE; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.CURRENT_FORMAT; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_DEPENDENCY; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_ICONS; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_PARAMETER; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_THUMB; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_FORMFACTOR; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_CATEGORY; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.assetstudiolib.GraphicGenerator; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.assetstudio.AssetType; -import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState; -import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState.SourceType; -import com.android.ide.eclipse.adt.internal.editors.IconFactory; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils; -import com.android.utils.Pair; -import com.google.common.collect.Lists; - -import org.eclipse.core.resources.IProject; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.RGB; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -/** An ADT template along with metadata */ -class TemplateMetadata { - private final Document mDocument; - private final List<Parameter> mParameters; - private final Map<String, Parameter> mParameterMap; - private List<Pair<String, Integer>> mDependencies; - private Integer mMinApi; - private Integer mMinBuildApi; - private Integer mRevision; - private boolean mNoIcons; - private CreateAssetSetWizardState mIconState; - private String mFormFactor; - private String mCategory; - - TemplateMetadata(@NonNull Document document) { - mDocument = document; - - NodeList parameters = mDocument.getElementsByTagName(TAG_PARAMETER); - mParameters = new ArrayList<Parameter>(parameters.getLength()); - mParameterMap = new HashMap<String, Parameter>(parameters.getLength()); - for (int index = 0, max = parameters.getLength(); index < max; index++) { - Element element = (Element) parameters.item(index); - Parameter parameter = new Parameter(this, element); - mParameters.add(parameter); - if (parameter.id != null) { - mParameterMap.put(parameter.id, parameter); - } - } - } - - boolean isSupported() { - String versionString = mDocument.getDocumentElement().getAttribute(ATTR_FORMAT); - if (versionString != null && !versionString.isEmpty()) { - try { - int version = Integer.parseInt(versionString); - return version <= CURRENT_FORMAT; - } catch (NumberFormatException nufe) { - return false; - } - } - - // Older templates without version specified: supported - return true; - } - - @Nullable - String getTitle() { - String name = mDocument.getDocumentElement().getAttribute(ATTR_NAME); - if (name != null && !name.isEmpty()) { - return name; - } - - return null; - } - - @Nullable - String getDescription() { - String description = mDocument.getDocumentElement().getAttribute(ATTR_DESCRIPTION); - if (description != null && !description.isEmpty()) { - return description; - } - - return null; - } - - int getMinSdk() { - if (mMinApi == null) { - mMinApi = 1; - String api = mDocument.getDocumentElement().getAttribute(ATTR_MIN_API); - if (api != null && !api.isEmpty()) { - try { - mMinApi = Integer.parseInt(api); - } catch (NumberFormatException nufe) { - // Templates aren't allowed to contain codenames, should always be an integer - AdtPlugin.log(nufe, null); - mMinApi = 1; - } - } - } - - return mMinApi.intValue(); - } - - int getMinBuildApi() { - if (mMinBuildApi == null) { - mMinBuildApi = 1; - String api = mDocument.getDocumentElement().getAttribute(ATTR_MIN_BUILD_API); - if (api != null && !api.isEmpty()) { - try { - mMinBuildApi = Integer.parseInt(api); - } catch (NumberFormatException nufe) { - // Templates aren't allowed to contain codenames, should always be an integer - AdtPlugin.log(nufe, null); - mMinBuildApi = 1; - } - } - } - - return mMinBuildApi.intValue(); - } - - public int getRevision() { - if (mRevision == null) { - mRevision = 1; - String revision = mDocument.getDocumentElement().getAttribute(ATTR_REVISION); - if (revision != null && !revision.isEmpty()) { - try { - mRevision = Integer.parseInt(revision); - } catch (NumberFormatException nufe) { - AdtPlugin.log(nufe, null); - mRevision = 1; - } - } - } - - return mRevision.intValue(); - } - - public String getFormFactor() { - if (mFormFactor == null) { - mFormFactor = "Mobile"; - - NodeList formfactorDeclarations = mDocument.getElementsByTagName(TAG_FORMFACTOR); - if (formfactorDeclarations.getLength() > 0) { - Element element = (Element) formfactorDeclarations.item(0); - String formFactor = element.getAttribute(ATTR_VALUE); - if (formFactor != null && !formFactor.isEmpty()) { - mFormFactor = formFactor; - } - } - } - return mFormFactor; - } - - public String getCategory() { - if (mCategory == null) { - mCategory = ""; - NodeList categories = mDocument.getElementsByTagName(TAG_CATEGORY); - if (categories.getLength() > 0) { - Element element = (Element) categories.item(0); - String category = element.getAttribute(ATTR_VALUE); - if (category != null && !category.isEmpty()) { - mCategory = category; - } - } - } - return mCategory; - } - - /** - * Returns a suitable icon wizard state instance if this wizard requests - * icons to be created, and null otherwise - * - * @return icon wizard state or null - */ - @Nullable - public CreateAssetSetWizardState getIconState(IProject project) { - if (mIconState == null && !mNoIcons) { - NodeList icons = mDocument.getElementsByTagName(TAG_ICONS); - if (icons.getLength() < 1) { - mNoIcons = true; - return null; - } - Element icon = (Element) icons.item(0); - - mIconState = new CreateAssetSetWizardState(); - mIconState.project = project; - - String typeString = getAttributeOrNull(icon, ATTR_TYPE); - if (typeString != null) { - typeString = typeString.toUpperCase(Locale.US); - boolean found = false; - for (AssetType type : AssetType.values()) { - if (typeString.equals(type.name())) { - mIconState.type = type; - found = true; - break; - } - } - if (!found) { - AdtPlugin.log(null, "Unknown asset type %1$s", typeString); - } - } - - mIconState.outputName = getAttributeOrNull(icon, ATTR_NAME); - if (mIconState.outputName != null) { - // Register parameter such that if it is referencing other values, it gets - // updated when other values are edited - Parameter outputParameter = new Parameter(this, - Parameter.Type.STRING, "_iconname", mIconState.outputName); //$NON-NLS-1$ - getParameters().add(outputParameter); - } - - RGB background = getRgb(icon, ATTR_BACKGROUND); - if (background != null) { - mIconState.background = background; - } - RGB foreground = getRgb(icon, ATTR_FOREGROUND); - if (foreground != null) { - mIconState.foreground = foreground; - } - String shapeString = getAttributeOrNull(icon, ATTR_SHAPE); - if (shapeString != null) { - shapeString = shapeString.toUpperCase(Locale.US); - boolean found = false; - for (GraphicGenerator.Shape shape : GraphicGenerator.Shape.values()) { - if (shapeString.equals(shape.name())) { - mIconState.shape = shape; - found = true; - break; - } - } - if (!found) { - AdtPlugin.log(null, "Unknown shape %1$s", shapeString); - } - } - String trimString = getAttributeOrNull(icon, ATTR_TRIM); - if (trimString != null) { - mIconState.trim = Boolean.valueOf(trimString); - } - String paddingString = getAttributeOrNull(icon, ATTR_PADDING); - if (paddingString != null) { - mIconState.padding = Integer.parseInt(paddingString); - } - String sourceTypeString = getAttributeOrNull(icon, ATTR_SOURCE_TYPE); - if (sourceTypeString != null) { - sourceTypeString = sourceTypeString.toUpperCase(Locale.US); - boolean found = false; - for (SourceType type : SourceType.values()) { - if (sourceTypeString.equals(type.name())) { - mIconState.sourceType = type; - found = true; - break; - } - } - if (!found) { - AdtPlugin.log(null, "Unknown source type %1$s", sourceTypeString); - } - } - mIconState.clipartName = getAttributeOrNull(icon, ATTR_CLIPART_NAME); - - String textString = getAttributeOrNull(icon, ATTR_TEXT); - if (textString != null) { - mIconState.text = textString; - } - } - - return mIconState; - } - - void updateIconName(List<Parameter> parameters, StringEvaluator evaluator) { - if (mIconState != null) { - NodeList icons = mDocument.getElementsByTagName(TAG_ICONS); - if (icons.getLength() < 1) { - return; - } - Element icon = (Element) icons.item(0); - String name = getAttributeOrNull(icon, ATTR_NAME); - if (name != null) { - mIconState.outputName = evaluator.evaluate(name, parameters); - } - } - } - - private static RGB getRgb(@NonNull Element element, @NonNull String name) { - String colorString = getAttributeOrNull(element, name); - if (colorString != null) { - int rgb = ImageUtils.getColor(colorString.trim()); - return ImageUtils.intToRgb(rgb); - } - - return null; - } - - @Nullable - private static String getAttributeOrNull(@NonNull Element element, @NonNull String name) { - String value = element.getAttribute(name); - if (value != null && value.isEmpty()) { - return null; - } - return value; - } - - @Nullable - String getThumbnailPath() { - // Apply selector logic. Pick the thumb first thumb that satisfies the largest number - // of conditions. - NodeList thumbs = mDocument.getElementsByTagName(TAG_THUMB); - if (thumbs.getLength() == 0) { - return null; - } - - - int bestMatchCount = 0; - Element bestMatch = null; - - for (int i = 0, n = thumbs.getLength(); i < n; i++) { - Element thumb = (Element) thumbs.item(i); - - NamedNodeMap attributes = thumb.getAttributes(); - if (bestMatch == null && attributes.getLength() == 0) { - bestMatch = thumb; - } else if (attributes.getLength() <= bestMatchCount) { - // Already have a match with this number of attributes, no point checking - continue; - } else { - boolean match = true; - for (int j = 0, max = attributes.getLength(); j < max; j++) { - Attr attribute = (Attr) attributes.item(j); - Parameter parameter = mParameterMap.get(attribute.getName()); - if (parameter == null) { - AdtPlugin.log(null, "Unexpected parameter in template thumbnail: %1$s", - attribute.getName()); - continue; - } - String thumbNailValue = attribute.getValue(); - String editedValue = parameter.value != null ? parameter.value.toString() : ""; - if (!thumbNailValue.equals(editedValue)) { - match = false; - break; - } - } - if (match) { - bestMatch = thumb; - bestMatchCount = attributes.getLength(); - } - } - } - - if (bestMatch != null) { - NodeList children = bestMatch.getChildNodes(); - for (int i = 0, n = children.getLength(); i < n; i++) { - Node child = children.item(i); - if (child.getNodeType() == Node.TEXT_NODE) { - return child.getNodeValue().trim(); - } - } - } - - return null; - } - - /** - * Returns the dependencies (as a list of pairs of names and revisions) - * required by this template - */ - List<Pair<String, Integer>> getDependencies() { - if (mDependencies == null) { - NodeList elements = mDocument.getElementsByTagName(TAG_DEPENDENCY); - if (elements.getLength() == 0) { - return Collections.emptyList(); - } - - List<Pair<String, Integer>> dependencies = Lists.newArrayList(); - for (int i = 0, n = elements.getLength(); i < n; i++) { - Element element = (Element) elements.item(i); - String name = element.getAttribute(ATTR_NAME); - int revision = -1; - String revisionString = element.getAttribute(ATTR_REVISION); - if (!revisionString.isEmpty()) { - revision = Integer.parseInt(revisionString); - } - dependencies.add(Pair.of(name, revision)); - } - mDependencies = dependencies; - } - - return mDependencies; - } - - /** Returns the list of available parameters */ - @NonNull - List<Parameter> getParameters() { - return mParameters; - } - - /** - * Returns the parameter of the given id, or null if not found - * - * @param id the id of the target parameter - * @return the corresponding parameter, or null if not found - */ - @Nullable - public Parameter getParameter(@NonNull String id) { - for (Parameter parameter : mParameters) { - if (id.equals(parameter.id)) { - return parameter; - } - } - - return null; - } - - /** Returns a default icon for templates */ - static Image getDefaultTemplateIcon() { - return IconFactory.getInstance().getIcon("default_template"); //$NON-NLS-1$ - } -} 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 deleted file mode 100644 index c3d28fcf2..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplatePreviewPage.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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/TemplateTestPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateTestPage.java deleted file mode 100644 index e461d5597..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateTestPage.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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.jface.dialogs.IMessageProvider; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.io.File; - -/** For template developers: Test local template directory */ -public class TemplateTestPage extends WizardPage - implements SelectionListener, ModifyListener { - private Text mLocation; - private Button mButton; - private static String sLocation; // Persist between repeated invocations - private Button mProjectToggle; - private File mTemplate; - - TemplateTestPage() { - super("testWizardPage"); //$NON-NLS-1$ - setTitle("Wizard Tester"); - setDescription("Test a new template"); - } - - @SuppressWarnings("unused") // SWT constructors have side effects and aren't unused - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - setControl(container); - container.setLayout(new GridLayout(3, false)); - - Label label = new Label(container, SWT.NONE); - label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - label.setText("Template Location:"); - - mLocation = new Text(container, SWT.BORDER); - GridData gd_mLocation = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); - gd_mLocation.widthHint = 400; - mLocation.setLayoutData(gd_mLocation); - if (sLocation != null) { - mLocation.setText(sLocation); - } - mLocation.addModifyListener(this); - - mButton = new Button(container, SWT.FLAT); - mButton.setText("..."); - - mProjectToggle = new Button(container, SWT.CHECK); - mProjectToggle.setEnabled(false); - mProjectToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); - mProjectToggle.setText("Full project template"); - new Label(container, SWT.NONE); - mButton.addSelectionListener(this); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - validatePage(); - } - - private boolean validatePage() { - String error = null; - - String path = mLocation.getText().trim(); - if (path == null || path.length() == 0) { - error = "Select a template directory"; - mTemplate = null; - } else { - mTemplate = new File(path); - if (!mTemplate.exists()) { - error = String.format("%1$s does not exist", path); - } else { - // Preserve across wizard sessions - sLocation = path; - - if (mTemplate.isDirectory()) { - if (!new File(mTemplate, TemplateHandler.TEMPLATE_XML).exists()) { - error = String.format("Not a template: missing template.xml file in %1$s ", - path); - } - } else { - if (mTemplate.getName().equals(TemplateHandler.TEMPLATE_XML)) { - mTemplate = mTemplate.getParentFile(); - } else { - error = String.format("Select a directory containing a template"); - } - } - } - } - - setPageComplete(error == null); - if (error != null) { - setMessage(error, IMessageProvider.ERROR); - } else { - setErrorMessage(null); - setMessage(null); - } - - return error == null; - } - - @Override - public void modifyText(ModifyEvent e) { - validatePage(); - } - - @Override - public void widgetSelected(SelectionEvent e) { - if (e.getSource() == mButton) { - DirectoryDialog dialog = new DirectoryDialog(mButton.getShell(), SWT.OPEN); - String path = mLocation.getText().trim(); - if (path.length() > 0) { - dialog.setFilterPath(path); - } - String file = dialog.open(); - if (file != null) { - mLocation.setText(file); - } - } - - validatePage(); - } - - File getLocation() { - return mTemplate; - } - - boolean isProjectTemplate() { - return mProjectToggle.getSelection(); - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateTestWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateTestWizard.java deleted file mode 100644 index b3b1ef2f4..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateTestWizard.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.core.resources.IProject; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.ui.IWorkbench; - -import java.io.File; - -/** - * Template wizard which creates parameterized templates - */ -public class TemplateTestWizard extends NewTemplateWizard { - private TemplateTestPage mSelectionPage; - private IProject mProject; - - /** Creates a new wizard for testing template definitions in a local directory */ - public TemplateTestWizard() { - super(""); - } - - @Override - public void init(IWorkbench workbench, IStructuredSelection selection) { - super.init(workbench, selection); - if (mValues != null) { - mProject = mValues.project; - } - - mMainPage = null; - mValues = null; - - mSelectionPage = new TemplateTestPage(); - } - - @Override - public void addPages() { - addPage(mSelectionPage); - } - - @Override - public IWizardPage getNextPage(IWizardPage page) { - if (page == mSelectionPage) { - File file = mSelectionPage.getLocation(); - if (file != null && file.exists()) { - if (mValues == null) { - mValues = new NewTemplateWizardState(); - mValues.setTemplateLocation(file); - mValues.project = mProject; - hideBuiltinParameters(); - - mMainPage = new NewTemplatePage(mValues, true); - addPage(mMainPage); - } else { - mValues.setTemplateLocation(file); - } - - return mMainPage; - } - } - - return super.getNextPage(page); - } -} 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 deleted file mode 100644 index 7ca32f91f..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateWizard.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 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.assetstudio.ConfigureAssetSetPage; -import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState; -import com.android.ide.eclipse.adt.internal.editors.IconFactory; -import com.google.common.collect.Lists; - -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.swt.widgets.Display; -import org.eclipse.ui.INewWizard; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.actions.WorkspaceModifyOperation; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.swing.SwingUtilities; - -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 ConfigureAssetSetPage mIconPage; - - protected TemplateWizard() { - } - - /** Should this wizard add an icon page? */ - protected boolean shouldAddIconPage() { - return false; - } - - @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); - - // Trigger a check to see if the SDK needs to be reloaded (which will - // invoke onSdkLoaded asynchronously as needed). - AdtPlugin.getDefault().refreshSdk(); - } - - @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 getIconPage(CreateAssetSetWizardState iconState) { - if (mIconPage == null) { - mIconPage = new ConfigureAssetSetPage(iconState); - mIconPage.setTitle("Configure Icon"); - addPage(mIconPage); - } - - return mIconPage; - } - - 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(); - - /** - * 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<Runnable> getFinalizingActions(); - - /** - * 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; - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TypedVariable.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TypedVariable.java deleted file mode 100644 index 468a10c77..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TypedVariable.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.android.ide.eclipse.adt.internal.wizards.templates; - -import java.util.Locale; - -import org.xml.sax.Attributes; - -public class TypedVariable { - public enum Type { - STRING, - BOOLEAN, - INTEGER; - - public static Type get(String name) { - if (name == null) { - return STRING; - } - try { - return valueOf(name.toUpperCase(Locale.US)); - } catch (IllegalArgumentException e) { - System.err.println("Unexpected global type '" + name + "'"); - System.err.println("Expected one of :"); - for (Type s : Type.values()) { - System.err.println(" " + s.name().toLowerCase(Locale.US)); - } - } - - return STRING; - } - } - - public static Object parseGlobal(Attributes attributes) { - String value = attributes.getValue(TemplateHandler.ATTR_VALUE); - Type type = Type.get(attributes.getValue(TemplateHandler.ATTR_TYPE)); - - switch (type) { - case STRING: - return value; - case BOOLEAN: - return Boolean.parseBoolean(value); - case INTEGER: - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - return value; - } - } - - return value; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/UpdateToolsPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/UpdateToolsPage.java deleted file mode 100644 index 5bbf449d4..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/UpdateToolsPage.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; - -class UpdateToolsPage extends WizardPage implements SelectionListener { - private Button mInstallButton; - UpdateToolsPage() { - super("update"); - setTitle("Update Tools"); - validatePage(); - } - - @Override - public void createControl(Composite parent) { - Composite container = new Composite(parent, SWT.NULL); - setControl(container); - container.setLayout(new GridLayout(1, false)); - - Label label = new Label(container, SWT.WRAP); - GridData layoutData = new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1); - layoutData.widthHint = NewTemplatePage.WIZARD_PAGE_WIDTH - 50; - label.setLayoutData(layoutData); - label.setText( - "Your tools installation appears to be out of date (or not yet installed).\n" + - "\n" + - "This wizard depends on templates distributed with the Android SDK Tools.\n" + - "\n" + - "Please update the tools first (via Window > Android SDK Manager, or by " + - "using the \"android\" command in a terminal window). Note that on Windows " + - "you may need to restart the IDE, since there are some known problems where " + - "Windows locks the files held open by the running IDE, so the updater is " + - "unable to delete them in order to upgrade them."); - - mInstallButton = new Button(container, SWT.NONE); - mInstallButton.setText("Check Again"); - mInstallButton.addSelectionListener(this); - } - - @Override - public boolean isPageComplete() { - return isUpToDate(); - } - - static boolean isUpToDate() { - return TemplateManager.getTemplateRootFolder() != null; - } - - private void validatePage() { - boolean ok = isUpToDate(); - setPageComplete(ok); - if (ok) { - setErrorMessage(null); - setMessage(null); - } else { - setErrorMessage("The tools need to be updated via the SDK Manager"); - } - } - - // ---- Implements SelectionListener ---- - - @Override - public void widgetSelected(SelectionEvent e) { - if (e.getSource() == mInstallButton) { - validatePage(); - } - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } -} |