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 | * Author: John Thompson, Greenstone Digital Library, University of Waikato
|
---|
9 | *
|
---|
10 | * Copyright (C) 1999 New Zealand Digital Library Project
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or modify
|
---|
13 | * it under the terms of the GNU General Public License as published by
|
---|
14 | * the Free Software Foundation; either version 2 of the License, or
|
---|
15 | * (at your option) any later version.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful,
|
---|
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
20 | * GNU General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, write to the Free Software
|
---|
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
25 | *########################################################################
|
---|
26 | */
|
---|
27 | package org.greenstone.gatherer.util;
|
---|
28 |
|
---|
29 | import java.util.Vector;
|
---|
30 | import javax.swing.JTree;
|
---|
31 | import javax.swing.event.TreeExpansionEvent;
|
---|
32 | import javax.swing.event.TreeExpansionListener;
|
---|
33 | import javax.swing.event.TreeSelectionEvent;
|
---|
34 | import javax.swing.event.TreeSelectionListener;
|
---|
35 | import javax.swing.tree.TreeModel;
|
---|
36 | import javax.swing.tree.TreePath;
|
---|
37 | import org.greenstone.gatherer.gui.tree.DragTree;
|
---|
38 | /** My latest diabolical class synchronizes the expansion state of two or more JTrees. Muh-hahahaha. Note that these tree should be based on the same model. If they aren't it won't work. So there.
|
---|
39 | * @author John Thompson, Greenstone Digital Library, University of Waikato
|
---|
40 | * @version 2.1
|
---|
41 | */
|
---|
42 | final public class TreeSynchronizer
|
---|
43 | extends Vector
|
---|
44 | implements TreeExpansionListener, TreeSelectionListener {
|
---|
45 | /** <i>true</i> if we should temporarily ignore further events, most likely because we know our actions are causing them. */
|
---|
46 | private boolean ignore;
|
---|
47 | /** A list of tree selection listeners. */
|
---|
48 | private Vector selection_listeners = new Vector();
|
---|
49 | /** Add a new tree to the synchronization list of trees to be synchronized.
|
---|
50 | * @param tree The lastest victim, a <strong>JTree</strong>.
|
---|
51 | */
|
---|
52 | public void add(JTree tree) {
|
---|
53 | super.add(tree);
|
---|
54 | tree.addTreeExpansionListener(this);
|
---|
55 | tree.addTreeSelectionListener(this);
|
---|
56 | }
|
---|
57 |
|
---|
58 | /** We allow the Gatherer to add tree listeners to this class, as it persists between collection changes transparently. Thus there is no need to reattach listeners everytime the collection changes. */
|
---|
59 | public void addTreeSelectionListener(TreeSelectionListener listener) {
|
---|
60 | if(!selection_listeners.contains(listener)) {
|
---|
61 | selection_listeners.add(listener);
|
---|
62 | }
|
---|
63 | }
|
---|
64 |
|
---|
65 | /** Called whenever an item in the tree has been collapsed.
|
---|
66 | * @param event A <strong>TreeExpansionEvent</strong> containing information about the event.
|
---|
67 | */
|
---|
68 | public void treeCollapsed(TreeExpansionEvent event) {
|
---|
69 | if(!ignore) {
|
---|
70 | ignore = true;
|
---|
71 | // Collapse that path in all registered trees.
|
---|
72 | JTree tree = (JTree)event.getSource();
|
---|
73 | TreePath path = event.getPath();
|
---|
74 | for(int i = size(); i != 0; i--) {
|
---|
75 | JTree sibling = (JTree) get(i - 1);
|
---|
76 | if(!sibling.equals(tree)) {
|
---|
77 | sibling.collapsePath(path);
|
---|
78 | }
|
---|
79 | }
|
---|
80 | ignore = false;
|
---|
81 | }
|
---|
82 | }
|
---|
83 | /** Called whenever an item in the tree has been expanded.
|
---|
84 | * @param event A <strong>TreeExpansionEvent</strong> containing information about the event.
|
---|
85 | */
|
---|
86 | public void treeExpanded(TreeExpansionEvent event) {
|
---|
87 | if(!ignore) {
|
---|
88 | ignore = true;
|
---|
89 | // Expand that path in all registered trees.
|
---|
90 | JTree tree = (JTree)event.getSource();
|
---|
91 | TreePath path = event.getPath();
|
---|
92 | for(int i = size(); i != 0; i--) {
|
---|
93 | JTree sibling = (JTree) get(i - 1);
|
---|
94 | if(!sibling.equals(tree)) {
|
---|
95 | sibling.expandPath(path);
|
---|
96 | }
|
---|
97 | }
|
---|
98 | ignore = false;
|
---|
99 | }
|
---|
100 | }
|
---|
101 | /** Called whenever the one of the trees selection changes.
|
---|
102 | * @param event A <strong>TreeSelectionEvent</strong> containing information about the event.
|
---|
103 | */
|
---|
104 | public void valueChanged(TreeSelectionEvent event) {
|
---|
105 | if(!ignore) {
|
---|
106 | ignore = true;
|
---|
107 | // Recover the tree that is the source.
|
---|
108 | JTree tree = (JTree) event.getSource();
|
---|
109 | // Brute Force approach.
|
---|
110 | // Extract the currently selected paths.
|
---|
111 | TreePath paths[] = tree.getSelectionPaths();
|
---|
112 | // Then for every registered tree, that isn't this one, ensure those paths are selected.
|
---|
113 | /*
|
---|
114 | for(int i = size(); paths != null && i != 0; i--) {
|
---|
115 | JTree sibling = (JTree) get(i - 1);
|
---|
116 | if(!sibling.equals(tree)) {
|
---|
117 | // One last thing to do. If this is actually a DragTree we are dealing with we have to tell it to set the selection values immediately, not wait for the clear until it is sure it is no the pre-cursor to a drag.
|
---|
118 | if(sibling instanceof DragTree) {
|
---|
119 | DragTree gtree = (DragTree)sibling;
|
---|
120 | gtree.setImmediate(true);
|
---|
121 | gtree.setSelectionPaths(paths);
|
---|
122 | // I'm going to ensure that the last selected path is visible.
|
---|
123 | gtree.scrollPathToVisible(paths[paths.length - 1]);
|
---|
124 | gtree.setImmediate(false);
|
---|
125 | }
|
---|
126 | else {
|
---|
127 | sibling.setSelectionPaths(paths);
|
---|
128 | sibling.scrollPathToVisible(paths[paths.length - 1]);
|
---|
129 | }
|
---|
130 | }
|
---|
131 | }
|
---|
132 | */
|
---|
133 | // Pass on message to all listeners.
|
---|
134 | for(int i = 0; i < selection_listeners.size(); i++) {
|
---|
135 | ((TreeSelectionListener) selection_listeners.get(i)).valueChanged(event);
|
---|
136 | }
|
---|
137 | ignore = false;
|
---|
138 | }
|
---|
139 | }
|
---|
140 | }
|
---|