/*
* Copyright 2003-2010 Tufts University Licensed under the
* Educational Community License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS"
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/*
* HierarchyModel.java
*
* Created on October 2, 2003, 10:56 AM
*/
package tufts.oki.hierarchy;
import java.util.Vector;
import java.util.HashMap;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.DefaultMutableTreeNode;
import java.util.Iterator;
import java.util.Enumeration;
/**
*
* @author Daisuke Fujiwara
*/
public class HierarchyModel implements osid.hierarchy.Hierarchy
{
private String description, name;
private osid.shared.Id ID;
boolean multipleParents = false;
boolean recursion = true;
private HashMap map;
private Vector availableTypes;
private DefaultTreeModel treeModel;
private int nextID = 1;
/** methods defined by Daisuke Fujiwara */
/**A method that returns a unique ID associated with this hierarchy model*/
protected String getNextID()
{
return Integer.toString(nextID++, 10);
}
/**A method that returns the associated tree model*/
public DefaultTreeModel getTreeModel()
{
return treeModel;
}
/**A method that fires the tree value changed event */
public void revalidateTree(HierarchyNode node)
{
if (treeModel != null && node != null)
treeModel.nodeChanged(node.getTreeNode());
}
/**A method that returns the root node of the hierarchy structure*/
protected HierarchyNode getRootNode() throws osid.hierarchy.HierarchyException
{
try
{
//this only works if the hierarchy is a single root structure
osid.hierarchy.NodeIterator i = getRootNodes();
HierarchyNode rootNode = (HierarchyNode)i.next();
return rootNode;
}
catch (osid.hierarchy.HierarchyException he)
{
throw new osid.hierarchy.HierarchyException("getRootNode caused a problem");
}
}
/** end **/
/** Creates a new instance of HierarchyModel */
public HierarchyModel()
{
map = new HashMap();
try
{
ID = new tufts.oki.shared.Id(getNextID());
}
catch (osid.shared.SharedException se)
{
System.err.println("shared exception");
}
name = "no name";
description = "no description";
availableTypes = new Vector();
}
public HierarchyModel(String name, String description)
{
this();
this.name = name;
this.description = description;
}
/**A method that adds a given type the list of the node types*/
public void addNodeType(osid.shared.Type type) throws osid.hierarchy.HierarchyException
{
if (type == null)
//throw new osid.hierarchy.HierarchyException(osid.hierarchy.HierarchyException.NULL_ARGUMENT);
throw new osid.hierarchy.HierarchyException("type can't be null");
if(!availableTypes.contains(type))
availableTypes.add(type);
else
throw new osid.hierarchy.HierarchyException("type already exists");
}
/**A method that removes a given type from the list of the node types*/
public void removeNodeType(osid.shared.Type nodeType) throws osid.hierarchy.HierarchyException
{
if (nodeType == null)
throw new osid.hierarchy.HierarchyException("type can't be null");
try
{
// check no Node has using this NodeType
for (osid.hierarchy.NodeIterator nodeIterator = getAllNodes(); nodeIterator.hasNext();)
{
if (nodeType.isEqual(nodeIterator.next().getType()))
throw new osid.hierarchy.HierarchyException("node is being used");
}
for (Iterator i = availableTypes.iterator(); i.hasNext();)
{
osid.shared.Type type = (osid.shared.Type)i.next();
if (nodeType.isEqual(type))
{
i.remove();
break;
}
}
}
catch (osid.hierarchy.HierarchyException oex)
{
throw new osid.hierarchy.HierarchyException(oex.getMessage());
}
//throw new osid.hierarchy.HierarchyException(osid.hierarchy.HierarchyException.NODE_TYPE_NOT_FOUND);
}
/**A method that returns whether the model allows multiple parents or not*/
public boolean allowsMultipleParents() throws osid.hierarchy.HierarchyException
{
return multipleParents;
}
/**A method that returns whether the model allows recursion or not*/
public boolean allowsRecursion() throws osid.hierarchy.HierarchyException
{
return recursion;
}
/**A methoid that creates a hierarchy node*/
public osid.hierarchy.Node createNode(osid.shared.Id nodeId, osid.shared.Id parentId, osid.shared.Type type, String name, String description) throws osid.hierarchy.HierarchyException
{
if ((nodeId == null) || (parentId == null) || (name == null) || (type == null) || (description == null))
throw new osid.hierarchy.HierarchyException("arguments are null");
DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode();
HierarchyNode node = new HierarchyNode(nodeId, treeNode);
node.setType(type);
node.updateDisplayName(name);
node.updateDescription(description);
treeNode.setUserObject(node);
//can we implement this in other way using the node interface?
try
{
HierarchyNode parentNode = (HierarchyNode)map.get(parentId.getIdString());
DefaultMutableTreeNode parentTreeNode = parentNode.getTreeNode();
if (parentTreeNode != null)
{
parentTreeNode.add(treeNode);
int[] childIndices = {parentTreeNode.getIndex(treeNode)};
treeModel.nodesWereInserted(parentTreeNode, childIndices);
}
else
throw new osid.hierarchy.HierarchyException("the parent node is null");
map.put(nodeId.getIdString(), node);
return (osid.hierarchy.Node)node;
}
catch (osid.shared.SharedException se)
{
throw new osid.hierarchy.HierarchyException("exception");
}
}
/**A method that creates a root node of the model*/
public osid.hierarchy.Node createRootNode(osid.shared.Id nodeId, osid.shared.Type type, String name, String description) throws osid.hierarchy.HierarchyException
{
if ((nodeId == null) || (name == null) || (type == null) || (description == null))
throw new osid.hierarchy.HierarchyException("arguments are null");
DefaultMutableTreeNode rootTreeNode = new DefaultMutableTreeNode();
HierarchyNode rootNode = new HierarchyNode(nodeId, rootTreeNode);
rootNode.setType(type);
rootNode.updateDisplayName(name);
rootNode.updateDescription(description);
rootTreeNode.setUserObject(rootNode);
try
{
map.put(nodeId.getIdString(), rootNode);
}
catch (osid.shared.SharedException se)
{
throw new osid.hierarchy.HierarchyException("Exception");
}
treeModel = new DefaultTreeModel(rootTreeNode);
return (osid.hierarchy.Node)rootNode;
}
/**A method that deletes the node with the given ID*/
public void deleteNode(osid.shared.Id nodeId) throws osid.hierarchy.HierarchyException
{
try
{
HierarchyNode node = (HierarchyNode)map.get(nodeId.getIdString());
if (node != null && !node.isRoot())
{
DefaultMutableTreeNode treeNode = node.getTreeNode();
if (treeNode != null)
treeModel.removeNodeFromParent(treeNode);
map.remove(nodeId.getIdString());
}
else
throw new osid.hierarchy.HierarchyException("can't delete the node");
}
catch (osid.shared.SharedException se)
{
throw new osid.hierarchy.HierarchyException("Exception");
}
}
/**A method that returns an iterator of the nodes contained in the model*/
public osid.hierarchy.NodeIterator getAllNodes() throws osid.hierarchy.HierarchyException
{
Vector list = new Vector();
for (Iterator i = map.values().iterator(); i.hasNext();)
list.add((osid.hierarchy.Node)i.next());
return (osid.hierarchy.NodeIterator)(new HierarchyNodeIterator(list));
}
/**A method that returns the description of the model*/
public String getDescription() throws osid.hierarchy.HierarchyException
{
return description;
}
/**A method that returns the display name of the model*/
public String getDisplayName() throws osid.hierarchy.HierarchyException
{
return name;
}
/**A method that returns the ID of the model*/
public osid.shared.Id getId() throws osid.hierarchy.HierarchyException
{
return ID;
}
/**A method that modifies the description of the model*/
public void updateDescription(java.lang.String description) throws osid.hierarchy.HierarchyException
{
this.description = description;
}
/**A method that retrieves the node associated with the given ID*/
public osid.hierarchy.Node getNode(osid.shared.Id nodeId) throws osid.hierarchy.HierarchyException
{
try
{
osid.hierarchy.Node node = (osid.hierarchy.Node)map.get(nodeId.getIdString());
return node;
}
catch (osid.shared.SharedException se)
{
throw new osid.hierarchy.HierarchyException("Exception");
}
}
/**A method that retrieves nodes types of the model*/
public osid.shared.TypeIterator getNodeTypes() throws osid.hierarchy.HierarchyException
{
return (osid.shared.TypeIterator) (new tufts.oki.shared.TypeIterator(availableTypes));
}
/**A method that returns an iterator of root nodes*/
public osid.hierarchy.NodeIterator getRootNodes() throws osid.hierarchy.HierarchyException
{
Vector rootNodes = new Vector();
for (Iterator i = map.values().iterator(); i.hasNext();)
{
osid.hierarchy.Node nextNode = (osid.hierarchy.Node)i.next();
if (nextNode.isRoot())
rootNodes.add(nextNode);
}
return (osid.hierarchy.NodeIterator)(new HierarchyNodeIterator(rootNodes));
}
public osid.hierarchy.TraversalInfoIterator traverse(osid.shared.Id startId, int mode, int direction, int levels) throws osid.hierarchy.HierarchyException
{
if ((mode != osid.hierarchy.Hierarchy.TRAVERSE_MODE_DEPTH_FIRST) && (mode != osid.hierarchy.Hierarchy.TRAVERSE_MODE_BREADTH_FIRST))
throw new osid.hierarchy.HierarchyException("unknown mode");
if ((direction != osid.hierarchy.Hierarchy.TRAVERSE_DIRECTION_UP) && (direction != osid.hierarchy.Hierarchy.TRAVERSE_DIRECTION_DOWN))
throw new osid.hierarchy.HierarchyException("unknown direction");
Vector traversalInfoList = new Vector();
HierarchyNode startingNode = (HierarchyNode)getNode(startId);
//osid.hierarchy.Node startingNode = getNode(startId);
//traversalInfoList.add(new HierarchyTraversalInfo(startingNode.getId(), startingNode.getName(), levels));
if (startingNode == null)
throw new osid.hierarchy.HierarchyException("unknown node");
else
{
Enumeration e;
DefaultMutableTreeNode startingTreeNode = startingNode.getTreeNode();
if (direction == osid.hierarchy.Hierarchy.TRAVERSE_DIRECTION_DOWN)
{
if (mode == osid.hierarchy.Hierarchy.TRAVERSE_MODE_DEPTH_FIRST)
e = startingTreeNode.depthFirstEnumeration();
else
e = startingTreeNode.breadthFirstEnumeration();
int maxLevel;
int currentLevel = startingTreeNode.getLevel();
int startLevel = currentLevel;
if (levels >= 0)
maxLevel = currentLevel + levels;
else
maxLevel = Integer.MAX_VALUE;
while (e.hasMoreElements())
{
DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode)e.nextElement();
if (nextNode.getLevel() > maxLevel)
break;
osid.hierarchy.Node node = (osid.hierarchy.Node)nextNode.getUserObject();
traversalInfoList.add((osid.hierarchy.TraversalInfo) (new HierarchyTraversalInfo(
node.getId(), node.getDisplayName(),
currentLevel - startLevel)));
}
}
else
{
HierarchyNode rootNode = (HierarchyNode)getRootNodes().next();
DefaultMutableTreeNode rootTreeNode = rootNode.getTreeNode();
if (mode == osid.hierarchy.Hierarchy.TRAVERSE_MODE_DEPTH_FIRST)
e = rootTreeNode.depthFirstEnumeration();
else
e = rootTreeNode.breadthFirstEnumeration();
int maxLevel;
int currentLevel = startingTreeNode.getLevel();
int startLevel = currentLevel + levels;
if (levels >= 0)
maxLevel = currentLevel;
else
maxLevel = Integer.MAX_VALUE;
// make a TraversalInfo for each node found
while (e.hasMoreElements())
{
DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode) e.nextElement();
if (nextNode.getLevel() >= startLevel)
{
osid.hierarchy.Node node = (osid.hierarchy.Node)nextNode.getUserObject();
traversalInfoList.add((osid.hierarchy.TraversalInfo) (new HierarchyTraversalInfo(
node.getId(), node.getDisplayName(),
currentLevel + startLevel)));
}
if (nextNode == startingTreeNode)
break;
}
Vector reverseVector = new Vector();
for (int j = traversalInfoList.size(); j >= 0; j--)
reverseVector.add(traversalInfoList.elementAt(j));
traversalInfoList = reverseVector;
}
}
HierarchyTraversalInfoIterator iterator = new HierarchyTraversalInfoIterator(traversalInfoList);
return (osid.hierarchy.TraversalInfoIterator)iterator;
}
/*
public Vector traverseUpDepthFirst(osid.hierarchy.Node node, int level)
{
Vector list = new Vector();
for(osid.hierarchy.NodeIterator iterator = node.getParents(); iterator.hasNext();)
{
osid.hierarchy.Node parent = iterator.next();
list.add(new HierarchyTraversalInfo(parent.getId(), parent.getName(), level));
if(!parent.isRoot() && level != 0)
list.add(traverseUpDepthFirst(parent, level - 1));
}
return list;
}
public Vector traverseUpBreadthFirst(osid.hierarchy.Node node, int level)
{
Vector list = new Vector();
for(osid.hierarchy.NodeIterator iterator = node.getParents(); iterator.hasNext();)
{
osid.hierarchy.Node parent = iterator.next();
list.add(new HierarchyTraversalInfo(parent.getId(), parent.getName(), level));
}
//how to do ?
return list;
}
public Vector traverseDownDepthFirst(osid.hierarchy.Node node, int level)
{
Vector list = new Vector();
for(osid.hierarchy.NodeIterator iterator = node.getChildren(); iterator.hasNext();)
{
osid.hierarchy.Node child = iterator.next();
traversalInfoList.add(new HierarchyTraversalInfo(child.getId(), child.getName(), level));
if(!child.isLeaf() && level != 0)
list.add(traverseDownDepthFirst(child, level - 1));
}
}
public Vector traverseDownBreadthFirst(osid.hierarchy.Node node, int level)
{
for(osid.hierarchy.NodeIterator iterator = node.getChildren(); iterator.hasNext();)
{
osid.hierarchy.Node child = iterator.next();
list.add(new HierarchyTraversalInfo(child.getId(), child.getName(), levels));
}
return list;
}
*/
}