/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * Copyright 2016 The ZAP Development Team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.zaproxy.zap.view; import java.awt.BorderLayout; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.border.EtchedBorder; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import org.apache.commons.lang.ArrayUtils; import org.zaproxy.zap.model.Tech; import org.zaproxy.zap.model.TechSet; /** * A {@code JPanel} that allows to display and select technologies through a check box tree. * * @see Tech * @see TechSet * @see JCheckBoxTree * @since 2.5.0 */ public class TechnologyTreePanel extends JPanel { private static final long serialVersionUID = 5514692105773714202L; private final JCheckBoxTree techTree; private final HashMap<Tech, DefaultMutableTreeNode> techToNodeMap; public TechnologyTreePanel(String nameRootNode) { setLayout(new BorderLayout()); techToNodeMap = new HashMap<>(); techTree = new JCheckBoxTree() { private static final long serialVersionUID = 1L; @Override protected void setExpandedState(TreePath path, boolean state) { // Ignore all collapse requests; collapse events will not be fired if (state) { super.setExpandedState(path, state); } } }; // Initialise the structure based on all the tech we know about TechSet ts = new TechSet(Tech.builtInTech); Iterator<Tech> iter = ts.getIncludeTech().iterator(); DefaultMutableTreeNode root = new DefaultMutableTreeNode(nameRootNode); Tech tech; DefaultMutableTreeNode parent; DefaultMutableTreeNode node; while (iter.hasNext()) { tech = iter.next(); if (tech.getParent() != null) { parent = techToNodeMap.get(tech.getParent()); } else { parent = null; } if (parent == null) { parent = root; } node = new DefaultMutableTreeNode(tech.getUiName()); parent.add(node); techToNodeMap.put(tech, node); } techTree.setModel(new DefaultTreeModel(root)); techTree.expandAll(); techTree.setCheckBoxEnabled(new TreePath(root), false); reset(); JScrollPane scrollPane = new JScrollPane(); scrollPane.setViewportView(techTree); scrollPane.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED)); add(scrollPane, BorderLayout.CENTER); } /** * Sets the technologies that should be selected, if included, and not if excluded. * * @param techSet the technologies that will be selected, if included, and not if excluded. * @see TechSet#includes(Tech) */ public void setTechSet(TechSet techSet) { Set<Tech> includedTech = techSet.getIncludeTech(); Iterator<Entry<Tech, DefaultMutableTreeNode>> iter = techToNodeMap.entrySet().iterator(); while (iter.hasNext()) { Entry<Tech, DefaultMutableTreeNode> node = iter.next(); TreePath tp = this.getPath(node.getValue()); Tech tech = node.getKey(); if (ArrayUtils.contains(Tech.builtInTopLevelTech, tech)) { techTree.check(tp, containsAnyOfTopLevelTech(includedTech, tech)); } else { techTree.check(tp, techSet.includes(tech)); } } } /** * Gets a {@code TechSet} with the technologies included, if selected, and excluded if not. * * @return a TechSet with the technologies included and excluded * @see TechSet#include(Tech) * @see TechSet#exclude(Tech) */ public TechSet getTechSet() { TechSet techSet = new TechSet(); Iterator<Entry<Tech, DefaultMutableTreeNode>> iter = techToNodeMap.entrySet().iterator(); while (iter.hasNext()) { Entry<Tech, DefaultMutableTreeNode> node = iter.next(); TreePath tp = this.getPath(node.getValue()); Tech tech = node.getKey(); if (techTree.isSelectedFully(tp)) { techSet.include(tech); } else { techSet.exclude(tech); } } return techSet; } /** * Resets the selection the panel by selecting all technologies. */ public void reset() { techTree.checkSubTree(techTree.getPathForRow(0), true); } private TreePath getPath(TreeNode node) { List<TreeNode> list = new ArrayList<>(); // Add all nodes to list while (node != null) { list.add(node); node = node.getParent(); } Collections.reverse(list); // Convert array of nodes to TreePath return new TreePath(list.toArray()); } private static boolean containsAnyOfTopLevelTech(Set<Tech> techSet, Tech topLevelTech) { for (Tech tech : techSet) { if (topLevelTech.equals(tech.getParent())) { return true; } } return false; } }