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;
|
||||
|
||||
import com.android.ide.eclipse.common.AndroidConstants;
|
||||
|
||||
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.ITypeRoot;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
@@ -32,6 +36,7 @@ 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:
|
||||
@@ -71,7 +76,7 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
||||
/** Keep track of the current workbench window. */
|
||||
private IWorkbenchWindow mWindow;
|
||||
private ITextSelection mSelection;
|
||||
private ICompilationUnit mUnit;
|
||||
private IFile mFile;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
mSelection = null;
|
||||
mUnit = null;
|
||||
mFile = null;
|
||||
|
||||
if (selection instanceof ITextSelection) {
|
||||
mSelection = (ITextSelection) selection;
|
||||
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.
|
||||
*/
|
||||
public void run(IAction action) {
|
||||
if (mSelection != null && mUnit != null) {
|
||||
ExtractStringRefactoring ref = new ExtractStringRefactoring(mUnit, mSelection);
|
||||
if (mSelection != null && mFile != null) {
|
||||
ExtractStringRefactoring ref = new ExtractStringRefactoring(mFile, mSelection);
|
||||
RefactoringWizard wizard = new ExtractStringWizard(ref, "Extract Android String");
|
||||
RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
|
||||
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();
|
||||
if (wwin != null) {
|
||||
IWorkbenchPage page = wwin.getActivePage();
|
||||
@@ -144,12 +148,19 @@ public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
|
||||
IEditorPart editor = page.getActiveEditor();
|
||||
if (editor != null) {
|
||||
IEditorInput input = editor.getEditorInput();
|
||||
if (input != null) {
|
||||
ITypeRoot typeRoot = JavaUI.getEditorInputTypeRoot(input);
|
||||
// The type root can be either a .class or a .java (aka compilation unit).
|
||||
// We want the compilation unit kind.
|
||||
if (typeRoot instanceof ICompilationUnit) {
|
||||
return (ICompilationUnit) typeRoot;
|
||||
|
||||
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(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.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;
|
||||
@@ -126,46 +128,54 @@ import javax.xml.xpath.XPathExpressionException;
|
||||
*/
|
||||
class ExtractStringRefactoring extends Refactoring {
|
||||
|
||||
/** The compilation unit, a.k.a. the Java file model. */
|
||||
private final ICompilationUnit mUnit;
|
||||
/** The file model being manipulated. */
|
||||
private final IFile mFile;
|
||||
/** The start of the selection in {@link #mFile}. */
|
||||
private final int mSelectionStart;
|
||||
/** The end of the selection in {@link #mFile}. */
|
||||
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. */
|
||||
private String mTokenString;
|
||||
/** Start position of the string token in the source buffer. */
|
||||
private int mTokenStart;
|
||||
/** End position of the string token in the source buffer. */
|
||||
private int mTokenEnd;
|
||||
|
||||
/** The XML string ID selected by the user in the wizard. */
|
||||
private String mXmlStringId;
|
||||
/** The path of the XML file that will define {@link #mXmlStringId}, selected by the user
|
||||
* in the wizard. */
|
||||
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;
|
||||
/** An instance of XPath, created lazily on demand. */
|
||||
private XPath mXPath;
|
||||
/** The list of changes computed by {@link #checkFinalConditions(IProgressMonitor)} and
|
||||
* used by {@link #createChange(IProgressMonitor)}. */
|
||||
private ArrayList<Change> mChanges;
|
||||
|
||||
public ExtractStringRefactoring(Map<String, String> arguments)
|
||||
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$
|
||||
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$
|
||||
}
|
||||
|
||||
private Map<String, String> createArgumentMap() {
|
||||
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-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$
|
||||
return args;
|
||||
}
|
||||
|
||||
public ExtractStringRefactoring(ICompilationUnit unit, ITextSelection selection) {
|
||||
mUnit = unit;
|
||||
|
||||
public ExtractStringRefactoring(IFile file, ITextSelection selection) {
|
||||
mFile = file;
|
||||
mSelectionStart = selection.getOffset();
|
||||
mSelectionEnd = mSelectionStart + selection.getLength();
|
||||
}
|
||||
@@ -207,75 +217,42 @@ class ExtractStringRefactoring extends Refactoring {
|
||||
public RefactoringStatus checkInitialConditions(IProgressMonitor monitor)
|
||||
throws CoreException, OperationCanceledException {
|
||||
|
||||
mUnit = null;
|
||||
mTokenString = null;
|
||||
mTokenStart = -1;
|
||||
mTokenEnd = -1;
|
||||
|
||||
RefactoringStatus status = new RefactoringStatus();
|
||||
|
||||
try {
|
||||
monitor.beginTask("Checking preconditions...", 3);
|
||||
monitor.beginTask("Checking preconditions...", 5);
|
||||
|
||||
if (!extraChecks(monitor, status)) {
|
||||
if (!checkSourceFile(mFile, status, monitor)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Try to get a compilation unit from this file. If it fails, mUnit is null.
|
||||
try {
|
||||
IBuffer buffer = mUnit.getBuffer();
|
||||
mUnit = JavaCore.createCompilationUnitFrom(mFile);
|
||||
|
||||
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());
|
||||
mTokenStart = scanner.getCurrentTokenStartPosition();
|
||||
mTokenEnd = scanner.getCurrentTokenEndPosition();
|
||||
}
|
||||
break;
|
||||
} else if (scanner.getCurrentTokenStartPosition() > mSelectionEnd) {
|
||||
// scanner is past the selection, abort.
|
||||
break;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
} catch (JavaModelException e1) {
|
||||
// Error in mUnit.getBuffer. Ignore.
|
||||
} catch (InvalidInputException e2) {
|
||||
// Error in scanner.getNextToken. Ignore.
|
||||
} finally {
|
||||
monitor.worked(1);
|
||||
|
||||
// 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 (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 (mUnit == null) {
|
||||
// Check this an XML file and get the selection and its context.
|
||||
// TODO
|
||||
status.addFatalError("Selection must be inside a Java source file.");
|
||||
}
|
||||
|
||||
if (mTokenString == null) {
|
||||
status.addFatalError("Please select a Java string literal.");
|
||||
}
|
||||
|
||||
monitor.worked(1);
|
||||
} finally {
|
||||
monitor.done();
|
||||
}
|
||||
@@ -283,31 +260,94 @@ class ExtractStringRefactoring extends Refactoring {
|
||||
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()
|
||||
* Might not be useful.
|
||||
*
|
||||
* On success, advance the monitor by 2.
|
||||
*
|
||||
* @return False if caller should abort, true if caller should continue.
|
||||
*/
|
||||
private boolean extraChecks(IProgressMonitor monitor, RefactoringStatus status) {
|
||||
//
|
||||
IResource res = mUnit.getPrimary().getResource();
|
||||
if (res == null || res.getType() != IResource.FILE) {
|
||||
status.addFatalError("Cannot access resource; only regular files can be used.");
|
||||
return false;
|
||||
}
|
||||
monitor.worked(1);
|
||||
|
||||
private boolean checkSourceFile(IFile file,
|
||||
RefactoringStatus status,
|
||||
IProgressMonitor monitor) {
|
||||
// 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.");
|
||||
return false;
|
||||
}
|
||||
monitor.worked(1);
|
||||
|
||||
// make sure we can write to it.
|
||||
ResourceAttributes resAttr = res.getResourceAttributes();
|
||||
if (mUnit.isReadOnly() || resAttr == null || resAttr.isReadOnly()) {
|
||||
ResourceAttributes resAttr = file.getResourceAttributes();
|
||||
if (resAttr == null || resAttr.isReadOnly()) {
|
||||
status.addFatalError("The file is read-only, please make it writeable first.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user