From 1e819951c28380c14b010c0cb82a69c987cdc617 Mon Sep 17 00:00:00 2001 From: Radim Kubacki Date: Wed, 22 Nov 2006 19:54:55 +0000 Subject: [PATCH] commited a patch provided by Andrei Badea : 1. Fixes the bug where if you slide the results window and invoke Run PMD the results window is docked in the output mode again. 2. Adds a Window - PMD Output action which opens the results window. 3. Allows jumping to a problem by pressing Enter in the results window. 4. Fixes the threading of OutputWindow. 5. Some minor cleanup in RunPMDAction. git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@4827 51baf565-9d33-0410-a72c-fc3788e3496d --- pmd-netbeans/src/pmd/Bundle.properties | 5 +- pmd-netbeans/src/pmd/GotoProblemAction.java | 4 +- pmd-netbeans/src/pmd/OutputWindow.java | 99 ++++++++++++++++--- pmd-netbeans/src/pmd/OutputWindowSettings.xml | 8 ++ pmd-netbeans/src/pmd/OutputWindowWstcref.xml | 7 ++ pmd-netbeans/src/pmd/RunPMDAction.java | 17 ++-- .../src/pmd/ShowOutputWindowAction.java | 59 +++++++++++ pmd-netbeans/src/pmd/mf-layer.xml | 25 +++++ 8 files changed, 193 insertions(+), 31 deletions(-) create mode 100644 pmd-netbeans/src/pmd/OutputWindowSettings.xml create mode 100644 pmd-netbeans/src/pmd/OutputWindowWstcref.xml create mode 100644 pmd-netbeans/src/pmd/ShowOutputWindowAction.java diff --git a/pmd-netbeans/src/pmd/Bundle.properties b/pmd-netbeans/src/pmd/Bundle.properties index bebe7473f2..0f84ac271e 100644 --- a/pmd-netbeans/src/pmd/Bundle.properties +++ b/pmd-netbeans/src/pmd/Bundle.properties @@ -25,14 +25,15 @@ # DAMAGE. # +CTL_ShowOutputWindowAction=PMD Output LBL_Action=Run PM&D OpenIDE-Module-Name=PMD OpenIDE-Module-Display-Category=Java OpenIDE-Module-Short-Description=Runs the PMD source code scanner tool. OpenIDE-Module-Long-Description=Runs the PMD source code scanner tool. \ - Finds various problems in your code and reports them to you easily. \ - Hyperlinked Output Window display. + Finds various problems in your code and reports them to you \ + in a tabular output window. LBL_pmd_annotation=PMD Error diff --git a/pmd-netbeans/src/pmd/GotoProblemAction.java b/pmd-netbeans/src/pmd/GotoProblemAction.java index d48357403f..cf838cd6e8 100644 --- a/pmd-netbeans/src/pmd/GotoProblemAction.java +++ b/pmd-netbeans/src/pmd/GotoProblemAction.java @@ -49,8 +49,8 @@ class GotoProblemAction extends AbstractAction { protected boolean action(){ return next? - !OutputWindow.getInstance().selectNextResult(): - !OutputWindow.getInstance().selectPreviousResult(); + !OutputWindow.findInstance().selectNextResult(): + !OutputWindow.findInstance().selectPreviousResult(); } public void actionPerformed(ActionEvent e) { diff --git a/pmd-netbeans/src/pmd/OutputWindow.java b/pmd-netbeans/src/pmd/OutputWindow.java index dbbc7187de..8fa00ac89e 100644 --- a/pmd-netbeans/src/pmd/OutputWindow.java +++ b/pmd-netbeans/src/pmd/OutputWindow.java @@ -28,28 +28,37 @@ package pmd; import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.Serializable; +import javax.swing.AbstractAction; import javax.swing.ActionMap; +import javax.swing.JComponent; import javax.swing.JScrollPane; import javax.swing.JTable; +import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; -import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; +import org.openide.ErrorManager; import org.openide.awt.StatusDisplayer; import org.openide.cookies.LineCookie; import org.openide.loaders.DataObject; import org.openide.text.Line; import org.openide.text.Line.Set; -import org.openide.windows.Mode; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; /** * * @author Tomasz Slota + * @author Andrei Badea */ public class OutputWindow extends TopComponent { + + private static final String PREFERRED_ID = "PMDOutputWindow"; + private JTable tblResults = new JTable(); private ViolationsTableModel tblMdlResults = new ViolationsTableModel(); private TableSorter tblSorter = null; @@ -57,6 +66,8 @@ public class OutputWindow extends TopComponent { /** Creates a new instance of OutputWindow */ private OutputWindow() { + setDisplayName("PMD Output"); + setLayout(new BorderLayout()); tblSorter = new TableSorter(tblMdlResults); @@ -80,6 +91,25 @@ public class OutputWindow extends TopComponent { } }); initActions(); + + tblResults.getActionMap().put("selectViolation", new AbstractAction() { + public void actionPerformed(ActionEvent e) { + int row = tblResults.getSelectedRow(); + if (row != -1) { + selectResultRow(row); + } + } + }); + tblResults.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( + KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), + "selectViolation"); + } + + public void requestActive() { + super.requestActive(); + if (tblResults != null) { + tblResults.requestFocusInWindow(); + } } /** Map F12/S-F12 to next/prev error */ @@ -126,7 +156,12 @@ public class OutputWindow extends TopComponent { return true; } - public static OutputWindow getInstance(){ + /** + * Gets default instance. Do not use directly: reserved for *.settings files only, + * i.e. deserialization routines; otherwise you could get a non-deserialized instance. + * To obtain the singleton instance, use {@link findInstance}. + */ + public static synchronized OutputWindow getDefault(){ if (instance == null){ instance = new OutputWindow(); } @@ -134,32 +169,55 @@ public class OutputWindow extends TopComponent { return instance; } - public void open() { - Mode m = WindowManager.getDefault().findMode("output"); - if (m != null) { - m.dockInto(this); + /** + * Obtain the OutputWindow_Generated instance. Never call {@link #getDefault} directly! + */ + public static synchronized OutputWindow findInstance() { + TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID); + if (win == null) { + ErrorManager.getDefault().log(ErrorManager.WARNING, + "Cannot find PMDOutputWindow component. It will not be located properly in the window system."); + return getDefault(); } - super.open(); + if (win instanceof OutputWindow) { + return (OutputWindow)win; + } + ErrorManager.getDefault().log(ErrorManager.WARNING, + "There seem to be multiple components with the '" + PREFERRED_ID + + "' ID. That is a potential source of errors and unexpected behavior."); + return getDefault(); + } + + public void promote() { + open(); + requestActive(); } protected String preferredID(){ - return "PMDOutput"; + return PREFERRED_ID; } public int getPersistenceType(){ - return PERSISTENCE_NEVER; + return PERSISTENCE_ALWAYS; + } + + /** + * Avoids serializing the properties of this top component, + * which is not really necessary. Instead, getDefault() will get called + * when the component (or actually the replacer returned by this method) + * is deserialized. + */ + public Object writeReplace() { + return new ResolvableHelper(); } public void setViolations(Fault violations[]){ tblMdlResults.setViolations(violations); if (violations.length > 0){ - SwingUtilities.invokeLater(new Runnable() { - public void run() { - selectResultRow(0); - tblResults.getSelectionModel().setSelectionInterval(0, 0); - } - }); + selectResultRow(0); + tblResults.getSelectionModel().setSelectionInterval(0, 0); + tblResults.getColumnModel().getSelectionModel().setSelectionInterval(0, 0); } } @@ -242,4 +300,13 @@ public class OutputWindow extends TopComponent { String msg = fault.getMessage(); return msg.substring(msg.indexOf(",") + 1); } + + final static class ResolvableHelper implements Serializable { + + private static final long serialVersionUID = 1L; + + public Object readResolve() { + return OutputWindow.getDefault(); + } + } } diff --git a/pmd-netbeans/src/pmd/OutputWindowSettings.xml b/pmd-netbeans/src/pmd/OutputWindowSettings.xml new file mode 100644 index 0000000000..a700a25d56 --- /dev/null +++ b/pmd-netbeans/src/pmd/OutputWindowSettings.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/pmd-netbeans/src/pmd/OutputWindowWstcref.xml b/pmd-netbeans/src/pmd/OutputWindowWstcref.xml new file mode 100644 index 0000000000..f82e4eda1d --- /dev/null +++ b/pmd-netbeans/src/pmd/OutputWindowWstcref.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pmd-netbeans/src/pmd/RunPMDAction.java b/pmd-netbeans/src/pmd/RunPMDAction.java index a3aa388f2a..48b521dedd 100644 --- a/pmd-netbeans/src/pmd/RunPMDAction.java +++ b/pmd-netbeans/src/pmd/RunPMDAction.java @@ -263,7 +263,6 @@ public class RunPMDAction extends CookieAction { */ protected void performAction( Node[] node ) { FaultRegistry.getInstance().clearRegistry(); - OutputWriter out = null; try { StatusDisplayer.getDefault().setStatusText("PMD checking for rule violations"); List list = getDataObjects(node); @@ -275,23 +274,19 @@ public class RunPMDAction extends CookieAction { else { StatusDisplayer.getDefault().setStatusText("PMD found rule violations"); } - - final OutputWindow wnd = OutputWindow.getInstance(); - wnd.setViolations(violations.toArray(new Fault[violations.size()])); - + SwingUtilities.invokeLater(new Runnable(){ public void run(){ + OutputWindow wnd = OutputWindow.findInstance(); + wnd.setViolations(violations.toArray(new Fault[violations.size()])); wnd.setDisplayName("PMD Output: found " + violations.size() + " violations"); - wnd.open(); - wnd.requestActive(); + if (violations.size() > 0 ) { + wnd.promote(); + } } }); } catch(IOException e) { ErrorManager.getDefault().notify(e); - } finally { - if (out != null) { - out.close(); - } } } diff --git a/pmd-netbeans/src/pmd/ShowOutputWindowAction.java b/pmd-netbeans/src/pmd/ShowOutputWindowAction.java new file mode 100644 index 0000000000..d0a693144e --- /dev/null +++ b/pmd-netbeans/src/pmd/ShowOutputWindowAction.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2006, the pmd-netbeans team + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ +package pmd; + +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.actions.CallableSystemAction; + +/** + * @author Andrei Badea + */ +public final class ShowOutputWindowAction extends CallableSystemAction { + + public void performAction() { + OutputWindow.findInstance().promote(); + } + + public String getName() { + return NbBundle.getMessage(ShowOutputWindowAction.class, "CTL_ShowOutputWindowAction"); + } + + protected void initialize() { + super.initialize(); + // see org.openide.util.actions.SystemAction.iconResource() javadoc for more details + putValue("noIconInMenu", Boolean.TRUE); + } + + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + protected boolean asynchronous() { + return false; + } +} diff --git a/pmd-netbeans/src/pmd/mf-layer.xml b/pmd-netbeans/src/pmd/mf-layer.xml index 75f8f09e09..b21f24e2f3 100644 --- a/pmd-netbeans/src/pmd/mf-layer.xml +++ b/pmd-netbeans/src/pmd/mf-layer.xml @@ -15,10 +15,22 @@ + + + + + + + + + + + + @@ -30,5 +42,18 @@ + + + + + + + + + + + + +