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.preferences; 17 18 import com.android.annotations.NonNull; 19 import com.android.ide.eclipse.adt.AdtPlugin; 20 import com.android.ide.eclipse.adt.AdtUtils; 21 import com.android.ide.eclipse.adt.internal.lint.EclipseLintClient; 22 import com.android.ide.eclipse.adt.internal.lint.EclipseLintRunner; 23 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; 24 import com.android.tools.lint.client.api.Configuration; 25 import com.android.tools.lint.client.api.IssueRegistry; 26 import com.android.tools.lint.detector.api.Category; 27 import com.android.tools.lint.detector.api.Issue; 28 import com.android.tools.lint.detector.api.Project; 29 import com.android.tools.lint.detector.api.Severity; 30 31 import org.eclipse.core.resources.IProject; 32 import org.eclipse.core.resources.IWorkspace; 33 import org.eclipse.core.resources.ResourcesPlugin; 34 import org.eclipse.core.runtime.IAdaptable; 35 import org.eclipse.jface.dialogs.MessageDialog; 36 import org.eclipse.jface.viewers.IColorProvider; 37 import org.eclipse.jface.viewers.ILabelProviderListener; 38 import org.eclipse.jface.viewers.ITableLabelProvider; 39 import org.eclipse.jface.viewers.TreeNodeContentProvider; 40 import org.eclipse.jface.viewers.TreeViewer; 41 import org.eclipse.jface.viewers.TreeViewerColumn; 42 import org.eclipse.jface.viewers.Viewer; 43 import org.eclipse.jface.window.Window; 44 import org.eclipse.swt.SWT; 45 import org.eclipse.swt.events.ControlEvent; 46 import org.eclipse.swt.events.ControlListener; 47 import org.eclipse.swt.events.ModifyEvent; 48 import org.eclipse.swt.events.ModifyListener; 49 import org.eclipse.swt.events.SelectionEvent; 50 import org.eclipse.swt.events.SelectionListener; 51 import org.eclipse.swt.events.TraverseEvent; 52 import org.eclipse.swt.events.TraverseListener; 53 import org.eclipse.swt.graphics.Color; 54 import org.eclipse.swt.graphics.Image; 55 import org.eclipse.swt.graphics.Rectangle; 56 import org.eclipse.swt.layout.GridData; 57 import org.eclipse.swt.layout.GridLayout; 58 import org.eclipse.swt.widgets.Button; 59 import org.eclipse.swt.widgets.Combo; 60 import org.eclipse.swt.widgets.Composite; 61 import org.eclipse.swt.widgets.Control; 62 import org.eclipse.swt.widgets.Label; 63 import org.eclipse.swt.widgets.Link; 64 import org.eclipse.swt.widgets.Shell; 65 import org.eclipse.swt.widgets.Text; 66 import org.eclipse.swt.widgets.Tree; 67 import org.eclipse.swt.widgets.TreeColumn; 68 import org.eclipse.swt.widgets.TreeItem; 69 import org.eclipse.ui.ISharedImages; 70 import org.eclipse.ui.IWorkbench; 71 import org.eclipse.ui.IWorkbenchPreferencePage; 72 import org.eclipse.ui.PlatformUI; 73 import org.eclipse.ui.dialogs.PreferencesUtil; 74 import org.eclipse.ui.dialogs.PropertyPage; 75 76 import java.io.File; 77 import java.util.ArrayList; 78 import java.util.Collections; 79 import java.util.HashMap; 80 import java.util.List; 81 import java.util.Locale; 82 import java.util.Map; 83 84 /** Preference page for configuring Lint preferences */ 85 public class LintPreferencePage extends PropertyPage implements IWorkbenchPreferencePage, 86 SelectionListener, ControlListener, ModifyListener { 87 private static final String ID = 88 "com.android.ide.eclipse.common.preferences.LintPreferencePage"; //$NON-NLS-1$ 89 private static final int ID_COLUMN_WIDTH = 150; 90 91 private EclipseLintClient mClient; 92 private IssueRegistry mRegistry; 93 private Configuration mConfiguration; 94 private IProject mProject; 95 private Map<Issue, Severity> mSeverities = new HashMap<Issue, Severity>(); 96 private Map<Issue, Severity> mInitialSeverities = Collections.<Issue, Severity>emptyMap(); 97 private boolean mIgnoreEvent; 98 99 private Tree mTree; 100 private TreeViewer mTreeViewer; 101 private Text mDetailsText; 102 private Button mCheckFileCheckbox; 103 private Button mCheckExportCheckbox; 104 private Link mWorkspaceLink; 105 private TreeColumn mNameColumn; 106 private TreeColumn mIdColumn; 107 private Combo mSeverityCombo; 108 private Button mIncludeAll; 109 private Button mIgnoreAll; 110 private Text mSearch; 111 112 /** 113 * Create the preference page. 114 */ 115 public LintPreferencePage() { 116 setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore()); 117 } 118 119 @Override 120 public Control createContents(Composite parent) { 121 IAdaptable resource = getElement(); 122 if (resource != null) { 123 mProject = (IProject) resource.getAdapter(IProject.class); 124 } 125 126 Composite container = new Composite(parent, SWT.NULL); 127 container.setLayout(new GridLayout(2, false)); 128 129 if (mProject != null) { 130 Label projectLabel = new Label(container, SWT.CHECK); 131 projectLabel.setLayoutData(new GridData(SWT.LEFT, SWT.BOTTOM, false, false, 1, 132 1)); 133 projectLabel.setText("Project-specific configuration:"); 134 135 mWorkspaceLink = new Link(container, SWT.NONE); 136 mWorkspaceLink.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 137 mWorkspaceLink.setText("<a>Configure Workspace Settings...</a>"); 138 mWorkspaceLink.addSelectionListener(this); 139 } else { 140 mCheckFileCheckbox = new Button(container, SWT.CHECK); 141 mCheckFileCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 142 2, 1)); 143 mCheckFileCheckbox.setSelection(true); 144 mCheckFileCheckbox.setText("When saving files, check for errors"); 145 146 mCheckExportCheckbox = new Button(container, SWT.CHECK); 147 mCheckExportCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 148 2, 1)); 149 mCheckExportCheckbox.setSelection(true); 150 mCheckExportCheckbox.setText("Run full error check when exporting app and abort if fatal errors are found"); 151 152 Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL); 153 separator.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1)); 154 155 Label checkListLabel = new Label(container, SWT.NONE); 156 checkListLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); 157 checkListLabel.setText("Issues:"); 158 } 159 160 mRegistry = EclipseLintClient.getRegistry(); 161 mClient = new EclipseLintClient(mRegistry, 162 mProject != null ? Collections.singletonList(mProject) : null, null, false); 163 Project project = null; 164 if (mProject != null) { 165 File dir = AdtUtils.getAbsolutePath(mProject).toFile(); 166 project = mClient.getProject(dir, dir); 167 } 168 mConfiguration = mClient.getConfiguration(project); 169 170 mSearch = new Text(container, SWT.SEARCH | SWT.ICON_CANCEL | SWT.ICON_SEARCH); 171 mSearch.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); 172 mSearch.addSelectionListener(this); 173 mSearch.addModifyListener(this); 174 // Grab the Enter key such that pressing return in the search box filters (instead 175 // of closing the options dialog) 176 mSearch.setMessage("type filter text (use ~ to filter by severity, e.g. ~ignore)"); 177 mSearch.addTraverseListener(new TraverseListener() { 178 @Override 179 public void keyTraversed(TraverseEvent e) { 180 if (e.keyCode == SWT.CR) { 181 updateFilter(); 182 e.doit = false; 183 } else if (e.keyCode == SWT.ARROW_DOWN) { 184 // Allow moving from the search into the table 185 if (mTree.getItemCount() > 0) { 186 TreeItem firstCategory = mTree.getItem(0); 187 if (firstCategory.getItemCount() > 0) { 188 TreeItem first = firstCategory.getItem(0); 189 mTree.setFocus(); 190 mTree.select(first); 191 } 192 } 193 } 194 } 195 }); 196 197 mTreeViewer = new TreeViewer(container, SWT.BORDER | SWT.FULL_SELECTION); 198 mTree = mTreeViewer.getTree(); 199 GridData gdTable = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1); 200 gdTable.widthHint = 500; 201 gdTable.heightHint = 160; 202 mTree.setLayoutData(gdTable); 203 mTree.setLinesVisible(true); 204 mTree.setHeaderVisible(true); 205 206 TreeViewerColumn column1 = new TreeViewerColumn(mTreeViewer, SWT.NONE); 207 mIdColumn = column1.getColumn(); 208 mIdColumn.setWidth(100); 209 mIdColumn.setText("Id"); 210 211 TreeViewerColumn column2 = new TreeViewerColumn(mTreeViewer, SWT.FILL); 212 mNameColumn = column2.getColumn(); 213 mNameColumn.setWidth(100); 214 mNameColumn.setText("Name"); 215 216 mTreeViewer.setContentProvider(new ContentProvider()); 217 mTreeViewer.setLabelProvider(new LabelProvider()); 218 219 mDetailsText = new Text(container, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP |SWT.V_SCROLL 220 | SWT.MULTI); 221 GridData gdText = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 2); 222 gdText.heightHint = 80; 223 mDetailsText.setLayoutData(gdText); 224 225 Label severityLabel = new Label(container, SWT.NONE); 226 severityLabel.setText("Severity:"); 227 228 mSeverityCombo = new Combo(container, SWT.READ_ONLY); 229 mSeverityCombo.setItems(new String[] { 230 "(Default)", "Fatal", "Error", "Warning", "Information", "Ignore" 231 }); 232 GridData gdSeverityCombo = new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1); 233 gdSeverityCombo.widthHint = 90; 234 mSeverityCombo.setLayoutData(gdSeverityCombo); 235 mSeverityCombo.setText(""); 236 mSeverityCombo.addSelectionListener(this); 237 238 List<Issue> issues = mRegistry.getIssues(); 239 for (Issue issue : issues) { 240 Severity severity = mConfiguration.getSeverity(issue); 241 mSeverities.put(issue, severity); 242 } 243 mInitialSeverities = new HashMap<Issue, Severity>(mSeverities); 244 245 mTreeViewer.setInput(mRegistry); 246 247 mTree.addSelectionListener(this); 248 // Add a listener to resize the column to the full width of the table 249 mTree.addControlListener(this); 250 251 loadSettings(false); 252 253 mTreeViewer.expandAll(); 254 255 return container; 256 } 257 258 /** 259 * Initialize the preference page. 260 */ 261 @Override 262 public void init(IWorkbench workbench) { 263 // Initialize the preference page 264 } 265 266 @Override 267 protected void contributeButtons(Composite parent) { 268 super.contributeButtons(parent); 269 270 // Add "Include All" button for quickly enabling all the detectors, including 271 // those disabled by default 272 mIncludeAll = new Button(parent, SWT.PUSH); 273 mIncludeAll.setText("Include All"); 274 mIncludeAll.addSelectionListener(this); 275 276 // Add "Ignore All" button for quickly disabling all the detectors 277 mIgnoreAll = new Button(parent, SWT.PUSH); 278 mIgnoreAll.setText("Ignore All"); 279 mIgnoreAll.addSelectionListener(this); 280 281 // As per the contributeButton javadoc: increase parent's column count for each 282 // added button 283 ((GridLayout) parent.getLayout()).numColumns += 2; 284 } 285 286 @Override 287 public void dispose() { 288 super.dispose(); 289 cancelPendingSearch(); 290 } 291 292 @Override 293 protected void performDefaults() { 294 super.performDefaults(); 295 296 mConfiguration.startBulkEditing(); 297 298 List<Issue> issues = mRegistry.getIssues(); 299 for (Issue issue : issues) { 300 mConfiguration.setSeverity(issue, null); 301 } 302 303 mConfiguration.finishBulkEditing(); 304 305 loadSettings(true); 306 } 307 308 @Override 309 public boolean performOk() { 310 storeSettings(); 311 return true; 312 } 313 314 private void loadSettings(boolean refresh) { 315 if (mCheckExportCheckbox != null) { 316 AdtPrefs prefs = AdtPrefs.getPrefs(); 317 mCheckFileCheckbox.setSelection(prefs.isLintOnSave()); 318 mCheckExportCheckbox.setSelection(prefs.isLintOnExport()); 319 } 320 321 mSeverities.clear(); 322 List<Issue> issues = mRegistry.getIssues(); 323 for (Issue issue : issues) { 324 Severity severity = mConfiguration.getSeverity(issue); 325 mSeverities.put(issue, severity); 326 } 327 328 if (refresh) { 329 mTreeViewer.refresh(); 330 } 331 } 332 333 private void storeSettings() { 334 // Lint on Save, Lint on Export 335 if (mCheckExportCheckbox != null) { 336 AdtPrefs prefs = AdtPrefs.getPrefs(); 337 prefs.setLintOnExport(mCheckExportCheckbox.getSelection()); 338 prefs.setLintOnSave(mCheckFileCheckbox.getSelection()); 339 } 340 341 mConfiguration.startBulkEditing(); 342 try { 343 // Severities 344 for (Map.Entry<Issue, Severity> entry : mSeverities.entrySet()) { 345 Issue issue = entry.getKey(); 346 Severity severity = entry.getValue(); 347 if (mConfiguration.getSeverity(issue) != severity) { 348 if ((severity == issue.getDefaultSeverity()) && issue.isEnabledByDefault()) { 349 severity = null; 350 } 351 mConfiguration.setSeverity(issue, severity); 352 } 353 } 354 } finally { 355 mConfiguration.finishBulkEditing(); 356 } 357 358 if (!mInitialSeverities.equals(mSeverities)) { 359 // Ask user whether we should re-run the rules. 360 MessageDialog dialog = new MessageDialog( 361 null, "Lint Settings Have Changed", null, 362 "The list of enabled checks has changed. Would you like to run lint now " + 363 "to update the results?", 364 MessageDialog.QUESTION, 365 new String[] { 366 "Yes", "No" 367 }, 368 0); // yes is the default 369 int result = dialog.open(); 370 if (result == 0) { 371 // Run lint on all the open Android projects 372 IWorkspace workspace = ResourcesPlugin.getWorkspace(); 373 IProject[] projects = workspace.getRoot().getProjects(); 374 List<IProject> androidProjects = new ArrayList<IProject>(projects.length); 375 for (IProject project : projects) { 376 if (project.isOpen() && BaseProjectHelper.isAndroidProject(project)) { 377 androidProjects.add(project); 378 } 379 } 380 381 EclipseLintRunner.startLint(androidProjects, null, false /*fatalOnly*/, 382 true /*show*/); 383 } 384 } 385 } 386 387 private void updateFilter() { 388 cancelPendingSearch(); 389 if (!mSearch.isDisposed()) { 390 // Clear selection before refiltering since otherwise it might be showing 391 // items no longer available in the list. 392 mTree.setSelection(new TreeItem[0]); 393 mDetailsText.setText(""); 394 try { 395 mIgnoreEvent = true; 396 mSeverityCombo.setText(""); 397 mSeverityCombo.setEnabled(false); 398 } finally { 399 mIgnoreEvent = false; 400 } 401 402 mTreeViewer.getContentProvider().inputChanged(mTreeViewer, null, mRegistry); 403 mTreeViewer.refresh(); 404 mTreeViewer.expandAll(); 405 } 406 } 407 408 private void cancelPendingSearch() { 409 if (mPendingUpdate != null) { 410 Shell shell = getShell(); 411 if (!shell.isDisposed()) { 412 getShell().getDisplay().timerExec(-1, mPendingUpdate); 413 } 414 mPendingUpdate = null; 415 } 416 } 417 418 private Runnable mPendingUpdate; 419 420 private void scheduleSearch() { 421 if (mPendingUpdate == null) { 422 mPendingUpdate = new Runnable() { 423 @Override 424 public void run() { 425 mPendingUpdate = null; 426 updateFilter(); 427 } 428 }; 429 } 430 getShell().getDisplay().timerExec(250 /*ms*/, mPendingUpdate); 431 } 432 433 // ---- Implements SelectionListener ---- 434 435 @Override 436 public void widgetSelected(SelectionEvent e) { 437 if (mIgnoreEvent) { 438 return; 439 } 440 441 Object source = e.getSource(); 442 if (source == mTree) { 443 TreeItem item = (TreeItem) e.item; 444 Object data = item != null ? item.getData() : null; 445 if (data instanceof Issue) { 446 Issue issue = (Issue) data; 447 String summary = issue.getDescription(); 448 String explanation = issue.getExplanation(); 449 450 StringBuilder sb = new StringBuilder(summary.length() + explanation.length() + 20); 451 sb.append(summary); 452 sb.append('\n').append('\n'); 453 sb.append(explanation); 454 mDetailsText.setText(sb.toString()); 455 try { 456 mIgnoreEvent = true; 457 Severity severity = getSeverity(issue); 458 mSeverityCombo.select(severity.ordinal() + 1); // Skip the default option 459 mSeverityCombo.setEnabled(true); 460 } finally { 461 mIgnoreEvent = false; 462 } 463 } else { 464 mDetailsText.setText(""); 465 try { 466 mIgnoreEvent = true; 467 mSeverityCombo.setText(""); 468 mSeverityCombo.setEnabled(false); 469 } finally { 470 mIgnoreEvent = false; 471 } 472 } 473 } else if (source == mWorkspaceLink) { 474 int result = PreferencesUtil.createPreferenceDialogOn(getShell(), ID, 475 new String[] { ID }, null).open(); 476 if (result == Window.OK) { 477 loadSettings(true); 478 } 479 } else if (source == mSeverityCombo) { 480 int index = mSeverityCombo.getSelectionIndex(); 481 Issue issue = (Issue) mTree.getSelection()[0].getData(); 482 Severity severity; 483 if (index == -1 || index == 0) { 484 // "(Default)" 485 severity = issue.getDefaultSeverity(); 486 } else { 487 // -1: Skip the "(Default)" 488 severity = Severity.values()[index - 1]; 489 } 490 mSeverities.put(issue, severity); 491 mTreeViewer.refresh(); 492 } else if (source == mIncludeAll) { 493 List<Issue> issues = mRegistry.getIssues(); 494 for (Issue issue : issues) { 495 // The default severity is never ignore; for disabled-by-default 496 // issues the {@link Issue#isEnabledByDefault()} method is false instead 497 mSeverities.put(issue, issue.getDefaultSeverity()); 498 } 499 mTreeViewer.refresh(); 500 } else if (source == mIgnoreAll) { 501 List<Issue> issues = mRegistry.getIssues(); 502 for (Issue issue : issues) { 503 mSeverities.put(issue, Severity.IGNORE); 504 } 505 mTreeViewer.refresh(); 506 } else if (source == mSearch) { 507 updateFilter(); 508 } 509 } 510 511 private Severity getSeverity(Issue issue) { 512 Severity severity = mSeverities.get(issue); 513 if (severity != null) { 514 return severity; 515 } 516 517 return mConfiguration.getSeverity(issue); 518 } 519 520 @Override 521 public void widgetDefaultSelected(SelectionEvent e) { 522 Object source = e.getSource(); 523 if (source == mTree) { 524 widgetSelected(e); 525 } else if (source == mSearch) { 526 if (e.detail == SWT.CANCEL) { 527 // Cancel the search 528 mSearch.setText(""); 529 } 530 updateFilter(); 531 } 532 } 533 534 // ---- Implements ModifyListener ---- 535 @Override 536 public void modifyText(ModifyEvent e) { 537 if (e.getSource() == mSearch) { 538 scheduleSearch(); 539 } 540 } 541 542 // ---- Implements ControlListener ---- 543 544 @Override 545 public void controlMoved(ControlEvent e) { 546 } 547 548 @Override 549 public void controlResized(ControlEvent e) { 550 Rectangle r = mTree.getClientArea(); 551 int availableWidth = r.width; 552 553 mIdColumn.setWidth(ID_COLUMN_WIDTH); 554 availableWidth -= ID_COLUMN_WIDTH; 555 556 // Name absorbs everything else 557 mNameColumn.setWidth(availableWidth); 558 } 559 560 private boolean filterMatches(@NonNull String filter, @NonNull Issue issue) { 561 return (filter.startsWith("~") //$NON-NLS-1$ 562 && mConfiguration.getSeverity(issue).getDescription() 563 .toLowerCase(Locale.US).startsWith(filter.substring(1))) 564 || issue.getCategory().getName().toLowerCase(Locale.US).startsWith(filter) 565 || issue.getCategory().getFullName().toLowerCase(Locale.US).startsWith(filter) 566 || issue.getId().toLowerCase(Locale.US).contains(filter) 567 || issue.getDescription().toLowerCase(Locale.US).contains(filter); 568 } 569 570 private class ContentProvider extends TreeNodeContentProvider { 571 private Map<Category, List<Issue>> mCategoryToIssues; 572 private Object[] mElements; 573 574 @Override 575 public Object[] getElements(Object inputElement) { 576 return mElements; 577 } 578 579 @Override 580 public boolean hasChildren(Object element) { 581 return element instanceof Category; 582 } 583 584 @Override 585 public Object[] getChildren(Object parentElement) { 586 assert mCategoryToIssues != null; 587 List<Issue> list = mCategoryToIssues.get(parentElement); 588 if (list == null) { 589 return new Object[0]; 590 } else { 591 return list.toArray(); 592 } 593 } 594 595 @Override 596 public Object getParent(Object element) { 597 return null; 598 } 599 600 @Override 601 public void inputChanged(final Viewer viewer, final Object oldInput, 602 final Object newInput) { 603 mCategoryToIssues = null; 604 605 String filter = mSearch.isDisposed() ? "" : mSearch.getText().trim(); 606 if (filter.length() == 0) { 607 filter = null; 608 } else { 609 filter = filter.toLowerCase(Locale.US); 610 } 611 612 mCategoryToIssues = new HashMap<Category, List<Issue>>(); 613 List<Issue> issues = mRegistry.getIssues(); 614 for (Issue issue : issues) { 615 if (filter == null || filterMatches(filter, issue)) { 616 List<Issue> list = mCategoryToIssues.get(issue.getCategory()); 617 if (list == null) { 618 list = new ArrayList<Issue>(); 619 mCategoryToIssues.put(issue.getCategory(), list); 620 } 621 list.add(issue); 622 } 623 } 624 625 if (filter == null) { 626 // Not filtering: show all categories 627 mElements = mRegistry.getCategories().toArray(); 628 } else { 629 // Filtering: only include categories that contain matches 630 if (mCategoryToIssues == null) { 631 getChildren(null); 632 } 633 634 // Preserve the current category order, so instead of 635 // just creating a list of the mCategoryToIssues keyset, add them 636 // in the order they appear in in the registry 637 List<Category> categories = new ArrayList<Category>(mCategoryToIssues.size()); 638 for (Category category : mRegistry.getCategories()) { 639 if (mCategoryToIssues.containsKey(category)) { 640 categories.add(category); 641 } 642 } 643 mElements = categories.toArray(); 644 } 645 } 646 } 647 648 private class LabelProvider implements ITableLabelProvider, IColorProvider { 649 650 @Override 651 public void addListener(ILabelProviderListener listener) { 652 } 653 654 @Override 655 public void dispose() { 656 } 657 658 @Override 659 public boolean isLabelProperty(Object element, String property) { 660 return true; 661 } 662 663 @Override 664 public void removeListener(ILabelProviderListener listener) { 665 } 666 667 @Override 668 public Image getColumnImage(Object element, int columnIndex) { 669 if (element instanceof Category) { 670 return null; 671 } 672 673 if (columnIndex == 1) { 674 Issue issue = (Issue) element; 675 Severity severity = mSeverities.get(issue); 676 if (severity == null) { 677 return null; 678 } 679 680 ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages(); 681 switch (severity) { 682 case FATAL: 683 case ERROR: 684 return sharedImages.getImage(ISharedImages.IMG_OBJS_ERROR_TSK); 685 case WARNING: 686 return sharedImages.getImage(ISharedImages.IMG_OBJS_WARN_TSK); 687 case INFORMATIONAL: 688 return sharedImages.getImage(ISharedImages.IMG_OBJS_INFO_TSK); 689 case IGNORE: 690 return sharedImages.getImage(ISharedImages.IMG_ELCL_REMOVE_DISABLED); 691 } 692 } 693 return null; 694 } 695 696 @Override 697 public String getColumnText(Object element, int columnIndex) { 698 if (element instanceof Category) { 699 if (columnIndex == 0) { 700 return ((Category) element).getFullName(); 701 } else { 702 return ((Category) element).getExplanation(); 703 } 704 } 705 706 Issue issue = (Issue) element; 707 switch (columnIndex) { 708 case 0: 709 return issue.getId(); 710 case 1: 711 return issue.getDescription(); 712 } 713 714 return null; 715 } 716 717 // ---- IColorProvider ---- 718 719 @Override 720 public Color getForeground(Object element) { 721 if (element instanceof Category) { 722 return mTree.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND); 723 } 724 725 if (element instanceof Issue) { 726 Issue issue = (Issue) element; 727 Severity severity = mSeverities.get(issue); 728 if (severity == Severity.IGNORE) { 729 return mTree.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY); 730 } 731 } 732 733 return null; 734 } 735 736 @Override 737 public Color getBackground(Object element) { 738 if (element instanceof Category) { 739 return mTree.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND); 740 } 741 return null; 742 } 743 } 744 }