/********************************************************************************
* *
* (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 UIArrangeTopDown 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 X position set or not.*/
private Hashtable htNodeXPositionSet = 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 UIArrangeTopDown() {}
/**
* 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, "UIArrange.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[] verticalSep = 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));
if (uinode == null) {
continue;
}
int level = ((Integer)htNodesLevel.get(nodeId)).intValue();
if (level > maxLevel) {
maxLevel = level;
}
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int height = uinode.getHeight();
if (uiViewPane != null) {
Point p = UIUtilities.scalePoint(height, height, uiViewPane.getScale());
height = p.y;
}
if (level > 0) {
int sepLevel = verticalSep[level-1];
if(height > sepLevel)
verticalSep[level-1] = height + FormatProperties.arrangeTopVerticalGap;
}
}
// First sort nodes parent wise and then set Y position for the node.. This might some what minimize cross over links
sortNodesParentwise();
setXPositionForNodes(viewFrame);
if (nodeLevelList.size() > 0) {
compactNodesInList(viewFrame, (Vector)nodeLevelList.elementAt(0));
}
// 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++){
finalizeXPos(viewFrame,(String)((Vector)nodeLevelList.get(0)).get(i));
}
}
//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 newY = 0;
if (view.equals(ProjectCompendium.APP.getHomeView())) {
newY = 40;
}
int j = 0;
for (j = 0; j < level; j++) {
newY += verticalSep[j];
}
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int height = uinode.getHeight();
if (uiViewPane != null) {
Point p = UIUtilities.scalePoint(height, height, uiViewPane.getScale());
height = p.x;
}
newY -= ((verticalSep[j-1]/2) + (height/2));
int newX = uinode.getNodePosition().getXPos();
//uinode.getNodePosition().setPos(newX, newY);
Point ptNew = new Point(newX, newY);
//uinode.setPosition(ptNew);
if (uiViewPane != null) {
Point loc = UIUtilities.transformPoint(newX, newY, uiViewPane.getScale());
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: (UIArrangeTopDown.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, "UIArrangeTopDown.noNodes") + 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, "UIArrangeTopDown.errorTopDown")); //$NON-NLS-1$
}
}
/**
* 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: (UIArrangeTopDown.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 xPositionForLevel1 = ( (NodePosition)nodePositionsCloneHashtable.get(levelOneNode.getId())).getXPos();
int secondXPositionForLevel1 = 0;
int indexForLevel1 = 0;
while (nodeLevelList.size() == 0) {
nodeLevelList.addElement(new Vector());
}
Vector nodeListAtLevel1 = (Vector)nodeLevelList.elementAt(0);
secondXPositionForLevel1 = 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()) && (xPositionForLevel1 > secondXPositionForLevel1)) {
secondXPositionForLevel1 = ( (NodePosition)nodePositionsCloneHashtable.get(nodeListAtLevel1.elementAt(indexForLevel1))).getXPos();
indexForLevel1++;
}
//-- insert at the correct position - sorted by y position
if (indexForLevel1 == nodeListAtLevel1.size()) {
if (xPositionForLevel1 > secondXPositionForLevel1)
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());
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 xPosition = ( (NodePosition)nodePositionsCloneHashtable.get(node.getId())).getXPos();
int secondXPosition = 0;
int index = 0;
boolean found = false;
while ((index < oldVector.size()) && (xPosition > secondXPosition)) {
secondXPosition = ( (NodePosition)nodePositionsCloneHashtable.get(oldVector.elementAt(index))).getXPos();
if (node.getId().equals((String)oldVector.elementAt(index))) {
found = true;
break;
}
index++;
}
if (index == oldVector.size()) {
if (xPosition > secondXPosition) {
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 previousParentXPosition = np.getXPos();
int currentParentXPosition = ( (NodePosition)nodePositionsCloneHashtable.get(levelOneNode.getId())).getXPos();
if(nodeAboveId != levelOneNode.getId()) {
if (currentParentXPosition < previousParentXPosition) {
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);
secondXPosition = 0;
index = 0;
while ((index < nodeListAtLevel.size()) && (xPosition > secondXPosition)) {
secondXPosition = ( (NodePosition)nodePositionsCloneHashtable.get(nodeListAtLevel.elementAt(index))).getXPos();
index++;
}
if (index == nodeListAtLevel.size()) {
if (xPosition > secondXPosition) {
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;
}//end startLevelCalculation
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 xPosition = ( (NodePosition)nodePositionsCloneHashtable.get(sFromNodeID)).getXPos();
int secondXPosition = 0;
int index = 0;
boolean found = false;
while ((index < oldVector.size()) && (xPosition > secondXPosition)) {
//NodeSummary tempNode = (NodeSummary)htNodes.get(oldVector.elementAt(index));
secondXPosition = ( (NodePosition)nodePositionsCloneHashtable.get(oldVector.elementAt(index))).getXPos();
if (nodeFrom.getId().equals((String)oldVector.elementAt(index))) {
found = true;
break;
}
index++;
}
if (index == oldVector.size()) {
if (xPosition > secondXPosition) {
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) {
// 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 currentParentXPosition = ((NodePosition)nodePositionsCloneHashtable.get(sToNodeID)).getXPos();
boolean isInserted = false;
for(int j=0; j<vtParentNodes.size();j++){
String nodeAboveId = (String)vtParentNodes.get(j);
NodePosition np = ( (NodePosition)nodePositionsCloneHashtable.get(nodeAboveId));
int previousParentXPosition = np.getXPos();
if(nodeAboveId != sToNodeID) {
if (currentParentXPosition < previousParentXPosition) {
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()));
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);
secondXPosition = 0;
index = 0;
while ((index < nodeListAtLevel.size()) && (xPosition > secondXPosition)) {
secondXPosition = ( (NodePosition)nodePositionsCloneHashtable.get(nodeListAtLevel.elementAt(index))).getXPos();
index++;
}
if (index == nodeListAtLevel.size() ) {
if (xPosition > secondXPosition) {
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;
}//end else
}//end for
return true;
}//end startRecursiveCalculations
/**
* 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);
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
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);
}
}
}
} else if ((vtParent == null)&& (indexOfParent > (indexFP + 1))) {
swapNodes(sNodeId, sFirstParent, sParent, i, nIndex);
}
}
}
}
break;
}
}
}
}
sortNodesBelow();
sortNodesAbove();
}
/**
* 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);
}
} 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;
}
}
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);
}
}
childSizeAbove += vtNodesBelow.size() - 1;
if(nIndex == (vtNodesBelowFP.size() - 1)) {
isSet = true;
}
} 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));
}
}
childSizeBelow += vtNodesBelow.size() - 1 ;
}
}
}
}
/**
* 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);
}
}
}
htNodesAbove.put((String) vtLevelNodes.get(j),vtNodesAbove);
}
}
}
}
/**
* 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);
}
}
}
htNodesBelow.put((String) vtLevelNodes.get(j),vtNodesBelow);
}
}
}
}
// 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 setXPositionForNodes(UIViewFrame viewFrame) {
int xPosition = 70;
// 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++) {
xPosition = calculateXPosition(viewFrame, (String)((Vector)nodeLevelList.elementAt(0)).elementAt(i), xPosition);
}
}
}
}
private Hashtable nodesXed = 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 calculateXPosition(UIViewFrame viewFrame, String nodeId, int xPosition) {
Integer count = new Integer(1);
if(nodesXed.containsKey(nodeId)){
count = (Integer) nodesXed.get(nodeId);
if(count.intValue() > recursionCount)
return xPosition;
else {
count = new Integer(count.intValue() + 1);
nodesXed.put(nodeId, count);
}
} else {
nodesXed.put(nodeId, count);
}
UIViewPane viewPane = ((UIMapViewFrame)viewFrame).getViewPane();
Vector childNodeList = (Vector) htNodesBelow.get(nodeId);
UINode parentNode = ((UINode)viewPane.get(nodeId));
double scale = viewPane.getScale();
if (childNodeList != null) {
for (int i = 0; i < childNodeList.size(); i++) {
xPosition = calculateXPosition(viewFrame, (String)childNodeList.elementAt(i), xPosition);
}
UINode lastChildNode = (UINode)viewPane.get((String)childNodeList.lastElement());
int firstChildPosition = ((UINode)viewPane.get((String)childNodeList.firstElement())).getNodePosition().getXPos();
int lastChildPosition = lastChildNode.getNodePosition().getXPos();
int newXPosition = firstChildPosition + (lastChildPosition + lastChildNode.getWidth() - firstChildPosition)/2;
newXPosition = newXPosition - parentNode.getWidth()/2;
int nodeLevel = ((Integer)htNodesLevel.get(nodeId)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(nodeId);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeXPosition = 0;
UINode node = ((UINode)viewPane.get(nodeId));
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(nodeLevel-1)).elementAt(indexOfPreviousNode)));
previousNodeXPosition = previousNode.getNodePosition().getXPos();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeWidth = previousNode.getWidth();
Point p1 = UIUtilities.scalePoint(nodeWidth, nodeWidth, scale);
nodeWidth = p1.y;
if ((previousNodeXPosition + nodeWidth + FormatProperties.arrangeTopHorizontalGap) > newXPosition) {
newXPosition = previousNodeXPosition + nodeWidth + (FormatProperties.arrangeTopHorizontalGap);
}
}
Point pos = node.getNodePosition().getPos();
node.getNodePosition().setPos(new Point( newXPosition, pos.y));
if (newXPosition > xPosition) {
xPosition = newXPosition;
}
} else {
// 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((htNodeXPositionSet.get(nodeId) == null) || (((Boolean)htNodeXPositionSet.get(nodeId)).booleanValue() == false)) {
UINode node = ((UINode)viewPane.get(nodeId));
int nodeLevel = ((Integer)htNodesLevel.get(nodeId)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(nodeId);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeXPosition = 0;
Point pos = node.getNodePosition().getPos();
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);
previousNodeXPosition = previousNode.getNodePosition().getXPos();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeWidth = previousNode.getWidth();
Point p1 = UIUtilities.scalePoint(nodeWidth, nodeWidth, scale);
nodeWidth = p1.y;
// 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().getXPos();
int parentPreviousNodeWth = parentPreviousNode.getWidth();
String sPreviousNodeParentId = previousNodeSum.getParentNode().getId();
if (!((Vector)htNodesAbove.get(nodeId)).contains(sPreviousNodeParentId)){
xPosition = parentPreviousNodePos + parentPreviousNodeWth + FormatProperties.arrangeTopHorizontalGap ;
}
}
}
if ((previousNodeXPosition + nodeWidth) > xPosition) {
xPosition = previousNodeXPosition + nodeWidth + (FormatProperties.arrangeTopHorizontalGap );
}
node.getNodePosition().setPos(new Point( xPosition, pos.y));
} else {
String sNodeId = node.getNode().getId();
int xPos = findPreviousNodeXPos(viewPane, sNodeId);
if(xPosition > xPos) {
node.getNodePosition().setPos(new Point(xPosition , pos.y));
} else {
node.getNodePosition().setPos(new Point(xPos, pos.y));
}
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeWidth = node.getWidth();
Point p1 = UIUtilities.scalePoint(nodeWidth, nodeWidth, scale);
nodeWidth = p1.y;
xPosition += (FormatProperties.arrangeTopHorizontalGap + nodeWidth);
}
}
}
htNodeXPositionSet.put(nodeId, new Boolean(true));
return xPosition;
}
private Hashtable nodesXFinalized = 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 finalizeXPos(UIViewFrame viewFrame, String sNodeID){
Integer count = new Integer(1);
if(nodesXFinalized.containsKey(sNodeID)){
count = (Integer) nodesXFinalized.get(sNodeID);
if(count.intValue() > recursionCount)
return;
else {
count = new Integer(count.intValue() + 1);
nodesXFinalized.put(sNodeID, count);
}
} else {
nodesXFinalized.put(sNodeID, count);
}
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++){
finalizeXPos(viewFrame, (String)vtChildNodes.get(i));
}
Vector vtChildren = (Vector)htNodesBelow.get(sNodeID);
int nodePosition = oNode.getNodePosition().getXPos();
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().getXPos();
int lastChildPosition = oLastChild.getNodePosition().getXPos();
int centerPosition = firstChildPosition + (lastChildPosition + oLastChild.getWidth() - firstChildPosition)/2;
centerPosition = centerPosition - oNode.getWidth()/2;
int nodeLevel = ((Integer)htNodesLevel.get(sNodeID)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(sNodeID);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeXPosition = 0;
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(nodeLevel-1)).elementAt(indexOfPreviousNode)));
previousNodeXPosition = previousNode.getNodePosition().getXPos();
int nodeWidth = previousNode.getWidth();
Point p2 = UIUtilities.scalePoint(nodeWidth, nodeWidth, scale);
nodeWidth = p2.y;
if ((previousNodeXPosition + nodeWidth + FormatProperties.arrangeTopHorizontalGap ) > nodePosition) {
nodePosition = previousNodeXPosition + nodeWidth + FormatProperties.arrangeTopHorizontalGap ;
oNode.getNodePosition().setPos(new Point (nodePosition , pos.y));
}
}
if(nodePosition <= centerPosition){
oNode.getNodePosition().setPos(new Point (centerPosition , pos.y));
} else {
int amount = nodePosition - centerPosition ;
getChildNodesDown(viewPane, sNodeID, amount);
}
}
}
int nodePosition = oNode.getNodePosition().getXPos();
int nodeLevel = ((Integer)htNodesLevel.get(sNodeID)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(sNodeID);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeXPosition = 0;
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(nodeLevel-1)).elementAt(indexOfPreviousNode)));
previousNodeXPosition = previousNode.getNodePosition().getXPos();
int nodeWidth = previousNode.getWidth();
Point p2 = UIUtilities.scalePoint(nodeWidth, nodeWidth, scale);
nodeWidth = p2.y;
if ((previousNodeXPosition + nodeWidth + FormatProperties.arrangeTopHorizontalGap) > nodePosition) {
nodePosition = previousNodeXPosition + nodeWidth + FormatProperties.arrangeTopHorizontalGap ;
oNode.getNodePosition().setPos(new Point (nodePosition , pos.y));
}
}
}
/**
* 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){
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);
}
Vector vtChildren = (Vector)htNodesBelow.get(sNodeID);
int nodePosition = oNode.getNodePosition().getXPos();
UINode lastNode = (UINode)viewPane.get((String)vtChildren.lastElement());
int firstChildPosition = ((UINode)viewPane.get((String)vtChildren.firstElement())).getNodePosition().getXPos();
int lastChildPosition = lastNode.getNodePosition().getXPos();
int centerPosition = firstChildPosition + (lastChildPosition + lastNode.getWidth() - firstChildPosition)/2;
centerPosition = centerPosition - oNode.getWidth()/2;
int nodeLevel = ((Integer)htNodesLevel.get(sNodeID)).intValue();
int indexOfNode = ((Vector)nodeLevelList.elementAt(nodeLevel - 1)).indexOf(sNodeID);
int indexOfPreviousNode = indexOfNode - 1;
int previousNodeXPosition = 0;
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(nodeLevel-1)).elementAt(indexOfPreviousNode)));
previousNodeXPosition = previousNode.getNodePosition().getXPos();
int nodeWidth = previousNode.getWidth();
Point p2 = UIUtilities.scalePoint(nodeWidth, nodeWidth, viewPane.getScale());
nodeWidth = p2.y;
if ((previousNodeXPosition + nodeWidth + FormatProperties.arrangeTopHorizontalGap) > nodePosition) {
nodePosition = previousNodeXPosition + nodeWidth + FormatProperties.arrangeTopHorizontalGap ;
oNode.getNodePosition().setPos(new Point (nodePosition , pos.y));
}
}
if(nodePosition <= centerPosition){
oNode.getNodePosition().setPos(new Point (centerPosition , pos.y));
}
} else {
int xPos = oNode.getNodePosition().getXPos();
xPos += amount;
oNode.getNodePosition().setPos(new Point(xPos , pos.y));
}
}
/**
* 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 findPreviousNodeXPos (UIViewPane viewPane, String nodeID){
int xPos = 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();
xPos = nodePosition.getXPos() + previousNode.getWidth() + FormatProperties.arrangeTopHorizontalGap ;
} else {
xPos = findPreviousNodeXPos(viewPane, sParentId);
}
}
return xPos;
}
//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);
}
Vector childNodeList = (Vector)htNodesBelow.get(nodeID);
if (childNodeList != null) {
compactNodesInList(viewFrame, childNodeList);
}
}
int currentNodeXPosition = 0;
int previousNodeXPosition = 0;
int compactAmount = 0;
double scale = viewPane.getScale();
// 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 firstNodeXPosition = firstNode.getNodePosition().getXPos();
UINode lastNode = (UINode)viewPane.get((String)childNodeList.lastElement());
int lastNodeXPosition = lastNode.getNodePosition().getXPos();
Point pos = node.getNodePosition().getPos();
int centerPosition = firstNodeXPosition + (lastNodeXPosition + lastNode.getWidth() - firstNodeXPosition)/2;
centerPosition = centerPosition - node.getWidth()/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(centerPosition , pos.y));
} else {
UINode previousNode = (UINode)viewPane.get((String)((Vector)nodeLevelList.get(level)).get(index - 1));
int previousNodeXPos = previousNode.getNodePosition().getXPos();
int previousNodeWidth = previousNode.getWidth();
if(centerPosition > previousNodeXPos + previousNodeWidth + FormatProperties.arrangeTopHorizontalGap ){
node.getNodePosition().setPos(new Point(centerPosition , pos.y));
} else {
node.getNodePosition().setPos(new Point( previousNodeXPos + previousNodeWidth + FormatProperties.arrangeTopHorizontalGap, pos.y ));
}
}
}
}
// 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)));
currentNodeXPosition = currentNode.getNodePosition().getXPos();
previousNodeXPosition = previousNode.getNodePosition().getXPos();
UINode node = ((UINode)viewPane.get((String)nodeList.elementAt(i)));
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeWidth = previousNode.getWidth();
Point p1 = UIUtilities.scalePoint(nodeWidth, nodeWidth, scale);
nodeWidth = p1.y;
if ((currentNodeXPosition - previousNodeXPosition - nodeWidth) > FormatProperties.arrangeTopHorizontalGap) {
compactDoneForNodes.clear();
compactAmount = checkCompact(viewFrame,
(String)nodeList.elementAt(i),
currentNodeXPosition - previousNodeXPosition - FormatProperties.arrangeTopHorizontalGap - nodeWidth,
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 firstNodeXPosition = firstNode.getNodePosition().getXPos();
UINode lastNode = (UINode)viewPane.get((String)childNodeList.lastElement());
int lastNodeXPosition = lastNode.getNodePosition().getXPos();
previousNodeXPosition = 0;
int previousNodeWidth = 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) {
previousNodeXPosition = previousNode.getNodePosition().getXPos();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
previousNodeWidth = previousNode.getWidth();
Point p2 = UIUtilities.scalePoint(previousNodeWidth, previousNodeWidth, scale);
previousNodeWidth = p2.y;
int centerPosition = firstNodeXPosition + (lastNodeXPosition + lastNode.getWidth() - firstNodeXPosition)/2;
centerPosition = centerPosition - node.getWidth()/2;
if ((previousNodeXPosition + previousNodeWidth + FormatProperties.arrangeTopHorizontalGap ) < centerPosition) {
node.getNodePosition().setPos(new Point( centerPosition , pos.y));
}
else {
node.getNodePosition().setPos(new Point(previousNodeXPosition + previousNodeWidth + FormatProperties.arrangeTopHorizontalGap , pos.y));
}
}
}
}
}
/**
* 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();
double scale = viewPane.getScale();
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 currentNodeXPosition = currentNode.getNodePosition().getXPos();
int level = ((Integer)htNodesLevel.get(nodeId)).intValue();
int indexOfCurrentNode = ((Vector)nodeLevelList.elementAt(level-1)).indexOf(nodeId);
int indexOfPreviousNode = indexOfCurrentNode - 1;
if (indexOfPreviousNode < 0) {
if (currentNodeXPosition < compactAmount) {
compactAmount = currentNodeXPosition - 70;
}
indexOfPreviousNode = 0;
}
else {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(level-1)).elementAt(indexOfPreviousNode)));
int previousNodeXPosition = previousNode.getNodePosition().getXPos();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int nodeWidth = currentNode.getWidth();
Point p = UIUtilities.scalePoint(nodeWidth, nodeWidth, scale);
nodeWidth = p.y;
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int previousNodeWidth = previousNode.getWidth();
Point p2 = UIUtilities.scalePoint(previousNodeWidth, previousNodeWidth, scale);
previousNodeWidth = p2.y;
if (!vtLevelChecked.contains(htNodesLevel.get(nodeId))) {
if ( (currentNodeXPosition - previousNodeXPosition - FormatProperties.arrangeTopHorizontalGap - previousNodeWidth) <
compactAmount) {
compactAmount = currentNodeXPosition - previousNodeXPosition - FormatProperties.arrangeTopHorizontalGap - previousNodeWidth;
}
}
}
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 xPosition = 0;
if (indexOfPreviousNode > -1) {
UINode previousNode = ((UINode)viewPane.get((String)((Vector)nodeLevelList.elementAt(level-1)).elementAt(indexOfPreviousNode)));
int previousNodeXPosition = previousNode.getNodePosition().getXPos();
// ALLOW FOR FACT VIEW MIGHT BE SCALED
int previousNodeWidth = previousNode.getWidth();
Point p = UIUtilities.scalePoint(previousNodeWidth, previousNodeWidth, viewPane.getScale());
previousNodeWidth = p.y;
if ((pos.x - compactAmount) < (previousNodeXPosition + previousNodeWidth + FormatProperties.arrangeTopHorizontalGap )) {
xPosition = previousNodeXPosition + previousNodeWidth + FormatProperties.arrangeTopHorizontalGap ;
}
else {
xPosition = pos.x - compactAmount;
}
}
else {
xPosition = pos.x - compactAmount;
}
if (xPosition < 0)
xPosition = 0;
node.getNodePosition().setPos(new Point(xPosition, pos.y));
compactDoneForNodes.put(nodeId, new Boolean(true));
Vector nodeList = (Vector)htNodesBelow.get(nodeId);
if (nodeList != null) {
for (int i = 0; i < nodeList.size(); i++) {
String sParentID = (String)((Vector) htNodesAbove.get(nodeList.elementAt(i))).firstElement();
if (nodeId.equals(sParentID)) {
compact(viewFrame, (String) nodeList.elementAt(i), compactAmount, compactDoneForNodes);
}
}
}
}
// ******** 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: (UIArrangeTopDown.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: (UIArrangeTopDown.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;
}
}