Removing leaves that are between nodes in a JTree - swing

Let's assume that I have a JTree similar to the picture I provided, in which the number of leaves and nodes will vary every time I run the code. Now how could I remove the nodes that are empty (AKA have no children) since I can't check so see if its going to be empty as I add them to the tree?
I have tried using an enumeration to traverse the tree and check for every node to check how many children it has but that didn't help because even if I could tell that the node I am at is a node that needs to be removed I have to tell his parent to remove him I cant tell him to remove himself from his parent node.
What do I need to use to achieve what I am looking for?

Now how could I remove the nodes that are empty...so i want a node to either have only other nodes or only leaves but not both at the same time
Traverse the tree and check for nodes which have the following criteria
Is a leaf
Has siblings that are not leafs.
even if I could tell that the node I am at is a node that needs to be removed I have to tell his parent to remove him I cant tell him to remove himself from his parent node.
That is what the DefaultTreeModel.removeNodeFromParent() method does. So you can traverse the tree recursively and just remove nodes based upon your given criteria.
DefaultMutableTreeNode root = new DefaultMutableTreeNode ("Root");
//other code
DefaultTreeModel treeModel = new DefaultTreeModel(root);
JTree tree = new JTree(treeModel);
//populate tree
recurseTree(root, treeModel);
//method to recursively remove leaf nodes that have non-leaf siblings
private void recurseTree(MutableTreeNode node, DefaultTreeModel treeModel){
if ( node.isLeaf() ){
TreeNode parent = node.getParent();
for ( int i = 0; i < parent.getChildCount(); i++ ){
if ( !parent.getChildAt(i).isLeaf() ){
treeModel.removeNodeFromParent(node);
break;
}
}
}else{
for ( int i = 0; i < node.getChildCount(); i++ ){
recurseTree((MutableTreeNode)node.getChildAt(i), treeModel);
}
}
}
All this being said, it looks like a long route around the initial addition of those nodes. Without knowing the underlying data structure to populate the tree one can only guess as to how to go about preventing those nodes from being added in the first place.

Related

Add same DefaultMutableTreeNode to 2 different DefaultMutableTreeNode

I have a DefaultMutableTreeNode("birds") which has n number of children. Now I want to add this node to 2 different parents DefaultMutableTreeNode("animals") & DefaultMutableTreeNodes("animals2").
But as the add or insert method of DefaultMutableTreeNode removes the child from it's parent first. The DefaultMutableTreeNode("birds") is getting added in only one of the parent node. Whichever is the called later.
Is there any way around this?
DefaultMutableTreeNode birds = new DefaultMutableTreeNode("birds");
DefaultMutableTreeNode animals = new DefaultMutableTreeNode("animals");
DefaultMutableTreeNode animals2 = new DefaultMutableTreeNode("animals2");
animals.add(birds);
animals2.add(birds);
If I correct understand your problem the best way is to create a method which provides "birds-hierarchy":
private DefaultMutableTreeNode createBirdsNode() {
DefaultMutableTreeNode birds = new DefaultMutableTreeNode("birds");
// add another nodes to birds node.
return birds;
}
And later you can use this method to add the complete hierarchy.
animals.add(createBirdsNode());
animals2.add(createBirdsNode());
I finally ended up with below solution
JTree.DynamicUtilTreeNode.createChildren(DefaultMutableTreeNode parent, Object children)
JTree myTree = new JTree(parent)
This takes a root node as input and children object can be either an array, vector or hashtable. I used hashtable initially to store all the tree's children(birds) and then added them to 2 different root nodes(animals & animals2).

JTree dynamic node insertion

I have a list populated with duplicate entries. I am using a hash to store each unique entry from this list. Each key will then point to an object of type DefaultMutableTreeNode which represents the JTree node. My goal is to have this node point to all entries from the list which have the same node-same as the parent.
I have added these parent-nodes without problems but when the children nodes are added (via insertNodeInto), only parent nodes appear. A code-snippet is below; am very appreciative for advice / time.
// an unsorted list of items
List<MyObject>list = hash.get(key);
// clause to check for size
if (list.size() > 0) {
// iterate through each item in the list and fetch obj
for (int i=0; i < list.size(); i++) {
MyObject be = list.get(i);
// if object is not in hash, add to hash and point obj to new node
if (!hashParents.containsKey(be)) {
DefaultMutableTreeNode parent =
new DefaultMutableTreeNode(be.getSequence());
// add the key and jtree node to hash
hashParents.put(be, parent);
// insert node to tree, relead model
((DefaultMutableTreeNode)(root)).insert(
new DefaultMutableTreeNode("parent node"),
root.getChildCount());
((DefaultTreeModel)(tree.getModel())).reload();
}
// now that a parent-node exists, create a child
DefaultMutableTreeNode child = new DefaultMutableTreeNode("child");
// insert the new child to the parent (from the hash)
((DefaultTreeModel)(tree.getModel())).insertNodeInto(child, hashParents.get(be),
hashParents.get(be).getChildCount());
// render the tree visible
((DefaultTreeModel)(tree.getModel())).reload();
}
}
You make mistake here
// insert node to tree, relead model
((DefaultMutableTreeNode)(root)).insert(
new DefaultMutableTreeNode("parent node"),
root.getChildCount());
You already create node parent above, but don't use it. You insert in tree another node, but child nodes you still insert in parent. That's why they don't appear in tree.
This code fragment look like
// insert node to tree, relead model
((DefaultMutableTreeNode)(root)).insert(
parent,
root.getChildCount());

to get leaf nodes directly in actionscript

in a complex XML where I dont know the leaf node names/or the level of depth they are, how could I extract all the leaf nodes inside a XMLList variable directly?
Thanks.
Since no one has replied so far, I am assuming that there is no easy using ECMA to achieve this for a generic XML... and that leaves UDF as the only choice (the function would recursively keep checking if there are any childs left - if not then its a leaf).
Thanks Guys.
/**
* function to check for the leaf nodes and return
* an XMLListCollection of leaf nodes. Give it
* your xml and an empty object of XMLListCollection for result.
**/
private function leafNodes(x:XML, retList:XMLListCollection):void {
var xlist:XMLList;
xlist = x.children();
if (x.children().length() == 0) { // leaf node
retList.addItem(x);
return;
}
for each (var it:XML in xlist)
leafNodes(it, retList);
return;
}

Building a new Dictionary out of an old one? Help with Dictionary recursion

I'm working with a large set of hierarchical taxonomic terms, where each term ("203") has a matching "term203" movie clip on the stage, and am having trouble getting a recursive function to return all of a given term's descendants.
There is a main Dictionary() object with the following nested organization for each term:
{ [object Movie Clip] : { "tid":203, "parent":99, "name":"Culture", selected:false, "otherData":"etc" } }
...where the [object Movie Clip]'s instance name would be "term203". All of these object:subObjectArray items ("terms") are stored in a master taxonomy:Dictionary() object.
I've been trying to make a recursive function (which is in itself already a little above my head) that takes the click.target of a movie clip and returns a new Dictionary() object with all of the children and grandchildren and great grandchildren (etc) of that term, in the same, nested organization described above.
The code below traces the right number of recursive loops, but the returned Dictionary() object only contains the first run's terms (only the immediate children of the requested term).
var taxonomy:Dictionary = new Dictionary();
// ...Term info is loaded into taxonomy from a JSON-style text file)
// ...MOUSE_OVER event listeners are added to each
function revealChildren(hvr:MouseEvent):void {
trace("Spotlighting " + taxonomy[hvr.target].name + "'s children...");
for(var key:Object in getAllChildren(taxonomy[hvr.target].tid)) {
trace("Animating " + taxonomy[key].tid); // Traces only immediate children
var revealTween = new Tween(key, "alpha", Regular.easeInOut, key.alpha, 1, 1, true);
}
}
function getAllChildren(origin):Dictionary {
var children:Dictionary = new Dictionary();
for(var element:Object in taxonomy) {
if(taxonomy[element].parent == origin) {
var subSet = getAllChildren(taxonomy[element].tid);
children[element] = subSet; // *CAN'T ACCESS 'subSet' PROPERLY*
trace("Parent = " + origin);
trace("Matched! Adding " + taxonomy[element].tid + " as key and setting its value to " + subSet); // Traces correct amount of times, one for each descendent
}
else {
}
}
return children;
}
I certainly do not claim to be the most efficient AS3 programmer, so I am open to alternative configurations. However, after trying static and nested Arrays, I would prefer to continue using the Dictionary() object as my main pool.
As noted, only the immediate children end up animating in the revealChildren() function. It's mystifying to me then, that in the getAllChildren() function, all of the descendants trace sequentially (well in no particular order) in the output window.
Also I can't get any sort of name or property out of the subSet Object. That could be the problem.
I've only tested it as far as 'two generations,' but it seems that only the first round of calling the function successfully adds those terms to the new Dictionary() object and returns it intact to the animating function.
Too bad dict.filter(getDescendants) won't work. Please help!
To simplify things, I've added an output parameter called children. This is the Dictionary into which our function will store its results. It has a default value, so you don't need to specify one. In that case, it will create a new instance for itself.
function getAllChildren(origin:*, children:Dictionary = null):Dictionary {
if (children = null) children = new Dictionary();
for(var element:* in taxonomy) {
if(taxonomy[element].parent == origin) {
children[element] = taxonomy[element];
getAllChildren(taxonomy[element].tid, children);
}
}
return children;
}
When a child is discovered, it is copied over exactly: children[element] = taxonomy[element];
Next, the function calls itself recursively, supplying it the same output dictionary as it has been using.
Edit:
In response to your comment... Your code originally said this after finding a child named element:
children[element] = getAllChildren(taxonomy[element].tid);
You're making children[element] equal to a Dictionary object here. What you create is a tree structure, mapping MovieClip objects to Dictionary objects containing a similar mapping of its children. Using a for in loop on this structure will only give you the top-level children. It will not recursively traverse the entire tree.

libxml2 - remove child, but not grandchildren

I'm using libxml2 to parse HTML. I want to remove certain formatting tags like <center>, while keeping their content (for example, a link).
This means I'll have to remove certain child nodes from my xmlNodeSet, but keep that node's children.
Right now, I got this code:
xmlNodePtr parentNode = nodes->nodeTab[i];
if (parentNode != NULL) {
xmlNodePtr child = parentNode->children;
xmlNodePtr parentNextSibling = parentNode->next;
xmlNodePtr grandParent = NULL;
while (child) {
xmlUnlinkNode(child);
if (parentNextSibling != NULL) {
xmlAddPrevSibling(parentNextSibling, child);
}
else {
if (grandParent == NULL)
grandParent = parentNode->parent;
xmlAddChild(grandParent, child);
}
child = child->next;
}
xmlUnlinkNode(parentNode);
xmlFree(parentNode);
}
The code does add the child to the document, but it also deletes the node I was adding it as a sibling to. What am I doing wrong?
You're not saving off the child->next pointer before you cut it out of the tree. As soon as you unlink a node, it isn't part of the tree, so child->next becomes NULL. Then, after you reinsert it into the tree (before parentNode->next), the child->next pointer now points to what was previously parentNode->next, so the next time through the loop, you delete parentNode->next. Things can only go downhill from there. :-)