/********************************************************************************
* *
* (c) Copyright 2010 Verizon Communications USA and The Open University UK *
* *
* This software is freely distributed in accordance with *
* the GNU Lesser General Public (LGPL) license, version 3 or later *
* as published by the Free Software Foundation. *
* For details see LGPL: http://www.fsf.org/licensing/licenses/lgpl.html *
* and GPL: http://www.fsf.org/licensing/licenses/gpl-3.0.html *
* *
* This software is provided by the copyright holders and contributors "as is" *
* and any express or implied warranties, including, but not limited to, the *
* implied warranties of merchantability and fitness for a particular purpose *
* are disclaimed. In no event shall the copyright owner or contributors be *
* liable for any direct, indirect, incidental, special, exemplary, or *
* consequential damages (including, but not limited to, procurement of *
* substitute goods or services; loss of use, data, or profits; or business *
* interruption) however caused and on any theory of liability, whether in *
* contract, strict liability, or tort (including negligence or otherwise) *
* arising in any way out of the use of this software, even if advised of the *
* possibility of such damage. *
* *
********************************************************************************/
package com.compendium.ui;
import java.awt.Point;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.compendium.LanguageProperties;
import com.compendium.ProjectCompendium;
import com.compendium.core.datamodel.IModel;
import com.compendium.core.datamodel.Link;
import com.compendium.core.datamodel.LinkProperties;
import com.compendium.core.datamodel.NodePosition;
import com.compendium.core.datamodel.NodeSummary;
import com.compendium.core.datamodel.PCSession;
import com.compendium.core.datamodel.View;
import com.compendium.core.datamodel.services.IViewService;
/**
* UIArrange defines code to arrange a map of nodes tidily
*
* @author Sajid Ali / Cheralathan Balakrishnan / Michelle Bachler / Alex Jarocha-Ernst / Lakshmi Prabhakaran
*/
public class UIArrangeLeftRight implements IUIArrange {
/**
* class's own logger
*/
final Logger log = LoggerFactory.getLogger(getClass());
/** The nodes to arrange.*/
private Hashtable htNodes = new Hashtable(51);
/** The nodes against their levels.*/
private Hashtable htNodesLevel = new Hashtable(51);
/** The nodes and their children.*/
private Hashtable htNodesBelow = new Hashtable(51);
/** The nodes against their ancestry.*/
private Hashtable htNodesAbove = new Hashtable();
/** Used for undo operations.*/
private Hashtable nodePositionsCloneHashtable = new Hashtable();
/** Used for redo operations.*/
private Hashtable nodePositionsCloneHashtableForRedo = new Hashtable();
/** Nodes at level one.*/
private Vector vtLevelOneNodes = new Vector(51);
/** Links to arrange.*/
private Vector vtLinks = new Vector(51);
/** Nodes against their levels.*/
private Vector vtNodesLevel = new Vector(51);
/** Nodes against thier levels in order.*/
private Vector vtNodesLevelOrdered = new Vector(51);
/** List of node levels.*/
private Vector nodeLevelList = new Vector();
/** The view service for accessing the databse.*/
private IViewService vs = null;
/** The session object for the current user with the current database.*/
private PCSession session = null;
/** The maximum indent level.*/
private int nMaxLevel = 0;
/** Node ID against Y position set or not.*/
private Hashtable htNodeYPositionSet = new Hashtable();
/** The number of position above the pointer position */
private int abovePointerPos = 0;
/** The number of position below the pointer position */
private int belowPointerPos = 1;
/** The number of children below the pointer position */
private int childSizeBelow = 0;
/** The number of children above the pointer position */
private int childSizeAbove = 0;
/** max number a node can recurse */
private int recursionCount = 3;
/**
* Constructor. Does nothing.
*/
public UIArrangeLeftRight() {}
/**
* Clear all the Vectors and Hashtables used to perform the arrange operations.
*/
public void clearData() {
htNodesLevel.clear();
htNodes.clear();
htNodesBelow.clear();
htNodesAbove.clear();
vtLinks.removeAllElements();
vtLevelOneNodes.removeAllElements();
vtNodesLevel.removeAllElements();
vtNodesLevelOrdered.removeAllElements();
nodeLevelList.removeAllElements();
}
/**
* Process the given view for arranging.
* @param view com.compendium.core.datamodel.View, the view to arrange.
*/
public boolean processView(View view) {
clearData();
IModel model = ProjectCompendium.APP.getModel();
session = model.getSession();
vs = model.getViewService();
Vector vtTemp = new Vector();
try {
vtTemp = vs.getNodePositions(session, view.getId());
}
catch(Exception ex) {
ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIArrangeLeftRight.cannotGetNodes") + view.getLabel()+"." + ex.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
}
nodePositionsCloneHashtable.clear();
for ( int i = 0; i < vtTemp.size(); i++) {
nodePositionsCloneHashtable.put(
((NodePosition)vtTemp.elementAt(i)).getNode().getId(),
((NodePosition)vtTemp.elementAt(i)).getClone());
}
// GET NODES FOR THIS VIEW AND STORE INTO HASTABLE BY ID
for(Enumeration en = vtTemp.elements();en.hasMoreElements();) {
NodePosition nodePos = (NodePosition)en.nextElement();
NodeSummary node = nodePos.getNode();
String key = node.getId();
htNodes.put(key, node);
}
for(Enumeration f = htNodes.elements();f.hasMoreElements();) {
NodeSummary nodeToPrint = (NodeSummary)f.nextElement();
//store the node into the hashtable.. the key being the nodeid, the object being the level integer
String key = nodeToPrint.getId();
htNodesLevel.put(key,new Integer(0));
}
//get the nodes and level numbers into a ht htNodesLevel
if (!startLevelCalculation(view)) {
return false;
}
return true;
}
/**
* This will arrange the nodes in the given view.
* @param view com.compendium.core.datamodel.View, the view to arrange.
* @param viewFrame com.compenduim.ui.UIViewFrame, the frame of the map view to arrange.
*/
public void arrangeView(View view, UIViewFrame viewFrame) {
UIViewPane uiViewPane = null;
if (viewFrame instanceof UIMapViewFrame){
uiViewPane = ((UIMapViewFrame)viewFrame).getViewPane();
processView(view);
//get the number of levels
int highestLevel = 0;
for(Enumeration e = htNodesLevel.keys();e.hasMoreElements();) {
String nodeId = (String)e.nextElement();
int level = ((Integer)htNodesLevel.get(nodeId)).intValue();
if (level > highestLevel) {
highestLevel = level;
}
}
int[] horizontalSep = new int[highestLevel];
int maxLevel = 0;
//get the maxiumum width of a uinode based on its bounds
for(Enumeration e = htNodesLevel.keys();e.hasMoreElements();) {
String nodeId = (String)e.nextElement();
//get the uinode and get its bounds/ccordinates
UINode uinode = ((UINode) ((UIMapViewFrame)viewFrame).getViewPane().get(nodeId));
int level = ((Integer)htNodesLevel.get(nodeId)).intValue();
if (level > maxLevel) {
maxLevel = level;
}
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int width = uinode.getWidth();
if (uiViewPane != null) {
Point p = UIUtilities.scalePoint(width, width, uiViewPane.getScale());
width = p.x;
}
if (level > 0) {
int sepLevel = horizontalSep[level-1];
if(width > sepLevel)
horizontalSep[level-1] = width + FormatProperties.arrangeLeftHorizontalGap;
}
}
// begin edit - Lakshmi (10/25/05)
// First sort nodes parent wise and then set Y position for the node.. This might some what minimize cross over links
sortNodesParentwise();
setYPositionForNodes(viewFrame);
//end edit - Lakshmi
if (nodeLevelList.size() > 0) {
compactNodesInList(viewFrame, (Vector)nodeLevelList.elementAt(0));
}
//begin edit - Lakshmi (10/25/05)
// This is to put all parents at the center of their children
if(nodeLevelList.size() > 1){
for(int i =0; i < ((Vector)nodeLevelList.get(0)).size(); i++){
finalizeYPos(viewFrame,(String)((Vector)nodeLevelList.get(0)).get(i));
}//end for
}//end if
//end edit - Lakshmi
//this hashtable maintains a count of nodes present on a particular level (key)
Hashtable htCount = new Hashtable();
for(int i=vtNodesLevel.size()-1; i >= 0; i--) {
String nodeId = (String)vtNodesLevel.elementAt(i);
int level = ((Integer)htNodesLevel.get(nodeId)).intValue();
int countAtLevel = 0;
int numberOfChildren = 0;
if(htNodesBelow.containsKey(nodeId))
numberOfChildren = ((Vector)htNodesBelow.get(nodeId)).size();
if(htCount.containsKey(new Integer(level)))
countAtLevel = ((Integer)htCount.get(new Integer(level))).intValue();
countAtLevel++;
if(numberOfChildren > 0)
countAtLevel = countAtLevel + (new Integer((numberOfChildren+1)/2)).intValue();
htCount.put(new Integer(level), new Integer(countAtLevel));
//get the uinode and set its bounds/ccordinates
UINode uinode = ((UINode) ((UIMapViewFrame)viewFrame).getViewPane().get(nodeId));
if(uinode != null) {
//get the x and y coordinates with the text field width in view for right centering..
int newX = 0;
if (view.equals(ProjectCompendium.APP.getHomeView())) {
newX = 70;
}
int j = 0;
for (j = 0; j < level; j++) {
newX += horizontalSep[j];
}
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int width = uinode.getWidth();
double scale = uiViewPane.getScale();
if (uiViewPane != null) {
Point p = UIUtilities.scalePoint(width, width, scale);
width = p.x;
}
newX -= ((horizontalSep[j-1]/2) + (width/2));
int newY = uinode.getNodePosition().getYPos();
//uinode.getNodePosition().setPos(newX, newY);
Point ptNew = new Point( newX, newY);
//uinode.setPosition(ptNew);
if (uiViewPane != null) {
Point loc = UIUtilities.transformPoint(newX ,newY, scale);
uinode.setBounds(loc.x, loc.y,
uinode.getWidth(),
uinode.getHeight());
}
uinode.updateLinks();
try {
view.setNodePosition(nodeId, ptNew);
}
catch(Exception ex) {
log.error("Error...", ex);
log.info("Error: (UIArrange.arrangeView) \n\n"+ex.getMessage()); //$NON-NLS-1$
}
}
}
if (uiViewPane != null)
uiViewPane.repaint();
Vector vtTemp = new Vector();
try {
vtTemp = vs.getNodePositions(session, view.getId());
}
catch(Exception ex) {
ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIArrange.cannotGetNodes") + view.getLabel()+". " + ex.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
}
nodePositionsCloneHashtableForRedo.clear();
for ( int i = 0; i < vtTemp.size(); i++) {
nodePositionsCloneHashtableForRedo.put(
((NodePosition)vtTemp.elementAt(i)).getNode().getId(),
((NodePosition)vtTemp.elementAt(i)).getClone());
}
} else {
ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIArrangeLeftRight.cannotArrange")); //$NON-NLS-1$
}
}//end arrangeView
/**
* Helper method. Calculate Level One Nodes here.
* @param view com.compendium.core.datamodel.View, the view to calculate lvel noe nodes for.
*/
private int calculateLevelOneNodes(View view) {
int nLevel = 1;
// upgrade the level with the current view
//nLevel = nNodeLevelUp;
IModel model = ProjectCompendium.APP.getModel();
PCSession session = ProjectCompendium.APP.getModel().getSession();
IViewService vs = model.getViewService();
vtLinks = new Vector(51);
try {
vtLinks = vs.getLinks(session, view.getId());
}
catch(Exception ex) {
ProjectCompendium.APP.displayError("Exception: (UIArrange.calculateLevelOneNodes) " + ex.getMessage()); //$NON-NLS-1$
}
if(htNodes.size() == 0)
return -1;
/**
* get each node and check if it is level 1 node
*/
for(Enumeration e = htNodes.elements();e.hasMoreElements();) {
int nNodeLevelOne = 1;
NodeSummary node = (NodeSummary)e.nextElement();
String key = node.getId();
// execute only if the node is new
if ( ((Integer)htNodesLevel.get(key)).intValue() == 0 ) {
/**
* Compare one end of the link with the current node for a match
* link.getTo() ------------<<------------ link.getFrom()
* ^^^^^^^^^^^^^^
* nodeOther = link.getFrom()
*/
LinkProperties props = null;
Link link = null;
// get links corresponding to this node
for (Enumeration eL = vtLinks.elements(); eL.hasMoreElements();) {
props = (LinkProperties)eL.nextElement();
link = props.getLink();
// TO FIX OLD BUG WHICH SHOULD NOT LONGER HAPPEN
if ( (link.getFrom().getId()).equals( link.getTo().getId() ) ) {
vtLinks.remove((Object)link);
}
else if( (link.getFrom()).getId().equals(key) || (link.getTo()).getId().equals(key)) {
if( (link.getFrom()).getId().equals(node.getId())) {
nNodeLevelOne *= 0;
break;
}else {
nNodeLevelOne *= 1;
}
}
}
/**
* if node on level one then export it.
*/
if(nNodeLevelOne == 1) {
// do for new nodes (whose levels are not set)
if(!(node.getLabel()).equals("Home Window")) { //$NON-NLS-1$
// add to vector with level one nodes
vtLevelOneNodes.addElement(node);
// set the level number for this node
htNodesLevel.put(key, new Integer(nNodeLevelOne));
}
}
}
}
// Reversing the elements of levelonenodes vector into a temp vector for proper
// ordering.. the elements in the levelonenodes vector seems to be in the reverse order!
Vector vtTemp = new Vector();
int numOfNodes = vtLevelOneNodes.size();
vtTemp.setSize(numOfNodes);
int pos = numOfNodes-1;
for (Enumeration eN = vtLevelOneNodes.elements(); eN.hasMoreElements();) {
NodeSummary node = (NodeSummary)eN.nextElement();
vtTemp.setElementAt(node,pos--);
}
vtLevelOneNodes.removeAllElements();
vtLevelOneNodes = vtTemp;
return nLevel;
}
/**
* Helper method. Handle the level calculations,
* @param view com.compendium.core.datamodel.View, the view to calculate levels for.
*/
private boolean startLevelCalculation(View view) {
int nLevel = 1;
nLevel = calculateLevelOneNodes(view);
// Reversing the elements of vtLinks vector into a temp vector for proper
// ordering.. the elements in the vtLinks vector seems to be in the reverse order!
Vector vtTemp = new Vector();
int numOfNodes = vtLinks.size();
vtTemp.setSize(numOfNodes);
int pos = numOfNodes-1;
LinkProperties props = null;
Link link = null;
for (Enumeration eN = vtLinks.elements(); eN.hasMoreElements();) {
props = (LinkProperties)eN.nextElement();
vtTemp.setElementAt(props,pos--);
}
vtLinks.removeAllElements();
vtLinks = vtTemp;
/**
* For all level one nodes start recursive export
*/
for(int i=0;i<vtLevelOneNodes.size();i++) {
//set the node in the position vector
NodeSummary levelOneNode = ((NodeSummary)vtLevelOneNodes.elementAt(i));
vtNodesLevel.addElement(levelOneNode.getId());
int yPositionForLevel1 = ( (NodePosition)nodePositionsCloneHashtable.get(levelOneNode.getId())).getYPos();
int secondYPositionForLevel1 = 0;
int indexForLevel1 = 0;
while (nodeLevelList.size() == 0) {
nodeLevelList.addElement(new Vector());
}
Vector nodeListAtLevel1 = (Vector)nodeLevelList.elementAt(0);
secondYPositionForLevel1 = 0;
// SOME SORT OF NODE ORDERING BY LEVEL AND Y POSITION ?
//-- begin sort(upto the current node in for loop) for level one based on y-position
//-- find a node's y position > current node's y position in level 1
indexForLevel1 = 0;
while ((indexForLevel1 < nodeListAtLevel1.size()) && (yPositionForLevel1 > secondYPositionForLevel1)) {
secondYPositionForLevel1 = ( (NodePosition)nodePositionsCloneHashtable.get(nodeListAtLevel1.elementAt(indexForLevel1))).getYPos();
indexForLevel1++;
}
//-- insert at the correct position - sorted by y position
if (indexForLevel1 == nodeListAtLevel1.size()) {
if (yPositionForLevel1 > secondYPositionForLevel1)
nodeListAtLevel1.addElement(levelOneNode.getId());
else
nodeListAtLevel1.insertElementAt(levelOneNode.getId(), (indexForLevel1 == 0)?indexForLevel1:indexForLevel1 - 1);
}
else {
nodeListAtLevel1.insertElementAt(levelOneNode.getId(), (indexForLevel1 == 0)?indexForLevel1:indexForLevel1 - 1);
}
//-- end sort
// PROCESS CURRENT NODES LINKS
for(Enumeration e = vtLinks.elements(); e.hasMoreElements();) {
props = (LinkProperties)e.nextElement();
link = props.getLink();
// check if this link is tied to the given node..
if((link.getTo()).getId().equals(levelOneNode.getId())) {
// get the from node from this link
NodeSummary node = (NodeSummary)htNodes.get((link.getFrom()).getId());
if (node != null) {
Integer previousLevel = (Integer)htNodesLevel.get(node.getId());
if ( (previousLevel != null) && (previousLevel.intValue() < (nLevel+1))) {
htNodesLevel.put(node.getId(),new Integer(nLevel+1));
}
//increment the vector of nodes below this node
Vector oldVector = null;
if(htNodesBelow.get(levelOneNode.getId()) != null)
oldVector = (Vector)htNodesBelow.get(levelOneNode.getId());
else
oldVector = new Vector();
int yPosition = ( (NodePosition)nodePositionsCloneHashtable.get(node.getId())).getYPos();
int secondYPosition = 0;
int index = 0;
boolean found = false;
while ((index < oldVector.size()) && (yPosition > secondYPosition)) {
secondYPosition = ( (NodePosition)nodePositionsCloneHashtable.get(oldVector.elementAt(index))).getYPos();
if (node.getId().equals((String)oldVector.elementAt(index))) {
found = true;
break;
}
index++;
}
if (index == oldVector.size()) {
if (yPosition > secondYPosition) {
oldVector.addElement(node.getId());
}
else if (!found) {
oldVector.insertElementAt(node.getId(), (index == 0)?index:index - 1);
}
} else if (!found) {
oldVector.insertElementAt(node.getId(), (index == 0)?index:index - 1);
}
NodeSummary mainNode = (NodeSummary)htNodes.get(node.getId());
//add the parent
Vector vtParentNodes = new Vector();
if (htNodesAbove.get(node.getId()) != null) {
//begin edit - Lakshmi (10/25/05)
// Get all parents for a node. Keeping track of all the parents, helps to sort child nodes and position them around
//their parents if possible.
vtParentNodes = (Vector) htNodesAbove.get(node.getId());
for(int j=0; j<vtParentNodes.size();j++){
String nodeAboveId = (String)vtParentNodes.get(j);
NodePosition np = ( (NodePosition)nodePositionsCloneHashtable.get(nodeAboveId));
int previousParentYPosition = np.getYPos();
int currentParentYPosition = ( (NodePosition)nodePositionsCloneHashtable.get(levelOneNode.getId())).getYPos();
if(nodeAboveId != levelOneNode.getId()) {
if (currentParentYPosition < previousParentYPosition) {
vtParentNodes.insertElementAt(levelOneNode.getId(), j);
break ;
}else {
vtParentNodes.add(levelOneNode.getId());
break;
}//end else
} //end if
} //end for
} else {
vtParentNodes.add(levelOneNode.getId());
} //end else
htNodesAbove.put(node.getId(), vtParentNodes);
mainNode.setParentNode((NodeSummary)htNodes.get((String) vtParentNodes.lastElement()));
// end edit - Lakshmi
if ((previousLevel != null) && (previousLevel.intValue() != 0)) {
if (previousLevel.intValue() < (nLevel + 1)) {
((Vector)nodeLevelList.elementAt(previousLevel.intValue()-1)).removeElement(node.getId());
}
else {
//oldVector.addElement(node.getId());
htNodesBelow.put(levelOneNode.getId(),oldVector);
//set the node in the position vector
vtNodesLevel.addElement(node.getId());
if (!startRecursiveCalculations(node,(nLevel+1))) {
return false;
}
continue;
}
}
while (nodeLevelList.size() < (nLevel + 1)) {
nodeLevelList.addElement(new Vector());
}
Vector nodeListAtLevel = (Vector)nodeLevelList.elementAt(nLevel);
secondYPosition = 0;
index = 0;
while ((index < nodeListAtLevel.size()) && (yPosition > secondYPosition)) {
secondYPosition = ( (NodePosition)nodePositionsCloneHashtable.get(nodeListAtLevel.elementAt(index))).getYPos();
index++;
}
if (index == nodeListAtLevel.size()) {
if (yPosition > secondYPosition) {
nodeListAtLevel.addElement(node.getId());
} else {
nodeListAtLevel.insertElementAt(node.getId(), (index == 0)?index:index - 1);
}
}
else {
nodeListAtLevel.insertElementAt(node.getId(), (index == 0)?index:index - 1);
}
//oldVector.addElement(node.getId());
htNodesBelow.put(levelOneNode.getId(),oldVector);
//set the node in the position vector
vtNodesLevel.addElement(node.getId());
if (!startRecursiveCalculations(node,(nLevel+1))) {
return false;
}
}
}
}
}
return true;
}
private Hashtable nodesRecursed = new Hashtable(51);
/**
* Helper method. This will calculate recursively all the nodes below. the given node.
* @param node com.compendium.core.datamodel.NodeSummary, the node to calculate for.
* @param LN, the level number.
*/
private boolean startRecursiveCalculations(NodeSummary node, int LN) {
Integer count = new Integer(1);
if(nodesRecursed.containsKey(node.getId())){
count = (Integer) nodesRecursed.get(node.getId());
if(count.intValue() > recursionCount) {
return true;
} else {
count = new Integer(count.intValue() + 1);
nodesRecursed.put(node.getId(), count);
}
} else {
nodesRecursed.put(node.getId(), count);
}
NodeSummary nodeFrom = new NodeSummary();
String sToNodeID = node.getId();
LinkProperties props = null;
Link link = null;
// get the links to this node
for(Enumeration e = vtLinks.elements(); e.hasMoreElements();) {
int levelNumber = LN;
props = (LinkProperties)e.nextElement();
link = props.getLink();
// check if this link is tied to the given node..
if((link.getTo()).getId().equals(sToNodeID)) {
if (link.getTo().getId().equals(link.getFrom().getId()) ) {
ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIArrange.message1a")+ //$NON-NLS-1$
": '"+node.getLabel()+"' "+ //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIArrange.message1b")+"\n\n"+ //$NON-NLS-1$ //$NON-NLS-2$
LanguageProperties.getString(LanguageProperties.UI_GENERAL_BUNDLE, "UIArrange.message1c")); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
// get the from node from this link
nodeFrom = (NodeSummary)htNodes.get((link.getFrom()).getId());
if (nodeFrom == null) {
continue;
}
levelNumber += 1;
String sFromNodeID = nodeFrom.getId();
// store the node in nodelevel hashtable with level info
Integer previousLevel = (Integer)htNodesLevel.get(sFromNodeID);
if ( (previousLevel != null) && (previousLevel.intValue() < levelNumber)) {
htNodesLevel.put(sFromNodeID, new Integer(levelNumber));
// if (!htNodesLinks.containsKey(sFromNodeID))
// htNodesLinks.put(sFromNodeID, new Hashtable());
// Hashtable htLinks = htNodes.get(sFromNodeID);
// htLinks.put(levelNumber, link);
// htNodesLinks.put(sFromNodeID, htLinks)
}
//increment the vector of nodes below this node
Vector oldVector = null;
if(htNodesBelow.get(node.getId()) != null)
oldVector = (Vector)htNodesBelow.get(node.getId());
else
oldVector = new Vector();
int yPosition = ( (NodePosition)nodePositionsCloneHashtable.get(sFromNodeID)).getYPos();
int secondYPosition = 0;
int index = 0;
boolean found = false;
while ((index < oldVector.size()) && (yPosition > secondYPosition)) {
//NodeSummary tempNode = (NodeSummary)htNodes.get(oldVector.elementAt(index));
secondYPosition = ( (NodePosition)nodePositionsCloneHashtable.get(oldVector.elementAt(index))).getYPos();
if (nodeFrom.getId().equals((String)oldVector.elementAt(index))) {
found = true;
break;
}
index++;
}
if (index == oldVector.size()) {
if (yPosition > secondYPosition) {
oldVector.addElement(nodeFrom.getId());
}
else if (!found) {
oldVector.insertElementAt(nodeFrom.getId(), (index == 0)?index:index - 1);
}
}
else if (!found) {
oldVector.insertElementAt(nodeFrom.getId(), (index == 0)?index:index - 1);
}
NodeSummary oFromNode = (NodeSummary)htNodes.get(sFromNodeID);
//add the parent
Vector vtParentNodes = new Vector();
if (htNodesAbove.get(oFromNode.getId()) != null) {
//begin edit - Lakshmi (10/25/05)
// Get all parents for a node. Keeping track of all the parents, helps to sort child nodes and position them around
//their parents if possible.
vtParentNodes = (Vector) htNodesAbove.get(sFromNodeID);
int currentParentYPosition = ((NodePosition)nodePositionsCloneHashtable.get(sToNodeID)).getYPos();
boolean isInserted = false;
for(int j=0; j<vtParentNodes.size();j++){
String nodeAboveId = (String)vtParentNodes.get(j);
NodePosition np = ( (NodePosition)nodePositionsCloneHashtable.get(nodeAboveId));
int previousParentYPosition = np.getYPos();
if(nodeAboveId != sToNodeID) {
if (currentParentYPosition < previousParentYPosition) {
vtParentNodes.insertElementAt(sToNodeID, j);
isInserted = true;
break ;
}//end if
} //end if
} // end for
if(!isInserted){
vtParentNodes.add(sToNodeID);
} //end if
} else {
vtParentNodes.add(sToNodeID);
} //end else
htNodesAbove.put(sFromNodeID, vtParentNodes);
oFromNode.setParentNode((NodeSummary)htNodes.get(vtParentNodes.lastElement()));
// end edit - Lakshmi
if ((previousLevel != null) && (previousLevel.intValue() != 0)) {
if (previousLevel.intValue() < levelNumber) {
((Vector)nodeLevelList.elementAt(previousLevel.intValue()-1)).removeElement(sFromNodeID);
}
else {
htNodesBelow.put(sToNodeID, oldVector);
//the maximum level number
if(levelNumber > nMaxLevel)
nMaxLevel = levelNumber;
//set the node in the position vector
vtNodesLevel.addElement(sFromNodeID);
if (!startRecursiveCalculations(nodeFrom, levelNumber))
return false;
continue;
}
}
while (nodeLevelList.size() < levelNumber) {
nodeLevelList.addElement(new Vector());
}
Vector nodeListAtLevel = (Vector)nodeLevelList.elementAt(levelNumber - 1);
secondYPosition = 0;
index = 0;
while ((index < nodeListAtLevel.size()) && (yPosition > secondYPosition)) {
secondYPosition = ( (NodePosition)nodePositionsCloneHashtable.get(nodeListAtLevel.elementAt(index))).getYPos();
index++;
}
if (index == nodeListAtLevel.size() ) {
if (yPosition > secondYPosition) {
nodeListAtLevel.addElement(sFromNodeID);
} else {
nodeListAtLevel.insertElementAt(sFromNodeID, (index == 0)?index:index - 1);
}
} else {
nodeListAtLevel.insertElementAt(sFromNodeID, (index == 0)?index:index - 1);
}
htNodesBelow.put(sToNodeID, oldVector);
//the maximum level number
if(levelNumber > nMaxLevel)
nMaxLevel = levelNumber;
//set the node in the position vector
vtNodesLevel.addElement(sFromNodeID);
if (!startRecursiveCalculations(nodeFrom, levelNumber))
return false;
}
}
return true;
}
/**
* Helper method. Sort the node calculated so far by thier parents.
*/
private void sortNodesParentwise() {
// this hashtable maintains a vector of nodeIDs that has been compared for sorting against the nodeId (key)
Hashtable htNodesChecked = new Hashtable();
for (int i = 1 ; i < nodeLevelList.size(); i++) {
Vector currentLevelList = (Vector)nodeLevelList.elementAt(i);
for (int j = 0; j < currentLevelList.size(); j++) {
NodeSummary nodeToSort = (NodeSummary)htNodes.get(currentLevelList.elementAt(j));
Vector vtParentNode = (Vector) htNodesAbove.get(nodeToSort.getId());
NodeSummary parentNodeSummary = ((NodeSummary)htNodes.get(vtParentNode.firstElement()));
String sParentNode = parentNodeSummary.getId();
int nIndexOfFirstParent = ((Vector)nodeLevelList.get(i -1)).indexOf(sParentNode);
//int firstParentYPosition = ((NodePosition)nodePositionsCloneHashtable.get(sParentNode)).getYPos();
//begin edit - Lakshmi (10/25/05)
// If the child node's first parent is below the parent of the node below current(child) node,
// then move the node below above. i.e. child nodes are positioned according to the parent's position.
// This is to minimize the cross over links.
Vector vtCheckedNodes = new Vector();
if (htNodesChecked.get(nodeToSort.getId()) != null){
vtCheckedNodes = (Vector) htNodesChecked.get(nodeToSort.getId());
}// end if
for (int k = j +1; k < currentLevelList.size(); k++) {
NodeSummary node = (NodeSummary)htNodes.get(currentLevelList.elementAt(k));
if (node != null) {
if(!vtCheckedNodes.contains(node.getId())){
Vector vtParentNodes = (Vector)htNodesAbove.get(node.getId());
if((vtParentNodes != null) && (vtParentNodes.size() > 0)){
for(int m = 0; m < vtParentNodes.size() ; m++){
String sID = (String)vtParentNodes.get(m);
NodePosition curNodeParent = (NodePosition)nodePositionsCloneHashtable.get(sID);
if (curNodeParent != null) {
int nIndexOfSecondParent = ((Vector)nodeLevelList.get(i -1)).indexOf(sID);
if ((nIndexOfFirstParent > nIndexOfSecondParent ) &&(nIndexOfSecondParent > -1)){
String sFirstNodeID = (String)currentLevelList.elementAt(k);
currentLevelList.remove(k);
currentLevelList.insertElementAt(sFirstNodeID, j);
nIndexOfFirstParent = ((Vector)nodeLevelList.get(i -1)).indexOf(((Vector)htNodesAbove.get(sFirstNodeID)).firstElement());
nodeToSort = (NodeSummary)htNodes.get(sFirstNodeID);
break ;
} else if((nIndexOfFirstParent == nIndexOfSecondParent) && (sID.equals(sParentNode))){
String sSecondNodeParent = node.getParentNode().getId();
int nIndexOfSecondNodeParent = ((Vector)nodeLevelList.get(i -1)).indexOf(sSecondNodeParent);
String sFirstNodeParent = nodeToSort.getParentNode().getId();
int nIndexOfFirstNodeParent = ((Vector)nodeLevelList.get(i -1)).indexOf(sFirstNodeParent);
if ((nIndexOfSecondNodeParent > -1) && ( nIndexOfFirstNodeParent > -1)){
if ((nIndexOfFirstParent >= nIndexOfSecondNodeParent) && (nIndexOfFirstNodeParent > nIndexOfSecondNodeParent)) {
String sFirstNodeID = (String)currentLevelList.elementAt(k);
currentLevelList.remove(k);
currentLevelList.insertElementAt(sFirstNodeID, j);
nIndexOfFirstParent = ((Vector)nodeLevelList.get(i -1)).indexOf(((Vector)htNodesAbove.get(sFirstNodeID)).firstElement());
nodeToSort = (NodeSummary)htNodes.get(sFirstNodeID);
break ;
}//end else if
}//end if
}//end else
}//end if
}//end for
// enter the the node id in the hashtable to avoid redundant comparison
Vector vtMarkCheckedNodesForKLoop = new Vector();
if (htNodesChecked.get(node.getId()) != null){
vtMarkCheckedNodesForKLoop = (Vector) htNodesChecked.get(node.getId());
}// end if
vtMarkCheckedNodesForKLoop.add(nodeToSort.getId());
htNodesChecked.put(node.getId(),vtMarkCheckedNodesForKLoop);
Vector vtMarkCheckedNodesForJLoop = new Vector();
if (htNodesChecked.get(nodeToSort.getId()) != null){
vtMarkCheckedNodesForJLoop = (Vector) htNodesChecked.get(nodeToSort.getId());
}// end if
vtMarkCheckedNodesForJLoop.add(node.getId());
htNodesChecked.put(nodeToSort.getId(),vtMarkCheckedNodesForJLoop);
}//end if
}//end if
}//end for
}//end for
}//end for
}//end for
// end edit - Lakshmi
sortNodesBelow();
sortNodeChildWise();
}//SortNodeParentWise
//begin edit - Lakshmi (10/25/05)
/**
* Helper method. Sort the node calculated by thier child node position.
*
*/
private void sortNodeChildWise(){
for(int i = nodeLevelList.size() -1; i > 0 ; i-- ) {
Vector vtLevelNodes = (Vector) nodeLevelList.get(i);
if (vtLevelNodes == null){
continue ;
}
for(int j = 0; j < vtLevelNodes.size(); j++ ) {
String sNodeId = (String) vtLevelNodes.get(j);
Vector vtNodesAbove = (Vector) htNodesAbove.get(sNodeId);
if ((vtNodesAbove != null ) && (vtNodesAbove.size() > 0)) {
int nSize = vtNodesAbove.size();
switch (nSize) {
case 1:
break;
default :
//currently arranging if the child node is first or last child of a parent
String sFirstParent = (String) vtNodesAbove.firstElement();
Vector vtNodesBelowFP = (Vector) htNodesBelow.get(sFirstParent);
int nIndex = vtNodesBelowFP.indexOf(sNodeId);
int indexOfFP = ((Vector)nodeLevelList.get(i-1)).indexOf(sFirstParent);
if ((nIndex == 0) || (nIndex == (vtNodesBelowFP.size() - 1))){
abovePointerPos = 0;
belowPointerPos = 1;
childSizeBelow = 0;
childSizeAbove = 0;
for(int loop = 1; loop < vtNodesAbove.size(); loop++){
String sParent = (String) vtNodesAbove.get(loop);
int indexOfParent = ((Vector)nodeLevelList.get(i-1)).indexOf(sParent);
if ((indexOfFP > -1) && (indexOfParent > -1)){
Vector vtFPParent = (Vector)htNodesAbove.get(sFirstParent);
Vector vtParent = (Vector)htNodesAbove.get(sParent);
int indexFP = ((Vector)nodeLevelList.get(i-1)).indexOf(sFirstParent);
if(((vtFPParent != null) && (vtParent != null))){
int fpParentSize = vtFPParent.size();
int parentSize = vtParent.size();
if (((fpParentSize == 1) && (parentSize == 1))) {
String fpParentId = (String) vtFPParent.firstElement();
String lpParentId = (String) vtParent.firstElement();
if(fpParentId == lpParentId){
if(indexOfParent > (indexFP + 1)){
swapNodes(sNodeId, sFirstParent, sParent, i, nIndex);
}//end if
}//end if
}//end if
} else if ((vtParent == null)&& (indexOfParent > (indexFP + 1))) {
swapNodes(sNodeId, sFirstParent, sParent, i, nIndex);
}//end if else
}//end if
}//end for
}//end if
break;
}//end switch
}//end if
}//end for
}//end for
sortNodesBelow();
sortNodesAbove();
}//sortNodeChildWise
/**
* Helper Method. To look for a node whose parent is placed above the parent of the current node in the same level and move it up.
* @param sNodeId The ID of the node which is compared to other nodes in the level
* @param sFirstParent The first parent ID of the node
* @param sParent The parent ID of the comparing node
* @param i Level at which the node is
* @param nIndex Index of the node in its parent's child vector
*/
private void swapNodes(String sNodeId, String sFirstParent, String sParent, int i, int nIndex){
Vector vtLevelNodes = (Vector) nodeLevelList.get(i);
Vector vtNodesBelowFP = (Vector) htNodesBelow.get(sFirstParent);
int indexFP = ((Vector)nodeLevelList.get(i-1)).indexOf(sFirstParent);
Vector vtNodesBelow = (Vector) htNodesBelow.get(sParent);
if (vtNodesBelow.size() == 1){
((Vector)nodeLevelList.get(i-1)).remove(sParent);
if(nIndex == 0){
((Vector)nodeLevelList.get(i-1)).insertElementAt(sParent, indexFP - abovePointerPos);
} else{
((Vector)nodeLevelList.get(i-1)).insertElementAt(sParent, indexFP + belowPointerPos);
}//end if else
} else {
int index = vtLevelNodes.indexOf(sNodeId);
boolean isSingleParentNodes = true;
boolean isSet = false;
for(int k = 0; k < vtNodesBelow.size(); k++) {
String nodeId = (String) vtNodesBelow.get(k);
int size = ((Vector)htNodesAbove.get(nodeId)).size();
if ((nodeId != sNodeId )&&(size != 1)){
isSingleParentNodes = false;
break;
}//end if
}//end for
if(isSingleParentNodes){
((Vector)nodeLevelList.get(i-1)).remove(sParent);
if((nIndex == 0) && (!isSet)){
((Vector)nodeLevelList.get(i-1)).insertElementAt(sParent, indexFP - abovePointerPos);
abovePointerPos ++;
for(int k = 0; k < vtNodesBelow.size(); k++) {
if(! sNodeId.equals(vtNodesBelow.get(k))) {
((Vector)nodeLevelList.get(i)).remove(vtNodesBelow.get(k));
((Vector)nodeLevelList.get(i)).insertElementAt(vtNodesBelow.get(k), index - childSizeAbove);
}//end if
}//end for
childSizeAbove += vtNodesBelow.size() - 1;
if(nIndex == (vtNodesBelowFP.size() - 1)) {
isSet = true;
}//end if
} else if((nIndex == (vtNodesBelowFP.size() - 1)) || (isSet == true)){
((Vector)nodeLevelList.get(i-1)).insertElementAt(sParent, indexFP + belowPointerPos);
belowPointerPos ++;
for(int k = vtNodesBelow.size()-1; k >= 0; k--) {
if(! sNodeId.equals(vtNodesBelow.get(k))) {
((Vector)nodeLevelList.get(i)).remove(vtNodesBelow.get(k));
((Vector)nodeLevelList.get(i)).insertElementAt(vtNodesBelow.get(k), (index + 1 + childSizeBelow));
}//end if
}//end for
childSizeBelow += vtNodesBelow.size() - 1 ;
}//end if else
}//end if
}//end if else
}//swapNodes
/**
* This method is to sort parent nodes based on nodes sorted child wise.
*/
private void sortNodesAbove(){
for (int i = nodeLevelList.size() -1; i >= 0 ; i--){
Vector vtLevelNodes = (Vector) nodeLevelList.get(i);
for(int j = 0; j < vtLevelNodes.size(); j++) {
Vector vtNodesAbove = (Vector) htNodesAbove.get((String) vtLevelNodes.get(j));
if(vtNodesAbove != null){
for(int k = vtNodesAbove.size() -1; k >= 0; k --){
for( int l = 0; l <= k - 1; l++){
int index = ((Vector)nodeLevelList.get(i - 1)).indexOf((String) vtNodesAbove.get(l));
int indxBelow = ((Vector)nodeLevelList.get(i - 1)).indexOf((String) vtNodesAbove.get(l + 1));
if((indxBelow != -1 ) && (index != -1 ) && (index > indxBelow)){
String temp = (String) vtNodesAbove.get(l + 1);
vtNodesAbove.remove(l+1);
vtNodesAbove.insertElementAt(temp, l);
}//end if
}//end for
}//end for
htNodesAbove.put((String) vtLevelNodes.get(j),vtNodesAbove);
}//end if
}//end for
}//end for
}//sortNodesAbove
/**
* This method is to sort child nodes below based on nodes sorted parent wise.
*/
private void sortNodesBelow(){
for (int i = 0; i < nodeLevelList.size() ; i++){
Vector vtLevelNodes = (Vector) nodeLevelList.get(i);
for(int j = 0; j < vtLevelNodes.size(); j++) {
Vector vtNodesBelow = (Vector) htNodesBelow.get((String) vtLevelNodes.get(j));
if(vtNodesBelow != null){
for(int k = vtNodesBelow.size() -1; k >= 0; k --){
for( int l = 0; l <= k - 1; l++){
int index = ((Vector)nodeLevelList.get(i + 1)).indexOf((String) vtNodesBelow.get(l));
int indxBelow = ((Vector)nodeLevelList.get(i + 1)).indexOf((String) vtNodesBelow.get(l + 1));
if((indxBelow != -1 ) && (index != -1 ) && (index > indxBelow)){
String temp = (String) vtNodesBelow.get(l + 1);
vtNodesBelow.remove(l+1);
vtNodesBelow.insertElementAt(temp, l);
}//end if
}//end for
}//end for
htNodesBelow.put((String) vtLevelNodes.get(j),vtNodesBelow);
}//end if
}//end for
}//end for
}//end sortNodesBelow
// end edit - Lakshmi
/**
* This method is added to enable the child nodes to be positioned at the center relative to the parent.
* @param viewFrame com.compendium.ui.UIViewFrame, the frame of the nodes to set the y positions for.
*/
private void setYPositionForNodes(UIViewFrame viewFrame) {
int yPosition = 20;
// TO FIX an ArrayIndexOutOfBoundsException
if ( nodeLevelList != null && nodeLevelList.size() > 0 ) {
if (nodeLevelList.elementAt(0) != null && ((Vector)nodeLevelList.elementAt(0)).size() > 0) {
for (int i = 0; i < ((Vector)nodeLevelList.elementAt(0)).size(); i++) {
String nodeId = (String)((Vector)nodeLevelList.elementAt(0)).elementAt(i);
yPosition = calculateYPosition(viewFrame, nodeId, yPosition);
}
}
}
}
private Hashtable nodesYed = new Hashtable(51);
/**
* Helper Method. This method is added to enable the child nodes to be positioned at the center relative to the parent.
* @param viewFrame com.compendium.ui.UIViewFrame, the frame of the node to calculate the y positions for.
* @param nodeId, the id of the node to calculate the y position for.
* @param yPosition, the starting y position.
* @return int, the calculated y position.
*/
private int calculateYPosition(UIViewFrame viewFrame, String nodeId, int yPosition) {
Integer count = new Integer(1);
if(nodesYed.containsKey(nodeId)){
count = (Integer) nodesYed.get(nodeId);
if(count.intValue() > recursionCount)
return yPosition;
else {
count = new Integer(count.intValue() + 1);
nodesYed.put(nodeId, count);
}
} else {
nodesYed.put(nodeId, count);
}
/* if(recursionCount > htNodes.size() || nodesYed.containsKey(nodeId)){
return yPosition;
}
nodesYed.put(nodeId, nodeId);
recursionCount ++;
*/
UIViewPane viewPane = ((UIMapViewFrame)viewFrame).getViewPane();
Vector childNodeList = (Vector) htNodesBelow.get(nodeId);
UINode parentNode = ((UINode)viewPane.get(nodeId));
if (childNodeList != null) {
for (int i = 0; i < childNodeList.size(); i++) {
yPosition = calculateYPosition(viewFrame, (String)childNodeList.elementAt(i), yPosition);
}
int firstChildPosition = ((UINode)viewPane.get((String)childNodeList.firstElement())).getNodePosition().getYPos();
int lastChildPosition = ((UINode)viewPane.get((String)childNodeList.lastElement())).getNodePosition().getYPos();
UINode lastChildNode = (UINode)viewPane.get((String)childNodeList.lastElement()) ;
int newYPosition = firstChildPosition + (lastChildPosition + lastChildNode.getHeight() - firstChildPosition)/2;
newYPosition = newYPosition - parentNode.getHeight()/2;
int nodeLevel = ((Integer)htNodesLevel.get(nodeId)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(nodeId);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeYPosition = 0;
UINode node = ((UINode)viewPane.get(nodeId));
double scale = viewPane.getScale();
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(nodeLevel-1)).elementAt(indexOfPreviousNode)));
previousNodeYPosition = previousNode.getNodePosition().getYPos();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeHeight = previousNode.getHeight();
Point p1 = UIUtilities.scalePoint(nodeHeight, nodeHeight, scale);
nodeHeight = p1.x;
if ((previousNodeYPosition + nodeHeight + FormatProperties.arrangeLeftVerticalGap) > newYPosition) {
newYPosition = previousNodeYPosition + nodeHeight + (FormatProperties.arrangeLeftVerticalGap);
}
}
Point pos = node.getNodePosition().getPos();
node.getNodePosition().setPos(new Point(pos.x, newYPosition));
if (newYPosition > yPosition) {
yPosition = newYPosition;
}
} else {
//begin edit - Lakshmi (10/25/05)
// if a child node has 2 parent , on arrange the node was dropping down. To avoid this, once the node's Y position is set
// it is not set again.
if((htNodeYPositionSet.get(nodeId) == null) || (((Boolean)htNodeYPositionSet.get(nodeId)).booleanValue() == false)) {
UINode node = ((UINode)viewPane.get(nodeId));
//end edit - Lakshmi
// begin edit, Alex Jarocha-Ernst
//previously, this didn't do anything with the previous node of a leaf
//this caused problems when the first node on a level had children, but
//successive ones did not
int nodeLevel = ((Integer)htNodesLevel.get(nodeId)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(nodeId);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeYPosition = 0;
Point pos = node.getNodePosition().getPos();
double scale = viewPane.getScale();
if(indexOfPreviousNode > -1) {
String sPreviousNodeID = (String)((Vector)nodeLevelList.elementAt(nodeLevel-1)).elementAt(indexOfPreviousNode);
UINode previousNode = ((UINode)viewPane.get(sPreviousNodeID));
// BUG FIX - Lakshmi 9/15/06 for NullPointerException
NodeSummary previousNodeSum = (NodeSummary)htNodes.get(sPreviousNodeID);
previousNodeYPosition = previousNode.getNodePosition().getYPos();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeHeight = previousNode.getHeight();
Point p1 = UIUtilities.scalePoint(nodeHeight, nodeHeight, scale);
nodeHeight = p1.x;
//begin edit - Lakshmi (10/25/05)
// This is to put the parent at the center of its children
Vector vtParentNodes = (Vector) htNodesAbove.get(node.getNode().getId());
if(vtParentNodes != null) {
String sFirstParentNodeId = (String) vtParentNodes.firstElement();
int nLevel = ((Integer)htNodesLevel.get(sFirstParentNodeId)).intValue();
int indexOfParent = ((Vector) nodeLevelList.get( nLevel - 1)).indexOf(sFirstParentNodeId);
if ((indexOfParent -1 ) >= 0 ) {
String sParentPreviousNodeId = (String)((Vector)nodeLevelList.get(nLevel - 1)).get(indexOfParent - 1);
UINode parentPreviousNode = ((UINode)viewPane.get(sParentPreviousNodeId));
int parentPreviousNodePos = parentPreviousNode.getNodePosition().getYPos();
int parentPreviousNodeHt = parentPreviousNode.getHeight();
String sPreviousNodeParentId = previousNodeSum.getParentNode().getId();
if (!((Vector)htNodesAbove.get(nodeId)).contains(sPreviousNodeParentId)){
yPosition = parentPreviousNodePos + parentPreviousNodeHt + FormatProperties.arrangeLeftVerticalGap ;
}//end if
}//end if
}//end if
//end edit - Lakshmi
if ((previousNodeYPosition + nodeHeight +FormatProperties.arrangeLeftVerticalGap) > yPosition) {
yPosition = previousNodeYPosition + nodeHeight + (FormatProperties.arrangeLeftVerticalGap);
}
node.getNodePosition().setPos(new Point(pos.x, yPosition));
} else {
//end edit, Alex Jarocha-Ernst
String sNodeId = node.getNode().getId();
int yPos = findPreviousNodeYPos(viewPane, sNodeId);
if(yPosition > yPos) {
node.getNodePosition().setPos(new Point(pos.x, yPosition));
} else {
node.getNodePosition().setPos(new Point(pos.x, yPos));
}
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeHeight = node.getHeight();
Point p1 = UIUtilities.scalePoint(nodeHeight, nodeHeight, scale);
nodeHeight = p1.x;
yPosition += (FormatProperties.arrangeLeftVerticalGap + nodeHeight);
}
}
}//end else
htNodeYPositionSet.put(nodeId, new Boolean(true));
return yPosition;
}//end calculateYPosition
private Hashtable nodesYFinalized = new Hashtable();
/**
* This method is to enable the child nodes to be positioned at the center relative to the parent after compact.
* @param viewFrame com.compendium.ui.UIViewFrame, the frame of the node to finalize the y positions for.
* @param sNodeID, the id of the node to finalize the y position for.
*/
private void finalizeYPos(UIViewFrame viewFrame, String sNodeID){
Integer count = new Integer(1);
if(nodesYFinalized.containsKey(sNodeID)){
count = (Integer) nodesYFinalized.get(sNodeID);
if(count.intValue() > recursionCount)
return ;
else {
count = new Integer(count.intValue() + 1);
nodesYFinalized.put(sNodeID, count);
}
} else {
nodesYFinalized.put(sNodeID, count);
}
/* if(recursionCount < htNodes.size() || !nodesYFinalized.containsKey(sNodeID)) {
nodesYFinalized.put(sNodeID, sNodeID);
recursionCount ++;
} else {
return;
}
*/
UIViewPane viewPane = ((UIMapViewFrame)viewFrame).getViewPane();
Vector vtChildNodes = (Vector)htNodesBelow.get(sNodeID);
UINode oNode = ((UINode)viewPane.get(sNodeID));
Point pos = oNode.getNodePosition().getPos();
double scale = viewPane.getScale();
if(vtChildNodes != null){
for (int i =0; i< vtChildNodes.size(); i++){
finalizeYPos(viewFrame, (String)vtChildNodes.get(i));
}//end for
Vector vtChildren = (Vector)htNodesBelow.get(sNodeID);
int nodePosition = oNode.getNodePosition().getYPos();
UINode oFirstChild = (UINode)viewPane.get((String)vtChildren.firstElement());
UINode oLastChild = (UINode)viewPane.get((String)vtChildren.lastElement());
String sFirstParentOfFC = (String)((Vector) htNodesAbove.get(vtChildren.firstElement())).firstElement();
String sFirstParentOfLC = (String)((Vector) htNodesAbove.get(vtChildren.lastElement())).firstElement();
if (sFirstParentOfFC.equals(sNodeID) && sFirstParentOfLC.equals(sNodeID)){
int firstChildPosition = oFirstChild.getNodePosition().getYPos();
int lastChildPosition = oLastChild.getNodePosition().getYPos();
int centerPosition = firstChildPosition + (lastChildPosition + oLastChild.getHeight() - firstChildPosition)/2;
centerPosition = centerPosition - oNode.getHeight()/2;
int nodeLevel = ((Integer)htNodesLevel.get(sNodeID)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(sNodeID);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeYPosition = 0;
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(nodeLevel-1)).elementAt(indexOfPreviousNode)));
previousNodeYPosition = previousNode.getNodePosition().getYPos();
int nodeHeight = previousNode.getHeight();
Point p2 = UIUtilities.scalePoint(nodeHeight, nodeHeight, scale);
nodeHeight = p2.x;
if ((previousNodeYPosition + nodeHeight + FormatProperties.arrangeLeftVerticalGap) > nodePosition) {
nodePosition = previousNodeYPosition + nodeHeight + (FormatProperties.arrangeLeftVerticalGap);
oNode.getNodePosition().setPos(new Point (pos.x , nodePosition));
}//end if
}//end if
if(nodePosition <= centerPosition){
oNode.getNodePosition().setPos(new Point (pos.x , centerPosition));
} else {
int amount = nodePosition - centerPosition ;
//recursionCount = 0;
getChildNodesDown(viewPane, sNodeID, amount);
}//end else
}//end if
}//end if
int nodePosition = oNode.getNodePosition().getYPos();
int nodeLevel = ((Integer)htNodesLevel.get(sNodeID)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(sNodeID);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeYPosition = 0;
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(nodeLevel-1)).elementAt(indexOfPreviousNode)));
previousNodeYPosition = previousNode.getNodePosition().getYPos();
int nodeHeight = previousNode.getHeight();
Point p1 = UIUtilities.scalePoint(nodeHeight, nodeHeight, scale);
nodeHeight = p1.x;
if ((previousNodeYPosition + nodeHeight) > nodePosition) {
nodePosition = previousNodeYPosition + nodeHeight + (FormatProperties.arrangeLeftVerticalGap);
oNode.getNodePosition().setPos(new Point(pos.x , nodePosition));
}//end if
}//end if
}//finalizeYPos
/**
* Helper Method. This method helps to put parent at the center of the children.
* @param viewPane com.compendium.ui.UIViewPane, the frame of the node to finalize the y positions for.
* @param sNodeID, the id of the node whose y position has to be increased.
* @param amount, the amount to increase in Y position
*/
private void getChildNodesDown (UIViewPane viewPane, String sNodeID, int amount){
/* if(recursionCount > (htNodes.size() + 5 )){
return ;
}
recursionCount ++;
*/
UINode oNode = ((UINode)viewPane.get(sNodeID));
Point pos = oNode.getNodePosition().getPos();
Vector vtChildNodes = (Vector) htNodesBelow.get(sNodeID);
if (vtChildNodes != null){
for(int i = 0; i < vtChildNodes.size(); i++){
getChildNodesDown(viewPane, (String)vtChildNodes.get(i), amount);
}//end for
Vector vtChildren = (Vector)htNodesBelow.get(sNodeID);
int nodePosition = oNode.getNodePosition().getYPos();
UINode lastNode = (UINode)viewPane.get((String)vtChildren.lastElement());
int firstChildPosition = ((UINode)viewPane.get((String)vtChildren.firstElement())).getNodePosition().getYPos();
int lastChildPosition = lastNode.getNodePosition().getYPos();
int centerPosition = firstChildPosition + (lastChildPosition + lastNode.getHeight() - firstChildPosition)/2;
centerPosition = centerPosition - oNode.getHeight()/2;
int nodeLevel = ((Integer)htNodesLevel.get(sNodeID)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(sNodeID);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeYPosition = 0;
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(nodeLevel-1)).elementAt(indexOfPreviousNode)));
previousNodeYPosition = previousNode.getNodePosition().getYPos();
int nodeHeight = previousNode.getHeight();
Point p2 = UIUtilities.scalePoint(nodeHeight, nodeHeight, viewPane.getScale());
nodeHeight = p2.x;
if ((previousNodeYPosition + nodeHeight + FormatProperties.arrangeLeftVerticalGap) > nodePosition) {
nodePosition = previousNodeYPosition + nodeHeight + (FormatProperties.arrangeLeftVerticalGap);
oNode.getNodePosition().setPos(new Point (pos.x , nodePosition));
}//end if
}//end if
if(nodePosition <= centerPosition){
oNode.getNodePosition().setPos(new Point (pos.x , centerPosition));
}//end if */
} else {//end if
int yPos = oNode.getNodePosition().getYPos();
yPos += amount;
oNode.getNodePosition().setPos(new Point(pos.x, yPos));
}//end else
}//end getChildNodesDown
/**
* Helper Method. To find y position for a node so that it is placed around its parent.
* @param viewPane com.compendium.ui.UIViewPane, the frame of the node.
* @param sNodeID, the id of the node whose previous node y position has to be found.
*
* @return int, The y position of the previous node.
*/
private int findPreviousNodeYPos (UIViewPane viewPane, String nodeID){
int yPos = 0;
Vector vtParents = (Vector)htNodesAbove.get(nodeID);
if(vtParents != null){
String sParentId = (String) vtParents.firstElement();
int index = ((Vector)nodeLevelList.get(((Integer)htNodesLevel.get(sParentId)).intValue() -1)).indexOf(sParentId);
if (index > 0){
String sPreviousNodeID = (String)((Vector)nodeLevelList.get(((Integer)htNodesLevel.get(sParentId)).intValue() -1)).get(index - 1);
UINode previousNode = (UINode) viewPane.get(sPreviousNodeID);
NodePosition nodePosition = previousNode.getNodePosition();
yPos = nodePosition.getYPos() + previousNode.getHeight() + FormatProperties.arrangeLeftVerticalGap;
} else {
yPos = findPreviousNodeYPos(viewPane, sParentId);
}//end else
}//end if
return yPos;
}//findPreviousNodeYpos
//end edit -Lakshmi
private Hashtable nodesCompacted = new Hashtable(51);
private Hashtable nodesCheckedForCompact = new Hashtable(51);
private Hashtable nodesCompact = new Hashtable(51);
/**
* Helper Method. This method compacts the nodes in the given list.
* @param viewFrame com.compendium.ui.UIViewFrame, the frame of the node to compact.
* @param nodeList, the list of node to compact.
*/
private void compactNodesInList(UIViewFrame viewFrame, Vector nodeList) {
UIViewPane viewPane = ((UIMapViewFrame)viewFrame).getViewPane();
Hashtable compactDoneForNodes = new Hashtable();
Vector vtLevelChecked = new Vector();
for (int i = 0; i < nodeList.size(); i++) {
String nodeID = (String)nodeList.elementAt(i);
Integer count = new Integer(1);
if(nodesCompacted.containsKey(nodeID)){
count = (Integer) nodesCompacted.get(nodeID);
if(count.intValue() > recursionCount)
continue ;
else {
count = new Integer(count.intValue() + 1);
nodesCompacted.put(nodeID, count);
}
} else {
nodesCompacted.put(nodeID, count);
}
/* if (recursionCount < htNodes.size() || !nodesCompacted.containsKey(nodeID)) {
nodesCompacted.put(nodeID, nodeID);
recursionCount ++;
} else {
continue;
}
*/
Vector childNodeList = (Vector)htNodesBelow.get(nodeID);
if (childNodeList != null) {
compactNodesInList(viewFrame, childNodeList);
}
}
int currentNodeYPosition = 0;
int previousNodeYPosition = 0;
int compactAmount = 0;
//begin edit - Lakshmi (10/25/05)
// This is to center the 1st node (if its a parent)at any level .
if ((nodeList != null) &&(nodeList.size() >= 1)) {
UINode node = ((UINode)viewPane.get((String)nodeList.elementAt(0)));
Vector childNodeList = (Vector) htNodesBelow.get(nodeList.get(0));
if(childNodeList != null){
UINode firstNode = (UINode)viewPane.get((String)childNodeList.firstElement());
int firstNodeYPosition = firstNode.getNodePosition().getYPos();
UINode lastNode = (UINode)viewPane.get((String)childNodeList.lastElement());
int lastNodeYPosition = lastNode.getNodePosition().getYPos();
Point pos = node.getNodePosition().getPos();
int centerPosition = firstNodeYPosition + (lastNodeYPosition + lastNode.getHeight() - firstNodeYPosition)/2;
centerPosition = centerPosition - node.getHeight()/2;
int level = ((Integer)htNodesLevel.get(node.getNode().getId())).intValue() - 1;
int index = ((Vector)nodeLevelList.get(level)).indexOf(node.getNode().getId());
if(index < 1){
node.getNodePosition().setPos(new Point(pos.x, centerPosition));
} else {
UINode previousNode = (UINode)viewPane.get((String)((Vector)nodeLevelList.get(level)).get(index - 1));
int previousNodeYPos = previousNode.getNodePosition().getYPos();
int previousNodeHeight = previousNode.getHeight();
if(centerPosition > previousNodeYPos + previousNodeHeight + FormatProperties.arrangeLeftVerticalGap ){
node.getNodePosition().setPos(new Point(pos.x, centerPosition));
} else {
node.getNodePosition().setPos(new Point(pos.x, previousNodeYPos + previousNodeHeight + FormatProperties.arrangeLeftVerticalGap));
}
}//end if
}//end if
}//end if
//end edit - Lakshmi
double scale = viewPane.getScale();
// this will arrange other nodes based on the above arrangement of 1st node.
for (int i = 1; i < nodeList.size(); i++) {
UINode currentNode = ((UINode)viewPane.get((String)nodeList.elementAt(i)));
UINode previousNode = ((UINode)viewPane.get((String)nodeList.elementAt(i-1)));
currentNodeYPosition = currentNode.getNodePosition().getYPos();
previousNodeYPosition = previousNode.getNodePosition().getYPos();
UINode node = ((UINode)viewPane.get((String)nodeList.elementAt(i)));
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeHeight = previousNode.getHeight();
Point p1 = UIUtilities.scalePoint(nodeHeight, nodeHeight, scale);
nodeHeight = p1.x;
if ((currentNodeYPosition - previousNodeYPosition - nodeHeight) > FormatProperties.arrangeLeftVerticalGap) {
compactDoneForNodes.clear();
compactAmount = checkCompact(viewFrame,
(String)nodeList.elementAt(i),
currentNodeYPosition - previousNodeYPosition - FormatProperties.arrangeLeftVerticalGap - nodeHeight,
compactDoneForNodes, vtLevelChecked);
if (compactAmount > 0) {
compact(viewFrame, (String)nodeList.elementAt(i), compactAmount, compactDoneForNodes);
}
}
Vector childNodeList = (Vector)htNodesBelow.get((String)nodeList.elementAt(i));
if (childNodeList != null) {
UINode firstNode = (UINode)viewPane.get((String)childNodeList.firstElement());
int firstNodeYPosition = firstNode.getNodePosition().getYPos();
UINode lastNode = (UINode)viewPane.get((String)childNodeList.lastElement());
int lastNodeYPosition = lastNode.getNodePosition().getYPos();
previousNodeYPosition = 0;
int previousNodeHeight = 0;
int level = ((Integer)htNodesLevel.get((String)nodeList.elementAt(i))).intValue();
int indexOfCurrentNode = ((Vector)nodeLevelList.elementAt(level-1)).indexOf((String)nodeList.elementAt(i));
int indexOfPreviousNode = indexOfCurrentNode - 1;
Point pos = node.getNodePosition().getPos();
if (indexOfPreviousNode > -1) {
previousNodeYPosition = previousNode.getNodePosition().getYPos();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
previousNodeHeight = previousNode.getHeight();
Point p2 = UIUtilities.scalePoint(previousNodeHeight, previousNodeHeight, scale);
previousNodeHeight = p2.x;
int centerPosition = firstNodeYPosition + (lastNodeYPosition + lastNode.getHeight() - firstNodeYPosition)/2;
centerPosition = centerPosition - node.getHeight()/2;
if ((previousNodeYPosition + previousNodeHeight + FormatProperties.arrangeLeftVerticalGap) < centerPosition) {
node.getNodePosition().setPos(new Point(pos.x, centerPosition));
}
else {
node.getNodePosition().setPos(new Point(pos.x, previousNodeYPosition + previousNodeHeight + FormatProperties.arrangeLeftVerticalGap));
}//end else
}//end if
}//end if
}//end for
}//compactNodesInList
/**
* Helper Method. This method checks the compactness of the node with the given id.
* @param viewFrame com.compendium.ui.UIViewFrame, the frame of the node to compact.
* @param nodeId, the id of the node to check.
* @param compactAmount, the amount to compact by.
* @param compactDoneForNodes, nodes already compacted.
*/
private int checkCompact(UIViewFrame viewFrame, String nodeId, int compactAmount, Hashtable compactDoneForNodes, Vector vtLevelChecked) {
UIViewPane viewPane = ((UIMapViewFrame)viewFrame).getViewPane();
compactDoneForNodes.put(nodeId, new Boolean(false));
Integer count = new Integer(1);
if(nodesCheckedForCompact.containsKey(nodeId)){
count = (Integer) nodesCheckedForCompact.get(nodeId);
if(count.intValue() > recursionCount)
return compactAmount;
else {
count = new Integer(count.intValue() + 1);
nodesCheckedForCompact.put(nodeId, count);
}
} else {
nodesCheckedForCompact.put(nodeId, count);
}
//get the level of this node
UINode currentNode = ((UINode)viewPane.get(nodeId));
int currentNodeYPosition = currentNode.getNodePosition().getYPos();
int level = ((Integer)htNodesLevel.get(nodeId)).intValue();
int indexOfCurrentNode = ((Vector)nodeLevelList.elementAt(level-1)).indexOf(nodeId);
int indexOfPreviousNode = indexOfCurrentNode - 1;
if (indexOfPreviousNode < 0) {
if (currentNodeYPosition < compactAmount) {
compactAmount = currentNodeYPosition - 20;
}
indexOfPreviousNode = 0;
}
else {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(level-1)).elementAt(indexOfPreviousNode)));
int previousNodeYPosition = previousNode.getNodePosition().getYPos();
double scale = viewPane.getScale();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeHeight = currentNode.getHeight();
Point p = UIUtilities.scalePoint(nodeHeight, nodeHeight, scale);
nodeHeight = p.x;
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int previousNodeHeight = previousNode.getHeight();
Point p2 = UIUtilities.scalePoint(previousNodeHeight, previousNodeHeight, scale);
previousNodeHeight = p2.x;
if (!vtLevelChecked.contains(htNodesLevel.get(nodeId))) {
if ( (currentNodeYPosition - previousNodeYPosition - FormatProperties.arrangeLeftVerticalGap - previousNodeHeight) <
compactAmount) {
compactAmount = currentNodeYPosition - previousNodeYPosition - FormatProperties.arrangeLeftVerticalGap - previousNodeHeight;
}//end if
}//end if
}//end else
Vector childNodeList = (Vector)htNodesBelow.get(nodeId);
if (childNodeList != null) {
compactAmount = checkCompact(viewFrame, (String)childNodeList.elementAt(0),compactAmount, compactDoneForNodes, vtLevelChecked);
}
if (compactAmount < 0) {
compactAmount = 0;
}
return compactAmount;
}
/**
* Helper Method. This method compacts the node with the given id.
* @param viewFrame com.compendium.ui.UIViewFrame, the frame of the node to compact.
* @param nodeId, the id of the node to compact.
* @param compactAmount, the amount to compact by.
* @param compactDoneForNodes, nodes already compacted.
*/
private void compact(UIViewFrame viewFrame, String nodeId, int compactAmount, Hashtable compactDoneForNodes) {
UIViewPane viewPane = ((UIMapViewFrame)viewFrame).getViewPane();
Boolean isCompactDone = (Boolean)compactDoneForNodes.get(nodeId);
if (isCompactDone != null) {
if (isCompactDone.booleanValue() == true) {
return;
}
}
Integer count = new Integer(1);
if(nodesCompact.containsKey(nodeId)){
count = (Integer) nodesCompact.get(nodeId);
if(count.intValue() > recursionCount) {
return ;
}
else {
count = new Integer(count.intValue() + 1);
nodesCompact.put(nodeId, count);
}
} else {
nodesCompact.put(nodeId, count);
}
UINode node = ((UINode)viewPane.get(nodeId));
Point pos = node.getNodePosition().getPos();
int level = ((Integer)htNodesLevel.get(nodeId)).intValue();
int indexOfCurrentNode = ((Vector)nodeLevelList.elementAt(level-1)).indexOf(nodeId);
int indexOfPreviousNode = indexOfCurrentNode - 1;
int yPosition = 0;
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(level-1)).elementAt(indexOfPreviousNode)));
int previousNodeYPosition = previousNode.getNodePosition().getYPos();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int previousNodeHeight = previousNode.getHeight();
Point p = UIUtilities.scalePoint(previousNodeHeight, previousNodeHeight, viewPane.getScale());
previousNodeHeight = p.x;
if ((pos.y - compactAmount) < (previousNodeYPosition + previousNodeHeight + FormatProperties.arrangeLeftVerticalGap)) {
yPosition = previousNodeYPosition + previousNodeHeight + FormatProperties.arrangeLeftVerticalGap;
}
else {
yPosition = pos.y - compactAmount;
}
}
else {
yPosition = pos.y - compactAmount;
}
if (yPosition < 0)
yPosition = 0;
node.getNodePosition().setPos(new Point(pos.x, yPosition));
compactDoneForNodes.put(nodeId, new Boolean(true));
Vector nodeList = (Vector)htNodesBelow.get(nodeId);
if (nodeList != null) {
for (int i = 0; i < nodeList.size(); i++) {
// begin edit - Lakshmi (10/25/05)
String sParentID = (String)((Vector) htNodesAbove.get(nodeList.elementAt(i))).firstElement();
if (nodeId.equals(sParentID)) {
compact(viewFrame, (String) nodeList.elementAt(i), compactAmount, compactDoneForNodes);
}// end if
//end edit - Lakshmi
}//end for
}//end if
}//compact
//******** UNDO / REDO **************//
/**
* Undo the last arrange for the given frame
* @param viewFrame com.compendium.ui.UIViewFrame, the frame to undo the arrange for.
*/
public void undoArrange(UIViewFrame viewFrame) {
UIViewPane pane = ((UIMapViewFrame)viewFrame).getViewPane();
for(Enumeration e = nodePositionsCloneHashtable.keys();
e.hasMoreElements();) {
String nodeID = (String)e.nextElement();
UINode uinode = (UINode)pane.get(nodeID);
NodePosition np = (NodePosition)nodePositionsCloneHashtable.get(nodeID);
Point loc = UIUtilities.transformPoint(np.getXPos(), np.getYPos(), pane.getScale());
uinode.setBounds(loc.x, loc.y,
uinode.getWidth(),
uinode.getHeight());
uinode.updateLinks();
try {
viewFrame.getView().setNodePosition(nodeID, np.getPos());
}
catch(Exception ex) {
log.info("Error: (UIArrange.undoArrange) \n\n"+ex.getMessage()); //$NON-NLS-1$
}
}
pane.repaint();
}
/**
* Redo the last arrange for the given frame
* @param viewFrame com.compendium.ui.UIViewFrame, the frame to undo the arrange for.
*/
public void redoArrange(UIViewFrame viewFrame) {
UIViewPane pane = ((UIMapViewFrame)viewFrame).getViewPane();
for(Enumeration e = nodePositionsCloneHashtableForRedo.keys();
e.hasMoreElements();) {
String nodeID = (String)e.nextElement();
UINode uinode = (UINode)pane.get(nodeID);
NodePosition np = (NodePosition)nodePositionsCloneHashtableForRedo.get(nodeID);
Point loc = UIUtilities.transformPoint(np.getXPos(), np.getYPos(), pane.getScale());
uinode.setBounds(loc.x, loc.y,
uinode.getWidth(),
uinode.getHeight());
uinode.updateLinks();
try {
viewFrame.getView().setNodePosition(nodeID, np.getPos());
}
catch(Exception ex) {
log.info("Error: (UIArrange.redoArrange) \n\n"+ex.getMessage()); //$NON-NLS-1$
}
}
pane.repaint();
}
/**
* Return the list of node levels.
* @return Vector, the node level list.
*/
public Vector getNodeLevelList() {
return nodeLevelList;
}
/**
* Return the list of nodes below.
* @return Hashtable, the nodes below list.
*/
public Hashtable getNodesBelow() {
return htNodesBelow;
}
/**
* Return the list of nodes.
* @return Hashtable, the nodes.
*/
public Hashtable getNodes() {
return htNodes;
}
/**
* Return the list of nodes mapped to levels.
* @return Hashtable, the list of nodes mapped to levels.
*/
public Hashtable getNodesLevel() {
return htNodesLevel;
}
}