aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java752
1 files changed, 752 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java
new file mode 100644
index 000000000..5cb94ba4b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java
@@ -0,0 +1,752 @@
+/*
+ * 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.preferences;
+
+import static com.android.tools.lint.detector.api.TextFormat.RAW;
+import static com.android.tools.lint.detector.api.TextFormat.TEXT;
+
+import com.android.annotations.NonNull;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.AdtUtils;
+import com.android.ide.eclipse.adt.internal.lint.EclipseLintClient;
+import com.android.ide.eclipse.adt.internal.lint.EclipseLintRunner;
+import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
+import com.android.tools.lint.client.api.Configuration;
+import com.android.tools.lint.client.api.IssueRegistry;
+import com.android.tools.lint.detector.api.Category;
+import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.Project;
+import com.android.tools.lint.detector.api.Severity;
+import com.android.tools.lint.detector.api.TextFormat;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.TreeNodeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/** Preference page for configuring Lint preferences */
+public class LintPreferencePage extends PropertyPage implements IWorkbenchPreferencePage,
+ SelectionListener, ControlListener, ModifyListener {
+ private static final String ID =
+ "com.android.ide.eclipse.common.preferences.LintPreferencePage"; //$NON-NLS-1$
+ private static final int ID_COLUMN_WIDTH = 150;
+
+ private EclipseLintClient mClient;
+ private IssueRegistry mRegistry;
+ private Configuration mConfiguration;
+ private IProject mProject;
+ private Map<Issue, Severity> mSeverities = new HashMap<Issue, Severity>();
+ private Map<Issue, Severity> mInitialSeverities = Collections.<Issue, Severity>emptyMap();
+ private boolean mIgnoreEvent;
+
+ private Tree mTree;
+ private TreeViewer mTreeViewer;
+ private Text mDetailsText;
+ private Button mCheckFileCheckbox;
+ private Button mCheckExportCheckbox;
+ private Link mWorkspaceLink;
+ private TreeColumn mNameColumn;
+ private TreeColumn mIdColumn;
+ private Combo mSeverityCombo;
+ private Button mIncludeAll;
+ private Button mIgnoreAll;
+ private Text mSearch;
+
+ /**
+ * Create the preference page.
+ */
+ public LintPreferencePage() {
+ setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore());
+ }
+
+ @Override
+ public Control createContents(Composite parent) {
+ IAdaptable resource = getElement();
+ if (resource != null) {
+ mProject = (IProject) resource.getAdapter(IProject.class);
+ }
+
+ Composite container = new Composite(parent, SWT.NULL);
+ container.setLayout(new GridLayout(2, false));
+
+ if (mProject != null) {
+ Label projectLabel = new Label(container, SWT.CHECK);
+ projectLabel.setLayoutData(new GridData(SWT.LEFT, SWT.BOTTOM, false, false, 1,
+ 1));
+ projectLabel.setText("Project-specific configuration:");
+
+ mWorkspaceLink = new Link(container, SWT.NONE);
+ mWorkspaceLink.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ mWorkspaceLink.setText("<a>Configure Workspace Settings...</a>");
+ mWorkspaceLink.addSelectionListener(this);
+ } else {
+ mCheckFileCheckbox = new Button(container, SWT.CHECK);
+ mCheckFileCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
+ 2, 1));
+ mCheckFileCheckbox.setSelection(true);
+ mCheckFileCheckbox.setText("When saving files, check for errors");
+
+ mCheckExportCheckbox = new Button(container, SWT.CHECK);
+ mCheckExportCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
+ 2, 1));
+ mCheckExportCheckbox.setSelection(true);
+ mCheckExportCheckbox.setText("Run full error check when exporting app and abort if fatal errors are found");
+
+ Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL);
+ separator.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
+
+ Label checkListLabel = new Label(container, SWT.NONE);
+ checkListLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+ checkListLabel.setText("Issues:");
+ }
+
+ mRegistry = EclipseLintClient.getRegistry();
+ mClient = new EclipseLintClient(mRegistry,
+ mProject != null ? Collections.singletonList(mProject) : null, null, false);
+ Project project = null;
+ if (mProject != null) {
+ File dir = AdtUtils.getAbsolutePath(mProject).toFile();
+ project = mClient.getProject(dir, dir);
+ }
+ mConfiguration = mClient.getConfigurationFor(project);
+
+ mSearch = new Text(container, SWT.SEARCH | SWT.ICON_CANCEL | SWT.ICON_SEARCH);
+ mSearch.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ mSearch.addSelectionListener(this);
+ mSearch.addModifyListener(this);
+ // Grab the Enter key such that pressing return in the search box filters (instead
+ // of closing the options dialog)
+ mSearch.setMessage("type filter text (use ~ to filter by severity, e.g. ~ignore)");
+ mSearch.addTraverseListener(new TraverseListener() {
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if (e.keyCode == SWT.CR) {
+ updateFilter();
+ e.doit = false;
+ } else if (e.keyCode == SWT.ARROW_DOWN) {
+ // Allow moving from the search into the table
+ if (mTree.getItemCount() > 0) {
+ TreeItem firstCategory = mTree.getItem(0);
+ if (firstCategory.getItemCount() > 0) {
+ TreeItem first = firstCategory.getItem(0);
+ mTree.setFocus();
+ mTree.select(first);
+ }
+ }
+ }
+ }
+ });
+
+ mTreeViewer = new TreeViewer(container, SWT.BORDER | SWT.FULL_SELECTION);
+ mTree = mTreeViewer.getTree();
+ GridData gdTable = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1);
+ gdTable.widthHint = 500;
+ gdTable.heightHint = 160;
+ mTree.setLayoutData(gdTable);
+ mTree.setLinesVisible(true);
+ mTree.setHeaderVisible(true);
+
+ TreeViewerColumn column1 = new TreeViewerColumn(mTreeViewer, SWT.NONE);
+ mIdColumn = column1.getColumn();
+ mIdColumn.setWidth(100);
+ mIdColumn.setText("Id");
+
+ TreeViewerColumn column2 = new TreeViewerColumn(mTreeViewer, SWT.FILL);
+ mNameColumn = column2.getColumn();
+ mNameColumn.setWidth(100);
+ mNameColumn.setText("Name");
+
+ mTreeViewer.setContentProvider(new ContentProvider());
+ mTreeViewer.setLabelProvider(new LabelProvider());
+
+ mDetailsText = new Text(container, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP |SWT.V_SCROLL
+ | SWT.MULTI);
+ GridData gdText = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 2);
+ gdText.heightHint = 80;
+ mDetailsText.setLayoutData(gdText);
+
+ Label severityLabel = new Label(container, SWT.NONE);
+ severityLabel.setText("Severity:");
+
+ mSeverityCombo = new Combo(container, SWT.READ_ONLY);
+ mSeverityCombo.setItems(new String[] {
+ "(Default)", "Fatal", "Error", "Warning", "Information", "Ignore"
+ });
+ GridData gdSeverityCombo = new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1);
+ gdSeverityCombo.widthHint = 90;
+ mSeverityCombo.setLayoutData(gdSeverityCombo);
+ mSeverityCombo.setText("");
+ mSeverityCombo.addSelectionListener(this);
+
+ List<Issue> issues = mRegistry.getIssues();
+ for (Issue issue : issues) {
+ Severity severity = mConfiguration.getSeverity(issue);
+ mSeverities.put(issue, severity);
+ }
+ mInitialSeverities = new HashMap<Issue, Severity>(mSeverities);
+
+ mTreeViewer.setInput(mRegistry);
+
+ mTree.addSelectionListener(this);
+ // Add a listener to resize the column to the full width of the table
+ mTree.addControlListener(this);
+
+ loadSettings(false);
+
+ mTreeViewer.expandAll();
+
+ return container;
+ }
+
+ /**
+ * Initialize the preference page.
+ */
+ @Override
+ public void init(IWorkbench workbench) {
+ // Initialize the preference page
+ }
+
+ @Override
+ protected void contributeButtons(Composite parent) {
+ super.contributeButtons(parent);
+
+ // Add "Include All" button for quickly enabling all the detectors, including
+ // those disabled by default
+ mIncludeAll = new Button(parent, SWT.PUSH);
+ mIncludeAll.setText("Include All");
+ mIncludeAll.addSelectionListener(this);
+
+ // Add "Ignore All" button for quickly disabling all the detectors
+ mIgnoreAll = new Button(parent, SWT.PUSH);
+ mIgnoreAll.setText("Ignore All");
+ mIgnoreAll.addSelectionListener(this);
+
+ // As per the contributeButton javadoc: increase parent's column count for each
+ // added button
+ ((GridLayout) parent.getLayout()).numColumns += 2;
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ cancelPendingSearch();
+ }
+
+ @Override
+ protected void performDefaults() {
+ super.performDefaults();
+
+ mConfiguration.startBulkEditing();
+
+ List<Issue> issues = mRegistry.getIssues();
+ for (Issue issue : issues) {
+ mConfiguration.setSeverity(issue, null);
+ }
+
+ mConfiguration.finishBulkEditing();
+
+ loadSettings(true);
+ }
+
+ @Override
+ public boolean performOk() {
+ storeSettings();
+ return true;
+ }
+
+ private void loadSettings(boolean refresh) {
+ if (mCheckExportCheckbox != null) {
+ AdtPrefs prefs = AdtPrefs.getPrefs();
+ mCheckFileCheckbox.setSelection(prefs.isLintOnSave());
+ mCheckExportCheckbox.setSelection(prefs.isLintOnExport());
+ }
+
+ mSeverities.clear();
+ List<Issue> issues = mRegistry.getIssues();
+ for (Issue issue : issues) {
+ Severity severity = mConfiguration.getSeverity(issue);
+ mSeverities.put(issue, severity);
+ }
+
+ if (refresh) {
+ mTreeViewer.refresh();
+ }
+ }
+
+ private void storeSettings() {
+ // Lint on Save, Lint on Export
+ if (mCheckExportCheckbox != null) {
+ AdtPrefs prefs = AdtPrefs.getPrefs();
+ prefs.setLintOnExport(mCheckExportCheckbox.getSelection());
+ prefs.setLintOnSave(mCheckFileCheckbox.getSelection());
+ }
+
+ if (mConfiguration == null) {
+ return;
+ }
+
+ mConfiguration.startBulkEditing();
+ try {
+ // Severities
+ for (Map.Entry<Issue, Severity> entry : mSeverities.entrySet()) {
+ Issue issue = entry.getKey();
+ Severity severity = entry.getValue();
+ if (mConfiguration.getSeverity(issue) != severity) {
+ if ((severity == issue.getDefaultSeverity()) && issue.isEnabledByDefault()) {
+ severity = null;
+ }
+ mConfiguration.setSeverity(issue, severity);
+ }
+ }
+ } finally {
+ mConfiguration.finishBulkEditing();
+ }
+
+ if (!mInitialSeverities.equals(mSeverities)) {
+ // Ask user whether we should re-run the rules.
+ MessageDialog dialog = new MessageDialog(
+ null, "Lint Settings Have Changed", null,
+ "The list of enabled checks has changed. Would you like to run lint now " +
+ "to update the results?",
+ MessageDialog.QUESTION,
+ new String[] {
+ "Yes", "No"
+ },
+ 0); // yes is the default
+ int result = dialog.open();
+ if (result == 0) {
+ // Run lint on all the open Android projects
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IProject[] projects = workspace.getRoot().getProjects();
+ List<IProject> androidProjects = new ArrayList<IProject>(projects.length);
+ for (IProject project : projects) {
+ if (project.isOpen() && BaseProjectHelper.isAndroidProject(project)) {
+ androidProjects.add(project);
+ }
+ }
+
+ EclipseLintRunner.startLint(androidProjects, null, null, false /*fatalOnly*/,
+ true /*show*/);
+ }
+ }
+ }
+
+ private void updateFilter() {
+ cancelPendingSearch();
+ if (!mSearch.isDisposed()) {
+ // Clear selection before refiltering since otherwise it might be showing
+ // items no longer available in the list.
+ mTree.setSelection(new TreeItem[0]);
+ mDetailsText.setText("");
+ try {
+ mIgnoreEvent = true;
+ mSeverityCombo.setText("");
+ mSeverityCombo.setEnabled(false);
+ } finally {
+ mIgnoreEvent = false;
+ }
+
+ mTreeViewer.getContentProvider().inputChanged(mTreeViewer, null, mRegistry);
+ mTreeViewer.refresh();
+ mTreeViewer.expandAll();
+ }
+ }
+
+ private void cancelPendingSearch() {
+ if (mPendingUpdate != null) {
+ Shell shell = getShell();
+ if (!shell.isDisposed()) {
+ getShell().getDisplay().timerExec(-1, mPendingUpdate);
+ }
+ mPendingUpdate = null;
+ }
+ }
+
+ private Runnable mPendingUpdate;
+
+ private void scheduleSearch() {
+ if (mPendingUpdate == null) {
+ mPendingUpdate = new Runnable() {
+ @Override
+ public void run() {
+ mPendingUpdate = null;
+ updateFilter();
+ }
+ };
+ }
+ getShell().getDisplay().timerExec(250 /*ms*/, mPendingUpdate);
+ }
+
+ // ---- Implements SelectionListener ----
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (mIgnoreEvent) {
+ return;
+ }
+
+ Object source = e.getSource();
+ if (source == mTree) {
+ TreeItem item = (TreeItem) e.item;
+ Object data = item != null ? item.getData() : null;
+ if (data instanceof Issue) {
+ Issue issue = (Issue) data;
+ String summary = issue.getBriefDescription(TextFormat.TEXT);
+ String explanation = issue.getExplanation(TextFormat.TEXT);
+
+ StringBuilder sb = new StringBuilder(summary.length() + explanation.length() + 20);
+ sb.append(summary);
+ sb.append('\n').append('\n');
+ sb.append(explanation);
+ mDetailsText.setText(sb.toString());
+ try {
+ mIgnoreEvent = true;
+ Severity severity = getSeverity(issue);
+ mSeverityCombo.select(severity.ordinal() + 1); // Skip the default option
+ mSeverityCombo.setEnabled(true);
+ } finally {
+ mIgnoreEvent = false;
+ }
+ } else {
+ mDetailsText.setText("");
+ try {
+ mIgnoreEvent = true;
+ mSeverityCombo.setText("");
+ mSeverityCombo.setEnabled(false);
+ } finally {
+ mIgnoreEvent = false;
+ }
+ }
+ } else if (source == mWorkspaceLink) {
+ int result = PreferencesUtil.createPreferenceDialogOn(getShell(), ID,
+ new String[] { ID }, null).open();
+ if (result == Window.OK) {
+ loadSettings(true);
+ }
+ } else if (source == mSeverityCombo) {
+ int index = mSeverityCombo.getSelectionIndex();
+ Issue issue = (Issue) mTree.getSelection()[0].getData();
+ Severity severity;
+ if (index == -1 || index == 0) {
+ // "(Default)"
+ severity = issue.getDefaultSeverity();
+ } else {
+ // -1: Skip the "(Default)"
+ severity = Severity.values()[index - 1];
+ }
+ mSeverities.put(issue, severity);
+ mTreeViewer.refresh();
+ } else if (source == mIncludeAll) {
+ List<Issue> issues = mRegistry.getIssues();
+ for (Issue issue : issues) {
+ // The default severity is never ignore; for disabled-by-default
+ // issues the {@link Issue#isEnabledByDefault()} method is false instead
+ mSeverities.put(issue, issue.getDefaultSeverity());
+ }
+ mTreeViewer.refresh();
+ } else if (source == mIgnoreAll) {
+ List<Issue> issues = mRegistry.getIssues();
+ for (Issue issue : issues) {
+ mSeverities.put(issue, Severity.IGNORE);
+ }
+ mTreeViewer.refresh();
+ } else if (source == mSearch) {
+ updateFilter();
+ }
+ }
+
+ private Severity getSeverity(Issue issue) {
+ Severity severity = mSeverities.get(issue);
+ if (severity != null) {
+ return severity;
+ }
+
+ return mConfiguration.getSeverity(issue);
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ Object source = e.getSource();
+ if (source == mTree) {
+ widgetSelected(e);
+ } else if (source == mSearch) {
+ if (e.detail == SWT.CANCEL) {
+ // Cancel the search
+ mSearch.setText("");
+ }
+ updateFilter();
+ }
+ }
+
+ // ---- Implements ModifyListener ----
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if (e.getSource() == mSearch) {
+ scheduleSearch();
+ }
+ }
+
+ // ---- Implements ControlListener ----
+
+ @Override
+ public void controlMoved(ControlEvent e) {
+ }
+
+ @Override
+ public void controlResized(ControlEvent e) {
+ Rectangle r = mTree.getClientArea();
+ int availableWidth = r.width;
+
+ mIdColumn.setWidth(ID_COLUMN_WIDTH);
+ availableWidth -= ID_COLUMN_WIDTH;
+
+ // Name absorbs everything else
+ mNameColumn.setWidth(availableWidth);
+ }
+
+ private boolean filterMatches(@NonNull String filter, @NonNull Issue issue) {
+ return (filter.startsWith("~") //$NON-NLS-1$
+ && mConfiguration.getSeverity(issue).getDescription()
+ .toLowerCase(Locale.US).startsWith(filter.substring(1)))
+ || issue.getCategory().getName().toLowerCase(Locale.US).startsWith(filter)
+ || issue.getCategory().getFullName().toLowerCase(Locale.US).startsWith(filter)
+ || issue.getId().toLowerCase(Locale.US).contains(filter)
+ || issue.getBriefDescription(RAW).toLowerCase(Locale.US).contains(filter);
+ }
+
+ private class ContentProvider extends TreeNodeContentProvider {
+ private Map<Category, List<Issue>> mCategoryToIssues;
+ private Object[] mElements;
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ return mElements;
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ return element instanceof Category;
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ assert mCategoryToIssues != null;
+ List<Issue> list = mCategoryToIssues.get(parentElement);
+ if (list == null) {
+ return new Object[0];
+ } else {
+ return list.toArray();
+ }
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ return null;
+ }
+
+ @Override
+ public void inputChanged(final Viewer viewer, final Object oldInput,
+ final Object newInput) {
+ mCategoryToIssues = null;
+
+ String filter = mSearch.isDisposed() ? "" : mSearch.getText().trim();
+ if (filter.length() == 0) {
+ filter = null;
+ } else {
+ filter = filter.toLowerCase(Locale.US);
+ }
+
+ mCategoryToIssues = new HashMap<Category, List<Issue>>();
+ List<Issue> issues = mRegistry.getIssues();
+ for (Issue issue : issues) {
+ if (filter == null || filterMatches(filter, issue)) {
+ List<Issue> list = mCategoryToIssues.get(issue.getCategory());
+ if (list == null) {
+ list = new ArrayList<Issue>();
+ mCategoryToIssues.put(issue.getCategory(), list);
+ }
+ list.add(issue);
+ }
+ }
+
+ if (filter == null) {
+ // Not filtering: show all categories
+ mElements = mRegistry.getCategories().toArray();
+ } else {
+ // Filtering: only include categories that contain matches
+ if (mCategoryToIssues == null) {
+ getChildren(null);
+ }
+
+ // Preserve the current category order, so instead of
+ // just creating a list of the mCategoryToIssues keyset, add them
+ // in the order they appear in in the registry
+ List<Category> categories = new ArrayList<Category>(mCategoryToIssues.size());
+ for (Category category : mRegistry.getCategories()) {
+ if (mCategoryToIssues.containsKey(category)) {
+ categories.add(category);
+ }
+ }
+ mElements = categories.toArray();
+ }
+ }
+ }
+
+ private class LabelProvider implements ITableLabelProvider, IColorProvider {
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ return true;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ if (element instanceof Category) {
+ return null;
+ }
+
+ if (columnIndex == 1) {
+ Issue issue = (Issue) element;
+ Severity severity = mSeverities.get(issue);
+ if (severity == null) {
+ return null;
+ }
+
+ ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
+ switch (severity) {
+ case FATAL:
+ case ERROR:
+ return sharedImages.getImage(ISharedImages.IMG_OBJS_ERROR_TSK);
+ case WARNING:
+ return sharedImages.getImage(ISharedImages.IMG_OBJS_WARN_TSK);
+ case INFORMATIONAL:
+ return sharedImages.getImage(ISharedImages.IMG_OBJS_INFO_TSK);
+ case IGNORE:
+ return sharedImages.getImage(ISharedImages.IMG_ELCL_REMOVE_DISABLED);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (element instanceof Category) {
+ if (columnIndex == 0) {
+ return ((Category) element).getFullName();
+ } else {
+ return null;
+ }
+ }
+
+ Issue issue = (Issue) element;
+ switch (columnIndex) {
+ case 0:
+ return issue.getId();
+ case 1:
+ return issue.getBriefDescription(TEXT);
+ }
+
+ return null;
+ }
+
+ // ---- IColorProvider ----
+
+ @Override
+ public Color getForeground(Object element) {
+ if (element instanceof Category) {
+ return mTree.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND);
+ }
+
+ if (element instanceof Issue) {
+ Issue issue = (Issue) element;
+ Severity severity = mSeverities.get(issue);
+ if (severity == Severity.IGNORE) {
+ return mTree.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Color getBackground(Object element) {
+ if (element instanceof Category) {
+ return mTree.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
+ }
+ return null;
+ }
+ }
+}