1 | /**
|
---|
2 | *#########################################################################
|
---|
3 | *
|
---|
4 | * A component of the Gatherer application, part of the Greenstone digital
|
---|
5 | * library suite from the New Zealand Digital Library Project at the
|
---|
6 | * University of Waikato, New Zealand.
|
---|
7 | *
|
---|
8 | * <BR><BR>
|
---|
9 | *
|
---|
10 | * Author: John Thompson, Greenstone Digital Library, University of Waikato
|
---|
11 | *
|
---|
12 | * <BR><BR>
|
---|
13 | *
|
---|
14 | * Copyright (C) 1999 New Zealand Digital Library Project
|
---|
15 | *
|
---|
16 | * <BR><BR>
|
---|
17 | *
|
---|
18 | * This program is free software; you can redistribute it and/or modify
|
---|
19 | * it under the terms of the GNU General Public License as published by
|
---|
20 | * the Free Software Foundation; either version 2 of the License, or
|
---|
21 | * (at your option) any later version.
|
---|
22 | *
|
---|
23 | * <BR><BR>
|
---|
24 | *
|
---|
25 | * This program is distributed in the hope that it will be useful,
|
---|
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
28 | * GNU General Public License for more details.
|
---|
29 | *
|
---|
30 | * <BR><BR>
|
---|
31 | *
|
---|
32 | * You should have received a copy of the GNU General Public License
|
---|
33 | * along with this program; if not, write to the Free Software
|
---|
34 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
35 | *########################################################################
|
---|
36 | */
|
---|
37 | package org.greenstone.gatherer.util;
|
---|
38 |
|
---|
39 | import java.awt.*;
|
---|
40 | import java.awt.event.*;
|
---|
41 | import java.io.*;
|
---|
42 | import java.util.*;
|
---|
43 | import javax.swing.*;
|
---|
44 | import javax.swing.tree.*;
|
---|
45 | import org.greenstone.gatherer.gui.GLIButton;
|
---|
46 | import org.greenstone.gatherer.util.DefaultSynchronizedTreeNode;
|
---|
47 | import org.greenstone.gatherer.util.SynchronizedTreeModel;
|
---|
48 | import org.greenstone.gatherer.util.SynchronizedTreeNode;
|
---|
49 |
|
---|
50 | public class TreeModelTest
|
---|
51 | extends JFrame {
|
---|
52 |
|
---|
53 | /** Testing - test frame size. */
|
---|
54 | static final private Dimension SIZE = new Dimension(400,400);
|
---|
55 |
|
---|
56 | /** Testing - should a debug file be written. */
|
---|
57 | static private boolean debug = false;
|
---|
58 |
|
---|
59 | /** Testing - debug output stream. */
|
---|
60 | static private FileOutputStream output = null;
|
---|
61 |
|
---|
62 | /** Testing - write a message to the debug file. */
|
---|
63 | static void debug(String message) {
|
---|
64 | if(debug) {
|
---|
65 | try {
|
---|
66 | if(output == null) {
|
---|
67 | output = new FileOutputStream(new File("debug.txt"));
|
---|
68 | }
|
---|
69 | output.write(message.getBytes());
|
---|
70 | output.flush();
|
---|
71 | }
|
---|
72 | catch (Exception error) {
|
---|
73 | error.printStackTrace();
|
---|
74 | }
|
---|
75 | }
|
---|
76 | }
|
---|
77 |
|
---|
78 | /** Testing - usage message. */
|
---|
79 | static void printUsage() {
|
---|
80 | System.out.println("Usage: java Test3 [-safe] [-debug]");
|
---|
81 | System.out.println(" safe - use SynchronizedTreeModel");
|
---|
82 | System.out.println(" debug - write debug messages to debug.txt file\n");
|
---|
83 | System.out.println("Actions:");
|
---|
84 | 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.");
|
---|
85 | System.out.println(" 'Remove Node' - Removes the selected node. Since this happens on the AWTEvent Thread it should always be safe.");
|
---|
86 | System.out.println(" 'Preset Structure' - Generates a small preset structure on a seperate (dangerous) thread.");
|
---|
87 | System.out.println(" 'Dangerous' - The ultimate test. Hammers the model with incessant random mutations from a separate thread.");
|
---|
88 | System.exit(0);
|
---|
89 | }
|
---|
90 | /** 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. */
|
---|
91 | static public void main(String[] args) {
|
---|
92 | boolean safe = false;
|
---|
93 | if(args.length <= 2) {
|
---|
94 | for(int i = 0; i < args.length; i++) {
|
---|
95 | String arg = args[i];
|
---|
96 | if(arg.equalsIgnoreCase("-safe")) {
|
---|
97 | safe = true;
|
---|
98 | }
|
---|
99 | else if(arg.equalsIgnoreCase("-debug")) {
|
---|
100 | debug = true;
|
---|
101 | }
|
---|
102 | else {
|
---|
103 | printUsage();
|
---|
104 | }
|
---|
105 | }
|
---|
106 | }
|
---|
107 | else {
|
---|
108 | printUsage();
|
---|
109 | }
|
---|
110 | new TreeModelTest(safe);
|
---|
111 | }
|
---|
112 |
|
---|
113 | /** Testing - a dangerous thread which hammers the mutable tree model. */
|
---|
114 | private DangerousTask task;
|
---|
115 |
|
---|
116 | /** Testing - a dangerous thread which builds a preset structure. */
|
---|
117 | private DangerousTask preset_task;
|
---|
118 |
|
---|
119 | /** Testing - the tree model, which may be a SynchronizedTreeModel. */
|
---|
120 | private DefaultTreeModel model;
|
---|
121 |
|
---|
122 | /** Testing - a button for toggling the dangerous thread on and off. */
|
---|
123 | private JToggleButton dangerous_button;
|
---|
124 |
|
---|
125 | /** Testing - the tree used during testing. */
|
---|
126 | private JTree tree;
|
---|
127 |
|
---|
128 | TreeModelTest(boolean safe) {
|
---|
129 | super("Testing");
|
---|
130 | setDefaultCloseOperation(EXIT_ON_CLOSE);
|
---|
131 | setSize(SIZE);
|
---|
132 | JPanel content_panel = (JPanel) getContentPane();
|
---|
133 |
|
---|
134 | // Creation
|
---|
135 | task = new DangerousTask(false);
|
---|
136 | preset_task = new DangerousTask(true);
|
---|
137 |
|
---|
138 | if(safe) {
|
---|
139 | model = new SynchronizedTreeModel(new DefaultSynchronizedTreeNode("Root"));
|
---|
140 | }
|
---|
141 | else {
|
---|
142 | model = new DefaultTreeModel(new DefaultMutableTreeNode("Root"));
|
---|
143 | }
|
---|
144 |
|
---|
145 | tree = new JTree(model);
|
---|
146 |
|
---|
147 | JPanel button_panel = new JPanel();
|
---|
148 | JButton add_button = new GLIButton("Add Node");
|
---|
149 | add_button.setMnemonic(KeyEvent.VK_A);
|
---|
150 | dangerous_button = new JToggleButton("Dangerous!");
|
---|
151 | dangerous_button.setSelected(false);
|
---|
152 | JButton remove_button = new GLIButton("Remove Node");
|
---|
153 | remove_button.setMnemonic(KeyEvent.VK_R);
|
---|
154 | JButton preset_button = new GLIButton("Preset Structure");
|
---|
155 | preset_button.setMnemonic(KeyEvent.VK_P);
|
---|
156 |
|
---|
157 | // Connection
|
---|
158 | add_button.addActionListener(new AddListener());
|
---|
159 | dangerous_button.addActionListener(new ActionListener() {
|
---|
160 | public void actionPerformed(ActionEvent event) {
|
---|
161 | if(dangerous_button.isSelected()) {
|
---|
162 | task.start();
|
---|
163 | }
|
---|
164 | else {
|
---|
165 | task.exit = true;
|
---|
166 | }
|
---|
167 | }
|
---|
168 | });
|
---|
169 | remove_button.addActionListener(new ActionListener() {
|
---|
170 | public void actionPerformed(ActionEvent event) {
|
---|
171 | ///ystem.err.println("*** Start Remove ***");
|
---|
172 | // Get the selected node
|
---|
173 | TreePath selected_path = tree.getSelectionPath();
|
---|
174 | if(selected_path != null) {
|
---|
175 | DefaultMutableTreeNode old_child = (DefaultMutableTreeNode) selected_path.getLastPathComponent();
|
---|
176 | if(!old_child.isRoot()) {
|
---|
177 | // Remove node.
|
---|
178 | model.removeNodeFromParent(old_child);
|
---|
179 | }
|
---|
180 | }
|
---|
181 | ///ystem.err.println("*** End Remove ***\n");
|
---|
182 | }
|
---|
183 | });
|
---|
184 | preset_button.addActionListener(new ActionListener() {
|
---|
185 | public void actionPerformed(ActionEvent event) {
|
---|
186 | preset_task.start();
|
---|
187 | }
|
---|
188 | });
|
---|
189 |
|
---|
190 | // Layout
|
---|
191 | button_panel.setLayout(new GridLayout(2,2));
|
---|
192 | button_panel.add(add_button);
|
---|
193 | button_panel.add(remove_button);
|
---|
194 | button_panel.add(preset_button);
|
---|
195 | button_panel.add(dangerous_button);
|
---|
196 |
|
---|
197 | content_panel.setLayout(new BorderLayout());
|
---|
198 | content_panel.add(new JScrollPane(tree), BorderLayout.CENTER);
|
---|
199 | content_panel.add(button_panel, BorderLayout.SOUTH);
|
---|
200 |
|
---|
201 | // Display
|
---|
202 | Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
|
---|
203 | setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
|
---|
204 | show();
|
---|
205 | }
|
---|
206 |
|
---|
207 | private class AddListener
|
---|
208 | implements ActionListener {
|
---|
209 | public void actionPerformed(ActionEvent event) {
|
---|
210 | ///ystem.err.println("*** Start Add ***");
|
---|
211 | // Get the selected node
|
---|
212 | TreePath selected_path = tree.getSelectionPath();
|
---|
213 | if(selected_path != null) {
|
---|
214 | DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selected_path.getLastPathComponent();
|
---|
215 | // Create a new node
|
---|
216 | MutableTreeNode new_child = new DefaultSynchronizedTreeNode( String.valueOf(System.currentTimeMillis()));
|
---|
217 | // Insert node.
|
---|
218 | model.insertNodeInto(new_child, parent, parent.getChildCount());
|
---|
219 | }
|
---|
220 | ///ystem.err.println("*** End Add ***\n");
|
---|
221 | }
|
---|
222 | }
|
---|
223 |
|
---|
224 | private class DangerousTask
|
---|
225 | extends Thread {
|
---|
226 |
|
---|
227 | private boolean exit = false;
|
---|
228 | private boolean preset = false;
|
---|
229 |
|
---|
230 | DangerousTask(boolean preset) {
|
---|
231 | this.preset = preset;
|
---|
232 | }
|
---|
233 |
|
---|
234 | public void run() {
|
---|
235 | if(preset) {
|
---|
236 | DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
|
---|
237 | MutableTreeNode alpha = new DefaultSynchronizedTreeNode("Alpha");
|
---|
238 | MutableTreeNode beta = new DefaultSynchronizedTreeNode("Beta");
|
---|
239 | MutableTreeNode delta = new DefaultSynchronizedTreeNode("Delta");
|
---|
240 | MutableTreeNode gamma = new DefaultSynchronizedTreeNode("Gamma");
|
---|
241 | MutableTreeNode epsilon = new DefaultSynchronizedTreeNode("Epsilon");
|
---|
242 | MutableTreeNode rho = new DefaultSynchronizedTreeNode("Rho");
|
---|
243 | MutableTreeNode pi = new DefaultSynchronizedTreeNode("Pi");
|
---|
244 | MutableTreeNode xhi = new DefaultSynchronizedTreeNode("Xhi");
|
---|
245 | MutableTreeNode kappa = new DefaultSynchronizedTreeNode("Kappa");
|
---|
246 | MutableTreeNode lambda = new DefaultSynchronizedTreeNode("Lambda");
|
---|
247 | MutableTreeNode omega = new DefaultSynchronizedTreeNode("Omega");MutableTreeNode tau = new DefaultSynchronizedTreeNode("Tau");
|
---|
248 |
|
---|
249 | model.insertNodeInto(alpha, root, 0);
|
---|
250 | model.insertNodeInto(omega, root, 1);
|
---|
251 | model.insertNodeInto(pi, root, 1);
|
---|
252 |
|
---|
253 | model.insertNodeInto(beta, alpha, 0);
|
---|
254 | model.insertNodeInto(delta, beta, 0);
|
---|
255 | model.insertNodeInto(epsilon, delta, 0);
|
---|
256 | model.insertNodeInto(gamma, delta, 0);
|
---|
257 | model.insertNodeInto(rho, pi, 0);
|
---|
258 | model.insertNodeInto(xhi, alpha, 0);
|
---|
259 | model.insertNodeInto(kappa, root, 1);
|
---|
260 |
|
---|
261 | debug("Root has: " + model.getChildCount(model.getRoot()));
|
---|
262 | }
|
---|
263 | else {
|
---|
264 | exit = false;
|
---|
265 | while(!exit) {
|
---|
266 | // Find a random node
|
---|
267 | DefaultMutableTreeNode current = (DefaultMutableTreeNode) model.getRoot();
|
---|
268 | while(Math.random() > 0.3 && model.getChildCount(current) > 0) {
|
---|
269 | int index = (int)(Math.random() * (model.getChildCount(current) - 1));
|
---|
270 | current = (DefaultMutableTreeNode) model.getChild(current, index);
|
---|
271 | }
|
---|
272 | // Either add or remove a random node.
|
---|
273 | if(Math.random() > 0.9) {
|
---|
274 | ///ystem.err.println("<< Expand >>");
|
---|
275 | TreePath path = new TreePath(model.getPathToRoot(current));
|
---|
276 | tree.expandPath(path);
|
---|
277 | }
|
---|
278 | else if(Math.random() > 0.4 || current.isRoot()) {
|
---|
279 | if(model.getChildCount(current) < 25) {
|
---|
280 | ///ystem.err.println("<<< Add >>>");
|
---|
281 | // Add a new node
|
---|
282 | MutableTreeNode new_child = new DefaultSynchronizedTreeNode(String.valueOf(System.currentTimeMillis()));
|
---|
283 | // Insert node.
|
---|
284 | model.insertNodeInto(new_child, current, model. getChildCount(current));
|
---|
285 | ///ystem.err.println("<<< >>>\n");
|
---|
286 | }
|
---|
287 | }
|
---|
288 | else {
|
---|
289 | ///ystem.err.println("<<< Remove >>>");
|
---|
290 | // Remove node.
|
---|
291 | model.removeNodeFromParent(current);
|
---|
292 | ///ystem.err.println("<<< >>>\n");
|
---|
293 | }
|
---|
294 |
|
---|
295 | // Wait some random minute amount of time
|
---|
296 | try {
|
---|
297 | synchronized(this) {
|
---|
298 | wait((int)(5 * Math.random()) + 1);
|
---|
299 | }
|
---|
300 | } catch (Exception exception) {
|
---|
301 | exception.printStackTrace();
|
---|
302 | }
|
---|
303 | }
|
---|
304 | }
|
---|
305 | }
|
---|
306 | }
|
---|
307 | }
|
---|