package org.greenstone.gatherer.util; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import javax.swing.*; import javax.swing.tree.*; import org.greenstone.gatherer.util.DefaultSynchronizedTreeNode; import org.greenstone.gatherer.util.SynchronizedTreeModel; import org.greenstone.gatherer.util.SynchronizedTreeNode; public class TreeModelTest extends JFrame { /** Testing - test frame size. */ static final private Dimension SIZE = new Dimension(400,400); /** Testing - should a debug file be written. */ static private boolean debug = false; /** Testing - debug output stream. */ static private FileOutputStream output = null; /** Testing - write a message to the debug file. */ static void debug(String message) { if(debug) { try { if(output == null) { output = new FileOutputStream(new File("debug.txt")); } output.write(message.getBytes()); output.flush(); } catch (Exception error) { error.printStackTrace(); } } } /** Testing - usage message. */ static void printUsage() { System.out.println("Usage: java Test3 [-safe] [-debug]"); System.out.println(" safe - use SynchronizedTreeModel"); System.out.println(" debug - write debug messages to debug.txt file\n"); System.out.println("Actions:"); System.out.println(" 'Add Node' - Adds a new node to the selected node. Since this happens on the AWTEvent Thread it should always be safe."); System.out.println(" 'Remove Node' - Removes the selected node. Since this happens on the AWTEvent Thread it should always be safe."); System.out.println(" 'Preset Structure' - Generates a small preset structure on a seperate (dangerous) thread."); System.out.println(" 'Dangerous' - The ultimate test. Hammers the model with incessant random mutations from a separate thread."); System.exit(0); } /** Testing - creates a frame containing a JTree backed by either a normal DefaultTreeModel or a SynchronizedTreeModel depending on arguments. There are also several actions you can perform by clicking on buttons. */ static public void main(String[] args) { boolean safe = false; if(args.length <= 2) { for(int i = 0; i < args.length; i++) { String arg = args[i]; if(arg.equalsIgnoreCase("-safe")) { safe = true; } else if(arg.equalsIgnoreCase("-debug")) { debug = true; } else { printUsage(); } } } else { printUsage(); } new TreeModelTest(safe); } /** Testing - a dangerous thread which hammers the mutable tree model. */ private DangerousTask task; /** Testing - a dangerous thread which builds a preset structure. */ private DangerousTask preset_task; /** Testing - the tree model, which may be a SynchronizedTreeModel. */ private DefaultTreeModel model; /** Testing - a button for toggling the dangerous thread on and off. */ private JToggleButton dangerous_button; /** Testing - the tree used during testing. */ private JTree tree; TreeModelTest(boolean safe) { super("Testing"); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(SIZE); JPanel content_panel = (JPanel) getContentPane(); // Creation task = new DangerousTask(false); preset_task = new DangerousTask(true); if(safe) { model = new SynchronizedTreeModel(new DefaultSynchronizedTreeNode("Root")); } else { model = new DefaultTreeModel(new DefaultMutableTreeNode("Root")); } tree = new JTree(model); JPanel button_panel = new JPanel(); JButton add_button = new JButton("Add Node"); dangerous_button = new JToggleButton("Dangerous!"); dangerous_button.setSelected(false); JButton remove_button = new JButton("Remove Node"); JButton preset_button = new JButton("Preset Structure"); // Connection add_button.addActionListener(new AddListener()); dangerous_button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { if(dangerous_button.isSelected()) { task.start(); } else { task.exit = true; } } }); remove_button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { ///ystem.err.println("*** Start Remove ***"); // Get the selected node TreePath selected_path = tree.getSelectionPath(); if(selected_path != null) { DefaultMutableTreeNode old_child = (DefaultMutableTreeNode) selected_path.getLastPathComponent(); if(!old_child.isRoot()) { // Remove node. model.removeNodeFromParent(old_child); } } ///ystem.err.println("*** End Remove ***\n"); } }); preset_button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { preset_task.start(); } }); // Layout button_panel.setLayout(new GridLayout(2,2)); button_panel.add(add_button); button_panel.add(remove_button); button_panel.add(preset_button); button_panel.add(dangerous_button); content_panel.setLayout(new BorderLayout()); content_panel.add(new JScrollPane(tree), BorderLayout.CENTER); content_panel.add(button_panel, BorderLayout.SOUTH); // Display Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize(); setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2); show(); } private class AddListener implements ActionListener { public void actionPerformed(ActionEvent event) { ///ystem.err.println("*** Start Add ***"); // Get the selected node TreePath selected_path = tree.getSelectionPath(); if(selected_path != null) { DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selected_path.getLastPathComponent(); // Create a new node MutableTreeNode new_child = new DefaultSynchronizedTreeNode( String.valueOf(System.currentTimeMillis())); // Insert node. model.insertNodeInto(new_child, parent, parent.getChildCount()); } ///ystem.err.println("*** End Add ***\n"); } } private class DangerousTask extends Thread { private boolean exit = false; private boolean preset = false; DangerousTask(boolean preset) { this.preset = preset; } public void run() { if(preset) { DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); MutableTreeNode alpha = new DefaultSynchronizedTreeNode("Alpha"); MutableTreeNode beta = new DefaultSynchronizedTreeNode("Beta"); MutableTreeNode delta = new DefaultSynchronizedTreeNode("Delta"); MutableTreeNode gamma = new DefaultSynchronizedTreeNode("Gamma"); MutableTreeNode epsilon = new DefaultSynchronizedTreeNode("Epsilon"); MutableTreeNode rho = new DefaultSynchronizedTreeNode("Rho"); MutableTreeNode pi = new DefaultSynchronizedTreeNode("Pi"); MutableTreeNode xhi = new DefaultSynchronizedTreeNode("Xhi"); MutableTreeNode kappa = new DefaultSynchronizedTreeNode("Kappa"); MutableTreeNode lambda = new DefaultSynchronizedTreeNode("Lambda"); MutableTreeNode omega = new DefaultSynchronizedTreeNode("Omega");MutableTreeNode tau = new DefaultSynchronizedTreeNode("Tau"); model.insertNodeInto(alpha, root, 0); model.insertNodeInto(omega, root, 1); model.insertNodeInto(pi, root, 1); model.insertNodeInto(beta, alpha, 0); model.insertNodeInto(delta, beta, 0); model.insertNodeInto(epsilon, delta, 0); model.insertNodeInto(gamma, delta, 0); model.insertNodeInto(rho, pi, 0); model.insertNodeInto(xhi, alpha, 0); model.insertNodeInto(kappa, root, 1); debug("Root has: " + model.getChildCount(model.getRoot())); } else { exit = false; while(!exit) { // Find a random node DefaultMutableTreeNode current = (DefaultMutableTreeNode) model.getRoot(); while(Math.random() > 0.3 && model.getChildCount(current) > 0) { int index = (int)(Math.random() * (model.getChildCount(current) - 1)); current = (DefaultMutableTreeNode) model.getChild(current, index); } // Either add or remove a random node. if(Math.random() > 0.9) { ///ystem.err.println("<< Expand >>"); TreePath path = new TreePath(model.getPathToRoot(current)); tree.expandPath(path); } else if(Math.random() > 0.4 || current.isRoot()) { if(model.getChildCount(current) < 25) { ///ystem.err.println("<<< Add >>>"); // Add a new node MutableTreeNode new_child = new DefaultSynchronizedTreeNode(String.valueOf(System.currentTimeMillis())); // Insert node. model.insertNodeInto(new_child, current, model. getChildCount(current)); ///ystem.err.println("<<< >>>\n"); } } else { ///ystem.err.println("<<< Remove >>>"); // Remove node. model.removeNodeFromParent(current); ///ystem.err.println("<<< >>>\n"); } // Wait some random minute amount of time try { synchronized(this) { wait((int)(5 * Math.random()) + 1); } } catch (Exception exception) { exception.printStackTrace(); } } } } } }