/* * User: tom * Date: Jul 8, 2002 * Time: 4:29:19 PM */ package net.sourceforge.pmd.jedit; import net.sourceforge.pmd.jedit.checkboxtree.*; import org.gjt.sp.jedit.AbstractOptionPane; import org.gjt.sp.jedit.EditPane; import org.gjt.sp.jedit.OptionPane; import org.gjt.sp.jedit.jEdit; import org.gjt.sp.jedit.GUIUtilities; import org.gjt.sp.util.StringList; import org.gjt.sp.jedit.browser.VFSBrowser; import org.gjt.sp.jedit.browser.VFSFileChooserDialog; import org.gjt.sp.jedit.View; import java.awt.FlowLayout; import java.awt.event.*; import javax.swing.*; import javax.swing.filechooser.*; import javax.swing.filechooser.FileFilter; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.util.List; import java.awt.BorderLayout; import java.awt.Dimension; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.RuleSetWriter; import java.io.*; import common.gui.pathbuilder.PathBuilder; import common.gui.pathbuilder.PathBuilderDialog; import ise.java.awt.KappaLayout; /* TODO: put strings in properties file QUESTION: would it be possible to run the examples through the Beauty plugin and the Code2Html plugin to format and colorize the examples per the users preferences? DONE: make custom rules a separate panel. -- added custom rules dialog. DONE: add ability to export current ruleset. */ public class PMDRulesOptionPane extends AbstractOptionPane implements OptionPane { SelectedRules rules; JTextArea exampleTextArea = new JTextArea( 12, 60 ); JTextField txtCustomRules; CheckboxTree tree; JCheckBox useDefaultRules = new JCheckBox( jEdit.getProperty( "net.sf.pmd.Select_default_rules", "Select default rules" ) ); JLabel exampleLabel; JButton exportButton = new JButton( "Export this ruleset" ); JButton customRulesButton= new JButton( "Custom Rules" ); static final String USE_DEFAULT_RULES_KEY = "pmd.use-default-rules"; public PMDRulesOptionPane() { super( PMDJEditPlugin.NAME ); rules = new SelectedRules(); } public void _init() { removeAll(); setLayout(new FlowLayout(FlowLayout.LEFT)); JPanel panel = new JPanel(new KappaLayout()); panel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); JLabel title = new JLabel("<html><b>" + jEdit.getProperty("options.pmd.rules.label", "PMD Rules")); panel.add("0, 0, 1, 1, W, w, 3", title); panel.add("0, 1, 1, 1, W, w, 3", getRulesPanel()); View view=PMDJEditPlugin.MainView; view.getContentPane().add(BorderLayout.WEST,panel); } private JPanel getRulesPanel() { JPanel panel = new JPanel(); panel.setLayout( new KappaLayout() ); JLabel rules_label = new JLabel( jEdit.getProperty( "net.sf.pmd.Rules", "Rules" ) ); useDefaultRules = new JCheckBox( jEdit.getProperty( "net.sf.pmd.Select_default_rules", "Select default rules" ) ); useDefaultRules.setSelected( jEdit.getBooleanProperty( USE_DEFAULT_RULES_KEY, false ) ); // use a checkbox tree for displaying the rules. This lets the rules be // grouped by ruleset, and makes it very easy to select an entire set of // rules with a single click. The tree is only 2 levels // deep, the first level is the ruleset level, the second level contains the // individual rules. Using the PROPAGATE_PRESERVING_UNCHECK checking mode // means the ruleset will be checked if one or more of the rules it contains // is checked. JScrollPane rules_pane = null; if ( rules == null ) { JOptionPane.showMessageDialog( null, jEdit.getProperty( "net.sf.pmd.Error_loading_rules._Check_any_custom_rulesets_for_errors.", "Error loading rules. Check any custom rulesets for errors." ), jEdit.getProperty( "net.sf.pmd.Error_Loading_Rules", "Error Loading Rules" ), JOptionPane.ERROR_MESSAGE ); } else { if ( jEdit.getBooleanProperty( USE_DEFAULT_RULES_KEY, false ) ) { rules.loadGoodRulesTree(); } tree = new CheckboxTree( rules.getRoot() ); tree.getCheckingModel().setCheckingMode( TreeCheckingModel.CheckingMode.PROPAGATE_PRESERVING_UNCHECK ); tree.setCheckingPaths( rules.getCheckingModel().getCheckingPaths() ); tree.setRootVisible( false ); tree.addMouseMotionListener( new MyMouseMotionAdapter() ); rules_pane = new JScrollPane( tree ); rules_pane.setMaximumSize( new Dimension( 500, 200 ) ); rules_pane.setPreferredSize( new Dimension( 500, 200 ) ); } useDefaultRules.addActionListener( new ActionListener() { public void actionPerformed( final ActionEvent ae ) { SwingUtilities.invokeLater( new Runnable() { public void run() { if ( ( ( JCheckBox ) ae.getSource() ).isSelected() ) { rules.loadGoodRulesTree(); customRulesButton.setEnabled( false ); } else { rules.loadTree(); customRulesButton.setEnabled( true ); } tree.setModel( rules.getTreeModel() ); tree.getCheckingModel().setCheckingMode( TreeCheckingModel.CheckingMode.PROPAGATE_PRESERVING_UNCHECK ); tree.setCheckingPaths( rules.getCheckingModel().getCheckingPaths() ); tree.invalidate(); tree.validate(); } } ); } } ); exampleLabel = new JLabel( jEdit.getProperty( "net.sf.pmd.Example", "Example" ) ); JScrollPane example_pane = new JScrollPane( exampleTextArea ); example_pane.setMaximumSize( new Dimension( 500, 200 ) ); example_pane.setPreferredSize( new Dimension( 500, 200 ) ); exportButton = new JButton( "Export this ruleset" ); exportButton.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent ae ) { RuleSets rulesets = rules.getSelectedRules(); RuleSet ruleset = new RuleSet(); for ( RuleSet rs : rulesets.getAllRuleSets() ) { ruleset.addRuleSet( rs ); } // file chooser VFSFileChooserDialog chooser = new VFSFileChooserDialog( GUIUtilities.getParentDialog( PMDRulesOptionPane.this ), jEdit.getActiveView(), System.getProperty( "user.home" ) + "/ruleset.xml", VFSBrowser.SAVE_DIALOG, false, false ); chooser.setTitle( "Export Ruleset" ); chooser.setVisible( true ); if ( chooser.getSelectedFiles() != null ) { try { String outfile = chooser.getSelectedFiles() [ 0 ]; OutputStream outputStream = new BufferedOutputStream( new FileOutputStream( outfile ) ); RuleSetWriter writer = new RuleSetWriter( outputStream ); writer.write( ruleset ); writer.close(); } catch ( Exception e ) { JOptionPane.showMessageDialog( GUIUtilities.getParentDialog( PMDRulesOptionPane.this ), "Error saving ruleset:\n" + e.getMessage(), "Error Saving Ruleset", JOptionPane.ERROR_MESSAGE ); } } } } ); JLabel more_info_label = new JLabel( jEdit.getProperty( "net.sf.pmd.Please_see_http>//pmd.sf.net/_for_more_information", "Please see http://pmd.sf.net/ for more information" ) ); customRulesButton = new JButton( "Custom Rules" ); customRulesButton.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent ae ) { customRulesDialog(); } } ); panel.setBorder( BorderFactory.createEmptyBorder( 12, 11, 11, 12 ) ); panel.add( "0, 0, 2, 1, W, w, 3", rules_label ); panel.add( "0, 1, 2, 1, W, w, 3", useDefaultRules ); panel.add( "0, 2, 2, 10, 0, w, 3", rules_pane ); panel.add( "0, 12, 1, 1, 0, w, 3", exportButton ); panel.add( "1, 12, 1, 1, 0, w, 3", customRulesButton ); panel.add( "0, 13, 2, 1, W, w, 3", exampleLabel ); panel.add( "0, 14, 2, 6, 0, wh, 3", example_pane ); panel.add( "0, 20, 2, 1, W, w, 3", more_info_label ); return panel; } public void _save() { if ( rules != null ) { rules.save( tree.getCheckingModel() ); } if ( txtCustomRules != null ) { jEdit.setProperty( PMDJEditPlugin.CUSTOM_RULES_PATH_KEY, txtCustomRules .getText() ); } jEdit.setBooleanProperty( USE_DEFAULT_RULES_KEY, useDefaultRules.isSelected() ); } private class MyMouseMotionAdapter extends java.awt.event.MouseMotionAdapter { public void mouseMoved( MouseEvent event ) { TreePath path = tree.getPathForLocation( event.getX(), event.getY() ); if ( path != null ) { DefaultMutableTreeNode node = ( DefaultMutableTreeNode ) path.getLastPathComponent(); if ( node != null ) { Object userObject = node.getUserObject(); if ( userObject instanceof RuleNode ) { changeExampleLabel( jEdit.getProperty( "net.sf.pmd.Example", "Example" ) ); Rule rule = (( RuleNode ) userObject).getRule(); String header = getRuleExampleHeader(rule); List<String> examples = ( ( RuleNode ) userObject ).getRule().getExamples(); exampleTextArea.setLineWrap( true ); exampleTextArea.setWrapStyleWord( true ); exampleTextArea.setText( header + StringList.join( examples, "\n---------\n" ) ); exampleTextArea.setCaretPosition( 0 ); } else if ( userObject instanceof RuleSetNode ) { changeExampleLabel( jEdit.getProperty( "net.sf.pmd.Description", "Description" ) ); String description = ( ( RuleSetNode ) userObject ).getRuleSet().getDescription(); description = cleanUpDescription( description ); exampleTextArea.setLineWrap( true ); exampleTextArea.setWrapStyleWord( true ); exampleTextArea.setText( description ); exampleTextArea.setCaretPosition( 0 ); } } } } } private String getRuleExampleHeader( Rule rule ) { StringBuilder sb = new StringBuilder(128); sb.append("Name: " ).append(rule.getName()); sb.append("\nLanguage: ").append(rule.getLanguage().getName()); sb.append("\nDescription: ").append(cleanUpDescription(rule.getDescription())); sb.append("\nError Message: ").append(rule.getMessage()); sb.append("\nPriority: ").append(rule.getPriority().toString()).append('\n'); return sb.toString(); } private String cleanUpDescription( String desc ) { desc = desc.replaceAll( "\\s+", " " ); desc = desc.trim(); return desc; } private void changeExampleLabel( final String text ) { SwingUtilities.invokeLater( new Runnable() { public void run() { exampleLabel.setText( text ); exampleLabel.repaint(); } } ); } private void customRulesDialog() { PathBuilderDialog dialog = new PathBuilderDialog( jEdit.getActiveView(), "Choose Custom Rulesets", "Custom Ruleset Files" ); PathBuilder pathBuilder = dialog.getPathBuilder(); pathBuilder.setAddButtonText( "Add Ruleset" ); pathBuilder.setRemoveButtonText( "Remove Ruleset" ); pathBuilder.setFileDialogTitle( "Select Ruleset File" ); pathBuilder.setFileFilter( new RulesetFileFilter() ); String paths = jEdit.getProperty( PMDJEditPlugin.CUSTOM_RULES_PATH_KEY, "" ); paths = paths.replaceAll( ",", File.pathSeparator ); pathBuilder.setPath( paths ); dialog.setVisible( true ); if ( dialog.getResult() ) { paths = pathBuilder.getPath(); paths = paths.replaceAll( File.pathSeparator, "," ); jEdit.setProperty( PMDJEditPlugin.CUSTOM_RULES_PATH_KEY, paths ); SwingUtilities.invokeLater( new Runnable() { public void run() { try { rules = new SelectedRules(); tree.setModel( rules.getTreeModel() ); tree.getCheckingModel().setCheckingMode( TreeCheckingModel.CheckingMode.PROPAGATE_PRESERVING_UNCHECK ); tree.setCheckingPaths( rules.getCheckingModel().getCheckingPaths() ); tree.invalidate(); tree.validate(); tree.repaint(); } catch ( Exception e ) { e.printStackTrace(); } } } ); } } public class RulesetFileFilter extends FileFilter { public boolean accept( File f ) { return f != null && ( f.isDirectory() || f.getName().endsWith( ".xml" ) ); } public String getDescription() { return "PMD Ruleset Files"; } } }