Home | History | Annotate | Download | only in extractstring
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.eclipse.adt.internal.refactorings.extractstring;
     18 
     19 import com.android.ide.eclipse.adt.AdtConstants;
     20 
     21 import org.eclipse.core.resources.IFile;
     22 import org.eclipse.core.resources.IProject;
     23 import org.eclipse.core.runtime.CoreException;
     24 import org.eclipse.jdt.core.ICompilationUnit;
     25 import org.eclipse.jdt.core.JavaCore;
     26 import org.eclipse.jface.action.IAction;
     27 import org.eclipse.jface.text.ITextSelection;
     28 import org.eclipse.jface.viewers.ISelection;
     29 import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
     30 import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
     31 import org.eclipse.ui.IEditorInput;
     32 import org.eclipse.ui.IEditorPart;
     33 import org.eclipse.ui.IWorkbenchPage;
     34 import org.eclipse.ui.IWorkbenchWindow;
     35 import org.eclipse.ui.IWorkbenchWindowActionDelegate;
     36 import org.eclipse.ui.PlatformUI;
     37 import org.eclipse.ui.part.FileEditorInput;
     38 
     39 /*
     40  * Quick Reference Link:
     41  * http://www.eclipse.org/articles/article.php?file=Article-Unleashing-the-Power-of-Refactoring/index.html
     42  * and
     43  * http://www.ibm.com/developerworks/opensource/library/os-ecjdt/
     44  */
     45 
     46 /**
     47  * Action executed when the "Extract String" menu item is invoked.
     48  * <p/>
     49  * The intent of the action is to start a refactoring that extracts a source string and
     50  * replaces it by an Android string resource ID.
     51  * <p/>
     52  * Workflow:
     53  * <ul>
     54  * <li> The action is currently located in the Refactoring menu in the main menu.
     55  * <li> TODO: extend the popup refactoring menu in a Java or Android XML file.
     56  * <li> The action is only enabled if the selection is 1 character or more. That is at least part
     57  *     of the string must be selected, it's not enough to just move the insertion point. This is
     58  *     a limitation due to {@link #selectionChanged(IAction, ISelection)} not being called when
     59  *     the insertion point is merely moved. TODO: address this limitation.
     60  * <ul> The action gets the current {@link ISelection}. It also knows the current
     61  *     {@link IWorkbenchWindow}. However for the refactoring we are also interested in having the
     62  *     actual resource file. By looking at the Active Window > Active Page > Active Editor we
     63  *     can get the {@link IEditorInput} and find the {@link ICompilationUnit} (aka Java file)
     64  *     that is being edited.
     65  * <ul> TODO: change this to find the {@link IFile} being manipulated. The {@link ICompilationUnit}
     66  *     can be inferred using {@link JavaCore#createCompilationUnitFrom(IFile)}. This will allow
     67  *     us to be able to work with a selection from an Android XML file later.
     68  * <li> The action creates a new {@link ExtractStringRefactoring} and make it run on in a new
     69  *     {@link ExtractStringWizard}.
     70  * <ul>
     71  */
     72 public class ExtractStringAction implements IWorkbenchWindowActionDelegate {
     73 
     74     /** Keep track of the current workbench window. */
     75     private IWorkbenchWindow mWindow;
     76     private ITextSelection mSelection;
     77     private IEditorPart mEditor;
     78     private IFile mFile;
     79 
     80     /**
     81      * Keep track of the current workbench window.
     82      */
     83     @Override
     84     public void init(IWorkbenchWindow window) {
     85         mWindow = window;
     86     }
     87 
     88     @Override
     89     public void dispose() {
     90         // Nothing to do
     91     }
     92 
     93     /**
     94      * Examine the selection to determine if the action should be enabled or not.
     95      * <p/>
     96      * Keep a link to the relevant selection structure (i.e. a part of the Java AST).
     97      */
     98     @Override
     99     public void selectionChanged(IAction action, ISelection selection) {
    100 
    101         // Note, two kinds of selections are returned here:
    102         // ITextSelection on a Java source window
    103         // IStructuredSelection in the outline or navigator
    104         // This simply deals with the refactoring based on a non-empty selection.
    105         // At that point, just enable the action and later decide if it's valid when it actually
    106         // runs since we don't have access to the AST yet.
    107 
    108         mSelection = null;
    109         mFile = null;
    110 
    111         if (selection instanceof ITextSelection) {
    112             mSelection = (ITextSelection) selection;
    113             if (mSelection.getLength() > 0) {
    114                 mEditor = getActiveEditor();
    115                 mFile = getSelectedFile(mEditor);
    116             }
    117         }
    118 
    119         action.setEnabled(mSelection != null && mFile != null);
    120     }
    121 
    122     /**
    123      * Create a new instance of our refactoring and a wizard to configure it.
    124      */
    125     @Override
    126     public void run(IAction action) {
    127         if (mSelection != null && mFile != null) {
    128             ExtractStringRefactoring ref = new ExtractStringRefactoring(mFile, mEditor, mSelection);
    129             RefactoringWizard wizard = new ExtractStringWizard(ref, mFile.getProject());
    130             RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
    131             try {
    132                 op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
    133             } catch (InterruptedException e) {
    134                 // Interrupted. Pass.
    135             }
    136         }
    137     }
    138 
    139     /**
    140      * Returns the active editor (hopefully matching our selection) or null.
    141      */
    142     private IEditorPart getActiveEditor() {
    143         IWorkbenchWindow wwin = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
    144         if (wwin != null) {
    145             IWorkbenchPage page = wwin.getActivePage();
    146             if (page != null) {
    147                 return page.getActiveEditor();
    148             }
    149         }
    150 
    151         return null;
    152     }
    153 
    154     /**
    155      * Returns the active {@link IFile} (hopefully matching our selection) or null.
    156      * The file is only returned if it's a file from a project with an Android nature.
    157      * <p/>
    158      * At that point we do not try to analyze if the selection nor the file is suitable
    159      * for the refactoring. This check is performed when the refactoring is invoked since
    160      * it can then produce meaningful error messages as needed.
    161      */
    162     private IFile getSelectedFile(IEditorPart editor) {
    163         if (editor != null) {
    164             IEditorInput input = editor.getEditorInput();
    165 
    166             if (input instanceof FileEditorInput) {
    167                 FileEditorInput fi = (FileEditorInput) input;
    168                 IFile file = fi.getFile();
    169                 if (file.exists()) {
    170                     IProject proj = file.getProject();
    171                     try {
    172                         if (proj != null && proj.hasNature(AdtConstants.NATURE_DEFAULT)) {
    173                             return file;
    174                         }
    175                     } catch (CoreException e) {
    176                         // ignore
    177                     }
    178                 }
    179             }
    180         }
    181 
    182         return null;
    183     }
    184 }
    185