/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.eclipse.org/org/documents/epl-v10.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ide.eclipse.adt.internal.lint; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtUtils; import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; import com.android.ide.eclipse.adt.internal.editors.IconFactory; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.TitleAreaDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PlatformUI; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @SuppressWarnings("restriction") // WST DOM access class LintListDialog extends TitleAreaDialog implements SelectionListener { private static final String PROJECT_LOGO_LARGE = "android-64"; //$NON-NLS-1$ private final IFile mFile; private final IEditorPart mEditor; private Button mFixButton; private Button mIgnoreButton; private Button mIgnoreAllButton; private Button mShowButton; private Text mDetailsText; private Button mIgnoreTypeButton; private LintList mList; LintListDialog( @NonNull Shell parentShell, @NonNull IFile file, @Nullable IEditorPart editor) { super(parentShell); mFile = file; mEditor = editor; setHelpAvailable(false); } @Override protected void setShellStyle(int newShellStyle) { // Allow resize super.setShellStyle(newShellStyle | SWT.TITLE | SWT.MODELESS | SWT.RESIZE); } @Override public boolean close() { mList.dispose(); return super.close(); } @Override protected Control createContents(Composite parent) { Control contents = super.createContents(parent); setTitle("Lint Warnings in Layout"); setMessage("Lint Errors found for the current layout:"); setTitleImage(IconFactory.getInstance().getIcon(PROJECT_LOGO_LARGE)); return contents; } @SuppressWarnings("unused") // SWT constructors have side effects, they are not unused @Override protected Control createDialogArea(Composite parent) { Composite area = (Composite) super.createDialogArea(parent); Composite container = new Composite(area, SWT.NONE); container.setLayoutData(new GridData(GridData.FILL_BOTH)); container.setLayout(new GridLayout(2, false)); IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); IWorkbenchPartSite site = null; if (page.getActivePart() != null) { site = page.getActivePart().getSite(); } mList = new LintList(site, container, null /*memento*/, true /*singleFile*/); mList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 6)); mShowButton = new Button(container, SWT.NONE); mShowButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); mShowButton.setText("Show"); mShowButton.setToolTipText("Opens the editor to reveal the XML with the issue"); mShowButton.addSelectionListener(this); mFixButton = new Button(container, SWT.NONE); mFixButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); mFixButton.setText("Fix"); mFixButton.setToolTipText("Automatically corrects the problem, if possible"); mFixButton.setEnabled(false); mFixButton.addSelectionListener(this); mIgnoreButton = new Button(container, SWT.NONE); mIgnoreButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); mIgnoreButton.setText("Suppress Issue"); mIgnoreButton.setToolTipText("Adds a special attribute in the layout to suppress this specific warning"); mIgnoreButton.addSelectionListener(this); mIgnoreAllButton = new Button(container, SWT.NONE); mIgnoreAllButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); mIgnoreAllButton.setText("Suppress in Layout"); mIgnoreAllButton.setEnabled(mEditor instanceof AndroidXmlEditor); mIgnoreAllButton.setToolTipText("Adds an attribute on the root element to suppress all issues of this type in this layout"); mIgnoreAllButton.addSelectionListener(this); mIgnoreTypeButton = new Button(container, SWT.NONE); mIgnoreTypeButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); mIgnoreTypeButton.setText("Disable Issue Type"); mIgnoreTypeButton.setToolTipText("Turns off checking for this type of error everywhere"); mIgnoreTypeButton.addSelectionListener(this); new Label(container, SWT.NONE); mDetailsText = new Text(container, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI); Display display = parent.getDisplay(); mDetailsText.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); mDetailsText.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); GridData gdText = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1); gdText.heightHint = 80; mDetailsText.setLayoutData(gdText); new Label(container, SWT.NONE); mList.addSelectionListener(this); mList.setResources(Collections.<IResource>singletonList(mFile)); mList.selectFirst(); if (mList.getSelectedMarkers().size() > 0) { updateSelectionState(); } return area; } /** * Create contents of the button bar. */ @Override protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); } /** * Return the initial size of the dialog. */ @Override protected Point getInitialSize() { return new Point(600, 400); } private void selectMarker(IMarker marker) { if (marker == null) { mDetailsText.setText(""); //$NON-NLS-1$ return; } mDetailsText.setText(EclipseLintClient.describe(marker)); } // ---- Implements SelectionListener ---- @Override public void widgetSelected(SelectionEvent e) { Object source = e.getSource(); if (source == mList.getTreeViewer().getControl()) { // Enable/disable buttons updateSelectionState(); } else if (source == mShowButton) { List<IMarker> selection = mList.getSelectedMarkers(); if (selection.size() > 0) { EclipseLintClient.showMarker(selection.get(0)); } } else if (source == mFixButton) { List<IMarker> selection = mList.getSelectedMarkers(); for (IMarker marker : selection) { List<LintFix> fixes = LintFix.getFixes(EclipseLintClient.getId(marker), marker); if (fixes == null) { continue; } LintFix fix = fixes.get(0); IEditorPart editor = AdtUtils.getActiveEditor(); if (editor instanceof AndroidXmlEditor) { IStructuredDocument doc = ((AndroidXmlEditor) editor).getStructuredDocument(); fix.apply(doc); if (fix.needsFocus()) { close(); } } else { AdtPlugin.log(IStatus.ERROR, "Did not find associated editor to apply fix"); } } } else if (source == mIgnoreTypeButton) { for (IMarker marker : mList.getSelectedMarkers()) { String id = EclipseLintClient.getId(marker); if (id != null) { LintFixGenerator.suppressDetector(id, true, mFile, true /*all*/); } } } else if (source == mIgnoreButton) { for (IMarker marker : mList.getSelectedMarkers()) { LintFixGenerator.addSuppressAnnotation(marker); } } else if (source == mIgnoreAllButton) { Set<String> ids = new HashSet<String>(); for (IMarker marker : mList.getSelectedMarkers()) { String id = EclipseLintClient.getId(marker); if (id != null && !ids.contains(id)) { ids.add(id); if (mEditor instanceof AndroidXmlEditor) { AndroidXmlEditor editor = (AndroidXmlEditor) mEditor; AddSuppressAttribute fix = AddSuppressAttribute.createFixForAll(editor, marker, id); if (fix != null) { IStructuredDocument document = editor.getStructuredDocument(); fix.apply(document); } } } } mList.refresh(); } } private void updateSelectionState() { List<IMarker> selection = mList.getSelectedMarkers(); if (selection.size() == 1) { selectMarker(selection.get(0)); } else { selectMarker(null); } boolean canFix = selection.size() > 0; for (IMarker marker : selection) { if (!LintFix.hasFix(EclipseLintClient.getId(marker))) { canFix = false; break; } // Some fixes cannot be run in bulk if (selection.size() > 1) { List<LintFix> fixes = LintFix.getFixes(EclipseLintClient.getId(marker), marker); if (fixes == null || !fixes.get(0).isBulkCapable()) { canFix = false; break; } } } mFixButton.setEnabled(canFix); } @Override public void widgetDefaultSelected(SelectionEvent e) { Object source = e.getSource(); if (source == mList.getTreeViewer().getControl()) { // Jump to editor List<IMarker> selection = mList.getSelectedMarkers(); if (selection.size() > 0) { EclipseLintClient.showMarker(selection.get(0)); close(); } } } }