001/* 002 * $Id: TreeTableDemo.java 1295 2012-07-20 10:13:54Z kleopatra $ 003 * 004 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020*/ 021//package org.jdesktop.swingx.demos.treetable; 022package ca.bc.webarts.widgets.treetable; 023 024import java.awt.BorderLayout; 025import java.awt.Color; 026import java.awt.Component; 027import java.awt.Dimension; 028import java.awt.Point; 029import java.awt.Window; 030import java.awt.event.MouseEvent; 031import java.util.ArrayList; 032import java.util.List; 033import java.util.logging.Logger; 034 035import javax.swing.JButton; 036import javax.swing.JComponent; 037import javax.swing.JFrame; 038import javax.swing.JLabel; 039import javax.swing.JPanel; 040import javax.swing.JScrollPane; 041import javax.swing.SwingUtilities; 042import javax.swing.table.TableModel; 043import javax.swing.tree.TreePath; 044 045import org.jdesktop.application.Action; 046import org.jdesktop.swingx.JXPanel; 047import org.jdesktop.swingx.JXTreeTable; 048import org.jdesktop.swingx.decorator.AbstractHighlighter; 049import org.jdesktop.swingx.decorator.ColorHighlighter; 050import org.jdesktop.swingx.decorator.ComponentAdapter; 051import org.jdesktop.swingx.decorator.HighlightPredicate; 052//import org.jdesktop.swingx.demos.tree.TreeDemoIconValues.LazyLoadingIconValue; 053import org.jdesktop.swingx.demos.tree.XTreeDemo; 054import org.jdesktop.swingx.event.AbstractInputEventDispatcher; 055import org.jdesktop.swingx.renderer.DefaultTableRenderer; 056import org.jdesktop.swingx.renderer.DefaultTreeRenderer; 057import org.jdesktop.swingx.renderer.IconValue; 058import org.jdesktop.swingx.renderer.StringValue; 059import org.jdesktop.swingx.renderer.StringValues; 060import org.jdesktop.swingx.table.ColumnFactory; 061import org.jdesktop.swingx.table.TableColumnExt; 062import org.jdesktop.swingx.treetable.TreeTableModel; 063import org.jdesktop.swingx.util.PaintUtils; 064//import org.jdesktop.swingxset.JXDemoFrame; 065import org.jdesktop.swingxset.util.ComponentModels; 066import org.jdesktop.swingxset.util.DemoUtils; 067 068import com.sun.swingset3.DemoProperties; 069 070import ca.bc.webarts.widgets.treetable.TreeDemoIconValues.LazyLoadingIconValue; 071import ca.bc.webarts.widgets.treetable.JXDemoFrame; 072 073 074/** 075 * A demo for the {@code JXTreeTable}. 076 * 077 * @author Karl George Schaefer 078 */ 079 080@DemoProperties( value = "JXTreeTable Demo", category = "Data", description = "Demonstrates JXTreeTable, a tree-based, grid component.", 081 sourceFiles = 082 { "ca/bc/webarts/widgets/treetable/TreeTableDemo.java" , 083 "ca/bc/webarts/widgets/treetable/TreeDemoIconValues.java" , 084 "ca/bc/webarts/widgets/treetable/JXDemoFrame.java" , 085 "ca/bc/webarts/widgets/treetable/TreeTableDemo.properties" } ) 086 087@SuppressWarnings( "serial" ) 088public class TreeTableDemo extends JPanel 089{ 090 ca.bc.webarts.tools.Log log_ = ca.bc.webarts.tools.Log.createLog( ca.bc.webarts.tools.Log.DEBUG ); 091 092 @SuppressWarnings( "unused" ) 093 private static final Logger LOG = Logger.getLogger( TreeTableDemo.class .getName() ); 094 095 private JXTreeTable treeTable; 096 private boolean initialized; 097 private JButton refreshButton; 098 private JButton expandButton; 099 private JButton collapseButton; 100 private AbstractInputEventDispatcher inputEventDispatcher; 101 private AbstractHighlighter mouseOverHighlighter; 102 103 104 public TreeTableDemo() 105 { 106 super( new BorderLayout() ); 107 log_ = ca.bc.webarts.tools.Log.createLog( ca.bc.webarts.tools.Log.DEBUG ); 108 initComponents(); 109 configureComponents(); 110 DemoUtils.injectResources( this ); 111 bind(); 112 log_.debug("TreeTableDemo Initialized"); 113 } 114 115 // ---------------- public api for Binding/Action control 116 117 118 //@Action 119 public void refreshModel() 120 { 121 log_.startMethod(); 122 treeTable.setTreeTableModel( createTreeModel() ); 123 expandAll(); 124 treeTable.packColumn( treeTable.getHierarchicalColumn(), -1 ); 125 log_.endMethod(); 126 } 127 128 // <snip> JXTreeTable convenience api 129 // expand/collapse all nodes 130 //@Action 131 public void expandAll() 132 { 133 log_.startMethod(); 134 treeTable.expandAll(); 135 log_.endMethod(); 136 } 137 138 139 // @Action 140 public void collapseAll() 141 { 142 log_.startMethod(); 143 treeTable.collapseAll(); 144 log_.endMethod(); 145 } 146 // </snip> 147 148 // ------------------- config/bind 149 150 151 private void bind() 152 { 153 log_.startMethod(); 154 // <snip>JXTreeTable column customization 155 // configure and install a custom columnFactory, arguably data related ;-) 156 ColumnFactory factory = new ColumnFactory() 157 { 158 String[] columnNameKeys = 159 { "componentType", "componentName", "componentLocation", "componentSize" }; 160 161 @Override 162 public void configureTableColumn( TableModel model, TableColumnExt columnExt ) 163 { 164 super.configureTableColumn( model, columnExt ); 165 if ( columnExt.getModelIndex() < columnNameKeys.length ) 166 { 167 columnExt.setTitle( DemoUtils.getResourceString( TreeTableDemo.class, columnNameKeys[columnExt.getModelIndex()] ) ); 168 } 169 } 170 171 }; 172 treeTable.setColumnFactory( factory ); 173 // </snip> 174 log_.endMethod(); 175 } 176 177 private void configureComponents() 178 { 179 log_.startMethod(); 180 // <snip> JXTreeTable rendering 181 // StringValue provides node text, used in hierarchical column 182 StringValue sv = new StringValue() 183 { 184 185 @Override 186 public String getString( Object value ) 187 { 188 if ( value instanceof Component ) 189 { 190 Component component = ( Component ) value; 191 String simpleName = component.getClass().getSimpleName(); 192 if ( simpleName.length() == 0 ) 193 { 194 // anonymous class 195 simpleName = component.getClass().getSuperclass().getSimpleName(); 196 } 197 return simpleName; 198 } 199 return StringValues.TO_STRING.getString( value ); 200 } 201 }; 202 // </snip> 203 204 // StringValue for lazy icon loading 205 StringValue keyValue = new StringValue() 206 { 207 @Override 208 public String getString( Object value ) 209 { 210 if ( value == null ) 211 { 212 return ""; 213 } 214 String simpleClassName = value.getClass().getSimpleName(); 215 if ( simpleClassName.length() == 0 ) 216 { 217 // anonymous class 218 simpleClassName = value.getClass().getSuperclass().getSimpleName(); 219 } 220 return simpleClassName + ".png"; 221 } 222 }; 223 // <snip> JXTreeTable rendering 224 // IconValue provides node icon (same as in XTreeDemo) 225 IconValue iv = new LazyLoadingIconValue( XTreeDemo.class, keyValue, "fallback.png" ); 226 // create and set a tree renderer using the custom Icon-/StringValue 227 treeTable.setTreeCellRenderer( new DefaultTreeRenderer( iv, sv ) ); 228 // string representation for use of Dimension/Point class 229 StringValue locSize = new StringValue() 230 { 231 232 @Override 233 public String getString( Object value ) 234 { 235 int x; 236 int y; 237 if ( value instanceof Dimension ) 238 { 239 x = ( ( Dimension ) value ).width; 240 y = ( ( Dimension ) value ).height; 241 } 242 else if ( value instanceof Point ) 243 { 244 x = ( ( Point ) value ).x; 245 y = ( ( Point ) value ).y; 246 } 247 else 248 { 249 return StringValues.TO_STRING.getString( value ); 250 } 251 return "(" + x + ", " + y + ")"; 252 } 253 }; 254 treeTable.setDefaultRenderer( Point.class, new DefaultTableRenderer( locSize, JLabel.CENTER ) ); 255 treeTable.setDefaultRenderer( Dimension.class, treeTable.getDefaultRenderer( Point.class ) ); 256 // </snip> 257 258 mouseOverHighlighter = new ColorHighlighter( HighlightPredicate.NEVER, PaintUtils.setSaturation( Color.MAGENTA, 0.3f ), null ); 259 treeTable.addHighlighter( mouseOverHighlighter ); 260 261 treeTable.setColumnControlVisible( true ); 262 263 264 refreshButton.setAction( DemoUtils.getAction( this, "refreshModel" ) ); 265 expandButton.setAction( DemoUtils.getAction( this, "expandAll" ) ); 266 collapseButton.setAction( DemoUtils.getAction( this, "collapseAll" ) ); 267 268 DemoUtils.setSnippet( "JXTreeTable convenience api", expandButton, collapseButton ); 269 DemoUtils.setSnippet( "JXTreeTable rendering", treeTable ); 270 log_.endMethod(); 271 } 272 273 // <snip> Input-/FocusEvent notification 274 // update Highlighter's predicate to highlight the tree row 275 // which contains the component under the current mouse position 276 protected void updateHighlighter( Component component ) 277 { 278 log_.startMethod(); 279 mouseOverHighlighter.setHighlightPredicate( HighlightPredicate.NEVER ); 280 if ( component != null ) 281 { 282 283 List<Component> pathList = new ArrayList<Component>(); 284 while ( component != null ) 285 { 286 pathList.add(0, component ); 287 component = component.getParent(); 288 } 289 final TreePath treePath = new TreePath( pathList.toArray() ); 290 treeTable.scrollPathToVisible( treePath ); 291 HighlightPredicate predicate = new HighlightPredicate() 292 { 293 294 @Override 295 public boolean isHighlighted( Component renderer, ComponentAdapter adapter ) 296 { 297 return adapter.row == treeTable.getRowForPath( treePath ); 298 } 299 }; 300 mouseOverHighlighter.setHighlightPredicate( predicate ); 301 // </snip> 302 303 } 304 log_.endMethod(); 305 } 306 307 308 /** 309 * Overridden to create and install the component tree model. 310 */ 311 @Override 312 public void addNotify() 313 { 314 log_.startMethod(); 315 super.addNotify(); 316 if ( !initialized ) 317 { 318 initialized = true; 319 refreshModel(); 320 } 321 installInputEventListener(); 322 log_.endMethod(); 323 } 324 325 326 @Override 327 public void removeNotify() 328 { 329 log_.startMethod(); 330 uninstallInputEventListener(); 331 super.removeNotify(); 332 log_.endMethod(); 333 } 334 335 336 // <snip> Input-/FocusEvent notification 337 // install custom dispatcher with demo frame 338 private void installInputEventListener() 339 { 340 log_.startMethod(); 341 if ( !( SwingUtilities.getWindowAncestor( this ) instanceof JXDemoFrame ) ) 342 { 343 return; 344 } 345 JXDemoFrame window = ( JXDemoFrame ) SwingUtilities.getWindowAncestor( this ); 346 if ( inputEventDispatcher == null ) 347 { 348 inputEventDispatcher = new AbstractInputEventDispatcher() 349 { 350 // updates Highlighter for mouseEntered/mouseExited 351 // of all components in the frame's container hierarchy 352 @Override 353 protected void processMouseEvent( MouseEvent e ) 354 { 355 if ( MouseEvent.MOUSE_ENTERED == e.getID() ) 356 { 357 updateHighlighter( e.getComponent() ); 358 } 359 else if ( MouseEvent.MOUSE_EXITED == e.getID() ) 360 { 361 updateHighlighter( null ); 362 } 363 } 364 365 }; 366 } 367 window.setInputEventDispatcher( inputEventDispatcher ); 368 // </snip> 369 log_.endMethod(); 370 } 371 372 373 private void uninstallInputEventListener() 374 { 375 log_.startMethod(); 376 if ( !( SwingUtilities.getWindowAncestor( this ) instanceof JXDemoFrame ) ) 377 { 378 return; 379 } 380 JXDemoFrame window = ( JXDemoFrame ) SwingUtilities.getWindowAncestor( this ); 381 window.setInputEventDispatcher( null ); 382 updateHighlighter( null ); 383 log_.endMethod(); 384 } 385 386 387 private TreeTableModel createTreeModel() 388 { 389 log_.startMethod(); 390 Window window = SwingUtilities.getWindowAncestor( this ); 391 TreeTableModel retVal = ComponentModels.getTreeTableModel( window != null ? window : this ); 392 log_.endMethod(); 393 return retVal; 394 } 395 396 // ----------------- init 397 398 private void initComponents() 399 { 400 log_.startMethod(); 401 treeTable = new JXTreeTable(); 402 treeTable.setName( "componentTreeTable" ); 403 add( new JScrollPane( treeTable ) ); 404 405 JComponent control = new JXPanel(); 406 refreshButton = new JButton(); 407 refreshButton.setName( "refreshButton" ); 408 409 expandButton = new JButton(); 410 expandButton.setName( "expandTreeTableButton" ); 411 412 collapseButton = new JButton(); 413 collapseButton.setName( "collapseTreeTableButton" ); 414 415 // control.add(refreshButton); 416 control.add( expandButton ); 417 control.add( collapseButton ); 418 add( control, BorderLayout.SOUTH ); 419 log_.endMethod(); 420 421 } 422 423 /** 424 * main method allows us to run as a standalone demo. 425 */ 426 public static void main( String[] args ) 427 { 428 SwingUtilities.invokeLater( new Runnable() 429 { 430 public void run() 431 { 432 JFrame frame = new JFrame( TreeTableDemo.class.getAnnotation( DemoProperties.class ).value() ); 433 434 frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 435 frame.getContentPane().add( new TreeTableDemo() ); 436 frame.setPreferredSize( new Dimension(800, 600 ) ); 437 frame.pack(); 438 frame.setLocationRelativeTo( null ); 439 frame.setVisible( true ); 440 } 441 } ); 442 } 443 444} 445 446