Path: blob/master/src/demo/share/jfc/SampleTree/DynamicTreeNode.java
41149 views
/*1* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/38394041import java.awt.Color;42import java.awt.Font;43import java.awt.GraphicsEnvironment;44import java.util.Random;45import javax.swing.tree.DefaultMutableTreeNode;464748/**49* DynamicTreeNode illustrates one of the possible ways in which dynamic50* loading can be used in tree. The basic premise behind this is that51* getChildCount() will be messaged from JTreeModel before any children52* are asked for. So, the first time getChildCount() is issued the53* children are loaded.<p>54* It should be noted that isLeaf will also be messaged from the model.55* The default behavior of TreeNode is to message getChildCount to56* determine this. As such, isLeaf is subclassed to always return false.<p>57* There are others ways this could be accomplished as well. Instead of58* subclassing TreeNode you could subclass JTreeModel and do the same59* thing in getChildCount(). Or, if you aren't using TreeNode you could60* write your own TreeModel implementation.61* Another solution would be to listen for TreeNodeExpansion events and62* the first time a node has been expanded post the appropriate insertion63* events. I would not recommend this approach though, the other two64* are much simpler and cleaner (and are faster from the perspective of65* how tree deals with it).66*67* NOTE: getAllowsChildren() can be messaged before getChildCount().68* For this example the nodes always allow children, so it isn't69* a problem, but if you do support true leaf nodes you may want70* to check for loading in getAllowsChildren too.71*72* @author Scott Violet73*/74@SuppressWarnings("serial")75public class DynamicTreeNode extends DefaultMutableTreeNode {76// Class stuff.7778/** Number of names. */79protected static float nameCount;80/** Names to use for children. */81protected static final String[] NAMES;82/** Potential fonts used to draw with. */83protected static Font[] fonts;84/** Used to generate the names. */85protected static Random nameGen;86/** Number of children to create for each node. */87protected static final int DEFAULT_CHILDREN_COUNT = 7;8889static {90String[] fontNames;9192try {93fontNames = GraphicsEnvironment.getLocalGraphicsEnvironment().94getAvailableFontFamilyNames();9596} catch (Exception e) {97fontNames = null;98}99if (fontNames == null || fontNames.length == 0) {100NAMES = new String[] { "Mark Andrews", "Tom Ball", "Alan Chung",101"Rob Davis", "Jeff Dinkins",102"Amy Fowler", "James Gosling",103"David Karlton", "Dave Kloba",104"Dave Moore", "Hans Muller",105"Rick Levenson", "Tim Prinzing",106"Chester Rose", "Ray Ryan",107"Georges Saab", "Scott Violet",108"Kathy Walrath", "Arnaud Weber" };109} else {110/* Create the Fonts, creating fonts is slow, much better to111do it once. */112int fontSize = 12;113114NAMES = fontNames;115fonts = new Font[NAMES.length];116for (int counter = 0, maxCounter = NAMES.length;117counter < maxCounter; counter++) {118try {119fonts[counter] = new Font(fontNames[counter], 0, fontSize);120} catch (Exception e) {121fonts[counter] = null;122}123fontSize = ((fontSize + 2 - 12) % 12) + 12;124}125}126nameCount = (float) NAMES.length;127nameGen = new Random(System.currentTimeMillis());128}129/** Have the children of this node been loaded yet? */130protected boolean hasLoaded;131132/**133* Constructs a new DynamicTreeNode instance with o as the user134* object.135*/136public DynamicTreeNode(Object o) {137super(o);138}139140@Override141public boolean isLeaf() {142return false;143}144145/**146* If hasLoaded is false, meaning the children have not yet been147* loaded, loadChildren is messaged and super is messaged for148* the return value.149*/150@Override151public int getChildCount() {152if (!hasLoaded) {153loadChildren();154}155return super.getChildCount();156}157158/**159* Messaged the first time getChildCount is messaged. Creates160* children with random names from names.161*/162protected void loadChildren() {163DynamicTreeNode newNode;164Font font;165int randomIndex;166SampleData data;167168for (int counter = 0; counter < DynamicTreeNode.DEFAULT_CHILDREN_COUNT;169counter++) {170randomIndex = (int) (nameGen.nextFloat() * nameCount);171String displayString = NAMES[randomIndex];172if (fonts == null || fonts[randomIndex].canDisplayUpTo(displayString)173!= -1) {174font = null;175} else {176font = fonts[randomIndex];177}178179if (counter % 2 == 0) {180data = new SampleData(font, Color.red, displayString);181} else {182data = new SampleData(font, Color.blue, displayString);183}184newNode = new DynamicTreeNode(data);185/* Don't use add() here, add calls insert(newNode, getChildCount())186so if you want to use add, just be sure to set hasLoaded = true187first. */188insert(newNode, counter);189}190/* This node has now been loaded, mark it so. */191hasLoaded = true;192}193}194195196