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
022package org.jdesktop.swingx.demos.treetable;
023
024
025
026import java.awt.BorderLayout;
027
028import java.awt.Color;
029
030import java.awt.Component;
031
032import java.awt.Dimension;
033
034import java.awt.Point;
035
036import java.awt.Window;
037
038import java.awt.event.MouseEvent;
039
040import java.util.ArrayList;
041
042import java.util.List;
043
044import java.util.logging.Logger;
045
046
047
048import javax.swing.JButton;
049
050import javax.swing.JComponent;
051
052import javax.swing.JFrame;
053
054import javax.swing.JLabel;
055
056import javax.swing.JPanel;
057
058import javax.swing.JScrollPane;
059
060import javax.swing.SwingUtilities;
061
062import javax.swing.table.TableModel;
063
064import javax.swing.tree.TreePath;
065
066
067
068import org.jdesktop.application.Action;
069
070import org.jdesktop.swingx.JXPanel;
071
072import org.jdesktop.swingx.JXTreeTable;
073
074import org.jdesktop.swingx.decorator.AbstractHighlighter;
075
076import org.jdesktop.swingx.decorator.ColorHighlighter;
077
078import org.jdesktop.swingx.decorator.ComponentAdapter;
079
080import org.jdesktop.swingx.decorator.HighlightPredicate;
081
082import org.jdesktop.swingx.demos.tree.TreeDemoIconValues.LazyLoadingIconValue;
083
084import org.jdesktop.swingx.demos.tree.XTreeDemo;
085
086import org.jdesktop.swingx.event.AbstractInputEventDispatcher;
087
088import org.jdesktop.swingx.renderer.DefaultTableRenderer;
089
090import org.jdesktop.swingx.renderer.DefaultTreeRenderer;
091
092import org.jdesktop.swingx.renderer.IconValue;
093
094import org.jdesktop.swingx.renderer.StringValue;
095
096import org.jdesktop.swingx.renderer.StringValues;
097
098import org.jdesktop.swingx.table.ColumnFactory;
099
100import org.jdesktop.swingx.table.TableColumnExt;
101
102import org.jdesktop.swingx.treetable.TreeTableModel;
103
104import org.jdesktop.swingx.util.PaintUtils;
105
106import org.jdesktop.swingxset.JXDemoFrame;
107
108import org.jdesktop.swingxset.util.ComponentModels;
109
110import org.jdesktop.swingxset.util.DemoUtils;
111
112
113
114import com.sun.swingset3.DemoProperties;
115
116
117
118/**
119  * A demo for the {@code JXTreeTable}.
120  *
121  * @author Karl George Schaefer
122  */
123
124
125
126@DemoProperties(value = "JXTreeTable Demo", category = "Data", description = "Demonstrates JXTreeTable, a tree-based, grid component.", sourceFiles =
127
128{ "org/jdesktop/swingx/demos/treetable/TreeTableDemo.java" , "org/jdesktop/swingx/demos/tree/TreeDemoIconValues.java" , "org/jdesktop/swingxset/JXDemoFrame.java" , "org/jdesktop/swingx/demos/treetable/resources/TreeTableDemo.properties" } )
129
130@SuppressWarnings("serial")
131
132public class TreeTableDemo extends JPanel
133
134{
135
136
137
138  @SuppressWarnings("unused")
139
140  private static final Logger LOG = Logger.getLogger(TreeTableDemo.class .getName());
141
142
143
144  private JXTreeTable treeTable;
145
146  private boolean initialized;
147
148  private JButton refreshButton;
149
150  private JButton expandButton;
151
152  private JButton collapseButton;
153
154  private AbstractInputEventDispatcher inputEventDispatcher;
155
156  private AbstractHighlighter mouseOverHighlighter;
157
158
159
160  public TreeTableDemo()
161
162  {
163
164    super(new BorderLayout());
165
166    initComponents();
167
168    configureComponents();
169
170    DemoUtils.injectResources(this);
171
172    bind();
173
174  }
175
176
177
178  // ---------------- public api for Binding/Action control
179
180
181
182
183
184  @Action
185
186  public void refreshModel()
187
188  {
189
190    treeTable.setTreeTableModel(createTreeModel());
191
192    expandAll();
193
194    treeTable.packColumn(treeTable.getHierarchicalColumn(), -1);
195
196  }
197
198
199
200
201  // <snip> JXTreeTable convenience api
202
203  // expand/collapse all nodes
204
205  @Action
206
207  public void expandAll()
208
209  {
210
211    treeTable.expandAll();
212
213  }
214
215
216
217  @Action
218
219  public void collapseAll()
220
221  {
222
223    treeTable.collapseAll();
224
225  }
226
227  // </snip>
228
229
230
231  // ------------------- config/bind
232
233
234
235
236
237  private void bind()
238
239  {
240
241    // <snip>JXTreeTable column customization
242
243    // configure and install a custom columnFactory, arguably data related ;-)
244
245    ColumnFactory factory = new ColumnFactory()
246
247    {
248
249      String[] columnNameKeys =
250
251      { "componentType", "componentName", "componentLocation", "componentSize" };
252
253
254
255      @Override
256
257      public void configureTableColumn(TableModel model, TableColumnExt columnExt)
258
259      {
260
261        super.configureTableColumn(model, columnExt);
262
263        if (columnExt.getModelIndex() < columnNameKeys.length)
264
265        {
266
267          columnExt.setTitle(DemoUtils.getResourceString(TreeTableDemo.class, columnNameKeys[columnExt.getModelIndex()]));
268
269        }
270
271      }
272
273
274
275    };
276
277    treeTable.setColumnFactory(factory);
278
279    // </snip>
280
281
282
283  }
284
285
286
287  private void configureComponents()
288
289  {
290
291    // <snip> JXTreeTable rendering
292
293    // StringValue provides node text, used in hierarchical column
294
295    StringValue sv = new StringValue()
296
297    {
298
299
300
301      @Override
302
303      public String getString(Object value)
304
305      {
306
307        if (value instanceof Component)
308
309        {
310
311          Component component = (Component) value;
312
313          String simpleName = component.getClass().getSimpleName();
314
315          if (simpleName.length() == 0)
316
317          {
318
319            // anonymous class
320
321            simpleName = component.getClass().getSuperclass().getSimpleName();
322
323          }
324
325          return simpleName;
326
327        }
328
329        return StringValues.TO_STRING.getString(value);
330
331      }
332
333    };
334
335    // </snip>
336
337
338
339    // StringValue for lazy icon loading
340
341    StringValue keyValue = new StringValue()
342
343    {
344
345
346
347      @Override
348
349      public String getString(Object value)
350
351      {
352
353        if (value == null)
354
355        {
356
357          return "";
358
359        }
360
361        String simpleClassName = value.getClass().getSimpleName();
362
363        if (simpleClassName.length() == 0)
364
365        {
366
367          // anonymous class
368
369          simpleClassName = value.getClass().getSuperclass().getSimpleName();
370
371        }
372
373        return simpleClassName + ".png";
374
375      }
376
377    };
378
379    // <snip> JXTreeTable rendering
380
381    // IconValue provides node icon (same as in XTreeDemo)
382
383    IconValue iv = new LazyLoadingIconValue(XTreeDemo.class, keyValue, "fallback.png");
384
385    // create and set a tree renderer using the custom Icon-/StringValue
386
387    treeTable.setTreeCellRenderer(new DefaultTreeRenderer(iv, sv));
388
389    // string representation for use of Dimension/Point class
390
391    StringValue locSize = new StringValue()
392
393    {
394
395
396
397      @Override
398
399      public String getString(Object value)
400
401      {
402
403        int x;
404
405        int y;
406
407        if (value instanceof Dimension)
408
409        {
410
411          x = ((Dimension) value).width;
412
413          y = ((Dimension) value).height;
414
415        }
416
417        else if (value instanceof Point)
418
419        {
420
421          x = ((Point) value).x;
422
423          y = ((Point) value).y;
424
425        }
426
427        else
428
429        {
430
431          return StringValues.TO_STRING.getString(value);
432
433        }
434
435        return "(" + x + ", " + y + ")";
436
437      }
438
439    };
440
441    treeTable.setDefaultRenderer(Point.class, new DefaultTableRenderer(locSize, JLabel.CENTER));
442
443    treeTable.setDefaultRenderer(Dimension.class, treeTable.getDefaultRenderer(Point.class));
444
445    // </snip>
446
447
448
449    mouseOverHighlighter = new ColorHighlighter(HighlightPredicate.NEVER, PaintUtils.setSaturation(Color.MAGENTA, 0.3f), null);
450
451    treeTable.addHighlighter(mouseOverHighlighter);
452
453
454
455    treeTable.setColumnControlVisible(true);
456
457
458
459    refreshButton.setAction(DemoUtils.getAction(this, "refreshModel"));
460
461    expandButton.setAction(DemoUtils.getAction(this, "expandAll"));
462
463    collapseButton.setAction(DemoUtils.getAction(this, "collapseAll"));
464
465
466
467    // Demo specific config
468
469    DemoUtils.setSnippet("JXTreeTable convenience api", expandButton, collapseButton);
470
471    DemoUtils.setSnippet("JXTreeTable rendering", treeTable);
472
473  }
474
475
476
477  // <snip> Input-/FocusEvent notification
478
479  // update Highlighter's predicate to highlight the tree row
480
481  // which contains the component under the current mouse position
482
483  protected void updateHighlighter(Component component)
484
485  {
486
487    mouseOverHighlighter.setHighlightPredicate(HighlightPredicate.NEVER);
488
489    if (component != null)
490
491    {
492
493
494
495      List<Component> pathList = new ArrayList<Component>();
496
497      while (component != null)
498
499      {
500
501        pathList.add(0, component);
502
503        component = component.getParent();
504
505      }
506
507      final TreePath treePath = new TreePath(pathList.toArray());
508
509      treeTable.scrollPathToVisible(treePath);
510
511      HighlightPredicate predicate = new HighlightPredicate()
512
513      {
514
515
516
517        @Override
518
519        public boolean isHighlighted(Component renderer, ComponentAdapter adapter)
520
521        {
522
523          return adapter.row == treeTable.getRowForPath(treePath);
524
525        }
526
527      };
528
529      mouseOverHighlighter.setHighlightPredicate(predicate);
530
531      // </snip>
532
533
534
535    }
536
537  }
538
539
540
541  /**
542      * Overridden to create and install the component tree model.
543      */
544
545  @Override
546
547  public void addNotify()
548
549  {
550
551    super.addNotify();
552
553    if (!initialized)
554
555    {
556
557      initialized = true;
558
559      refreshModel();
560
561    }
562
563    installInputEventListener();
564
565  }
566
567
568
569  @Override
570
571  public void removeNotify()
572
573  {
574
575    uninstallInputEventListener();
576
577    super.removeNotify();
578
579  }
580
581  // <snip> Input-/FocusEvent notification
582
583  // install custom dispatcher with demo frame
584
585  private void installInputEventListener()
586
587  {
588
589    if (!(SwingUtilities.getWindowAncestor(this) instanceof JXDemoFrame))
590
591    {
592
593      return;
594
595    }
596
597    JXDemoFrame window = (JXDemoFrame) SwingUtilities.getWindowAncestor(this);
598
599    if (inputEventDispatcher == null)
600
601    {
602
603      inputEventDispatcher = new AbstractInputEventDispatcher()
604
605      {
606
607        // updates Highlighter for mouseEntered/mouseExited
608
609        // of all components in the frame's container hierarchy
610
611        @Override
612
613        protected void processMouseEvent(MouseEvent e)
614
615        {
616
617          if (MouseEvent.MOUSE_ENTERED == e.getID())
618
619          {
620
621            updateHighlighter(e.getComponent());
622
623          }
624
625          else if (MouseEvent.MOUSE_EXITED == e.getID())
626
627          {
628
629            updateHighlighter(null);
630
631          }
632
633        }
634
635
636
637      };
638
639    }
640
641    window.setInputEventDispatcher(inputEventDispatcher);
642
643    // </snip>
644
645
646
647  }
648
649
650
651  private void uninstallInputEventListener()
652
653  {
654
655    if (!(SwingUtilities.getWindowAncestor(this) instanceof JXDemoFrame))
656
657    {
658
659      return;
660
661    }
662
663    JXDemoFrame window = (JXDemoFrame) SwingUtilities.getWindowAncestor(this);
664
665    window.setInputEventDispatcher(null);
666
667    updateHighlighter(null);
668
669
670
671  }
672
673
674
675  private TreeTableModel createTreeModel()
676
677  {
678
679    Window window = SwingUtilities.getWindowAncestor(this);
680
681    return ComponentModels.getTreeTableModel(window != null ? window : this);
682
683  }
684
685
686
687  // ----------------- init
688
689
690
691  private void initComponents()
692
693  {
694
695    treeTable = new JXTreeTable();
696
697    treeTable.setName("componentTreeTable");
698
699    add(new JScrollPane(treeTable));
700
701
702
703    JComponent control = new JXPanel();
704
705    refreshButton = new JButton();
706
707    refreshButton.setName("refreshButton");
708
709
710
711    expandButton = new JButton();
712
713    expandButton.setName("expandTreeTableButton");
714
715
716
717    collapseButton = new JButton();
718
719    collapseButton.setName("collapseTreeTableButton");
720
721
722
723    // control.add(refreshButton);
724
725    control.add(expandButton);
726
727    control.add(collapseButton);
728
729    add(control, BorderLayout.SOUTH);
730
731
732
733  }
734
735
736
737  /**
738      * main method allows us to run as a standalone demo.
739      */
740
741  public static void main(String[] args)
742
743  {
744
745    SwingUtilities.invokeLater(new Runnable()
746
747    {
748
749      public void run()
750
751      {
752
753        JFrame frame = new JFrame(TreeTableDemo.class.getAnnotation(DemoProperties.class).value());
754
755
756
757        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
758
759        frame.getContentPane().add(new TreeTableDemo());
760
761        frame.setPreferredSize(new Dimension(800, 600));
762
763        frame.pack();
764
765        frame.setLocationRelativeTo(null);
766
767        frame.setVisible(true);
768
769      }
770
771    } );
772
773  }
774
775
776
777}
778
779