Automated import from //branches/donutburger/...@141823,141823
This commit is contained in:
committed by
The Android Open Source Project
parent
511d471363
commit
b6007ebd5c
@@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
package com.android.ide.eclipse.adt.refactorings.extractstring;
|
package com.android.ide.eclipse.adt.refactorings.extractstring;
|
||||||
|
|
||||||
|
import com.android.ide.eclipse.common.AndroidConstants;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IFile;
|
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.ICompilationUnit;
|
||||||
import org.eclipse.jdt.core.ITypeRoot;
|
import org.eclipse.jdt.core.ITypeRoot;
|
||||||
import org.eclipse.jdt.core.JavaCore;
|
import org.eclipse.jdt.core.JavaCore;
|
||||||
@@ -32,6 +36,7 @@ import org.eclipse.ui.IWorkbenchPage;
|
|||||||
import org.eclipse.ui.IWorkbenchWindow;
|
import org.eclipse.ui.IWorkbenchWindow;
|
||||||
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
|
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
|
||||||
import org.eclipse.ui.PlatformUI;
|
import org.eclipse.ui.PlatformUI;
|
||||||
|
import org.eclipse.ui.part.FileEditorInput;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Quick Reference Link:
|
* Quick Reference Link:
|
||||||
@@ -71,7 +76,7 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
/** Keep track of the current workbench window. */
|
/** Keep track of the current workbench window. */
|
||||||
private IWorkbenchWindow mWindow;
|
private IWorkbenchWindow mWindow;
|
||||||
private ITextSelection mSelection;
|
private ITextSelection mSelection;
|
||||||
private ICompilationUnit mUnit;
|
private IFile mFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep track of the current workbench window.
|
* Keep track of the current workbench window.
|
||||||
@@ -99,30 +104,24 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
// runs since we don't have access to the AST yet.
|
// runs since we don't have access to the AST yet.
|
||||||
|
|
||||||
mSelection = null;
|
mSelection = null;
|
||||||
mUnit = null;
|
mFile = null;
|
||||||
|
|
||||||
if (selection instanceof ITextSelection) {
|
if (selection instanceof ITextSelection) {
|
||||||
mSelection = (ITextSelection) selection;
|
mSelection = (ITextSelection) selection;
|
||||||
if (mSelection.getLength() > 0) {
|
if (mSelection.getLength() > 0) {
|
||||||
mUnit = getCompilationUnit();
|
mFile = getSelectedFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep for debugging purposes
|
|
||||||
//System.out.println(String.format("-- Selection: %d + %d = %s",
|
|
||||||
// mSelection.getOffset(),
|
|
||||||
// mSelection.getLength(),
|
|
||||||
// mSelection.getText()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
action.setEnabled(mSelection != null && mUnit != null);
|
action.setEnabled(mSelection != null && mFile != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance of our refactoring and a wizard to configure it.
|
* Create a new instance of our refactoring and a wizard to configure it.
|
||||||
*/
|
*/
|
||||||
public void run(IAction action) {
|
public void run(IAction action) {
|
||||||
if (mSelection != null && mUnit != null) {
|
if (mSelection != null && mFile != null) {
|
||||||
ExtractStringRefactoring ref = new ExtractStringRefactoring(mUnit, mSelection);
|
ExtractStringRefactoring ref = new ExtractStringRefactoring(mFile, mSelection);
|
||||||
RefactoringWizard wizard = new ExtractStringWizard(ref, "Extract Android String");
|
RefactoringWizard wizard = new ExtractStringWizard(ref, "Extract Android String");
|
||||||
RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
|
RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
|
||||||
try {
|
try {
|
||||||
@@ -134,9 +133,14 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the active {@link ICompilationUnit} or 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 ICompilationUnit getCompilationUnit() {
|
private IFile getSelectedFile() {
|
||||||
IWorkbenchWindow wwin = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
|
IWorkbenchWindow wwin = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
|
||||||
if (wwin != null) {
|
if (wwin != null) {
|
||||||
IWorkbenchPage page = wwin.getActivePage();
|
IWorkbenchPage page = wwin.getActivePage();
|
||||||
@@ -144,12 +148,19 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
|||||||
IEditorPart editor = page.getActiveEditor();
|
IEditorPart editor = page.getActiveEditor();
|
||||||
if (editor != null) {
|
if (editor != null) {
|
||||||
IEditorInput input = editor.getEditorInput();
|
IEditorInput input = editor.getEditorInput();
|
||||||
if (input != null) {
|
|
||||||
ITypeRoot typeRoot = JavaUI.getEditorInputTypeRoot(input);
|
if (input instanceof FileEditorInput) {
|
||||||
// The type root can be either a .class or a .java (aka compilation unit).
|
FileEditorInput fi = (FileEditorInput) input;
|
||||||
// We want the compilation unit kind.
|
IFile file = fi.getFile();
|
||||||
if (typeRoot instanceof ICompilationUnit) {
|
if (file.exists()) {
|
||||||
return (ICompilationUnit) typeRoot;
|
IProject proj = file.getProject();
|
||||||
|
try {
|
||||||
|
if (proj != null && proj.hasNature(AndroidConstants.NATURE)) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
} catch (CoreException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ import org.eclipse.core.resources.IFile;
|
|||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.resources.IResource;
|
import org.eclipse.core.resources.IResource;
|
||||||
import org.eclipse.core.resources.ResourceAttributes;
|
import org.eclipse.core.resources.ResourceAttributes;
|
||||||
|
import org.eclipse.core.resources.ResourcesPlugin;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
import org.eclipse.core.runtime.IProgressMonitor;
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
import org.eclipse.core.runtime.OperationCanceledException;
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
import org.eclipse.core.runtime.Path;
|
import org.eclipse.core.runtime.Path;
|
||||||
@@ -126,46 +128,54 @@ import javax.xml.xpath.XPathExpressionException;
|
|||||||
*/
|
*/
|
||||||
class ExtractStringRefactoring extends Refactoring {
|
class ExtractStringRefactoring extends Refactoring {
|
||||||
|
|
||||||
/** The compilation unit, a.k.a. the Java file model. */
|
/** The file model being manipulated. */
|
||||||
private final ICompilationUnit mUnit;
|
private final IFile mFile;
|
||||||
|
/** The start of the selection in {@link #mFile}. */
|
||||||
private final int mSelectionStart;
|
private final int mSelectionStart;
|
||||||
|
/** The end of the selection in {@link #mFile}. */
|
||||||
private final int mSelectionEnd;
|
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. */
|
/** The actual string selected, after UTF characters have been escaped, good for display. */
|
||||||
private String mTokenString;
|
private String mTokenString;
|
||||||
/** Start position of the string token in the source buffer. */
|
|
||||||
private int mTokenStart;
|
/** The XML string ID selected by the user in the wizard. */
|
||||||
/** End position of the string token in the source buffer. */
|
|
||||||
private int mTokenEnd;
|
|
||||||
private String mXmlStringId;
|
private String mXmlStringId;
|
||||||
|
/** The path of the XML file that will define {@link #mXmlStringId}, selected by the user
|
||||||
|
* in the wizard. */
|
||||||
private String mTargetXmlFileWsPath;
|
private String mTargetXmlFileWsPath;
|
||||||
|
|
||||||
|
/** 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. */
|
||||||
private HashMap<String,HashSet<String>> mResIdCache;
|
private HashMap<String,HashSet<String>> mResIdCache;
|
||||||
|
/** An instance of XPath, created lazily on demand. */
|
||||||
private XPath mXPath;
|
private XPath mXPath;
|
||||||
|
/** The list of changes computed by {@link #checkFinalConditions(IProgressMonitor)} and
|
||||||
|
* used by {@link #createChange(IProgressMonitor)}. */
|
||||||
private ArrayList<Change> mChanges;
|
private ArrayList<Change> mChanges;
|
||||||
|
|
||||||
public ExtractStringRefactoring(Map<String, String> arguments)
|
public ExtractStringRefactoring(Map<String, String> arguments)
|
||||||
throws NullPointerException {
|
throws NullPointerException {
|
||||||
mUnit = (ICompilationUnit) JavaCore.create(arguments.get("CU")); //$NON-NLS-1$
|
|
||||||
|
IPath path = Path.fromPortableString(arguments.get("file")); //$NON-NLS-1$
|
||||||
|
mFile = (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(path);
|
||||||
mSelectionStart = Integer.parseInt(arguments.get("sel-start")); //$NON-NLS-1$
|
mSelectionStart = Integer.parseInt(arguments.get("sel-start")); //$NON-NLS-1$
|
||||||
mSelectionEnd = Integer.parseInt(arguments.get("sel-end")); //$NON-NLS-1$
|
mSelectionEnd = Integer.parseInt(arguments.get("sel-end")); //$NON-NLS-1$
|
||||||
mTokenStart = Integer.parseInt(arguments.get("tok-start")); //$NON-NLS-1$
|
|
||||||
mTokenEnd = Integer.parseInt(arguments.get("tok-end")); //$NON-NLS-1$
|
|
||||||
mTokenString = arguments.get("tok-esc"); //$NON-NLS-1$
|
mTokenString = arguments.get("tok-esc"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> createArgumentMap() {
|
private Map<String, String> createArgumentMap() {
|
||||||
HashMap<String, String> args = new HashMap<String, String>();
|
HashMap<String, String> args = new HashMap<String, String>();
|
||||||
args.put("CU", mUnit.getHandleIdentifier()); //$NON-NLS-1$
|
args.put("file", mFile.getFullPath().toPortableString()); //$NON-NLS-1$
|
||||||
args.put("sel-start", Integer.toString(mSelectionStart)); //$NON-NLS-1$
|
args.put("sel-start", Integer.toString(mSelectionStart)); //$NON-NLS-1$
|
||||||
args.put("sel-end", Integer.toString(mSelectionEnd)); //$NON-NLS-1$
|
args.put("sel-end", Integer.toString(mSelectionEnd)); //$NON-NLS-1$
|
||||||
args.put("tok-start", Integer.toString(mTokenStart)); //$NON-NLS-1$
|
|
||||||
args.put("tok-end", Integer.toString(mTokenEnd)); //$NON-NLS-1$
|
|
||||||
args.put("tok-esc", mTokenString); //$NON-NLS-1$
|
args.put("tok-esc", mTokenString); //$NON-NLS-1$
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExtractStringRefactoring(ICompilationUnit unit, ITextSelection selection) {
|
public ExtractStringRefactoring(IFile file, ITextSelection selection) {
|
||||||
mUnit = unit;
|
mFile = file;
|
||||||
|
|
||||||
mSelectionStart = selection.getOffset();
|
mSelectionStart = selection.getOffset();
|
||||||
mSelectionEnd = mSelectionStart + selection.getLength();
|
mSelectionEnd = mSelectionStart + selection.getLength();
|
||||||
}
|
}
|
||||||
@@ -207,75 +217,42 @@ class ExtractStringRefactoring extends Refactoring {
|
|||||||
public RefactoringStatus checkInitialConditions(IProgressMonitor monitor)
|
public RefactoringStatus checkInitialConditions(IProgressMonitor monitor)
|
||||||
throws CoreException, OperationCanceledException {
|
throws CoreException, OperationCanceledException {
|
||||||
|
|
||||||
|
mUnit = null;
|
||||||
mTokenString = null;
|
mTokenString = null;
|
||||||
mTokenStart = -1;
|
|
||||||
mTokenEnd = -1;
|
|
||||||
|
|
||||||
RefactoringStatus status = new RefactoringStatus();
|
RefactoringStatus status = new RefactoringStatus();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
monitor.beginTask("Checking preconditions...", 3);
|
monitor.beginTask("Checking preconditions...", 5);
|
||||||
|
|
||||||
if (!extraChecks(monitor, status)) {
|
if (!checkSourceFile(mFile, status, monitor)) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to get a compilation unit from this file. If it fails, mUnit is null.
|
||||||
try {
|
try {
|
||||||
IBuffer buffer = mUnit.getBuffer();
|
mUnit = JavaCore.createCompilationUnitFrom(mFile);
|
||||||
|
|
||||||
IScanner scanner = ToolFactory.createScanner(
|
// Make sure the unit is not read-only, e.g. it's not a class file or inside a Jar
|
||||||
false, //tokenizeComments
|
if (mUnit.isReadOnly()) {
|
||||||
false, //tokenizeWhiteSpace
|
status.addFatalError("The file is read-only, please make it writeable first.");
|
||||||
false, //assertMode
|
return status;
|
||||||
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 of the right type
|
|
||||||
if (token == ITerminalSymbols.TokenNameStringLiteral) {
|
|
||||||
mTokenString = new String(scanner.getCurrentTokenSource());
|
|
||||||
mTokenStart = scanner.getCurrentTokenStartPosition();
|
|
||||||
mTokenEnd = scanner.getCurrentTokenEndPosition();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else if (scanner.getCurrentTokenStartPosition() > mSelectionEnd) {
|
|
||||||
// scanner is past the selection, abort.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (JavaModelException e1) {
|
|
||||||
// Error in mUnit.getBuffer. Ignore.
|
// This is a Java file. Check if it contains the selection we want.
|
||||||
} catch (InvalidInputException e2) {
|
if (!findSelectionInJavaUnit(mUnit, status, monitor)) {
|
||||||
// Error in scanner.getNextToken. Ignore.
|
return status;
|
||||||
} finally {
|
}
|
||||||
monitor.worked(1);
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
// That was not a Java file. Ignore.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTokenString != null) {
|
if (mUnit == null) {
|
||||||
// As a literal string, the token should have surrounding quotes. Remove them.
|
// Check this an XML file and get the selection and its context.
|
||||||
int len = mTokenString.length();
|
// TODO
|
||||||
if (len > 0 &&
|
status.addFatalError("Selection must be inside a Java source file.");
|
||||||
mTokenString.charAt(0) == '"' &&
|
|
||||||
mTokenString.charAt(len - 1) == '"') {
|
|
||||||
mTokenString = mTokenString.substring(1, len - 1);
|
|
||||||
}
|
|
||||||
// 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);
|
|
||||||
} finally {
|
} finally {
|
||||||
monitor.done();
|
monitor.done();
|
||||||
}
|
}
|
||||||
@@ -283,31 +260,94 @@ class ExtractStringRefactoring extends Refactoring {
|
|||||||
return status;
|
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.
|
||||||
|
*/
|
||||||
|
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 of 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.
|
||||||
|
int len = mTokenString.length();
|
||||||
|
if (len > 0 &&
|
||||||
|
mTokenString.charAt(0) == '"' &&
|
||||||
|
mTokenString.charAt(len - 1) == '"') {
|
||||||
|
mTokenString = mTokenString.substring(1, len - 1);
|
||||||
|
}
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests from org.eclipse.jdt.internal.corext.refactoringChecks#validateEdit()
|
* Tests from org.eclipse.jdt.internal.corext.refactoringChecks#validateEdit()
|
||||||
* Might not be useful.
|
* Might not be useful.
|
||||||
*
|
*
|
||||||
|
* On success, advance the monitor by 2.
|
||||||
|
*
|
||||||
* @return False if caller should abort, true if caller should continue.
|
* @return False if caller should abort, true if caller should continue.
|
||||||
*/
|
*/
|
||||||
private boolean extraChecks(IProgressMonitor monitor, RefactoringStatus status) {
|
private boolean checkSourceFile(IFile file,
|
||||||
//
|
RefactoringStatus status,
|
||||||
IResource res = mUnit.getPrimary().getResource();
|
IProgressMonitor monitor) {
|
||||||
if (res == null || res.getType() != IResource.FILE) {
|
|
||||||
status.addFatalError("Cannot access resource; only regular files can be used.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
monitor.worked(1);
|
|
||||||
|
|
||||||
// check whether the source file is in sync
|
// check whether the source file is in sync
|
||||||
if (!res.isSynchronized(IResource.DEPTH_ZERO)) {
|
if (!file.isSynchronized(IResource.DEPTH_ZERO)) {
|
||||||
status.addFatalError("The file is not synchronized. Please save it first.");
|
status.addFatalError("The file is not synchronized. Please save it first.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
monitor.worked(1);
|
monitor.worked(1);
|
||||||
|
|
||||||
// make sure we can write to it.
|
// make sure we can write to it.
|
||||||
ResourceAttributes resAttr = res.getResourceAttributes();
|
ResourceAttributes resAttr = file.getResourceAttributes();
|
||||||
if (mUnit.isReadOnly() || resAttr == null || resAttr.isReadOnly()) {
|
if (resAttr == null || resAttr.isReadOnly()) {
|
||||||
status.addFatalError("The file is read-only, please make it writeable first.");
|
status.addFatalError("The file is read-only, please make it writeable first.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user