⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tree.java

📁 基于Junit的 功能和单元测试的的测试工具。只支持Swing.
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package org.uispec4j;

import junit.framework.Assert;
import junit.framework.AssertionFailedError;
import org.uispec4j.assertion.Assertion;
import org.uispec4j.utils.ArrayUtils;
import org.uispec4j.utils.ColorUtils;
import org.uispec4j.utils.Utils;

import javax.accessibility.AccessibleComponent;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Wrapper for JTree components.<p>
 * The nodes of a tree are identified using stringified paths. For instance, for the tree
 * below:
 * <pre><code>
 * root
 *   |
 *   +- child
 *   |  |
 *   |  +- subChild
 *   |
 *   +- otherChild
 *      |
 *      +- otherSubChild
 * </code></pre>
 * the "subChild" element is identified with the following path:
 * <pre><code>
 *   child/subChild
 * </code></pre>
 * Note that when defining paths the root element name is always omitted. The root
 * node path itself is denoted by an empty string ("").<p>
 * The default path separator is "/". However, this separator can be customized as follows:
 * <ul>
 * <li>By setting it on a given Tree instance using {@link Tree#setSeparator(String)}</li>
 * <li>By setting it on all new Tree instances using {@link Tree#setDefaultSeparator(String)}</li>
 * <li>By setting it on all new Tree instances using the <code>uispec4j.tree.separator</code>
 * property.</li>
 * </ul>
 * When using paths, it is also possible to use substrings from the displayed node names.
 * For instance, instead of writing:
 * <pre><code>
 *   otherChild/otherSubChild
 * </code></pre>
 * one can write:
 * <pre><code>
 *   other/sub
 * </code></pre>
 * <p/>
 * The contents of the tree can be checked with {@link #contentEquals(String)},
 * which is used as follows:
 * <pre><code>
 * assertTrue(jTree.contentEquals("root\n" +
 *                                "  child1\n" +
 *                                "    child1_1\n" +
 *                                "  child2"));
 * </code></pre>
 * <p/>
 * The conversion between the values (Strings) given in the tests and the values
 * actually displayed by the JTree renderer is performed by a dedicated
 * {@link TreeCellValueConverter}, which retrieves the graphical component that draws
 * the tree nodes and determines the displayed value accordingly.
 * A {@link DefaultTreeCellValueConverter} is used by default by the Tree component.
 */
public class Tree extends AbstractUIComponent {

  public static final String TYPE_NAME = "tree";
  public static final Class[] SWING_CLASSES = {JTree.class};
  static final String SEPARATOR_PROPERTY = "uispec4j.tree.separator";

  private JTree jTree;
  static String defaultSeparator = "/";
  private String separator;
  private TreeCellValueConverter cellValueConverter = new DefaultTreeCellValueConverter();

  private static final Pattern COLOR_PROPERTY_PATTERN =
    Pattern.compile(" #\\(.*color=([\\w]+)\\)");

  public Tree(JTree jTree) {
    this.jTree = jTree;
    this.separator = initSeparator();
  }

  private static String initSeparator() {
    String property = System.getProperty(Tree.SEPARATOR_PROPERTY);
    if ((property != null) && (property.length() > 0)) {
      return property;
    }
    return Tree.defaultSeparator;
  }

  public String getDescriptionTypeName() {
    return TYPE_NAME;
  }

  public Component getAwtComponent() {
    return jTree;
  }

  /**
   * Returns the JTree wrapped by this component.
   */
  public JTree getJTree() {
    return jTree;
  }

  /**
   * Sets the separator to be used for specifying node paths in this jTree instance.
   */
  public void setSeparator(String separator) {
    checkSeparator(separator);
    this.separator = separator;
  }

  private static void checkSeparator(String separator) {
    if (separator == null) {
      throw new IllegalArgumentException("Separator must not be null");
    }
    else if (separator.length() == 0) {
      throw new IllegalArgumentException("Separator must not be empty");
    }
  }

  /**
   * Returns the separator currently used for specifying node paths in this jTree instance.
   */
  public String getSeparator() {
    return separator;
  }

  /**
   * Sets the separator to be used for specifying node paths in new jTree instances.
   */
  public static void setDefaultSeparator(String separator) {
    checkSeparator(separator);
    defaultSeparator = separator;
  }

  /**
   * Sets a new converter for retrieving the text displayed on the tree cells.
   */
  public void setCellValueConverter(TreeCellValueConverter converter) {
    this.cellValueConverter = converter;
  }

  /**
   * Checks the nodes structure displayed by the jTree.<p>
   * The expected contents is a newline (\n) separated string where nodes are
   * indented with two-space steps.
   * For instance:
   * <code><pre>
   * assertTrue(jTree.contentEquals("root\n" +
   *                                "  child1\n" +
   *                                "    child1_1\n" +
   *                                "  child2"));
   * </pre></code>
   * Text display properties such as boldness and color can be checked using a "#(...)"
   * specifier.
   * For instance:
   * <code><pre>
   * assertTrue(jTree.contentEquals("root\n" +
   *                                "  child1 #(bold)\n" +
   *                                "    child1_1 #(bold,color=red)\n" +
   *                                "  child2"));
   * </pre></code>
   * The properties are defined as follows:
   * <ul>
   * <li>The "bold" property must be present if and only if the node text is bold</li>
   * <li>The "color" property value can be numeric ("0000ee") or approximative ("blue")
   * (see the <a href="http://www.uispec4j.org/usingcolors.html">Using colors</a> page
   * for more information)</li>
   * <li>The "bold" property, if present, must be placed before the "color" property</li>
   * </ul>
   */
  public Assertion contentEquals(final String expectedContents) {
    return new Assertion() {
      public void check() {
        String trimmedExpected = expectedContents.trim();
        Assert.assertTrue("Expected tree description should not be empty",
                          (trimmedExpected != null) && (trimmedExpected.length() > 0));
        checkContents(trimmedExpected);
      }
    };
  }

  /**
   * Checks that a node identified by the given path is present in the jTree.
   */
  public Assertion contains(final String path) {
    return new Assertion() {
      public void check() {
        getTreePath(path);
      }
    };
  }

  /**
   * Selects the root node of the jTree.
   */
  public void selectRoot() {
    jTree.setSelectionPath(new TreePath(jTree.getModel().getRoot()));
  }

  /**
   * Expands the current jTree selection with a given node.
   */
  public void addToSelection(String path) {
    jTree.addSelectionPath(getTreePath(path));
  }

  /**
   * Removes the given node from the current jTree selection.
   */
  public void removeFromSelection(String path) {
    TreePath jTreePath = getTreePath(path);
    jTree.removeSelectionPath(jTreePath);
  }

  /**
   * Expands the current jTree selection with a node identified by its position in its parent node.
   * <p>This method is preferred over {@link #addToSelection(String)} when there are several nodes
   * with the same name under a given parent.
   */
  public void addToSelection(String parentPath, int childIndex) {
    jTree.addSelectionPath(computeChildTreePath(parentPath, childIndex));
  }

  /**
   * Removes the current selection.
   */
  public void clearSelection() {
    jTree.clearSelection();
  }

  /**
   * Sets the selection on the given node.
   */
  public void select(String path) {
    jTree.clearSelection();
    jTree.setSelectionPath(getTreePath(path));
  }

  /**
   * Sets the jTree selection on a node identified by its position in its parent node.
   * <p>This method is preferred over {@link #select(String)} when there are several nodes
   * with the same name under a given parent.
   */
  public void select(String parentPath, int childIndex) {
    int childCount = getChildCount(parentPath);
    if (childIndex < 0 || childCount <= childIndex) {
      throw new RuntimeException("No child found under '" +
                                 parentPath +
                                 "' for index '" + childIndex + "'");
    }
    jTree.clearSelection();
    jTree.addSelectionPath(computeChildTreePath(parentPath, childIndex));
  }

  /**
   * Selects under a given parent all the nodes whose name contains a given substring.
   * This method will throw an exception if no the parent path was invalid or if no children
   * were found.
   */
  public void select(String parentPath, String childSubstring) {
    TreePath jTreePath = getTreePath(parentPath);
    TreeModel model = jTree.getModel();
    Object node = jTreePath.getLastPathComponent();
    List subPaths = new ArrayList();
    for (int i = 0, max = model.getChildCount(node); i < max; i++) {
      Object child = model.getChild(node, i);
      String text = getShownText(child);
      if (text.indexOf(childSubstring) >= 0) {
        subPaths.add(jTreePath.pathByAddingChild(child));
      }
    }
    if (subPaths.isEmpty()) {
      Assert.fail("No children found");
    }

    TreePath[] result = (TreePath[])subPaths.toArray(new TreePath[subPaths.size()]);
    jTree.setSelectionPaths(result);
  }

  public void select(String[] paths) {
    jTree.clearSelection();
    for (int i = 0; i < paths.length; i++) {
      String path = paths[i];
      jTree.addSelectionPath(getTreePath(path));
    }
  }

  /**
   * Simulates a user left-click on a given node.
   */
  public void click(String path) {
    TreePath jTreePath = getTreePath(path);
    jTree.setSelectionPath(jTreePath);
    clickOnTreePath(getTreePath(path), false, Key.Modifier.NONE);
  }

  /**
   * Simulates a user right-click on a given node.
   */
  public void rightClick(String path) {
    TreePath jTreePath = getTreePath(path);
    jTree.setSelectionPath(jTreePath);
    clickOnTreePath(jTreePath, true, Key.Modifier.NONE);
  }

  /**
   * Right-clicks on the first selected node.
   */
  public void rightClickInSelection() {
    TreePath selectionPath = jTree.getSelectionPath();
    Assert.assertNotNull("There is no current selection", selectionPath);
    clickOnTreePath(selectionPath, true, Key.Modifier.NONE);
  }

  public Trigger triggerClick(final String path) {
    return new Trigger() {
      public void run() throws Exception {
        click(path);
      }
    };
  }

  public Trigger triggerRightClick(final String path) {
    return new Trigger() {
      public void run() throws Exception {
        rightClick(path);
      }
    };
  }

  public Trigger triggerRightClickInSelection() {
    return new Trigger() {
      public void run() throws Exception {
        rightClickInSelection();
      }
    };
  }

  /**
   * Returns the number of children of a given node.
   */
  public int getChildCount(String path) {
    TreePath jTreePath = getTreePath(path);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -