diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipant.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipant.java | 752 |
1 files changed, 752 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipant.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipant.java new file mode 100644 index 000000000..438e82223 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipant.java @@ -0,0 +1,752 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.adt.internal.refactorings.core; + +import static com.android.SdkConstants.ANDROID_PREFIX; +import static com.android.SdkConstants.ANDROID_URI; +import static com.android.SdkConstants.ATTR_ID; +import static com.android.SdkConstants.ATTR_NAME; +import static com.android.SdkConstants.ATTR_TYPE; +import static com.android.SdkConstants.DOT_XML; +import static com.android.SdkConstants.EXT_XML; +import static com.android.SdkConstants.FD_RES; +import static com.android.SdkConstants.FN_RESOURCE_CLASS; +import static com.android.SdkConstants.NEW_ID_PREFIX; +import static com.android.SdkConstants.PREFIX_RESOURCE_REF; +import static com.android.SdkConstants.PREFIX_THEME_REF; +import static com.android.SdkConstants.R_CLASS; +import static com.android.SdkConstants.TAG_ITEM; +import static com.android.SdkConstants.TOOLS_URI; + +import com.android.SdkConstants; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.AdtUtils; +import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; +import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; +import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator; +import com.android.ide.eclipse.adt.internal.sdk.ProjectState; +import com.android.ide.eclipse.adt.internal.sdk.Sdk; +import com.android.resources.ResourceFolderType; +import com.android.resources.ResourceType; +import com.android.utils.SdkUtils; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jdt.core.IField; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.internal.corext.refactoring.rename.RenameFieldProcessor; +import org.eclipse.ltk.core.refactoring.Change; +import org.eclipse.ltk.core.refactoring.CompositeChange; +import org.eclipse.ltk.core.refactoring.RefactoringStatus; +import org.eclipse.ltk.core.refactoring.TextChange; +import org.eclipse.ltk.core.refactoring.TextFileChange; +import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; +import org.eclipse.ltk.core.refactoring.participants.RenameParticipant; +import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring; +import org.eclipse.ltk.core.refactoring.resource.RenameResourceChange; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.ReplaceEdit; +import org.eclipse.text.edits.TextEdit; +import org.eclipse.wst.sse.core.StructuredModelManager; +import org.eclipse.wst.sse.core.internal.provisional.IModelManager; +import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; +import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; +import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; +import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * A rename participant handling renames of resources (such as R.id.foo and R.layout.bar). + * This reacts to refactorings of fields in the R inner classes (such as R.id), and updates + * the XML files as appropriate; renaming .xml files, updating XML attributes, resource + * references in style declarations, and so on. + */ +@SuppressWarnings("restriction") // WTP API +public class RenameResourceParticipant extends RenameParticipant { + /** The project we're refactoring in */ + private @NonNull IProject mProject; + + /** The type of the resource we're refactoring, such as {@link ResourceType#ID} */ + private @NonNull ResourceType mType; + /** + * The type of the resource folder we're refactoring in, such as + * {@link ResourceFolderType#VALUES}. When refactoring non value files, we need to + * rename the files as well. + */ + private @NonNull ResourceFolderType mFolderType; + + /** The previous name of the resource */ + private @NonNull String mOldName; + + /** The new name of the resource */ + private @NonNull String mNewName; + + /** Whether references to the resource should be updated */ + private boolean mUpdateReferences; + + /** A match pattern to look for in XML, such as {@code @attr/foo} */ + private @NonNull String mXmlMatch1; + + /** A match pattern to look for in XML, such as {@code ?attr/foo} */ + private @Nullable String mXmlMatch2; + + /** A match pattern to look for in XML, such as {@code ?foo} */ + private @Nullable String mXmlMatch3; + + /** The value to replace a reference to {@link #mXmlMatch1} with, such as {@code @attr/bar} */ + private @NonNull String mXmlNewValue1; + + /** The value to replace a reference to {@link #mXmlMatch2} with, such as {@code ?attr/bar} */ + private @Nullable String mXmlNewValue2; + + /** The value to replace a reference to {@link #mXmlMatch3} with, such as {@code ?bar} */ + private @Nullable String mXmlNewValue3; + + /** + * If non null, this refactoring was initiated as a file rename of an XML file (and if + * null, we are just reacting to a Java field rename) + */ + private IFile mRenamedFile; + + /** + * If renaming a field, we need to create an embedded field refactoring to update the + * Java sources referring to the corresponding R class field. This is stored as an + * instance such that we can have it participate in both the condition check methods + * as well as the {@link #createChange(IProgressMonitor)} refactoring operation. + */ + private RenameRefactoring mFieldRefactoring; + + /** + * Set while we are creating an embedded Java refactoring. This could cause a recursive + * invocation of the XML renaming refactoring to react to the field, so this is flag + * during the call to the Java processor, and is used to ignore requests for adding in + * field reactions during that time. + */ + private static boolean sIgnore; + + /** + * Creates a new {@linkplain RenameResourceParticipant} + */ + public RenameResourceParticipant() { + } + + @Override + public String getName() { + return "Android Rename Field Participant"; + } + + @Override + protected boolean initialize(Object element) { + if (sIgnore) { + return false; + } + + if (element instanceof IField) { + IField field = (IField) element; + IType declaringType = field.getDeclaringType(); + if (declaringType != null) { + if (R_CLASS.equals(declaringType.getParent().getElementName())) { + String typeName = declaringType.getElementName(); + mType = ResourceType.getEnum(typeName); + if (mType != null) { + mUpdateReferences = getArguments().getUpdateReferences(); + mFolderType = AdtUtils.getFolderTypeFor(mType); + IJavaProject javaProject = (IJavaProject) field.getAncestor( + IJavaElement.JAVA_PROJECT); + mProject = javaProject.getProject(); + mOldName = field.getElementName(); + mNewName = getArguments().getNewName(); + mFieldRefactoring = null; + mRenamedFile = null; + createXmlSearchPatterns(); + return true; + } + } + } + + return false; + } else if (element instanceof IFile) { + IFile file = (IFile) element; + mProject = file.getProject(); + if (BaseProjectHelper.isAndroidProject(mProject)) { + IPath path = file.getFullPath(); + int segments = path.segmentCount(); + if (segments == 4 && path.segment(1).equals(FD_RES)) { + String parentName = file.getParent().getName(); + mFolderType = ResourceFolderType.getFolderType(parentName); + if (mFolderType != null && mFolderType != ResourceFolderType.VALUES) { + mType = AdtUtils.getResourceTypeFor(mFolderType); + if (mType != null) { + mUpdateReferences = getArguments().getUpdateReferences(); + mProject = file.getProject(); + mOldName = AdtUtils.stripAllExtensions(file.getName()); + mNewName = AdtUtils.stripAllExtensions(getArguments().getNewName()); + mRenamedFile = file; + createXmlSearchPatterns(); + + mFieldRefactoring = null; + IField field = getResourceField(mProject, mType, mOldName); + if (field != null) { + mFieldRefactoring = createFieldRefactoring(field); + } else { + // no corresponding field; aapt has not run yet. Perhaps user has + // turned off auto build. + mFieldRefactoring = null; + } + + return true; + } + } + } + } + } else if (element instanceof String) { + String uri = (String) element; + if (uri.startsWith(PREFIX_RESOURCE_REF) && !uri.startsWith(ANDROID_PREFIX)) { + RenameResourceProcessor processor = (RenameResourceProcessor) getProcessor(); + mProject = processor.getProject(); + mType = processor.getType(); + mFolderType = AdtUtils.getFolderTypeFor(mType); + mOldName = processor.getCurrentName(); + mNewName = processor.getNewName(); + assert uri.endsWith(mOldName) && uri.contains(mType.getName()) : uri; + mUpdateReferences = getArguments().getUpdateReferences(); + if (mNewName.isEmpty()) { + mUpdateReferences = false; + } + mRenamedFile = null; + createXmlSearchPatterns(); + mFieldRefactoring = null; + if (!mNewName.isEmpty()) { + IField field = getResourceField(mProject, mType, mOldName); + if (field != null) { + mFieldRefactoring = createFieldRefactoring(field); + } + } + + return true; + } + } + + return false; + } + + /** Create nested Java refactoring which updates the R field references, if applicable */ + private RenameRefactoring createFieldRefactoring(IField field) { + return createFieldRefactoring(field, mNewName, mUpdateReferences); + } + + /** + * Create nested Java refactoring which updates the R field references, if + * applicable + * + * @param field the field to be refactored + * @param newName the new name + * @param updateReferences whether references should be updated + * @return a new rename refactoring + */ + public static RenameRefactoring createFieldRefactoring( + @NonNull IField field, + @NonNull String newName, + boolean updateReferences) { + RenameFieldProcessor processor = new RenameFieldProcessor(field); + processor.setRenameGetter(false); + processor.setRenameSetter(false); + RenameRefactoring refactoring = new RenameRefactoring(processor); + processor.setUpdateReferences(updateReferences); + processor.setUpdateTextualMatches(false); + processor.setNewElementName(newName); + try { + if (refactoring.isApplicable()) { + return refactoring; + } + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + + return null; + } + + private void createXmlSearchPatterns() { + // Set up search strings for the attribute iterator. This will + // identify string matches for mXmlMatch1, 2 and 3, and when matched, + // will add a replacement edit for mXmlNewValue1, 2, or 3. + mXmlMatch2 = null; + mXmlNewValue2 = null; + mXmlMatch3 = null; + mXmlNewValue3 = null; + + String typeName = mType.getName(); + if (mUpdateReferences) { + mXmlMatch1 = PREFIX_RESOURCE_REF + typeName + '/' + mOldName; + mXmlNewValue1 = PREFIX_RESOURCE_REF + typeName + '/' + mNewName; + if (mType == ResourceType.ID) { + mXmlMatch2 = NEW_ID_PREFIX + mOldName; + mXmlNewValue2 = NEW_ID_PREFIX + mNewName; + } else if (mType == ResourceType.ATTR) { + // When renaming @attr/foo, also edit ?attr/foo + mXmlMatch2 = PREFIX_THEME_REF + typeName + '/' + mOldName; + mXmlNewValue2 = PREFIX_THEME_REF + typeName + '/' + mNewName; + // as well as ?foo + mXmlMatch3 = PREFIX_THEME_REF + mOldName; + mXmlNewValue3 = PREFIX_THEME_REF + mNewName; + } + } else if (mType == ResourceType.ID) { + mXmlMatch1 = NEW_ID_PREFIX + mOldName; + mXmlNewValue1 = NEW_ID_PREFIX + mNewName; + } + } + + @Override + public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) + throws OperationCanceledException { + if (mRenamedFile != null && getArguments().getNewName().indexOf('.') == -1 + && mRenamedFile.getName().indexOf('.') != -1) { + return RefactoringStatus.createErrorStatus( + String.format("You must include the file extension (%1$s?)", + mRenamedFile.getName().substring(mRenamedFile.getName().indexOf('.')))); + } + + // Ensure that the new name is valid + if (mNewName != null && !mNewName.isEmpty()) { + ResourceNameValidator validator = ResourceNameValidator.create(false, mProject, mType); + String error = validator.isValid(mNewName); + if (error != null) { + return RefactoringStatus.createErrorStatus(error); + } + } + + if (mFieldRefactoring != null) { + try { + sIgnore = true; + return mFieldRefactoring.checkAllConditions(pm); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } finally { + sIgnore = false; + } + } + + return new RefactoringStatus(); + } + + @Override + public Change createChange(IProgressMonitor monitor) throws CoreException, + OperationCanceledException { + if (monitor.isCanceled()) { + return null; + } + + CompositeChange result = new CompositeChange("Update resource references"); + + // Only show the children in the refactoring preview dialog + result.markAsSynthetic(); + + addResourceFileChanges(result, mProject, monitor); + + // If renaming resources in a library project, also offer to rename references + // in including projects + if (mUpdateReferences) { + ProjectState projectState = Sdk.getProjectState(mProject); + if (projectState != null && projectState.isLibrary()) { + List<ProjectState> parentProjects = projectState.getParentProjects(); + for (ProjectState state : parentProjects) { + IProject project = state.getProject(); + CompositeChange nested = new CompositeChange( + String.format("Update references in %1$s", project.getName())); + addResourceFileChanges(nested, project, monitor); + if (nested.getChildren().length > 0) { + result.add(nested); + } + } + } + } + + if (mFieldRefactoring != null) { + // We have to add in Java field refactoring + try { + sIgnore = true; + addJavaChanges(result, monitor); + } finally { + sIgnore = false; + } + } else { + // Disable field refactoring added by the default Java field rename handler + disableExistingResourceFileChange(); + } + + return (result.getChildren().length == 0) ? null : result; + } + + /** + * Adds all changes to resource files (typically XML but also renaming drawable files + * + * @param project the Android project + * @param className the layout classes + */ + private void addResourceFileChanges( + CompositeChange change, + IProject project, + IProgressMonitor monitor) + throws OperationCanceledException { + if (monitor.isCanceled()) { + return; + } + + try { + // Update resource references in the manifest + IFile manifest = project.getFile(SdkConstants.ANDROID_MANIFEST_XML); + if (manifest != null) { + addResourceXmlChanges(manifest, change, null); + } + + // Update references in XML resource files + IFolder resFolder = project.getFolder(SdkConstants.FD_RESOURCES); + + IResource[] folders = resFolder.members(); + for (IResource folder : folders) { + if (!(folder instanceof IFolder)) { + continue; + } + String folderName = folder.getName(); + ResourceFolderType folderType = ResourceFolderType.getFolderType(folderName); + IResource[] files = ((IFolder) folder).members(); + for (int i = 0; i < files.length; i++) { + IResource member = files[i]; + if ((member instanceof IFile) && member.exists()) { + IFile file = (IFile) member; + String fileName = member.getName(); + + if (SdkUtils.endsWith(fileName, DOT_XML)) { + addResourceXmlChanges(file, change, folderType); + } + + if ((mRenamedFile == null || !mRenamedFile.equals(file)) + && fileName.startsWith(mOldName) + && fileName.length() > mOldName.length() + && fileName.charAt(mOldName.length()) == '.' + && mFolderType != ResourceFolderType.VALUES + && mFolderType == folderType) { + // Rename this file + String newFile = mNewName + fileName.substring(mOldName.length()); + IPath path = file.getFullPath(); + change.add(new RenameResourceChange(path, newFile)); + } + } + } + } + } catch (CoreException e) { + RefactoringUtil.log(e); + } + } + + private void addJavaChanges(CompositeChange result, IProgressMonitor monitor) + throws CoreException, OperationCanceledException { + if (monitor.isCanceled()) { + return; + } + + RefactoringStatus status = mFieldRefactoring.checkAllConditions(monitor); + if (status != null && !status.hasError()) { + Change fieldChanges = mFieldRefactoring.createChange(monitor); + if (fieldChanges != null) { + result.add(fieldChanges); + + // Look for the field change on the R.java class; it's a derived file + // and will generate file modified manually warnings. Disable it. + disableRClassChanges(fieldChanges); + } + } + } + + private boolean addResourceXmlChanges( + IFile file, + CompositeChange changes, + ResourceFolderType folderType) { + IModelManager modelManager = StructuredModelManager.getModelManager(); + IStructuredModel model = null; + try { + model = modelManager.getExistingModelForRead(file); + if (model == null) { + model = modelManager.getModelForRead(file); + } + if (model != null) { + IStructuredDocument document = model.getStructuredDocument(); + if (model instanceof IDOMModel) { + IDOMModel domModel = (IDOMModel) model; + Element root = domModel.getDocument().getDocumentElement(); + if (root != null) { + List<TextEdit> edits = new ArrayList<TextEdit>(); + addReplacements(edits, root, document, folderType); + if (!edits.isEmpty()) { + MultiTextEdit rootEdit = new MultiTextEdit(); + rootEdit.addChildren(edits.toArray(new TextEdit[edits.size()])); + TextFileChange change = new TextFileChange(file.getName(), file); + change.setTextType(EXT_XML); + change.setEdit(rootEdit); + changes.add(change); + } + } + } else { + return false; + } + } + + return true; + } catch (IOException e) { + AdtPlugin.log(e, null); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } finally { + if (model != null) { + model.releaseFromRead(); + } + } + + return false; + } + + private void addReplacements( + @NonNull List<TextEdit> edits, + @NonNull Element element, + @NonNull IStructuredDocument document, + @Nullable ResourceFolderType folderType) { + String tag = element.getTagName(); + if (folderType == ResourceFolderType.VALUES) { + // Look for + // <item name="main_layout" type="layout">...</item> + // <item name="myid" type="id"/> + // <string name="mystring">...</string> + // etc + if (tag.equals(mType.getName()) + || (tag.equals(TAG_ITEM) + && (mType == ResourceType.ID + || mType.getName().equals(element.getAttribute(ATTR_TYPE))))) { + Attr nameNode = element.getAttributeNode(ATTR_NAME); + if (nameNode != null && nameNode.getValue().equals(mOldName)) { + int start = RefactoringUtil.getAttributeValueRangeStart(nameNode, document); + if (start != -1) { + int end = start + mOldName.length(); + edits.add(new ReplaceEdit(start, end - start, mNewName)); + } + } + } + } + + NamedNodeMap attributes = element.getAttributes(); + for (int i = 0, n = attributes.getLength(); i < n; i++) { + Attr attr = (Attr) attributes.item(i); + String value = attr.getValue(); + + // If not updating references, only update XML matches that define the id + if (!mUpdateReferences && (!ATTR_ID.equals(attr.getLocalName()) || + !ANDROID_URI.equals(attr.getNamespaceURI()))) { + + if (TOOLS_URI.equals(attr.getNamespaceURI()) && value.equals(mXmlMatch1)) { + int start = RefactoringUtil.getAttributeValueRangeStart(attr, document); + if (start != -1) { + int end = start + mXmlMatch1.length(); + edits.add(new ReplaceEdit(start, end - start, mXmlNewValue1)); + } + } + + continue; + } + + // Replace XML attribute reference, such as + // android:id="@+id/oldName" => android:id="+id/newName" + + String match = null; + String matchedValue = null; + + if (value.equals(mXmlMatch1)) { + match = mXmlMatch1; + matchedValue = mXmlNewValue1; + } else if (value.equals(mXmlMatch2)) { + match = mXmlMatch2; + matchedValue = mXmlNewValue2; + } else if (value.equals(mXmlMatch3)) { + match = mXmlMatch3; + matchedValue = mXmlNewValue3; + } else { + continue; + } + + if (match != null) { + if (mNewName.isEmpty() && ATTR_ID.equals(attr.getLocalName()) && + ANDROID_URI.equals(attr.getNamespaceURI())) { + // Delete attribute + IndexedRegion region = (IndexedRegion) attr; + int start = region.getStartOffset(); + int end = region.getEndOffset(); + edits.add(new ReplaceEdit(start, end - start, "")); + } else { + int start = RefactoringUtil.getAttributeValueRangeStart(attr, document); + if (start != -1) { + int end = start + match.length(); + edits.add(new ReplaceEdit(start, end - start, matchedValue)); + } + } + } + } + + NodeList children = element.getChildNodes(); + for (int i = 0, n = children.getLength(); i < n; i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + addReplacements(edits, (Element) child, document, folderType); + } else if (child.getNodeType() == Node.TEXT_NODE && mUpdateReferences) { + // Replace XML text, such as @color/custom_theme_color in + // <item name="android:windowBackground">@color/custom_theme_color</item> + // + String text = child.getNodeValue(); + int index = getFirstNonBlankIndex(text); + if (index != -1) { + String match = null; + String matchedValue = null; + if (mXmlMatch1 != null + && text.startsWith(mXmlMatch1) && text.trim().equals(mXmlMatch1)) { + match = mXmlMatch1; + matchedValue = mXmlNewValue1; + } else if (mXmlMatch2 != null + && text.startsWith(mXmlMatch2) && text.trim().equals(mXmlMatch2)) { + match = mXmlMatch2; + matchedValue = mXmlNewValue2; + } else if (mXmlMatch3 != null + && text.startsWith(mXmlMatch3) && text.trim().equals(mXmlMatch3)) { + match = mXmlMatch3; + matchedValue = mXmlNewValue3; + } + if (match != null) { + IndexedRegion region = (IndexedRegion) child; + int start = region.getStartOffset() + index; + int end = start + match.length(); + edits.add(new ReplaceEdit(start, end - start, matchedValue)); + } + } + } + } + } + + /** + * Returns the index of the first non-space character in the string, or -1 + * if the string is empty or has only whitespace + * + * @param s the string to check + * @return the index of the first non whitespace character + */ + private int getFirstNonBlankIndex(String s) { + for (int i = 0, n = s.length(); i < n; i++) { + if (!Character.isWhitespace(s.charAt(i))) { + return i; + } + } + + return -1; + } + + /** + * Initiates a renaming of a resource item + * + * @param project the project containing the resource references + * @param type the type of resource + * @param name the name of the resource + * @return false if initiating the rename failed + */ + @Nullable + private static IField getResourceField( + @NonNull IProject project, + @NonNull ResourceType type, + @NonNull String name) { + try { + IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); + if (javaProject == null) { + return null; + } + + String pkg = ManifestInfo.get(project).getPackage(); + // TODO: Rename in all libraries too? + IType t = javaProject.findType(pkg + '.' + R_CLASS + '.' + type.getName()); + if (t == null) { + return null; + } + + return t.getField(name); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + + return null; + } + + /** + * Searches for existing changes in the refactoring which modifies the R + * field to rename it. it's derived so performing this change will generate + * a "generated code was modified manually" warning + */ + private void disableExistingResourceFileChange() { + IFolder genFolder = mProject.getFolder(SdkConstants.FD_GEN_SOURCES); + if (genFolder != null && genFolder.exists()) { + ManifestInfo manifestInfo = ManifestInfo.get(mProject); + String pkg = manifestInfo.getPackage(); + if (pkg != null) { + IFile rFile = genFolder.getFile(pkg.replace('.', '/') + '/' + FN_RESOURCE_CLASS); + TextChange change = getTextChange(rFile); + if (change != null) { + change.setEnabled(false); + } + } + } + } + + /** + * Searches for existing changes in the refactoring which modifies the R + * field to rename it. it's derived so performing this change will generate + * a "generated code was modified manually" warning + * + * @param change the change to disable R file changes in + */ + public static void disableRClassChanges(Change change) { + if (change.getName().equals(FN_RESOURCE_CLASS)) { + change.setEnabled(false); + } + // Look for the field change on the R.java class; it's a derived file + // and will generate file modified manually warnings. Disable it. + if (change instanceof CompositeChange) { + for (Change outer : ((CompositeChange) change).getChildren()) { + disableRClassChanges(outer); + } + } + } +} |