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