Home | History | Annotate | Download | only in lint
      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.SdkConstants.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.preferences.AdtPrefs;
     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.jdt.core.IJavaProject;
     31 import org.eclipse.jdt.ui.JavaElementLabelProvider;
     32 import org.eclipse.jface.action.Action;
     33 import org.eclipse.jface.action.ActionContributionItem;
     34 import org.eclipse.jface.action.IAction;
     35 import org.eclipse.jface.action.IMenuCreator;
     36 import org.eclipse.jface.action.Separator;
     37 import org.eclipse.jface.dialogs.MessageDialog;
     38 import org.eclipse.jface.resource.ImageDescriptor;
     39 import org.eclipse.jface.viewers.ILabelProvider;
     40 import org.eclipse.jface.viewers.ISelection;
     41 import org.eclipse.swt.widgets.Control;
     42 import org.eclipse.swt.widgets.Menu;
     43 import org.eclipse.ui.IObjectActionDelegate;
     44 import org.eclipse.ui.ISharedImages;
     45 import org.eclipse.ui.IWorkbenchPart;
     46 import org.eclipse.ui.IWorkbenchWindow;
     47 import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
     48 import org.eclipse.ui.PlatformUI;
     49 import org.eclipse.ui.texteditor.ITextEditor;
     50 
     51 import java.util.ArrayList;
     52 import java.util.List;
     53 
     54 /**
     55  * Action which runs Lint on the currently projects (and also provides a
     56  * pulldown menu in the toolbar for selecting specifically which projects to
     57  * check)
     58  */
     59 public class RunLintAction implements IObjectActionDelegate, IMenuCreator,
     60         IWorkbenchWindowPulldownDelegate {
     61 
     62     private ISelection mSelection;
     63     private Menu mMenu;
     64 
     65     @Override
     66     public void selectionChanged(IAction action, ISelection selection) {
     67         mSelection = selection;
     68     }
     69 
     70     @Override
     71     public void run(IAction action) {
     72         List<IProject> projects = getProjects(mSelection, true /* warn */);
     73 
     74         if (!projects.isEmpty()) {
     75             EclipseLintRunner.startLint(projects, null, null, false /*fatalOnly*/, true /*show*/);
     76         }
     77     }
     78 
     79     /** Returns the Android project(s) to apply a lint run to. */
     80     static List<IProject> getProjects(ISelection selection, boolean warn) {
     81         List<IProject> projects = AdtUtils.getSelectedProjects(selection);
     82 
     83         if (projects.isEmpty() && warn) {
     84             MessageDialog.openWarning(AdtPlugin.getShell(), "Lint",
     85                     "Could not run Lint: Select an Android project first.");
     86         }
     87 
     88         return projects;
     89     }
     90 
     91     @Override
     92     public void setActivePart(IAction action, IWorkbenchPart targetPart) {
     93     }
     94 
     95     @Override
     96     public void dispose() {
     97         if (mMenu != null) {
     98             mMenu.dispose();
     99         }
    100     }
    101 
    102     @Override
    103     public void init(IWorkbenchWindow window) {
    104     }
    105 
    106     // ---- IMenuCreator ----
    107 
    108     @Override
    109     public Menu getMenu(Control parent) {
    110         mMenu = new Menu(parent);
    111 
    112         IconFactory iconFactory = IconFactory.getInstance();
    113         ImageDescriptor allIcon = iconFactory.getImageDescriptor("lintrun"); //$NON-NLS-1$
    114         LintMenuAction allAction = new LintMenuAction("Check All Projects", allIcon,
    115                 ACTION_RUN, null);
    116 
    117         addAction(allAction);
    118         addSeparator();
    119         IJavaProject[] projects = AdtUtils.getOpenAndroidProjects();
    120         ILabelProvider provider = new JavaElementLabelProvider(
    121                 JavaElementLabelProvider.SHOW_DEFAULT);
    122         for (IJavaProject project : projects) {
    123             IProject p = project.getProject();
    124             ImageDescriptor icon = ImageDescriptor.createFromImage(provider.getImage(p));
    125             String label = String.format("Check %1$s", p.getName());
    126             LintMenuAction projectAction = new LintMenuAction(label, icon, ACTION_RUN, p);
    127             addAction(projectAction);
    128         }
    129 
    130         ITextEditor textEditor = AdtUtils.getActiveTextEditor();
    131         if (textEditor != null) {
    132             IFile file = AdtUtils.getActiveFile();
    133             // Currently only supported for XML files
    134             if (file != null && LintUtils.endsWith(file.getName(), DOT_XML)) {
    135                 ImageDescriptor icon = ImageDescriptor.createFromImage(provider.getImage(file));
    136                 IAction fileAction = new LintMenuAction("Check Current File", icon, ACTION_RUN,
    137                         file);
    138 
    139                 addSeparator();
    140                 addAction(fileAction);
    141             }
    142         }
    143 
    144         ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
    145         ImageDescriptor clear = images.getImageDescriptor(ISharedImages.IMG_ELCL_REMOVEALL);
    146         LintMenuAction clearAction = new LintMenuAction("Clear Lint Warnings", clear, ACTION_CLEAR,
    147                 null);
    148         addSeparator();
    149         addAction(clearAction);
    150 
    151         LintMenuAction excludeAction = new LintMenuAction("Skip Library Project Dependencies",
    152                 allIcon, ACTION_TOGGLE_EXCLUDE, null);
    153         addSeparator();
    154         addAction(excludeAction);
    155         excludeAction.setChecked(AdtPrefs.getPrefs().getSkipLibrariesFromLint());
    156 
    157         return mMenu;
    158     }
    159 
    160     private void addAction(IAction action) {
    161         ActionContributionItem item = new ActionContributionItem(action);
    162         item.fill(mMenu, -1);
    163     }
    164 
    165     private void addSeparator() {
    166         new Separator().fill(mMenu, -1);
    167     }
    168 
    169     @Override
    170     public Menu getMenu(Menu parent) {
    171         return null;
    172     }
    173 
    174     private static final int ACTION_RUN = 1;
    175     private static final int ACTION_CLEAR = 2;
    176     private static final int ACTION_TOGGLE_EXCLUDE = 3;
    177 
    178     /**
    179      * Actions in the pulldown context menu: run lint or clear lint markers on
    180      * the given resource
    181      */
    182     private static class LintMenuAction extends Action {
    183         private final IResource mResource;
    184         private final int mAction;
    185 
    186         /**
    187          * Creates a new context menu action
    188          *
    189          * @param text the label
    190          * @param descriptor the icon
    191          * @param action the action to run: run lint, clear, or toggle exclude libraries
    192          * @param resource the resource to check or clear markers for, where
    193          *            null means all projects
    194          */
    195         private LintMenuAction(String text, ImageDescriptor descriptor, int action,
    196                 IResource resource) {
    197             super(text, action == ACTION_TOGGLE_EXCLUDE ? AS_CHECK_BOX : AS_PUSH_BUTTON);
    198             if (descriptor != null) {
    199                 setImageDescriptor(descriptor);
    200             }
    201             mAction = action;
    202             mResource = resource;
    203         }
    204 
    205         @Override
    206         public void run() {
    207             if (mAction == ACTION_TOGGLE_EXCLUDE) {
    208                 AdtPrefs prefs = AdtPrefs.getPrefs();
    209                 prefs.setSkipLibrariesFromLint(!prefs.getSkipLibrariesFromLint());
    210                 return;
    211             }
    212             List<IResource> resources = new ArrayList<IResource>();
    213             if (mResource == null) {
    214                 // All projects
    215                 IJavaProject[] open = AdtUtils.getOpenAndroidProjects();
    216                 for (IJavaProject project : open) {
    217                     resources.add(project.getProject());
    218                 }
    219             } else {
    220                 resources.add(mResource);
    221             }
    222             EclipseLintRunner.cancelCurrentJobs(false);
    223             if (mAction == ACTION_CLEAR) {
    224                 EclipseLintClient.clearMarkers(resources);
    225             } else {
    226                 assert mAction == ACTION_RUN;
    227                 EclipseLintRunner.startLint(resources, null, null, false /*fatalOnly*/,
    228                         true /*show*/);
    229             }
    230         }
    231     }
    232 }
    233