1 /* 2 * Copyright (C) 2010 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.actions; 18 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.AndroidConstants; 21 import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; 22 import com.android.sdklib.SdkConstants; 23 import com.android.sdklib.xml.AndroidManifest; 24 import com.android.sdklib.xml.ManifestData; 25 26 import org.eclipse.core.resources.IFile; 27 import org.eclipse.core.resources.IFolder; 28 import org.eclipse.core.resources.IMarker; 29 import org.eclipse.core.resources.IProject; 30 import org.eclipse.core.resources.IResource; 31 import org.eclipse.core.resources.IResourceVisitor; 32 import org.eclipse.core.runtime.CoreException; 33 import org.eclipse.core.runtime.IAdaptable; 34 import org.eclipse.core.runtime.IPath; 35 import org.eclipse.core.runtime.IProgressMonitor; 36 import org.eclipse.core.runtime.OperationCanceledException; 37 import org.eclipse.core.runtime.Status; 38 import org.eclipse.jdt.core.ICompilationUnit; 39 import org.eclipse.jdt.core.JavaCore; 40 import org.eclipse.jdt.core.JavaModelException; 41 import org.eclipse.jdt.core.dom.AST; 42 import org.eclipse.jdt.core.dom.ASTParser; 43 import org.eclipse.jdt.core.dom.ASTVisitor; 44 import org.eclipse.jdt.core.dom.CompilationUnit; 45 import org.eclipse.jdt.core.dom.ImportDeclaration; 46 import org.eclipse.jdt.core.dom.Name; 47 import org.eclipse.jdt.core.dom.QualifiedName; 48 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 49 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 50 import org.eclipse.jface.action.IAction; 51 import org.eclipse.jface.dialogs.IInputValidator; 52 import org.eclipse.jface.dialogs.InputDialog; 53 import org.eclipse.jface.viewers.ISelection; 54 import org.eclipse.jface.viewers.IStructuredSelection; 55 import org.eclipse.jface.window.Window; 56 import org.eclipse.ltk.core.refactoring.Change; 57 import org.eclipse.ltk.core.refactoring.CompositeChange; 58 import org.eclipse.ltk.core.refactoring.Refactoring; 59 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 60 import org.eclipse.ltk.core.refactoring.TextEditChangeGroup; 61 import org.eclipse.ltk.core.refactoring.TextFileChange; 62 import org.eclipse.ltk.ui.refactoring.RefactoringWizard; 63 import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation; 64 import org.eclipse.text.edits.MalformedTreeException; 65 import org.eclipse.text.edits.MultiTextEdit; 66 import org.eclipse.text.edits.ReplaceEdit; 67 import org.eclipse.text.edits.TextEdit; 68 import org.eclipse.text.edits.TextEditGroup; 69 import org.eclipse.ui.IObjectActionDelegate; 70 import org.eclipse.ui.IWorkbenchPart; 71 import org.eclipse.ui.IWorkbenchWindow; 72 import org.eclipse.ui.IWorkbenchWindowActionDelegate; 73 import org.eclipse.wst.sse.core.StructuredModelManager; 74 import org.eclipse.wst.sse.core.internal.provisional.IModelManager; 75 import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; 76 import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; 77 import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; 78 import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; 79 import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; 80 81 import java.io.IOException; 82 import java.util.ArrayList; 83 import java.util.Arrays; 84 import java.util.Collections; 85 import java.util.Iterator; 86 import java.util.List; 87 88 /** 89 * Refactoring steps: 90 * <ol> 91 * <li>Update the "package" attribute of the <manifest> tag with the new 92 * name.</li> 93 * <li>Replace all values for the "android:name" attribute in the 94 * <application> and "component class" (<activity>, <service>, 95 * <receiver>, and <provider>) tags with the non-shorthand version 96 * of the class name</li> 97 * <li>Replace package resource imports (*.R) in .java files</li> 98 * <li>Update package name in the namespace declarations (e.g. "xmlns:app") 99 * used for custom styleable attributes in layout resource files</li> 100 * </ol> 101 * Caveat: Sometimes it is necessary to perform a project-wide 102 * "Organize Imports" afterwards. (CTRL+SHIFT+O when a project has active 103 * selection) 104 */ 105 public class RenamePackageAction implements IObjectActionDelegate { 106 107 private ISelection mSelection; 108 109 private Name mOldPackageName, mNewPackageName; 110 111 public final static String[] MAIN_COMPONENT_TYPES = { 112 AndroidManifest.NODE_ACTIVITY, AndroidManifest.NODE_SERVICE, 113 AndroidManifest.NODE_RECEIVER, AndroidManifest.NODE_PROVIDER, 114 AndroidManifest.NODE_APPLICATION 115 }; 116 117 List<String> MAIN_COMPONENT_TYPES_LIST = Arrays.asList(MAIN_COMPONENT_TYPES); 118 119 public final static String ANDROID_NS_URI = SdkConstants.NS_RESOURCES; 120 121 public final static String NAMESPACE_DECLARATION_PREFIX = "xmlns:"; //$NON-NLS-1$ 122 123 IWorkbenchPart mTargetPart; 124 125 /** 126 * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) 127 */ setActivePart(IAction action, IWorkbenchPart targetPart)128 public void setActivePart(IAction action, IWorkbenchPart targetPart) { 129 mTargetPart = targetPart; 130 } 131 selectionChanged(IAction action, ISelection selection)132 public void selectionChanged(IAction action, ISelection selection) { 133 mSelection = selection; 134 } 135 136 /** 137 * @see IWorkbenchWindowActionDelegate#init 138 */ init(IWorkbenchWindow window)139 public void init(IWorkbenchWindow window) { 140 // pass 141 } 142 run(IAction action)143 public void run(IAction action) { 144 145 // Prompt for refactoring on the selected project 146 if (mSelection instanceof IStructuredSelection) { 147 for (Iterator<?> it = ((IStructuredSelection) mSelection).iterator(); it.hasNext();) { 148 Object element = it.next(); 149 IProject project = null; 150 if (element instanceof IProject) { 151 project = (IProject) element; 152 } else if (element instanceof IAdaptable) { 153 project = (IProject) ((IAdaptable) element).getAdapter(IProject.class); 154 } 155 if (project != null) { 156 // TODO/FIXME Uncomment this when support for Eclipse 3.4 is dropped! 157 /* 158 // It is advisable that the user saves before proceeding, 159 // revealing any compilation errors. The following lines 160 // enforce a save as a convenience. 161 RefactoringSaveHelper save_helper = new RefactoringSaveHelper( 162 RefactoringSaveHelper.SAVE_ALL_ALWAYS_ASK); 163 if (save_helper.saveEditors(AdtPlugin.getDisplay().getActiveShell())) { 164 promptNewName(project); 165 } 166 */ 167 168 promptNewName(project); 169 } 170 } 171 } 172 } 173 174 /* 175 * Validate the new package name and start the refactoring wizard 176 */ promptNewName(final IProject project)177 private void promptNewName(final IProject project) { 178 179 ManifestData manifestData = AndroidManifestHelper.parseForData(project); 180 if (manifestData == null) { 181 return; 182 } 183 184 final String old_package_name_string = manifestData.getPackage(); 185 186 final AST ast_validator = AST.newAST(AST.JLS3); 187 mOldPackageName = ast_validator.newName(old_package_name_string); 188 189 IInputValidator validator = new IInputValidator() { 190 191 public String isValid(String newText) { 192 try { 193 ast_validator.newName(newText); 194 } catch (IllegalArgumentException e) { 195 return "Illegal package name."; 196 } 197 198 if (newText.equals(old_package_name_string)) 199 return "No change."; 200 else 201 return null; 202 } 203 }; 204 205 InputDialog dialog = new InputDialog(AdtPlugin.getDisplay().getActiveShell(), 206 "Rename Application Package", "Enter new package name:", old_package_name_string, 207 validator); 208 209 if (dialog.open() == Window.OK) { 210 mNewPackageName = ast_validator.newName(dialog.getValue()); 211 initiateAndroidPackageRefactoring(project); 212 } 213 } 214 215 initiateAndroidPackageRefactoring(final IProject project)216 private void initiateAndroidPackageRefactoring(final IProject project) { 217 218 Refactoring package_name_refactoring = new ApplicationPackageNameRefactoring(project); 219 220 ApplicationPackageNameRefactoringWizard wizard = 221 new ApplicationPackageNameRefactoringWizard(package_name_refactoring); 222 RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard); 223 try { 224 op.run(AdtPlugin.getDisplay().getActiveShell(), package_name_refactoring.getName()); 225 } catch (InterruptedException e) { 226 Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e); 227 AdtPlugin.getDefault().getLog().log(s); 228 } 229 } 230 updateJavaFileImports(CompilationUnit cu)231 TextEdit updateJavaFileImports(CompilationUnit cu) { 232 233 ImportVisitor import_visitor = new ImportVisitor(cu.getAST()); 234 cu.accept(import_visitor); 235 TextEdit rewritten_imports = import_visitor.getTextEdit(); 236 237 // If the import of R was potentially implicit, insert an import statement 238 if (cu.getPackage().getName().getFullyQualifiedName() 239 .equals(mOldPackageName.getFullyQualifiedName())) { 240 241 ImportRewrite irw = ImportRewrite.create(cu, true); 242 irw.addImport(mNewPackageName.getFullyQualifiedName() + '.' 243 + AndroidConstants.FN_RESOURCE_BASE); 244 245 try { 246 rewritten_imports.addChild( irw.rewriteImports(null) ); 247 } catch (MalformedTreeException e) { 248 Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e); 249 AdtPlugin.getDefault().getLog().log(s); 250 } catch (CoreException e) { 251 Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e); 252 AdtPlugin.getDefault().getLog().log(s); 253 } 254 } 255 256 return rewritten_imports; 257 } 258 259 // XML utility functions stripQuotes(String text)260 private String stripQuotes(String text) { 261 int len = text.length(); 262 if (len >= 2 && text.charAt(0) == '"' && text.charAt(len - 1) == '"') { 263 return text.substring(1, len - 1); 264 } else if (len >= 2 && text.charAt(0) == '\'' && text.charAt(len - 1) == '\'') { 265 return text.substring(1, len - 1); 266 } 267 return text; 268 } 269 addQuotes(String text)270 private String addQuotes(String text) { 271 return '"' + text + '"'; 272 } 273 274 /* 275 * Make the appropriate package name changes to a resource file, 276 * e.g. .xml files in res/layout. This entails updating the namespace 277 * declarations for custom styleable attributes. The namespace prefix 278 * is user-defined and may be declared in any element where or parent 279 * element of where the prefix is used. 280 */ editXmlResourceFile(IFile file)281 TextFileChange editXmlResourceFile(IFile file) { 282 283 IModelManager modelManager = StructuredModelManager.getModelManager(); 284 IStructuredDocument sdoc = null; 285 try { 286 sdoc = modelManager.createStructuredDocumentFor(file); 287 } catch (IOException e) { 288 Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e); 289 AdtPlugin.getDefault().getLog().log(s); 290 } catch (CoreException e) { 291 Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e); 292 AdtPlugin.getDefault().getLog().log(s); 293 } 294 295 TextFileChange xmlChange = new TextFileChange("XML resource file edit", file); 296 xmlChange.setTextType(AndroidConstants.EXT_XML); 297 298 MultiTextEdit multiEdit = new MultiTextEdit(); 299 ArrayList<TextEditGroup> editGroups = new ArrayList<TextEditGroup>(); 300 301 final String oldAppNamespaceString = String.format(AndroidConstants.NS_CUSTOM_RESOURCES, 302 mOldPackageName.getFullyQualifiedName()); 303 final String newAppNamespaceString = String.format(AndroidConstants.NS_CUSTOM_RESOURCES, 304 mNewPackageName.getFullyQualifiedName()); 305 306 // Prepare the change set 307 for (IStructuredDocumentRegion region : sdoc.getStructuredDocumentRegions()) { 308 309 if (!DOMRegionContext.XML_TAG_NAME.equals(region.getType())) { 310 continue; 311 } 312 313 int nb = region.getNumberOfRegions(); 314 ITextRegionList list = region.getRegions(); 315 String lastAttrName = null; 316 317 for (int i = 0; i < nb; i++) { 318 ITextRegion subRegion = list.get(i); 319 String type = subRegion.getType(); 320 321 if (DOMRegionContext.XML_TAG_ATTRIBUTE_NAME.equals(type)) { 322 // Memorize the last attribute name seen 323 lastAttrName = region.getText(subRegion); 324 325 } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(type)) { 326 // Check this is the attribute and the original string 327 328 if (lastAttrName.startsWith(NAMESPACE_DECLARATION_PREFIX)) { 329 330 String lastAttrValue = region.getText(subRegion); 331 if (oldAppNamespaceString.equals(stripQuotes(lastAttrValue))) { 332 333 // Found an occurrence. Create a change for it. 334 TextEdit edit = new ReplaceEdit(region.getStartOffset() 335 + subRegion.getStart(), subRegion.getTextLength(), 336 addQuotes(newAppNamespaceString)); 337 TextEditGroup editGroup = new TextEditGroup( 338 "Replace package name in custom namespace prefix", edit); 339 340 multiEdit.addChild(edit); 341 editGroups.add(editGroup); 342 } 343 } 344 } 345 } 346 } 347 348 if (multiEdit.hasChildren()) { 349 xmlChange.setEdit(multiEdit); 350 for (TextEditGroup group : editGroups) { 351 xmlChange.addTextEditChangeGroup(new TextEditChangeGroup(xmlChange, group)); 352 } 353 354 return xmlChange; 355 } 356 return null; 357 } 358 359 /* 360 * Replace all instances of the package name in AndroidManifest.xml. 361 * This includes expanding shorthand paths for each Component (Activity, 362 * Service, etc.) and of course updating the application package name. 363 * The namespace prefix might not be "android", so we resolve it 364 * dynamically. 365 */ editAndroidManifest(IFile file)366 TextFileChange editAndroidManifest(IFile file) { 367 368 IModelManager modelManager = StructuredModelManager.getModelManager(); 369 IStructuredDocument sdoc = null; 370 try { 371 sdoc = modelManager.createStructuredDocumentFor(file); 372 } catch (IOException e) { 373 Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e); 374 AdtPlugin.getDefault().getLog().log(s); 375 } catch (CoreException e) { 376 Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e); 377 AdtPlugin.getDefault().getLog().log(s); 378 } 379 380 TextFileChange xmlChange = new TextFileChange("Make Manifest edits", file); 381 xmlChange.setTextType(AndroidConstants.EXT_XML); 382 383 MultiTextEdit multiEdit = new MultiTextEdit(); 384 ArrayList<TextEditGroup> editGroups = new ArrayList<TextEditGroup>(); 385 386 // The namespace prefix is guaranteed to be resolved before 387 // the first use of this attribute 388 String android_name_attribute = null; 389 390 // Prepare the change set 391 for (IStructuredDocumentRegion region : sdoc.getStructuredDocumentRegions()) { 392 393 // Only look at XML "top regions" 394 if (!DOMRegionContext.XML_TAG_NAME.equals(region.getType())) { 395 continue; 396 } 397 398 int nb = region.getNumberOfRegions(); 399 ITextRegionList list = region.getRegions(); 400 String lastTagName = null, lastAttrName = null; 401 402 for (int i = 0; i < nb; i++) { 403 ITextRegion subRegion = list.get(i); 404 String type = subRegion.getType(); 405 406 if (DOMRegionContext.XML_TAG_NAME.equals(type)) { 407 // Memorize the last tag name seen 408 lastTagName = region.getText(subRegion); 409 410 } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_NAME.equals(type)) { 411 // Memorize the last attribute name seen 412 lastAttrName = region.getText(subRegion); 413 414 } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(type)) { 415 416 String lastAttrValue = region.getText(subRegion); 417 if (lastAttrName.startsWith(NAMESPACE_DECLARATION_PREFIX)) { 418 419 // Resolves the android namespace prefix for this file 420 if (ANDROID_NS_URI.equals(stripQuotes(lastAttrValue))) { 421 String android_namespace_prefix = lastAttrName 422 .substring(NAMESPACE_DECLARATION_PREFIX.length()); 423 android_name_attribute = android_namespace_prefix + ':' 424 + AndroidManifest.ATTRIBUTE_NAME; 425 } 426 } 427 428 else if (AndroidManifest.NODE_MANIFEST.equals(lastTagName) 429 && AndroidManifest.ATTRIBUTE_PACKAGE.equals(lastAttrName)) { 430 431 // Found an occurrence. Create a change for it. 432 TextEdit edit = new ReplaceEdit(region.getStartOffset() 433 + subRegion.getStart(), subRegion.getTextLength(), 434 addQuotes(mNewPackageName.getFullyQualifiedName())); 435 436 multiEdit.addChild(edit); 437 editGroups.add(new TextEditGroup("Change Android package name", edit)); 438 439 } else if (MAIN_COMPONENT_TYPES_LIST.contains(lastTagName) 440 && lastAttrName.equals(android_name_attribute)) { 441 442 String package_path = stripQuotes(lastAttrValue); 443 String old_package_name_string = mOldPackageName.getFullyQualifiedName(); 444 445 String absolute_path = AndroidManifest.combinePackageAndClassName( 446 old_package_name_string, package_path); 447 448 TextEdit edit = new ReplaceEdit(region.getStartOffset() 449 + subRegion.getStart(), subRegion.getTextLength(), 450 addQuotes(absolute_path)); 451 452 multiEdit.addChild(edit); 453 454 editGroups.add(new TextEditGroup("Update component path", edit)); 455 } 456 } 457 } 458 } 459 460 if (multiEdit.hasChildren()) { 461 xmlChange.setEdit(multiEdit); 462 for (TextEditGroup group : editGroups) { 463 xmlChange.addTextEditChangeGroup(new TextEditChangeGroup(xmlChange, group)); 464 } 465 466 return xmlChange; 467 } 468 return null; 469 } 470 471 472 /* 473 * Iterates through all project files, taking distinct actions based on 474 * whether the file is: 475 * 1) a .java file (replaces or inserts the "import" statements) 476 * 2) a .xml layout file (updates namespace declarations) 477 * 3) the AndroidManifest.xml 478 */ 479 class JavaFileVisitor implements IResourceVisitor { 480 481 final List<TextFileChange> mChanges = new ArrayList<TextFileChange>(); 482 483 final ASTParser mParser = ASTParser.newParser(AST.JLS3); 484 getChange()485 public CompositeChange getChange() { 486 487 Collections.reverse(mChanges); 488 CompositeChange change = new CompositeChange("Refactoring Application package name", 489 mChanges.toArray(new Change[mChanges.size()])); 490 return change; 491 } 492 visit(IResource resource)493 public boolean visit(IResource resource) throws CoreException { 494 if (resource instanceof IFile) { 495 IFile file = (IFile) resource; 496 if (AndroidConstants.EXT_JAVA.equals(file.getFileExtension())) { 497 498 ICompilationUnit icu = JavaCore.createCompilationUnitFrom(file); 499 500 mParser.setSource(icu); 501 CompilationUnit cu = (CompilationUnit) mParser.createAST(null); 502 503 TextEdit text_edit = updateJavaFileImports(cu); 504 if (text_edit.hasChildren()) { 505 MultiTextEdit edit = new MultiTextEdit(); 506 edit.addChild(text_edit); 507 508 TextFileChange text_file_change = new TextFileChange(file.getName(), file); 509 text_file_change.setTextType(AndroidConstants.EXT_JAVA); 510 text_file_change.setEdit(edit); 511 mChanges.add(text_file_change); 512 } 513 514 // XXX Partially taken from ExtractStringRefactoring.java 515 // Check this a Layout XML file and get the selection and 516 // its context. 517 } else if (AndroidConstants.EXT_XML.equals(file.getFileExtension())) { 518 519 if (SdkConstants.FN_ANDROID_MANIFEST_XML.equals(file.getName())) { 520 521 TextFileChange manifest_change = editAndroidManifest(file); 522 mChanges.add(manifest_change); 523 524 } else { 525 526 // Currently we only support Android resource XML files, 527 // so they must have a path 528 // similar to 529 // project/res/<type>[-<configuration>]/*.xml 530 // There is no support for sub folders, so the segment 531 // count must be 4. 532 // We don't need to check the type folder name because 533 // a/ we only accept 534 // an AndroidXmlEditor source and b/ aapt generates a 535 // compilation error for 536 // unknown folders. 537 IPath path = file.getFullPath(); 538 // check if we are inside the project/res/* folder. 539 if (path.segmentCount() == 4) { 540 if (path.segment(1).equalsIgnoreCase(SdkConstants.FD_RESOURCES)) { 541 542 543 TextFileChange xmlChange = editXmlResourceFile(file); 544 if (xmlChange != null) { 545 mChanges.add(xmlChange); 546 } 547 } 548 } 549 } 550 } 551 552 return false; 553 554 } else if (resource instanceof IFolder) { 555 return !SdkConstants.FD_GEN_SOURCES.equals(resource.getName()); 556 } 557 558 return true; 559 } 560 } 561 562 class ImportVisitor extends ASTVisitor { 563 564 final AST mAst; 565 final ASTRewrite mRewriter; 566 ImportVisitor(AST ast)567 ImportVisitor(AST ast) { 568 mAst = ast; 569 mRewriter = ASTRewrite.create(ast); 570 } 571 getTextEdit()572 public TextEdit getTextEdit() { 573 try { 574 return this.mRewriter.rewriteAST(); 575 } catch (JavaModelException e) { 576 Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e); 577 AdtPlugin.getDefault().getLog().log(s); 578 } catch (IllegalArgumentException e) { 579 Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e); 580 AdtPlugin.getDefault().getLog().log(s); 581 } 582 return null; 583 } 584 585 @Override visit(ImportDeclaration id)586 public boolean visit(ImportDeclaration id) { 587 588 Name import_name = id.getName(); 589 if (import_name.isQualifiedName()) { 590 QualifiedName qualified_import_name = (QualifiedName) import_name; 591 592 if (qualified_import_name.getName().getIdentifier() 593 .equals(AndroidConstants.FN_RESOURCE_BASE)) { 594 mRewriter.replace(qualified_import_name.getQualifier(), mNewPackageName, 595 null); 596 } 597 } 598 599 return true; 600 } 601 } 602 603 class ApplicationPackageNameRefactoringWizard extends RefactoringWizard { 604 ApplicationPackageNameRefactoringWizard(Refactoring refactoring)605 public ApplicationPackageNameRefactoringWizard(Refactoring refactoring) { 606 super(refactoring, 0); 607 } 608 609 @Override addUserInputPages()610 protected void addUserInputPages() { 611 } 612 } 613 614 /* 615 * Wrapper class defining the stages of the refactoring process 616 */ 617 class ApplicationPackageNameRefactoring extends Refactoring { 618 619 IProject mProject; 620 ApplicationPackageNameRefactoring(final IProject project)621 ApplicationPackageNameRefactoring(final IProject project) { 622 mProject = project; 623 } 624 625 @Override checkFinalConditions(IProgressMonitor pm)626 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, 627 OperationCanceledException { 628 629 return new RefactoringStatus(); 630 } 631 632 @Override checkInitialConditions(IProgressMonitor pm)633 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, 634 OperationCanceledException { 635 636 // Accurate refactoring of the "shorthand" names in 637 // AndroidManifest.xml 638 // depends on not having compilation errors. 639 if (mProject.findMaxProblemSeverity( 640 IMarker.PROBLEM, 641 true, 642 IResource.DEPTH_INFINITE) == IMarker.SEVERITY_ERROR) { 643 return RefactoringStatus 644 .createFatalErrorStatus("Fix the errors in your project, first."); 645 } 646 647 return new RefactoringStatus(); 648 } 649 650 @Override createChange(IProgressMonitor pm)651 public Change createChange(IProgressMonitor pm) throws CoreException, 652 OperationCanceledException { 653 654 // Traverse all files in the project, building up a list of changes 655 JavaFileVisitor file_visitor = new JavaFileVisitor(); 656 mProject.accept(file_visitor); 657 return file_visitor.getChange(); 658 } 659 660 @Override getName()661 public String getName() { 662 return "AndroidPackageNameRefactoring"; //$NON-NLS-1$ 663 } 664 } 665 } 666