View Javadoc

1   /*
2   Wotonomy: OpenStep design patterns for pure Java applications.
3   Copyright (C) 2002 Intersect Software Corporation
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  Lesser General Public License for more details.
14  
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, see http://www.gnu.org
17  */
18  
19  package net.wotonomy.ui.swing;
20  
21  import javax.swing.JTree;
22  import javax.swing.table.TableColumn;
23  
24  import net.wotonomy.foundation.NSArray;
25  import net.wotonomy.ui.EODisplayGroup;
26  import net.wotonomy.ui.swing.components.TreeTableCellRenderer;
27  
28  /***
29  * TreeColumnAssociation is a TableColumnAssocation 
30  * that works like a TreeAssociation, allowing any
31  * table to display hierarchical data in a tabular format.
32  * This class is mainly a convenience for connecting a 
33  * TreeAssociation to a JTree to a TreeTableCellRenderer 
34  * to a TableColumn.<br><br>
35  * 
36  * Like TableColumnAssociation, you must call setTable()
37  * to specify the JTable to be used.  (The corresponding
38  * table association will direct all column header sorting
39  * to the root node of the tree association.)
40  *
41  * You may also optionally call setTree() to specify a 
42  * customized JTree to be used.  If not specified, a 
43  * slightly customized JTree will be used (see createTree()
44  * and configureColumn()).
45  *  
46  * TreeColumnAssociation supports the following bindings,
47  * just as TableColumnAssociation does:
48  * <ul>
49  * <li>value: a property convertable to a string for
50  * display in the cells of the table column.  This 
51  * binding is equivalent to the titles binding of 
52  * TreeAssociation.</li> 
53  *
54  * <li>editable: a property convertable to a boolean 
55  * that determines the editability of the corresponding
56  * cells in the column.</li> 
57  * </ul>
58  *
59  * TreeColumnAssociation additionally supports the following
60  * bindings, just as TreeAssociation does, except that the 
61  * value binding is used instead of the titles binding.
62  * <ul>
63  * <li>children: a property of a node value that returns
64  * zero, one or many objects, each of which will correspond
65  * to a child node for the corresponding node in the tree.
66  * If this aspect is not bound, the tree behaves like a list.</li>
67  *
68  * <li>isLeaf: a property of a node value that returns
69  * a value convertable to a boolean value. 
70  * If the isLeaf aspect is not bound, the tree will force 
71  * nodes to load their children to determine whether they 
72  * are leaf nodes (in effect loading the grandchildren for 
73  * any expanded node).
74  * </li>
75  * </ul>
76  *
77  * @author michael@mpowers.net
78  * @author $Author: cgruber $
79  * @version $Revision: 904 $
80  */
81  public class TreeColumnAssociation extends TableColumnAssociation
82  {
83      static final NSArray aspects = 
84          new NSArray( new Object[] {
85              ValueAspect, EditableAspect, ChildrenAspect, IsLeafAspect
86          } );
87      static final NSArray aspectSignatures = 
88          new NSArray( new Object[] {
89              AttributeToOneAspectSignature
90          } );
91      static final NSArray objectKeysTaken = 
92          new NSArray( new Object[] {
93              "table" 
94          } );
95  		
96  	EODisplayGroup childrenDisplayGroup, leafDisplayGroup;
97  	String childrenKey, leafKey;
98      
99      TreeModelAssociation treeAssociation;
100     JTree tree;
101 
102     /***
103     * Constructor specifying the object to be controlled by this
104     * association.  Throws an exception if the object is not
105 	* a TableColumn.  
106     */
107     public TreeColumnAssociation ( Object anObject )
108     {
109         super( anObject );
110     }
111 	
112     /***
113     * Returns a List of aspect signatures whose contents
114     * correspond with the aspects list.  Each element is 
115     * a string whose characters represent a capability of
116     * the corresponding aspect. <ul>
117     * <li>"A" attribute: the aspect can be bound to
118     * an attribute.</li>
119     * <li>"1" to-one: the aspect can be bound to a
120     * property that returns a single object.</li>
121     * <li>"M" to-one: the aspect can be bound to a
122     * property that returns multiple objects.</li>
123     * </ul> 
124     * An empty signature "" means that the aspect can
125     * bind without needing a key.
126     * This implementation returns "A1M" for each
127     * element in the aspects array.
128     */
129     public static NSArray aspectSignatures ()
130     {
131         return aspectSignatures;
132     }
133     
134     /***
135     * Returns a List that describes the aspects supported
136     * by this class.  Each element in the list is the string
137     * name of the aspect.  This implementation returns an
138     * empty list.
139     */
140     public static NSArray aspects ()
141     {
142         return aspects;
143     }
144     
145     /***
146     * Binds the specified aspect of this association to the
147     * specified key on the specified display group.
148     */
149     public void bindAspect ( 
150         String anAspect, EODisplayGroup aDisplayGroup, String aKey )
151 	{
152 		if ( ChildrenAspect.equals( anAspect ) )
153 		{
154 			childrenDisplayGroup = aDisplayGroup;	
155 			childrenKey = aKey;
156 		}
157 		if ( IsLeafAspect.equals( anAspect ) )
158 		{
159 			leafDisplayGroup = aDisplayGroup;
160 			leafKey = aKey;
161 		}
162 		super.bindAspect( anAspect, aDisplayGroup, aKey );
163 	}
164 	
165     /***
166     * Overridden to call createTree if necessary,
167     * call configureColumn, call createTreeAssociation
168     * if necessary, and then call to super.
169     */
170     public void establishConnection ()
171     {
172         if ( tree == null )
173         {
174             tree = createTree();
175         }
176         
177         configureColumn( (TableColumn) object() );
178         
179         if ( treeAssociation == null )
180         {
181             treeAssociation = createTreeAssociation( tree );
182         }
183         
184         treeAssociation.bindAspect( TitlesAspect, valueDisplayGroup, valueKey );
185         if ( childrenKey != null )
186         {
187             treeAssociation.bindAspect( ChildrenAspect, childrenDisplayGroup, childrenKey );
188         }
189         if ( leafKey != null )
190         {
191             treeAssociation.bindAspect( IsLeafAspect, leafDisplayGroup, leafKey );
192         }
193 
194         // ensure table association's source is tree asssociation's child group
195         getTableAssociation().bindAspect( 
196                 SourceAspect, treeAssociation.childrenDisplayGroup, "" );
197                 
198         treeAssociation.establishConnection();
199 
200         table.setRowHeight( tree.getRowHeight() );      
201         
202         super.establishConnection();
203                 
204         // cause sort ordering to apply to root node of tree
205         if ( childrenKey != null )
206         {        
207             getTableAssociation().sortTarget = 
208                 (EODisplayGroup) treeAssociation.getRoot();
209         }
210     }
211     
212     /***
213     * Breaks the connection between this association and 
214     * its object.  Override to stop listening for events
215     * from the object.
216     */
217     public void breakConnection ()
218     {
219         super.breakConnection();
220         treeAssociation.breakConnection();
221         
222         // restore original source display group
223         getTableAssociation().sortTarget = null;
224     }
225 
226     /***
227     * Called by establishConnection if setTree was not called.
228     * This implementation returns a stock JTree.  Override
229     * to provide your own customized JTree.  Note that
230     * TreeTableCellRenderer will further customize this tree
231     * when configureColumn is called.
232     */
233     protected JTree createTree()
234     {
235         return new JTree();
236     }
237 
238     /***
239     * Called by establishConnection to create a tree association
240     * only if no tree association has already been created.
241     * This implementation returns a stock TreeAssociation.
242     * Override to return your own customized TreeAssociation.
243     */    
244     protected TreeModelAssociation createTreeAssociation( JTree aTree )
245     {
246         return new TreeAssociation( aTree );
247     }
248     
249     /***
250     * Called by establishConnection to configure the column
251     * with a TreeTableCellRenderer using the current JTree.
252     * Override to further customize the column, or customize
253     * your column yourself after the call to establishConnection.
254     */
255     protected void configureColumn( TableColumn aColumn )
256     {
257         aColumn.setCellRenderer( new TreeTableCellRenderer( tree ) );
258     }
259     
260 	/***
261 	* Gets the JTree currently used for the column renderer.
262     * If not specified, returns null.
263 	*/
264 	public JTree getTree()
265 	{
266         return tree;
267 	}
268 
269 	/***
270 	* Gets the TreeModelAssociation currently used for the tree.
271     * If not tree is not specified, returns null.
272 	*/
273 	public TreeModelAssociation getTreeModelAssociation()
274 	{
275         if ( tree == null ) return null;
276         if (!( tree.getModel() instanceof TreeModelAssociation )) return null;
277         return (TreeModelAssociation) tree.getModel();
278 	}
279 
280 	/***
281 	* Sets the JTree to be used for the column renderer.
282     * If not specified, createTree() will be called to create a JTree.
283 	*/
284 	public void setTree( JTree aTree )
285 	{
286         tree = aTree;
287 	}
288 
289 }
290 
291 /*
292  * $Log$
293  * Revision 1.2  2006/02/18 23:19:05  cgruber
294  * Update imports and maven dependencies.
295  *
296  * Revision 1.1  2006/02/16 13:22:22  cgruber
297  * Check in all sources in eclipse-friendly maven-enabled packages.
298  *
299  * Revision 1.9  2003/08/06 23:07:52  chochos
300  * general code cleanup (mostly, removing unused imports)
301  *
302  * Revision 1.8  2002/05/03 21:31:50  mpowers
303  * Actually works better without selectionPaintedImmediately.
304  *
305  * Revision 1.7  2002/04/12 21:05:58  mpowers
306  * Now distinguishing changes in titles group even better.
307  *
308  * Revision 1.6  2002/03/08 23:18:48  mpowers
309  * Added accessor for tree association.
310  *
311  * Revision 1.5  2002/03/07 23:04:36  mpowers
312  * Refining TreeColumnAssociation.
313  *
314  * Revision 1.4  2002/03/06 13:04:16  mpowers
315  * Implemented cascading qualifiers in tree nodes.
316  *
317  * Revision 1.3  2002/03/05 23:18:28  mpowers
318  * Added documentation.
319  * Added isSelectionPaintedImmediate and isSelectionTracking attributes
320  * to TableAssociation.
321  * Added getTableAssociation to TableColumnAssociation.
322  *
323  * Revision 1.2  2002/03/04 22:48:22  mpowers
324  * Now working with table association to sort the root node.
325  *
326  * Revision 1.1  2002/03/01 23:42:09  mpowers
327  * Implemented TreeColumnAssociation, and updated documentation.
328  *
329  *
330  */
331