OSDN Git Service

Automated import from //branches/donutburger/...@141823,141823
authorRaphael Moll <>
Wed, 25 Mar 2009 03:57:57 +0000 (20:57 -0700)
committerThe Android Open Source Project <initial-contribution@android.com>
Wed, 25 Mar 2009 03:57:57 +0000 (20:57 -0700)
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringAction.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringRefactoring.java

index 5287015..dceb144 100644 (file)
 
 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
+                            }
                         }
                     }
                 }
index 715503c..99711bf 100644 (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();
-
-                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;
-                    }
-                }
-            } catch (JavaModelException e1) {
-                // Error in mUnit.getBuffer. Ignore.
-            } catch (InvalidInputException e2) {
-                // Error in scanner.getNextToken. Ignore.
-            } finally {
-                monitor.worked(1);
-            }
+                mUnit = JavaCore.createCompilationUnitFrom(mFile);
 
-            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);
+                // 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;
                 }
-                // 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();
         }
@@ -284,30 +261,93 @@ class ExtractStringRefactoring extends Refactoring {
     }
 
     /**
-     * Tests from org.eclipse.jdt.internal.corext.refactoringChecks#validateEdit()
-     * Might not be useful.
+     * Try to find the selected Java element in the compilation unit.
      * 
-     * @return False if caller should abort, true if caller should continue.
+     * 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 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;
+    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 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;
         }