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