source: trunk/gli/src/org/greenstone/gatherer/util/SynchronizedTreeModel.java@ 8243

Last change on this file since 8243 was 8243, checked in by mdewsnip, 20 years ago

Removed all occurrences of classes explicitly importing other classes in the same package.

  • Property svn:keywords set to Author Date Id Revision
File size: 4.5 KB
Line 
1package org.greenstone.gatherer.util;
2
3import javax.swing.*;
4import javax.swing.tree.*;
5
6
7/** This synchronized TreeModel is comprised of two seperate models. The extended model is used to paint the screen, and can only be updated on the AWTEvent Thread. The second, private, model contains the current actual state of the model with changes made immediately. If such changes occur then a task is queued in the AWTEvent Thread to update the 'painted' model. This model depends on the TreeNodes used having these properties:
8* TreeNode x_node = new TreeNode("x");
9* TreeNode y_node = x_node.cloneNode();
10* for(int i = 0; i < x_node.getChildCount(); i++) {
11* x_node.getChildAt(i) != y_node.getChildAt(i);
12* x_node.getChildAt(i).equals(y_node.getChildAt(i));
13* }
14* x_node != y_node;
15* (new TreeNode("x")).equals(new TreeNode("x"));
16* In other words, any two different instances of the tree node must be equal according to the equals method.
17* Methods which need data from the tree should also use the model methods (ie model.getChildCount(node) rather than node.getChildCount()) and should not be in the AWTEvent Thread (as such calls will see the possibly out of date 'visual' model, not the actual underlying model).
18*/
19public class SynchronizedTreeModel
20 extends DefaultTreeModel
21 implements Runnable {
22
23 private boolean changed = false;
24 private DefaultTreeModel offscreen;
25 private TreeModelTest test = null;
26
27 SynchronizedTreeModel(SynchronizedTreeNode root) {
28 super(root);
29 offscreen = new DefaultTreeModel(root.cloneNode());
30 }
31
32 SynchronizedTreeModel(SynchronizedTreeNode root, TreeModelTest test) {
33 super(root);
34 offscreen = new DefaultTreeModel(root.cloneNode());
35 this.test = test;
36 }
37
38 /** Returns the child of parent at index index in the parent's child array. */
39 public Object getChild(Object parent, int index) {
40 if(isEventThread()) {
41 return super.getChild(parent, index);
42 }
43 else {
44 return offscreen.getChild(parent, index);
45 }
46 }
47
48 /** Returns the number of children of parent. */
49 public int getChildCount(Object parent) {
50 if(isEventThread()) {
51 return super.getChildCount(parent);
52 }
53 else {
54 return offscreen.getChildCount(parent);
55 }
56 }
57
58 /** Builds the parents of node up to and including the root node, where the original node is the last element in the returned array. This is probably the most 'expensive' method we make synchronized, but it isn't called often so thats ok. */
59 public TreeNode[] getPathToRoot(TreeNode aNode) {
60 if(isEventThread()) {
61 return super.getPathToRoot(aNode);
62 }
63 else {
64 return offscreen.getPathToRoot(aNode);
65 }
66 }
67
68 public Object getRoot() {
69 if(isEventThread()) {
70 return super.getRoot();
71 }
72 else {
73 return offscreen.getRoot();
74 }
75 }
76
77 /** Invoked this to insert newChild at location index in parents children. */
78 public void insertNodeInto(MutableTreeNode newChild, MutableTreeNode parent, int index) {
79 if(isEventThread()) {
80 if(test != null) test.debug("insertNodeInto(" + newChild + ", " + parent + ", " + index + ")");
81 super.insertNodeInto(newChild, parent, index);
82 }
83 else {
84 if(test != null) test.debug("offscreen.insertNodeInto(" + newChild + ", " + parent + ", " + index + ")");
85 offscreen.insertNodeInto(newChild, parent, index);
86 queueUpdate();
87 }
88 }
89
90 /** Message this to remove node from its parent. */
91 public void removeNodeFromParent(MutableTreeNode node) {
92 if(isEventThread()) {
93 if(test != null) test.debug("removeNodeFromParent(" + node + ")");
94 super.removeNodeFromParent(node);
95 }
96 else {
97 if(test != null) test.debug("offscreen.removeNodeFromParent(" + node + ")");
98 offscreen.removeNodeFromParent(node);
99 queueUpdate();
100 }
101 }
102
103 public void run() {
104 synchronized(this) {
105 if(changed) {
106 setRoot(((SynchronizedTreeNode)(offscreen.getRoot())). cloneNode());
107 nodeChanged(root);
108 changed = false;
109 if(test != null) test.debug("Painted model refreshed.");
110 }
111 else {
112 if(test != null) test.debug("Painted model is current.");
113 }
114 }
115 }
116
117 /** Determine if this call is happening on the AWTEvent Dispatch Thread. */
118 private boolean isEventThread() {
119 return SwingUtilities.isEventDispatchThread();
120 }
121
122 private synchronized void queueUpdate() {
123 changed = true;
124 SwingUtilities.invokeLater(this);
125 if(test != null) test.debug("Painted model is obsolete.");
126 }
127}
Note: See TracBrowser for help on using the repository browser.