• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.AndroidConstants;
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      */
init(IWorkbenchWindow window)83     public void init(IWorkbenchWindow window) {
84         mWindow = window;
85     }
86 
dispose()87     public void dispose() {
88         // Nothing to do
89     }
90 
91     /**
92      * Examine the selection to determine if the action should be enabled or not.
93      * <p/>
94      * Keep a link to the relevant selection structure (i.e. a part of the Java AST).
95      */
selectionChanged(IAction action, ISelection selection)96     public void selectionChanged(IAction action, ISelection selection) {
97 
98         // Note, two kinds of selections are returned here:
99         // ITextSelection on a Java source window
100         // IStructuredSelection in the outline or navigator
101         // This simply deals with the refactoring based on a non-empty selection.
102         // At that point, just enable the action and later decide if it's valid when it actually
103         // runs since we don't have access to the AST yet.
104 
105         mSelection = null;
106         mFile = null;
107 
108         if (selection instanceof ITextSelection) {
109             mSelection = (ITextSelection) selection;
110             if (mSelection.getLength() > 0) {
111                 mEditor = getActiveEditor();
112                 mFile = getSelectedFile(mEditor);
113             }
114         }
115 
116         action.setEnabled(mSelection != null && mFile != null);
117     }
118 
119     /**
120      * Create a new instance of our refactoring and a wizard to configure it.
121      */
run(IAction action)122     public void run(IAction action) {
123         if (mSelection != null && mFile != null) {
124             ExtractStringRefactoring ref = new ExtractStringRefactoring(mFile, mEditor, mSelection);
125             RefactoringWizard wizard = new ExtractStringWizard(ref, mFile.getProject());
126             RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
127             try {
128                 op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
129             } catch (InterruptedException e) {
130                 // Interrupted. Pass.
131             }
132         }
133     }
134 
135     /**
136      * Returns the active editor (hopefully matching our selection) or null.
137      */
getActiveEditor()138     private IEditorPart getActiveEditor() {
139         IWorkbenchWindow wwin = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
140         if (wwin != null) {
141             IWorkbenchPage page = wwin.getActivePage();
142             if (page != null) {
143                 return page.getActiveEditor();
144             }
145         }
146 
147         return null;
148     }
149 
150     /**
151      * Returns the active {@link IFile} (hopefully matching our selection) or null.
152      * The file is only returned if it's a file from a project with an Android nature.
153      * <p/>
154      * At that point we do not try to analyze if the selection nor the file is suitable
155      * for the refactoring. This check is performed when the refactoring is invoked since
156      * it can then produce meaningful error messages as needed.
157      */
getSelectedFile(IEditorPart editor)158     private IFile getSelectedFile(IEditorPart editor) {
159         if (editor != null) {
160             IEditorInput input = editor.getEditorInput();
161 
162             if (input instanceof FileEditorInput) {
163                 FileEditorInput fi = (FileEditorInput) input;
164                 IFile file = fi.getFile();
165                 if (file.exists()) {
166                     IProject proj = file.getProject();
167                     try {
168                         if (proj != null && proj.hasNature(AndroidConstants.NATURE)) {
169                             return file;
170                         }
171                     } catch (CoreException e) {
172                         // ignore
173                     }
174                 }
175             }
176         }
177 
178         return null;
179     }
180 }
181