diff --git a/README.adoc b/README.adoc index bd08256..4fd0a2a 100644 --- a/README.adoc +++ b/README.adoc @@ -1,28 +1,38 @@ -= sonarlint4netbeans - -== SonarLint integration for Apache Netbeans - -Features: - -- Support Java and Javascript -- Annotation in editor -- Type SonarLint in Action Items -- Enable/Disable Rules in Tools/Options/Miscellaneous/SonarLint -- Severity icons - -== Screenshot - -.SonarLint in Java editor and show action items for selected project -image::docs/JavaEditorAnnotationAndActionItems.jpg[] - -.Show Action Items fo currently edited file only -image::docs/JavascriptActionItems.jpg[] - -.SonarLint analyzer name and version -image::docs/OptionsSonarLintAnalyzers.jpg[] - -.SonarLint rules enabled or disabled -image::docs/OptionsSonarLintRules.jpg[] - -.Sonar rule details window -image::docs/SonarRuleDetailsWindow.jpg[] \ No newline at end of file += sonarlint4netbeans + +== SonarLint integration for Apache Netbeans + +Features: + +- Support Java and Javascript +- Annotation in editor +- Type SonarLint in Action Items +- Enable/Disable Rules in Tools/Options/Miscellaneous/SonarLint +- Filter Rules in Tools/Options/Miscellaneous/SonarLint option panel and "Sonar Rule Details" window +- Severity icons + +== Screenshot + +.SonarLint in Java editor and show action items for selected project +image::docs/JavaEditorAnnotationAndActionItems.jpg[] + +.Show Action Items fo currently edited file only +image::docs/JavascriptActionItems.jpg[] + +.SonarLint analyzer name and version +image::docs/OptionsSonarLintAnalyzers.jpg[] + +.SonarLint rules enabled or disabled +image::docs/OptionsSonarLintRules.jpg[] + +.SonarLint rules enabled or disabled with key filter +image::docs/OptionsSonarLintRulesWithKeyFilter.jpg[] + +.SonarLint rules enabled or disabled with name filter +image::docs/OptionsSonarLintRulesWithNameFilter.jpg[] + +.Sonar rule details window with key filter +image::docs/SonarRuleDetailsWindowWithKeyFilter.jpg[] + +.Sonar rule details window with name filter +image::docs/SonarRuleDetailsWindowWithNameFilter.jpg[] \ No newline at end of file diff --git a/docs/OptionsSonarLintRules.jpg b/docs/OptionsSonarLintRules.jpg index 2c061cf..c433963 100644 Binary files a/docs/OptionsSonarLintRules.jpg and b/docs/OptionsSonarLintRules.jpg differ diff --git a/docs/OptionsSonarLintRulesWithKeyFilter.jpg b/docs/OptionsSonarLintRulesWithKeyFilter.jpg new file mode 100644 index 0000000..b7b0d71 Binary files /dev/null and b/docs/OptionsSonarLintRulesWithKeyFilter.jpg differ diff --git a/docs/OptionsSonarLintRulesWithNameFilter.jpg b/docs/OptionsSonarLintRulesWithNameFilter.jpg new file mode 100644 index 0000000..4d27e12 Binary files /dev/null and b/docs/OptionsSonarLintRulesWithNameFilter.jpg differ diff --git a/docs/SonarRuleDetailsWindow.jpg b/docs/SonarRuleDetailsWindowWithKeyFilter.jpg similarity index 100% rename from docs/SonarRuleDetailsWindow.jpg rename to docs/SonarRuleDetailsWindowWithKeyFilter.jpg diff --git a/docs/SonarRuleDetailsWindowWithNameFilter.jpg b/docs/SonarRuleDetailsWindowWithNameFilter.jpg new file mode 100644 index 0000000..dc7cb99 Binary files /dev/null and b/docs/SonarRuleDetailsWindowWithNameFilter.jpg differ diff --git a/pom.xml b/pom.xml index 786269a..5612387 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 fr.philippefichet.sonarlint sonarlint4netbeans - 1.3.0 + 1.4.0 nbm SonarLint for Netbeans diff --git a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintPanel.form b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintPanel.form index 452849f..be494fc 100644 --- a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintPanel.form +++ b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintPanel.form @@ -22,6 +22,11 @@ -->
+ + + + + @@ -31,7 +36,7 @@ - + @@ -72,6 +77,8 @@ + + @@ -81,10 +88,10 @@ - + - - + + @@ -93,7 +100,18 @@ - + + + + + + + + + + + + diff --git a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintPanel.java b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintPanel.java index c2123fb..b49d0aa 100644 --- a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintPanel.java +++ b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintPanel.java @@ -21,24 +21,28 @@ import java.awt.BorderLayout; import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; import javax.swing.BoxLayout; import javax.swing.ImageIcon; +import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; +import javax.swing.JSeparator; import javax.swing.JTable; +import javax.swing.JTextField; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import org.openide.util.Lookup; -import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; import org.sonarsource.sonarlint.core.client.api.common.RuleKey; import org.sonarsource.sonarlint.core.client.api.connected.LoadedAnalyzer; @@ -49,17 +53,7 @@ public final class SonarLintPanel extends javax.swing.JPanel { private final Map ruleKeyChanged = new HashMap<>(); private DefaultTableModel analyzerDefaultTableModel = new DefaultTableModel(); - private DefaultTableModel rulesDefaultTableModel = new DefaultTableModel() { - @Override - public boolean isCellEditable(int row, int column) { - return column < 1; - } - - @Override - public Class getColumnClass(int columnIndex) { - return columnIndex == 0 ? Boolean.class : String.class; - } - }; + private SonarLintRuleTableModel rulesDefaultTableModel = new SonarLintRuleTableModel(); public SonarLintPanel(SonarLintOptionsPanelController controller) { this.controller = controller; @@ -88,23 +82,7 @@ public SonarLintPanel(SonarLintOptionsPanelController controller) { }); } - rulesDefaultTableModel.addColumn(""); - rulesDefaultTableModel.addColumn("Language"); - rulesDefaultTableModel.addColumn("Severity"); - rulesDefaultTableModel.addColumn("Key"); - rulesDefaultTableModel.addColumn("Details"); - Collection allRuleDetails = engine.getAllRuleDetails(); - allRuleDetails.stream().sorted((r1, r2) -> { - return r1.getKey().compareTo(r2.getKey()); - }).map(ruleDetail -> new Object[] { - !engine.isExcluded(ruleDetail), - ruleDetail.getLanguageKey(), - ruleDetail.getSeverity(), - ruleDetail.getKey(), - ruleDetail.getName()} - ).collect(Collectors.toList()).forEach(rulesDefaultTableModel::addRow); - - rulesDefaultTableModel.addTableModelListener((e) -> { + rulesDefaultTableModel.addTableModelListener(e -> { controller.changed(); int column = e.getColumn(); @@ -120,7 +98,7 @@ public SonarLintPanel(SonarLintOptionsPanelController controller) { categoriesList.addListSelectionListener((e) -> { if ("Rules".equals(categoriesList.getSelectedValue())) { - initRulesPanel(); + initRulesPanel(engine); } if ("Analyzers".equals(categoriesList.getSelectedValue())) { initAnalyzersPanel(); @@ -130,7 +108,7 @@ public SonarLintPanel(SonarLintOptionsPanelController controller) { }); // Rule panel by default - initRulesPanel(); + initRulesPanel(engine); optionPanel.revalidate(); optionPanel.repaint(); }); @@ -144,8 +122,35 @@ private void initAnalyzersPanel() { optionPanel.add(analyzersTable, BorderLayout.CENTER); } - private void initRulesPanel() { + private void initRulesPanel(SonarLintEngine engine) { optionPanel.removeAll(); + + JPanel languageKeyContainer = new JPanel(new FlowLayout()); + JTextField rulesFilter = new JTextField(); + rulesFilter.setColumns(20); + JComboBox comboLanguageKey = new JComboBox<>(); + engine.getAllRuleDetails().stream() + .map(r -> r.getLanguageKey()) + .distinct() + .forEach(comboLanguageKey::addItem); + rulesFilter.addKeyListener(new KeyAdapter() { + @Override + public void keyReleased(KeyEvent e) { + rulesDefaultTableModel.setRules(engine, (String)comboLanguageKey.getSelectedItem(), rulesFilter.getText()); + } + }); + comboLanguageKey.addActionListener( + e -> + rulesDefaultTableModel.setRules(engine, (String)comboLanguageKey.getSelectedItem(), rulesFilter.getText()) + ); + languageKeyContainer.add(new JLabel("language key: ")); + languageKeyContainer.add(comboLanguageKey); + languageKeyContainer.add(new JSeparator()); + languageKeyContainer.add(new JLabel("filter: ")); + languageKeyContainer.add(rulesFilter); + + JPanel northContainer = new JPanel(); + northContainer.setLayout(new BoxLayout(northContainer, BoxLayout.Y_AXIS)); JTable rulesTable = new JTable(rulesDefaultTableModel); rulesTable.getColumnModel().getColumn(0).setMaxWidth(50); rulesTable.getColumnModel().getColumn(1).setMaxWidth(250); @@ -162,7 +167,11 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole return defaultTableCellRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); } }); - optionPanel.add(rulesTable.getTableHeader(), BorderLayout.NORTH); + + rulesDefaultTableModel.setRules(engine, (String)comboLanguageKey.getSelectedItem(), rulesFilter.getText()); + northContainer.add(languageKeyContainer); + northContainer.add(rulesTable.getTableHeader()); + optionPanel.add(northContainer, BorderLayout.NORTH); optionPanel.add(rulesTable, BorderLayout.CENTER); } @@ -178,8 +187,10 @@ private void initComponents() { categoriesLabel = new javax.swing.JLabel(); categoriesScrollPanel = new javax.swing.JScrollPane(); categoriesList = new javax.swing.JList<>(); + optionScrollPane = new javax.swing.JScrollPane(); optionPanel = new javax.swing.JPanel(); + setPreferredSize(getPreferredSize()); setLayout(new java.awt.BorderLayout(10, 0)); categoriesPanel.setLayout(new javax.swing.BoxLayout(categoriesPanel, javax.swing.BoxLayout.PAGE_AXIS)); @@ -192,15 +203,21 @@ private void initComponents() { public int getSize() { return strings.length; } public String getElementAt(int i) { return strings[i]; } }); + categoriesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + categoriesList.setSelectedIndex(0); categoriesScrollPanel.setViewportView(categoriesList); categoriesPanel.add(categoriesScrollPanel); add(categoriesPanel, java.awt.BorderLayout.WEST); + optionScrollPane.setViewportView(null); + optionPanel.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); optionPanel.setLayout(new java.awt.BorderLayout()); - add(optionPanel, java.awt.BorderLayout.CENTER); + optionScrollPane.setViewportView(optionPanel); + + add(optionScrollPane, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents void load() { @@ -235,10 +252,11 @@ boolean valid() { } // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel categoriesLabel; - private javax.swing.JList categoriesList; - private javax.swing.JPanel categoriesPanel; - private javax.swing.JScrollPane categoriesScrollPanel; - private javax.swing.JPanel optionPanel; + javax.swing.JLabel categoriesLabel; + javax.swing.JList categoriesList; + javax.swing.JPanel categoriesPanel; + javax.swing.JScrollPane categoriesScrollPanel; + javax.swing.JPanel optionPanel; + javax.swing.JScrollPane optionScrollPane; // End of variables declaration//GEN-END:variables } diff --git a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintRuleTableModel.java b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintRuleTableModel.java new file mode 100644 index 0000000..486f73d --- /dev/null +++ b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintRuleTableModel.java @@ -0,0 +1,76 @@ +/* + * sonarlint4netbeans: SonarLint integration for Apache Netbeans + * Copyright (C) 2020 Philippe FICHET. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package fr.philippefichet.sonarlint.netbeans; + +import java.util.Collection; +import java.util.stream.Collectors; +import javax.swing.table.DefaultTableModel; +import org.sonarsource.sonarlint.core.client.api.common.RuleDetails; + + +/** + * + * @author FICHET Philippe + */ +public class SonarLintRuleTableModel extends DefaultTableModel { + + public SonarLintRuleTableModel() { + init(); + } + + private void init() { + addColumn(""); + addColumn("Language"); + addColumn("Severity"); + addColumn("Key"); + addColumn("Details"); + } + + public void setRules(SonarLintEngine engine, String languagekey, String ruleFilter) { + while(getRowCount() > 0) { + removeRow(0); + } + Collection allRuleDetails = engine.getAllRuleDetails(); + allRuleDetails.stream() + .filter( + SonarLintUtils.FilterBy.languageKey(languagekey) + .and(SonarLintUtils.FilterBy.keyAndName(ruleFilter)) + ) + .sorted((r1, r2) -> + r1.getKey().compareTo(r2.getKey()) + ).map(ruleDetail -> new Object[] { + !engine.isExcluded(ruleDetail), + ruleDetail.getLanguageKey(), + ruleDetail.getSeverity(), + ruleDetail.getKey(), + ruleDetail.getName()} + ).collect(Collectors.toList()).forEach(this::addRow); + } + + @Override + public boolean isCellEditable(int row, int column) { + return column < 1; + } + + @Override + public Class getColumnClass(int columnIndex) { + return columnIndex == 0 ? Boolean.class : String.class; + } +} diff --git a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintUtils.java b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintUtils.java index 162fa2e..a428c4e 100644 --- a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintUtils.java +++ b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarLintUtils.java @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.Predicate; import java.util.logging.Logger; import javax.swing.ImageIcon; import org.netbeans.api.project.FileOwnerQuery; @@ -54,7 +55,34 @@ public final class SonarLintUtils { private SonarLintUtils() { } - + + public static class FilterBy { + + private FilterBy() { + } + + /** + * Create a predicat to filter rule detail by language key + * @param languageKey language key to filter + * @return Predicat to filter rule detail by language key + */ + public static Predicate languageKey(String languageKey) { + return ruleDetail -> ruleDetail.getLanguageKey().equals(languageKey); + } + + /** + * Create a predicat to filter rule detail by key or name + * @param keyOrName key or name to filter + * @return Predicat to filter rule detail by key or name + */ + public static Predicate keyAndName(String keyOrName) { + String ruleFilterLowerCase = keyOrName.toLowerCase(); + return ruleDetail -> keyOrName.isEmpty() + || ruleDetail.getKey().toLowerCase().contains(ruleFilterLowerCase) + || ruleDetail.getName().toLowerCase().contains(ruleFilterLowerCase); + } + } + public static Optional toImageIcon(String severity) { URL resource = SonarLintUtils.class.getClassLoader().getResource("fr/philippefichet/sonarlint/netbeans/resources/sonarlint-" + severity.toLowerCase() + ".png"); @@ -63,7 +91,7 @@ public static Optional toImageIcon(String severity) } return Optional.of(new ImageIcon(resource, severity)); } - + public static String toURL(RuleDetails ruleDetails) { String[] keySplit = ruleDetails.getKey().split(":"); diff --git a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarRuleDetailsTopComponent.form b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarRuleDetailsTopComponent.form index 3b9e48c..ee42c10 100644 --- a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarRuleDetailsTopComponent.form +++ b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarRuleDetailsTopComponent.form @@ -97,6 +97,7 @@ + diff --git a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarRuleDetailsTopComponent.java b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarRuleDetailsTopComponent.java index 87d6116..581ca22 100644 --- a/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarRuleDetailsTopComponent.java +++ b/src/main/java/fr/philippefichet/sonarlint/netbeans/SonarRuleDetailsTopComponent.java @@ -138,6 +138,7 @@ public Component getListCellRendererComponent(JList list, Stri } }); initListAllRuleDetails(); + sonarLintAllRules.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); sonarLintAllRules.addListSelectionListener(new javax.swing.event.ListSelectionListener() { public void valueChanged(javax.swing.event.ListSelectionEvent evt) { sonarLintAllRulesValueChanged(evt); @@ -175,7 +176,7 @@ private void initListAllRuleDetails() { DefaultListModel model = new DefaultListModel<>(); Collection rules = engine.getAllRuleDetails(); rules.stream().sorted((r1, r2) -> r1.getKey().compareTo(r2.getKey())) - .filter(rule -> ruleKeyFilter.isEmpty() || rule.getKey().toLowerCase().contains(ruleKeyFilter)) + .filter(SonarLintUtils.FilterBy.keyAndName(ruleKeyFilter)) .forEach(rule -> model.addElement(rule.getKey())); sonarLintAllRules.setModel(model); sonarLintAllRules.updateUI(); diff --git a/src/main/resources/fr/philippefichet/sonarlint/netbeans/Bundle.properties b/src/main/resources/fr/philippefichet/sonarlint/netbeans/Bundle.properties index 98269f3..7784938 100644 --- a/src/main/resources/fr/philippefichet/sonarlint/netbeans/Bundle.properties +++ b/src/main/resources/fr/philippefichet/sonarlint/netbeans/Bundle.properties @@ -7,6 +7,7 @@ Features:\n\
  • Annotation in editor
  • \
  • Type SonarLint in Action Items
  • \
  • Enable/Disable Rules in Tools/Options/Miscellaneous/SonarLint
  • \ +
  • Filter Rules in Tools/Options/Miscellaneous/SonarLint option panel and "Sonar Rule Details" window
  • \
  • Severity icons
  • \ OpenIDE-Module-Name=sonarlint4netbeans