1 /* 2 * Copyright (C) 2011 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 package com.android.ide.eclipse.adt.internal.editors.layout.refactoring; 17 18 import com.android.ide.eclipse.adt.AdtConstants; 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.AdtUtils; 21 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate; 22 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo; 23 24 import org.eclipse.core.resources.IFile; 25 import org.eclipse.core.resources.IProject; 26 import org.eclipse.core.runtime.CoreException; 27 import org.eclipse.jface.action.Action; 28 import org.eclipse.jface.action.IAction; 29 import org.eclipse.jface.text.ITextSelection; 30 import org.eclipse.jface.viewers.ISelection; 31 import org.eclipse.jface.viewers.ITreeSelection; 32 import org.eclipse.ui.IEditorInput; 33 import org.eclipse.ui.IEditorPart; 34 import org.eclipse.ui.IEditorSite; 35 import org.eclipse.ui.IWorkbenchWindow; 36 import org.eclipse.ui.IWorkbenchWindowActionDelegate; 37 import org.eclipse.ui.part.FileEditorInput; 38 39 abstract class VisualRefactoringAction implements IWorkbenchWindowActionDelegate { 40 protected IWorkbenchWindow mWindow; 41 protected ITextSelection mTextSelection; 42 protected ITreeSelection mTreeSelection; 43 protected LayoutEditorDelegate mDelegate; 44 protected IFile mFile; 45 46 /** 47 * Keep track of the current workbench window. 48 */ 49 @Override init(IWorkbenchWindow window)50 public void init(IWorkbenchWindow window) { 51 mWindow = window; 52 } 53 54 @Override dispose()55 public void dispose() { 56 } 57 58 /** 59 * Examine the selection to determine if the action should be enabled or not. 60 * <p/> 61 * Keep a link to the relevant selection structure 62 */ 63 @Override selectionChanged(IAction action, ISelection selection)64 public void selectionChanged(IAction action, ISelection selection) { 65 // Look for selections in XML and in the layout UI editor 66 67 // Note, two kinds of selections are returned here: 68 // ITextSelection on a Java source window 69 // IStructuredSelection in the outline or navigator 70 // This simply deals with the refactoring based on a non-empty selection. 71 // At that point, just enable the action and later decide if it's valid when it actually 72 // runs since we don't have access to the AST yet. 73 74 mTextSelection = null; 75 mTreeSelection = null; 76 mFile = null; 77 78 IEditorPart editor = null; 79 80 if (selection instanceof ITextSelection) { 81 mTextSelection = (ITextSelection) selection; 82 editor = AdtUtils.getActiveEditor(); 83 mFile = getSelectedFile(editor); 84 } else if (selection instanceof ITreeSelection) { 85 Object firstElement = ((ITreeSelection)selection).getFirstElement(); 86 if (firstElement instanceof CanvasViewInfo) { 87 mTreeSelection = (ITreeSelection) selection; 88 editor = AdtUtils.getActiveEditor(); 89 mFile = getSelectedFile(editor); 90 } 91 } 92 93 mDelegate = LayoutEditorDelegate.fromEditor(editor); 94 95 action.setEnabled((mTextSelection != null || mTreeSelection != null) 96 && mFile != null && mDelegate != null); 97 } 98 99 /** 100 * Create a new instance of our refactoring and a wizard to configure it. 101 */ 102 @Override run(IAction action)103 public abstract void run(IAction action); 104 105 /** 106 * Returns the active {@link IFile} (hopefully matching our selection) or null. 107 * The file is only returned if it's a file from a project with an Android nature. 108 * <p/> 109 * At that point we do not try to analyze if the selection nor the file is suitable 110 * for the refactoring. This check is performed when the refactoring is invoked since 111 * it can then produce meaningful error messages as needed. 112 */ getSelectedFile(IEditorPart editor)113 private IFile getSelectedFile(IEditorPart editor) { 114 if (editor != null) { 115 IEditorInput input = editor.getEditorInput(); 116 117 if (input instanceof FileEditorInput) { 118 FileEditorInput fi = (FileEditorInput) input; 119 IFile file = fi.getFile(); 120 if (file.exists()) { 121 IProject proj = file.getProject(); 122 try { 123 if (proj != null && proj.hasNature(AdtConstants.NATURE_DEFAULT)) { 124 return file; 125 } 126 } catch (CoreException e) { 127 // ignore 128 } 129 } 130 } 131 } 132 133 return null; 134 } 135 create(String title, LayoutEditorDelegate editorDelegate, Class<? extends VisualRefactoringAction> clz)136 public static IAction create(String title, LayoutEditorDelegate editorDelegate, 137 Class<? extends VisualRefactoringAction> clz) { 138 return new ActionWrapper(title, editorDelegate, clz); 139 } 140 141 private static class ActionWrapper extends Action { 142 private Class<? extends VisualRefactoringAction> mClass; 143 private LayoutEditorDelegate mEditorDelegate; 144 ActionWrapper(String title, LayoutEditorDelegate editorDelegate, Class<? extends VisualRefactoringAction> clz)145 ActionWrapper(String title, LayoutEditorDelegate editorDelegate, 146 Class<? extends VisualRefactoringAction> clz) { 147 super(title); 148 mEditorDelegate = editorDelegate; 149 mClass = clz; 150 } 151 152 @Override run()153 public void run() { 154 VisualRefactoringAction action; 155 try { 156 action = mClass.newInstance(); 157 } catch (Exception e) { 158 AdtPlugin.log(e, null); 159 return; 160 } 161 IEditorSite site = mEditorDelegate.getEditor().getEditorSite(); 162 action.init(site.getWorkbenchWindow()); 163 ISelection selection = site.getSelectionProvider().getSelection(); 164 action.selectionChanged(ActionWrapper.this, selection); 165 if (isEnabled()) { 166 action.run(ActionWrapper.this); 167 } 168 } 169 } 170 } 171