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.common.xml.ManifestData;
     20 import com.android.ide.eclipse.adt.AdtConstants;
     21 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
     22 import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
     23 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
     24 import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper;
     25 import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.NonLibraryProjectOnlyFilter;
     26 import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
     27 import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard.ExportWizardPage;
     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.Label;
     44 import org.eclipse.swt.widgets.Text;
     45 
     46 /**
     47  * First Export Wizard Page. Display warning/errors.
     48  */
     49 final class ProjectCheckPage extends ExportWizardPage {
     50     private final static String IMG_ERROR = "error.png"; //$NON-NLS-1$
     51     private final static String IMG_WARNING = "warning.png"; //$NON-NLS-1$
     52 
     53     private final ExportWizard mWizard;
     54     private Image mError;
     55     private Image mWarning;
     56     private boolean mHasMessage = false;
     57     private Composite mTopComposite;
     58     private Composite mErrorComposite;
     59     private Text mProjectText;
     60     private ProjectChooserHelper mProjectChooserHelper;
     61     private boolean mFirstOnShow = true;
     62 
     63     protected ProjectCheckPage(ExportWizard wizard, String pageName) {
     64         super(pageName);
     65         mWizard = wizard;
     66 
     67         setTitle("Project Checks");
     68         setDescription("Performs a set of checks to make sure the application can be exported.");
     69     }
     70 
     71     @Override
     72     public void createControl(Composite parent) {
     73         mProjectChooserHelper = new ProjectChooserHelper(parent.getShell(),
     74                 new NonLibraryProjectOnlyFilter());
     75 
     76         GridLayout gl = null;
     77         GridData gd = null;
     78 
     79         mTopComposite = new Composite(parent, SWT.NONE);
     80         mTopComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
     81         mTopComposite.setLayout(new GridLayout(1, false));
     82 
     83         // composite for the project selection.
     84         Composite projectComposite = new Composite(mTopComposite, SWT.NONE);
     85         projectComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
     86         projectComposite.setLayout(gl = new GridLayout(3, false));
     87         gl.marginHeight = gl.marginWidth = 0;
     88 
     89         Label label = new Label(projectComposite, SWT.NONE);
     90         label.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
     91         gd.horizontalSpan = 3;
     92         label.setText("Select the project to export:");
     93 
     94         new Label(projectComposite, SWT.NONE).setText("Project:");
     95         mProjectText = new Text(projectComposite, SWT.BORDER);
     96         mProjectText.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
     97         mProjectText.addModifyListener(new ModifyListener() {
     98             @Override
     99             public void modifyText(ModifyEvent e) {
    100                 handleProjectNameChange();
    101             }
    102         });
    103 
    104         Button browseButton = new Button(projectComposite, SWT.PUSH);
    105         browseButton.setText("Browse...");
    106         browseButton.addSelectionListener(new SelectionAdapter() {
    107             @Override
    108             public void widgetSelected(SelectionEvent e) {
    109                 IJavaProject javaProject = mProjectChooserHelper.chooseJavaProject(
    110                         mProjectText.getText().trim(),
    111                         "Please select a project to export");
    112 
    113                 if (javaProject != null) {
    114                     IProject project = javaProject.getProject();
    115 
    116                     // set the new name in the text field. The modify listener will take
    117                     // care of updating the status and the ExportWizard object.
    118                     mProjectText.setText(project.getName());
    119                 }
    120             }
    121         });
    122 
    123         setControl(mTopComposite);
    124     }
    125 
    126     @Override
    127     void onShow() {
    128         if (mFirstOnShow) {
    129             // get the project and init the ui
    130             IProject project = mWizard.getProject();
    131             if (project != null) {
    132                 mProjectText.setText(project.getName());
    133             }
    134 
    135             mFirstOnShow = false;
    136         }
    137     }
    138 
    139     private void buildErrorUi(IProject project) {
    140         // Show description the first time
    141         setErrorMessage(null);
    142         setMessage(null);
    143         setPageComplete(true);
    144         mHasMessage = false;
    145 
    146         // composite parent for the warning/error
    147         GridLayout gl = null;
    148         mErrorComposite = new Composite(mTopComposite, SWT.NONE);
    149         mErrorComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    150         gl = new GridLayout(2, false);
    151         gl.marginHeight = gl.marginWidth = 0;
    152         gl.verticalSpacing *= 3; // more spacing than normal.
    153         mErrorComposite.setLayout(gl);
    154 
    155         if (project == null) {
    156             setErrorMessage("Select project to export.");
    157             mHasMessage = true;
    158         } else {
    159             try {
    160                 if (project.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
    161                     addError(mErrorComposite, "Project is not an Android project.");
    162                 } else {
    163                     // check for errors
    164                     if (ProjectHelper.hasError(project, true))  {
    165                         addError(mErrorComposite, "Project has compilation error(s)");
    166                     }
    167 
    168                     // check the project output
    169                     IFolder outputIFolder = BaseProjectHelper.getJavaOutputFolder(project);
    170                     if (outputIFolder == null) {
    171                         addError(mErrorComposite,
    172                                 "Unable to get the output folder of the project!");
    173                     }
    174 
    175                     // project is an android project, we check the debuggable attribute.
    176                     ManifestData manifestData = AndroidManifestHelper.parseForData(project);
    177                     Boolean debuggable = null;
    178                     if (manifestData != null) {
    179                         debuggable = manifestData.getDebuggable();
    180                     }
    181 
    182                     if (debuggable != null && debuggable == Boolean.TRUE) {
    183                         addWarning(mErrorComposite,
    184                                 "The manifest 'debuggable' attribute is set to true.\n" +
    185                                 "You should set it to false for applications that you release to the public.\n\n" +
    186                                 "Applications with debuggable=true are compiled in debug mode always.");
    187                     }
    188 
    189                     // check for mapview stuff
    190                 }
    191             } catch (CoreException e) {
    192                 // unable to access nature
    193                 addError(mErrorComposite, "Unable to get project nature");
    194             }
    195         }
    196 
    197         if (mHasMessage == false) {
    198             Label label = new Label(mErrorComposite, SWT.NONE);
    199             GridData gd = new GridData(GridData.FILL_HORIZONTAL);
    200             gd.horizontalSpan = 2;
    201             label.setLayoutData(gd);
    202             label.setText("No errors found. Click Next.");
    203         }
    204 
    205         mTopComposite.layout();
    206     }
    207 
    208     /**
    209      * Adds an error label to a {@link Composite} object.
    210      * @param parent the Composite parent.
    211      * @param message the error message.
    212      */
    213     private void addError(Composite parent, String message) {
    214         if (mError == null) {
    215             mError = IconFactory.getInstance().getIcon(IMG_ERROR);
    216         }
    217 
    218         new Label(parent, SWT.NONE).setImage(mError);
    219         Label label = new Label(parent, SWT.NONE);
    220         label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    221         label.setText(message);
    222 
    223         setErrorMessage("Application cannot be exported due to the error(s) below.");
    224         setPageComplete(false);
    225         mHasMessage = true;
    226     }
    227 
    228     /**
    229      * Adds a warning label to a {@link Composite} object.
    230      * @param parent the Composite parent.
    231      * @param message the warning message.
    232      */
    233     private void addWarning(Composite parent, String message) {
    234         if (mWarning == null) {
    235             mWarning = IconFactory.getInstance().getIcon(IMG_WARNING);
    236         }
    237 
    238         new Label(parent, SWT.NONE).setImage(mWarning);
    239         Label label = new Label(parent, SWT.NONE);
    240         label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    241         label.setText(message);
    242 
    243         mHasMessage = true;
    244     }
    245 
    246     /**
    247      * Checks the parameters for correctness, and update the error message and buttons.
    248      */
    249     private void handleProjectNameChange() {
    250         setPageComplete(false);
    251 
    252         if (mErrorComposite != null) {
    253             mErrorComposite.dispose();
    254             mErrorComposite = null;
    255         }
    256 
    257         // update the wizard with the new project
    258         mWizard.setProject(null);
    259 
    260         //test the project name first!
    261         String text = mProjectText.getText().trim();
    262         if (text.length() == 0) {
    263             setErrorMessage("Select project to export.");
    264         } else if (text.matches("[a-zA-Z0-9_ \\.-]+") == false) {
    265             setErrorMessage("Project name contains unsupported characters!");
    266         } else {
    267             IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null);
    268             IProject found = null;
    269             for (IJavaProject javaProject : projects) {
    270                 if (javaProject.getProject().getName().equals(text)) {
    271                     found = javaProject.getProject();
    272                     break;
    273                 }
    274 
    275             }
    276 
    277             if (found != null) {
    278                 setErrorMessage(null);
    279 
    280                 // update the wizard with the new project
    281                 mWizard.setProject(found);
    282 
    283                 // now rebuild the error ui.
    284                 buildErrorUi(found);
    285             } else {
    286                 setErrorMessage(String.format("There is no android project named '%1$s'",
    287                         text));
    288             }
    289         }
    290     }
    291 }
    292