1 /* 2 * Copyright (C) 2011 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.newproject; 17 18 import com.android.SdkConstants; 19 import com.android.ide.eclipse.adt.AdtConstants; 20 import com.android.ide.eclipse.adt.AdtPlugin; 21 import com.android.ide.eclipse.adt.internal.sdk.Sdk; 22 import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener; 23 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; 24 import com.android.sdklib.IAndroidTarget; 25 26 import org.eclipse.core.filesystem.URIUtil; 27 import org.eclipse.core.resources.IProject; 28 import org.eclipse.core.resources.IWorkspace; 29 import org.eclipse.core.resources.ResourcesPlugin; 30 import org.eclipse.core.runtime.IPath; 31 import org.eclipse.core.runtime.IStatus; 32 import org.eclipse.core.runtime.Path; 33 import org.eclipse.core.runtime.Status; 34 import org.eclipse.jdt.core.JavaConventions; 35 import org.eclipse.jface.dialogs.IMessageProvider; 36 import org.eclipse.jface.wizard.WizardPage; 37 import org.eclipse.swt.SWT; 38 import org.eclipse.swt.events.ModifyEvent; 39 import org.eclipse.swt.events.ModifyListener; 40 import org.eclipse.swt.events.SelectionEvent; 41 import org.eclipse.swt.events.SelectionListener; 42 import org.eclipse.swt.layout.GridData; 43 import org.eclipse.swt.layout.GridLayout; 44 import org.eclipse.swt.widgets.Button; 45 import org.eclipse.swt.widgets.Combo; 46 import org.eclipse.swt.widgets.Composite; 47 import org.eclipse.swt.widgets.Label; 48 import org.eclipse.swt.widgets.Text; 49 50 import java.io.File; 51 import java.io.FileFilter; 52 import java.net.URI; 53 54 /** Page where you choose the application name, activity name, and optional test project info */ 55 public class ApplicationInfoPage extends WizardPage implements SelectionListener, ModifyListener, 56 ITargetChangeListener { 57 private static final String JDK_15 = "1.5"; //$NON-NLS-1$ 58 private final static String DUMMY_PACKAGE = "your.package.namespace"; 59 60 /** Suffix added by default to activity names */ 61 static final String ACTIVITY_NAME_SUFFIX = "Activity"; //$NON-NLS-1$ 62 63 private final NewProjectWizardState mValues; 64 65 private Text mApplicationText; 66 private Text mPackageText; 67 private Text mActivityText; 68 private Button mCreateActivityCheckbox; 69 private Combo mSdkCombo; 70 71 private boolean mIgnore; 72 private Button mCreateTestCheckbox; 73 private Text mTestProjectNameText; 74 private Text mTestApplicationText; 75 private Text mTestPackageText; 76 private Label mTestProjectNameLabel; 77 private Label mTestApplicationLabel; 78 private Label mTestPackageLabel; 79 80 /** 81 * Create the wizard. 82 */ ApplicationInfoPage(NewProjectWizardState values)83 ApplicationInfoPage(NewProjectWizardState values) { 84 super("appInfo"); //$NON-NLS-1$ 85 mValues = values; 86 87 setTitle("Application Info"); 88 setDescription("Configure the new Android Project"); 89 AdtPlugin.getDefault().addTargetListener(this); 90 } 91 92 /** 93 * Create contents of the wizard. 94 */ 95 @Override 96 @SuppressWarnings("unused") // Eclipse marks SWT constructors with side effects as unused createControl(Composite parent)97 public void createControl(Composite parent) { 98 Composite container = new Composite(parent, SWT.NULL); 99 container.setLayout(new GridLayout(2, false)); 100 101 Label applicationLabel = new Label(container, SWT.NONE); 102 applicationLabel.setText("Application Name:"); 103 104 mApplicationText = new Text(container, SWT.BORDER); 105 mApplicationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 106 mApplicationText.addModifyListener(this); 107 108 Label packageLabel = new Label(container, SWT.NONE); 109 packageLabel.setText("Package Name:"); 110 111 mPackageText = new Text(container, SWT.BORDER); 112 mPackageText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 113 mPackageText.addModifyListener(this); 114 115 if (mValues.mode != Mode.TEST) { 116 mCreateActivityCheckbox = new Button(container, SWT.CHECK); 117 mCreateActivityCheckbox.setText("Create Activity:"); 118 mCreateActivityCheckbox.addSelectionListener(this); 119 120 mActivityText = new Text(container, SWT.BORDER); 121 mActivityText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 122 mActivityText.addModifyListener(this); 123 } 124 125 Label minSdkLabel = new Label(container, SWT.NONE); 126 minSdkLabel.setText("Minimum SDK:"); 127 128 mSdkCombo = new Combo(container, SWT.NONE); 129 GridData gdSdkCombo = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1); 130 gdSdkCombo.widthHint = 200; 131 mSdkCombo.setLayoutData(gdSdkCombo); 132 mSdkCombo.addSelectionListener(this); 133 mSdkCombo.addModifyListener(this); 134 135 onSdkLoaded(); 136 137 setControl(container); 138 new Label(container, SWT.NONE); 139 new Label(container, SWT.NONE); 140 141 mCreateTestCheckbox = new Button(container, SWT.CHECK); 142 mCreateTestCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); 143 mCreateTestCheckbox.setText("Create a Test Project"); 144 mCreateTestCheckbox.addSelectionListener(this); 145 146 mTestProjectNameLabel = new Label(container, SWT.NONE); 147 mTestProjectNameLabel.setText("Test Project Name:"); 148 149 mTestProjectNameText = new Text(container, SWT.BORDER); 150 mTestProjectNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 151 mTestProjectNameText.addModifyListener(this); 152 153 mTestApplicationLabel = new Label(container, SWT.NONE); 154 mTestApplicationLabel.setText("Test Application:"); 155 156 mTestApplicationText = new Text(container, SWT.BORDER); 157 mTestApplicationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 158 mTestApplicationText.addModifyListener(this); 159 160 mTestPackageLabel = new Label(container, SWT.NONE); 161 mTestPackageLabel.setText("Test Package:"); 162 163 mTestPackageText = new Text(container, SWT.BORDER); 164 mTestPackageText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 165 mTestPackageText.addModifyListener(this); 166 } 167 168 /** Controls whether the options for creating a paired test project should be shown */ showTestOptions(boolean visible)169 private void showTestOptions(boolean visible) { 170 if (mValues.mode == Mode.SAMPLE) { 171 visible = false; 172 } 173 174 mCreateTestCheckbox.setVisible(visible); 175 mTestProjectNameLabel.setVisible(visible); 176 mTestProjectNameText.setVisible(visible); 177 mTestApplicationLabel.setVisible(visible); 178 mTestApplicationText.setVisible(visible); 179 mTestPackageLabel.setVisible(visible); 180 mTestPackageText.setVisible(visible); 181 } 182 183 /** Controls whether the options for creating a paired test project should be enabled */ enableTestOptions(boolean enabled)184 private void enableTestOptions(boolean enabled) { 185 mTestProjectNameLabel.setEnabled(enabled); 186 mTestProjectNameText.setEnabled(enabled); 187 mTestApplicationLabel.setEnabled(enabled); 188 mTestApplicationText.setEnabled(enabled); 189 mTestPackageLabel.setEnabled(enabled); 190 mTestPackageText.setEnabled(enabled); 191 } 192 193 @Override setVisible(boolean visible)194 public void setVisible(boolean visible) { 195 super.setVisible(visible); 196 197 if (visible) { 198 try { 199 mIgnore = true; 200 if (mValues.applicationName != null) { 201 mApplicationText.setText(mValues.applicationName); 202 } 203 if (mValues.packageName != null) { 204 mPackageText.setText(mValues.packageName); 205 } else { 206 mPackageText.setText(DUMMY_PACKAGE); 207 } 208 209 if (mValues.mode != Mode.TEST) { 210 mCreateActivityCheckbox.setSelection(mValues.createActivity); 211 mActivityText.setEnabled(mValues.createActivity); 212 if (mValues.activityName != null) { 213 mActivityText.setText(mValues.activityName); 214 } 215 } 216 if (mValues.minSdk != null && mValues.minSdk.length() > 0) { 217 mSdkCombo.setText(mValues.minSdk); 218 } 219 220 showTestOptions(mValues.mode == Mode.ANY); 221 enableTestOptions(mCreateTestCheckbox.getSelection()); 222 223 if (mValues.testProjectName != null) { 224 mTestProjectNameText.setText(mValues.testProjectName); 225 } 226 if (mValues.testApplicationName != null) { 227 mTestApplicationText.setText(mValues.testApplicationName); 228 } 229 if (mValues.testProjectName != null) { 230 mTestPackageText.setText(mValues.testProjectName); 231 } 232 } finally { 233 mIgnore = false; 234 } 235 } 236 237 // Start focus with the package name, since the other fields are typically assigned 238 // reasonable defaults 239 mPackageText.setFocus(); 240 mPackageText.selectAll(); 241 242 validatePage(); 243 } 244 setSdkTargets(IAndroidTarget[] targets, IAndroidTarget target)245 protected void setSdkTargets(IAndroidTarget[] targets, IAndroidTarget target) { 246 if (targets == null) { 247 targets = new IAndroidTarget[0]; 248 } 249 int selectionIndex = -1; 250 String[] items = new String[targets.length]; 251 for (int i = 0, n = targets.length; i < n; i++) { 252 items[i] = targetLabel(targets[i]); 253 if (targets[i] == target) { 254 selectionIndex = i; 255 } 256 } 257 try { 258 mIgnore = true; 259 mSdkCombo.setItems(items); 260 mSdkCombo.setData(targets); 261 if (selectionIndex != -1) { 262 mSdkCombo.select(selectionIndex); 263 } 264 } finally { 265 mIgnore = false; 266 } 267 } 268 targetLabel(IAndroidTarget target)269 private String targetLabel(IAndroidTarget target) { 270 // In the minimum SDK chooser, show the targets with api number and description, 271 // such as "11 (Android 3.0)" 272 return String.format("%1$s (%2$s)", target.getVersion().getApiString(), 273 target.getFullName()); 274 } 275 276 @Override dispose()277 public void dispose() { 278 AdtPlugin.getDefault().removeTargetListener(this); 279 super.dispose(); 280 } 281 282 @Override isPageComplete()283 public boolean isPageComplete() { 284 // This page is only needed when creating new projects 285 if (mValues.useExisting || mValues.mode != Mode.ANY) { 286 return true; 287 } 288 289 // Ensure that we reach this page 290 if (mValues.packageName == null) { 291 return false; 292 } 293 294 return super.isPageComplete(); 295 } 296 297 @Override modifyText(ModifyEvent e)298 public void modifyText(ModifyEvent e) { 299 if (mIgnore) { 300 return; 301 } 302 303 Object source = e.getSource(); 304 if (source == mSdkCombo) { 305 mValues.minSdk = mSdkCombo.getText().trim(); 306 IAndroidTarget[] targets = (IAndroidTarget[]) mSdkCombo.getData(); 307 // An editable combo will treat item selection the same way as a user edit, 308 // so we need to see if the string looks like a labeled version 309 int index = mSdkCombo.getSelectionIndex(); 310 if (index != -1) { 311 if (index >= 0 && index < targets.length) { 312 IAndroidTarget target = targets[index]; 313 if (targetLabel(target).equals(mValues.minSdk)) { 314 mValues.minSdk = target.getVersion().getApiString(); 315 } 316 } 317 } 318 319 // Ensure that we never pick up the (Android x.y) suffix shown in combobox 320 // for readability 321 int separator = mValues.minSdk.indexOf(' '); 322 if (separator != -1) { 323 mValues.minSdk = mValues.minSdk.substring(0, separator); 324 } 325 mValues.minSdkModifiedByUser = true; 326 mValues.updateSdkTargetToMatchMinSdkVersion(); 327 } else if (source == mApplicationText) { 328 mValues.applicationName = mApplicationText.getText().trim(); 329 mValues.applicationNameModifiedByUser = true; 330 331 if (!mValues.testApplicationNameModified) { 332 mValues.testApplicationName = suggestTestApplicationName(mValues.applicationName); 333 try { 334 mIgnore = true; 335 mTestApplicationText.setText(mValues.testApplicationName); 336 } finally { 337 mIgnore = false; 338 } 339 } 340 341 } else if (source == mPackageText) { 342 mValues.packageName = mPackageText.getText().trim(); 343 mValues.packageNameModifiedByUser = true; 344 345 if (!mValues.testPackageModified) { 346 mValues.testPackageName = suggestTestPackage(mValues.packageName); 347 try { 348 mIgnore = true; 349 mTestPackageText.setText(mValues.testPackageName); 350 } finally { 351 mIgnore = false; 352 } 353 } 354 } else if (source == mActivityText) { 355 mValues.activityName = mActivityText.getText().trim(); 356 mValues.activityNameModifiedByUser = true; 357 } else if (source == mTestApplicationText) { 358 mValues.testApplicationName = mTestApplicationText.getText().trim(); 359 mValues.testApplicationNameModified = true; 360 } else if (source == mTestPackageText) { 361 mValues.testPackageName = mTestPackageText.getText().trim(); 362 mValues.testPackageModified = true; 363 } else if (source == mTestProjectNameText) { 364 mValues.testProjectName = mTestProjectNameText.getText().trim(); 365 mValues.testProjectModified = true; 366 } 367 368 validatePage(); 369 } 370 371 @Override widgetSelected(SelectionEvent e)372 public void widgetSelected(SelectionEvent e) { 373 if (mIgnore) { 374 return; 375 } 376 377 Object source = e.getSource(); 378 379 if (source == mCreateActivityCheckbox) { 380 mValues.createActivity = mCreateActivityCheckbox.getSelection(); 381 mActivityText.setEnabled(mValues.createActivity); 382 } else if (source == mSdkCombo) { 383 int index = mSdkCombo.getSelectionIndex(); 384 IAndroidTarget[] targets = (IAndroidTarget[]) mSdkCombo.getData(); 385 if (index != -1) { 386 if (index >= 0 && index < targets.length) { 387 IAndroidTarget target = targets[index]; 388 // Even though we are showing the logical version name, we place the 389 // actual api number as the minimum SDK 390 mValues.minSdk = target.getVersion().getApiString(); 391 } 392 } else { 393 String text = mSdkCombo.getText(); 394 boolean found = false; 395 for (IAndroidTarget target : targets) { 396 if (targetLabel(target).equals(text)) { 397 mValues.minSdk = target.getVersion().getApiString(); 398 found = true; 399 break; 400 } 401 } 402 if (!found) { 403 mValues.minSdk = text; 404 } 405 } 406 } else if (source == mCreateTestCheckbox) { 407 mValues.createPairProject = mCreateTestCheckbox.getSelection(); 408 enableTestOptions(mValues.createPairProject); 409 if (mValues.createPairProject) { 410 if (mValues.testProjectName == null || mValues.testProjectName.length() == 0) { 411 mValues.testProjectName = suggestTestProjectName(mValues.projectName); 412 } 413 if (mValues.testApplicationName == null || 414 mValues.testApplicationName.length() == 0) { 415 mValues.testApplicationName = 416 suggestTestApplicationName(mValues.applicationName); 417 } 418 if (mValues.testPackageName == null || mValues.testPackageName.length() == 0) { 419 mValues.testPackageName = suggestTestPackage(mValues.packageName); 420 } 421 422 try { 423 mIgnore = true; 424 mTestProjectNameText.setText(mValues.testProjectName); 425 mTestApplicationText.setText(mValues.testApplicationName); 426 mTestPackageText.setText(mValues.testPackageName); 427 } finally { 428 mIgnore = false; 429 } 430 } 431 } 432 433 validatePage(); 434 } 435 436 @Override widgetDefaultSelected(SelectionEvent e)437 public void widgetDefaultSelected(SelectionEvent e) { 438 } 439 validatePage()440 private void validatePage() { 441 IStatus status = validatePackage(mValues.packageName); 442 if (status == null || status.getSeverity() != IStatus.ERROR) { 443 IStatus validActivity = validateActivity(); 444 if (validActivity != null) { 445 status = validActivity; 446 } 447 } 448 if (status == null || status.getSeverity() != IStatus.ERROR) { 449 IStatus validMinSdk = validateMinSdk(); 450 if (validMinSdk != null) { 451 status = validMinSdk; 452 } 453 } 454 455 if (status == null || status.getSeverity() != IStatus.ERROR) { 456 IStatus validSourceFolder = validateSourceFolder(); 457 if (validSourceFolder != null) { 458 status = validSourceFolder; 459 } 460 } 461 462 // If creating a test project to go along with the main project, also validate 463 // the additional test project parameters 464 if (status == null || status.getSeverity() != IStatus.ERROR) { 465 if (mValues.createPairProject) { 466 IStatus validTestProject = ProjectNamePage.validateProjectName( 467 mValues.testProjectName); 468 if (validTestProject != null) { 469 status = validTestProject; 470 } 471 472 if (status == null || status.getSeverity() != IStatus.ERROR) { 473 IStatus validTestLocation = validateTestProjectLocation(); 474 if (validTestLocation != null) { 475 status = validTestLocation; 476 } 477 } 478 479 if (status == null || status.getSeverity() != IStatus.ERROR) { 480 IStatus validTestPackage = validatePackage(mValues.testPackageName); 481 if (validTestPackage != null) { 482 status = new Status(validTestPackage.getSeverity(), 483 AdtPlugin.PLUGIN_ID, 484 validTestPackage.getMessage() + " (in test package)"); 485 } 486 } 487 488 if (status == null || status.getSeverity() != IStatus.ERROR) { 489 if (mValues.projectName.equals(mValues.testProjectName)) { 490 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 491 "The main project name and the test project name must be different."); 492 } 493 } 494 } 495 } 496 497 // -- update UI & enable finish if there's no error 498 setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); 499 if (status != null) { 500 setMessage(status.getMessage(), 501 status.getSeverity() == IStatus.ERROR 502 ? IMessageProvider.ERROR : IMessageProvider.WARNING); 503 } else { 504 setErrorMessage(null); 505 setMessage(null); 506 } 507 } 508 validateTestProjectLocation()509 private IStatus validateTestProjectLocation() { 510 assert mValues.createPairProject; 511 512 // Validate location 513 Path path = new Path(mValues.projectLocation.getPath()); 514 if (!mValues.useExisting) { 515 if (!mValues.useDefaultLocation) { 516 // If not using the default value validate the location. 517 URI uri = URIUtil.toURI(path.toOSString()); 518 IWorkspace workspace = ResourcesPlugin.getWorkspace(); 519 IProject handle = workspace.getRoot().getProject(mValues.testProjectName); 520 IStatus locationStatus = workspace.validateProjectLocationURI(handle, uri); 521 if (!locationStatus.isOK()) { 522 return locationStatus; 523 } 524 // The location is valid as far as Eclipse is concerned (i.e. mostly not 525 // an existing workspace project.) Check it either doesn't exist or is 526 // a directory that is empty. 527 File f = path.toFile(); 528 if (f.exists() && !f.isDirectory()) { 529 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 530 "A directory name must be specified."); 531 } else if (f.isDirectory()) { 532 // However if the directory exists, we should put a 533 // warning if it is not empty. We don't put an error 534 // (we'll ask the user again for confirmation before 535 // using the directory.) 536 String[] l = f.list(); 537 if (l != null && l.length != 0) { 538 return new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, 539 "The selected output directory is not empty."); 540 } 541 } 542 } else { 543 IPath destPath = path.removeLastSegments(1).append(mValues.testProjectName); 544 File dest = destPath.toFile(); 545 if (dest.exists()) { 546 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 547 String.format( 548 "There is already a file or directory named \"%1$s\" in the selected location.", 549 mValues.testProjectName)); 550 } 551 } 552 } 553 554 return null; 555 } 556 validateSourceFolder()557 private IStatus validateSourceFolder() { 558 // This check does nothing when creating a new project. 559 // This check is also useless when no activity is present or created. 560 mValues.sourceFolder = SdkConstants.FD_SOURCES; 561 if (!mValues.useExisting || !mValues.createActivity) { 562 return null; 563 } 564 565 String osTarget = mValues.activityName; 566 if (osTarget.indexOf('.') == -1) { 567 osTarget = mValues.packageName + File.separator + osTarget; 568 } else if (osTarget.indexOf('.') == 0) { 569 osTarget = mValues.packageName + osTarget; 570 } 571 osTarget = osTarget.replace('.', File.separatorChar) + SdkConstants.DOT_JAVA; 572 573 File projectDir = mValues.projectLocation; 574 File[] allDirs = projectDir.listFiles(new FileFilter() { 575 @Override 576 public boolean accept(File pathname) { 577 return pathname.isDirectory(); 578 } 579 }); 580 if (allDirs != null) { 581 boolean found = false; 582 for (File f : allDirs) { 583 Path path = new Path(f.getAbsolutePath()); 584 File java_activity = path.append(osTarget).toFile(); 585 if (java_activity.isFile()) { 586 mValues.sourceFolder = f.getName(); 587 found = true; 588 break; 589 } 590 } 591 592 if (!found) { 593 String projectPath = projectDir.getPath(); 594 if (allDirs.length > 0) { 595 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 596 String.format("%1$s can not be found under %2$s.", osTarget, 597 projectPath)); 598 } else { 599 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 600 String.format("No source folders can be found in %1$s.", 601 projectPath)); 602 } 603 } 604 } 605 606 return null; 607 } 608 validateMinSdk()609 private IStatus validateMinSdk() { 610 // Validate min SDK field 611 // If the min sdk version is empty, it is always accepted. 612 if (mValues.minSdk == null || mValues.minSdk.length() == 0) { 613 return null; 614 } 615 616 IAndroidTarget target = mValues.target; 617 if (target == null) { 618 return null; 619 } 620 621 // If the current target is a preview, explicitly indicate minSdkVersion 622 // must be set to this target name. 623 if (target.getVersion().isPreview() && !target.getVersion().equals(mValues.minSdk)) { 624 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 625 String.format( 626 "The SDK target is a preview. Min SDK Version must be set to '%s'.", 627 target.getVersion().getCodename())); 628 } 629 630 if (!target.getVersion().equals(mValues.minSdk)) { 631 return new Status(target.getVersion().isPreview() ? IStatus.ERROR : IStatus.WARNING, 632 AdtPlugin.PLUGIN_ID, 633 "The API level for the selected SDK target does not match the Min SDK Version." 634 ); 635 } 636 637 return null; 638 } 639 validatePackage(String packageFieldContents)640 public static IStatus validatePackage(String packageFieldContents) { 641 // Validate package 642 if (packageFieldContents == null || packageFieldContents.length() == 0) { 643 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 644 "Package name must be specified."); 645 } else if (packageFieldContents.equals(DUMMY_PACKAGE)) { 646 // The dummy package name is just a placeholder package (which isn't even valid 647 // because it contains the reserved Java keyword "package") but we want to 648 // make the error message say that a proper package should be entered rather than 649 // what's wrong with this specific package. (And the reason we provide a dummy 650 // package rather than a blank line is to make it more clear to beginners what 651 // we're looking for. 652 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 653 "Package name must be specified."); 654 } 655 // Check it's a valid package string 656 IStatus status = JavaConventions.validatePackageName(packageFieldContents, JDK_15, 657 JDK_15); 658 if (!status.isOK()) { 659 return status; 660 } 661 662 // The Android Activity Manager does not accept packages names with only one 663 // identifier. Check the package name has at least one dot in them (the previous rule 664 // validated that if such a dot exist, it's not the first nor last characters of the 665 // string.) 666 if (packageFieldContents.indexOf('.') == -1) { 667 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 668 "Package name must have at least two identifiers."); 669 } 670 671 return null; 672 } 673 validateClass(String className)674 public static IStatus validateClass(String className) { 675 if (className == null || className.length() == 0) { 676 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 677 "Class name must be specified."); 678 } 679 if (className.indexOf('.') != -1) { 680 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 681 "Enter just a class name, not a full package name"); 682 } 683 return JavaConventions.validateJavaTypeName(className, JDK_15, JDK_15); 684 } 685 validateActivity()686 private IStatus validateActivity() { 687 // Validate activity (if creating an activity) 688 if (!mValues.createActivity) { 689 return null; 690 } 691 692 return validateActivity(mValues.activityName); 693 } 694 695 /** 696 * Validates the given activity name 697 * 698 * @param activityFieldContents the activity name to validate 699 * @return a status for whether the activity name is valid 700 */ validateActivity(String activityFieldContents)701 public static IStatus validateActivity(String activityFieldContents) { 702 // Validate activity field 703 if (activityFieldContents == null || activityFieldContents.length() == 0) { 704 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 705 "Activity name must be specified."); 706 } else if (ACTIVITY_NAME_SUFFIX.equals(activityFieldContents)) { 707 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Enter a valid activity name"); 708 } else if (activityFieldContents.contains("..")) { //$NON-NLS-1$ 709 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 710 "Package segments in activity name cannot be empty (..)"); 711 } 712 // The activity field can actually contain part of a sub-package name 713 // or it can start with a dot "." to indicates it comes from the parent package 714 // name. 715 String packageName = ""; //$NON-NLS-1$ 716 int pos = activityFieldContents.lastIndexOf('.'); 717 if (pos >= 0) { 718 packageName = activityFieldContents.substring(0, pos); 719 if (packageName.startsWith(".")) { //$NON-NLS-1$ 720 packageName = packageName.substring(1); 721 } 722 723 activityFieldContents = activityFieldContents.substring(pos + 1); 724 } 725 726 // the activity field can contain a simple java identifier, or a 727 // package name or one that starts with a dot. So if it starts with a dot, 728 // ignore this dot -- the rest must look like a package name. 729 if (activityFieldContents.length() > 0 && activityFieldContents.charAt(0) == '.') { 730 activityFieldContents = activityFieldContents.substring(1); 731 } 732 733 // Check it's a valid activity string 734 IStatus status = JavaConventions.validateTypeVariableName(activityFieldContents, JDK_15, 735 JDK_15); 736 if (!status.isOK()) { 737 return status; 738 } 739 740 // Check it's a valid package string 741 if (packageName.length() > 0) { 742 status = JavaConventions.validatePackageName(packageName, JDK_15, JDK_15); 743 if (!status.isOK()) { 744 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 745 status.getMessage() + " (in the activity name)"); 746 } 747 } 748 749 return null; 750 } 751 752 // ---- Implement ITargetChangeListener ---- 753 754 @Override onSdkLoaded()755 public void onSdkLoaded() { 756 if (mSdkCombo == null) { 757 return; 758 } 759 760 // Update the sdk target selector with the new targets 761 762 // get the targets from the sdk 763 IAndroidTarget[] targets = null; 764 if (Sdk.getCurrent() != null) { 765 targets = Sdk.getCurrent().getTargets(); 766 } 767 setSdkTargets(targets, mValues.target); 768 } 769 770 @Override onProjectTargetChange(IProject changedProject)771 public void onProjectTargetChange(IProject changedProject) { 772 // Ignore 773 } 774 775 @Override onTargetLoaded(IAndroidTarget target)776 public void onTargetLoaded(IAndroidTarget target) { 777 // Ignore 778 } 779 suggestTestApplicationName(String applicationName)780 public static String suggestTestApplicationName(String applicationName) { 781 if (applicationName == null) { 782 applicationName = ""; //$NON-NLS-1$ 783 } 784 if (applicationName.indexOf(' ') != -1) { 785 return applicationName + " Test"; //$NON-NLS-1$ 786 } else { 787 return applicationName + "Test"; //$NON-NLS-1$ 788 } 789 } 790 suggestTestProjectName(String projectName)791 public static String suggestTestProjectName(String projectName) { 792 if (projectName == null) { 793 projectName = ""; //$NON-NLS-1$ 794 } 795 if (projectName.length() > 0 && Character.isUpperCase(projectName.charAt(0))) { 796 return projectName + "Test"; //$NON-NLS-1$ 797 } else { 798 return projectName + "-test"; //$NON-NLS-1$ 799 } 800 } 801 802 suggestTestPackage(String packagePath)803 public static String suggestTestPackage(String packagePath) { 804 if (packagePath == null) { 805 packagePath = ""; //$NON-NLS-1$ 806 } 807 return packagePath + ".test"; //$NON-NLS-1$ 808 } 809 } 810