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 init(IWorkbenchWindow window)84 public void init(IWorkbenchWindow window) { 85 mWindow = window; 86 } 87 88 @Override dispose()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 selectionChanged(IAction action, ISelection selection)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 run(IAction action)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 */ getActiveEditor()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 */ getSelectedFile(IEditorPart editor)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