• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &lt;manifest&gt; tag with the new
92  * name.</li>
93  * <li>Replace all values for the "android:name" attribute in the
94  * &lt;application&gt; and "component class" (&lt;activity&gt;, &lt;service&gt;,
95  * &lt;receiver&gt;, and &lt;provider&gt;) 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