aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipant.java547
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeMoveParticipant.java362
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeRenameParticipant.java529
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/FixImportsJob.java148
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringUtil.java224
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourcePage.java177
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipant.java752
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceProcessor.java211
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceWizard.java157
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceXmlTextAction.java410
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResult.java163
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/EnabledTextEditGroup.java40
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringAction.java184
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringContribution.java53
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringDescriptor.java71
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringInputPage.java606
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringProposal.java185
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringRefactoring.java1933
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringWizard.java50
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ReplaceStringsVisitor.java480
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/XmlStringFileHelper.java187
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoring.java586
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoringWizard.java35
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/RenamePackageAction.java174
24 files changed, 0 insertions, 8264 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipant.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipant.java
deleted file mode 100644
index b821777a5..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidPackageRenameParticipant.java
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * 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_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.ATTR_PACKAGE;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.EXT_XML;
-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.project.AndroidManifestHelper;
-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.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.IJavaElement;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IPackageFragment;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.internal.corext.refactoring.changes.RenamePackageChange;
-import org.eclipse.jdt.internal.corext.refactoring.rename.RenameCompilationUnitProcessor;
-import org.eclipse.jdt.internal.corext.refactoring.rename.RenameTypeProcessor;
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.Region;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.CompositeChange;
-import org.eclipse.ltk.core.refactoring.FileStatusContext;
-import org.eclipse.ltk.core.refactoring.NullChange;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
-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.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.Document;
-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 package in an Android project.
- * The class updates android manifest and the layout file
- * The user can suppress refactoring by disabling the "Update references" checkbox
- * <p>
- * Rename participants are registered via the extension point <code>
- * org.eclipse.ltk.core.refactoring.renameParticipants</code>.
- * Extensions to this extension point must therefore extend
- * <code>org.eclipse.ltk.core.refactoring.participants.RenameParticipant</code>.
- * </p>
- */
-@SuppressWarnings("restriction")
-public class AndroidPackageRenameParticipant extends RenameParticipant {
-
- private IProject mProject;
- private IFile mManifestFile;
- private IPackageFragment mPackageFragment;
- private String mOldPackage;
- private String mNewPackage;
- private String mAppPackage;
- private boolean mRefactoringAppPackage;
-
- @Override
- public String getName() {
- return "Android Package Rename";
- }
-
- @Override
- public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
- throws OperationCanceledException {
- if (mAppPackage.equals(mOldPackage) && !mRefactoringAppPackage) {
- IRegion region = null;
- Document document = DomUtilities.getDocument(mManifestFile);
- if (document != null && document.getDocumentElement() != null) {
- Attr attribute = document.getDocumentElement().getAttributeNode(ATTR_PACKAGE);
- if (attribute instanceof IndexedRegion) {
- IndexedRegion ir = (IndexedRegion) attribute;
- int start = ir.getStartOffset();
- region = new Region(start, ir.getEndOffset() - start);
- }
- }
- if (region == null) {
- region = new Region(0, 0);
- }
- // There's no line wrapping in the error dialog, so split up the message into
- // individually digestible pieces of information
- RefactoringStatusContext ctx = new FileStatusContext(mManifestFile, region);
- RefactoringStatus status = RefactoringStatus.createInfoStatus(
- "You are refactoring the same package as your application's " +
- "package (specified in the manifest).\n", ctx);
- status.addInfo(
- "Note that this refactoring does NOT also update your " +
- "application package.", ctx);
- status.addInfo("The application package defines your application's identity.", ctx);
- status.addInfo(
- "If you change it, then it is considered to be a different application.", ctx);
- status.addInfo("(Users of the previous version cannot update to the new version.)",
- ctx);
- status.addInfo(
- "The application package, and the package containing the code, can differ.",
- ctx);
- status.addInfo(
- "To really change application package, " +
- "choose \"Android Tools\" > \"Rename Application Package.\" " +
- "from the project context menu.", ctx);
- return status;
- }
-
- return new RefactoringStatus();
- }
-
- @Override
- protected boolean initialize(final Object element) {
- mRefactoringAppPackage = false;
- try {
- // Only propose this refactoring if the "Update References" checkbox is set.
- if (!getArguments().getUpdateReferences()) {
- return false;
- }
-
- if (element instanceof IPackageFragment) {
- mPackageFragment = (IPackageFragment) element;
- if (!mPackageFragment.containsJavaResources()) {
- return false;
- }
- IJavaProject javaProject = (IJavaProject) mPackageFragment
- .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("Invalid or missing the "
- + SdkConstants.FN_ANDROID_MANIFEST_XML + " in the "
- + mProject.getName() + " project.");
- return false;
- }
- mManifestFile = (IFile) manifestResource;
- String packageName = mPackageFragment.getElementName();
- ManifestData manifestData;
- manifestData = AndroidManifestHelper.parseForData(mManifestFile);
- if (manifestData == null) {
- return false;
- }
- mAppPackage = manifestData.getPackage();
- mOldPackage = packageName;
- mNewPackage = getArguments().getNewName();
- if (mOldPackage == null || mNewPackage == null) {
- return false;
- }
-
- if (RefactoringUtil.isRefactorAppPackage()
- && mAppPackage != null
- && mAppPackage.equals(packageName)) {
- mRefactoringAppPackage = true;
- }
-
- return true;
- }
- } catch (JavaModelException ignore) {
- }
- return false;
- }
-
-
- @Override
- public Change createChange(IProgressMonitor pm) throws CoreException,
- OperationCanceledException {
- if (pm.isCanceled()) {
- return null;
- }
- 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;
- }
- }
- }
-
- IPath pkgPath = mPackageFragment.getPath();
- IPath genPath = mProject.getFullPath().append(SdkConstants.FD_GEN_SOURCES);
- if (genPath.isPrefixOf(pkgPath)) {
- RefactoringUtil.logInfo(getName() + ": Cannot rename generated package.");
- return null;
- }
- CompositeChange result = new CompositeChange(getName());
- result.markAsSynthetic();
-
- addManifestFileChanges(result);
-
- // Update layout files; we don't just need to react to custom view
- // changes, we need to update fragment references and even tool:context activity
- // references
- addLayoutFileChanges(mProject, result);
-
- // Also update in dependent projects
- ProjectState projectState = Sdk.getProjectState(mProject);
- if (projectState != null) {
- Collection<ProjectState> parentProjects = projectState.getFullParentProjects();
- for (ProjectState parentProject : parentProjects) {
- IProject project = parentProject.getProject();
- addLayoutFileChanges(project, result);
- }
- }
-
- if (mRefactoringAppPackage) {
- Change genChange = getGenPackageChange(pm);
- if (genChange != null) {
- result.add(genChange);
- }
-
- return new NullChange("Update Imports") {
- @Override
- public Change perform(IProgressMonitor monitor) throws CoreException {
- FixImportsJob job = new FixImportsJob("Fix Rename Package",
- mManifestFile, mNewPackage);
- job.schedule(500);
-
- // Not undoable: just return null instead of an undo-change.
- return null;
- }
- };
- }
-
- return (result.getChildren().length == 0) ? null : result;
- }
-
- /**
- * Returns Android gen package text change
- *
- * @param pm the progress monitor
- *
- * @return Android gen package text change
- * @throws CoreException if an error happens
- * @throws OperationCanceledException if the operation is canceled
- */
- public Change getGenPackageChange(IProgressMonitor pm) throws CoreException,
- OperationCanceledException {
- if (mRefactoringAppPackage) {
- IPackageFragment genJavaPackageFragment = getGenPackageFragment();
- if (genJavaPackageFragment != null && genJavaPackageFragment.exists()) {
- return new RenamePackageChange(genJavaPackageFragment, mNewPackage, true);
- }
- }
- return null;
- }
-
- /**
- * Return the gen package fragment
- */
- private IPackageFragment getGenPackageFragment() throws JavaModelException {
- IJavaProject javaProject = (IJavaProject) mPackageFragment
- .getAncestor(IJavaElement.JAVA_PROJECT);
- if (javaProject != null && javaProject.isOpen()) {
- IProject project = javaProject.getProject();
- IFolder genFolder = project.getFolder(SdkConstants.FD_GEN_SOURCES);
- if (genFolder.exists()) {
- String javaPackagePath = mAppPackage.replace('.', '/');
- IPath genJavaPackagePath = genFolder.getFullPath().append(javaPackagePath);
- IPackageFragment genPackageFragment = javaProject
- .findPackageFragment(genJavaPackagePath);
- return genPackageFragment;
- }
- }
- return null;
- }
-
- /**
- * Returns the new class name
- *
- * @param fqcn the fully qualified class name in the renamed package
- * @return the new class name
- */
- private String getNewClassName(String fqcn) {
- assert isInRenamedPackage(fqcn) : fqcn;
- int lastDot = fqcn.lastIndexOf('.');
- if (lastDot < 0) {
- return mNewPackage;
- }
- String name = fqcn.substring(lastDot, fqcn.length());
- String newClassName = mNewPackage + name;
- return newClassName;
- }
-
- private void addManifestFileChanges(CompositeChange result) {
- addXmlFileChanges(mManifestFile, result, true);
- }
-
- private void addLayoutFileChanges(IProject project, CompositeChange result) {
- try {
- // Update references in XML resource files
- IFolder resFolder = project.getFolder(SdkConstants.FD_RESOURCES);
-
- IResource[] folders = resFolder.members();
- for (IResource folder : folders) {
- String folderName = folder.getName();
- ResourceFolderType folderType = ResourceFolderType.getFolderType(folderName);
- if (folderType != ResourceFolderType.LAYOUT) {
- continue;
- }
- if (!(folder instanceof IFolder)) {
- continue;
- }
- 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)) {
- addXmlFileChanges(file, result, false);
- }
- }
- }
- }
- } catch (CoreException e) {
- RefactoringUtil.log(e);
- }
- }
-
- private boolean addXmlFileChanges(IFile file, CompositeChange changes, boolean isManifest) {
- 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>();
- if (isManifest) {
- addManifestReplacements(edits, root, document);
- } else {
- addLayoutReplacements(edits, root, document);
- }
- 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 boolean isInRenamedPackage(String fqcn) {
- return fqcn.startsWith(mOldPackage)
- && fqcn.length() > mOldPackage.length()
- && fqcn.indexOf('.', mOldPackage.length() + 1) == -1;
- }
-
- private void addLayoutReplacements(
- @NonNull List<TextEdit> edits,
- @NonNull Element element,
- @NonNull IStructuredDocument document) {
- String tag = element.getTagName();
- if (isInRenamedPackage(tag)) {
- int start = RefactoringUtil.getTagNameRangeStart(element, document);
- if (start != -1) {
- int end = start + tag.length();
- edits.add(new ReplaceEdit(start, end - start, getNewClassName(tag)));
- }
- } else {
- Attr classNode = null;
- if (tag.equals(VIEW_TAG)) {
- classNode = element.getAttributeNode(ATTR_CLASS);
- } else if (tag.equals(VIEW_FRAGMENT)) {
- classNode = element.getAttributeNode(ATTR_CLASS);
- if (classNode == null) {
- classNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
- }
- } else if (element.hasAttributeNS(TOOLS_URI, ATTR_CONTEXT)) {
- classNode = element.getAttributeNodeNS(TOOLS_URI, ATTR_CONTEXT);
- if (classNode != null && classNode.getValue().startsWith(".")) { //$NON-NLS-1$
- classNode = null;
- }
- }
- if (classNode != null) {
- String fqcn = classNode.getValue();
- if (isInRenamedPackage(fqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document);
- if (start != -1) {
- int end = start + fqcn.length();
- edits.add(new ReplaceEdit(start, end - start, getNewClassName(fqcn)));
- }
- }
- }
- }
-
- 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) {
- addLayoutReplacements(edits, (Element) child, document);
- }
- }
- }
-
- private void addManifestReplacements(
- @NonNull List<TextEdit> edits,
- @NonNull Element element,
- @NonNull IStructuredDocument document) {
- if (mRefactoringAppPackage &&
- element == element.getOwnerDocument().getDocumentElement()) {
- // Update the app package declaration
- Attr pkg = element.getAttributeNode(ATTR_PACKAGE);
- if (pkg != null && pkg.getValue().equals(mOldPackage)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(pkg, document);
- if (start != -1) {
- int end = start + mOldPackage.length();
- edits.add(new ReplaceEdit(start, end - start, mNewPackage));
- }
- }
- }
-
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attr = (Attr) attributes.item(i);
- if (!RefactoringUtil.isManifestClassAttribute(attr)) {
- continue;
- }
-
- String value = attr.getValue();
- if (isInRenamedPackage(value)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(attr, document);
- if (start != -1) {
- int end = start + value.length();
- edits.add(new ReplaceEdit(start, end - start, getNewClassName(value)));
- }
- } else if (value.startsWith(".")) {
- // If we're renaming the app package
- String fqcn = mAppPackage + value;
- if (isInRenamedPackage(fqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(attr, document);
- if (start != -1) {
- int end = start + value.length();
- String newClassName = getNewClassName(fqcn);
- if (mRefactoringAppPackage) {
- newClassName = newClassName.substring(mNewPackage.length());
- } else if (newClassName.startsWith(mOldPackage)
- && newClassName.charAt(mOldPackage.length()) == '.') {
- newClassName = newClassName.substring(mOldPackage.length());
- }
-
- if (!newClassName.equals(value)) {
- edits.add(new ReplaceEdit(start, end - start, newClassName));
- }
- }
- }
- }
- }
-
- 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) {
- addManifestReplacements(edits, (Element) child, document);
- }
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeMoveParticipant.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeMoveParticipant.java
deleted file mode 100644
index 2146184c8..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeMoveParticipant.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * 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_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.DOT_XML;
-import static com.android.SdkConstants.EXT_XML;
-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.project.AndroidManifestHelper;
-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.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.OperationCanceledException;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IPackageFragment;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
-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.MoveParticipant;
-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 move 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
- * <p>
- * Rename participants are registered via the extension point <code>
- * org.eclipse.ltk.core.refactoring.moveParticipants</code>.
- * Extensions to this extension point must therefore extend <code>org.eclipse.ltk.core.refactoring.participants.MoveParticipant</code>.
- * </p>
- */
-@SuppressWarnings("restriction")
-public class AndroidTypeMoveParticipant extends MoveParticipant {
-
- private IProject mProject;
- protected IFile mManifestFile;
- protected String mOldFqcn;
- protected String mNewFqcn;
- protected String mAppPackage;
-
- @Override
- public String getName() {
- return "Android Type Move";
- }
-
- @Override
- public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
- throws OperationCanceledException {
- return new RefactoringStatus();
- }
-
- @Override
- protected boolean initialize(Object element) {
- 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("Invalid or missing the "
- + SdkConstants.FN_ANDROID_MANIFEST_XML + " in the " + mProject.getName()
- + " project.");
- return false;
- }
- mManifestFile = (IFile) manifestResource;
- ManifestData manifestData;
- manifestData = AndroidManifestHelper.parseForData(mManifestFile);
- if (manifestData == null) {
- return false;
- }
- mAppPackage = manifestData.getPackage();
- mOldFqcn = type.getFullyQualifiedName();
- Object destination = getArguments().getDestination();
- if (destination instanceof IPackageFragment) {
- IPackageFragment packageFragment = (IPackageFragment) destination;
- mNewFqcn = packageFragment.getElementName() + "." + type.getElementName();
- } else if (destination instanceof IResource) {
- try {
- IPackageFragment[] fragments = javaProject.getPackageFragments();
- for (IPackageFragment fragment : fragments) {
- IResource resource = fragment.getResource();
- if (resource.equals(destination)) {
- mNewFqcn = fragment.getElementName() + '.' + type.getElementName();
- break;
- }
- }
- } catch (JavaModelException e) {
- // pass
- }
- }
- return mOldFqcn != null && mNewFqcn != null;
- }
-
- return false;
- }
-
- @Override
- public Change createChange(IProgressMonitor pm) throws CoreException,
- OperationCanceledException {
- if (pm.isCanceled()) {
- return null;
- }
- if (!getArguments().getUpdateReferences()) {
- return null;
- }
- CompositeChange result = new CompositeChange(getName());
- result.markAsSynthetic();
-
- addManifestFileChanges(result);
-
- // Update layout files; we don't just need to react to custom view
- // changes, we need to update fragment references and even tool:context activity
- // references
- addLayoutFileChanges(mProject, result);
-
- // Also update in dependent projects
- ProjectState projectState = Sdk.getProjectState(mProject);
- if (projectState != null) {
- Collection<ProjectState> parentProjects = projectState.getFullParentProjects();
- for (ProjectState parentProject : parentProjects) {
- IProject project = parentProject.getProject();
- addLayoutFileChanges(project, result);
- }
- }
-
- return (result.getChildren().length == 0) ? null : result;
- }
-
- private void addManifestFileChanges(CompositeChange result) {
- addXmlFileChanges(mManifestFile, result, true);
- }
-
- private void addLayoutFileChanges(IProject project, CompositeChange result) {
- try {
- // Update references in XML resource files
- IFolder resFolder = project.getFolder(SdkConstants.FD_RESOURCES);
-
- IResource[] folders = resFolder.members();
- for (IResource folder : folders) {
- String folderName = folder.getName();
- ResourceFolderType folderType = ResourceFolderType.getFolderType(folderName);
- if (folderType != ResourceFolderType.LAYOUT) {
- continue;
- }
- if (!(folder instanceof IFolder)) {
- continue;
- }
- 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)) {
- addXmlFileChanges(file, result, false);
- }
- }
- }
- }
- } catch (CoreException e) {
- RefactoringUtil.log(e);
- }
- }
-
- private boolean addXmlFileChanges(IFile file, CompositeChange changes, boolean isManifest) {
- 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>();
- if (isManifest) {
- addManifestReplacements(edits, root, document);
- } else {
- addLayoutReplacements(edits, root, document);
- }
- 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 addLayoutReplacements(
- @NonNull List<TextEdit> edits,
- @NonNull Element element,
- @NonNull IStructuredDocument document) {
- String tag = element.getTagName();
- if (tag.equals(mOldFqcn)) {
- int start = RefactoringUtil.getTagNameRangeStart(element, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- } else if (tag.equals(VIEW_TAG)) {
- Attr classNode = element.getAttributeNode(ATTR_CLASS);
- if (classNode != null && classNode.getValue().equals(mOldFqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- }
- } else if (tag.equals(VIEW_FRAGMENT)) {
- Attr classNode = element.getAttributeNode(ATTR_CLASS);
- if (classNode == null) {
- classNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
- }
- if (classNode != null && classNode.getValue().equals(mOldFqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- }
- } else if (element.hasAttributeNS(TOOLS_URI, ATTR_CONTEXT)) {
- Attr classNode = element.getAttributeNodeNS(TOOLS_URI, ATTR_CONTEXT);
- if (classNode != null && classNode.getValue().equals(mOldFqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- }
- }
-
- 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) {
- addLayoutReplacements(edits, (Element) child, document);
- }
- }
- }
-
- private void addManifestReplacements(
- @NonNull List<TextEdit> edits,
- @NonNull Element element,
- @NonNull IStructuredDocument document) {
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attr = (Attr) attributes.item(i);
- if (!RefactoringUtil.isManifestClassAttribute(attr)) {
- continue;
- }
-
- String value = attr.getValue();
- if (value.equals(mOldFqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(attr, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- } else if (value.startsWith(".")) { //$NON-NLS-1$
- String fqcn = mAppPackage + value;
- if (fqcn.equals(mOldFqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(attr, document);
- if (start != -1) {
- int end = start + value.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- }
- }
- }
-
- 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) {
- addManifestReplacements(edits, (Element) child, document);
- }
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeRenameParticipant.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeRenameParticipant.java
deleted file mode 100644
index 7843ab3b4..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/AndroidTypeRenameParticipant.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * 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.
- * <p>
- * Rename participants are registered via the extension point <code>
- * org.eclipse.ltk.core.refactoring.renameParticipants</code>.
- * Extensions to this extension point must therefore extend
- * <code>org.eclipse.ltk.core.refactoring.participants.RenameParticipant</code>.
- */
-@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<ProjectState> parentProjects = projectState.getFullParentProjects();
- for (ProjectState parentProject : parentProjects) {
- IProject project = parentProject.getProject();
- IResource manifestResource = project.findMember(AdtConstants.WS_SEP
- + SdkConstants.FN_ANDROID_MANIFEST_XML);
- if (manifestResource != null && manifestResource.exists()
- && manifestResource instanceof IFile) {
- addManifestFileChanges((IFile) manifestResource, result);
- }
- addLayoutFileChanges(project, result);
- addJavaChanges(project, result, pm);
- }
- }
-
- // Look for the field change on the R.java class; it's a derived file
- // and will generate file modified manually warnings. Disable it.
- RenameResourceParticipant.disableRClassChanges(result);
-
- return (result.getChildren().length == 0) ? null : result;
- }
-
- private void addJavaChanges(IProject project, CompositeChange result, IProgressMonitor monitor) {
- if (!mIsCustomView) {
- return;
- }
-
- // Also rename styleables, if any
- try {
- // Find R class
- IJavaProject javaProject = BaseProjectHelper.getJavaProject(project);
- ManifestInfo info = ManifestInfo.get(project);
- info.getPackage();
- String rFqcn = info.getPackage() + '.' + R_CLASS;
- IType styleable = javaProject.findType(rFqcn + '.' + ResourceType.STYLEABLE.getName());
- if (styleable != null) {
- IField[] fields = styleable.getFields();
- CompositeChange fieldChanges = null;
- for (IField field : fields) {
- String name = field.getElementName();
- if (name.equals(mOldSimpleName) || name.startsWith(mOldSimpleName)
- && name.length() > mOldSimpleName.length()
- && name.charAt(mOldSimpleName.length()) == '_') {
- // Rename styleable fields
- String newName = name.equals(mOldSimpleName) ? mNewSimpleName :
- mNewSimpleName + name.substring(mOldSimpleName.length());
- RenameRefactoring refactoring =
- RenameResourceParticipant.createFieldRefactoring(field,
- newName, true);
-
- try {
- sIgnore = true;
- RefactoringStatus status = refactoring.checkAllConditions(monitor);
- if (status != null && !status.hasError()) {
- Change fieldChange = refactoring.createChange(monitor);
- if (fieldChange != null) {
- if (fieldChanges == null) {
- fieldChanges = new CompositeChange(
- "Update custom view styleable fields");
- // Disable these changes. They sometimes end up
- // editing the wrong offsets. It looks like Eclipse
- // doesn't ensure that after applying each change it
- // also adjusts the other field offsets. I poked around
- // and couldn't find a way to do this properly, but
- // at least by listing the diffs here it shows what should
- // be done.
- fieldChanges.setEnabled(false);
- }
- // Disable change: see comment above.
- fieldChange.setEnabled(false);
- fieldChanges.add(fieldChange);
- }
- }
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- } finally {
- sIgnore = false;
- }
- }
- }
- if (fieldChanges != null) {
- result.add(fieldChanges);
- }
- }
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
- }
-
- private void addManifestFileChanges(IFile manifestFile, CompositeChange result) {
- addXmlFileChanges(manifestFile, result, null);
- }
-
- private void addLayoutFileChanges(IProject project, CompositeChange result) {
- try {
- // Update references in XML resource files
- IFolder resFolder = project.getFolder(SdkConstants.FD_RESOURCES);
-
- IResource[] folders = resFolder.members();
- for (IResource folder : folders) {
- String folderName = folder.getName();
- ResourceFolderType folderType = ResourceFolderType.getFolderType(folderName);
- if (folderType != ResourceFolderType.LAYOUT &&
- folderType != ResourceFolderType.VALUES) {
- continue;
- }
- if (!(folder instanceof IFolder)) {
- continue;
- }
- 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)) {
- addXmlFileChanges(file, result, folderType);
- }
- }
- }
- }
- } catch (CoreException e) {
- RefactoringUtil.log(e);
- }
- }
-
- private boolean addXmlFileChanges(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>();
- if (folderType == null) {
- assert file.getName().equals(ANDROID_MANIFEST_XML);
- addManifestReplacements(edits, root, document);
- } else if (folderType == ResourceFolderType.VALUES) {
- addValueReplacements(edits, root, document);
- } else {
- assert folderType == ResourceFolderType.LAYOUT;
- addLayoutReplacements(edits, root, document);
- }
- 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 addLayoutReplacements(
- @NonNull List<TextEdit> edits,
- @NonNull Element element,
- @NonNull IStructuredDocument document) {
- String tag = element.getTagName();
- if (tag.equals(mOldFqcn)) {
- int start = RefactoringUtil.getTagNameRangeStart(element, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- } else if (tag.equals(VIEW_TAG)) {
- // TODO: Handle inner classes ($ vs .) ?
- Attr classNode = element.getAttributeNode(ATTR_CLASS);
- if (classNode != null && classNode.getValue().equals(mOldFqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- }
- } else if (tag.equals(VIEW_FRAGMENT)) {
- Attr classNode = element.getAttributeNode(ATTR_CLASS);
- if (classNode == null) {
- classNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
- }
- if (classNode != null && classNode.getValue().equals(mOldFqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- }
- } else if (element.hasAttributeNS(TOOLS_URI, ATTR_CONTEXT)) {
- Attr classNode = element.getAttributeNodeNS(TOOLS_URI, ATTR_CONTEXT);
- if (classNode != null && classNode.getValue().equals(mOldFqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- } else if (classNode != null && classNode.getValue().equals(mOldDottedName)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(classNode, document);
- if (start != -1) {
- int end = start + mOldDottedName.length();
- edits.add(new ReplaceEdit(start, end - start, mNewDottedName));
- }
- }
- }
-
- 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) {
- addLayoutReplacements(edits, (Element) child, document);
- }
- }
- }
-
- private void addValueReplacements(
- @NonNull List<TextEdit> edits,
- @NonNull Element root,
- @NonNull IStructuredDocument document) {
- // Look for styleable renames for custom views
- String declareStyleable = ResourceType.DECLARE_STYLEABLE.getName();
- List<Element> topLevel = DomUtilities.getChildren(root);
- for (Element element : topLevel) {
- String tag = element.getTagName();
- if (declareStyleable.equals(tag)) {
- Attr nameNode = element.getAttributeNode(ATTR_NAME);
- if (nameNode != null && mOldSimpleName.equals(nameNode.getValue())) {
- int start = RefactoringUtil.getAttributeValueRangeStart(nameNode, document);
- if (start != -1) {
- int end = start + mOldSimpleName.length();
- edits.add(new ReplaceEdit(start, end - start, mNewSimpleName));
- }
- }
- }
- }
- }
-
- private void addManifestReplacements(
- @NonNull List<TextEdit> edits,
- @NonNull Element element,
- @NonNull IStructuredDocument document) {
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attr = (Attr) attributes.item(i);
- if (!RefactoringUtil.isManifestClassAttribute(attr)) {
- continue;
- }
-
- String value = attr.getValue();
- if (value.equals(mOldFqcn)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(attr, document);
- if (start != -1) {
- int end = start + mOldFqcn.length();
- edits.add(new ReplaceEdit(start, end - start, mNewFqcn));
- }
- } else if (value.equals(mOldDottedName)) {
- int start = RefactoringUtil.getAttributeValueRangeStart(attr, document);
- if (start != -1) {
- int end = start + mOldDottedName.length();
- edits.add(new ReplaceEdit(start, end - start, mNewDottedName));
- }
- }
- }
-
- 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) {
- addManifestReplacements(edits, (Element) child, document);
- }
- }
- }
-} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/FixImportsJob.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/FixImportsJob.java
deleted file mode 100644
index 552e6a845..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/FixImportsJob.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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 org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IncrementalProjectBuilder;
-import org.eclipse.core.resources.WorkspaceJob;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IPackageFragment;
-import org.eclipse.jdt.core.ISourceRange;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.dom.CompilationUnit;
-import org.eclipse.jdt.core.search.TypeNameMatch;
-import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
-import org.eclipse.jdt.internal.corext.codemanipulation.OrganizeImportsOperation;
-import org.eclipse.jdt.internal.corext.codemanipulation.OrganizeImportsOperation.IChooseImportQuery;
-import org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter;
-import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
-import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
-import org.eclipse.jdt.ui.SharedASTProvider;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.progress.IProgressService;
-
-/**
- * The helper class which fixes the import errors after refactoring
- *
- */
-@SuppressWarnings("restriction")
-public class FixImportsJob extends WorkspaceJob {
-
- private IFile mAndroidManifest;
-
- private String mJavaPackage;
-
- /**
- * Creates a new <code>FixImportsJob</code>
- *
- * @param name the job name
- * @param androidManifest the android manifest file
- * @param javaPackage the android java package
- */
- public FixImportsJob(String name, IFile androidManifest, String javaPackage) {
- super(name);
- this.mAndroidManifest = androidManifest;
- this.mJavaPackage = javaPackage;
- }
-
- @Override
- public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException {
- if (mJavaPackage == null || mAndroidManifest == null || !mAndroidManifest.exists()) {
- return Status.CANCEL_STATUS;
- }
- IProject project = mAndroidManifest.getProject();
- IJavaProject javaProject = JavaCore.create(project);
- if (javaProject == null || !javaProject.isOpen()) {
- return Status.CANCEL_STATUS;
- }
-
- project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor);
-
- IMarker[] markers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
- for (int i = 0; i < markers.length; i++) {
- IMarker marker = markers[i];
- IResource resource = marker.getResource();
- try {
- IJavaElement element = JavaCore.create(resource);
- if (element != null && (element instanceof ICompilationUnit)) {
- final ICompilationUnit cu = (ICompilationUnit) element;
- IPackageFragment packageFragment = (IPackageFragment) cu
- .getAncestor(IJavaElement.PACKAGE_FRAGMENT);
- if (packageFragment != null && packageFragment.exists()) {
- String packageName = packageFragment.getElementName();
- if (packageName != null && packageName.startsWith(mJavaPackage)) {
- CompilationUnit astRoot = SharedASTProvider.getAST(cu,
- SharedASTProvider.WAIT_ACTIVE_ONLY, null);
- CodeGenerationSettings settings = JavaPreferencesSettings
- .getCodeGenerationSettings(cu.getJavaProject());
- final boolean hasAmbiguity[] = new boolean[] {
- false
- };
- IChooseImportQuery query = new IChooseImportQuery() {
- @Override
- public TypeNameMatch[] chooseImports(TypeNameMatch[][] openChoices,
- ISourceRange[] ranges) {
- hasAmbiguity[0] = true;
- return new TypeNameMatch[0];
- }
- };
- final OrganizeImportsOperation op = new OrganizeImportsOperation(cu,
- astRoot, settings.importIgnoreLowercase, !cu.isWorkingCopy(),
- true, query);
- Display.getDefault().asyncExec(new Runnable() {
-
- @Override
- public void run() {
- try {
- IProgressService progressService = PlatformUI
- .getWorkbench().getProgressService();
- progressService.run(
- true,
- true,
- new WorkbenchRunnableAdapter(op, op
- .getScheduleRule()));
- IEditorPart openEditor = EditorUtility.isOpenInEditor(cu);
- if (openEditor != null) {
- openEditor.doSave(monitor);
- }
- } catch (Throwable e) {
- RefactoringUtil.log(e);
- }
- }
- });
-
- }
- }
- }
- } catch (Throwable e) {
- RefactoringUtil.log(e);
- }
- }
- return Status.OK_STATUS;
- }
-} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringUtil.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringUtil.java
deleted file mode 100644
index 04ebcfa26..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RefactoringUtil.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * 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_URI;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.xml.AndroidManifest.ATTRIBUTE_BACKUP_AGENT;
-import static com.android.xml.AndroidManifest.ATTRIBUTE_MANAGE_SPACE_ACTIVITY;
-import static com.android.xml.AndroidManifest.ATTRIBUTE_PARENT_ACTIVITY_NAME;
-import static com.android.xml.AndroidManifest.ATTRIBUTE_TARGET_ACTIVITY;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.xml.AndroidManifest;
-
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.wst.sse.core.StructuredModelManager;
-import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
-import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-
-/**
- * The utility class for android refactoring
- *
- */
-@SuppressWarnings("restriction")
-public class RefactoringUtil {
-
- private static boolean sRefactorAppPackage = false;
-
- /**
- * Releases SSE read model; saves SSE model if exists edit model
- * Called in dispose method of refactoring change classes
- *
- * @param model the SSE model
- * @param document the document
- */
- public static void fixModel(IStructuredModel model, IDocument document) {
- if (model != null) {
- model.releaseFromRead();
- }
- model = null;
- if (document == null) {
- return;
- }
- try {
- model = StructuredModelManager.getModelManager().getExistingModelForEdit(document);
- if (model != null) {
- model.save();
- }
- } catch (UnsupportedEncodingException e1) {
- // ignore
- } catch (IOException e1) {
- // ignore
- } catch (CoreException e1) {
- // ignore
- } finally {
- if (model != null) {
- model.releaseFromEdit();
- }
- }
- }
-
- /**
- * Logs the info message
- *
- * @param message the message
- */
- public static void logInfo(String message) {
- AdtPlugin.log(IStatus.INFO, AdtPlugin.PLUGIN_ID, message);
- }
-
- /**
- * Logs the the exception
- *
- * @param e the exception
- */
- public static void log(Throwable e) {
- AdtPlugin.log(e, e.getMessage());
- }
-
- /**
- * @return true if Rename/Move package needs to change the application package
- * default is false
- *
- */
- public static boolean isRefactorAppPackage() {
- return sRefactorAppPackage;
- }
-
- /**
- * @param refactorAppPackage true if Rename/Move package needs to change the application package
- */
- public static void setRefactorAppPackage(boolean refactorAppPackage) {
- RefactoringUtil.sRefactorAppPackage = refactorAppPackage;
- }
-
- /**
- * Returns the range of the attribute value in the given document
- *
- * @param attr the attribute to look up
- * @param document the document containing the attribute
- * @return the range of the value text, not including quotes, in the document
- */
- public static int getAttributeValueRangeStart(
- @NonNull Attr attr,
- @NonNull IDocument document) {
- IndexedRegion region = (IndexedRegion) attr;
- int potentialStart = attr.getName().length() + 2; // + 2: add ="
- String text;
- try {
- text = document.get(region.getStartOffset(),
- region.getEndOffset() - region.getStartOffset());
- } catch (BadLocationException e) {
- return -1;
- }
- String value = attr.getValue();
- int index = text.indexOf(value, potentialStart);
- if (index != -1) {
- return region.getStartOffset() + index;
- } else {
- return -1;
- }
- }
-
- /**
- * Returns the start of the tag name of the given element
- *
- * @param element the element to look up
- * @param document the document containing the attribute
- * @return the index of the start tag in the document
- */
- public static int getTagNameRangeStart(
- @NonNull Element element,
- @NonNull IDocument document) {
- IndexedRegion region = (IndexedRegion) element;
- int potentialStart = 1; // add '<'
- String text;
- try {
- text = document.get(region.getStartOffset(),
- region.getEndOffset() - region.getStartOffset());
- } catch (BadLocationException e) {
- return -1;
- }
- int index = text.indexOf(element.getTagName(), potentialStart);
- if (index != -1) {
- return region.getStartOffset() + index;
- } else {
- return -1;
- }
- }
-
- /**
- * Returns whether the given manifest attribute should be considered to describe
- * a class name. These will be eligible for refactoring when classes are renamed
- * or moved.
- *
- * @param attribute the manifest attribute
- * @return true if this attribute can describe a class
- */
- public static boolean isManifestClassAttribute(@NonNull Attr attribute) {
- return isManifestClassAttribute(
- attribute.getOwnerElement().getTagName(),
- attribute.getNamespaceURI(),
- attribute.getLocalName());
- }
-
- /**
- * Returns whether the given manifest attribute should be considered to describe
- * a class name. These will be eligible for refactoring when classes are renamed
- * or moved.
- *
- * @param tag the tag, if known
- * @param uri the attribute namespace, if any
- * @param name the attribute local name, if any
- * @return true if this attribute can describe a class
- */
- public static boolean isManifestClassAttribute(
- @Nullable String tag,
- @Nullable String uri,
- @Nullable String name) {
- if (name == null) {
- return false;
- }
-
- if ((name.equals(ATTR_NAME)
- && (AndroidManifest.NODE_ACTIVITY.equals(tag)
- || AndroidManifest.NODE_APPLICATION.equals(tag)
- || AndroidManifest.NODE_INSTRUMENTATION.equals(tag)
- || AndroidManifest.NODE_PROVIDER.equals(tag)
- || AndroidManifest.NODE_SERVICE.equals(tag)
- || AndroidManifest.NODE_RECEIVER.equals(tag)))
- || name.equals(ATTRIBUTE_TARGET_ACTIVITY)
- || name.equals(ATTRIBUTE_MANAGE_SPACE_ACTIVITY)
- || name.equals(ATTRIBUTE_BACKUP_AGENT)
- || name.equals(ATTRIBUTE_PARENT_ACTIVITY_NAME)) {
- return ANDROID_URI.equals(uri);
- }
-
- return false;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourcePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourcePage.java
deleted file mode 100644
index 6779fd322..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourcePage.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * 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.PREFIX_RESOURCE_REF;
-import static com.android.SdkConstants.R_CLASS;
-
-import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator;
-import com.android.resources.ResourceType;
-
-import org.eclipse.jdt.internal.ui.refactoring.TextInputWizardPage;
-import org.eclipse.jface.dialogs.Dialog;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-import java.util.Set;
-
-@SuppressWarnings("restriction") // JDT refactoring UI
-class RenameResourcePage extends TextInputWizardPage implements SelectionListener {
- private Label mXmlLabel;
- private Label mJavaLabel;
- private Button mUpdateReferences;
- private boolean mCanClear;
- private ResourceType mType;
- private ResourceNameValidator mValidator;
-
- /**
- * Create the wizard.
- * @param type the type of the resource to be renamed
- * @param initial initial renamed value
- * @param canClear whether the dialog should allow clearing the field
- */
- public RenameResourcePage(ResourceType type, String initial, boolean canClear) {
- super(type.getName(), true, initial);
- mType = type;
- mCanClear = canClear;
-
- mValidator = ResourceNameValidator.create(false /*allowXmlExtension*/,
- (Set<String>) null, mType);
- }
-
- @SuppressWarnings("unused") // SWT constructors aren't really unused, they have side effects
- @Override
- public void createControl(Composite parent) {
- Composite container = new Composite(parent, SWT.NULL);
- setControl(container);
- initializeDialogUnits(container);
- container.setLayout(new GridLayout(2, false));
- Label nameLabel = new Label(container, SWT.NONE);
- nameLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
- nameLabel.setText("New Name:");
- Text text = super.createTextInputField(container);
- text.selectAll();
- text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- Label xmlLabel = new Label(container, SWT.NONE);
- xmlLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
- xmlLabel.setText("XML:");
- mXmlLabel = new Label(container, SWT.NONE);
- mXmlLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
- Label javaLabel = new Label(container, SWT.NONE);
- javaLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
- javaLabel.setText("Java:");
- mJavaLabel = new Label(container, SWT.NONE);
- mJavaLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
- new Label(container, SWT.NONE);
- new Label(container, SWT.NONE);
- mUpdateReferences = new Button(container, SWT.CHECK);
- mUpdateReferences.setSelection(true);
- mUpdateReferences.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
- mUpdateReferences.setText("Update References");
- mUpdateReferences.addSelectionListener(this);
-
- Dialog.applyDialogFont(container);
- }
-
- @Override
- public void setVisible(boolean visible) {
- if (visible) {
- RenameResourceProcessor processor = getProcessor();
- String newName = processor.getNewName();
- if (newName != null && newName.length() > 0
- && !newName.equals(getInitialValue())) {
- Text textField = getTextField();
- textField.setText(newName);
- textField.setSelection(0, newName.length());
- }
- }
-
- super.setVisible(visible);
- }
-
- @Override
- protected RefactoringStatus validateTextField(String newName) {
- if (newName.isEmpty() && isEmptyInputValid()) {
- getProcessor().setNewName("");
- return RefactoringStatus.createWarningStatus(
- "The resource definition will be deleted");
- }
-
- String error = mValidator.isValid(newName);
- if (error != null) {
- return RefactoringStatus.createErrorStatus(error);
- }
-
- RenameResourceProcessor processor = getProcessor();
- processor.setNewName(newName);
- return processor.checkNewName(newName);
- }
-
- private RenameResourceProcessor getProcessor() {
- RenameRefactoring refactoring = (RenameRefactoring) getRefactoring();
- return (RenameResourceProcessor) refactoring.getProcessor();
- }
-
- @Override
- protected boolean isEmptyInputValid() {
- return mCanClear;
- }
-
- @Override
- protected boolean isInitialInputValid() {
- RenameResourceProcessor processor = getProcessor();
- return processor.getNewName() != null
- && !processor.getNewName().equals(processor.getCurrentName());
- }
-
- @Override
- protected void textModified(String text) {
- super.textModified(text);
- if (mXmlLabel != null && mJavaLabel != null) {
- String xml = PREFIX_RESOURCE_REF + mType.getName() + '/' + text;
- String java = R_CLASS + '.' + mType.getName() + '.' + text;
- if (text.isEmpty()) {
- xml = java = "";
- }
- mXmlLabel.setText(xml);
- mJavaLabel.setText(java);
- }
- }
-
- // ---- Implements SelectionListener ----
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- if (e.getSource() == mUpdateReferences) {
- RenameResourceProcessor processor = getProcessor();
- boolean update = mUpdateReferences.getSelection();
- processor.setUpdateReferences(update);
- }
- }
-
- @Override
- public void widgetDefaultSelected(SelectionEvent e) {
- }
-}
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
deleted file mode 100644
index 438e82223..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceParticipant.java
+++ /dev/null
@@ -1,752 +0,0 @@
-/*
- * 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);
- }
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceProcessor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceProcessor.java
deleted file mode 100644
index 5ea99411c..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceProcessor.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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.PREFIX_RESOURCE_REF;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator;
-import com.android.resources.ResourceType;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
-import org.eclipse.ltk.core.refactoring.participants.ParticipantManager;
-import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
-import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
-import org.eclipse.ltk.core.refactoring.participants.RenameProcessor;
-import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
-
-/**
- * A rename processor for Android resources.
- */
-public class RenameResourceProcessor extends RenameProcessor {
- private IProject mProject;
- private ResourceType mType;
- private String mCurrentName;
- private String mNewName;
- private boolean mUpdateReferences = true;
- private ResourceNameValidator mValidator;
- private RenameArguments mRenameArguments;
-
- /**
- * Creates a new rename resource processor.
- *
- * @param project the project containing the renamed resource
- * @param type the type of the resource
- * @param currentName the current name of the resource
- * @param newName the new name of the resource, or null if not known
- */
- public RenameResourceProcessor(
- @NonNull IProject project,
- @NonNull ResourceType type,
- @NonNull String currentName,
- @Nullable String newName) {
- mProject = project;
- mType = type;
- mCurrentName = currentName;
- mNewName = newName != null ? newName : currentName;
- mUpdateReferences= true;
- mValidator = ResourceNameValidator.create(false, mProject, mType);
- }
-
- /**
- * Returns the project containing the renamed resource
- *
- * @return the project containing the renamed resource
- */
- @NonNull
- public IProject getProject() {
- return mProject;
- }
-
- /**
- * Returns the new resource name
- *
- * @return the new resource name
- */
- @NonNull
- public String getNewName() {
- return mNewName;
- }
-
- /**
- * Returns the current name of the resource
- *
- * @return the current name of the resource
- */
- public String getCurrentName() {
- return mCurrentName;
- }
-
- /**
- * Returns the type of the resource
- *
- * @return the type of the resource
- */
- @NonNull
- public ResourceType getType() {
- return mType;
- }
-
- /**
- * Sets the new name
- *
- * @param newName the new name
- */
- public void setNewName(@NonNull String newName) {
- mNewName = newName;
- }
-
- /**
- * Returns {@code true} if the refactoring processor also updates references
- *
- * @return {@code true} if the refactoring processor also updates references
- */
- public boolean isUpdateReferences() {
- return mUpdateReferences;
- }
-
- /**
- * Specifies if the refactoring processor also updates references. The
- * default behavior is to update references.
- *
- * @param updateReferences {@code true} if the refactoring processor should
- * also updates references
- */
- public void setUpdateReferences(boolean updateReferences) {
- mUpdateReferences = updateReferences;
- }
-
- /**
- * Checks the given new potential name and returns a {@link RefactoringStatus} indicating
- * whether the potential new name is valid
- *
- * @param name the name to check
- * @return a {@link RefactoringStatus} with the validation result
- */
- public RefactoringStatus checkNewName(String name) {
- String error = mValidator.isValid(name);
- if (error != null) {
- return RefactoringStatus.createFatalErrorStatus(error);
- }
-
- return new RefactoringStatus();
- }
-
- @Override
- public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
- return new RefactoringStatus();
- }
-
- @Override
- public RefactoringStatus checkFinalConditions(IProgressMonitor pm,
- CheckConditionsContext context) throws CoreException {
- pm.beginTask("", 1);
- try {
- mRenameArguments = new RenameArguments(getNewName(), isUpdateReferences());
- return new RefactoringStatus();
- } finally {
- pm.done();
- }
- }
-
- @Override
- public Change createChange(IProgressMonitor pm) throws CoreException {
- pm.beginTask("", 1);
- try {
- // Added by {@link RenameResourceParticipant}
- return null;
- } finally {
- pm.done();
- }
- }
-
- @Override
- public Object[] getElements() {
- return new Object[0];
- }
-
- @Override
- public String getIdentifier() {
- return "com.android.ide.renameResourceProcessor"; //$NON-NLS-1$
- }
-
- @Override
- public String getProcessorName() {
- return "Rename Android Resource";
- }
-
- @Override
- public boolean isApplicable() {
- return true;
- }
-
- @Override
- public RefactoringParticipant[] loadParticipants(RefactoringStatus status,
- SharableParticipants shared) throws CoreException {
- String[] affectedNatures = new String[] { AdtConstants.NATURE_DEFAULT };
- String url = PREFIX_RESOURCE_REF + mType.getName() + '/' + mCurrentName;
- return ParticipantManager.loadRenameParticipants(status, this, url, mRenameArguments,
- null, affectedNatures, shared);
- }
-} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceWizard.java
deleted file mode 100644
index 6ffe25d22..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceWizard.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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 com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.resources.ResourceType;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
-import org.eclipse.jdt.internal.ui.JavaPluginImages;
-import org.eclipse.jdt.internal.ui.refactoring.reorg.RenameRefactoringWizard;
-import org.eclipse.jdt.ui.refactoring.RefactoringSaveHelper;
-import org.eclipse.jface.dialogs.IDialogConstants;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-import org.eclipse.swt.widgets.Shell;
-
-/**
- * Rename refactoring wizard for Android resources such as {@code @id/foo}
- */
-@SuppressWarnings("restriction") // JDT refactoring UI
-public class RenameResourceWizard extends RenameRefactoringWizard {
- private ResourceType mType;
- private boolean mCanClear;
-
- /**
- * Constructs a new {@linkplain RenameResourceWizard}
- *
- * @param refactoring the refactoring
- * @param type the type of resource being renamed
- * @param canClear whether the user can clear the value
- */
- public RenameResourceWizard(
- @NonNull RenameRefactoring refactoring,
- @NonNull ResourceType type,
- boolean canClear) {
- super(refactoring,
- "Rename Resource",
- "Enter the new name for this resource",
- JavaPluginImages.DESC_WIZBAN_REFACTOR_FIELD,
- IJavaHelpContextIds.RENAME_FIELD_WIZARD_PAGE);
- mType = type;
- mCanClear = canClear;
- }
-
- @Override
- protected void addUserInputPages() {
- RenameRefactoring refactoring = (RenameRefactoring) getRefactoring();
- RenameResourceProcessor processor = (RenameResourceProcessor) refactoring.getProcessor();
- String name = processor.getNewName();
- addPage(new RenameResourcePage(mType, name, mCanClear));
- }
-
- /**
- * Initiates a renaming of a resource item
- *
- * @param shell the shell to parent the dialog to
- * @param project the project containing the resource references
- * @param type the type of resource
- * @param currentName the name of the resource
- * @param newName the new name, or null if not known
- * @param canClear whether the name is allowed to be cleared
- * @return false if initiating the rename failed
- */
- public static RenameResult renameResource(
- @NonNull Shell shell,
- @NonNull IProject project,
- @NonNull ResourceType type,
- @NonNull String currentName,
- @Nullable String newName,
- boolean canClear) {
- try {
- RenameResourceProcessor processor = new RenameResourceProcessor(project, type,
- currentName, newName);
- RenameRefactoring refactoring = new RenameRefactoring(processor);
- if (!refactoring.isApplicable()) {
- return RenameResult.unavailable();
- }
-
- if (!show(refactoring, processor, shell, type, canClear)) {
- return RenameResult.canceled();
- }
- return RenameResult.name(processor.getNewName());
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
-
- return RenameResult.unavailable();
- }
-
- /**
- * Show a refactoring dialog for the given resource refactoring operation
- *
- * @param refactoring the rename refactoring
- * @param processor the field processor
- * @param parent the parent shell
- * @param type the resource type
- * @param canClear whether the user is allowed to clear/reset the name to
- * nothing
- * @return true if the refactoring was performed, and false if it was
- * canceled
- * @throws CoreException if an unexpected error occurs
- */
- private static boolean show(
- @NonNull RenameRefactoring refactoring,
- @NonNull RenameResourceProcessor processor,
- @NonNull Shell parent,
- @NonNull ResourceType type,
- boolean canClear) throws CoreException {
- RefactoringSaveHelper saveHelper = new RefactoringSaveHelper(
- RefactoringSaveHelper.SAVE_REFACTORING);
- if (!saveHelper.saveEditors(parent)) {
- return false;
- }
-
- try {
- RenameResourceWizard wizard = new RenameResourceWizard(refactoring, type, canClear);
- RefactoringWizardOpenOperation operation = new RefactoringWizardOpenOperation(wizard);
- String dialogTitle = wizard.getDefaultPageTitle();
- int result = operation.run(parent, dialogTitle == null ? "" : dialogTitle);
- RefactoringStatus status = operation.getInitialConditionCheckingStatus();
- if (status.hasFatalError()) {
- return false;
- }
- if (result == RefactoringWizardOpenOperation.INITIAL_CONDITION_CHECKING_FAILED
- || result == IDialogConstants.CANCEL_ID) {
- saveHelper.triggerIncrementalBuild();
- return false;
- }
-
- // Save modified resources; need to trigger R file regeneration
- saveHelper.saveEditors(parent);
-
- return true;
- } catch (InterruptedException e) {
- return false; // Canceled
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceXmlTextAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceXmlTextAction.java
deleted file mode 100644
index 8ecb08836..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResourceXmlTextAction.java
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * 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_MANIFEST_XML;
-import static com.android.SdkConstants.ANDROID_PREFIX;
-import static com.android.SdkConstants.ANDROID_THEME_PREFIX;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_TYPE;
-import static com.android.SdkConstants.TAG_ITEM;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.common.resources.ResourceUrl;
-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.BaseProjectHelper;
-import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.resources.ResourceType;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.internal.corext.refactoring.rename.RenameTypeProcessor;
-import org.eclipse.jdt.internal.ui.refactoring.reorg.RenameTypeWizard;
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionProvider;
-import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IFileEditorInput;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.texteditor.IDocumentProvider;
-import org.eclipse.ui.texteditor.ITextEditor;
-import org.eclipse.ui.texteditor.ITextEditorExtension;
-import org.eclipse.ui.texteditor.ITextEditorExtension2;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.util.List;
-
-/**
- * Text action for XML files to invoke renaming
- * <p>
- * TODO: Handle other types of renaming: invoking class renaming when editing
- * class names in layout files and manifest files, renaming attribute names when
- * editing a styleable attribute, etc.
- */
-@SuppressWarnings("restriction") // Java rename refactoring
-public final class RenameResourceXmlTextAction extends Action {
- private final ITextEditor mEditor;
-
- /**
- * Creates a new {@linkplain RenameResourceXmlTextAction}
- *
- * @param editor the associated editor
- */
- public RenameResourceXmlTextAction(@NonNull ITextEditor editor) {
- super("Rename");
- mEditor = editor;
- }
-
- @Override
- public void run() {
- if (!validateEditorInputState()) {
- return;
- }
- IFile file = getFile();
- if (file == null) {
- return;
- }
- IProject project = file.getProject();
- if (project == null) {
- return;
- }
- IDocument document = getDocument();
- if (document == null) {
- return;
- }
- ITextSelection selection = getSelection();
- if (selection == null) {
- return;
- }
-
- ResourceUrl resource = findResource(document, selection.getOffset());
-
- if (resource == null) {
- resource = findItemDefinition(document, selection.getOffset());
- }
-
- if (resource != null) {
- ResourceType type = resource.type;
- String name = resource.name;
- Shell shell = mEditor.getSite().getShell();
- boolean canClear = false;
-
- RenameResourceWizard.renameResource(shell, project, type, name, null, canClear);
- return;
- }
-
- String className = findClassName(document, file, selection.getOffset());
- if (className != null) {
- assert className.equals(className.trim());
- IType type = findType(className, project);
- if (type != null) {
- RenameTypeProcessor processor = new RenameTypeProcessor(type);
- //processor.setNewElementName(className);
- processor.setUpdateQualifiedNames(true);
- processor.setUpdateSimilarDeclarations(false);
- //processor.setMatchStrategy(?);
- //processor.setFilePatterns(patterns);
- processor.setUpdateReferences(true);
-
- RenameRefactoring refactoring = new RenameRefactoring(processor);
- RenameTypeWizard wizard = new RenameTypeWizard(refactoring);
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
- op.run(window.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- }
- }
-
- return;
- }
-
- // Fallback: tell user the cursor isn't in the right place
- MessageDialog.openInformation(mEditor.getSite().getShell(),
- "Rename",
- "Operation unavailable on the current selection.\n"
- + "Select an Android resource name or class.");
- }
-
- private boolean validateEditorInputState() {
- if (mEditor instanceof ITextEditorExtension2)
- return ((ITextEditorExtension2) mEditor).validateEditorInputState();
- else if (mEditor instanceof ITextEditorExtension)
- return !((ITextEditorExtension) mEditor).isEditorInputReadOnly();
- else if (mEditor != null)
- return mEditor.isEditable();
- else
- return false;
- }
-
- /**
- * Searches for a resource URL around the caret, such as {@code @string/foo}
- *
- * @param document the document to search in
- * @param offset the offset to search at
- * @return a resource pair, or null if not found
- */
- @Nullable
- public static ResourceUrl findResource(@NonNull IDocument document, int offset) {
- try {
- int max = document.getLength();
- if (offset >= max) {
- offset = max - 1;
- } else if (offset < 0) {
- offset = 0;
- } else if (offset > 0) {
- // If the caret is right after a resource name (meaning getChar(offset) points
- // to the following character), back up
- char c = document.getChar(offset);
- if (!isValidResourceNameChar(c)) {
- offset--;
- }
- }
-
- int start = offset;
- boolean valid = true;
- for (; start >= 0; start--) {
- char c = document.getChar(start);
- if (c == '@' || c == '?') {
- break;
- } else if (!isValidResourceNameChar(c)) {
- valid = false;
- break;
- }
- }
- if (valid) {
- // Search forwards for the end
- int end = start + 1;
- for (; end < max; end++) {
- char c = document.getChar(end);
- if (!isValidResourceNameChar(c)) {
- break;
- }
- }
- if (end > start + 1) {
- String url = document.get(start, end - start);
-
- // Don't allow renaming framework resources -- @android:string/ok etc
- if (url.startsWith(ANDROID_PREFIX) || url.startsWith(ANDROID_THEME_PREFIX)) {
- return null;
- }
-
- return ResourceUrl.parse(url);
- }
- }
- } catch (BadLocationException e) {
- AdtPlugin.log(e, null);
- }
-
- return null;
- }
-
- private static boolean isValidResourceNameChar(char c) {
- return c == '@' || c == '?' || c == '/' || c == '+' || Character.isJavaIdentifierPart(c);
- }
-
- /**
- * Searches for an item definition around the caret, such as
- * {@code <string name="foo">My String</string>}
- */
- private ResourceUrl findItemDefinition(IDocument document, int offset) {
- Node node = DomUtilities.getNode(document, offset);
- if (node == null) {
- return null;
- }
- if (node.getNodeType() == Node.TEXT_NODE) {
- node = node.getParentNode();
- }
- if (node == null || node.getNodeType() != Node.ELEMENT_NODE) {
- return null;
- }
-
- Element element = (Element) node;
- String name = element.getAttribute(ATTR_NAME);
- if (name == null || name.isEmpty()) {
- return null;
- }
- String typeString = element.getTagName();
- if (TAG_ITEM.equals(typeString)) {
- typeString = element.getAttribute(ATTR_TYPE);
- if (typeString == null || typeString.isEmpty()) {
- return null;
- }
- }
- ResourceType type = ResourceType.getEnum(typeString);
- if (type != null) {
- return ResourceUrl.create(type, name, false, false);
- }
-
- return null;
- }
-
- /**
- * Searches for a fully qualified class name around the caret, such as {@code foo.bar.MyClass}
- *
- * @param document the document to search in
- * @param file the file, if known
- * @param offset the offset to search at
- * @return a resource pair, or null if not found
- */
- @Nullable
- public static String findClassName(
- @NonNull IDocument document,
- @Nullable IFile file,
- int offset) {
- try {
- int max = document.getLength();
- if (offset >= max) {
- offset = max - 1;
- } else if (offset < 0) {
- offset = 0;
- } else if (offset > 0) {
- // If the caret is right after a resource name (meaning getChar(offset) points
- // to the following character), back up
- char c = document.getChar(offset);
- if (Character.isJavaIdentifierPart(c)) {
- offset--;
- }
- }
-
- int start = offset;
- for (; start >= 0; start--) {
- char c = document.getChar(start);
- if (c == '"' || c == '<' || c == '/') {
- start++;
- break;
- } else if (c != '.' && !Character.isJavaIdentifierPart(c)) {
- return null;
- }
- }
- // Search forwards for the end
- int end = start + 1;
- for (; end < max; end++) {
- char c = document.getChar(end);
- if (c != '.' && !Character.isJavaIdentifierPart(c)) {
- if (c != '"' && c != '>' && !Character.isWhitespace(c)) {
- return null;
- }
- break;
- }
- }
- if (end > start + 1) {
- String fqcn = document.get(start, end - start);
- int dot = fqcn.indexOf('.');
- if (dot == -1) { // Only support fully qualified names
- return null;
- }
- if (dot == 0) { // Special case for manifests: prepend package
- if (file != null && file.getName().equals(ANDROID_MANIFEST_XML)) {
- ManifestInfo info = ManifestInfo.get(file.getProject());
- return info.getPackage() + fqcn;
- }
- return null;
- }
-
- return fqcn;
- }
- } catch (BadLocationException e) {
- AdtPlugin.log(e, null);
- }
-
- return null;
- }
-
- @Nullable
- private IType findType(@NonNull String className, @NonNull IProject project) {
- IType type = null;
- try {
- IJavaProject javaProject = BaseProjectHelper.getJavaProject(project);
- type = javaProject.findType(className);
- if (type == null || !type.exists()) {
- return null;
- }
- if (!type.isBinary()) {
- return type;
- }
- // See if this class is coming through a library project jar file and
- // if so locate the real class
- ProjectState projectState = Sdk.getProjectState(project);
- if (projectState != null) {
- List<IProject> libraries = projectState.getFullLibraryProjects();
- for (IProject library : libraries) {
- javaProject = BaseProjectHelper.getJavaProject(library);
- type = javaProject.findType(className);
- if (type != null && type.exists() && !type.isBinary()) {
- return type;
- }
- }
- }
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
-
- return null;
- }
-
- private ITextSelection getSelection() {
- ISelectionProvider selectionProvider = mEditor.getSelectionProvider();
- if (selectionProvider == null) {
- return null;
- }
- ISelection selection = selectionProvider.getSelection();
- if (!(selection instanceof ITextSelection)) {
- return null;
- }
- return (ITextSelection) selection;
- }
-
- private IDocument getDocument() {
- IDocumentProvider documentProvider = mEditor.getDocumentProvider();
- if (documentProvider == null) {
- return null;
- }
- IDocument document = documentProvider.getDocument(mEditor.getEditorInput());
- if (document == null) {
- return null;
- }
- return document;
- }
-
- @Nullable
- private IFile getFile() {
- IEditorInput input = mEditor.getEditorInput();
- if (input instanceof IFileEditorInput) {
- IFileEditorInput fileInput = (IFileEditorInput) input;
- return fileInput.getFile();
- }
-
- return null;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResult.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResult.java
deleted file mode 100644
index ade346fa9..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/core/RenameResult.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * 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 com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-
-/**
- * A result from a renaming operation
- */
-public class RenameResult {
- private boolean mCanceled;
- private boolean mUnavailable;
- private @Nullable String mName;
- private boolean mClear;
-
- /**
- * Constructs a new rename result
- */
- private RenameResult() {
- }
-
- /**
- * Creates a new blank {@linkplain RenameResult}
- * @return a new result
- */
- @NonNull
- public static RenameResult create() {
- return new RenameResult();
- }
-
- /**
- * Creates a new {@linkplain RenameResult} for a user canceled renaming operation
- * @return a canceled operation
- */
- @NonNull
- public static RenameResult canceled() {
- return new RenameResult().setCanceled(true);
- }
-
- /**
- * Creates a {@linkplain RenameResult} for a renaming operation that was
- * not available (for example because the field attempted to be renamed
- * does not yet exist (or does not exist any more)
- *
- * @return a new result
- */
- @NonNull
- public static RenameResult unavailable() {
- return new RenameResult().setUnavailable(true);
- }
-
- /**
- * Creates a new {@linkplain RenameResult} for a successful renaming
- * operation to the given name
- *
- * @param name the new name
- * @return a new result
- */
- @NonNull
- public static RenameResult name(@Nullable String name) {
- return new RenameResult().setName(name);
- }
-
- /**
- * Marks this result as canceled
- *
- * @param canceled whether the result was canceled
- * @return this, for constructor chaining
- */
- @NonNull
- public RenameResult setCanceled(boolean canceled) {
- mCanceled = canceled;
- return this;
- }
-
- /**
- * Marks this result as unavailable
- *
- * @param unavailable whether this result was unavailable
- * @return this, for constructor chaining
- */
- @NonNull
- public RenameResult setUnavailable(boolean unavailable) {
- mUnavailable = unavailable;
- return this;
- }
-
- /**
- * Sets the new name of the renaming operation
- *
- * @param name the new name
- * @return this, for constructor chaining
- */
- @NonNull
- public RenameResult setName(@Nullable String name) {
- mName = name;
- return this;
- }
-
- /**
- * Marks this result as clearing the name (reverting it back to the default)
- *
- * @param clear whether the name was cleared
- * @return this, for constructor chaining
- */
- @NonNull
- public RenameResult setCleared(boolean clear) {
- mClear = clear;
- return this;
- }
-
- /**
- * Returns whether this result represents a canceled renaming operation
- *
- * @return true if the operation was canceled
- */
- public boolean isCanceled() {
- return mCanceled;
- }
-
- /**
- * Returns whether this result represents an unavailable renaming operation
- *
- * @return true if the operation was not available
- */
- public boolean isUnavailable() {
- return mUnavailable;
- }
-
- /**
- * Returns whether this result represents a renaming back to the default (possibly
- * clear) name. In this case, {@link #getName()} will return {@code null}.
- *
- * @return true if the name should be reset
- */
- public boolean isCleared() {
- return mClear;
- }
-
- /**
- * Returns the new name.
- *
- * @return the new name
- */
- @Nullable
- public String getName() {
- return mName;
- }
-} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/EnabledTextEditGroup.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/EnabledTextEditGroup.java
deleted file mode 100644
index 15f6c4719..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/EnabledTextEditGroup.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.extractstring;
-
-import org.eclipse.text.edits.TextEditGroup;
-
-/**
- * A {@link TextEditGroup} that we want to enable or disable by default.
- * This is used to propose a change that may not compile, so we'll create
- * a change that is disabled.
- * <p/>
- * Disabling the change is done by the refactoring class when processing
- * the text edit groups generated by the Java AST visitor.
- */
-class EnabledTextEditGroup extends TextEditGroup {
- private final boolean mEnabled;
-
- public EnabledTextEditGroup(String name, boolean enabled) {
- super(name);
- mEnabled = enabled;
- }
-
- public boolean isEnabled() {
- return mEnabled;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringAction.java
deleted file mode 100644
index 14556fd9f..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringAction.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2009 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.extractstring;
-
-import com.android.ide.eclipse.adt.AdtConstants;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.IWorkbenchWindowActionDelegate;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.part.FileEditorInput;
-
-/*
- * Quick Reference Link:
- * http://www.eclipse.org/articles/article.php?file=Article-Unleashing-the-Power-of-Refactoring/index.html
- * and
- * http://www.ibm.com/developerworks/opensource/library/os-ecjdt/
- */
-
-/**
- * Action executed when the "Extract String" menu item is invoked.
- * <p/>
- * The intent of the action is to start a refactoring that extracts a source string and
- * replaces it by an Android string resource ID.
- * <p/>
- * Workflow:
- * <ul>
- * <li> The action is currently located in the Refactoring menu in the main menu.
- * <li> TODO: extend the popup refactoring menu in a Java or Android XML file.
- * <li> The action is only enabled if the selection is 1 character or more. That is at least part
- * of the string must be selected, it's not enough to just move the insertion point. This is
- * a limitation due to {@link #selectionChanged(IAction, ISelection)} not being called when
- * the insertion point is merely moved. TODO: address this limitation.
- * <ul> The action gets the current {@link ISelection}. It also knows the current
- * {@link IWorkbenchWindow}. However for the refactoring we are also interested in having the
- * actual resource file. By looking at the Active Window > Active Page > Active Editor we
- * can get the {@link IEditorInput} and find the {@link ICompilationUnit} (aka Java file)
- * that is being edited.
- * <ul> TODO: change this to find the {@link IFile} being manipulated. The {@link ICompilationUnit}
- * can be inferred using {@link JavaCore#createCompilationUnitFrom(IFile)}. This will allow
- * us to be able to work with a selection from an Android XML file later.
- * <li> The action creates a new {@link ExtractStringRefactoring} and make it run on in a new
- * {@link ExtractStringWizard}.
- * <ul>
- */
-public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
-
- /** Keep track of the current workbench window. */
- private IWorkbenchWindow mWindow;
- private ITextSelection mSelection;
- private IEditorPart mEditor;
- private IFile mFile;
-
- /**
- * Keep track of the current workbench window.
- */
- @Override
- public void init(IWorkbenchWindow window) {
- mWindow = window;
- }
-
- @Override
- public void dispose() {
- // Nothing to do
- }
-
- /**
- * Examine the selection to determine if the action should be enabled or not.
- * <p/>
- * Keep a link to the relevant selection structure (i.e. a part of the Java AST).
- */
- @Override
- public void selectionChanged(IAction action, ISelection selection) {
-
- // Note, two kinds of selections are returned here:
- // ITextSelection on a Java source window
- // IStructuredSelection in the outline or navigator
- // This simply deals with the refactoring based on a non-empty selection.
- // At that point, just enable the action and later decide if it's valid when it actually
- // runs since we don't have access to the AST yet.
-
- mSelection = null;
- mFile = null;
-
- if (selection instanceof ITextSelection) {
- mSelection = (ITextSelection) selection;
- if (mSelection.getLength() > 0) {
- mEditor = getActiveEditor();
- mFile = getSelectedFile(mEditor);
- }
- }
-
- action.setEnabled(mSelection != null && mFile != null);
- }
-
- /**
- * Create a new instance of our refactoring and a wizard to configure it.
- */
- @Override
- public void run(IAction action) {
- if (mSelection != null && mFile != null) {
- ExtractStringRefactoring ref = new ExtractStringRefactoring(mFile, mEditor, mSelection);
- RefactoringWizard wizard = new ExtractStringWizard(ref, mFile.getProject());
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- // Interrupted. Pass.
- }
- }
- }
-
- /**
- * Returns the active editor (hopefully matching our selection) or null.
- */
- private IEditorPart getActiveEditor() {
- IWorkbenchWindow wwin = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
- if (wwin != null) {
- IWorkbenchPage page = wwin.getActivePage();
- if (page != null) {
- return page.getActiveEditor();
- }
- }
-
- return null;
- }
-
- /**
- * Returns the active {@link IFile} (hopefully matching our selection) or null.
- * The file is only returned if it's a file from a project with an Android nature.
- * <p/>
- * At that point we do not try to analyze if the selection nor the file is suitable
- * for the refactoring. This check is performed when the refactoring is invoked since
- * it can then produce meaningful error messages as needed.
- */
- private IFile getSelectedFile(IEditorPart editor) {
- if (editor != null) {
- IEditorInput input = editor.getEditorInput();
-
- if (input instanceof FileEditorInput) {
- FileEditorInput fi = (FileEditorInput) input;
- IFile file = fi.getFile();
- if (file.exists()) {
- IProject proj = file.getProject();
- try {
- if (proj != null && proj.hasNature(AdtConstants.NATURE_DEFAULT)) {
- return file;
- }
- } catch (CoreException e) {
- // ignore
- }
- }
- }
- }
-
- return null;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringContribution.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringContribution.java
deleted file mode 100644
index 61bd06e81..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringContribution.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2009 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.extractstring;
-
-import org.eclipse.ltk.core.refactoring.RefactoringContribution;
-import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
-
-import java.util.Map;
-
-/**
- * @see ExtractStringDescriptor
- */
-public class ExtractStringContribution extends RefactoringContribution {
-
- /* (non-Javadoc)
- * @see org.eclipse.ltk.core.refactoring.RefactoringContribution#createDescriptor(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.util.Map, int)
- */
- @SuppressWarnings({"unchecked", "rawtypes"})
- @Override
- public RefactoringDescriptor createDescriptor(
- String id,
- String project,
- String description,
- String comment,
- Map arguments,
- int flags)
- throws IllegalArgumentException {
- return new ExtractStringDescriptor(project, description, comment, arguments);
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- public Map retrieveArgumentMap(RefactoringDescriptor descriptor) {
- if (descriptor instanceof ExtractStringDescriptor) {
- return ((ExtractStringDescriptor) descriptor).getArguments();
- }
- return super.retrieveArgumentMap(descriptor);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringDescriptor.java
deleted file mode 100644
index 190736aad..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringDescriptor.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2009 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.extractstring;
-
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-
-import java.util.Map;
-
-/**
- * A descriptor that allows an {@link ExtractStringRefactoring} to be created from
- * a previous instance of itself.
- */
-public class ExtractStringDescriptor extends RefactoringDescriptor {
-
- public static final String ID =
- "com.android.ide.eclipse.adt.refactoring.extract.string"; //$NON-NLS-1$
-
- private final Map<String, String> mArguments;
-
- public ExtractStringDescriptor(String project, String description, String comment,
- Map<String, String> arguments) {
- super(ID, project, description, comment,
- RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE //flags
- );
- mArguments = arguments;
- }
-
- public Map<String, String> getArguments() {
- return mArguments;
- }
-
- /**
- * Creates a new refactoring instance for this refactoring descriptor based on
- * an argument map. The argument map is created by the refactoring itself in
- * {@link ExtractStringRefactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)}
- * <p/>
- * This is apparently used to replay a refactoring.
- *
- * {@inheritDoc}
- *
- * @throws CoreException
- */
- @Override
- public Refactoring createRefactoring(RefactoringStatus status) throws CoreException {
- try {
- ExtractStringRefactoring ref = new ExtractStringRefactoring(mArguments);
- return ref;
- } catch (NullPointerException e) {
- status.addFatalError("Failed to recreate ExtractStringRefactoring from descriptor");
- return null;
- }
- }
-
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringInputPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringInputPage.java
deleted file mode 100644
index 5ac5f5c4e..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringInputPage.java
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Copyright (C) 2009 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.extractstring;
-
-
-import com.android.SdkConstants;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector;
-import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.SelectorMode;
-import com.android.resources.ResourceFolderType;
-
-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.jface.wizard.WizardPage;
-import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Group;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TreeSet;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @see ExtractStringRefactoring
- */
-class ExtractStringInputPage extends UserInputWizardPage {
-
- /** Last res file path used, shared across the session instances but specific to the
- * current project. The default for unknown projects is {@link #DEFAULT_RES_FILE_PATH}. */
- private static HashMap<String, String> sLastResFilePath = new HashMap<String, String>();
-
- /** The project where the user selection happened. */
- private final IProject mProject;
-
- /** Text field where the user enters the new ID to be generated or replaced with. */
- private Combo mStringIdCombo;
- /** Text field where the user enters the new string value. */
- private Text mStringValueField;
- /** The configuration selector, to select the resource path of the XML file. */
- private ConfigurationSelector mConfigSelector;
- /** The combo to display the existing XML files or enter a new one. */
- private Combo mResFileCombo;
- /** Checkbox asking whether to replace in all Java files. */
- private Button mReplaceAllJava;
- /** Checkbox asking whether to replace in all XML files with same name but other res config */
- private Button mReplaceAllXml;
-
- /** Regex pattern to read a valid res XML file path. It checks that the are 2 folders and
- * a leaf file name ending with .xml */
- private static final Pattern RES_XML_FILE_REGEX = Pattern.compile(
- "/res/[a-z][a-zA-Z0-9_-]+/[^.]+\\.xml"); //$NON-NLS-1$
- /** Absolute destination folder root, e.g. "/res/" */
- private static final String RES_FOLDER_ABS =
- AdtConstants.WS_RESOURCES + AdtConstants.WS_SEP;
- /** Relative destination folder root, e.g. "res/" */
- private static final String RES_FOLDER_REL =
- SdkConstants.FD_RESOURCES + AdtConstants.WS_SEP;
-
- private static final String DEFAULT_RES_FILE_PATH = "/res/values/strings.xml"; //$NON-NLS-1$
-
- private XmlStringFileHelper mXmlHelper = new XmlStringFileHelper();
-
- private final OnConfigSelectorUpdated mOnConfigSelectorUpdated = new OnConfigSelectorUpdated();
-
- private ModifyListener mValidateOnModify = new ModifyListener() {
- @Override
- public void modifyText(ModifyEvent e) {
- validatePage();
- }
- };
-
- private SelectionListener mValidateOnSelection = new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- validatePage();
- }
- };
-
- public ExtractStringInputPage(IProject project) {
- super("ExtractStringInputPage"); //$NON-NLS-1$
- mProject = project;
- }
-
- /**
- * Create the UI for the refactoring wizard.
- * <p/>
- * Note that at that point the initial conditions have been checked in
- * {@link ExtractStringRefactoring}.
- * <p/>
- *
- * Note: the special tag below defines this as the entry point for the WindowsDesigner Editor.
- * @wbp.parser.entryPoint
- */
- @Override
- public void createControl(Composite parent) {
- Composite content = new Composite(parent, SWT.NONE);
- GridLayout layout = new GridLayout();
- content.setLayout(layout);
-
- createStringGroup(content);
- createResFileGroup(content);
- createOptionGroup(content);
-
- initUi();
- setControl(content);
- }
-
- /**
- * Creates the top group with the field to replace which string and by what
- * and by which options.
- *
- * @param content A composite with a 1-column grid layout
- */
- public void createStringGroup(Composite content) {
-
- final ExtractStringRefactoring ref = getOurRefactoring();
-
- Group group = new Group(content, SWT.NONE);
- group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- group.setText("New String");
- if (ref.getMode() == ExtractStringRefactoring.Mode.EDIT_SOURCE) {
- group.setText("String Replacement");
- }
-
- GridLayout layout = new GridLayout();
- layout.numColumns = 2;
- group.setLayout(layout);
-
- // line: Textfield for string value (based on selection, if any)
-
- Label label = new Label(group, SWT.NONE);
- label.setText("&String");
-
- String selectedString = ref.getTokenString();
-
- mStringValueField = new Text(group, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
- mStringValueField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- mStringValueField.setText(selectedString != null ? selectedString : ""); //$NON-NLS-1$
-
- ref.setNewStringValue(mStringValueField.getText());
-
- mStringValueField.addModifyListener(new ModifyListener() {
- @Override
- public void modifyText(ModifyEvent e) {
- validatePage();
- }
- });
-
- // line : Textfield for new ID
-
- label = new Label(group, SWT.NONE);
- label.setText("ID &R.string.");
- if (ref.getMode() == ExtractStringRefactoring.Mode.EDIT_SOURCE) {
- label.setText("&Replace by R.string.");
- } else if (ref.getMode() == ExtractStringRefactoring.Mode.SELECT_NEW_ID) {
- label.setText("New &R.string.");
- }
-
- mStringIdCombo = new Combo(group, SWT.SINGLE | SWT.LEFT | SWT.BORDER | SWT.DROP_DOWN);
- mStringIdCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- mStringIdCombo.setText(guessId(selectedString));
- mStringIdCombo.forceFocus();
-
- ref.setNewStringId(mStringIdCombo.getText().trim());
-
- mStringIdCombo.addModifyListener(mValidateOnModify);
- mStringIdCombo.addSelectionListener(mValidateOnSelection);
- }
-
- /**
- * Creates the lower group with the fields to choose the resource confirmation and
- * the target XML file.
- *
- * @param content A composite with a 1-column grid layout
- */
- private void createResFileGroup(Composite content) {
-
- Group group = new Group(content, SWT.NONE);
- GridData gd = new GridData(GridData.FILL_HORIZONTAL);
- gd.grabExcessVerticalSpace = true;
- group.setLayoutData(gd);
- group.setText("XML resource to edit");
-
- GridLayout layout = new GridLayout();
- layout.numColumns = 2;
- group.setLayout(layout);
-
- // line: selection of the res config
-
- Label label;
- label = new Label(group, SWT.NONE);
- label.setText("&Configuration:");
-
- mConfigSelector = new ConfigurationSelector(group, SelectorMode.DEFAULT);
- gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL);
- gd.horizontalSpan = 2;
- gd.widthHint = ConfigurationSelector.WIDTH_HINT;
- gd.heightHint = ConfigurationSelector.HEIGHT_HINT;
- mConfigSelector.setLayoutData(gd);
- mConfigSelector.setOnChangeListener(mOnConfigSelectorUpdated);
-
- // line: selection of the output file
-
- label = new Label(group, SWT.NONE);
- label.setText("Resource &file:");
-
- mResFileCombo = new Combo(group, SWT.DROP_DOWN);
- mResFileCombo.select(0);
- mResFileCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- mResFileCombo.addModifyListener(mOnConfigSelectorUpdated);
- }
-
- /**
- * Creates the bottom option groups with a few checkboxes.
- *
- * @param content A composite with a 1-column grid layout
- */
- private void createOptionGroup(Composite content) {
- Group options = new Group(content, SWT.NONE);
- options.setText("Options");
- GridData gd_Options = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
- gd_Options.widthHint = 77;
- options.setLayoutData(gd_Options);
- options.setLayout(new GridLayout(1, false));
-
- mReplaceAllJava = new Button(options, SWT.CHECK);
- mReplaceAllJava.setToolTipText("When checked, the exact same string literal will be replaced in all Java files.");
- mReplaceAllJava.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- mReplaceAllJava.setText("Replace in all &Java files");
- mReplaceAllJava.addSelectionListener(mValidateOnSelection);
-
- mReplaceAllXml = new Button(options, SWT.CHECK);
- mReplaceAllXml.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- mReplaceAllXml.setToolTipText("When checked, string literals will be replaced in other XML resource files having the same name but located in different resource configuration folders.");
- mReplaceAllXml.setText("Replace in all &XML files for different configuration");
- mReplaceAllXml.addSelectionListener(mValidateOnSelection);
- }
-
- // -- Start of internal part ----------
- // Hide everything down-below from WindowsDesigner Editor
- //$hide>>$
-
- /**
- * Init UI just after it has been created the first time.
- */
- private void initUi() {
- // set output file name to the last one used
- String projPath = mProject.getFullPath().toPortableString();
- String filePath = sLastResFilePath.get(projPath);
-
- mResFileCombo.setText(filePath != null ? filePath : DEFAULT_RES_FILE_PATH);
- mOnConfigSelectorUpdated.run();
- validatePage();
- }
-
- /**
- * Utility method to guess a suitable new XML ID based on the selected string.
- */
- public static String guessId(String text) {
- if (text == null) {
- return ""; //$NON-NLS-1$
- }
-
- // make lower case
- text = text.toLowerCase(Locale.US);
-
- // everything not alphanumeric becomes an underscore
- text = text.replaceAll("[^a-zA-Z0-9]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
-
- // the id must be a proper Java identifier, so it can't start with a number
- if (text.length() > 0 && !Character.isJavaIdentifierStart(text.charAt(0))) {
- text = "_" + text; //$NON-NLS-1$
- }
- return text;
- }
-
- /**
- * Returns the {@link ExtractStringRefactoring} instance used by this wizard page.
- */
- private ExtractStringRefactoring getOurRefactoring() {
- return (ExtractStringRefactoring) getRefactoring();
- }
-
- /**
- * Validates fields of the wizard input page. Displays errors as appropriate and
- * enable the "Next" button (or not) by calling {@link #setPageComplete(boolean)}.
- *
- * If validation succeeds, this updates the text id & value in the refactoring object.
- *
- * @return True if the page has been positively validated. It may still have warnings.
- */
- private boolean validatePage() {
- boolean success = true;
-
- ExtractStringRefactoring ref = getOurRefactoring();
-
- ref.setReplaceAllJava(mReplaceAllJava.getSelection());
- ref.setReplaceAllXml(mReplaceAllXml.isEnabled() && mReplaceAllXml.getSelection());
-
- // Analyze fatal errors.
-
- String text = mStringIdCombo.getText().trim();
- if (text == null || text.length() < 1) {
- setErrorMessage("Please provide a resource ID.");
- success = false;
- } else {
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- boolean ok = i == 0 ?
- Character.isJavaIdentifierStart(c) :
- Character.isJavaIdentifierPart(c);
- if (!ok) {
- setErrorMessage(String.format(
- "The resource ID must be a valid Java identifier. The character %1$c at position %2$d is not acceptable.",
- c, i+1));
- success = false;
- break;
- }
- }
-
- // update the field in the refactoring object in case of success
- if (success) {
- ref.setNewStringId(text);
- }
- }
-
- String resFile = mResFileCombo.getText();
- if (success) {
- if (resFile == null || resFile.length() == 0) {
- setErrorMessage("A resource file name is required.");
- success = false;
- } else if (!RES_XML_FILE_REGEX.matcher(resFile).matches()) {
- setErrorMessage("The XML file name is not valid.");
- success = false;
- }
- }
-
- // Analyze info & warnings.
-
- if (success) {
- setErrorMessage(null);
-
- ref.setTargetFile(resFile);
- sLastResFilePath.put(mProject.getFullPath().toPortableString(), resFile);
-
- String idValue = mXmlHelper.valueOfStringId(mProject, resFile, text);
- if (idValue != null) {
- String msg = String.format("%1$s already contains a string ID '%2$s' with value '%3$s'.",
- resFile,
- text,
- idValue);
- if (ref.getMode() == ExtractStringRefactoring.Mode.SELECT_NEW_ID) {
- setErrorMessage(msg);
- success = false;
- } else {
- setMessage(msg, WizardPage.WARNING);
- }
- } else if (mProject.findMember(resFile) == null) {
- setMessage(
- String.format("File %2$s does not exist and will be created.",
- text, resFile),
- WizardPage.INFORMATION);
- } else {
- setMessage(null);
- }
- }
-
- if (success) {
- // Also update the text value in case of success.
- ref.setNewStringValue(mStringValueField.getText());
- }
-
- setPageComplete(success);
- return success;
- }
-
- private void updateStringValueCombo() {
- String resFile = mResFileCombo.getText();
- Map<String, String> ids = mXmlHelper.getResIdsForFile(mProject, resFile);
-
- // get the current text from the combo, to make sure we don't change it
- String currText = mStringIdCombo.getText();
-
- // erase the choices and fill with the given ids
- mStringIdCombo.removeAll();
- mStringIdCombo.setItems(ids.keySet().toArray(new String[ids.size()]));
-
- // set the current text to preserve it in case it changed
- if (!currText.equals(mStringIdCombo.getText())) {
- mStringIdCombo.setText(currText);
- }
- }
-
- private class OnConfigSelectorUpdated implements Runnable, ModifyListener {
-
- /** Regex pattern to parse a valid res path: it reads (/res/folder-name/)+(filename). */
- private final Pattern mPathRegex = Pattern.compile(
- "(/res/[a-z][a-zA-Z0-9_-]+/)(.+)"); //$NON-NLS-1$
-
- /** Temporary config object used to retrieve the Config Selector value. */
- private FolderConfiguration mTempConfig = new FolderConfiguration();
-
- private HashMap<String, TreeSet<String>> mFolderCache =
- new HashMap<String, TreeSet<String>>();
- private String mLastFolderUsedInCombo = null;
- private boolean mInternalConfigChange;
- private boolean mInternalFileComboChange;
-
- /**
- * Callback invoked when the {@link ConfigurationSelector} has been changed.
- * <p/>
- * The callback does the following:
- * <ul>
- * <li> Examine the current file name to retrieve the XML filename, if any.
- * <li> Recompute the path based on the configuration selector (e.g. /res/values-fr/).
- * <li> Examine the path to retrieve all the files in it. Keep those in a local cache.
- * <li> If the XML filename from step 1 is not in the file list, it's a custom file name.
- * Insert it and sort it.
- * <li> Re-populate the file combo with all the choices.
- * <li> Select the original XML file.
- */
- @Override
- public void run() {
- if (mInternalConfigChange) {
- return;
- }
-
- // get current leafname, if any
- String leafName = ""; //$NON-NLS-1$
- String currPath = mResFileCombo.getText();
- Matcher m = mPathRegex.matcher(currPath);
- if (m.matches()) {
- // Note: groups 1 and 2 cannot be null.
- leafName = m.group(2);
- currPath = m.group(1);
- } else {
- // There was a path but it was invalid. Ignore it.
- currPath = ""; //$NON-NLS-1$
- }
-
- // recreate the res path from the current configuration
- mConfigSelector.getConfiguration(mTempConfig);
- StringBuffer sb = new StringBuffer(RES_FOLDER_ABS);
- sb.append(mTempConfig.getFolderName(ResourceFolderType.VALUES));
- sb.append(AdtConstants.WS_SEP);
-
- String newPath = sb.toString();
-
- if (newPath.equals(currPath) && newPath.equals(mLastFolderUsedInCombo)) {
- // Path has not changed. No need to reload.
- return;
- }
-
- // Get all the files at the new path
-
- TreeSet<String> filePaths = mFolderCache.get(newPath);
-
- if (filePaths == null) {
- filePaths = new TreeSet<String>();
-
- IFolder folder = mProject.getFolder(newPath);
- if (folder != null && folder.exists()) {
- try {
- for (IResource res : folder.members()) {
- String name = res.getName();
- if (res.getType() == IResource.FILE && name.endsWith(".xml")) {
- filePaths.add(newPath + name);
- }
- }
- } catch (CoreException e) {
- // Ignore.
- }
- }
-
- mFolderCache.put(newPath, filePaths);
- }
-
- currPath = newPath + leafName;
- if (leafName.length() > 0 && !filePaths.contains(currPath)) {
- filePaths.add(currPath);
- }
-
- // Fill the combo
- try {
- mInternalFileComboChange = true;
-
- mResFileCombo.removeAll();
-
- for (String filePath : filePaths) {
- mResFileCombo.add(filePath);
- }
-
- int index = -1;
- if (leafName.length() > 0) {
- index = mResFileCombo.indexOf(currPath);
- if (index >= 0) {
- mResFileCombo.select(index);
- }
- }
-
- if (index == -1) {
- mResFileCombo.setText(currPath);
- }
-
- mLastFolderUsedInCombo = newPath;
-
- } finally {
- mInternalFileComboChange = false;
- }
-
- // finally validate the whole page
- updateStringValueCombo();
- validatePage();
- }
-
- /**
- * Callback invoked when {@link ExtractStringInputPage#mResFileCombo} has been
- * modified.
- */
- @Override
- public void modifyText(ModifyEvent e) {
- if (mInternalFileComboChange) {
- return;
- }
-
- String wsFolderPath = mResFileCombo.getText();
-
- // This is a custom path, we need to sanitize it.
- // First it should start with "/res/". Then we need to make sure there are no
- // relative paths, things like "../" or "./" or even "//".
- wsFolderPath = wsFolderPath.replaceAll("/+\\.\\./+|/+\\./+|//+|\\\\+|^/+", "/"); //$NON-NLS-1$ //$NON-NLS-2$
- wsFolderPath = wsFolderPath.replaceAll("^\\.\\./+|^\\./+", ""); //$NON-NLS-1$ //$NON-NLS-2$
- wsFolderPath = wsFolderPath.replaceAll("/+\\.\\.$|/+\\.$|/+$", ""); //$NON-NLS-1$ //$NON-NLS-2$
-
- // We get "res/foo" from selections relative to the project when we want a "/res/foo" path.
- if (wsFolderPath.startsWith(RES_FOLDER_REL)) {
- wsFolderPath = RES_FOLDER_ABS + wsFolderPath.substring(RES_FOLDER_REL.length());
-
- mInternalFileComboChange = true;
- mResFileCombo.setText(wsFolderPath);
- mInternalFileComboChange = false;
- }
-
- if (wsFolderPath.startsWith(RES_FOLDER_ABS)) {
- wsFolderPath = wsFolderPath.substring(RES_FOLDER_ABS.length());
-
- int pos = wsFolderPath.indexOf(AdtConstants.WS_SEP_CHAR);
- if (pos >= 0) {
- wsFolderPath = wsFolderPath.substring(0, pos);
- }
-
- String[] folderSegments = wsFolderPath.split(SdkConstants.RES_QUALIFIER_SEP);
-
- if (folderSegments.length > 0) {
- String folderName = folderSegments[0];
-
- if (folderName != null && !folderName.equals(wsFolderPath)) {
- // update config selector
- mInternalConfigChange = true;
- mConfigSelector.setConfiguration(folderSegments);
- mInternalConfigChange = false;
- }
- }
- }
-
- updateStringValueCombo();
- validatePage();
- }
- }
-
- // End of hiding from SWT Designer
- //$hide<<$
-
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringProposal.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringProposal.java
deleted file mode 100644
index 5400be4e4..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringProposal.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2011 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.extractstring;
-
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AdtUtils;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.jdt.core.IBuffer;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.dom.ASTNode;
-import org.eclipse.jdt.ui.text.java.IInvocationContext;
-import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.text.TextSelection;
-import org.eclipse.jface.text.contentassist.IContextInformation;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PlatformUI;
-
-/**
- * Proposal for extracting strings in Java files
- */
-public class ExtractStringProposal implements IJavaCompletionProposal {
- private IInvocationContext mContext;
-
- public ExtractStringProposal(IInvocationContext context) {
- mContext = context;
- }
-
- @Override
- public void apply(IDocument document) {
- IEditorPart editor = AdtUtils.getActiveEditor();
- IFile file = AdtUtils.getActiveFile();
- if (editor == null || file == null) {
- return;
- }
-
- ASTNode coveringNode = mContext.getCoveringNode();
- int start = coveringNode.getStartPosition();
- int length = coveringNode.getLength();
- ITextSelection selection = new TextSelection(start, length);
-
- ExtractStringRefactoring refactoring = new ExtractStringRefactoring(file, editor,
- selection);
-
- RefactoringWizard wizard = new ExtractStringWizard(refactoring, file.getProject());
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
- op.run(window.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- }
- }
-
- @Override
- public Point getSelection(IDocument document) {
- return null;
- }
-
- @Override
- public String getAdditionalProposalInfo() {
- try {
- ASTNode coveringNode = mContext.getCoveringNode();
- int start = coveringNode.getStartPosition();
- int length = coveringNode.getLength();
- IBuffer buffer = mContext.getCompilationUnit().getBuffer();
- StringBuilder sb = new StringBuilder();
- String string = buffer.getText(start, length);
- string = ExtractStringRefactoring.unquoteAttrValue(string);
- String token = ExtractStringInputPage.guessId(string);
-
- // Look up the beginning and the end of the line (outside of the extracted string)
- // such that we can show a preview of the diff, e.g. if you have
- // foo.setTitle("Hello"); we want to show foo.setTitle(R.string.hello);
- // so we need to extract "foo.setTitle(" and ");".
-
- // Look backwards to the beginning of the line (and strip whitespace)
- int i = start - 1;
- while (i > 0) {
- char c = buffer.getChar(i);
- if (c == '\r' || (c == '\n')) {
- break;
- }
- i--;
- }
- String linePrefix = buffer.getText(i + 1, start - (i + 1)).trim();
-
- // Look forwards to the end of the line (and strip whitespace)
- i = start + length;
- while (i < buffer.getLength()) {
- char c = buffer.getChar(i);
- if (c == '\r' || (c == '\n')) {
- break;
- }
- i++;
- }
- String lineSuffix = buffer.getText(start + length, i - (start + length));
-
- // Should we show the replacement as just R.string.foo or
- // context.getString(R.string.foo) ?
- boolean useContext = false;
- ASTNode parent = coveringNode.getParent();
- if (parent != null) {
- int type = parent.getNodeType();
- if (type == ASTNode.ASSIGNMENT
- || type == ASTNode.VARIABLE_DECLARATION_STATEMENT
- || type == ASTNode.VARIABLE_DECLARATION_FRAGMENT
- || type == ASTNode.VARIABLE_DECLARATION_EXPRESSION) {
- useContext = true;
- }
- }
-
- // Display .java change:
- sb.append("...<br>"); //$NON-NLS-1$
- sb.append(linePrefix);
- sb.append("<b>"); //$NON-NLS-1$
- if (useContext) {
- sb.append("context.getString("); //$NON-NLS-1$
- }
- sb.append("R.string."); //$NON-NLS-1$
- sb.append(token);
- if (useContext) {
- sb.append(")"); //$NON-NLS-1$
- }
- sb.append("</b>"); //$NON-NLS-1$
- sb.append(lineSuffix);
- sb.append("<br>...<br>"); //$NON-NLS-1$
-
- // Display strings.xml change:
- sb.append("<br>"); //$NON-NLS-1$
- sb.append("&lt;resources&gt;<br>"); //$NON-NLS-1$
- sb.append(" <b>&lt;string name=\""); //$NON-NLS-1$
- sb.append(token);
- sb.append("\"&gt;"); //$NON-NLS-1$
- sb.append(string);
- sb.append("&lt;/string&gt;</b><br>"); //$NON-NLS-1$
- sb.append("&lt;/resources&gt;"); //$NON-NLS-1$
-
- return sb.toString();
- } catch (JavaModelException e) {
- AdtPlugin.log(e, null);
- }
-
- return "Initiates the Extract String refactoring operation";
- }
-
- @Override
- public String getDisplayString() {
- return "Extract String";
- }
-
- @Override
- public Image getImage() {
- return AdtPlugin.getAndroidLogo();
- }
-
- @Override
- public IContextInformation getContextInformation() {
- return null;
- }
-
- @Override
- public int getRelevance() {
- return 80;
- }
-} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringRefactoring.java
deleted file mode 100644
index db0b0967d..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringRefactoring.java
+++ /dev/null
@@ -1,1933 +0,0 @@
-/*
- * Copyright (C) 2009 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.extractstring;
-
-import static com.android.SdkConstants.QUOT_ENTITY;
-import static com.android.SdkConstants.STRING_PREFIX;
-
-import com.android.SdkConstants;
-import com.android.ide.common.res2.ValueXmlHelper;
-import com.android.ide.common.xml.ManifestData;
-import com.android.ide.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.ReferenceAttributeDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode;
-import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
-import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ResourceType;
-
-import org.eclipse.core.resources.IContainer;
-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.resources.ResourceAttributes;
-import org.eclipse.core.resources.ResourcesPlugin;
-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.core.runtime.Path;
-import org.eclipse.core.runtime.SubMonitor;
-import org.eclipse.jdt.core.IBuffer;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IPackageFragment;
-import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.ToolFactory;
-import org.eclipse.jdt.core.compiler.IScanner;
-import org.eclipse.jdt.core.compiler.ITerminalSymbols;
-import org.eclipse.jdt.core.compiler.InvalidInputException;
-import org.eclipse.jdt.core.dom.AST;
-import org.eclipse.jdt.core.dom.ASTNode;
-import org.eclipse.jdt.core.dom.ASTParser;
-import org.eclipse.jdt.core.dom.CompilationUnit;
-import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
-import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.ChangeDescriptor;
-import org.eclipse.ltk.core.refactoring.CompositeChange;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.TextEditChangeGroup;
-import org.eclipse.ltk.core.refactoring.TextFileChange;
-import org.eclipse.text.edits.InsertEdit;
-import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.text.edits.ReplaceEdit;
-import org.eclipse.text.edits.TextEdit;
-import org.eclipse.text.edits.TextEditGroup;
-import org.eclipse.ui.IEditorPart;
-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.sse.core.internal.provisional.text.IStructuredDocumentRegion;
-import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
-import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
-import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;
-import org.w3c.dom.Node;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-
-/**
- * This refactoring extracts a string from a file and replaces it by an Android resource ID
- * such as R.string.foo.
- * <p/>
- * There are a number of scenarios, which are not all supported yet. The workflow works as
- * such:
- * <ul>
- * <li> User selects a string in a Java and invokes the {@link ExtractStringAction}.
- * <li> The action finds the {@link ICompilationUnit} being edited as well as the current
- * {@link ITextSelection}. The action creates a new instance of this refactoring as
- * well as an {@link ExtractStringWizard} and runs the operation.
- * <li> Step 1 of the refactoring is to check the preliminary conditions. Right now we check
- * that the java source is not read-only and is in sync. We also try to find a string under
- * the selection. If this fails, the refactoring is aborted.
- * <li> On success, the wizard is shown, which lets the user input the new ID to use.
- * <li> The wizard sets the user input values into this refactoring instance, e.g. the new string
- * ID, the XML file to update, etc. The wizard does use the utility method
- * {@link XmlStringFileHelper#valueOfStringId(IProject, String, String)} to check whether
- * the new ID is already defined in the target XML file.
- * <li> Once Preview or Finish is selected in the wizard, the
- * {@link #checkFinalConditions(IProgressMonitor)} is called to double-check the user input
- * and compute the actual changes.
- * <li> When all changes are computed, {@link #createChange(IProgressMonitor)} is invoked.
- * </ul>
- *
- * The list of changes are:
- * <ul>
- * <li> If the target XML does not exist, create it with the new string ID.
- * <li> If the target XML exists, find the <resources> node and add the new string ID right after.
- * If the node is <resources/>, it needs to be opened.
- * <li> Create an AST rewriter to edit the source Java file and replace all occurrences by the
- * new computed R.string.foo. Also need to rewrite imports to import R as needed.
- * If there's already a conflicting R included, we need to insert the FQCN instead.
- * <li> TODO: Have a pref in the wizard: [x] Change other XML Files
- * <li> TODO: Have a pref in the wizard: [x] Change other Java Files
- * </ul>
- */
-@SuppressWarnings("restriction")
-public class ExtractStringRefactoring extends Refactoring {
-
- public enum Mode {
- /**
- * the Extract String refactoring is called on an <em>existing</em> source file.
- * Its purpose is then to get the selected string of the source and propose to
- * change it by an XML id. The XML id may be a new one or an existing one.
- */
- EDIT_SOURCE,
- /**
- * The Extract String refactoring is called without any source file.
- * Its purpose is then to create a new XML string ID or select/modify an existing one.
- */
- SELECT_ID,
- /**
- * The Extract String refactoring is called without any source file.
- * Its purpose is then to create a new XML string ID. The ID must not already exist.
- */
- SELECT_NEW_ID
- }
-
- /** The {@link Mode} of operation of the refactoring. */
- private final Mode mMode;
- /** Non-null when editing an Android Resource XML file: identifies the attribute name
- * of the value being edited. When null, the source is an Android Java file. */
- private String mXmlAttributeName;
- /** The file model being manipulated.
- * Value is null when not on {@link Mode#EDIT_SOURCE} mode. */
- private final IFile mFile;
- /** The editor. Non-null when invoked from {@link ExtractStringAction}. Null otherwise. */
- private final IEditorPart mEditor;
- /** The project that contains {@link #mFile} and that contains the target XML file to modify. */
- private final IProject mProject;
- /** The start of the selection in {@link #mFile}.
- * Value is -1 when not on {@link Mode#EDIT_SOURCE} mode. */
- private final int mSelectionStart;
- /** The end of the selection in {@link #mFile}.
- * Value is -1 when not on {@link Mode#EDIT_SOURCE} mode. */
- private final int mSelectionEnd;
-
- /** The compilation unit, only defined if {@link #mFile} points to a usable Java source file. */
- private ICompilationUnit mUnit;
- /** The actual string selected, after UTF characters have been escaped, good for display.
- * Value is null when not on {@link Mode#EDIT_SOURCE} mode. */
- private String mTokenString;
-
- /** The XML string ID selected by the user in the wizard. */
- private String mXmlStringId;
- /** The XML string value. Might be different than the initial selected string. */
- private String mXmlStringValue;
- /** The path of the XML file that will define {@link #mXmlStringId}, selected by the user
- * in the wizard. This is relative to the project, e.g. "/res/values/string.xml" */
- private String mTargetXmlFileWsPath;
- /** True if we should find & replace in all Java files. */
- private boolean mReplaceAllJava;
- /** True if we should find & replace in all XML files of the same name in other res configs
- * (other than the main {@link #mTargetXmlFileWsPath}.) */
- private boolean mReplaceAllXml;
-
- /** The list of changes computed by {@link #checkFinalConditions(IProgressMonitor)} and
- * used by {@link #createChange(IProgressMonitor)}. */
- private ArrayList<Change> mChanges;
-
- private XmlStringFileHelper mXmlHelper = new XmlStringFileHelper();
-
- private static final String KEY_MODE = "mode"; //$NON-NLS-1$
- private static final String KEY_FILE = "file"; //$NON-NLS-1$
- private static final String KEY_PROJECT = "proj"; //$NON-NLS-1$
- private static final String KEY_SEL_START = "sel-start"; //$NON-NLS-1$
- private static final String KEY_SEL_END = "sel-end"; //$NON-NLS-1$
- private static final String KEY_TOK_ESC = "tok-esc"; //$NON-NLS-1$
- private static final String KEY_XML_ATTR_NAME = "xml-attr-name"; //$NON-NLS-1$
- private static final String KEY_RPLC_ALL_JAVA = "rplc-all-java"; //$NON-NLS-1$
- private static final String KEY_RPLC_ALL_XML = "rplc-all-xml"; //$NON-NLS-1$
-
- /**
- * This constructor is solely used by {@link ExtractStringDescriptor},
- * to replay a previous refactoring.
- * <p/>
- * To create a refactoring from code, please use one of the two other constructors.
- *
- * @param arguments A map previously created using {@link #createArgumentMap()}.
- * @throws NullPointerException
- */
- public ExtractStringRefactoring(Map<String, String> arguments) throws NullPointerException {
-
- mReplaceAllJava = Boolean.parseBoolean(arguments.get(KEY_RPLC_ALL_JAVA));
- mReplaceAllXml = Boolean.parseBoolean(arguments.get(KEY_RPLC_ALL_XML));
- mMode = Mode.valueOf(arguments.get(KEY_MODE));
-
- IPath path = Path.fromPortableString(arguments.get(KEY_PROJECT));
- mProject = (IProject) ResourcesPlugin.getWorkspace().getRoot().findMember(path);
-
- if (mMode == Mode.EDIT_SOURCE) {
- path = Path.fromPortableString(arguments.get(KEY_FILE));
- mFile = (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(path);
-
- mSelectionStart = Integer.parseInt(arguments.get(KEY_SEL_START));
- mSelectionEnd = Integer.parseInt(arguments.get(KEY_SEL_END));
- mTokenString = arguments.get(KEY_TOK_ESC);
- mXmlAttributeName = arguments.get(KEY_XML_ATTR_NAME);
- } else {
- mFile = null;
- mSelectionStart = mSelectionEnd = -1;
- mTokenString = null;
- mXmlAttributeName = null;
- }
-
- mEditor = null;
- }
-
- private Map<String, String> createArgumentMap() {
- HashMap<String, String> args = new HashMap<String, String>();
- args.put(KEY_RPLC_ALL_JAVA, Boolean.toString(mReplaceAllJava));
- args.put(KEY_RPLC_ALL_XML, Boolean.toString(mReplaceAllXml));
- args.put(KEY_MODE, mMode.name());
- args.put(KEY_PROJECT, mProject.getFullPath().toPortableString());
- if (mMode == Mode.EDIT_SOURCE) {
- args.put(KEY_FILE, mFile.getFullPath().toPortableString());
- args.put(KEY_SEL_START, Integer.toString(mSelectionStart));
- args.put(KEY_SEL_END, Integer.toString(mSelectionEnd));
- args.put(KEY_TOK_ESC, mTokenString);
- args.put(KEY_XML_ATTR_NAME, mXmlAttributeName);
- }
- return args;
- }
-
- /**
- * Constructor to use when the Extract String refactoring is called on an
- * *existing* source file. Its purpose is then to get the selected string of
- * the source and propose to change it by an XML id. The XML id may be a new one
- * or an existing one.
- *
- * @param file The source file to process. Cannot be null. File must exist in workspace.
- * @param editor The editor.
- * @param selection The selection in the source file. Cannot be null or empty.
- */
- public ExtractStringRefactoring(IFile file, IEditorPart editor, ITextSelection selection) {
- mMode = Mode.EDIT_SOURCE;
- mFile = file;
- mEditor = editor;
- mProject = file.getProject();
- mSelectionStart = selection.getOffset();
- mSelectionEnd = mSelectionStart + Math.max(0, selection.getLength() - 1);
- }
-
- /**
- * Constructor to use when the Extract String refactoring is called without
- * any source file. Its purpose is then to create a new XML string ID.
- * <p/>
- * For example this is currently invoked by the ResourceChooser when
- * the user wants to create a new string rather than select an existing one.
- *
- * @param project The project where the target XML file to modify is located. Cannot be null.
- * @param enforceNew If true the XML ID must be a new one.
- * If false, an existing ID can be used.
- */
- public ExtractStringRefactoring(IProject project, boolean enforceNew) {
- mMode = enforceNew ? Mode.SELECT_NEW_ID : Mode.SELECT_ID;
- mFile = null;
- mEditor = null;
- mProject = project;
- mSelectionStart = mSelectionEnd = -1;
- }
-
- /**
- * Sets the replacement string ID. Used by the wizard to set the user input.
- */
- public void setNewStringId(String newStringId) {
- mXmlStringId = newStringId;
- }
-
- /**
- * Sets the replacement string ID. Used by the wizard to set the user input.
- */
- public void setNewStringValue(String newStringValue) {
- mXmlStringValue = newStringValue;
- }
-
- /**
- * Sets the target file. This is a project path, e.g. "/res/values/strings.xml".
- * Used by the wizard to set the user input.
- */
- public void setTargetFile(String targetXmlFileWsPath) {
- mTargetXmlFileWsPath = targetXmlFileWsPath;
- }
-
- public void setReplaceAllJava(boolean replaceAllJava) {
- mReplaceAllJava = replaceAllJava;
- }
-
- public void setReplaceAllXml(boolean replaceAllXml) {
- mReplaceAllXml = replaceAllXml;
- }
-
- /**
- * @see org.eclipse.ltk.core.refactoring.Refactoring#getName()
- */
- @Override
- public String getName() {
- if (mMode == Mode.SELECT_ID) {
- return "Create or Use Android String";
- } else if (mMode == Mode.SELECT_NEW_ID) {
- return "Create New Android String";
- }
-
- return "Extract Android String";
- }
-
- public Mode getMode() {
- return mMode;
- }
-
- /**
- * Gets the actual string selected, after UTF characters have been escaped,
- * good for display. Value can be null.
- */
- public String getTokenString() {
- return mTokenString;
- }
-
- /** Returns the XML string ID selected by the user in the wizard. */
- public String getXmlStringId() {
- return mXmlStringId;
- }
-
- /**
- * Step 1 of 3 of the refactoring:
- * Checks that the current selection meets the initial condition before the ExtractString
- * wizard is shown. The check is supposed to be lightweight and quick. Note that at that
- * point the wizard has not been created yet.
- * <p/>
- * Here we scan the source buffer to find the token matching the selection.
- * The check is successful is a Java string literal is selected, the source is in sync
- * and is not read-only.
- * <p/>
- * This is also used to extract the string to be modified, so that we can display it in
- * the refactoring wizard.
- *
- * @see org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
- *
- * @throws CoreException
- */
- @Override
- public RefactoringStatus checkInitialConditions(IProgressMonitor monitor)
- throws CoreException, OperationCanceledException {
-
- mUnit = null;
- mTokenString = null;
-
- RefactoringStatus status = new RefactoringStatus();
-
- try {
- monitor.beginTask("Checking preconditions...", 6);
-
- if (mMode != Mode.EDIT_SOURCE) {
- monitor.worked(6);
- return status;
- }
-
- if (!checkSourceFile(mFile, status, monitor)) {
- return status;
- }
-
- // Try to get a compilation unit from this file. If it fails, mUnit is null.
- try {
- mUnit = JavaCore.createCompilationUnitFrom(mFile);
-
- // Make sure the unit is not read-only, e.g. it's not a class file or inside a Jar
- if (mUnit.isReadOnly()) {
- status.addFatalError("The file is read-only, please make it writeable first.");
- return status;
- }
-
- // This is a Java file. Check if it contains the selection we want.
- if (!findSelectionInJavaUnit(mUnit, status, monitor)) {
- return status;
- }
-
- } catch (Exception e) {
- // That was not a Java file. Ignore.
- }
-
- if (mUnit != null) {
- monitor.worked(1);
- return status;
- }
-
- // Check this a Layout XML file and get the selection and its context.
- if (mFile != null && SdkConstants.EXT_XML.equals(mFile.getFileExtension())) {
-
- // Currently we only support Android resource XML files, so they must have a path
- // similar to
- // project/res/<type>[-<configuration>]/*.xml
- // project/AndroidManifest.xml
- // There is no support for sub folders, so the segment count must be 4 or 2.
- // We don't need to check the type folder name because a/ we only accept
- // an AndroidXmlEditor source and b/ aapt generates a compilation error for
- // unknown folders.
-
- IPath path = mFile.getFullPath();
- if ((path.segmentCount() == 4 &&
- path.segment(1).equalsIgnoreCase(SdkConstants.FD_RESOURCES)) ||
- (path.segmentCount() == 2 &&
- path.segment(1).equalsIgnoreCase(SdkConstants.FN_ANDROID_MANIFEST_XML))) {
- if (!findSelectionInXmlFile(mFile, status, monitor)) {
- return status;
- }
- }
- }
-
- if (!status.isOK()) {
- status.addFatalError(
- "Selection must be inside a Java source or an Android Layout XML file.");
- }
-
- } finally {
- monitor.done();
- }
-
- return status;
- }
-
- /**
- * Try to find the selected Java element in the compilation unit.
- *
- * If selection matches a string literal, capture it, otherwise add a fatal error
- * to the status.
- *
- * On success, advance the monitor by 3.
- * Returns status.isOK().
- */
- private boolean findSelectionInJavaUnit(ICompilationUnit unit,
- RefactoringStatus status, IProgressMonitor monitor) {
- try {
- IBuffer buffer = unit.getBuffer();
-
- IScanner scanner = ToolFactory.createScanner(
- false, //tokenizeComments
- false, //tokenizeWhiteSpace
- false, //assertMode
- false //recordLineSeparator
- );
- scanner.setSource(buffer.getCharacters());
- monitor.worked(1);
-
- for(int token = scanner.getNextToken();
- token != ITerminalSymbols.TokenNameEOF;
- token = scanner.getNextToken()) {
- if (scanner.getCurrentTokenStartPosition() <= mSelectionStart &&
- scanner.getCurrentTokenEndPosition() >= mSelectionEnd) {
- // found the token, but only keep if the right type
- if (token == ITerminalSymbols.TokenNameStringLiteral) {
- mTokenString = new String(scanner.getCurrentTokenSource());
- }
- break;
- } else if (scanner.getCurrentTokenStartPosition() > mSelectionEnd) {
- // scanner is past the selection, abort.
- break;
- }
- }
- } catch (JavaModelException e1) {
- // Error in unit.getBuffer. Ignore.
- } catch (InvalidInputException e2) {
- // Error in scanner.getNextToken. Ignore.
- } finally {
- monitor.worked(1);
- }
-
- if (mTokenString != null) {
- // As a literal string, the token should have surrounding quotes. Remove them.
- // Note: unquoteAttrValue technically removes either " or ' paired quotes, whereas
- // the Java token should only have " quotes. Since we know the type to be a string
- // literal, there should be no confusion here.
- mTokenString = unquoteAttrValue(mTokenString);
-
- // We need a non-empty string literal
- if (mTokenString.length() == 0) {
- mTokenString = null;
- }
- }
-
- if (mTokenString == null) {
- status.addFatalError("Please select a Java string literal.");
- }
-
- monitor.worked(1);
- return status.isOK();
- }
-
- /**
- * Try to find the selected XML element. This implementation replies on the refactoring
- * originating from an Android Layout Editor. We rely on some internal properties of the
- * Structured XML editor to retrieve file content to avoid parsing it again. We also rely
- * on our specific Android XML model to get element & attribute descriptor properties.
- *
- * If selection matches a string literal, capture it, otherwise add a fatal error
- * to the status.
- *
- * On success, advance the monitor by 1.
- * Returns status.isOK().
- */
- private boolean findSelectionInXmlFile(IFile file,
- RefactoringStatus status,
- IProgressMonitor monitor) {
-
- try {
- if (!(mEditor instanceof AndroidXmlEditor)) {
- status.addFatalError("Only the Android XML Editor is currently supported.");
- return status.isOK();
- }
-
- AndroidXmlEditor editor = (AndroidXmlEditor) mEditor;
- IStructuredModel smodel = null;
- Node node = null;
- String currAttrName = null;
-
- try {
- // See the portability note in AndroidXmlEditor#getModelForRead() javadoc.
- smodel = editor.getModelForRead();
- if (smodel != null) {
- // The structured model gives the us the actual XML Node element where the
- // offset is. By using this Node, we can find the exact UiElementNode of our
- // model and thus we'll be able to get the properties of the attribute -- to
- // check if it accepts a string reference. This does not however tell us if
- // the selection is actually in an attribute value, nor which attribute is
- // being edited.
- for(int offset = mSelectionStart; offset >= 0 && node == null; --offset) {
- node = (Node) smodel.getIndexedRegion(offset);
- }
-
- if (node == null) {
- status.addFatalError(
- "The selection does not match any element in the XML document.");
- return status.isOK();
- }
-
- if (node.getNodeType() != Node.ELEMENT_NODE) {
- status.addFatalError("The selection is not inside an actual XML element.");
- return status.isOK();
- }
-
- IStructuredDocument sdoc = smodel.getStructuredDocument();
- if (sdoc != null) {
- // Portability note: all the structured document implementation is
- // under wst.sse.core.internal.provisional so we can expect it to change in
- // a distant future if they start cleaning their codebase, however unlikely
- // that is.
-
- int selStart = mSelectionStart;
- IStructuredDocumentRegion region =
- sdoc.getRegionAtCharacterOffset(selStart);
- if (region != null &&
- DOMRegionContext.XML_TAG_NAME.equals(region.getType())) {
- // Find if any sub-region representing an attribute contains the
- // selection. If it does, returns the name of the attribute in
- // currAttrName and returns the value in the field mTokenString.
- currAttrName = findSelectionInRegion(region, selStart);
-
- if (mTokenString == null) {
- status.addFatalError(
- "The selection is not inside an actual XML attribute value.");
- }
- }
- }
-
- if (mTokenString != null && node != null && currAttrName != null) {
-
- // Validate that the attribute accepts a string reference.
- // This sets mTokenString to null by side-effect when it fails and
- // adds a fatal error to the status as needed.
- validateSelectedAttribute(editor, node, currAttrName, status);
-
- } else {
- // We shouldn't get here: we're missing one of the token string, the node
- // or the attribute name. All of them have been checked earlier so don't
- // set any specific error.
- mTokenString = null;
- }
- }
- } catch (Throwable t) {
- // Since we use some internal APIs, use a broad catch-all to report any
- // unexpected issue rather than crash the whole refactoring.
- status.addFatalError(
- String.format("XML parsing error: %1$s", t.getMessage()));
- } finally {
- if (smodel != null) {
- smodel.releaseFromRead();
- }
- }
-
- } finally {
- monitor.worked(1);
- }
-
- return status.isOK();
- }
-
- /**
- * The region gives us the textual representation of the XML element
- * where the selection starts, split using sub-regions. We now just
- * need to iterate through the sub-regions to find which one
- * contains the actual selection. We're interested in an attribute
- * value however when we find one we want to memorize the attribute
- * name that was defined just before.
- *
- * @return When the cursor is on a valid attribute name or value, returns the string of
- * attribute name. As a side-effect, returns the value of the attribute in {@link #mTokenString}
- */
- private String findSelectionInRegion(IStructuredDocumentRegion region, int selStart) {
-
- String currAttrName = null;
-
- int startInRegion = selStart - region.getStartOffset();
-
- int nb = region.getNumberOfRegions();
- ITextRegionList list = region.getRegions();
- String currAttrValue = null;
-
- for (int i = 0; i < nb; i++) {
- ITextRegion subRegion = list.get(i);
- String type = subRegion.getType();
-
- if (DOMRegionContext.XML_TAG_ATTRIBUTE_NAME.equals(type)) {
- currAttrName = region.getText(subRegion);
-
- // I like to select the attribute definition and invoke
- // the extract string wizard. So if the selection is on
- // the attribute name part, find the value that is just
- // after and use it as if it were the selection.
-
- if (subRegion.getStart() <= startInRegion &&
- startInRegion < subRegion.getTextEnd()) {
- // A well-formed attribute is composed of a name,
- // an equal sign and the value. There can't be any space
- // in between, which makes the parsing a lot easier.
- if (i <= nb - 3 &&
- DOMRegionContext.XML_TAG_ATTRIBUTE_EQUALS.equals(
- list.get(i + 1).getType())) {
- subRegion = list.get(i + 2);
- type = subRegion.getType();
- if (DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(
- type)) {
- currAttrValue = region.getText(subRegion);
- }
- }
- }
-
- } else if (subRegion.getStart() <= startInRegion &&
- startInRegion < subRegion.getTextEnd() &&
- DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(type)) {
- currAttrValue = region.getText(subRegion);
- }
-
- if (currAttrValue != null) {
- // We found the value. Only accept it if not empty
- // and if we found an attribute name before.
- String text = currAttrValue;
-
- // The attribute value contains XML quotes. Remove them.
- text = unquoteAttrValue(text);
- if (text.length() > 0 && currAttrName != null) {
- // Setting mTokenString to non-null marks the fact we
- // accept this attribute.
- mTokenString = text;
- }
-
- break;
- }
- }
-
- return currAttrName;
- }
-
- /**
- * Attribute values found as text for {@link DOMRegionContext#XML_TAG_ATTRIBUTE_VALUE}
- * contain XML quotes. This removes the quotes (either single or double quotes).
- *
- * @param attrValue The attribute value, as extracted by
- * {@link IStructuredDocumentRegion#getText(ITextRegion)}.
- * Must not be null.
- * @return The attribute value, without quotes. Whitespace is not trimmed, if any.
- * String may be empty, but not null.
- */
- static String unquoteAttrValue(String attrValue) {
- int len = attrValue.length();
- int len1 = len - 1;
- if (len >= 2 &&
- attrValue.charAt(0) == '"' &&
- attrValue.charAt(len1) == '"') {
- attrValue = attrValue.substring(1, len1);
- } else if (len >= 2 &&
- attrValue.charAt(0) == '\'' &&
- attrValue.charAt(len1) == '\'') {
- attrValue = attrValue.substring(1, len1);
- }
-
- return attrValue;
- }
-
- /**
- * Validates that the attribute accepts a string reference.
- * This sets mTokenString to null by side-effect when it fails and
- * adds a fatal error to the status as needed.
- */
- private void validateSelectedAttribute(AndroidXmlEditor editor, Node node,
- String attrName, RefactoringStatus status) {
- UiElementNode rootUiNode = editor.getUiRootNode();
- UiElementNode currentUiNode =
- rootUiNode == null ? null : rootUiNode.findXmlNode(node);
- ReferenceAttributeDescriptor attrDesc = null;
-
- if (currentUiNode != null) {
- // remove any namespace prefix from the attribute name
- String name = attrName;
- int pos = name.indexOf(':');
- if (pos > 0 && pos < name.length() - 1) {
- name = name.substring(pos + 1);
- }
-
- for (UiAttributeNode attrNode : currentUiNode.getAllUiAttributes()) {
- if (attrNode.getDescriptor().getXmlLocalName().equals(name)) {
- AttributeDescriptor desc = attrNode.getDescriptor();
- if (desc instanceof ReferenceAttributeDescriptor) {
- attrDesc = (ReferenceAttributeDescriptor) desc;
- }
- break;
- }
- }
- }
-
- // The attribute descriptor is a resource reference. It must either accept
- // of any resource type or specifically accept string types.
- if (attrDesc != null &&
- (attrDesc.getResourceType() == null ||
- attrDesc.getResourceType() == ResourceType.STRING)) {
- // We have one more check to do: is the current string value already
- // an Android XML string reference? If so, we can't edit it.
- if (mTokenString != null && mTokenString.startsWith("@")) { //$NON-NLS-1$
- int pos1 = 0;
- if (mTokenString.length() > 1 && mTokenString.charAt(1) == '+') {
- pos1++;
- }
- int pos2 = mTokenString.indexOf('/');
- if (pos2 > pos1) {
- String kind = mTokenString.substring(pos1 + 1, pos2);
- if (ResourceType.STRING.getName().equals(kind)) {
- mTokenString = null;
- status.addFatalError(String.format(
- "The attribute %1$s already contains a %2$s reference.",
- attrName,
- kind));
- }
- }
- }
-
- if (mTokenString != null) {
- // We're done with all our checks. mTokenString contains the
- // current attribute value. We don't memorize the region nor the
- // attribute, however we memorize the textual attribute name so
- // that we can offer replacement for all its occurrences.
- mXmlAttributeName = attrName;
- }
-
- } else {
- mTokenString = null;
- status.addFatalError(String.format(
- "The attribute %1$s does not accept a string reference.",
- attrName));
- }
- }
-
- /**
- * Tests from org.eclipse.jdt.internal.corext.refactoringChecks#validateEdit()
- * Might not be useful.
- *
- * On success, advance the monitor by 2.
- *
- * @return False if caller should abort, true if caller should continue.
- */
- private boolean checkSourceFile(IFile file,
- RefactoringStatus status,
- IProgressMonitor monitor) {
- // check whether the source file is in sync
- if (!file.isSynchronized(IResource.DEPTH_ZERO)) {
- status.addFatalError("The file is not synchronized. Please save it first.");
- return false;
- }
- monitor.worked(1);
-
- // make sure we can write to it.
- ResourceAttributes resAttr = file.getResourceAttributes();
- if (resAttr == null || resAttr.isReadOnly()) {
- status.addFatalError("The file is read-only, please make it writeable first.");
- return false;
- }
- monitor.worked(1);
-
- return true;
- }
-
- /**
- * Step 2 of 3 of the refactoring:
- * Check the conditions once the user filled values in the refactoring wizard,
- * then prepare the changes to be applied.
- * <p/>
- * In this case, most of the sanity checks are done by the wizard so essentially this
- * should only be called if the wizard positively validated the user input.
- *
- * Here we do check that the target resource XML file either does not exists or
- * is not read-only.
- *
- * @see org.eclipse.ltk.core.refactoring.Refactoring#checkFinalConditions(IProgressMonitor)
- *
- * @throws CoreException
- */
- @Override
- public RefactoringStatus checkFinalConditions(IProgressMonitor monitor)
- throws CoreException, OperationCanceledException {
- RefactoringStatus status = new RefactoringStatus();
-
- try {
- monitor.beginTask("Checking post-conditions...", 5);
-
- if (mXmlStringId == null || mXmlStringId.length() <= 0) {
- // this is not supposed to happen
- status.addFatalError("Missing replacement string ID");
- } else if (mTargetXmlFileWsPath == null || mTargetXmlFileWsPath.length() <= 0) {
- // this is not supposed to happen
- status.addFatalError("Missing target xml file path");
- }
- monitor.worked(1);
-
- // Either that resource must not exist or it must be a writable file.
- IResource targetXml = getTargetXmlResource(mTargetXmlFileWsPath);
- if (targetXml != null) {
- if (targetXml.getType() != IResource.FILE) {
- status.addFatalError(
- String.format("XML file '%1$s' is not a file.", mTargetXmlFileWsPath));
- } else {
- ResourceAttributes attr = targetXml.getResourceAttributes();
- if (attr != null && attr.isReadOnly()) {
- status.addFatalError(
- String.format("XML file '%1$s' is read-only.",
- mTargetXmlFileWsPath));
- }
- }
- }
- monitor.worked(1);
-
- if (status.hasError()) {
- return status;
- }
-
- mChanges = new ArrayList<Change>();
-
-
- // Prepare the change to create/edit the String ID in the res/values XML file.
- if (!mXmlStringValue.equals(
- mXmlHelper.valueOfStringId(mProject, mTargetXmlFileWsPath, mXmlStringId))) {
- // We actually change it only if the ID doesn't exist yet or has a different value
- Change change = createXmlChanges((IFile) targetXml, mXmlStringId, mXmlStringValue,
- status, SubMonitor.convert(monitor, 1));
- if (change != null) {
- mChanges.add(change);
- }
- }
-
- if (status.hasError()) {
- return status;
- }
-
- if (mMode == Mode.EDIT_SOURCE) {
- List<Change> changes = null;
- if (mXmlAttributeName != null) {
- // Prepare the change to the Android resource XML file
- changes = computeXmlSourceChanges(mFile,
- mXmlStringId,
- mTokenString,
- mXmlAttributeName,
- true, // allConfigurations
- status,
- monitor);
-
- } else if (mUnit != null) {
- // Prepare the change to the Java compilation unit
- changes = computeJavaChanges(mUnit, mXmlStringId, mTokenString,
- status, SubMonitor.convert(monitor, 1));
- }
- if (changes != null) {
- mChanges.addAll(changes);
- }
- }
-
- if (mReplaceAllJava) {
- String currentIdentifier = mUnit != null ? mUnit.getHandleIdentifier() : ""; //$NON-NLS-1$
-
- SubMonitor submon = SubMonitor.convert(monitor, 1);
- for (ICompilationUnit unit : findAllJavaUnits()) {
- // Only process Java compilation units that exist, are not derived
- // and are not read-only.
- if (unit == null || !unit.exists()) {
- continue;
- }
- IResource resource = unit.getResource();
- if (resource == null || resource.isDerived()) {
- continue;
- }
-
- // Ensure that we don't process the current compilation unit (processed
- // as mUnit above) twice
- if (currentIdentifier.equals(unit.getHandleIdentifier())) {
- continue;
- }
-
- ResourceAttributes attrs = resource.getResourceAttributes();
- if (attrs != null && attrs.isReadOnly()) {
- continue;
- }
-
- List<Change> changes = computeJavaChanges(
- unit, mXmlStringId, mTokenString,
- status, SubMonitor.convert(submon, 1));
- if (changes != null) {
- mChanges.addAll(changes);
- }
- }
- }
-
- if (mReplaceAllXml) {
- SubMonitor submon = SubMonitor.convert(monitor, 1);
- for (IFile xmlFile : findAllResXmlFiles()) {
- if (xmlFile != null) {
- List<Change> changes = computeXmlSourceChanges(xmlFile,
- mXmlStringId,
- mTokenString,
- mXmlAttributeName,
- false, // allConfigurations
- status,
- SubMonitor.convert(submon, 1));
- if (changes != null) {
- mChanges.addAll(changes);
- }
- }
- }
- }
-
- monitor.worked(1);
- } finally {
- monitor.done();
- }
-
- return status;
- }
-
- // --- XML changes ---
-
- /**
- * Returns a foreach-compatible iterator over all XML files in the project's
- * /res folder, excluding the target XML file (the one where we'll write/edit
- * the string id).
- */
- private Iterable<IFile> findAllResXmlFiles() {
- return new Iterable<IFile>() {
- @Override
- public Iterator<IFile> iterator() {
- return new Iterator<IFile>() {
- final Queue<IFile> mFiles = new LinkedList<IFile>();
- final Queue<IResource> mFolders = new LinkedList<IResource>();
- IPath mFilterPath1 = null;
- IPath mFilterPath2 = null;
- {
- // Filter out the XML file where we'll be writing the XML string id.
- IResource filterRes = mProject.findMember(mTargetXmlFileWsPath);
- if (filterRes != null) {
- mFilterPath1 = filterRes.getFullPath();
- }
- // Filter out the XML source file, if any (e.g. typically a layout)
- if (mFile != null) {
- mFilterPath2 = mFile.getFullPath();
- }
-
- // We want to process the manifest
- IResource man = mProject.findMember("AndroidManifest.xml"); // TODO find a constant
- if (man.exists() && man instanceof IFile && !man.equals(mFile)) {
- mFiles.add((IFile) man);
- }
-
- // Add all /res folders (technically we don't need to process /res/values
- // XML files that contain resources/string elements, but it's easier to
- // not filter them out.)
- IFolder f = mProject.getFolder(AdtConstants.WS_RESOURCES);
- if (f.exists()) {
- try {
- mFolders.addAll(
- Arrays.asList(f.members(IContainer.EXCLUDE_DERIVED)));
- } catch (CoreException e) {
- // pass
- }
- }
- }
-
- @Override
- public boolean hasNext() {
- if (!mFiles.isEmpty()) {
- return true;
- }
-
- while (!mFolders.isEmpty()) {
- IResource res = mFolders.poll();
- if (res.exists() && res instanceof IFolder) {
- IFolder f = (IFolder) res;
- try {
- getFileList(f);
- if (!mFiles.isEmpty()) {
- return true;
- }
- } catch (CoreException e) {
- // pass
- }
- }
- }
- return false;
- }
-
- private void getFileList(IFolder folder) throws CoreException {
- for (IResource res : folder.members(IContainer.EXCLUDE_DERIVED)) {
- // Only accept file resources which are not derived and actually exist
- if (res.exists() && !res.isDerived() && res instanceof IFile) {
- IFile file = (IFile) res;
- // Must have an XML extension
- if (SdkConstants.EXT_XML.equals(file.getFileExtension())) {
- IPath p = file.getFullPath();
- // And not be either paths we want to filter out
- if ((mFilterPath1 != null && mFilterPath1.equals(p)) ||
- (mFilterPath2 != null && mFilterPath2.equals(p))) {
- continue;
- }
- mFiles.add(file);
- }
- }
- }
- }
-
- @Override
- public IFile next() {
- IFile file = mFiles.poll();
- hasNext();
- return file;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException(
- "This iterator does not support removal"); //$NON-NLS-1$
- }
- };
- }
- };
- }
-
- /**
- * Internal helper that actually prepares the {@link Change} that adds the given
- * ID to the given XML File.
- * <p/>
- * This does not actually modify the file.
- *
- * @param targetXml The file resource to modify.
- * @param xmlStringId The new ID to insert.
- * @param tokenString The old string, which will be the value in the XML string.
- * @return A new {@link TextEdit} that describes how to change the file.
- */
- private Change createXmlChanges(IFile targetXml,
- String xmlStringId,
- String tokenString,
- RefactoringStatus status,
- SubMonitor monitor) {
-
- TextFileChange xmlChange = new TextFileChange(getName(), targetXml);
- xmlChange.setTextType(SdkConstants.EXT_XML);
-
- String error = ""; //$NON-NLS-1$
- TextEdit edit = null;
- TextEditGroup editGroup = null;
-
- try {
- if (!targetXml.exists()) {
- // Kludge: use targetXml==null as a signal this is a new file being created
- targetXml = null;
- }
-
- edit = createXmlReplaceEdit(targetXml, xmlStringId, tokenString, status,
- SubMonitor.convert(monitor, 1));
- } catch (IOException e) {
- error = e.toString();
- } catch (CoreException e) {
- // Failed to read file. Ignore. Will handle error below.
- error = e.toString();
- }
-
- if (edit == null) {
- status.addFatalError(String.format("Failed to modify file %1$s%2$s",
- targetXml == null ? "" : targetXml.getFullPath(), //$NON-NLS-1$
- error == null ? "" : ": " + error)); //$NON-NLS-1$
- return null;
- }
-
- editGroup = new TextEditGroup(targetXml == null ? "Create <string> in new XML file"
- : "Insert <string> in XML file",
- edit);
-
- xmlChange.setEdit(edit);
- // The TextEditChangeGroup let the user toggle this change on and off later.
- xmlChange.addTextEditChangeGroup(new TextEditChangeGroup(xmlChange, editGroup));
-
- monitor.worked(1);
- return xmlChange;
- }
-
- /**
- * Scan the XML file to find the best place where to insert the new string element.
- * <p/>
- * This handles a variety of cases, including replacing existing ids in place,
- * adding the top resources element if missing and the XML PI if not present.
- * It tries to preserve indentation when adding new elements at the end of an existing XML.
- *
- * @param file The XML file to modify, that must be present in the workspace.
- * Pass null to create a change for a new file that doesn't exist yet.
- * @param xmlStringId The new ID to insert.
- * @param tokenString The old string, which will be the value in the XML string.
- * @param status The in-out refactoring status. Used to log a more detailed error if the
- * XML has a top element that is not a resources element.
- * @param monitor A monitor to track progress.
- * @return A new {@link TextEdit} for either a replace or an insert operation, or null in case
- * of error.
- * @throws CoreException - if the file's contents or description can not be read.
- * @throws IOException - if the file's contents can not be read or its detected encoding does
- * not support its contents.
- */
- private TextEdit createXmlReplaceEdit(IFile file,
- String xmlStringId,
- String tokenString,
- RefactoringStatus status,
- SubMonitor monitor)
- throws IOException, CoreException {
-
- IModelManager modelMan = StructuredModelManager.getModelManager();
-
- final String NODE_RESOURCES = SdkConstants.TAG_RESOURCES;
- final String NODE_STRING = SdkConstants.TAG_STRING;
- final String ATTR_NAME = SdkConstants.ATTR_NAME;
-
-
- // Scan the source to find the best insertion point.
-
- // 1- The most common case we need to handle is the one of inserting at the end
- // of a valid XML document, respecting the whitespace last used.
- //
- // Ideally we have this structure:
- // <xml ...>
- // <resource>
- // ...ws1...<string>blah</string>...ws2...
- // </resource>
- //
- // where ws1 and ws2 are the whitespace respectively before and after the last element
- // just before the closing </resource>.
- // In this case we want to generate the new string just before ws2...</resource> with
- // the same whitespace as ws1.
- //
- // 2- Another expected case is there's already an existing string which "name" attribute
- // equals to xmlStringId and we just want to replace its value.
- //
- // Other cases we need to handle:
- // 3- There is no element at all -> create a full new <resource>+<string> content.
- // 4- There is <resource/>, that is the tag is not opened. This can be handled as the
- // previous case, generating full content but also replacing <resource/>.
- // 5- There is a top element that is not <resource>. That's a fatal error and we abort.
-
- IStructuredModel smodel = null;
-
- // Single and double quotes must be escaped in the <string>value</string> declaration
- tokenString = ValueXmlHelper.escapeResourceString(tokenString);
-
- try {
- IStructuredDocument sdoc = null;
- boolean checkTopElement = true;
- boolean replaceStringContent = false;
- boolean hasPiXml = false;
- int newResStart = 0;
- int newResLength = 0;
- String lineSep = "\n"; //$NON-NLS-1$
-
- if (file != null) {
- smodel = modelMan.getExistingModelForRead(file);
- if (smodel != null) {
- sdoc = smodel.getStructuredDocument();
- } else if (smodel == null) {
- // The model is not currently open.
- if (file.exists()) {
- sdoc = modelMan.createStructuredDocumentFor(file);
- } else {
- sdoc = modelMan.createNewStructuredDocumentFor(file);
- }
- }
- }
-
- if (sdoc == null && file != null) {
- // Get a document matching the actual saved file
- sdoc = modelMan.createStructuredDocumentFor(file);
- }
-
- if (sdoc != null) {
- String wsBefore = ""; //$NON-NLS-1$
- String lastWs = null;
-
- lineSep = sdoc.getLineDelimiter();
- if (lineSep == null || lineSep.length() == 0) {
- // That wasn't too useful, let's go back to a reasonable default
- lineSep = "\n"; //$NON-NLS-1$
- }
-
- for (IStructuredDocumentRegion regions : sdoc.getStructuredDocumentRegions()) {
- String type = regions.getType();
-
- if (DOMRegionContext.XML_CONTENT.equals(type)) {
-
- if (replaceStringContent) {
- // Generate a replacement for a <string> value matching the string ID.
- return new ReplaceEdit(
- regions.getStartOffset(), regions.getLength(), tokenString);
- }
-
- // Otherwise capture what should be whitespace content
- lastWs = regions.getFullText();
- continue;
-
- } else if (DOMRegionContext.XML_PI_OPEN.equals(type) && !hasPiXml) {
-
- int nb = regions.getNumberOfRegions();
- ITextRegionList list = regions.getRegions();
- for (int i = 0; i < nb; i++) {
- ITextRegion region = list.get(i);
- type = region.getType();
- if (DOMRegionContext.XML_TAG_NAME.equals(type)) {
- String name = regions.getText(region);
- if ("xml".equals(name)) { //$NON-NLS-1$
- hasPiXml = true;
- break;
- }
- }
- }
- continue;
-
- } else if (!DOMRegionContext.XML_TAG_NAME.equals(type)) {
- // ignore things which are not a tag nor text content (such as comments)
- continue;
- }
-
- int nb = regions.getNumberOfRegions();
- ITextRegionList list = regions.getRegions();
-
- String name = null;
- String attrName = null;
- String attrValue = null;
- boolean isEmptyTag = false;
- boolean isCloseTag = false;
-
- for (int i = 0; i < nb; i++) {
- ITextRegion region = list.get(i);
- type = region.getType();
-
- if (DOMRegionContext.XML_END_TAG_OPEN.equals(type)) {
- isCloseTag = true;
- } else if (DOMRegionContext.XML_EMPTY_TAG_CLOSE.equals(type)) {
- isEmptyTag = true;
- } else if (DOMRegionContext.XML_TAG_NAME.equals(type)) {
- name = regions.getText(region);
- } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_NAME.equals(type) &&
- NODE_STRING.equals(name)) {
- // Record the attribute names into a <string> element.
- attrName = regions.getText(region);
- } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(type) &&
- ATTR_NAME.equals(attrName)) {
- // Record the value of a <string name=...> attribute
- attrValue = regions.getText(region);
-
- if (attrValue != null &&
- unquoteAttrValue(attrValue).equals(xmlStringId)) {
- // We found a <string name=> matching the string ID to replace.
- // We'll generate a replacement when we process the string value
- // (that is the next XML_CONTENT region.)
- replaceStringContent = true;
- }
- }
- }
-
- if (checkTopElement) {
- // Check the top element has a resource name
- checkTopElement = false;
- if (!NODE_RESOURCES.equals(name)) {
- status.addFatalError(
- String.format("XML file lacks a <resource> tag: %1$s",
- mTargetXmlFileWsPath));
- return null;
-
- }
-
- if (isEmptyTag) {
- // The top element is an empty "<resource/>" tag. We need to do
- // a full new resource+string replacement.
- newResStart = regions.getStartOffset();
- newResLength = regions.getLength();
- }
- }
-
- if (NODE_RESOURCES.equals(name)) {
- if (isCloseTag) {
- // We found the </resource> tag and we want
- // to insert just before this one.
-
- StringBuilder content = new StringBuilder();
- content.append(wsBefore)
- .append("<string name=\"") //$NON-NLS-1$
- .append(xmlStringId)
- .append("\">") //$NON-NLS-1$
- .append(tokenString)
- .append("</string>"); //$NON-NLS-1$
-
- // Backup to insert before the whitespace preceding </resource>
- IStructuredDocumentRegion insertBeforeReg = regions;
- while (true) {
- IStructuredDocumentRegion previous = insertBeforeReg.getPrevious();
- if (previous != null &&
- DOMRegionContext.XML_CONTENT.equals(previous.getType()) &&
- previous.getText().trim().length() == 0) {
- insertBeforeReg = previous;
- } else {
- break;
- }
- }
- if (insertBeforeReg == regions) {
- // If we have not found any whitespace before </resources>,
- // at least add a line separator.
- content.append(lineSep);
- }
-
- return new InsertEdit(insertBeforeReg.getStartOffset(),
- content.toString());
- }
- } else {
- // For any other tag than <resource>, capture whitespace before and after.
- if (!isCloseTag) {
- wsBefore = lastWs;
- }
- }
- }
- }
-
- // We reach here either because there's no XML content at all or because
- // there's an empty <resource/>.
- // Provide a full new resource+string replacement.
- StringBuilder content = new StringBuilder();
- if (!hasPiXml) {
- content.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); //$NON-NLS-1$
- content.append(lineSep);
- } else if (newResLength == 0 && sdoc != null) {
- // If inserting at the end, check if the last region is some whitespace.
- // If there's no newline, insert one ourselves.
- IStructuredDocumentRegion lastReg = sdoc.getLastStructuredDocumentRegion();
- if (lastReg != null && lastReg.getText().indexOf('\n') == -1) {
- content.append('\n');
- }
- }
-
- // FIXME how to access formatting preferences to generate the proper indentation?
- content.append("<resources>").append(lineSep); //$NON-NLS-1$
- content.append(" <string name=\"") //$NON-NLS-1$
- .append(xmlStringId)
- .append("\">") //$NON-NLS-1$
- .append(tokenString)
- .append("</string>") //$NON-NLS-1$
- .append(lineSep);
- content.append("</resources>").append(lineSep); //$NON-NLS-1$
-
- if (newResLength > 0) {
- // Replace existing piece
- return new ReplaceEdit(newResStart, newResLength, content.toString());
- } else {
- // Insert at the end.
- int offset = sdoc == null ? 0 : sdoc.getLength();
- return new InsertEdit(offset, content.toString());
- }
- } catch (IOException e) {
- // This is expected to happen and is properly reported to the UI.
- throw e;
- } catch (CoreException e) {
- // This is expected to happen and is properly reported to the UI.
- throw e;
- } catch (Throwable t) {
- // Since we use some internal APIs, use a broad catch-all to report any
- // unexpected issue rather than crash the whole refactoring.
- status.addFatalError(
- String.format("XML replace error: %1$s", t.getMessage()));
- } finally {
- if (smodel != null) {
- smodel.releaseFromRead();
- }
- }
-
- return null;
- }
-
- /**
- * Computes the changes to be made to the source Android XML file and
- * returns a list of {@link Change}.
- * <p/>
- * This function scans an XML file, looking for an attribute value equals to
- * <code>tokenString</code>. If non null, <code>xmlAttrName</code> limit the search
- * to only attributes that have that name.
- * If found, a change is made to replace each occurrence of <code>tokenString</code>
- * by a new "@string/..." using the new <code>xmlStringId</code>.
- *
- * @param sourceFile The file to process.
- * A status error will be generated if it does not exists.
- * Must not be null.
- * @param tokenString The string to find. Must not be null or empty.
- * @param xmlAttrName Optional attribute name to limit the search. Can be null.
- * @param allConfigurations True if this function should can all XML files with the same
- * name and the same resource type folder but with different configurations.
- * @param status Status used to report fatal errors.
- * @param monitor Used to log progress.
- */
- private List<Change> computeXmlSourceChanges(IFile sourceFile,
- String xmlStringId,
- String tokenString,
- String xmlAttrName,
- boolean allConfigurations,
- RefactoringStatus status,
- IProgressMonitor monitor) {
-
- if (!sourceFile.exists()) {
- status.addFatalError(String.format("XML file '%1$s' does not exist.",
- sourceFile.getFullPath().toOSString()));
- return null;
- }
-
- // We shouldn't be trying to replace a null or empty string.
- assert tokenString != null && tokenString.length() > 0;
- if (tokenString == null || tokenString.length() == 0) {
- return null;
- }
-
- // Note: initially this method was only processing files using a pattern
- // /project/res/<type>-<configuration>/<filename.xml>
- // However the last version made that more generic to be able to process any XML
- // files. We should probably revisit and simplify this later.
- HashSet<IFile> files = new HashSet<IFile>();
- files.add(sourceFile);
-
- if (allConfigurations && SdkConstants.EXT_XML.equals(sourceFile.getFileExtension())) {
- IPath path = sourceFile.getFullPath();
- if (path.segmentCount() == 4 && path.segment(1).equals(SdkConstants.FD_RESOURCES)) {
- IProject project = sourceFile.getProject();
- String filename = path.segment(3);
- String initialTypeName = path.segment(2);
- ResourceFolderType type = ResourceFolderType.getFolderType(initialTypeName);
-
- IContainer res = sourceFile.getParent().getParent();
- if (type != null && res != null && res.getType() == IResource.FOLDER) {
- try {
- for (IResource r : res.members()) {
- if (r != null && r.getType() == IResource.FOLDER) {
- String name = r.getName();
- // Skip the initial folder name, it's already in the list.
- if (!name.equals(initialTypeName)) {
- // Only accept the same folder type (e.g. layout-*)
- ResourceFolderType t =
- ResourceFolderType.getFolderType(name);
- if (type.equals(t)) {
- // recompute the path
- IPath p = res.getProjectRelativePath().append(name).
- append(filename);
- IResource f = project.findMember(p);
- if (f != null && f instanceof IFile) {
- files.add((IFile) f);
- }
- }
- }
- }
- }
- } catch (CoreException e) {
- // Ignore.
- }
- }
- }
- }
-
- SubMonitor subMonitor = SubMonitor.convert(monitor, Math.min(1, files.size()));
-
- ArrayList<Change> changes = new ArrayList<Change>();
-
- // Portability note: getModelManager is part of wst.sse.core however the
- // interface returned is part of wst.sse.core.internal.provisional so we can
- // expect it to change in a distant future if they start cleaning their codebase,
- // however unlikely that is.
- IModelManager modelManager = StructuredModelManager.getModelManager();
-
- for (IFile file : files) {
-
- IStructuredModel smodel = null;
- MultiTextEdit multiEdit = null;
- TextFileChange xmlChange = null;
- ArrayList<TextEditGroup> editGroups = null;
-
- try {
- IStructuredDocument sdoc = null;
-
- smodel = modelManager.getExistingModelForRead(file);
- if (smodel != null) {
- sdoc = smodel.getStructuredDocument();
- } else if (smodel == null) {
- // The model is not currently open.
- if (file.exists()) {
- sdoc = modelManager.createStructuredDocumentFor(file);
- } else {
- sdoc = modelManager.createNewStructuredDocumentFor(file);
- }
- }
-
- if (sdoc == null) {
- status.addFatalError("XML structured document not found"); //$NON-NLS-1$
- continue;
- }
-
- multiEdit = new MultiTextEdit();
- editGroups = new ArrayList<TextEditGroup>();
- xmlChange = new TextFileChange(getName(), file);
- xmlChange.setTextType("xml"); //$NON-NLS-1$
-
- String quotedReplacement = quotedAttrValue(STRING_PREFIX + xmlStringId);
-
- // Prepare the change set
- for (IStructuredDocumentRegion regions : sdoc.getStructuredDocumentRegions()) {
- // Only look at XML "top regions"
- if (!DOMRegionContext.XML_TAG_NAME.equals(regions.getType())) {
- continue;
- }
-
- int nb = regions.getNumberOfRegions();
- ITextRegionList list = regions.getRegions();
- String lastAttrName = null;
-
- for (int i = 0; i < nb; i++) {
- ITextRegion subRegion = list.get(i);
- String type = subRegion.getType();
-
- if (DOMRegionContext.XML_TAG_ATTRIBUTE_NAME.equals(type)) {
- // Memorize the last attribute name seen
- lastAttrName = regions.getText(subRegion);
-
- } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(type)) {
- // Check this is the attribute and the original string
- String text = regions.getText(subRegion);
-
- // Remove " or ' quoting present in the attribute value
- text = unquoteAttrValue(text);
-
- if (tokenString.equals(text) &&
- (xmlAttrName == null || xmlAttrName.equals(lastAttrName))) {
-
- // Found an occurrence. Create a change for it.
- TextEdit edit = new ReplaceEdit(
- regions.getStartOffset() + subRegion.getStart(),
- subRegion.getTextLength(),
- quotedReplacement);
- TextEditGroup editGroup = new TextEditGroup(
- "Replace attribute string by ID",
- edit);
-
- multiEdit.addChild(edit);
- editGroups.add(editGroup);
- }
- }
- }
- }
- } catch (Throwable t) {
- // Since we use some internal APIs, use a broad catch-all to report any
- // unexpected issue rather than crash the whole refactoring.
- status.addFatalError(
- String.format("XML refactoring error: %1$s", t.getMessage()));
- } finally {
- if (smodel != null) {
- smodel.releaseFromRead();
- }
-
- if (multiEdit != null &&
- xmlChange != null &&
- editGroups != null &&
- multiEdit.hasChildren()) {
- xmlChange.setEdit(multiEdit);
- for (TextEditGroup group : editGroups) {
- xmlChange.addTextEditChangeGroup(
- new TextEditChangeGroup(xmlChange, group));
- }
- changes.add(xmlChange);
- }
- subMonitor.worked(1);
- }
- } // for files
-
- if (changes.size() > 0) {
- return changes;
- }
- return null;
- }
-
- /**
- * Returns a quoted attribute value suitable to be placed after an attributeName=
- * statement in an XML stream.
- *
- * According to http://www.w3.org/TR/2008/REC-xml-20081126/#NT-AttValue
- * the attribute value can be either quoted using ' or " and the corresponding
- * entities &apos; or &quot; must be used inside.
- */
- private String quotedAttrValue(String attrValue) {
- if (attrValue.indexOf('"') == -1) {
- // no double-quotes inside, use double-quotes around.
- return '"' + attrValue + '"';
- }
- if (attrValue.indexOf('\'') == -1) {
- // no single-quotes inside, use single-quotes around.
- return '\'' + attrValue + '\'';
- }
- // If we get here, there's a mix. Opt for double-quote around and replace
- // inner double-quotes.
- attrValue = attrValue.replace("\"", QUOT_ENTITY); //$NON-NLS-1$
- return '"' + attrValue + '"';
- }
-
- // --- Java changes ---
-
- /**
- * Returns a foreach compatible iterator over all ICompilationUnit in the project.
- */
- private Iterable<ICompilationUnit> findAllJavaUnits() {
- final IJavaProject javaProject = JavaCore.create(mProject);
-
- return new Iterable<ICompilationUnit>() {
- @Override
- public Iterator<ICompilationUnit> iterator() {
- return new Iterator<ICompilationUnit>() {
- final Queue<ICompilationUnit> mUnits = new LinkedList<ICompilationUnit>();
- final Queue<IPackageFragment> mFragments = new LinkedList<IPackageFragment>();
- {
- try {
- IPackageFragment[] tmpFrags = javaProject.getPackageFragments();
- if (tmpFrags != null && tmpFrags.length > 0) {
- mFragments.addAll(Arrays.asList(tmpFrags));
- }
- } catch (JavaModelException e) {
- // pass
- }
- }
-
- @Override
- public boolean hasNext() {
- if (!mUnits.isEmpty()) {
- return true;
- }
-
- while (!mFragments.isEmpty()) {
- try {
- IPackageFragment fragment = mFragments.poll();
- if (fragment.getKind() == IPackageFragmentRoot.K_SOURCE) {
- ICompilationUnit[] tmpUnits = fragment.getCompilationUnits();
- if (tmpUnits != null && tmpUnits.length > 0) {
- mUnits.addAll(Arrays.asList(tmpUnits));
- return true;
- }
- }
- } catch (JavaModelException e) {
- // pass
- }
- }
- return false;
- }
-
- @Override
- public ICompilationUnit next() {
- ICompilationUnit unit = mUnits.poll();
- hasNext();
- return unit;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException(
- "This iterator does not support removal"); //$NON-NLS-1$
- }
- };
- }
- };
- }
-
- /**
- * Computes the changes to be made to Java file(s) and returns a list of {@link Change}.
- * <p/>
- * This function scans a Java compilation unit using {@link ReplaceStringsVisitor}, looking
- * for a string literal equals to <code>tokenString</code>.
- * If found, a change is made to replace each occurrence of <code>tokenString</code> by
- * a piece of Java code that somehow accesses R.string.<code>xmlStringId</code>.
- *
- * @param unit The compilated unit to process. Must not be null.
- * @param tokenString The string to find. Must not be null or empty.
- * @param status Status used to report fatal errors.
- * @param monitor Used to log progress.
- */
- private List<Change> computeJavaChanges(ICompilationUnit unit,
- String xmlStringId,
- String tokenString,
- RefactoringStatus status,
- SubMonitor monitor) {
-
- // We shouldn't be trying to replace a null or empty string.
- assert tokenString != null && tokenString.length() > 0;
- if (tokenString == null || tokenString.length() == 0) {
- return null;
- }
-
- // Get the Android package name from the Android Manifest. We need it to create
- // the FQCN of the R class.
- String packageName = null;
- String error = null;
- IResource manifestFile = mProject.findMember(SdkConstants.FN_ANDROID_MANIFEST_XML);
- if (manifestFile == null || manifestFile.getType() != IResource.FILE) {
- error = "File not found";
- } else {
- ManifestData manifestData = AndroidManifestHelper.parseForData((IFile) manifestFile);
- if (manifestData == null) {
- error = "Invalid content";
- } else {
- packageName = manifestData.getPackage();
- if (packageName == null) {
- error = "Missing package definition";
- }
- }
- }
-
- if (error != null) {
- status.addFatalError(
- String.format("Failed to parse file %1$s: %2$s.",
- manifestFile == null ? "" : manifestFile.getFullPath(), //$NON-NLS-1$
- error));
- return null;
- }
-
- // Right now the changes array will contain one TextFileChange at most.
- ArrayList<Change> changes = new ArrayList<Change>();
-
- // This is the unit that will be modified.
- TextFileChange change = new TextFileChange(getName(), (IFile) unit.getResource());
- change.setTextType("java"); //$NON-NLS-1$
-
- // Create an AST for this compilation unit
- ASTParser parser = ASTParser.newParser(AST.JLS3);
- parser.setProject(unit.getJavaProject());
- parser.setSource(unit);
- parser.setResolveBindings(true);
- ASTNode node = parser.createAST(monitor.newChild(1));
-
- // The ASTNode must be a CompilationUnit, by design
- if (!(node instanceof CompilationUnit)) {
- status.addFatalError(String.format("Internal error: ASTNode class %s", //$NON-NLS-1$
- node.getClass()));
- return null;
- }
-
- // ImportRewrite will allow us to add the new type to the imports and will resolve
- // what the Java source must reference, e.g. the FQCN or just the simple name.
- ImportRewrite importRewrite = ImportRewrite.create((CompilationUnit) node, true);
- String Rqualifier = packageName + ".R"; //$NON-NLS-1$
- Rqualifier = importRewrite.addImport(Rqualifier);
-
- // Rewrite the AST itself via an ASTVisitor
- AST ast = node.getAST();
- ASTRewrite astRewrite = ASTRewrite.create(ast);
- ArrayList<TextEditGroup> astEditGroups = new ArrayList<TextEditGroup>();
- ReplaceStringsVisitor visitor = new ReplaceStringsVisitor(
- ast, astRewrite, astEditGroups,
- tokenString, Rqualifier, xmlStringId);
- node.accept(visitor);
-
- // Finally prepare the change set
- try {
- MultiTextEdit edit = new MultiTextEdit();
-
- // Create the edit to change the imports, only if anything changed
- TextEdit subEdit = importRewrite.rewriteImports(monitor.newChild(1));
- if (subEdit.hasChildren()) {
- edit.addChild(subEdit);
- }
-
- // Create the edit to change the Java source, only if anything changed
- subEdit = astRewrite.rewriteAST();
- if (subEdit.hasChildren()) {
- edit.addChild(subEdit);
- }
-
- // Only create a change set if any edit was collected
- if (edit.hasChildren()) {
- change.setEdit(edit);
-
- // Create TextEditChangeGroups which let the user turn changes on or off
- // individually. This must be done after the change.setEdit() call above.
- for (TextEditGroup editGroup : astEditGroups) {
- TextEditChangeGroup group = new TextEditChangeGroup(change, editGroup);
- if (editGroup instanceof EnabledTextEditGroup) {
- group.setEnabled(((EnabledTextEditGroup) editGroup).isEnabled());
- }
- change.addTextEditChangeGroup(group);
- }
-
- changes.add(change);
- }
-
- monitor.worked(1);
-
- if (changes.size() > 0) {
- return changes;
- }
-
- } catch (CoreException e) {
- // ImportRewrite.rewriteImports failed.
- status.addFatalError(e.getMessage());
- }
- return null;
- }
-
- // ----
-
- /**
- * Step 3 of 3 of the refactoring: returns the {@link Change} that will be able to do the
- * work and creates a descriptor that can be used to replay that refactoring later.
- *
- * @see org.eclipse.ltk.core.refactoring.Refactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)
- *
- * @throws CoreException
- */
- @Override
- public Change createChange(IProgressMonitor monitor)
- throws CoreException, OperationCanceledException {
-
- try {
- monitor.beginTask("Applying changes...", 1);
-
- CompositeChange change = new CompositeChange(
- getName(),
- mChanges.toArray(new Change[mChanges.size()])) {
- @Override
- public ChangeDescriptor getDescriptor() {
-
- String comment = String.format(
- "Extracts string '%1$s' into R.string.%2$s",
- mTokenString,
- mXmlStringId);
-
- ExtractStringDescriptor desc = new ExtractStringDescriptor(
- mProject.getName(), //project
- comment, //description
- comment, //comment
- createArgumentMap());
-
- return new RefactoringChangeDescriptor(desc);
- }
- };
-
- monitor.worked(1);
-
- return change;
-
- } finally {
- monitor.done();
- }
-
- }
-
- /**
- * Given a file project path, returns its resource in the same project than the
- * compilation unit. The resource may not exist.
- */
- private IResource getTargetXmlResource(String xmlFileWsPath) {
- IResource resource = mProject.getFile(xmlFileWsPath);
- return resource;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringWizard.java
deleted file mode 100644
index 556dff0df..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringWizard.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2009 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.extractstring;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-
-/**
- * A wizard for ExtractString based on a simple dialog with one page.
- *
- * @see ExtractStringInputPage
- * @see ExtractStringRefactoring
- */
-public class ExtractStringWizard extends RefactoringWizard {
-
- private final IProject mProject;
-
- /**
- * Create a wizard for ExtractString based on a simple dialog with one page.
- *
- * @param ref The instance of {@link ExtractStringRefactoring} to associate to the wizard.
- * @param project The project where the wizard was invoked from (e.g. where the user selection
- * happened, so that we can retrieve project resources.)
- */
- public ExtractStringWizard(ExtractStringRefactoring ref, IProject project) {
- super(ref, DIALOG_BASED_USER_INTERFACE | PREVIEW_EXPAND_FIRST_NODE);
- mProject = project;
- setDefaultPageTitle(ref.getName());
- }
-
- @Override
- protected void addUserInputPages() {
- addPage(new ExtractStringInputPage(mProject));
- }
-
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ReplaceStringsVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ReplaceStringsVisitor.java
deleted file mode 100644
index e058ce1ba..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ReplaceStringsVisitor.java
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Copyright (C) 2009 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.extractstring;
-
-import org.eclipse.jdt.core.dom.AST;
-import org.eclipse.jdt.core.dom.ASTNode;
-import org.eclipse.jdt.core.dom.ASTVisitor;
-import org.eclipse.jdt.core.dom.Assignment;
-import org.eclipse.jdt.core.dom.ClassInstanceCreation;
-import org.eclipse.jdt.core.dom.Expression;
-import org.eclipse.jdt.core.dom.IMethodBinding;
-import org.eclipse.jdt.core.dom.ITypeBinding;
-import org.eclipse.jdt.core.dom.IVariableBinding;
-import org.eclipse.jdt.core.dom.MethodDeclaration;
-import org.eclipse.jdt.core.dom.MethodInvocation;
-import org.eclipse.jdt.core.dom.Modifier;
-import org.eclipse.jdt.core.dom.Name;
-import org.eclipse.jdt.core.dom.SimpleName;
-import org.eclipse.jdt.core.dom.SimpleType;
-import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
-import org.eclipse.jdt.core.dom.StringLiteral;
-import org.eclipse.jdt.core.dom.Type;
-import org.eclipse.jdt.core.dom.TypeDeclaration;
-import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
-import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
-import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
-import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
-import org.eclipse.text.edits.TextEditGroup;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.TreeMap;
-
-/**
- * Visitor used by {@link ExtractStringRefactoring} to extract a string from an existing
- * Java source and replace it by an Android XML string reference.
- *
- * @see ExtractStringRefactoring#computeJavaChanges
- */
-class ReplaceStringsVisitor extends ASTVisitor {
-
- private static final String CLASS_ANDROID_CONTEXT = "android.content.Context"; //$NON-NLS-1$
- private static final String CLASS_JAVA_CHAR_SEQUENCE = "java.lang.CharSequence"; //$NON-NLS-1$
- private static final String CLASS_JAVA_STRING = "java.lang.String"; //$NON-NLS-1$
-
-
- private final AST mAst;
- private final ASTRewrite mRewriter;
- private final String mOldString;
- private final String mRQualifier;
- private final String mXmlId;
- private final ArrayList<TextEditGroup> mEditGroups;
-
- public ReplaceStringsVisitor(AST ast,
- ASTRewrite astRewrite,
- ArrayList<TextEditGroup> editGroups,
- String oldString,
- String rQualifier,
- String xmlId) {
- mAst = ast;
- mRewriter = astRewrite;
- mEditGroups = editGroups;
- mOldString = oldString;
- mRQualifier = rQualifier;
- mXmlId = xmlId;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public boolean visit(StringLiteral node) {
- if (node.getLiteralValue().equals(mOldString)) {
-
- // We want to analyze the calling context to understand whether we can
- // just replace the string literal by the named int constant (R.id.foo)
- // or if we should generate a Context.getString() call.
- boolean useGetResource = false;
- useGetResource = examineVariableDeclaration(node) ||
- examineMethodInvocation(node) ||
- examineAssignment(node);
-
- Name qualifierName = mAst.newName(mRQualifier + ".string"); //$NON-NLS-1$
- SimpleName idName = mAst.newSimpleName(mXmlId);
- ASTNode newNode = mAst.newQualifiedName(qualifierName, idName);
- boolean disabledChange = false;
- String title = "Replace string by ID";
-
- if (useGetResource) {
- Expression context = methodHasContextArgument(node);
- if (context == null && !isClassDerivedFromContext(node)) {
- // if we don't have a class that derives from Context and
- // we don't have a Context method argument, then try a bit harder:
- // can we find a method or a field that will give us a context?
- context = findContextFieldOrMethod(node);
-
- if (context == null) {
- // If not, let's write Context.getString(), which is technically
- // invalid but makes it a good clue on how to fix it. Since these
- // will not compile, we create a disabled change by default.
- context = mAst.newSimpleName("Context"); //$NON-NLS-1$
- disabledChange = true;
- }
- }
-
- MethodInvocation mi2 = mAst.newMethodInvocation();
- mi2.setName(mAst.newSimpleName("getString")); //$NON-NLS-1$
- mi2.setExpression(context);
- mi2.arguments().add(newNode);
-
- newNode = mi2;
- title = "Replace string by Context.getString(R.string...)";
- }
-
- TextEditGroup editGroup = new EnabledTextEditGroup(title, !disabledChange);
- mEditGroups.add(editGroup);
- mRewriter.replace(node, newNode, editGroup);
- }
- return super.visit(node);
- }
-
- /**
- * Examines if the StringLiteral is part of an assignment corresponding to the
- * a string variable declaration, e.g. String foo = id.
- *
- * The parent fragment is of syntax "var = expr" or "var[] = expr".
- * We want the type of the variable, which is either held by a
- * VariableDeclarationStatement ("type [fragment]") or by a
- * VariableDeclarationExpression. In either case, the type can be an array
- * but for us all that matters is to know whether the type is an int or
- * a string.
- */
- private boolean examineVariableDeclaration(StringLiteral node) {
- VariableDeclarationFragment fragment = findParentClass(node,
- VariableDeclarationFragment.class);
-
- if (fragment != null) {
- ASTNode parent = fragment.getParent();
-
- Type type = null;
- if (parent instanceof VariableDeclarationStatement) {
- type = ((VariableDeclarationStatement) parent).getType();
- } else if (parent instanceof VariableDeclarationExpression) {
- type = ((VariableDeclarationExpression) parent).getType();
- }
-
- if (type instanceof SimpleType) {
- return isJavaString(type.resolveBinding());
- }
- }
-
- return false;
- }
-
- /**
- * Examines if the StringLiteral is part of a assignment to a variable that
- * is a string. We need to lookup the variable to find its type, either in the
- * enclosing method or class type.
- */
- private boolean examineAssignment(StringLiteral node) {
-
- Assignment assignment = findParentClass(node, Assignment.class);
- if (assignment != null) {
- Expression left = assignment.getLeftHandSide();
-
- ITypeBinding typeBinding = left.resolveTypeBinding();
- return isJavaString(typeBinding);
- }
-
- return false;
- }
-
- /**
- * If the expression is part of a method invocation (aka a function call) or a
- * class instance creation (aka a "new SomeClass" constructor call), we try to
- * find the type of the argument being used. If it is a String (most likely), we
- * want to return true (to generate a getString() call). However if there might
- * be a similar method that takes an int, in which case we don't want to do that.
- *
- * This covers the case of Activity.setTitle(int resId) vs setTitle(String str).
- */
- @SuppressWarnings("rawtypes")
- private boolean examineMethodInvocation(StringLiteral node) {
-
- ASTNode parent = null;
- List arguments = null;
- IMethodBinding methodBinding = null;
-
- MethodInvocation invoke = findParentClass(node, MethodInvocation.class);
- if (invoke != null) {
- parent = invoke;
- arguments = invoke.arguments();
- methodBinding = invoke.resolveMethodBinding();
- } else {
- ClassInstanceCreation newclass = findParentClass(node, ClassInstanceCreation.class);
- if (newclass != null) {
- parent = newclass;
- arguments = newclass.arguments();
- methodBinding = newclass.resolveConstructorBinding();
- }
- }
-
- if (parent != null && arguments != null && methodBinding != null) {
- // We want to know which argument this is.
- // Walk up the hierarchy again to find the immediate child of the parent,
- // which should turn out to be one of the invocation arguments.
- ASTNode child = null;
- for (ASTNode n = node; n != parent; ) {
- ASTNode p = n.getParent();
- if (p == parent) {
- child = n;
- break;
- }
- n = p;
- }
- if (child == null) {
- // This can't happen: a parent of 'node' must be the child of 'parent'.
- return false;
- }
-
- // Find the index
- int index = 0;
- for (Object arg : arguments) {
- if (arg == child) {
- break;
- }
- index++;
- }
-
- if (index == arguments.size()) {
- // This can't happen: one of the arguments of 'invoke' must be 'child'.
- return false;
- }
-
- // Eventually we want to determine if the parameter is a string type,
- // in which case a Context.getString() call must be generated.
- boolean useStringType = false;
-
- // Find the type of that argument
- ITypeBinding[] types = methodBinding.getParameterTypes();
- if (index < types.length) {
- ITypeBinding type = types[index];
- useStringType = isJavaString(type);
- }
-
- // Now that we know that this method takes a String parameter, can we find
- // a variant that would accept an int for the same parameter position?
- if (useStringType) {
- String name = methodBinding.getName();
- ITypeBinding clazz = methodBinding.getDeclaringClass();
- nextMethod: for (IMethodBinding mb2 : clazz.getDeclaredMethods()) {
- if (methodBinding == mb2 || !mb2.getName().equals(name)) {
- continue;
- }
- // We found a method with the same name. We want the same parameters
- // except that the one at 'index' must be an int type.
- ITypeBinding[] types2 = mb2.getParameterTypes();
- int len2 = types2.length;
- if (types.length == len2) {
- for (int i = 0; i < len2; i++) {
- if (i == index) {
- ITypeBinding type2 = types2[i];
- if (!("int".equals(type2.getQualifiedName()))) { //$NON-NLS-1$
- // The argument at 'index' is not an int.
- continue nextMethod;
- }
- } else if (!types[i].equals(types2[i])) {
- // One of the other arguments do not match our original method
- continue nextMethod;
- }
- }
- // If we got here, we found a perfect match: a method with the same
- // arguments except the one at 'index' is an int. In this case we
- // don't need to convert our R.id into a string.
- useStringType = false;
- break;
- }
- }
- }
-
- return useStringType;
- }
- return false;
- }
-
- /**
- * Examines if the StringLiteral is part of a method declaration (a.k.a. a function
- * definition) which takes a Context argument.
- * If such, it returns the name of the variable as a {@link SimpleName}.
- * Otherwise it returns null.
- */
- private SimpleName methodHasContextArgument(StringLiteral node) {
- MethodDeclaration decl = findParentClass(node, MethodDeclaration.class);
- if (decl != null) {
- for (Object obj : decl.parameters()) {
- if (obj instanceof SingleVariableDeclaration) {
- SingleVariableDeclaration var = (SingleVariableDeclaration) obj;
- if (isAndroidContext(var.getType())) {
- return mAst.newSimpleName(var.getName().getIdentifier());
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Walks up the node hierarchy to find the class (aka type) where this statement
- * is used and returns true if this class derives from android.content.Context.
- */
- private boolean isClassDerivedFromContext(StringLiteral node) {
- TypeDeclaration clazz = findParentClass(node, TypeDeclaration.class);
- if (clazz != null) {
- // This is the class that the user is currently writing, so it can't be
- // a Context by itself, it has to be derived from it.
- return isAndroidContext(clazz.getSuperclassType());
- }
- return false;
- }
-
- private Expression findContextFieldOrMethod(StringLiteral node) {
- TypeDeclaration clazz = findParentClass(node, TypeDeclaration.class);
- return clazz == null ? null : findContextFieldOrMethod(clazz.resolveBinding());
- }
-
- private Expression findContextFieldOrMethod(ITypeBinding clazzType) {
- TreeMap<Integer, Expression> results = new TreeMap<Integer, Expression>();
- findContextCandidates(results, clazzType, 0 /*superType*/);
- if (results.size() > 0) {
- Integer bestRating = results.keySet().iterator().next();
- return results.get(bestRating);
- }
- return null;
- }
-
- /**
- * Find all method or fields that are candidates for providing a Context.
- * There can be various choices amongst this class or its super classes.
- * Sort them by rating in the results map.
- *
- * The best ever choice is to find a method with no argument that returns a Context.
- * The second suitable choice is to find a Context field.
- * The least desirable choice is to find a method with arguments. It's not really
- * desirable since we can't generate these arguments automatically.
- *
- * Methods and fields from supertypes are ignored if they are private.
- *
- * The rating is reversed: the lowest rating integer is used for the best candidate.
- * Because the superType argument is actually a recursion index, this makes the most
- * immediate classes more desirable.
- *
- * @param results The map that accumulates the rating=>expression results. The lower
- * rating number is the best candidate.
- * @param clazzType The class examined.
- * @param superType The recursion index.
- * 0 for the immediate class, 1 for its super class, etc.
- */
- private void findContextCandidates(TreeMap<Integer, Expression> results,
- ITypeBinding clazzType,
- int superType) {
- for (IMethodBinding mb : clazzType.getDeclaredMethods()) {
- // If we're looking at supertypes, we can't use private methods.
- if (superType != 0 && Modifier.isPrivate(mb.getModifiers())) {
- continue;
- }
-
- if (isAndroidContext(mb.getReturnType())) {
- // We found a method that returns something derived from Context.
-
- int argsLen = mb.getParameterTypes().length;
- if (argsLen == 0) {
- // We'll favor any method that takes no argument,
- // That would be the best candidate ever, so we can stop here.
- MethodInvocation mi = mAst.newMethodInvocation();
- mi.setName(mAst.newSimpleName(mb.getName()));
- results.put(Integer.MIN_VALUE, mi);
- return;
- } else {
- // A method with arguments isn't as interesting since we wouldn't
- // know how to populate such arguments. We'll use it if there are
- // no other alternatives. We'll favor the one with the less arguments.
- Integer rating = Integer.valueOf(10000 + 1000 * superType + argsLen);
- if (!results.containsKey(rating)) {
- MethodInvocation mi = mAst.newMethodInvocation();
- mi.setName(mAst.newSimpleName(mb.getName()));
- results.put(rating, mi);
- }
- }
- }
- }
-
- // A direct Context field would be more interesting than a method with
- // arguments. Try to find one.
- for (IVariableBinding var : clazzType.getDeclaredFields()) {
- // If we're looking at supertypes, we can't use private field.
- if (superType != 0 && Modifier.isPrivate(var.getModifiers())) {
- continue;
- }
-
- if (isAndroidContext(var.getType())) {
- // We found such a field. Let's use it.
- Integer rating = Integer.valueOf(superType);
- results.put(rating, mAst.newSimpleName(var.getName()));
- break;
- }
- }
-
- // Examine the super class to see if we can locate a better match
- clazzType = clazzType.getSuperclass();
- if (clazzType != null) {
- findContextCandidates(results, clazzType, superType + 1);
- }
- }
-
- /**
- * Walks up the node hierarchy and returns the first ASTNode of the requested class.
- * Only look at parents.
- *
- * Implementation note: this is a generic method so that it returns the node already
- * casted to the requested type.
- */
- @SuppressWarnings("unchecked")
- private <T extends ASTNode> T findParentClass(ASTNode node, Class<T> clazz) {
- if (node != null) {
- for (node = node.getParent(); node != null; node = node.getParent()) {
- if (node.getClass().equals(clazz)) {
- return (T) node;
- }
- }
- }
- return null;
- }
-
- /**
- * Returns true if the given type is or derives from android.content.Context.
- */
- private boolean isAndroidContext(Type type) {
- if (type != null) {
- return isAndroidContext(type.resolveBinding());
- }
- return false;
- }
-
- /**
- * Returns true if the given type is or derives from android.content.Context.
- */
- private boolean isAndroidContext(ITypeBinding type) {
- for (; type != null; type = type.getSuperclass()) {
- if (CLASS_ANDROID_CONTEXT.equals(type.getQualifiedName())) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if this type binding represents a String or CharSequence type.
- */
- private boolean isJavaString(ITypeBinding type) {
- for (; type != null; type = type.getSuperclass()) {
- if (CLASS_JAVA_STRING.equals(type.getQualifiedName()) ||
- CLASS_JAVA_CHAR_SEQUENCE.equals(type.getQualifiedName())) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/XmlStringFileHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/XmlStringFileHelper.java
deleted file mode 100644
index 01e814ef2..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/XmlStringFileHelper.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2009 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.extractstring;
-
-import com.android.SdkConstants;
-import com.android.ide.eclipse.adt.AdtPlugin;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-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.xml.core.internal.provisional.document.IDOMDocument;
-import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * An helper utility to get IDs out of an Android XML resource file.
- */
-@SuppressWarnings("restriction")
-class XmlStringFileHelper {
-
- /** A temporary cache of R.string IDs defined by a given xml file. The key is the
- * project path of the file, the data is a set of known string Ids for that file.
- *
- * Map type: map [String filename] => map [String id => String value].
- */
- private HashMap<String, Map<String, String>> mResIdCache =
- new HashMap<String, Map<String, String>>();
-
- public XmlStringFileHelper() {
- }
-
- /**
- * Utility method used by the wizard to retrieve the actual value definition of a given
- * string ID.
- *
- * @param project The project contain the XML file.
- * @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml".
- * The given file may or may not exist.
- * @param stringId The string ID to find.
- * @return The value string if the ID is defined, null otherwise.
- */
- public String valueOfStringId(IProject project, String xmlFileWsPath, String stringId) {
- Map<String, String> cache = getResIdsForFile(project, xmlFileWsPath);
- return cache.get(stringId);
- }
-
- /**
- * Utility method that retrieves all the *string* IDs defined in the given Android resource
- * file. The instance maintains an internal cache so a given file is retrieved only once.
- * Callers should consider the set to be read-only.
- *
- * @param project The project contain the XML file.
- * @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml".
- * The given file may or may not exist.
- * @return The map of string IDs => values defined in the given file. Cached. Never null.
- */
- public Map<String, String> getResIdsForFile(IProject project, String xmlFileWsPath) {
- Map<String, String> cache = mResIdCache.get(xmlFileWsPath);
- if (cache == null) {
- cache = internalGetResIdsForFile(project, xmlFileWsPath);
- mResIdCache.put(xmlFileWsPath, cache);
- }
- return cache;
- }
-
- /**
- * Extract all the defined string IDs from a given file using XPath.
- * @param project The project contain the XML file.
- * @param xmlFileWsPath The project path of the file to parse. It may not exist.
- * @return The map of all string IDs => values defined in the file.
- * The returned set is always non null. It is empty if the file does not exist.
- */
- private Map<String, String> internalGetResIdsForFile(IProject project, String xmlFileWsPath) {
-
- TreeMap<String, String> ids = new TreeMap<String, String>();
-
- // Access the project that contains the resource that contains the compilation unit
- IResource resource = project.getFile(xmlFileWsPath);
-
- if (resource != null && resource.exists() && resource.getType() == IResource.FILE) {
- IStructuredModel smodel = null;
-
- try {
- IFile file = (IFile) resource;
- IModelManager modelMan = StructuredModelManager.getModelManager();
- smodel = modelMan.getExistingModelForRead(file);
- if (smodel == null) {
- smodel = modelMan.getModelForRead(file);
- }
-
- if (smodel instanceof IDOMModel) {
- IDOMDocument doc = ((IDOMModel) smodel).getDocument();
-
- // We want all the IDs in an XML structure like this:
- // <resources>
- // <string name="ID">something</string>
- // </resources>
-
- Node root = findChild(doc, null, SdkConstants.TAG_RESOURCES);
- if (root != null) {
- for (Node strNode = findChild(root, null,
- SdkConstants.TAG_STRING);
- strNode != null;
- strNode = findChild(null, strNode,
- SdkConstants.TAG_STRING)) {
- NamedNodeMap attrs = strNode.getAttributes();
- Node nameAttr = attrs.getNamedItem(SdkConstants.ATTR_NAME);
- if (nameAttr != null) {
- String id = nameAttr.getNodeValue();
-
- // Find the TEXT node right after the element.
- // Whitespace matters so we don't try to normalize it.
- String text = ""; //$NON-NLS-1$
- for (Node txtNode = strNode.getFirstChild();
- txtNode != null && txtNode.getNodeType() == Node.TEXT_NODE;
- txtNode = txtNode.getNextSibling()) {
- text += txtNode.getNodeValue();
- }
-
- ids.put(id, text);
- }
- }
- }
- }
-
- } catch (Throwable e) {
- AdtPlugin.log(e, "GetResIds failed in %1$s", xmlFileWsPath); //$NON-NLS-1$
- } finally {
- if (smodel != null) {
- smodel.releaseFromRead();
- }
- }
- }
-
- return ids;
- }
-
- /**
- * Utility method that finds the next node of the requested element name.
- *
- * @param parent The parent node. If not null, will to start searching its children.
- * Set to null when iterating through children.
- * @param lastChild The last child returned. Use null when visiting a parent the first time.
- * @param elementName The element name of the node to find.
- * @return The next children or sibling nide with the requested element name or null.
- */
- private Node findChild(Node parent, Node lastChild, String elementName) {
- if (lastChild == null && parent != null) {
- lastChild = parent.getFirstChild();
- } else if (lastChild != null) {
- lastChild = lastChild.getNextSibling();
- }
-
- for ( ; lastChild != null ; lastChild = lastChild.getNextSibling()) {
- if (lastChild.getNodeType() == Node.ELEMENT_NODE &&
- lastChild.getNamespaceURI() == null && // resources don't have any NS URI
- elementName.equals(lastChild.getLocalName())) {
- return lastChild;
- }
- }
-
- return null;
- }
-
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoring.java
deleted file mode 100644
index 406cebca4..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoring.java
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * 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.renamepackage;
-
-import static com.android.SdkConstants.FN_BUILD_CONFIG_BASE;
-import static com.android.SdkConstants.FN_MANIFEST_BASE;
-import static com.android.SdkConstants.FN_RESOURCE_BASE;
-
-import com.android.SdkConstants;
-import com.android.ide.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.xml.AndroidManifest;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IResourceVisitor;
-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.core.runtime.Status;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.dom.AST;
-import org.eclipse.jdt.core.dom.ASTParser;
-import org.eclipse.jdt.core.dom.ASTVisitor;
-import org.eclipse.jdt.core.dom.CompilationUnit;
-import org.eclipse.jdt.core.dom.ImportDeclaration;
-import org.eclipse.jdt.core.dom.Name;
-import org.eclipse.jdt.core.dom.QualifiedName;
-import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
-import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.CompositeChange;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.TextEditChangeGroup;
-import org.eclipse.ltk.core.refactoring.TextFileChange;
-import org.eclipse.text.edits.MalformedTreeException;
-import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.text.edits.ReplaceEdit;
-import org.eclipse.text.edits.TextEdit;
-import org.eclipse.text.edits.TextEditGroup;
-import org.eclipse.wst.sse.core.StructuredModelManager;
-import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
-import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
-import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
-import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
-import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
-import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Wrapper class defining the stages of the refactoring process
- */
-@SuppressWarnings("restriction")
-class ApplicationPackageNameRefactoring extends Refactoring {
- private final IProject mProject;
- private final Name mOldPackageName;
- private final Name mNewPackageName;
-
- List<String> MAIN_COMPONENT_TYPES_LIST = Arrays.asList(MAIN_COMPONENT_TYPES);
-
- ApplicationPackageNameRefactoring(
- IProject project,
- Name oldPackageName,
- Name newPackageName) {
- mProject = project;
- mOldPackageName = oldPackageName;
- mNewPackageName = newPackageName;
- }
-
- @Override
- public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
- throws CoreException, OperationCanceledException {
-
- // Accurate refactoring of the "shorthand" names in
- // AndroidManifest.xml depends on not having compilation errors.
- if (mProject.findMaxProblemSeverity(
- IMarker.PROBLEM,
- true,
- IResource.DEPTH_INFINITE) == IMarker.SEVERITY_ERROR) {
- return
- RefactoringStatus.createFatalErrorStatus("Fix the errors in your project, first.");
- }
-
- return new RefactoringStatus();
- }
-
- @Override
- public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
- throws OperationCanceledException {
-
- return new RefactoringStatus();
- }
-
- @Override
- public Change createChange(IProgressMonitor pm) throws CoreException,
- OperationCanceledException {
-
- // Traverse all files in the project, building up a list of changes
- JavaFileVisitor fileVisitor = new JavaFileVisitor();
- mProject.accept(fileVisitor);
- return fileVisitor.getChange();
- }
-
- @Override
- public String getName() {
- return "AndroidPackageNameRefactoring"; //$NON-NLS-1$
- }
-
- public final static String[] MAIN_COMPONENT_TYPES = {
- AndroidManifest.NODE_ACTIVITY, AndroidManifest.NODE_SERVICE,
- AndroidManifest.NODE_RECEIVER, AndroidManifest.NODE_PROVIDER,
- AndroidManifest.NODE_APPLICATION
- };
-
-
- TextEdit updateJavaFileImports(CompilationUnit cu) {
-
- ImportVisitor importVisitor = new ImportVisitor(cu.getAST());
- cu.accept(importVisitor);
- TextEdit rewrittenImports = importVisitor.getTextEdit();
-
- // If the import of R was potentially implicit, insert an import statement
- if (rewrittenImports != null && cu.getPackage().getName().getFullyQualifiedName()
- .equals(mOldPackageName.getFullyQualifiedName())) {
-
- UsageVisitor usageVisitor = new UsageVisitor();
- cu.accept(usageVisitor);
-
- if (usageVisitor.seenAny()) {
- ImportRewrite irw = ImportRewrite.create(cu, true);
- if (usageVisitor.hasSeenR()) {
- irw.addImport(mNewPackageName.getFullyQualifiedName() + '.'
- + FN_RESOURCE_BASE);
- }
- if (usageVisitor.hasSeenBuildConfig()) {
- irw.addImport(mNewPackageName.getFullyQualifiedName() + '.'
- + FN_BUILD_CONFIG_BASE);
- }
- if (usageVisitor.hasSeenManifest()) {
- irw.addImport(mNewPackageName.getFullyQualifiedName() + '.'
- + FN_MANIFEST_BASE);
- }
-
- try {
- rewrittenImports.addChild( irw.rewriteImports(null) );
- } catch (MalformedTreeException e) {
- Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e);
- AdtPlugin.getDefault().getLog().log(s);
- } catch (CoreException e) {
- Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e);
- AdtPlugin.getDefault().getLog().log(s);
- }
- }
- }
-
- return rewrittenImports;
- }
-
- // XML utility functions
- private String stripQuotes(String text) {
- int len = text.length();
- if (len >= 2 && text.charAt(0) == '"' && text.charAt(len - 1) == '"') {
- return text.substring(1, len - 1);
- } else if (len >= 2 && text.charAt(0) == '\'' && text.charAt(len - 1) == '\'') {
- return text.substring(1, len - 1);
- }
- return text;
- }
-
- private String addQuotes(String text) {
- return '"' + text + '"';
- }
-
- /*
- * Make the appropriate package name changes to a resource file,
- * e.g. .xml files in res/layout. This entails updating the namespace
- * declarations for custom styleable attributes. The namespace prefix
- * is user-defined and may be declared in any element where or parent
- * element of where the prefix is used.
- */
- TextFileChange editXmlResourceFile(IFile file) {
-
- IModelManager modelManager = StructuredModelManager.getModelManager();
- IStructuredDocument sdoc = null;
- try {
- sdoc = modelManager.createStructuredDocumentFor(file);
- } catch (IOException e) {
- Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e);
- AdtPlugin.getDefault().getLog().log(s);
- } catch (CoreException e) {
- Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e);
- AdtPlugin.getDefault().getLog().log(s);
- }
-
- if (sdoc == null) {
- return null;
- }
-
- TextFileChange xmlChange = new TextFileChange("XML resource file edit", file);
- xmlChange.setTextType(SdkConstants.EXT_XML);
-
- MultiTextEdit multiEdit = new MultiTextEdit();
- ArrayList<TextEditGroup> editGroups = new ArrayList<TextEditGroup>();
-
- final String oldAppNamespaceString = String.format(AdtConstants.NS_CUSTOM_RESOURCES,
- mOldPackageName.getFullyQualifiedName());
- final String newAppNamespaceString = String.format(AdtConstants.NS_CUSTOM_RESOURCES,
- mNewPackageName.getFullyQualifiedName());
-
- // Prepare the change set
- for (IStructuredDocumentRegion region : sdoc.getStructuredDocumentRegions()) {
-
- if (!DOMRegionContext.XML_TAG_NAME.equals(region.getType())) {
- continue;
- }
-
- int nb = region.getNumberOfRegions();
- ITextRegionList list = region.getRegions();
- String lastAttrName = null;
-
- for (int i = 0; i < nb; i++) {
- ITextRegion subRegion = list.get(i);
- String type = subRegion.getType();
-
- if (DOMRegionContext.XML_TAG_ATTRIBUTE_NAME.equals(type)) {
- // Memorize the last attribute name seen
- lastAttrName = region.getText(subRegion);
-
- } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(type)) {
- // Check this is the attribute and the original string
-
- if (lastAttrName != null &&
- lastAttrName.startsWith(SdkConstants.XMLNS_PREFIX)) {
-
- String lastAttrValue = region.getText(subRegion);
- if (oldAppNamespaceString.equals(stripQuotes(lastAttrValue))) {
-
- // Found an occurrence. Create a change for it.
- TextEdit edit = new ReplaceEdit(
- region.getStartOffset() + subRegion.getStart(),
- subRegion.getTextLength(),
- addQuotes(newAppNamespaceString));
- TextEditGroup editGroup = new TextEditGroup(
- "Replace package name in custom namespace prefix", edit);
-
- multiEdit.addChild(edit);
- editGroups.add(editGroup);
- }
- }
- }
- }
- }
-
- if (multiEdit.hasChildren()) {
- xmlChange.setEdit(multiEdit);
- for (TextEditGroup group : editGroups) {
- xmlChange.addTextEditChangeGroup(new TextEditChangeGroup(xmlChange, group));
- }
-
- return xmlChange;
- }
- return null;
- }
-
- /*
- * Replace all instances of the package name in AndroidManifest.xml.
- * This includes expanding shorthand paths for each Component (Activity,
- * Service, etc.) and of course updating the application package name.
- * The namespace prefix might not be "android", so we resolve it
- * dynamically.
- */
- TextFileChange editAndroidManifest(IFile file) {
-
- IModelManager modelManager = StructuredModelManager.getModelManager();
- IStructuredDocument sdoc = null;
- try {
- sdoc = modelManager.createStructuredDocumentFor(file);
- } catch (IOException e) {
- Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e);
- AdtPlugin.getDefault().getLog().log(s);
- } catch (CoreException e) {
- Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e);
- AdtPlugin.getDefault().getLog().log(s);
- }
-
- if (sdoc == null) {
- return null;
- }
-
- TextFileChange xmlChange = new TextFileChange("Make Manifest edits", file);
- xmlChange.setTextType(SdkConstants.EXT_XML);
-
- MultiTextEdit multiEdit = new MultiTextEdit();
- ArrayList<TextEditGroup> editGroups = new ArrayList<TextEditGroup>();
-
- // The namespace prefix is guaranteed to be resolved before
- // the first use of this attribute
- String android_name_attribute = null;
-
- // Prepare the change set
- for (IStructuredDocumentRegion region : sdoc.getStructuredDocumentRegions()) {
-
- // Only look at XML "top regions"
- if (!DOMRegionContext.XML_TAG_NAME.equals(region.getType())) {
- continue;
- }
-
- int nb = region.getNumberOfRegions();
- ITextRegionList list = region.getRegions();
- String lastTagName = null, lastAttrName = null;
-
- for (int i = 0; i < nb; i++) {
- ITextRegion subRegion = list.get(i);
- String type = subRegion.getType();
-
- if (DOMRegionContext.XML_TAG_NAME.equals(type)) {
- // Memorize the last tag name seen
- lastTagName = region.getText(subRegion);
-
- } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_NAME.equals(type)) {
- // Memorize the last attribute name seen
- lastAttrName = region.getText(subRegion);
-
- } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(type)) {
-
- String lastAttrValue = region.getText(subRegion);
- if (lastAttrName != null &&
- lastAttrName.startsWith(SdkConstants.XMLNS_PREFIX)) {
-
- // Resolves the android namespace prefix for this file
- if (SdkConstants.ANDROID_URI.equals(stripQuotes(lastAttrValue))) {
- String android_namespace_prefix = lastAttrName
- .substring(SdkConstants.XMLNS_PREFIX.length());
- android_name_attribute = android_namespace_prefix + ':'
- + AndroidManifest.ATTRIBUTE_NAME;
- }
- } else if (AndroidManifest.NODE_MANIFEST.equals(lastTagName)
- && AndroidManifest.ATTRIBUTE_PACKAGE.equals(lastAttrName)) {
-
- // Found an occurrence. Create a change for it.
- TextEdit edit = new ReplaceEdit(region.getStartOffset()
- + subRegion.getStart(), subRegion.getTextLength(),
- addQuotes(mNewPackageName.getFullyQualifiedName()));
-
- multiEdit.addChild(edit);
- editGroups.add(new TextEditGroup("Change Android package name", edit));
-
- } else if (MAIN_COMPONENT_TYPES_LIST.contains(lastTagName)
- && lastAttrName != null
- && lastAttrName.equals(android_name_attribute)) {
-
- String package_path = stripQuotes(lastAttrValue);
- String old_package_name_string = mOldPackageName.getFullyQualifiedName();
-
- String absolute_path = AndroidManifest.combinePackageAndClassName(
- old_package_name_string, package_path);
-
- TextEdit edit = new ReplaceEdit(region.getStartOffset()
- + subRegion.getStart(), subRegion.getTextLength(),
- addQuotes(absolute_path));
-
- multiEdit.addChild(edit);
-
- editGroups.add(new TextEditGroup("Update component path", edit));
- }
- }
- }
- }
-
- if (multiEdit.hasChildren()) {
- xmlChange.setEdit(multiEdit);
- for (TextEditGroup group : editGroups) {
- xmlChange.addTextEditChangeGroup(new TextEditChangeGroup(xmlChange, group));
- }
-
- return xmlChange;
- }
- return null;
- }
-
-
- /*
- * Iterates through all project files, taking distinct actions based on
- * whether the file is:
- * 1) a .java file (replaces or inserts the "import" statements)
- * 2) a .xml layout file (updates namespace declarations)
- * 3) the AndroidManifest.xml
- */
- class JavaFileVisitor implements IResourceVisitor {
-
- final List<TextFileChange> mChanges = new ArrayList<TextFileChange>();
-
- final ASTParser mParser = ASTParser.newParser(AST.JLS3);
-
- public CompositeChange getChange() {
-
- Collections.reverse(mChanges);
- CompositeChange change = new CompositeChange("Refactoring Application package name",
- mChanges.toArray(new Change[mChanges.size()]));
- change.markAsSynthetic();
- return change;
- }
-
- @Override
- public boolean visit(IResource resource) throws CoreException {
- if (resource instanceof IFile) {
- IFile file = (IFile) resource;
- if (SdkConstants.EXT_JAVA.equals(file.getFileExtension())) {
-
- ICompilationUnit icu = JavaCore.createCompilationUnitFrom(file);
-
- mParser.setSource(icu);
- CompilationUnit cu = (CompilationUnit) mParser.createAST(null);
-
- TextEdit textEdit = updateJavaFileImports(cu);
- if (textEdit != null && textEdit.hasChildren()) {
- MultiTextEdit edit = new MultiTextEdit();
- edit.addChild(textEdit);
-
- TextFileChange text_file_change = new TextFileChange(file.getName(), file);
- text_file_change.setTextType(SdkConstants.EXT_JAVA);
- text_file_change.setEdit(edit);
- mChanges.add(text_file_change);
- }
-
- // XXX Partially taken from ExtractStringRefactoring.java
- // Check this a Layout XML file and get the selection and
- // its context.
- } else if (SdkConstants.EXT_XML.equals(file.getFileExtension())) {
-
- if (SdkConstants.FN_ANDROID_MANIFEST_XML.equals(file.getName())) {
- // Ensure that this is the root manifest, not some other copy
- // (such as the one in bin/)
- IPath path = file.getFullPath();
- if (path.segmentCount() == 2) {
- TextFileChange manifest_change = editAndroidManifest(file);
- mChanges.add(manifest_change);
- }
- } else {
-
- // Currently we only support Android resource XML files,
- // so they must have a path similar to
- // project/res/<type>[-<configuration>]/*.xml
- // There is no support for sub folders, so the segment count must be 4.
- // We don't need to check the type folder name because
- // a/ we only accept an AndroidXmlEditor source and
- // b/ aapt generates a compilation error for unknown folders.
- IPath path = file.getFullPath();
- // check if we are inside the project/res/* folder.
- if (path.segmentCount() == 4) {
- if (path.segment(1).equalsIgnoreCase(SdkConstants.FD_RESOURCES)) {
-
-
- TextFileChange xmlChange = editXmlResourceFile(file);
- if (xmlChange != null) {
- mChanges.add(xmlChange);
- }
- }
- }
- }
- }
-
- return false;
-
- } else if (resource instanceof IFolder) {
- return !SdkConstants.FD_GEN_SOURCES.equals(resource.getName());
- }
-
- return true;
- }
- }
-
- private static class UsageVisitor extends ASTVisitor {
- private boolean mSeenManifest;
- private boolean mSeenR;
- private boolean mSeenBuildConfig;
-
- @Override
- public boolean visit(QualifiedName node) {
- Name qualifier = node.getQualifier();
- if (qualifier.isSimpleName()) {
- String name = qualifier.toString();
- if (name.equals(FN_RESOURCE_BASE)) {
- mSeenR = true;
- } else if (name.equals(FN_BUILD_CONFIG_BASE)) {
- mSeenBuildConfig = true;
- } else if (name.equals(FN_MANIFEST_BASE)) {
- mSeenManifest = true;
- }
- }
- return super.visit(node);
- };
-
- public boolean seenAny() {
- return mSeenR || mSeenBuildConfig || mSeenManifest;
- }
-
- public boolean hasSeenBuildConfig() {
- return mSeenBuildConfig;
- }
- public boolean hasSeenManifest() {
- return mSeenManifest;
- }
- public boolean hasSeenR() {
- return mSeenR;
- }
- }
-
- private class ImportVisitor extends ASTVisitor {
-
- final AST mAst;
- final ASTRewrite mRewriter;
-
- ImportVisitor(AST ast) {
- mAst = ast;
- mRewriter = ASTRewrite.create(ast);
- }
-
- public TextEdit getTextEdit() {
- try {
- return this.mRewriter.rewriteAST();
- } catch (JavaModelException e) {
- Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e);
- AdtPlugin.getDefault().getLog().log(s);
- } catch (IllegalArgumentException e) {
- Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e);
- AdtPlugin.getDefault().getLog().log(s);
- }
- return null;
- }
-
- @Override
- public boolean visit(ImportDeclaration id) {
-
- Name importName = id.getName();
- if (importName.isQualifiedName()) {
- QualifiedName qualifiedImportName = (QualifiedName) importName;
-
- String identifier = qualifiedImportName.getName().getIdentifier();
- if (identifier.equals(FN_RESOURCE_BASE)) {
- mRewriter.replace(qualifiedImportName.getQualifier(), mNewPackageName,
- null);
- } else if (identifier.equals(FN_BUILD_CONFIG_BASE)
- && mOldPackageName.toString().equals(
- qualifiedImportName.getQualifier().toString())) {
- mRewriter.replace(qualifiedImportName.getQualifier(), mNewPackageName,
- null);
-
- } else if (identifier.equals(FN_MANIFEST_BASE)
- && mOldPackageName.toString().equals(
- qualifiedImportName.getQualifier().toString())) {
- mRewriter.replace(qualifiedImportName.getQualifier(), mNewPackageName,
- null);
- }
- }
-
- return true;
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoringWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoringWizard.java
deleted file mode 100644
index 3651855a7..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoringWizard.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.renamepackage;
-
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-
-/**
- * @see RenamePackageAction
- */
-class ApplicationPackageNameRefactoringWizard extends RefactoringWizard {
-
- public ApplicationPackageNameRefactoringWizard(Refactoring refactoring) {
- super(refactoring, 0);
- }
-
- @Override
- protected void addUserInputPages() {
- }
-}
-
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/RenamePackageAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/RenamePackageAction.java
deleted file mode 100644
index bb475aab1..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/RenamePackageAction.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * 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.renamepackage;
-
-import com.android.ide.common.xml.ManifestData;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.jdt.core.dom.AST;
-import org.eclipse.jdt.core.dom.Name;
-import org.eclipse.jdt.ui.refactoring.RefactoringSaveHelper;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.dialogs.IInputValidator;
-import org.eclipse.jface.dialogs.InputDialog;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.window.Window;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-import org.eclipse.ui.IObjectActionDelegate;
-import org.eclipse.ui.IWorkbenchPart;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.IWorkbenchWindowActionDelegate;
-
-import java.util.Iterator;
-
-/**
- * Refactoring steps:
- * <ol>
- * <li>Update the "package" attribute of the &lt;manifest&gt; tag with the new
- * name.</li>
- * <li>Replace all values for the "android:name" attribute in the
- * &lt;application&gt; and "component class" (&lt;activity&gt;, &lt;service&gt;,
- * &lt;receiver&gt;, and &lt;provider&gt;) tags with the non-shorthand version
- * of the class name</li>
- * <li>Replace package resource imports (*.R) in .java files</li>
- * <li>Update package name in the namespace declarations (e.g. "xmlns:app")
- * used for custom styleable attributes in layout resource files</li>
- * </ol>
- * Caveat: Sometimes it is necessary to perform a project-wide
- * "Organize Imports" afterwards. (CTRL+SHIFT+O when a project has active
- * selection)
- */
-public class RenamePackageAction implements IObjectActionDelegate {
-
- private ISelection mSelection;
- @SuppressWarnings("unused") private IWorkbenchPart mTargetPart; // TODO cleanup
-
- /**
- * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
- */
- @Override
- public void setActivePart(IAction action, IWorkbenchPart targetPart) {
- mTargetPart = targetPart;
- }
-
- @Override
- public void selectionChanged(IAction action, ISelection selection) {
- mSelection = selection;
- }
-
- /**
- * @see IWorkbenchWindowActionDelegate#init
- */
- public void init(IWorkbenchWindow window) {
- // pass
- }
-
- @Override
- public void run(IAction action) {
-
- // Prompt for refactoring on the selected project
- if (mSelection instanceof IStructuredSelection) {
- for (Iterator<?> it = ((IStructuredSelection) mSelection).iterator(); it.hasNext();) {
- Object element = it.next();
- IProject project = null;
- if (element instanceof IProject) {
- project = (IProject) element;
- } else if (element instanceof IAdaptable) {
- project = (IProject) ((IAdaptable) element).getAdapter(IProject.class);
- }
- if (project != null) {
- // It is advisable that the user saves before proceeding,
- // revealing any compilation errors. The following lines
- // enforce a save as a convenience.
- RefactoringSaveHelper save_helper = new RefactoringSaveHelper(
- RefactoringSaveHelper.SAVE_ALL_ALWAYS_ASK);
- if (save_helper.saveEditors(AdtPlugin.getShell())) {
- promptNewName(project);
- }
- }
- }
- }
- }
-
- /*
- * Validate the new package name and start the refactoring wizard
- */
- private void promptNewName(final IProject project) {
-
- ManifestData manifestData = AndroidManifestHelper.parseForData(project);
- if (manifestData == null) {
- return;
- }
-
- final String oldPackageNameString = manifestData.getPackage();
-
- final AST astValidator = AST.newAST(AST.JLS3);
- Name oldPackageName = astValidator.newName(oldPackageNameString);
-
- IInputValidator validator = new IInputValidator() {
-
- @Override
- public String isValid(String newText) {
- try {
- astValidator.newName(newText);
- } catch (IllegalArgumentException e) {
- return "Illegal package name.";
- }
-
- if (newText.equals(oldPackageNameString))
- return "No change.";
- else
- return null;
- }
- };
-
- InputDialog dialog = new InputDialog(AdtPlugin.getShell(),
- "Rename Application Package", "Enter new package name:", oldPackageNameString,
- validator);
-
- if (dialog.open() == Window.OK) {
- Name newPackageName = astValidator.newName(dialog.getValue());
- initiateAndroidPackageRefactoring(project, oldPackageName, newPackageName);
- }
- }
-
-
- private void initiateAndroidPackageRefactoring(
- final IProject project,
- Name oldPackageName,
- Name newPackageName) {
-
- Refactoring package_name_refactoring =
- new ApplicationPackageNameRefactoring(project, oldPackageName, newPackageName);
-
- ApplicationPackageNameRefactoringWizard wizard =
- new ApplicationPackageNameRefactoringWizard(package_name_refactoring);
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- op.run(AdtPlugin.getShell(), package_name_refactoring.getName());
- } catch (InterruptedException e) {
- Status s = new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, e.getMessage(), e);
- AdtPlugin.getDefault().getLog().log(s);
- }
- }
-}