Automated import from //branches/donutburger/...@141823,141823

This commit is contained in:
Raphael Moll
2009-03-24 20:57:57 -07:00
committed by The Android Open Source Project
parent 511d471363
commit b6007ebd5c
2 changed files with 153 additions and 102 deletions

View File

@@ -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
}
}
}
}

View File

@@ -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);
if (!extraChecks(monitor, status)) {
monitor.beginTask("Checking preconditions...", 5);
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);
}
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;
// 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) {
status.addFatalError("Please select a Java string literal.");
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.");
}
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;
}