/*
* Copyright (C) 2012 Jason Gedge <http://www.gedge.ca>
*
* This file is part of the OpGraph project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package ca.gedge.opgraph.app.components.library;
import java.util.Enumeration;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import ca.gedge.opgraph.library.NodeData;
import ca.gedge.opgraph.library.NodeLibrary;
import ca.gedge.opgraph.library.NodeLibraryListener;
/**
* A tree model for viewing a node library.
*/
class NodeLibraryTreeModel
extends DefaultTreeModel
implements NodeLibraryListener
{
/** The node library */
private NodeLibrary library;
/** The filter being used */
private NodeInfoFilter filter;
/**
* Constructs a model that references a specified library.
*
* @param library the library
*/
public NodeLibraryTreeModel(NodeLibrary library) {
this(library, null);
}
/**
* Constructs a model that references a specified library and filters
* nodes based on a given string.
*
* @param library the library
* @param filter the filter string
*/
public NodeLibraryTreeModel(NodeLibrary library, NodeInfoFilter filter) {
super(new DefaultMutableTreeNode());
this.library = library;
this.filter = filter;
if(this.library != null) {
for(NodeData nodeData : this.library)
nodeRegistered(nodeData);
}
}
/**
* Gets whether or not a given node matches the filter.
*
* @param node the node to check
*
* @return <code>true</code> if the node fits the filter pattern,
* <code>false</code> otherwise
*/
public boolean matches(DefaultMutableTreeNode node) {
boolean ret = true;
if(filter != null) {
final Object obj = node.getUserObject();
if(obj != null && (obj instanceof NodeData))
ret = filter.isAccepted((NodeData)obj);
}
return ret;
}
/**
* Gets whether or not a node contains a child that matches the filter.
*
* @param node the node to begin searching from
*
* @return <code>true</code> if the given node contains a child that
* matches the filter, <code>false</code> otherwise
*/
public boolean containsMatchingChild(DefaultMutableTreeNode node) {
final Enumeration<?> e = node.breadthFirstEnumeration();
while(e.hasMoreElements()) {
final Object unknownNode = e.nextElement();
if(unknownNode instanceof DefaultMutableTreeNode) {
if(matches( (DefaultMutableTreeNode)unknownNode ))
return true;
}
}
return false;
}
/**
* Gets the child index for a given category. If a node does not exist
* for the category, one is created.
*
* @param category the category
*
* @return the node associated with the given category
*/
private DefaultMutableTreeNode getNodeForCategory(String category) {
final DefaultMutableTreeNode root = (DefaultMutableTreeNode)getRoot();
DefaultMutableTreeNode ret = null;
int index = 0;
for(; index < root.getChildCount(); ++index) {
final DefaultMutableTreeNode node = (DefaultMutableTreeNode)root.getChildAt(index);
int comp = category.compareTo(node.getUserObject().toString());
if(comp == 0) {
ret = node;
break;
} else if(comp == 1) {
break;
}
}
if(ret == null) {
ret = new DefaultMutableTreeNode(category);
insertNodeInto(ret, (DefaultMutableTreeNode)getRoot(), index);
}
return ret;
}
//
// NodeLibraryListener
//
@Override
public void nodeRegistered(NodeData info) {
final DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(info, false);
if(matches(newNode)) {
final String category = (info.category.length() == 0 ? "General" : info.category);
final DefaultMutableTreeNode node = getNodeForCategory(category);
if(node != null)
node.add(newNode);
}
}
@Override
public void nodeUnregistered(NodeData info) {
final String category = (info.category.length() == 0 ? "General" : info.category);
DefaultMutableTreeNode node = getNodeForCategory(category);
if(node != null) {
for(int index = 0; index < node.getChildCount(); ++index) {
final DefaultMutableTreeNode child = (DefaultMutableTreeNode)node.getChildAt(index);
if(child.getUserObject() == info) {
child.removeFromParent();
nodesWereRemoved(node, new int[]{index}, new Object[]{child});
break;
}
}
// Now that we've unregistered the node, recurse up through ancestors
// and remove them from their parents if they contain no children
while(node != null && node.getChildCount() == 0) {
final TreeNode parent = node.getParent();
if(parent != null) {
node.removeFromParent();
nodesWereRemoved(node.getParent(), new int[]{parent.getIndex(node)}, new Object[]{node});
}
if(node instanceof DefaultMutableTreeNode)
node = (DefaultMutableTreeNode)parent;
else
break;
}
}
}
}