jdk
1/*
2* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3*
4* Redistribution and use in source and binary forms, with or without
5* modification, are permitted provided that the following conditions
6* are met:
7*
8* - Redistributions of source code must retain the above copyright
9* notice, this list of conditions and the following disclaimer.
10*
11* - Redistributions in binary form must reproduce the above copyright
12* notice, this list of conditions and the following disclaimer in the
13* documentation and/or other materials provided with the distribution.
14*
15* - Neither the name of Oracle nor the names of its
16* contributors may be used to endorse or promote products derived
17* from this software without specific prior written permission.
18*
19* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*/
31
32/*
33* This source code is provided to illustrate the usage of a given feature
34* or technique and has been deliberately simplified. Additional steps
35* required for a production-quality application, such as security checks,
36* input validation and proper error handling, might not be present in
37* this sample code.
38*/
39
40
41
42import java.awt.Color;43import java.awt.Font;44import java.awt.GraphicsEnvironment;45import java.util.Random;46import javax.swing.tree.DefaultMutableTreeNode;47
48
49/**
50* DynamicTreeNode illustrates one of the possible ways in which dynamic
51* loading can be used in tree. The basic premise behind this is that
52* getChildCount() will be messaged from JTreeModel before any children
53* are asked for. So, the first time getChildCount() is issued the
54* children are loaded.<p>
55* It should be noted that isLeaf will also be messaged from the model.
56* The default behavior of TreeNode is to message getChildCount to
57* determine this. As such, isLeaf is subclassed to always return false.<p>
58* There are others ways this could be accomplished as well. Instead of
59* subclassing TreeNode you could subclass JTreeModel and do the same
60* thing in getChildCount(). Or, if you aren't using TreeNode you could
61* write your own TreeModel implementation.
62* Another solution would be to listen for TreeNodeExpansion events and
63* the first time a node has been expanded post the appropriate insertion
64* events. I would not recommend this approach though, the other two
65* are much simpler and cleaner (and are faster from the perspective of
66* how tree deals with it).
67*
68* NOTE: getAllowsChildren() can be messaged before getChildCount().
69* For this example the nodes always allow children, so it isn't
70* a problem, but if you do support true leaf nodes you may want
71* to check for loading in getAllowsChildren too.
72*
73* @author Scott Violet
74*/
75@SuppressWarnings("serial")76public class DynamicTreeNode extends DefaultMutableTreeNode {77// Class stuff.78
79/** Number of names. */80protected static float nameCount;81/** Names to use for children. */82protected static final String[] NAMES;83/** Potential fonts used to draw with. */84protected static Font[] fonts;85/** Used to generate the names. */86protected static Random nameGen;87/** Number of children to create for each node. */88protected static final int DEFAULT_CHILDREN_COUNT = 7;89
90static {91String[] fontNames;92
93try {94fontNames = GraphicsEnvironment.getLocalGraphicsEnvironment().95getAvailableFontFamilyNames();96
97} catch (Exception e) {98fontNames = null;99}100if (fontNames == null || fontNames.length == 0) {101NAMES = new String[] { "Mark Andrews", "Tom Ball", "Alan Chung",102"Rob Davis", "Jeff Dinkins",103"Amy Fowler", "James Gosling",104"David Karlton", "Dave Kloba",105"Dave Moore", "Hans Muller",106"Rick Levenson", "Tim Prinzing",107"Chester Rose", "Ray Ryan",108"Georges Saab", "Scott Violet",109"Kathy Walrath", "Arnaud Weber" };110} else {111/* Create the Fonts, creating fonts is slow, much better to112do it once. */
113int fontSize = 12;114
115NAMES = fontNames;116fonts = new Font[NAMES.length];117for (int counter = 0, maxCounter = NAMES.length;118counter < maxCounter; counter++) {119try {120fonts[counter] = new Font(fontNames[counter], 0, fontSize);121} catch (Exception e) {122fonts[counter] = null;123}124fontSize = ((fontSize + 2 - 12) % 12) + 12;125}126}127nameCount = (float) NAMES.length;128nameGen = new Random(System.currentTimeMillis());129}130/** Have the children of this node been loaded yet? */131protected boolean hasLoaded;132
133/**134* Constructs a new DynamicTreeNode instance with o as the user
135* object.
136*/
137public DynamicTreeNode(Object o) {138super(o);139}140
141@Override142public boolean isLeaf() {143return false;144}145
146/**147* If hasLoaded is false, meaning the children have not yet been
148* loaded, loadChildren is messaged and super is messaged for
149* the return value.
150*/
151@Override152public int getChildCount() {153if (!hasLoaded) {154loadChildren();155}156return super.getChildCount();157}158
159/**160* Messaged the first time getChildCount is messaged. Creates
161* children with random names from names.
162*/
163protected void loadChildren() {164DynamicTreeNode newNode;165Font font;166int randomIndex;167SampleData data;168
169for (int counter = 0; counter < DynamicTreeNode.DEFAULT_CHILDREN_COUNT;170counter++) {171randomIndex = (int) (nameGen.nextFloat() * nameCount);172String displayString = NAMES[randomIndex];173if (fonts == null || fonts[randomIndex].canDisplayUpTo(displayString)174!= -1) {175font = null;176} else {177font = fonts[randomIndex];178}179
180if (counter % 2 == 0) {181data = new SampleData(font, Color.red, displayString);182} else {183data = new SampleData(font, Color.blue, displayString);184}185newNode = new DynamicTreeNode(data);186/* Don't use add() here, add calls insert(newNode, getChildCount())187so if you want to use add, just be sure to set hasLoaded = true
188first. */
189insert(newNode, counter);190}191/* This node has now been loaded, mark it so. */192hasLoaded = true;193}194}
195