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