/* * Copyright (C) 2010 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_MANIFEST_XML; import static com.android.SdkConstants.ANDROID_URI; import static com.android.SdkConstants.ATTR_CLASS; import static com.android.SdkConstants.ATTR_CONTEXT; import static com.android.SdkConstants.ATTR_NAME; import static com.android.SdkConstants.CLASS_VIEW; import static com.android.SdkConstants.DOT_XML; import static com.android.SdkConstants.EXT_XML; import static com.android.SdkConstants.R_CLASS; import static com.android.SdkConstants.TOOLS_URI; import static com.android.SdkConstants.VIEW_FRAGMENT; import static com.android.SdkConstants.VIEW_TAG; import com.android.SdkConstants; import com.android.annotations.NonNull; import com.android.ide.common.xml.ManifestData; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; 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.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; 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.core.ITypeHierarchy; import org.eclipse.jdt.internal.corext.refactoring.rename.RenameCompilationUnitProcessor; import org.eclipse.jdt.internal.corext.refactoring.rename.RenameTypeProcessor; 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.TextFileChange; import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor; import org.eclipse.ltk.core.refactoring.participants.RenameParticipant; import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring; 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.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.Collection; import java.util.List; /** * A participant to participate in refactorings that rename a type in an Android project. * The class updates android manifest and the layout file * The user can suppress refactoring by disabling the "Update references" checkbox. *
* Rename participants are registered via the extension point
* org.eclipse.ltk.core.refactoring.renameParticipants
.
* Extensions to this extension point must therefore extend
* org.eclipse.ltk.core.refactoring.participants.RenameParticipant
.
*/
@SuppressWarnings("restriction")
public class AndroidTypeRenameParticipant extends RenameParticipant {
private IProject mProject;
private IFile mManifestFile;
private String mOldFqcn;
private String mNewFqcn;
private String mOldSimpleName;
private String mNewSimpleName;
private String mOldDottedName;
private String mNewDottedName;
private boolean mIsCustomView;
/**
* 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;
@Override
public String getName() {
return "Android Type Rename";
}
@Override
public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
throws OperationCanceledException {
return new RefactoringStatus();
}
@Override
protected boolean initialize(Object element) {
if (sIgnore) {
return false;
}
if (element instanceof IType) {
IType type = (IType) element;
IJavaProject javaProject = (IJavaProject) type.getAncestor(IJavaElement.JAVA_PROJECT);
mProject = javaProject.getProject();
IResource manifestResource = mProject.findMember(AdtConstants.WS_SEP
+ SdkConstants.FN_ANDROID_MANIFEST_XML);
if (manifestResource == null || !manifestResource.exists()
|| !(manifestResource instanceof IFile)) {
RefactoringUtil.logInfo(
String.format("Invalid or missing file %1$s in project %2$s",
SdkConstants.FN_ANDROID_MANIFEST_XML,
mProject.getName()));
return false;
}
try {
IType classView = javaProject.findType(CLASS_VIEW);
if (classView != null) {
ITypeHierarchy hierarchy = type.newSupertypeHierarchy(new NullProgressMonitor());
if (hierarchy.contains(classView)) {
mIsCustomView = true;
}
}
} catch (CoreException e) {
AdtPlugin.log(e, null);
}
mManifestFile = (IFile) manifestResource;
ManifestData manifestData;
manifestData = AndroidManifestHelper.parseForData(mManifestFile);
if (manifestData == null) {
return false;
}
mOldSimpleName = type.getElementName();
mOldDottedName = '.' + mOldSimpleName;
mOldFqcn = type.getFullyQualifiedName();
String packageName = type.getPackageFragment().getElementName();
mNewSimpleName = getArguments().getNewName();
mNewDottedName = '.' + mNewSimpleName;
if (packageName != null) {
mNewFqcn = packageName + mNewDottedName;
} else {
mNewFqcn = mNewSimpleName;
}
if (mOldFqcn == null || mNewFqcn == null) {
return false;
}
if (!RefactoringUtil.isRefactorAppPackage() && mNewFqcn.indexOf('.') == -1) {
mNewFqcn = packageName + mNewDottedName;
}
return true;
}
return false;
}
@Override
public Change createChange(IProgressMonitor pm) throws CoreException,
OperationCanceledException {
if (pm.isCanceled()) {
return null;
}
// Only propose this refactoring if the "Update References" checkbox is set.
if (!getArguments().getUpdateReferences()) {
return null;
}
RefactoringProcessor p = getProcessor();
if (p instanceof RenameCompilationUnitProcessor) {
RenameTypeProcessor rtp =
((RenameCompilationUnitProcessor) p).getRenameTypeProcessor();
if (rtp != null) {
String pattern = rtp.getFilePatterns();
boolean updQualf = rtp.getUpdateQualifiedNames();
if (updQualf && pattern != null && pattern.contains("xml")) { //$NON-NLS-1$
// Do not propose this refactoring if the
// "Update fully qualified names in non-Java files" option is
// checked and the file patterns mention XML. [c.f. SDK bug 21589]
return null;
}
}
}
CompositeChange result = new CompositeChange(getName());
// Only show the children in the refactoring preview dialog
result.markAsSynthetic();
addManifestFileChanges(mManifestFile, result);
addLayoutFileChanges(mProject, result);
addJavaChanges(mProject, result, pm);
// Also update in dependent projects
// TODO: Also do the Java elements, if they are in Jar files, since the library
// projects do this (and the JDT refactoring does not include them)
ProjectState projectState = Sdk.getProjectState(mProject);
if (projectState != null) {
Collection