Home | History | Annotate | Download | only in export
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.eclipse.adt.internal.wizards.export;
     18 
     19 import com.android.ide.eclipse.adt.AndroidConstants;
     20 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
     21 import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
     22 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
     23 import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper;
     24 import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
     25 import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.NonLibraryProjectOnlyFilter;
     26 import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage;
     27 import com.android.sdklib.xml.ManifestData;
     28 
     29 import org.eclipse.core.resources.IFolder;
     30 import org.eclipse.core.resources.IProject;
     31 import org.eclipse.core.runtime.CoreException;
     32 import org.eclipse.jdt.core.IJavaProject;
     33 import org.eclipse.swt.SWT;
     34 import org.eclipse.swt.events.ModifyEvent;
     35 import org.eclipse.swt.events.ModifyListener;
     36 import org.eclipse.swt.events.SelectionAdapter;
     37 import org.eclipse.swt.events.SelectionEvent;
     38 import org.eclipse.swt.graphics.Image;
     39 import org.eclipse.swt.layout.GridData;
     40 import org.eclipse.swt.layout.GridLayout;
     41 import org.eclipse.swt.widgets.Button;
     42 import org.eclipse.swt.widgets.Composite;
     43 import org.eclipse.swt.widgets.Display;
     44 import org.eclipse.swt.widgets.Label;
     45 import org.eclipse.swt.widgets.Text;
     46 
     47 import java.io.File;
     48 
     49 /**
     50  * First Export Wizard Page. Display warning/errors.
     51  */
     52 final class ProjectCheckPage extends ExportWizardPage {
     53     private final static String IMG_ERROR = "error.png"; //$NON-NLS-1$
     54     private final static String IMG_WARNING = "warning.png"; //$NON-NLS-1$
     55 
     56     private final ExportWizard mWizard;
     57     private Display mDisplay;
     58     private Image mError;
     59     private Image mWarning;
     60     private boolean mHasMessage = false;
     61     private Composite mTopComposite;
     62     private Composite mErrorComposite;
     63     private Text mProjectText;
     64     private ProjectChooserHelper mProjectChooserHelper;
     65     private boolean mFirstOnShow = true;
     66 
     67     protected ProjectCheckPage(ExportWizard wizard, String pageName) {
     68         super(pageName);
     69         mWizard = wizard;
     70 
     71         setTitle("Project Checks");
     72         setDescription("Performs a set of checks to make sure the application can be exported.");
     73     }
     74 
     75     public void createControl(Composite parent) {
     76         mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(),
     77                 new NonLibraryProjectOnlyFilter());
     78         mDisplay = parent.getDisplay();
     79 
     80         GridLayout gl = null;
     81         GridData gd = null;
     82 
     83         mTopComposite = new Composite(parent, SWT.NONE);
     84         mTopComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
     85         mTopComposite.setLayout(new GridLayout(1, false));
     86 
     87         // composite for the project selection.
     88         Composite projectComposite = new Composite(mTopComposite, SWT.NONE);
     89         projectComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
     90         projectComposite.setLayout(gl = new GridLayout(3, false));
     91         gl.marginHeight = gl.marginWidth = 0;
     92 
     93         Label label = new Label(projectComposite, SWT.NONE);
     94         label.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
     95         gd.horizontalSpan = 3;
     96         label.setText("Select the project to export:");
     97 
     98         new Label(projectComposite, SWT.NONE).setText("Project:");
     99         mProjectText = new Text(projectComposite, SWT.BORDER);
    100         mProjectText.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
    101         mProjectText.addModifyListener(new ModifyListener() {
    102             public void modifyText(ModifyEvent e) {
    103                 handleProjectNameChange();
    104             }
    105         });
    106 
    107         Button browseButton = new Button(projectComposite, SWT.PUSH);
    108         browseButton.setText("Browse...");
    109         browseButton.addSelectionListener(new SelectionAdapter() {
    110             @Override
    111             public void widgetSelected(SelectionEvent e) {
    112                 IJavaProject javaProject = mProjectChooserHelper.chooseJavaProject(
    113                         mProjectText.getText().trim(),
    114                         "Please select a project to export");
    115 
    116                 if (javaProject != null) {
    117                     IProject project = javaProject.getProject();
    118 
    119                     // set the new name in the text field. The modify listener will take
    120                     // care of updating the status and the ExportWizard object.
    121                     mProjectText.setText(project.getName());
    122                 }
    123             }
    124         });
    125 
    126         setControl(mTopComposite);
    127     }
    128 
    129     @Override
    130     void onShow() {
    131         if (mFirstOnShow) {
    132             // get the project and init the ui
    133             IProject project = mWizard.getProject();
    134             if (project != null) {
    135                 mProjectText.setText(project.getName());
    136             }
    137 
    138             mFirstOnShow = false;
    139         }
    140     }
    141 
    142     private void buildErrorUi(IProject project) {
    143         // Show description the first time
    144         setErrorMessage(null);
    145         setMessage(null);
    146         setPageComplete(true);
    147         mHasMessage = false;
    148 
    149         // composite parent for the warning/error
    150         GridLayout gl = null;
    151         mErrorComposite = new Composite(mTopComposite, SWT.NONE);
    152         mErrorComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    153         gl = new GridLayout(2, false);
    154         gl.marginHeight = gl.marginWidth = 0;
    155         gl.verticalSpacing *= 3; // more spacing than normal.
    156         mErrorComposite.setLayout(gl);
    157 
    158         if (project == null) {
    159             setErrorMessage("Select project to export.");
    160             mHasMessage = true;
    161         } else {
    162             try {
    163                 if (project.hasNature(AndroidConstants.NATURE_DEFAULT) == false) {
    164                     addError(mErrorComposite, "Project is not an Android project.");
    165                 } else {
    166                     // check for errors
    167                     if (ProjectHelper.hasError(project, true))  {
    168                         addError(mErrorComposite, "Project has compilation error(s)");
    169                     }
    170 
    171                     // check the project output
    172                     IFolder outputIFolder = BaseProjectHelper.getOutputFolder(project);
    173                     if (outputIFolder != null) {
    174                         String outputOsPath =  outputIFolder.getLocation().toOSString();
    175                         String apkFilePath =  outputOsPath + File.separator + project.getName() +
    176                                 AndroidConstants.DOT_ANDROID_PACKAGE;
    177 
    178                         File f = new File(apkFilePath);
    179                         if (f.isFile() == false) {
    180                             addError(mErrorComposite,
    181                                     String.format("%1$s/%2$s/%1$s%3$s does not exists!",
    182                                             project.getName(),
    183                                             outputIFolder.getName(),
    184                                             AndroidConstants.DOT_ANDROID_PACKAGE));
    185                         }
    186                     } else {
    187                         addError(mErrorComposite,
    188                                 "Unable to get the output folder of the project!");
    189                     }
    190 
    191 
    192                     // project is an android project, we check the debuggable attribute.
    193                     ManifestData manifestData = AndroidManifestHelper.parseForData(project);
    194                     Boolean debuggable = null;
    195                     if (manifestData != null) {
    196                         debuggable = manifestData.getDebuggable();
    197                     }
    198 
    199                     if (debuggable != null && debuggable == Boolean.TRUE) {
    200                         addWarning(mErrorComposite,
    201                                 "The manifest 'debuggable' attribute is set to true.\nYou should set it to false for applications that you release to the public.");
    202                     }
    203 
    204                     // check for mapview stuff
    205                 }
    206             } catch (CoreException e) {
    207                 // unable to access nature
    208                 addError(mErrorComposite, "Unable to get project nature");
    209             }
    210         }
    211 
    212         if (mHasMessage == false) {
    213             Label label = new Label(mErrorComposite, SWT.NONE);
    214             GridData gd = new GridData(GridData.FILL_HORIZONTAL);
    215             gd.horizontalSpan = 2;
    216             label.setLayoutData(gd);
    217             label.setText("No errors found. Click Next.");
    218         }
    219 
    220         mTopComposite.layout();
    221     }
    222 
    223     /**
    224      * Adds an error label to a {@link Composite} object.
    225      * @param parent the Composite parent.
    226      * @param message the error message.
    227      */
    228     private void addError(Composite parent, String message) {
    229         if (mError == null) {
    230             mError = IconFactory.getInstance().getIcon(IMG_ERROR);
    231         }
    232 
    233         new Label(parent, SWT.NONE).setImage(mError);
    234         Label label = new Label(parent, SWT.NONE);
    235         label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    236         label.setText(message);
    237 
    238         setErrorMessage("Application cannot be exported due to the error(s) below.");
    239         setPageComplete(false);
    240         mHasMessage = true;
    241     }
    242 
    243     /**
    244      * Adds a warning label to a {@link Composite} object.
    245      * @param parent the Composite parent.
    246      * @param message the warning message.
    247      */
    248     private void addWarning(Composite parent, String message) {
    249         if (mWarning == null) {
    250             mWarning = IconFactory.getInstance().getIcon(IMG_WARNING);
    251         }
    252 
    253         new Label(parent, SWT.NONE).setImage(mWarning);
    254         Label label = new Label(parent, SWT.NONE);
    255         label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    256         label.setText(message);
    257 
    258         mHasMessage = true;
    259     }
    260 
    261     /**
    262      * Checks the parameters for correctness, and update the error message and buttons.
    263      */
    264     private void handleProjectNameChange() {
    265         setPageComplete(false);
    266 
    267         if (mErrorComposite != null) {
    268             mErrorComposite.dispose();
    269             mErrorComposite = null;
    270         }
    271 
    272         // update the wizard with the new project
    273         mWizard.setProject(null);
    274 
    275         //test the project name first!
    276         String text = mProjectText.getText().trim();
    277         if (text.length() == 0) {
    278             setErrorMessage("Select project to export.");
    279         } else if (text.matches("[a-zA-Z0-9_ \\.-]+") == false) {
    280             setErrorMessage("Project name contains unsupported characters!");
    281         } else {
    282             IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null);
    283             IProject found = null;
    284             for (IJavaProject javaProject : projects) {
    285                 if (javaProject.getProject().getName().equals(text)) {
    286                     found = javaProject.getProject();
    287                     break;
    288                 }
    289 
    290             }
    291 
    292             if (found != null) {
    293                 setErrorMessage(null);
    294 
    295                 // update the wizard with the new project
    296                 mWizard.setProject(found);
    297 
    298                 // now rebuild the error ui.
    299                 buildErrorUi(found);
    300             } else {
    301                 setErrorMessage(String.format("There is no android project named '%1$s'",
    302                         text));
    303             }
    304         }
    305     }
    306 }
    307