Author: pmouawad
Date: Sat Nov 18 13:23:38 2017
New Revision: 1815663

URL: http://svn.apache.org/viewvc?rev=1815663&view=rev
Log:
Bug 61776 - View Results Tree: Expansion of "Add expand/collapse" all menu in 
render XML view
Contributed by Maxime Chassagneux and Grahama Russell
This closes #329
This closes #294
Bugzilla Id: 61776

Modified:
    jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsXML.java
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
    jmeter/trunk/xdocs/changes.xml
    jmeter/trunk/xdocs/usermanual/component_reference.xml

Modified: 
jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsXML.java
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsXML.java?rev=1815663&r1=1815662&r2=1815663&view=diff
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsXML.java 
(original)
+++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsXML.java 
Sat Nov 18 13:23:38 2017
@@ -21,16 +21,27 @@ package org.apache.jmeter.visualizers;
 
 import java.awt.Component;
 import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
 import java.io.ByteArrayInputStream;
 import java.io.StringWriter;
+import java.util.Enumeration;
+import java.util.function.Consumer;
 
+import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
 import javax.swing.JScrollPane;
 import javax.swing.JTree;
+import javax.swing.SwingUtilities;
 import javax.swing.ToolTipManager;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
 import javax.swing.tree.TreeSelectionModel;
 
 import org.apache.jmeter.samplers.SampleResult;
@@ -49,9 +60,9 @@ public class RenderAsXML extends Sampler
 
     private static final Logger log = 
LoggerFactory.getLogger(RenderAsXML.class);
 
-    private static final byte[] XML_PFX = {'<','?','x','m','l',' '};//"<?xml "
+    private static final byte[] XML_PFX = {'<', '?', 'x', 'm', 'l', ' 
'};//"<?xml "
 
-    public RenderAsXML(){
+    public RenderAsXML() {
         activateSearchExtension = false; // TODO work out how to search the 
XML pane
     }
 
@@ -66,8 +77,8 @@ public class RenderAsXML extends Sampler
         results.setCaretPosition(0);
         byte[] source = res.getResponseData();
         final ByteArrayInputStream baIS = new ByteArrayInputStream(source);
-        for(int i=0; i<source.length-XML_PFX.length; i++){
-            if (JOrphanUtils.startsWith(source, XML_PFX, i)){
+        for (int i = 0; i < source.length - XML_PFX.length; i++) {
+            if (JOrphanUtils.startsWith(source, XML_PFX, i)) {
                 baIS.skip(i);// NOSONAR Skip the leading bytes (if any)
                 break;
             }
@@ -78,12 +89,14 @@ public class RenderAsXML extends Sampler
         org.w3c.dom.Document document = tidy.parseDOM(baIS, null);
         document.normalize();
         if (tidy.getParseErrors() > 0) {
-            showErrorMessageDialog(sw.toString(),
+            showErrorMessageDialog(
+                    sw.toString(),
                     "Tidy: " + tidy.getParseErrors() + " errors, " + 
tidy.getParseWarnings() + " warnings",
                     JOptionPane.WARNING_MESSAGE);
         }
 
         JPanel domTreePanel = new DOMTreePanel(document);
+        new ExpandPopupMenu().add(domTreePanel);
         resultsScrollPane.setViewportView(domTreePanel);
     }
 
@@ -96,18 +109,70 @@ public class RenderAsXML extends Sampler
         resultsScrollPane.setViewportView(null); // clear result tab on Ctrl-E
     }
 
+    private static class ExpandPopupMenu extends JPopupMenu implements 
ActionListener {
+
+        private static final long serialVersionUID = 1L;
+        private JMenuItem expand;
+        private JMenuItem collapse;
+        private JTree tree;
+
+        ExpandPopupMenu() {
+            expand = new 
JMenuItem(JMeterUtils.getResString("menu_expand_all"));
+            expand.addActionListener(this);
+            add(expand);
+            collapse = new 
JMenuItem(JMeterUtils.getResString("menu_collapse_all"));
+            collapse.addActionListener(this);
+            add(collapse);
+        }
+
+        void setTree(JTree tree) {
+            this.tree = tree;
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            if (e.getSource() == expand) {
+                expandAll(tree.getSelectionPath());
+            }
+            if (e.getSource() == collapse) {
+                collapseAll(tree.getSelectionPath());
+            }
+        }
+
+        private void collapseAll(TreePath parent) {
+            applyToChildren(parent, this::collapseAll);
+            tree.collapsePath(parent);
+        }
+
+        private void expandAll(TreePath parent) {
+            applyToChildren(parent, this::expandAll);
+            tree.expandPath(parent);
+        }
+
+        private void applyToChildren(TreePath parent, Consumer<TreePath> 
method) {
+            TreeNode node = ((TreeNode) parent.getLastPathComponent());
+            Enumeration<?> e = node.children();
+            while (e.hasMoreElements()) {
+                TreeNode n = (TreeNode) e.nextElement();
+                TreePath path = parent.pathByAddingChild(n);
+                method.accept(path);
+            }
+        }
+    }
+
     /*
      *
      * A Dom tree panel for to display response as tree view author <a
-     * href="mailto:[email protected]";>Dave Maung</a> 
+     * href="mailto:[email protected]";>Dave Maung</a>
      * TODO implement to find any nodes in the tree using TreePath.
      *
      */
-    private static class DOMTreePanel extends JPanel {
+    private static class DOMTreePanel extends JPanel implements MouseListener {
 
         private static final long serialVersionUID = 6871690021183779153L;
 
         private JTree domJTree;
+        private ExpandPopupMenu popupMenu;
 
         public DOMTreePanel(org.w3c.dom.Document document) {
             super(new GridLayout(1, 0));
@@ -115,9 +180,11 @@ public class RenderAsXML extends Sampler
                 Node firstElement = getFirstElement(document);
                 DefaultMutableTreeNode top = new 
XMLDefaultMutableTreeNode(firstElement);
                 domJTree = new JTree(top);
-
                 
domJTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
                 domJTree.setShowsRootHandles(true);
+                domJTree.addMouseListener(this);
+                popupMenu = new ExpandPopupMenu();
+                popupMenu.setTree(domJTree);
                 JScrollPane domJScrollPane = new JScrollPane(domJTree);
                 domJTree.setAutoscrolls(true);
                 this.add(domJScrollPane);
@@ -126,7 +193,6 @@ public class RenderAsXML extends Sampler
             } catch (SAXException e) {
                 log.warn("Error trying to parse document", e);
             }
-
         }
 
         /**
@@ -134,7 +200,6 @@ public class RenderAsXML extends Sampler
          * We let user insert them however in DOMTreeView, we don't display 
them.
          *
          * @param parent {@link Node}
-         * @return
          */
         private Node getFirstElement(Node parent) {
             NodeList childNodes = parent.getChildNodes();
@@ -142,7 +207,7 @@ public class RenderAsXML extends Sampler
             for (int i = 0; i < childNodes.getLength(); i++) {
                 Node childNode = childNodes.item(i);
                 toReturn = childNode;
-                if (childNode.getNodeType() == Node.ELEMENT_NODE){
+                if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                     break;
                 }
 
@@ -154,16 +219,19 @@ public class RenderAsXML extends Sampler
          * This class is to view as tooltext. This is very useful, when the
          * contents has long string and does not fit in the view. it will also
          * automatically wrap line for each 100 characters since tool tip
-         * support html. 
+         * support html.
          */
         private static class DomTreeRenderer extends DefaultTreeCellRenderer {
 
             private static final long serialVersionUID = 240210061375790195L;
 
             @Override
-            public Component getTreeCellRendererComponent(JTree tree, Object 
value, boolean sel, boolean expanded,
+            public Component getTreeCellRendererComponent(
+                    JTree tree, Object value, boolean sel, boolean expanded,
                     boolean leaf, int row, boolean phasFocus) {
-                super.getTreeCellRendererComponent(tree, value, sel, expanded, 
leaf, row, phasFocus);
+
+                super.getTreeCellRendererComponent(
+                        tree, value, sel, expanded, leaf, row, phasFocus);
 
                 DefaultMutableTreeNode valueTreeNode = 
(DefaultMutableTreeNode) value;
                 setToolTipText(getHTML(valueTreeNode.toString(), "<br>", 
100)); // $NON-NLS-1$
@@ -172,11 +240,6 @@ public class RenderAsXML extends Sampler
 
             /**
              * get the html
-             *
-             * @param str
-             * @param separator
-             * @param maxChar
-             * @return
              */
             private String getHTML(String str, String separator, int maxChar) {
                 StringBuilder strBuf = new StringBuilder("<html><body 
bgcolor=\"yellow\"><b>"); // $NON-NLS-1$
@@ -197,26 +260,58 @@ public class RenderAsXML extends Sampler
             private String encode(char c) {
                 String toReturn = String.valueOf(c);
                 switch (c) {
-                case '<': // $NON-NLS-1$
-                    toReturn = "&lt;"; // $NON-NLS-1$
-                    break;
-                case '>': // $NON-NLS-1$
-                    toReturn = "&gt;"; // $NON-NLS-1$
-                    break;
-                case '\'': // $NON-NLS-1$
-                    toReturn = "&apos;"; // $NON-NLS-1$
-                    break;
-                case '\"': // $NON-NLS-1$
-                    toReturn = "&quot;"; // $NON-NLS-1$
-                    break;
-                default:
-                    // ignored
-                    break;
+                    case '<': // $NON-NLS-1$
+                        toReturn = "&lt;"; // $NON-NLS-1$
+                        break;
+                    case '>': // $NON-NLS-1$
+                        toReturn = "&gt;"; // $NON-NLS-1$
+                        break;
+                    case '\'': // $NON-NLS-1$
+                        toReturn = "&apos;"; // $NON-NLS-1$
+                        break;
+                    case '\"': // $NON-NLS-1$
+                        toReturn = "&quot;"; // $NON-NLS-1$
+                        break;
+                    default:
+                        // ignored
+                        break;
 
                 }
                 return toReturn;
             }
         }
+
+        @Override
+        public void mouseClicked(MouseEvent e) {
+            if (SwingUtilities.isRightMouseButton(e)) {
+                int x = e.getX();
+                int y = e.getY();
+                JTree tree = (JTree) e.getSource();
+
+                int rowIndex = tree.getClosestRowForLocation(x, y);
+                if (rowIndex > -1) {
+                    tree.setSelectionRow(rowIndex);
+                    popupMenu.show(tree, x, y);
+                }
+            }
+        }
+
+        @Override
+        public void mousePressed(MouseEvent e) {
+        }
+
+        @Override
+        public void mouseReleased(MouseEvent e) {
+        }
+
+        @Override
+        public void mouseEntered(MouseEvent e) {
+        }
+
+        @Override
+        public void mouseExited(MouseEvent e) {
+        }
+
     }
 
     private static void showErrorMessageDialog(String message, String title, 
int messageType) {

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1815663&r1=1815662&r2=1815663&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties 
(original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Sat 
Nov 18 13:23:38 2017
@@ -677,9 +677,11 @@ md5hex_assertion_title=MD5Hex Assertion
 mechanism=Mechanism
 menu_assertions=Assertions
 menu_collapse_all=Collapse All
+menu_collapse_all_from_selected_node=Collapse All From Selected Node
 menu_config_element=Config Element
 menu_edit=Edit
 menu_expand_all=Expand All
+menu_expand_all_from_selected_node=Expand All From Selected Node
 menu_fragments=Test Fragment
 menu_generative_controller=Sampler
 menu_listener=Listener

Modified: 
jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1815663&r1=1815662&r2=1815663&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties 
(original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties 
Sat Nov 18 13:23:38 2017
@@ -667,9 +667,11 @@ md5hex_assertion_title=Assertion MD5Hex
 mechanism=M\u00E9canisme
 menu_assertions=Assertions
 menu_collapse_all=R\u00E9duire tout
+menu_collapse_all_from_selected_node=R\u00E9duire tout \u00E0 partir du noeud 
s\u00E9lection\u00E9
 menu_config_element=Configurations
 menu_edit=Editer
 menu_expand_all=Etendre tout
+menu_expand_all_from_selected_node=Etendre tout \u00E0 partir du noeud 
s\u00E9lection\u00E9
 menu_fragments=Fragment d'\u00E9l\u00E9ments
 menu_generative_controller=Echantillons
 menu_listener=R\u00E9cepteurs

Modified: jmeter/trunk/xdocs/changes.xml
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1815663&r1=1815662&r2=1815663&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Sat Nov 18 13:23:38 2017
@@ -114,6 +114,7 @@ Summary
 <ul>
     <li><bug>57760</bug>View Results Tree : Cookie Header is wrongly shown as 
empty(no cookies) when viewing a recorder Sample Result. Contributed by Ubik 
Load Pack (support at ubikloadpack.com)</li>
     <li><bug>61769</bug>View Results Tree: Use syntax highlighter in XPath 
Tester, JSON Path Tester and CSS/JQuery Tester. Contributed by Ubik Load Pack 
(support at ubikloadpack.com)</li>
+    <li><bug>61776</bug>View Results Tree: Expansion of <code>Add 
expand/collapse all</code> menu in render XML view. Contributed by Maxime 
Chassagneux and Graham Russell</li>
 </ul>
 
 <h3>Timers, Assertions, Config, Pre- &amp; Post-Processors</h3>

Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1815663&r1=1815662&r2=1815663&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/component_reference.xml Sat Nov 18 13:23:38 
2017
@@ -2794,8 +2794,8 @@ are part of the test plan.</p></descript
 <component name="View Results Tree" index="&sect-num;.3.6" width="910" 
height="659" screenshot="view_results_tree.png">
 <description>
 <note>
-View Results Tree MUST NOT BE USED during load test as it consumes a lot of 
resources (memory and CPU). Use it only for either functional testing or 
-during Test Plan debugging and Validation.
+View Results Tree MUST NOT BE USED during load test as it consumes a lot of 
resources (memory and CPU).
+Use it only for either functional testing or during Test Plan debugging and 
Validation.
 </note>
 The View Results Tree shows a tree of all sample responses, allowing you to 
view the
 response for any sample.  In addition to showing the response, you can see the 
time it took to get
@@ -2895,8 +2895,9 @@ video/
 </source>
 <br/></td></tr>
 <tr><td><code>XML</code></td>
-<td>The <i>XML view</i> will show response in tree style. 
+<td>The <i>XML view</i> will show response in tree style.
 Any DTD nodes or Prolog nodes will not show up in tree; however, response may 
contain those nodes.
+You can right-click on any node and expand or collapse all nodes below it.
 <br/></td></tr>
 <tr><td><code>XPath Tester</code></td>
 <td>The <i>XPath Tester</i> only works for text responses. It shows the plain 
text in the upper panel.


Reply via email to