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 public void init(IWorkbenchWindow window) { 84 mWindow = window; 85 } 86 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 */ 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 */ 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 */ 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 */ 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(AdtConstants.NATURE_DEFAULT)) { 169 return file; 170 } 171 } catch (CoreException e) { 172 // ignore 173 } 174 } 175 } 176 } 177 178 return null; 179 } 180 } 181