1 /* 2 * Copyright (C) 2012 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 package com.android.ide.eclipse.adt.internal.wizards.templates; 17 18 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.internal.wizards.newproject.WorkingSetGroup; 21 import com.android.ide.eclipse.adt.internal.wizards.newproject.WorkingSetHelper; 22 23 import org.eclipse.core.runtime.IPath; 24 import org.eclipse.core.runtime.IStatus; 25 import org.eclipse.core.runtime.Platform; 26 import org.eclipse.core.runtime.Status; 27 import org.eclipse.jface.dialogs.IMessageProvider; 28 import org.eclipse.jface.viewers.IStructuredSelection; 29 import org.eclipse.jface.wizard.IWizardPage; 30 import org.eclipse.jface.wizard.WizardPage; 31 import org.eclipse.swt.SWT; 32 import org.eclipse.swt.events.FocusEvent; 33 import org.eclipse.swt.events.FocusListener; 34 import org.eclipse.swt.events.ModifyEvent; 35 import org.eclipse.swt.events.ModifyListener; 36 import org.eclipse.swt.events.SelectionEvent; 37 import org.eclipse.swt.events.SelectionListener; 38 import org.eclipse.swt.layout.GridData; 39 import org.eclipse.swt.layout.GridLayout; 40 import org.eclipse.swt.widgets.Button; 41 import org.eclipse.swt.widgets.Composite; 42 import org.eclipse.swt.widgets.DirectoryDialog; 43 import org.eclipse.swt.widgets.Label; 44 import org.eclipse.swt.widgets.Shell; 45 import org.eclipse.swt.widgets.Text; 46 import org.eclipse.ui.IWorkbenchPart; 47 import org.eclipse.ui.IWorkingSet; 48 49 import java.io.File; 50 51 /** 52 * Second wizard page in the "New Project From Template" wizard 53 */ 54 public class ProjectContentsPage extends WizardPage 55 implements ModifyListener, SelectionListener, FocusListener { 56 57 private final NewProjectWizardState mValues; 58 59 private boolean mIgnore; 60 private Button mCustomIconToggle; 61 private Button mLibraryToggle; 62 63 private Button mUseDefaultLocationToggle; 64 private Label mLocationLabel; 65 private Text mLocationText; 66 private Button mChooseLocationButton; 67 private static String sLastProjectLocation = System.getProperty("user.home"); //$NON-NLS-1$ 68 private Button mCreateActivityToggle; 69 private WorkingSetGroup mWorkingSetGroup; 70 ProjectContentsPage(NewProjectWizardState values)71 ProjectContentsPage(NewProjectWizardState values) { 72 super("newAndroidApp"); //$NON-NLS-1$ 73 mValues = values; 74 setTitle("New Android Application"); 75 setDescription("Configure Project"); 76 77 mWorkingSetGroup = new WorkingSetGroup(); 78 setWorkingSets(new IWorkingSet[0]); 79 } 80 81 @Override createControl(Composite parent)82 public void createControl(Composite parent) { 83 Composite container = new Composite(parent, SWT.NULL); 84 setControl(container); 85 GridLayout gl_container = new GridLayout(4, false); 86 gl_container.horizontalSpacing = 10; 87 container.setLayout(gl_container); 88 89 mCustomIconToggle = new Button(container, SWT.CHECK); 90 mCustomIconToggle.setSelection(true); 91 mCustomIconToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 92 mCustomIconToggle.setText("Create custom launcher icon"); 93 mCustomIconToggle.setSelection(mValues.createIcon); 94 mCustomIconToggle.addSelectionListener(this); 95 96 mCreateActivityToggle = new Button(container, SWT.CHECK); 97 mCreateActivityToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 98 4, 1)); 99 mCreateActivityToggle.setText("Create activity"); 100 mCreateActivityToggle.setSelection(mValues.createActivity); 101 mCreateActivityToggle.addSelectionListener(this); 102 103 new Label(container, SWT.NONE).setLayoutData( 104 new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 105 106 mLibraryToggle = new Button(container, SWT.CHECK); 107 mLibraryToggle.setSelection(true); 108 mLibraryToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 109 mLibraryToggle.setText("Mark this project as a library"); 110 mLibraryToggle.setSelection(mValues.isLibrary); 111 mLibraryToggle.addSelectionListener(this); 112 113 // Blank line 114 new Label(container, SWT.NONE).setLayoutData( 115 new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 116 117 mUseDefaultLocationToggle = new Button(container, SWT.CHECK); 118 mUseDefaultLocationToggle.setLayoutData( 119 new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 120 mUseDefaultLocationToggle.setText("Create Project in Workspace"); 121 mUseDefaultLocationToggle.addSelectionListener(this); 122 123 mLocationLabel = new Label(container, SWT.NONE); 124 mLocationLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 125 mLocationLabel.setText("Location:"); 126 127 mLocationText = new Text(container, SWT.BORDER); 128 mLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); 129 mLocationText.addModifyListener(this); 130 131 mChooseLocationButton = new Button(container, SWT.NONE); 132 mChooseLocationButton.setText("Browse..."); 133 mChooseLocationButton.addSelectionListener(this); 134 mChooseLocationButton.setEnabled(false); 135 setUseCustomLocation(!mValues.useDefaultLocation); 136 137 new Label(container, SWT.NONE).setLayoutData( 138 new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 139 140 Composite group = mWorkingSetGroup.createControl(container); 141 group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 4, 1)); 142 } 143 144 @Override setVisible(boolean visible)145 public void setVisible(boolean visible) { 146 super.setVisible(visible); 147 148 if (visible) { 149 try { 150 mIgnore = true; 151 mUseDefaultLocationToggle.setSelection(mValues.useDefaultLocation); 152 mLocationText.setText(mValues.projectLocation); 153 } finally { 154 mIgnore = false; 155 } 156 } 157 158 validatePage(); 159 } 160 setUseCustomLocation(boolean en)161 private void setUseCustomLocation(boolean en) { 162 mValues.useDefaultLocation = !en; 163 mUseDefaultLocationToggle.setSelection(!en); 164 if (!en) { 165 updateProjectLocation(mValues.projectName); 166 } 167 168 mLocationLabel.setEnabled(en); 169 mLocationText.setEnabled(en); 170 mChooseLocationButton.setEnabled(en); 171 } 172 init(IStructuredSelection selection, IWorkbenchPart activePart)173 void init(IStructuredSelection selection, IWorkbenchPart activePart) { 174 setWorkingSets(WorkingSetHelper.getSelectedWorkingSet(selection, activePart)); 175 } 176 177 /** 178 * Returns the working sets to which the new project should be added. 179 * 180 * @return the selected working sets to which the new project should be added 181 */ getWorkingSets()182 private IWorkingSet[] getWorkingSets() { 183 return mWorkingSetGroup.getSelectedWorkingSets(); 184 } 185 186 /** 187 * Sets the working sets to which the new project should be added. 188 * 189 * @param workingSets the initial selected working sets 190 */ setWorkingSets(IWorkingSet[] workingSets)191 private void setWorkingSets(IWorkingSet[] workingSets) { 192 assert workingSets != null; 193 mWorkingSetGroup.setWorkingSets(workingSets); 194 } 195 196 @Override getNextPage()197 public IWizardPage getNextPage() { 198 // Sync working set data to the value object, since the WorkingSetGroup 199 // doesn't let us add listeners to do this lazily 200 mValues.workingSets = getWorkingSets(); 201 202 return super.getNextPage(); 203 } 204 205 // ---- Implements ModifyListener ---- 206 207 @Override modifyText(ModifyEvent e)208 public void modifyText(ModifyEvent e) { 209 if (mIgnore) { 210 return; 211 } 212 213 Object source = e.getSource(); 214 if (source == mLocationText) { 215 mValues.projectLocation = mLocationText.getText().trim(); 216 } 217 218 validatePage(); 219 } 220 221 222 /** If the project should be created in the workspace, then update the project location 223 * based on the project name. */ updateProjectLocation(String projectName)224 private void updateProjectLocation(String projectName) { 225 if (projectName == null) { 226 projectName = ""; 227 } 228 229 boolean useDefaultLocation = mUseDefaultLocationToggle.getSelection(); 230 231 if (useDefaultLocation) { 232 IPath workspace = Platform.getLocation(); 233 String projectLocation = workspace.append(projectName).toOSString(); 234 mLocationText.setText(projectLocation); 235 mValues.projectLocation = projectLocation; 236 } 237 } 238 239 // ---- Implements SelectionListener ---- 240 241 @Override widgetSelected(SelectionEvent e)242 public void widgetSelected(SelectionEvent e) { 243 if (mIgnore) { 244 return; 245 } 246 247 Object source = e.getSource(); 248 if (source == mCustomIconToggle) { 249 mValues.createIcon = mCustomIconToggle.getSelection(); 250 } else if (source == mLibraryToggle) { 251 mValues.isLibrary = mLibraryToggle.getSelection(); 252 } else if (source == mCreateActivityToggle) { 253 mValues.createActivity = mCreateActivityToggle.getSelection(); 254 } else if (source == mUseDefaultLocationToggle) { 255 boolean useDefault = mUseDefaultLocationToggle.getSelection(); 256 setUseCustomLocation(!useDefault); 257 } else if (source == mChooseLocationButton) { 258 String dir = promptUserForLocation(getShell()); 259 if (dir != null) { 260 mLocationText.setText(dir); 261 mValues.projectLocation = dir; 262 } 263 } 264 265 validatePage(); 266 } 267 promptUserForLocation(Shell shell)268 private String promptUserForLocation(Shell shell) { 269 DirectoryDialog dd = new DirectoryDialog(getShell()); 270 dd.setMessage("Select folder where project should be created"); 271 272 String curLocation = mLocationText.getText().trim(); 273 if (!curLocation.isEmpty()) { 274 dd.setFilterPath(curLocation); 275 } else if (sLastProjectLocation != null) { 276 dd.setFilterPath(sLastProjectLocation); 277 } 278 279 String dir = dd.open(); 280 if (dir != null) { 281 sLastProjectLocation = dir; 282 } 283 284 return dir; 285 } 286 287 @Override widgetDefaultSelected(SelectionEvent e)288 public void widgetDefaultSelected(SelectionEvent e) { 289 } 290 291 // ---- Implements FocusListener ---- 292 293 @Override focusGained(FocusEvent e)294 public void focusGained(FocusEvent e) { 295 } 296 297 @Override focusLost(FocusEvent e)298 public void focusLost(FocusEvent e) { 299 } 300 301 // Validation 302 validatePage()303 void validatePage() { 304 IStatus status = validateProjectLocation(); 305 306 setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); 307 if (status != null) { 308 setMessage(status.getMessage(), 309 status.getSeverity() == IStatus.ERROR 310 ? IMessageProvider.ERROR : IMessageProvider.WARNING); 311 } else { 312 setErrorMessage(null); 313 setMessage(null); 314 } 315 } 316 validateLocationInWorkspace(NewProjectWizardState values)317 static IStatus validateLocationInWorkspace(NewProjectWizardState values) { 318 if (values.useDefaultLocation) { 319 return null; 320 } 321 322 // Validate location 323 if (values.projectName != null) { 324 File dest = Platform.getLocation().append(values.projectName).toFile(); 325 if (dest.exists()) { 326 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format( 327 "There is already a file or directory named \"%1$s\" in the selected location.", 328 values.projectName)); 329 } 330 } 331 332 return null; 333 } 334 validateProjectLocation()335 private IStatus validateProjectLocation() { 336 if (mValues.useDefaultLocation) { 337 return validateLocationInWorkspace(mValues); 338 } 339 340 String location = mLocationText.getText(); 341 if (location.trim().isEmpty()) { 342 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 343 "Provide a valid file system location where the project should be created."); 344 } 345 346 File f = new File(location); 347 if (f.exists()) { 348 if (!f.isDirectory()) { 349 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 350 String.format("'%s' is not a valid folder.", location)); 351 } 352 353 File[] children = f.listFiles(); 354 if (children != null && children.length > 0) { 355 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 356 String.format("Folder '%s' is not empty.", location)); 357 } 358 } 359 360 // if the folder doesn't exist, then make sure that the parent 361 // exists and is a writable folder 362 File parent = f.getParentFile(); 363 if (!parent.exists()) { 364 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 365 String.format("Folder '%s' does not exist.", parent.getName())); 366 } 367 368 if (!parent.isDirectory()) { 369 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 370 String.format("'%s' is not a folder.", parent.getName())); 371 } 372 373 if (!parent.canWrite()) { 374 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 375 String.format("'%s' is not writeable.", parent.getName())); 376 } 377 378 return null; 379 } 380 } 381