• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.ide.eclipse.adt.internal.lint;
18 
19 import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML;
20 
21 import com.android.ide.eclipse.adt.AdtPlugin;
22 import com.android.ide.eclipse.adt.AdtUtils;
23 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
24 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
25 import com.android.tools.lint.detector.api.LintUtils;
26 
27 import org.eclipse.core.resources.IFile;
28 import org.eclipse.core.resources.IProject;
29 import org.eclipse.core.resources.IResource;
30 import org.eclipse.core.runtime.IAdaptable;
31 import org.eclipse.jdt.core.IJavaProject;
32 import org.eclipse.jdt.ui.JavaElementLabelProvider;
33 import org.eclipse.jface.action.Action;
34 import org.eclipse.jface.action.ActionContributionItem;
35 import org.eclipse.jface.action.IAction;
36 import org.eclipse.jface.action.IMenuCreator;
37 import org.eclipse.jface.action.Separator;
38 import org.eclipse.jface.dialogs.MessageDialog;
39 import org.eclipse.jface.resource.ImageDescriptor;
40 import org.eclipse.jface.viewers.ILabelProvider;
41 import org.eclipse.jface.viewers.ISelection;
42 import org.eclipse.jface.viewers.IStructuredSelection;
43 import org.eclipse.swt.widgets.Control;
44 import org.eclipse.swt.widgets.Menu;
45 import org.eclipse.ui.IObjectActionDelegate;
46 import org.eclipse.ui.ISharedImages;
47 import org.eclipse.ui.IWorkbenchPart;
48 import org.eclipse.ui.IWorkbenchWindow;
49 import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
50 import org.eclipse.ui.PlatformUI;
51 import org.eclipse.ui.texteditor.ITextEditor;
52 
53 import java.util.ArrayList;
54 import java.util.Collections;
55 import java.util.Iterator;
56 import java.util.List;
57 
58 /**
59  * Action which runs Lint on the currently projects (and also provides a
60  * pulldown menu in the toolbar for selecting specifically which projects to
61  * check)
62  */
63 public class RunLintAction implements IObjectActionDelegate, IMenuCreator,
64         IWorkbenchWindowPulldownDelegate {
65 
66     private ISelection mSelection;
67     private Menu mMenu;
68 
69     @Override
selectionChanged(IAction action, ISelection selection)70     public void selectionChanged(IAction action, ISelection selection) {
71         mSelection = selection;
72     }
73 
74     @Override
run(IAction action)75     public void run(IAction action) {
76         List<IProject> projects = getProjects(mSelection, true /* warn */);
77 
78         if (!projects.isEmpty()) {
79             EclipseLintRunner.startLint(projects, null, false /*fatalOnly*/, true /*show*/);
80         } else {
81             MessageDialog.openWarning(AdtPlugin.getDisplay().getActiveShell(), "Lint",
82                     "Could not run Lint: Select a project first.");
83         }
84     }
85 
86     /** Returns the Android project(s) to apply a lint run to. */
getProjects(ISelection selection, boolean warn)87     static List<IProject> getProjects(ISelection selection, boolean warn) {
88         List<IProject> projects = new ArrayList<IProject>();
89 
90         if (selection instanceof IStructuredSelection) {
91             IStructuredSelection structuredSelection = (IStructuredSelection) selection;
92             // get the unique selected item.
93             Iterator<?> iterator = structuredSelection.iterator();
94             while (iterator.hasNext()) {
95                 Object element = iterator.next();
96 
97                 // First look up the resource (since some adaptables
98                 // provide an IResource but not an IProject, and we can
99                 // always go from IResource to IProject)
100                 IResource resource = null;
101                 if (element instanceof IResource) { // may include IProject
102                    resource = (IResource) element;
103                 } else if (element instanceof IAdaptable) {
104                     IAdaptable adaptable = (IAdaptable)element;
105                     Object adapter = adaptable.getAdapter(IResource.class);
106                     resource = (IResource) adapter;
107                 }
108 
109                 // get the project object from it.
110                 IProject project = null;
111                 if (resource != null) {
112                     project = resource.getProject();
113                 } else if (element instanceof IAdaptable) {
114                     project = (IProject) ((IAdaptable) element).getAdapter(IProject.class);
115                 }
116 
117                 if (project != null && !projects.contains(project)) {
118                     projects.add(project);
119                 }
120             }
121         }
122 
123         if (projects.isEmpty()) {
124             // Try to look at the active editor instead
125             IFile file = AdtUtils.getActiveFile();
126             if (file != null) {
127                 projects.add(file.getProject());
128             }
129         }
130 
131         if (projects.isEmpty()) {
132             // If we didn't find a default project based on the selection, check how many
133             // open Android projects we can find in the current workspace. If there's only
134             // one, we'll just select it by default.
135             IJavaProject[] open = AdtUtils.getOpenAndroidProjects();
136             for (IJavaProject project : open) {
137                 projects.add(project.getProject());
138             }
139         } else {
140             // Make sure all the projects are Android projects
141             for (IProject project : projects) {
142                 if (!BaseProjectHelper.isAndroidProject(project)) {
143                     if (warn) {
144                         MessageDialog.openWarning(AdtPlugin.getDisplay().getActiveShell(),
145                                 "Lint", "Select Android projects.");
146                     }
147                     return Collections.emptyList();
148                 }
149             }
150         }
151 
152         if (projects.isEmpty() && warn) {
153             MessageDialog.openWarning(AdtPlugin.getDisplay().getActiveShell(), "Lint",
154                     "Could not run Lint: Select a project first.");
155         }
156 
157         return projects;
158     }
159 
160     @Override
setActivePart(IAction action, IWorkbenchPart targetPart)161     public void setActivePart(IAction action, IWorkbenchPart targetPart) {
162     }
163 
164     @Override
dispose()165     public void dispose() {
166         if (mMenu != null) {
167             mMenu.dispose();
168         }
169     }
170 
171     @Override
init(IWorkbenchWindow window)172     public void init(IWorkbenchWindow window) {
173     }
174 
175     // ---- IMenuCreator ----
176 
177     @Override
getMenu(Control parent)178     public Menu getMenu(Control parent) {
179         mMenu = new Menu(parent);
180 
181         IconFactory iconFactory = IconFactory.getInstance();
182         ImageDescriptor allIcon = iconFactory.getImageDescriptor("lintrun"); //$NON-NLS-1$
183         LintMenuAction allAction = new LintMenuAction("Check All Projects", allIcon, false, null);
184 
185         addAction(allAction);
186         addSeparator();
187         IJavaProject[] projects = AdtUtils.getOpenAndroidProjects();
188         ILabelProvider provider = new JavaElementLabelProvider(
189                 JavaElementLabelProvider.SHOW_DEFAULT);
190         for (IJavaProject project : projects) {
191             IProject p = project.getProject();
192             ImageDescriptor icon = ImageDescriptor.createFromImage(provider.getImage(p));
193             String label = String.format("Check %1$s", p.getName());
194             LintMenuAction projectAction = new LintMenuAction(label, icon, false, p);
195             addAction(projectAction);
196         }
197 
198         ITextEditor textEditor = AdtUtils.getActiveTextEditor();
199         if (textEditor != null) {
200             IFile file = AdtUtils.getActiveFile();
201             // Currently only supported for XML files
202             if (file != null && LintUtils.endsWith(file.getName(), DOT_XML)) {
203                 ImageDescriptor icon = ImageDescriptor.createFromImage(provider.getImage(file));
204                 IAction fileAction = new LintMenuAction("Check Current File", icon, false, file);
205 
206                 addSeparator();
207                 addAction(fileAction);
208             }
209         }
210 
211         ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
212         ImageDescriptor clear = images.getImageDescriptor(ISharedImages.IMG_ELCL_REMOVEALL);
213         LintMenuAction clearAction = new LintMenuAction("Clear Lint Markers", clear, true, null);
214         addSeparator();
215         addAction(clearAction);
216 
217         return mMenu;
218     }
219 
addAction(IAction action)220     private void addAction(IAction action) {
221         ActionContributionItem item = new ActionContributionItem(action);
222         item.fill(mMenu, -1);
223     }
224 
addSeparator()225     private void addSeparator() {
226         new Separator().fill(mMenu, -1);
227     }
228 
229     @Override
getMenu(Menu parent)230     public Menu getMenu(Menu parent) {
231         return null;
232     }
233 
234     /**
235      * Actions in the pulldown context menu: run lint or clear lint markers on
236      * the given resource
237      */
238     private static class LintMenuAction extends Action {
239         private final boolean mClear;
240         private final IResource mResource;
241 
242         /**
243          * Creates a new context menu action
244          *
245          * @param text the label
246          * @param descriptor the icon
247          * @param clear if true, clear lint markers otherwise check the resource
248          * @param resource the resource to check or clear markers for, where
249          *            null means all projects
250          */
LintMenuAction(String text, ImageDescriptor descriptor, boolean clear, IResource resource)251         private LintMenuAction(String text, ImageDescriptor descriptor, boolean clear,
252                 IResource resource) {
253             super(text, descriptor);
254             mClear = clear;
255             mResource = resource;
256         }
257 
258         @Override
run()259         public void run() {
260             List<IResource> resources = new ArrayList<IResource>();
261             if (mResource == null) {
262                 // All projects
263                 IJavaProject[] open = AdtUtils.getOpenAndroidProjects();
264                 for (IJavaProject project : open) {
265                     resources.add(project.getProject());
266                 }
267             } else {
268                 resources.add(mResource);
269             }
270             EclipseLintRunner.cancelCurrentJobs(false);
271             if (mClear) {
272                 EclipseLintClient.clearMarkers(resources);
273             } else {
274                 EclipseLintRunner.startLint(resources, null, false /*fatalOnly*/, true /*show*/);
275             }
276         }
277     }
278 }
279