1 /* 2 * Copyright (C) 2007 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.editors.manifest.model; 18 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.AdtConstants; 21 import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; 22 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; 23 import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor; 24 import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors; 25 import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper; 26 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; 27 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiTextAttributeNode; 28 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; 29 import com.android.sdklib.SdkConstants; 30 import com.android.sdklib.xml.AndroidManifest; 31 32 import org.eclipse.core.resources.IFile; 33 import org.eclipse.core.resources.IProject; 34 import org.eclipse.core.runtime.CoreException; 35 import org.eclipse.core.runtime.NullProgressMonitor; 36 import org.eclipse.jdt.core.Flags; 37 import org.eclipse.jdt.core.IClasspathEntry; 38 import org.eclipse.jdt.core.IJavaElement; 39 import org.eclipse.jdt.core.IJavaProject; 40 import org.eclipse.jdt.core.IPackageFragment; 41 import org.eclipse.jdt.core.IPackageFragmentRoot; 42 import org.eclipse.jdt.core.IType; 43 import org.eclipse.jdt.core.ITypeHierarchy; 44 import org.eclipse.jdt.core.JavaCore; 45 import org.eclipse.jdt.core.JavaModelException; 46 import org.eclipse.jdt.core.search.IJavaSearchScope; 47 import org.eclipse.jdt.core.search.SearchEngine; 48 import org.eclipse.jdt.ui.IJavaElementSearchConstants; 49 import org.eclipse.jdt.ui.JavaUI; 50 import org.eclipse.jdt.ui.actions.OpenNewClassWizardAction; 51 import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension; 52 import org.eclipse.jdt.ui.dialogs.ITypeInfoRequestor; 53 import org.eclipse.jdt.ui.dialogs.ITypeSelectionComponent; 54 import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension; 55 import org.eclipse.jdt.ui.wizards.NewClassWizardPage; 56 import org.eclipse.jface.dialogs.IMessageProvider; 57 import org.eclipse.jface.window.Window; 58 import org.eclipse.swt.SWT; 59 import org.eclipse.swt.events.DisposeEvent; 60 import org.eclipse.swt.events.DisposeListener; 61 import org.eclipse.swt.events.ModifyEvent; 62 import org.eclipse.swt.events.ModifyListener; 63 import org.eclipse.swt.events.SelectionAdapter; 64 import org.eclipse.swt.events.SelectionEvent; 65 import org.eclipse.swt.layout.GridData; 66 import org.eclipse.swt.layout.GridLayout; 67 import org.eclipse.swt.widgets.Button; 68 import org.eclipse.swt.widgets.Composite; 69 import org.eclipse.swt.widgets.Control; 70 import org.eclipse.swt.widgets.Text; 71 import org.eclipse.ui.IEditorInput; 72 import org.eclipse.ui.IFileEditorInput; 73 import org.eclipse.ui.PartInitException; 74 import org.eclipse.ui.PlatformUI; 75 import org.eclipse.ui.dialogs.SelectionDialog; 76 import org.eclipse.ui.forms.IManagedForm; 77 import org.eclipse.ui.forms.events.HyperlinkAdapter; 78 import org.eclipse.ui.forms.events.HyperlinkEvent; 79 import org.eclipse.ui.forms.widgets.FormText; 80 import org.eclipse.ui.forms.widgets.FormToolkit; 81 import org.eclipse.ui.forms.widgets.TableWrapData; 82 import org.w3c.dom.Element; 83 84 import java.util.ArrayList; 85 86 /** 87 * Represents an XML attribute for a class, that can be modified using a simple text field or 88 * a dialog to choose an existing class. Also, there's a link to create a new class. 89 * <p/> 90 * See {@link UiTextAttributeNode} for more information. 91 */ 92 public class UiClassAttributeNode extends UiTextAttributeNode { 93 94 private String mReferenceClass; 95 private IPostTypeCreationAction mPostCreationAction; 96 private boolean mMandatory; 97 private final boolean mDefaultToProjectOnly; 98 99 private class HierarchyTypeSelection extends TypeSelectionExtension { 100 101 private IJavaProject mJavaProject; 102 private IType mReferenceType; 103 private Button mProjectOnly; 104 private boolean mUseProjectOnly; 105 106 public HierarchyTypeSelection(IProject project, String referenceClass) 107 throws JavaModelException { 108 mJavaProject = JavaCore.create(project); 109 mReferenceType = mJavaProject.findType(referenceClass); 110 } 111 112 @Override 113 public ITypeInfoFilterExtension getFilterExtension() { 114 return new ITypeInfoFilterExtension() { 115 public boolean select(ITypeInfoRequestor typeInfoRequestor) { 116 117 boolean projectOnly = mUseProjectOnly; 118 119 String packageName = typeInfoRequestor.getPackageName(); 120 String typeName = typeInfoRequestor.getTypeName(); 121 String enclosingType = typeInfoRequestor.getEnclosingName(); 122 123 // build the full class name. 124 StringBuilder sb = new StringBuilder(packageName); 125 sb.append('.'); 126 if (enclosingType.length() > 0) { 127 sb.append(enclosingType); 128 sb.append('.'); 129 } 130 sb.append(typeName); 131 132 String className = sb.toString(); 133 134 try { 135 IType type = mJavaProject.findType(className); 136 137 if (type == null) { 138 return false; 139 } 140 141 // don't display abstract classes 142 if ((type.getFlags() & Flags.AccAbstract) != 0) { 143 return false; 144 } 145 146 // if project-only is selected, make sure the package fragment is 147 // an actual source (thus "from this project"). 148 if (projectOnly) { 149 IPackageFragment frag = type.getPackageFragment(); 150 if (frag == null || frag.getKind() != IPackageFragmentRoot.K_SOURCE) { 151 return false; 152 } 153 } 154 155 // get the type hierarchy and reference type is one of the super classes. 156 ITypeHierarchy hierarchy = type.newSupertypeHierarchy( 157 new NullProgressMonitor()); 158 159 IType[] supertypes = hierarchy.getAllSupertypes(type); 160 int n = supertypes.length; 161 for (int i = 0; i < n; i++) { 162 IType st = supertypes[i]; 163 if (mReferenceType.equals(st)) { 164 return true; 165 } 166 } 167 } catch (JavaModelException e) { 168 } 169 170 return false; 171 } 172 }; 173 } 174 175 @Override 176 public Control createContentArea(Composite parent) { 177 178 mProjectOnly = new Button(parent, SWT.CHECK); 179 mProjectOnly.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 180 mProjectOnly.setText(String.format("Display classes from sources of project '%s' only", 181 mJavaProject.getProject().getName())); 182 183 mUseProjectOnly = mDefaultToProjectOnly; 184 mProjectOnly.setSelection(mUseProjectOnly); 185 186 mProjectOnly.addSelectionListener(new SelectionAdapter() { 187 @Override 188 public void widgetSelected(SelectionEvent e) { 189 super.widgetSelected(e); 190 mUseProjectOnly = mProjectOnly.getSelection(); 191 getTypeSelectionComponent().triggerSearch(); 192 } 193 }); 194 195 return super.createContentArea(parent); 196 } 197 } 198 199 /** 200 * Classes which implement this interface provide a method processing newly created classes. 201 */ 202 public static interface IPostTypeCreationAction { 203 /** 204 * Sent to process a newly created class. 205 * @param newType the IType representing the newly created class. 206 */ 207 public void processNewType(IType newType); 208 } 209 210 /** 211 * Creates a {@link UiClassAttributeNode} object that will display ui to select or create 212 * classes. 213 * @param referenceClass The allowed supertype of the classes that are to be selected 214 * or created. Can be null. 215 * @param postCreationAction a {@link IPostTypeCreationAction} object handling post creation 216 * modification of the class. 217 * @param mandatory indicates if the class value is mandatory 218 * @param attributeDescriptor the {@link AttributeDescriptor} object linked to the Ui Node. 219 * @param defaultToProjectOnly When true display classes of this project only by default. 220 * When false any class path will be considered. The user can always toggle this. 221 */ 222 public UiClassAttributeNode(String referenceClass, IPostTypeCreationAction postCreationAction, 223 boolean mandatory, AttributeDescriptor attributeDescriptor, UiElementNode uiParent, 224 boolean defaultToProjectOnly) { 225 super(attributeDescriptor, uiParent); 226 227 mReferenceClass = referenceClass; 228 mPostCreationAction = postCreationAction; 229 mMandatory = mandatory; 230 mDefaultToProjectOnly = defaultToProjectOnly; 231 } 232 233 /* (non-java doc) 234 * Creates a label widget and an associated text field. 235 * <p/> 236 * As most other parts of the android manifest editor, this assumes the 237 * parent uses a table layout with 2 columns. 238 */ 239 @Override 240 public void createUiControl(final Composite parent, IManagedForm managedForm) { 241 setManagedForm(managedForm); 242 FormToolkit toolkit = managedForm.getToolkit(); 243 TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); 244 245 StringBuilder label = new StringBuilder(); 246 label.append("<form><p><a href='unused'>"); 247 label.append(desc.getUiName()); 248 label.append("</a></p></form>"); 249 FormText formText = SectionHelper.createFormText(parent, toolkit, true /* isHtml */, 250 label.toString(), true /* setupLayoutData */); 251 formText.addHyperlinkListener(new HyperlinkAdapter() { 252 @Override 253 public void linkActivated(HyperlinkEvent e) { 254 super.linkActivated(e); 255 handleLabelClick(); 256 } 257 }); 258 formText.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); 259 SectionHelper.addControlTooltip(formText, desc.getTooltip()); 260 261 Composite composite = toolkit.createComposite(parent); 262 composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); 263 GridLayout gl = new GridLayout(2, false); 264 gl.marginHeight = gl.marginWidth = 0; 265 composite.setLayout(gl); 266 // Fixes missing text borders under GTK... also requires adding a 1-pixel margin 267 // for the text field below 268 toolkit.paintBordersFor(composite); 269 270 final Text text = toolkit.createText(composite, getCurrentValue()); 271 GridData gd = new GridData(GridData.FILL_HORIZONTAL); 272 gd.horizontalIndent = 1; // Needed by the fixed composite borders under GTK 273 text.setLayoutData(gd); 274 Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH); 275 276 setTextWidget(text); 277 278 browseButton.addSelectionListener(new SelectionAdapter() { 279 @Override 280 public void widgetSelected(SelectionEvent e) { 281 super.widgetSelected(e); 282 handleBrowseClick(); 283 } 284 }); 285 } 286 287 /* (non-java doc) 288 * 289 * Add a modify listener that will check the validity of the class 290 */ 291 @Override 292 protected void onAddValidators(final Text text) { 293 ModifyListener listener = new ModifyListener() { 294 public void modifyText(ModifyEvent e) { 295 try { 296 String textValue = text.getText().trim(); 297 if (textValue.length() == 0) { 298 if (mMandatory) { 299 setErrorMessage("Value is mandatory", text); 300 } else { 301 setErrorMessage(null, text); 302 } 303 return; 304 } 305 // first we need the current java package. 306 String javaPackage = getManifestPackage(); 307 308 // build the fully qualified name of the class 309 String className = AndroidManifest.combinePackageAndClassName( 310 javaPackage, textValue); 311 312 // only test the vilibility for activities. 313 boolean testVisibility = SdkConstants.CLASS_ACTIVITY.equals( 314 mReferenceClass); 315 316 // test the class 317 setErrorMessage(BaseProjectHelper.testClassForManifest( 318 BaseProjectHelper.getJavaProject(getProject()), className, 319 mReferenceClass, testVisibility), text); 320 } catch (CoreException ce) { 321 setErrorMessage(ce.getMessage(), text); 322 } 323 } 324 }; 325 326 text.addModifyListener(listener); 327 328 // Make sure the validator removes its message(s) when the widget is disposed 329 text.addDisposeListener(new DisposeListener() { 330 public void widgetDisposed(DisposeEvent e) { 331 // we don't want to use setErrorMessage, because we don't want to reset 332 // the error flag in the UiAttributeNode 333 getManagedForm().getMessageManager().removeMessage(text, text); 334 } 335 }); 336 337 // Finally call the validator once to make sure the initial value is processed 338 listener.modifyText(null); 339 } 340 341 private void handleBrowseClick() { 342 Text text = getTextWidget(); 343 344 // we need to get the project of the manifest. 345 IProject project = getProject(); 346 if (project != null) { 347 348 // Create a search scope including only the source folder of the current 349 // project. 350 IPackageFragmentRoot[] packageFragmentRoots = getPackageFragmentRoots(project, 351 true /*include_containers*/); 352 IJavaSearchScope scope = SearchEngine.createJavaSearchScope( 353 packageFragmentRoots, 354 false); 355 356 try { 357 SelectionDialog dlg = JavaUI.createTypeDialog(text.getShell(), 358 PlatformUI.getWorkbench().getProgressService(), 359 scope, 360 IJavaElementSearchConstants.CONSIDER_CLASSES, // style 361 false, // no multiple selection 362 "**", //$NON-NLS-1$ //filter 363 new HierarchyTypeSelection(project, mReferenceClass)); 364 dlg.setMessage(String.format("Select class name for element %1$s:", 365 getUiParent().getBreadcrumbTrailDescription(false /* include_root */))); 366 if (dlg instanceof ITypeSelectionComponent) { 367 ((ITypeSelectionComponent)dlg).triggerSearch(); 368 } 369 370 if (dlg.open() == Window.OK) { 371 Object[] results = dlg.getResult(); 372 if (results.length == 1) { 373 handleNewType((IType)results[0]); 374 } 375 } 376 } catch (JavaModelException e1) { 377 AdtPlugin.log(e1, "UiClassAttributeNode HandleBrowser failed"); 378 } 379 } 380 } 381 382 private void handleLabelClick() { 383 // get the current value 384 String className = getTextWidget().getText().trim(); 385 386 // get the package name from the manifest. 387 String packageName = getManifestPackage(); 388 389 if (className.length() == 0) { 390 createNewClass(packageName, null /* className */); 391 } else { 392 // build back the fully qualified class name. 393 String fullClassName = className; 394 if (className.startsWith(".")) { //$NON-NLS-1$ 395 fullClassName = packageName + className; 396 } else { 397 String[] segments = className.split(AdtConstants.RE_DOT); 398 if (segments.length == 1) { 399 fullClassName = packageName + "." + className; //$NON-NLS-1$ 400 } 401 } 402 403 // in case the type is enclosed, we need to replace the $ with . 404 fullClassName = fullClassName.replaceAll("\\$", "\\."); //$NON-NLS-1$ //$NON-NLS2$ 405 406 // now we try to find the file that contains this class and we open it in the editor. 407 IProject project = getProject(); 408 IJavaProject javaProject = JavaCore.create(project); 409 410 try { 411 IType result = javaProject.findType(fullClassName); 412 if (result != null) { 413 JavaUI.openInEditor(result); 414 } else { 415 // split the last segment from the fullClassname 416 int index = fullClassName.lastIndexOf('.'); 417 if (index != -1) { 418 createNewClass(fullClassName.substring(0, index), 419 fullClassName.substring(index+1)); 420 } else { 421 createNewClass(packageName, className); 422 } 423 } 424 } catch (JavaModelException e) { 425 AdtPlugin.log(e, "UiClassAttributeNode HandleLabel failed"); 426 } catch (PartInitException e) { 427 AdtPlugin.log(e, "UiClassAttributeNode HandleLabel failed"); 428 } 429 } 430 } 431 432 private IProject getProject() { 433 UiElementNode uiNode = getUiParent(); 434 AndroidXmlEditor editor = uiNode.getEditor(); 435 IEditorInput input = editor.getEditorInput(); 436 if (input instanceof IFileEditorInput) { 437 // from the file editor we can get the IFile object, and from it, the IProject. 438 IFile file = ((IFileEditorInput)input).getFile(); 439 return file.getProject(); 440 } 441 442 return null; 443 } 444 445 446 /** 447 * Returns the current value of the /manifest/package attribute. 448 * @return the package or an empty string if not found 449 */ 450 private String getManifestPackage() { 451 // get the root uiNode to get the 'package' attribute value. 452 UiElementNode rootNode = getUiParent().getUiRoot(); 453 454 Element xmlElement = (Element) rootNode.getXmlNode(); 455 456 if (xmlElement != null) { 457 return xmlElement.getAttribute(AndroidManifestDescriptors.PACKAGE_ATTR); 458 } 459 return ""; //$NON-NLS-1$ 460 } 461 462 463 /** 464 * Computes and return the {@link IPackageFragmentRoot}s corresponding to the source folders of 465 * the specified project. 466 * @param project the project 467 * @param include_containers True to include containers 468 * @return an array of IPackageFragmentRoot. 469 */ 470 private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project, 471 boolean include_containers) { 472 ArrayList<IPackageFragmentRoot> result = new ArrayList<IPackageFragmentRoot>(); 473 try { 474 IJavaProject javaProject = JavaCore.create(project); 475 IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots(); 476 for (int i = 0; i < roots.length; i++) { 477 IClasspathEntry entry = roots[i].getRawClasspathEntry(); 478 if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE || 479 (include_containers && 480 entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER)) { 481 result.add(roots[i]); 482 } 483 } 484 } catch (JavaModelException e) { 485 } 486 487 return result.toArray(new IPackageFragmentRoot[result.size()]); 488 } 489 490 private void handleNewType(IType type) { 491 Text text = getTextWidget(); 492 493 // get the fully qualified name with $ to properly detect the enclosing types. 494 String name = type.getFullyQualifiedName('$'); 495 496 String packageValue = getManifestPackage(); 497 498 // check if the class doesn't start with the package. 499 if (packageValue.length() > 0 && name.startsWith(packageValue)) { 500 // if it does, we remove the package and the first dot. 501 name = name.substring(packageValue.length() + 1); 502 503 // look for how many segments we have left. 504 // if one, just write it that way. 505 // if more than one, write it with a leading dot. 506 String[] packages = name.split(AdtConstants.RE_DOT); 507 if (packages.length == 1) { 508 text.setText(name); 509 } else { 510 text.setText("." + name); //$NON-NLS-1$ 511 } 512 } else { 513 text.setText(name); 514 } 515 } 516 517 private void createNewClass(String packageName, String className) { 518 // create the wizard page for the class creation, and configure it 519 NewClassWizardPage page = new NewClassWizardPage(); 520 521 // set the parent class 522 page.setSuperClass(mReferenceClass, true /* canBeModified */); 523 524 // get the source folders as java elements. 525 IPackageFragmentRoot[] roots = getPackageFragmentRoots(getProject(), 526 true /*include_containers*/); 527 528 IPackageFragmentRoot currentRoot = null; 529 IPackageFragment currentFragment = null; 530 int packageMatchCount = -1; 531 532 for (IPackageFragmentRoot root : roots) { 533 // Get the java element for the package. 534 // This method is said to always return a IPackageFragment even if the 535 // underlying folder doesn't exist... 536 IPackageFragment fragment = root.getPackageFragment(packageName); 537 if (fragment != null && fragment.exists()) { 538 // we have a perfect match! we use it. 539 currentRoot = root; 540 currentFragment = fragment; 541 packageMatchCount = -1; 542 break; 543 } else { 544 // we don't have a match. we look for the fragment with the best match 545 // (ie the closest parent package we can find) 546 try { 547 IJavaElement[] children; 548 children = root.getChildren(); 549 for (IJavaElement child : children) { 550 if (child instanceof IPackageFragment) { 551 fragment = (IPackageFragment)child; 552 if (packageName.startsWith(fragment.getElementName())) { 553 // its a match. get the number of segments 554 String[] segments = fragment.getElementName().split("\\."); //$NON-NLS-1$ 555 if (segments.length > packageMatchCount) { 556 packageMatchCount = segments.length; 557 currentFragment = fragment; 558 currentRoot = root; 559 } 560 } 561 } 562 } 563 } catch (JavaModelException e) { 564 // Couldn't get the children: we just ignore this package root. 565 } 566 } 567 } 568 569 ArrayList<IPackageFragment> createdFragments = null; 570 571 if (currentRoot != null) { 572 // if we have a perfect match, we set it and we're done. 573 if (packageMatchCount == -1) { 574 page.setPackageFragmentRoot(currentRoot, true /* canBeModified*/); 575 page.setPackageFragment(currentFragment, true /* canBeModified */); 576 } else { 577 // we have a partial match. 578 // create the package. We have to start with the first segment so that we 579 // know what to delete in case of a cancel. 580 try { 581 createdFragments = new ArrayList<IPackageFragment>(); 582 583 int totalCount = packageName.split("\\.").length; //$NON-NLS-1$ 584 int count = 0; 585 int index = -1; 586 // skip the matching packages 587 while (count < packageMatchCount) { 588 index = packageName.indexOf('.', index+1); 589 count++; 590 } 591 592 // create the rest of the segments, except for the last one as indexOf will 593 // return -1; 594 while (count < totalCount - 1) { 595 index = packageName.indexOf('.', index+1); 596 count++; 597 createdFragments.add(currentRoot.createPackageFragment( 598 packageName.substring(0, index), 599 true /* force*/, new NullProgressMonitor())); 600 } 601 602 // create the last package 603 createdFragments.add(currentRoot.createPackageFragment( 604 packageName, true /* force*/, new NullProgressMonitor())); 605 606 // set the root and fragment in the Wizard page 607 page.setPackageFragmentRoot(currentRoot, true /* canBeModified*/); 608 page.setPackageFragment(createdFragments.get(createdFragments.size()-1), 609 true /* canBeModified */); 610 } catch (JavaModelException e) { 611 // if we can't create the packages, there's a problem. we revert to the default 612 // package 613 for (IPackageFragmentRoot root : roots) { 614 // Get the java element for the package. 615 // This method is said to always return a IPackageFragment even if the 616 // underlying folder doesn't exist... 617 IPackageFragment fragment = root.getPackageFragment(packageName); 618 if (fragment != null && fragment.exists()) { 619 page.setPackageFragmentRoot(root, true /* canBeModified*/); 620 page.setPackageFragment(fragment, true /* canBeModified */); 621 break; 622 } 623 } 624 } 625 } 626 } else if (roots.length > 0) { 627 // if we haven't found a valid fragment, we set the root to the first source folder. 628 page.setPackageFragmentRoot(roots[0], true /* canBeModified*/); 629 } 630 631 // if we have a starting class name we use it 632 if (className != null) { 633 page.setTypeName(className, true /* canBeModified*/); 634 } 635 636 // create the action that will open it the wizard. 637 OpenNewClassWizardAction action = new OpenNewClassWizardAction(); 638 action.setConfiguredWizardPage(page); 639 action.run(); 640 IJavaElement element = action.getCreatedElement(); 641 642 if (element != null) { 643 if (element.getElementType() == IJavaElement.TYPE) { 644 645 IType type = (IType)element; 646 647 if (mPostCreationAction != null) { 648 mPostCreationAction.processNewType(type); 649 } 650 651 handleNewType(type); 652 } 653 } else { 654 // lets delete the packages we created just for this. 655 // we need to start with the leaf and go up 656 if (createdFragments != null) { 657 try { 658 for (int i = createdFragments.size() - 1 ; i >= 0 ; i--) { 659 createdFragments.get(i).delete(true /* force*/, new NullProgressMonitor()); 660 } 661 } catch (JavaModelException e) { 662 e.printStackTrace(); 663 } 664 } 665 } 666 } 667 668 /** 669 * Sets the error messages. If message is <code>null</code>, the message is removed. 670 * @param message the message to set, or <code>null</code> to remove the current message 671 * @param textWidget the {@link Text} widget associated to the message. 672 */ 673 private final void setErrorMessage(String message, Text textWidget) { 674 if (message != null) { 675 setHasError(true); 676 getManagedForm().getMessageManager().addMessage(textWidget, message, null /* data */, 677 IMessageProvider.ERROR, textWidget); 678 } else { 679 setHasError(false); 680 getManagedForm().getMessageManager().removeMessage(textWidget, textWidget); 681 } 682 } 683 684 @Override 685 public String[] getPossibleValues(String prefix) { 686 // TODO: compute a list of existing classes for content assist completion 687 return null; 688 } 689 } 690 691