• 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 package com.android.ide.eclipse.adt.internal.lint;
17 
18 import com.android.annotations.NonNull;
19 import com.android.annotations.Nullable;
20 import com.android.ide.eclipse.adt.AdtPlugin;
21 import com.android.ide.eclipse.adt.AdtUtils;
22 import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
23 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
24 
25 import org.eclipse.core.resources.IFile;
26 import org.eclipse.core.resources.IMarker;
27 import org.eclipse.core.resources.IResource;
28 import org.eclipse.core.runtime.IStatus;
29 import org.eclipse.jface.dialogs.IDialogConstants;
30 import org.eclipse.jface.dialogs.TitleAreaDialog;
31 import org.eclipse.swt.SWT;
32 import org.eclipse.swt.events.SelectionEvent;
33 import org.eclipse.swt.events.SelectionListener;
34 import org.eclipse.swt.graphics.Point;
35 import org.eclipse.swt.layout.GridData;
36 import org.eclipse.swt.layout.GridLayout;
37 import org.eclipse.swt.widgets.Button;
38 import org.eclipse.swt.widgets.Composite;
39 import org.eclipse.swt.widgets.Control;
40 import org.eclipse.swt.widgets.Display;
41 import org.eclipse.swt.widgets.Label;
42 import org.eclipse.swt.widgets.Shell;
43 import org.eclipse.swt.widgets.Text;
44 import org.eclipse.ui.IEditorPart;
45 import org.eclipse.ui.IWorkbenchPage;
46 import org.eclipse.ui.IWorkbenchPartSite;
47 import org.eclipse.ui.PlatformUI;
48 import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
49 
50 import java.util.Collections;
51 import java.util.HashSet;
52 import java.util.List;
53 import java.util.Set;
54 
55 @SuppressWarnings("restriction") // WST DOM access
56 class LintListDialog extends TitleAreaDialog implements SelectionListener {
57     private static final String PROJECT_LOGO_LARGE = "android-64"; //$NON-NLS-1$
58     private final IFile mFile;
59     private final IEditorPart mEditor;
60     private Button mFixButton;
61     private Button mIgnoreButton;
62     private Button mIgnoreAllButton;
63     private Button mShowButton;
64     private Text mDetailsText;
65     private Button mIgnoreTypeButton;
66     private LintList mList;
67 
LintListDialog( @onNull Shell parentShell, @NonNull IFile file, @Nullable IEditorPart editor)68     LintListDialog(
69             @NonNull Shell parentShell,
70             @NonNull IFile file,
71             @Nullable IEditorPart editor) {
72         super(parentShell);
73         mFile = file;
74         mEditor = editor;
75         setHelpAvailable(false);
76     }
77 
78     @Override
setShellStyle(int newShellStyle)79     protected void setShellStyle(int newShellStyle) {
80         // Allow resize
81         super.setShellStyle(newShellStyle | SWT.TITLE | SWT.MODELESS | SWT.RESIZE);
82     }
83 
84     @Override
close()85     public boolean close() {
86         mList.dispose();
87         return super.close();
88     }
89 
90     @Override
createContents(Composite parent)91     protected Control createContents(Composite parent) {
92       Control contents = super.createContents(parent);
93       setTitle("Lint Warnings in Layout");
94       setMessage("Lint Errors found for the current layout:");
95       setTitleImage(IconFactory.getInstance().getIcon(PROJECT_LOGO_LARGE));
96 
97       return contents;
98     }
99 
100     @SuppressWarnings("unused") // SWT constructors have side effects, they are not unused
101     @Override
createDialogArea(Composite parent)102     protected Control createDialogArea(Composite parent) {
103         Composite area = (Composite) super.createDialogArea(parent);
104         Composite container = new Composite(area, SWT.NONE);
105         container.setLayoutData(new GridData(GridData.FILL_BOTH));
106 
107         container.setLayout(new GridLayout(2, false));
108         IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
109         IWorkbenchPartSite site = null;
110         if (page.getActivePart() != null) {
111             site = page.getActivePart().getSite();
112         }
113 
114         mList = new LintList(site, container, null /*memento*/, true /*singleFile*/);
115         mList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 6));
116 
117         mShowButton = new Button(container, SWT.NONE);
118         mShowButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
119         mShowButton.setText("Show");
120         mShowButton.setToolTipText("Opens the editor to reveal the XML with the issue");
121         mShowButton.addSelectionListener(this);
122 
123         mFixButton = new Button(container, SWT.NONE);
124         mFixButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
125         mFixButton.setText("Fix");
126         mFixButton.setToolTipText("Automatically corrects the problem, if possible");
127         mFixButton.setEnabled(false);
128         mFixButton.addSelectionListener(this);
129 
130         mIgnoreButton = new Button(container, SWT.NONE);
131         mIgnoreButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
132         mIgnoreButton.setText("Suppress Issue");
133         mIgnoreButton.setToolTipText("Adds a special attribute in the layout to suppress this specific warning");
134         mIgnoreButton.addSelectionListener(this);
135 
136         mIgnoreAllButton = new Button(container, SWT.NONE);
137         mIgnoreAllButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
138         mIgnoreAllButton.setText("Suppress in Layout");
139         mIgnoreAllButton.setEnabled(mEditor instanceof AndroidXmlEditor);
140         mIgnoreAllButton.setToolTipText("Adds an attribute on the root element to suppress all issues of this type in this layout");
141         mIgnoreAllButton.addSelectionListener(this);
142 
143         mIgnoreTypeButton = new Button(container, SWT.NONE);
144         mIgnoreTypeButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
145         mIgnoreTypeButton.setText("Disable Issue Type");
146         mIgnoreTypeButton.setToolTipText("Turns off checking for this type of error everywhere");
147         mIgnoreTypeButton.addSelectionListener(this);
148 
149         new Label(container, SWT.NONE);
150 
151         mDetailsText = new Text(container, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP
152                 | SWT.V_SCROLL | SWT.MULTI);
153         Display display = parent.getDisplay();
154         mDetailsText.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
155         mDetailsText.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
156         GridData gdText = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
157         gdText.heightHint = 80;
158         mDetailsText.setLayoutData(gdText);
159 
160         new Label(container, SWT.NONE);
161 
162         mList.addSelectionListener(this);
163 
164         mList.setResources(Collections.<IResource>singletonList(mFile));
165         mList.selectFirst();
166         if (mList.getSelectedMarkers().size() > 0) {
167             updateSelectionState();
168         }
169 
170         return area;
171     }
172 
173     /**
174      * Create contents of the button bar.
175      */
176     @Override
createButtonsForButtonBar(Composite parent)177     protected void createButtonsForButtonBar(Composite parent) {
178         createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
179     }
180 
181     /**
182      * Return the initial size of the dialog.
183      */
184     @Override
getInitialSize()185     protected Point getInitialSize() {
186         return new Point(600, 400);
187     }
188 
selectMarker(IMarker marker)189     private void selectMarker(IMarker marker) {
190         if (marker == null) {
191             mDetailsText.setText(""); //$NON-NLS-1$
192             return;
193         }
194 
195         mDetailsText.setText(EclipseLintClient.describe(marker));
196     }
197 
198     // ---- Implements SelectionListener ----
199 
200     @Override
widgetSelected(SelectionEvent e)201     public void widgetSelected(SelectionEvent e) {
202         Object source = e.getSource();
203         if (source == mList.getTreeViewer().getControl()) {
204             // Enable/disable buttons
205             updateSelectionState();
206         } else if (source == mShowButton) {
207             List<IMarker> selection = mList.getSelectedMarkers();
208             if (selection.size() > 0) {
209                 EclipseLintClient.showMarker(selection.get(0));
210             }
211         } else if (source == mFixButton) {
212             List<IMarker> selection = mList.getSelectedMarkers();
213             for (IMarker marker : selection) {
214                 List<LintFix> fixes = LintFix.getFixes(EclipseLintClient.getId(marker), marker);
215                 if (fixes == null) {
216                     continue;
217                 }
218                 LintFix fix = fixes.get(0);
219                 IEditorPart editor = AdtUtils.getActiveEditor();
220                 if (editor instanceof AndroidXmlEditor) {
221                     IStructuredDocument doc = ((AndroidXmlEditor) editor).getStructuredDocument();
222                     fix.apply(doc);
223                     if (fix.needsFocus()) {
224                         close();
225                     }
226                 } else {
227                     AdtPlugin.log(IStatus.ERROR, "Did not find associated editor to apply fix");
228                 }
229             }
230         } else if (source == mIgnoreTypeButton) {
231             for (IMarker marker : mList.getSelectedMarkers()) {
232                 String id = EclipseLintClient.getId(marker);
233                 if (id != null) {
234                     LintFixGenerator.suppressDetector(id, true, mFile, true /*all*/);
235                 }
236             }
237         } else if (source == mIgnoreButton) {
238             for (IMarker marker : mList.getSelectedMarkers()) {
239                 LintFixGenerator.addSuppressAnnotation(marker);
240             }
241         } else if (source == mIgnoreAllButton) {
242             Set<String> ids = new HashSet<String>();
243             for (IMarker marker : mList.getSelectedMarkers()) {
244                 String id = EclipseLintClient.getId(marker);
245                 if (id != null && !ids.contains(id)) {
246                     ids.add(id);
247                     if (mEditor instanceof AndroidXmlEditor) {
248                         AndroidXmlEditor editor = (AndroidXmlEditor) mEditor;
249                         AddSuppressAttribute fix = AddSuppressAttribute.createFixForAll(editor,
250                                 marker, id);
251                         if (fix != null) {
252                             IStructuredDocument document = editor.getStructuredDocument();
253                             fix.apply(document);
254                         }
255                     }
256                 }
257             }
258             mList.refresh();
259         }
260     }
261 
updateSelectionState()262     private void updateSelectionState() {
263         List<IMarker> selection = mList.getSelectedMarkers();
264 
265         if (selection.size() == 1) {
266             selectMarker(selection.get(0));
267         } else {
268             selectMarker(null);
269         }
270 
271         boolean canFix = selection.size() > 0;
272         for (IMarker marker : selection) {
273             if (!LintFix.hasFix(EclipseLintClient.getId(marker))) {
274                 canFix = false;
275                 break;
276             }
277 
278             // Some fixes cannot be run in bulk
279             if (selection.size() > 1) {
280                 List<LintFix> fixes = LintFix.getFixes(EclipseLintClient.getId(marker), marker);
281                 if (fixes == null || !fixes.get(0).isBulkCapable()) {
282                     canFix = false;
283                     break;
284                 }
285             }
286         }
287 
288         mFixButton.setEnabled(canFix);
289     }
290 
291     @Override
widgetDefaultSelected(SelectionEvent e)292     public void widgetDefaultSelected(SelectionEvent e) {
293         Object source = e.getSource();
294         if (source == mList.getTreeViewer().getControl()) {
295             // Jump to editor
296             List<IMarker> selection = mList.getSelectedMarkers();
297             if (selection.size() > 0) {
298                 EclipseLintClient.showMarker(selection.get(0));
299                 close();
300             }
301         }
302     }
303 }
304