001: /*
002: * Jacareto Copyright (c) 2002-2005
003: * Applied Computer Science Research Group, Darmstadt University of
004: * Technology, Institute of Mathematics & Computer Science,
005: * Ludwigsburg University of Education, and Computer Based
006: * Learning Research Group, Aachen University. All rights reserved.
007: *
008: * Jacareto is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * Jacareto is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public
019: * License along with Jacareto; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: package jacareto.cleverphl.gui;
025:
026: import jacareto.cleverphl.session.Session;
027: import jacareto.comp.Components;
028: import jacareto.comp.ComponentsEvent;
029: import jacareto.comp.ComponentsListener;
030: import jacareto.comp.select.ComponentSelection;
031: import jacareto.comp.select.ComponentSelectionEvent;
032: import jacareto.comp.select.ComponentSelectionListener;
033: import jacareto.system.Environment;
034: import jacareto.system.Language;
035: import jacareto.test.Test;
036:
037: import org.apache.log4j.Logger;
038:
039: import java.awt.Component;
040: import java.awt.Insets;
041:
042: import java.util.Enumeration;
043: import java.util.Hashtable;
044: import java.util.Iterator;
045: import java.util.Vector;
046:
047: import javax.swing.JTree;
048: import javax.swing.event.TreeModelEvent;
049: import javax.swing.event.TreeModelListener;
050: import javax.swing.event.TreeSelectionEvent;
051: import javax.swing.event.TreeSelectionListener;
052: import javax.swing.tree.DefaultMutableTreeNode;
053: import javax.swing.tree.TreePath;
054:
055: /**
056: * The JTree displaying the components tree.
057: *
058: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
059: * @version 1.0
060: */
061: public class ComponentsTreeVisualization extends JTree implements
062: ComponentsListener, TreeModelListener,
063: ComponentSelectionListener {
064: private Components components;
065: private ComponentSelection componentSelection;
066: private Session session;
067: private Logger logger;
068: private Language language;
069: private ComponentTree componentTree;
070:
071: /** The vector of the (sub)tests of the tree elements to test. */
072: private Vector tests;
073:
074: /** Whether ot not this instance listens to component selection changes. */
075: private boolean listenToComponentSelectionChanges;
076:
077: /** Whether ot not this instance listens to tree selection changes. */
078: private boolean listenToTreeSelectionChanges;
079:
080: /** The internal listener. */
081: private ComponentsTreeListener componentsTreeListener;
082:
083: /**
084: * Creates a new components tree visualization of the specified components.
085: *
086: * @param env DOCUMENT ME!
087: * @param session the actual session
088: * @param components the components
089: */
090: public ComponentsTreeVisualization(Environment env,
091: Session session, Components components) {
092: super ();
093:
094: this .logger = env.getLogger();
095: this .language = env.getLanguage();
096: this .components = components;
097: this .componentSelection = components.getComponentSelection();
098: componentSelection.addComponentSelectionListener(this );
099: this .session = session;
100: components.addComponentsListener(this );
101: tests = new Vector();
102: componentsTreeListener = new ComponentsTreeListener();
103: this .getSelectionModel().addTreeSelectionListener(
104: componentsTreeListener);
105:
106: listenToComponentSelectionChanges = true;
107: listenToTreeSelectionChanges = true;
108: updateTree();
109: }
110:
111: public void updateTree() {
112: if (componentTree != null) {
113: listenToTreeSelectionChanges = false;
114: clearSelection();
115: listenToTreeSelectionChanges = true;
116: getModel().removeTreeModelListener(this );
117: }
118:
119: componentTree = new ComponentTree(components);
120: this .setModel(componentTree.createTreeModel());
121: this .getModel().addTreeModelListener(this );
122:
123: // validate ();
124: // repaint ();
125: }
126:
127: /**
128: * Called when the component tree has changed.
129: *
130: * @param event DOCUMENT ME!
131: */
132: public void componentTreeChanged(ComponentsEvent event) {
133: updateTree();
134: }
135:
136: /**
137: * Called when a user defined name has been set.
138: *
139: * @param event DOCUMENT ME!
140: */
141: public void userDefinedNameSet(ComponentsEvent event) {
142: }
143:
144: /**
145: * Returns the insets.
146: *
147: * @return the insets.
148: */
149: public Insets getInsets() {
150: return new Insets(5, 5, 5, 5);
151: }
152:
153: /**
154: * Inserts tests into the record of the actual session for the selected tree paths.
155: *
156: * @param isRecursive DOCUMENT ME!
157: * @param defaultCorrect DOCUMENT ME!
158: * @param defaultIgnore DOCUMENT ME!
159: */
160: public void insertTests(boolean isRecursive,
161: boolean defaultCorrect, boolean defaultIgnore) {
162: TreePath[] tp = getSelectionPaths();
163:
164: if (tp != null) {
165: traverseTreeForTestInsertion((DefaultMutableTreeNode) tp[0]
166: .getLastPathComponent(), isRecursive,
167: defaultCorrect, defaultIgnore);
168:
169: for (int i = 1; i < tp.length; i++) {
170: if (!tp[i].isDescendant(tp[i - 1])) {
171: traverseTreeForTestInsertion(
172: (DefaultMutableTreeNode) tp[i]
173: .getLastPathComponent(),
174: isRecursive, defaultCorrect, defaultIgnore);
175: }
176: }
177: }
178: }
179:
180: /**
181: * Traverses a (sub)tree of components with <code>node</code> as root element and inserts this
182: * tree as a tree of tests in the actual sessions record.
183: *
184: * @param node of the component tree for which to insert the tests
185: * @param isRecursive DOCUMENT ME!
186: * @param defaultCorrect DOCUMENT ME!
187: * @param defaultIgnore DOCUMENT ME!
188: */
189: private void traverseTreeForTestInsertion(
190: DefaultMutableTreeNode node, boolean isRecursive,
191: boolean defaultCorrect, boolean defaultIgnore) {
192: Component component;
193:
194: if (node.getParent() != null) {
195: component = components.getComponent(getComponentPath(node));
196: components.toFront(component);
197:
198: Test tmpTest = session.getTestLoader().getTest(component);
199:
200: if (tmpTest != null) {
201: if (isRecursive) {
202: tests.add(recurseTree(node, tmpTest,
203: defaultCorrect, defaultIgnore));
204: } else {
205: tests.add(tmpTest);
206: }
207: } else {
208: logger
209: .info(language
210: .getString("CleverPHL.Menu.InsertTestIntoTreeFrame.NotInserted"));
211: logger.info(getComponentPath(node));
212:
213: if (!node.isLeaf() && isRecursive) {
214: logger
215: .info(language
216: .getString("CleverPHL.Menu.InsertTestIntoTreeFrame.Recursing"));
217:
218: Enumeration children = node.children();
219:
220: while (children.hasMoreElements()) {
221: traverseTreeForTestInsertion(
222: (DefaultMutableTreeNode) children
223: .nextElement(), isRecursive,
224: defaultCorrect, defaultIgnore);
225: }
226: }
227: }
228: } else if (isRecursive) //we are in the root element of all components
229: {
230: Enumeration children = node.children();
231:
232: while (children.hasMoreElements()) {
233: traverseTreeForTestInsertion(
234: (DefaultMutableTreeNode) children.nextElement(),
235: isRecursive, defaultCorrect, defaultIgnore);
236: }
237: }
238:
239: Iterator testIter = tests.iterator();
240:
241: while (testIter.hasNext()) {
242: Test test = (Test) testIter.next();
243: test.setCorrecting(defaultCorrect);
244: test.setIgnoring(defaultIgnore);
245: session.insertRecordable(test);
246: logger
247: .info(language
248: .getString("CleverPHL.Menu.InsertTestIntoTreeFrame.Inserted"));
249: }
250:
251: if (!tests.isEmpty()) {
252: session.restructureRecord();
253: tests.clear();
254: }
255: }
256:
257: /**
258: * Recurses a (sub)tree, starting with <code>node</code> as root node and adds the tests of its
259: * children to the corresponding root node <code>test</code> of the test tree
260: *
261: * @param node the node of the component tree for which to insert the tests.
262: * @param test the node of the test tree to which the subtests shoud be inserted
263: * @param defaultCorrect DOCUMENT ME!
264: * @param defaultIgnore DOCUMENT ME!
265: *
266: * @return <code>test</code> with added subtests
267: */
268: private Test recurseTree(DefaultMutableTreeNode node, Test test,
269: boolean defaultCorrect, boolean defaultIgnore) {
270: Component component;
271:
272: Enumeration children = node.children();
273:
274: while (children.hasMoreElements()) {
275: DefaultMutableTreeNode child = (DefaultMutableTreeNode) children
276: .nextElement();
277: component = components
278: .getComponent(getComponentPath(child));
279:
280: Test tmpTest = session.getTestLoader().getTest(component);
281:
282: if (tmpTest != null) {
283: test.addChild(recurseTree(child, tmpTest,
284: defaultCorrect, defaultIgnore));
285: tmpTest.setCorrecting(defaultCorrect);
286: tmpTest.setIgnoring(defaultIgnore);
287: } else {
288: logger
289: .info(language
290: .getString("CleverPHL.Menu.InsertTestIntoTreeFrame.NotInserted"));
291: logger.info(getComponentPath(child));
292: logger
293: .info(language
294: .getString("CleverPHL.Menu.InsertTestIntoTreeFrame.Recursing"));
295:
296: Hashtable grandTests = new Hashtable();
297: Enumeration grandchildren = child.children();
298:
299: while (grandchildren.hasMoreElements()) {
300: DefaultMutableTreeNode grandchild = (DefaultMutableTreeNode) grandchildren
301: .nextElement();
302: component = components
303: .getComponent(getComponentPath(child));
304: tmpTest = session.getTestLoader()
305: .getTest(component);
306:
307: if (tmpTest != null) {
308: grandTests.put(grandchild, tmpTest);
309: tmpTest.setCorrecting(defaultCorrect);
310: tmpTest.setIgnoring(defaultIgnore);
311: }
312: }
313:
314: Enumeration grandEnum = grandTests.keys();
315:
316: while (grandEnum.hasMoreElements()) {
317: Object grandchild = grandEnum.nextElement();
318: test.addChild(recurseTree(
319: (DefaultMutableTreeNode) grandchild,
320: (Test) grandTests.get(grandchild),
321: defaultCorrect, defaultIgnore));
322: }
323: }
324: }
325:
326: return test;
327: }
328:
329: /**
330: * Build the component name path for <code>node</code>
331: *
332: * @param node the node for which to buid the compnent name path
333: *
334: * @return the component name path
335: */
336: public String getComponentPath(DefaultMutableTreeNode node) {
337: String componentPath = "";
338:
339: if (node != null) {
340: componentPath = node.getUserObject().toString();
341:
342: DefaultMutableTreeNode helper = node;
343:
344: while (helper.getParent() != null) {
345: helper = (DefaultMutableTreeNode) helper.getParent();
346:
347: if (helper.getParent() != null) {
348: componentPath = helper.getUserObject().toString()
349: + "." + componentPath;
350: }
351: }
352:
353: return componentPath;
354: }
355:
356: return componentPath;
357: }
358:
359: /**
360: * Invoked after nodes have been inserted into the tree.
361: *
362: * @param e DOCUMENT ME!
363: */
364: public void treeNodesInserted(TreeModelEvent e) {
365: expandRow(0);
366: }
367:
368: /**
369: * Invoked after a node (or a set of siblings) has changed in some way.
370: *
371: * @param e DOCUMENT ME!
372: */
373: public void treeNodesChanged(TreeModelEvent e) {
374: }
375:
376: /**
377: * Invoked after nodes have been removed from the tree.
378: *
379: * @param e DOCUMENT ME!
380: */
381: public void treeNodesRemoved(TreeModelEvent e) {
382: }
383:
384: /**
385: * Invoked after the tree has drastically changed structure from a given node down.
386: *
387: * @param e DOCUMENT ME!
388: */
389: public void treeStructureChanged(TreeModelEvent e) {
390: }
391:
392: /**
393: * DOCUMENT ME!
394: *
395: * @return Components
396: */
397: public Components getTreeComponents() {
398: return components;
399: }
400:
401: /**
402: * Called when the component selection has changed.
403: *
404: * @param event DOCUMENT ME!
405: */
406: public void componentSelectionChanged(ComponentSelectionEvent event) {
407: if (!listenToComponentSelectionChanges) {
408: return;
409: }
410:
411: switch (event.getID()) {
412: case ComponentSelectionEvent.COMPONENTS_ADDED:
413: listenToTreeSelectionChanges = false;
414:
415: //System.out.println ("Components added");
416: Component[] addedComponents = event.getComponents();
417:
418: for (int n = 0; n < addedComponents.length; n++) {
419: DefaultMutableTreeNode node = componentTree
420: .getNode(addedComponents[n]);
421:
422: //System.out.println ("Node == null: " + (node == null));
423: if (node != null) {
424: TreePath pathToAdd = new TreePath(node.getPath());
425:
426: //System.out.println ("Adding selection path");
427: //System.out.println ("Path = null: " + (pathToAdd == null));
428: addSelectionPath(pathToAdd);
429: }
430: }
431:
432: listenToTreeSelectionChanges = true;
433:
434: break;
435:
436: case ComponentSelectionEvent.COMPONENTS_REMOVED:
437: listenToTreeSelectionChanges = false;
438:
439: Component[] removedComponents = event.getComponents();
440:
441: for (int n = 0; n < removedComponents.length; n++) {
442: DefaultMutableTreeNode node = componentTree
443: .getNode(removedComponents[n]);
444:
445: if (node != null) {
446: removeSelectionPath(new TreePath(node.getPath()));
447: }
448: }
449:
450: listenToTreeSelectionChanges = true;
451:
452: break;
453:
454: case ComponentSelectionEvent.SELECTION_CLEARED:
455: listenToTreeSelectionChanges = false;
456: clearSelection();
457: listenToTreeSelectionChanges = true;
458:
459: break;
460: }
461: }
462:
463: // internal listener class
464: class ComponentsTreeListener implements TreeSelectionListener {
465: //~ Methods --------------------------------------------------------------------------------
466:
467: /**
468: * Called when the tree selection has changed.
469: *
470: * @param event DOCUMENT ME!
471: */
472: public void valueChanged(TreeSelectionEvent event) {
473: if (!listenToTreeSelectionChanges) {
474: return;
475: }
476:
477: listenToComponentSelectionChanges = false;
478:
479: TreePath[] selectedPaths = getSelectionPaths();
480:
481: if (!componentSelection.isEmpty()) {
482: componentSelection.clear();
483: }
484:
485: Vector newComponents = new Vector(5, 5);
486:
487: for (int i = 0; i < selectedPaths.length; i++) {
488: DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedPaths[i]
489: .getLastPathComponent();
490: Component component = components
491: .getComponent(getComponentPath(node));
492:
493: if (component != null) {
494: newComponents.add(component);
495: }
496: }
497:
498: if (newComponents.size() > 0) {
499: Component[] addedComponents = new Component[newComponents
500: .size()];
501:
502: for (int i = 0; i < newComponents.size(); i++) {
503: addedComponents[i] = (Component) newComponents
504: .get(i);
505: }
506:
507: componentSelection.add(addedComponents);
508: }
509:
510: listenToComponentSelectionChanges = true;
511: }
512: }
513: }
|