/**
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations under
* the License.
*
* The Original Code is OpenELIS code.
*
* Copyright (C) The Minnesota Department of Health. All Rights Reserved.
*/
package us.mn.state.health.lims.common.valueholder.tree;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* The class which stores the state of the tree in the user session. The state of the tree can include
* expanded nodes, highlighted node, paginated node etc.
*
* @author jalpesh
*
*/
public class TreeStateManager
implements java.io.Serializable
{
/** The object which stores all the expanded nodes */
private Hashtable expandedNodes = new Hashtable();
/**
* Hashtable to keep track of the paginated nodes by the user. It will store
* keys in form of <nodePath> and the value will be the PageNodeData class.
*/
private Hashtable paginatedNodes = new Hashtable();
/**
* Hashtable which can store user data for the tree.
*/
private Hashtable userData = new Hashtable();
private static final String prefix = "TreeState";
private String name; // name of the tree
private String expandNodesFromPath; // indicates that all nodes below this node are to be expanded
private String highlightedNodePath; // indicate the path to the highlighted node
private String highlightedNodeData; // the data field associated with the highlighted node
private String highlightedNodeName; // the name of the highlighted node
private TreePopup highlightedNodePopup; // the popup item associated with the selected node
/**
* PaginatedNodeData
*
* Contains data related to the paginated node
*
*/
public class PaginatedNodeData
implements Serializable
{
protected String nodePath;
protected String pageBegin = null;
protected int pageSize = -1;
protected int pageAction = -1;
protected String firstChildName;
protected String firstChildData;
protected String firstChildPath;
protected String lastChildName;
protected String lastChildData;
protected String lastChildPath;
public static final int MOVE_FORWARD = 1;
public static final int MOVE_BACK = 2;
/**
* Private method used by the TreeStateManager
* @param request
*/
protected PaginatedNodeData(HttpServletRequest request)
{
if(request == null)
return;
nodePath = request.getParameter(name + "_pageRequestNodePath");
pageBegin = request.getParameter(name + "_pageBegin");
if(!isEmpty(request, name + "_pageAction"))
pageAction = Integer.parseInt(request.getParameter(name + "_pageAction"));
if(!isEmpty(request, name + "_pageSize"))
pageSize = Integer.parseInt(request.getParameter(name + "_pageSize"));
firstChildName = request.getParameter(name + "_firstChildName");
firstChildPath = request.getParameter(name + "_firstChildPath");
firstChildData = request.getParameter(name + "_firstChildData");
lastChildName = request.getParameter(name + "_lastChildName");
lastChildPath = request.getParameter(name + "_lastChildPath");
lastChildData = request.getParameter(name + "_lastChildData");
}
/**
* Return the page range begin for this paginated tree node
* @return
*/
public int getPageRangeBegin()
{
if(pageBegin == null)
return -1;
else
return Integer.parseInt(pageBegin);
}
/**
* Returns the action performed by the user on the paginated node.
*
* @return An integer which could be MOVE_FORWARD, if the user had hit the next button,
* or MOVE_BACKWARD if the user had hit the previous button. If no action has been performed
* it will return -1
*/
public int getPageAction()
{
return pageAction;
}
/**
* Return the data field of the first child in the current window of the paginated node.
*
* @return Returns the firstChildData field.
*/
public String getFirstChildData()
{
return firstChildData;
}
/**
* Return the name of the first child in the current window of the paginated node.
*
* @return Returns the firstChildName.
*/
public String getFirstChildName()
{
return firstChildName;
}
/**
* Return the node path of the first child in the current window of the paginated node.
*
* @return Returns the firstChildPath.
*/
public String getFirstChildPath()
{
return firstChildPath;
}
/**
* Return the data field of the last child in the current window of the paginated node.
*
* @return Returns the lastChildData.
*/
public String getLastChildData()
{
return lastChildData;
}
/**
* Return the name of the last child in the current window of the paginated node.
*
* @return Returns the lastChildName.
*/
public String getLastChildName()
{
return lastChildName;
}
/**
* Return the node path of the last child in the current window of the paginated node.
*
* @return Returns the lastChildPath.
*/
public String getLastChildPath()
{
return lastChildPath;
}
/**
* @return Returns the pageSize of the paginated node.
*/
public int getPageSize()
{
return pageSize;
}
/**
* Sample toString implementation for debugging.
*/
public String toString()
{
return "Paginated Node is :" + nodePath + "\n" +
" PageAction :" + pageAction + "\n" +
" PageBegin :" + pageBegin + "\n" +
" firstChildName :" + firstChildName + "\n" +
" firstChildData :" + firstChildData + "\n" +
" firstChildPath :" + firstChildPath + "\n" +
" lastChildName :" + lastChildName + "\n" +
" lastChildData :" + lastChildData + "\n" +
" lastChildPath :" + lastChildPath + "\n";
}
}
protected TreeStateManager(String name)
{
this.name = name; // name of the tree
}
/**
* Return an instance of the TreeStateManager for the tree with the given name. If the object does not exist
* in the session, it creates a new one and saves it in the user session.
* @param session The session object
* @param name The name of the tree
* @return TreeStateManager instance.
*/
public static TreeStateManager getInstance(HttpSession session, String name)
{
TreeStateManager tsm = (TreeStateManager)session.getAttribute(prefix+name);
if(tsm == null)
{
tsm = new TreeStateManager(name);
session.setAttribute(prefix+name, tsm);
}
return tsm;
}
/**
* @return Returns the selected popup item of the tree node.
*/
public TreePopup getHighlightedNodePopup()
{
return highlightedNodePopup;
}
/**
* @return Returns the highlightedNodeName.
*/
public String getHighlightedNodeName()
{
return highlightedNodeName;
}
/**
* @param highlightedNodeName The highlightedNodeName to set.
*/
public void setHighlightedNodeName(String highlightedNodeName)
{
this.highlightedNodeName = highlightedNodeName;
}
/**
* @return Returns the highlightedNodeData.
*/
public String getHighlightedNodeData()
{
return highlightedNodeData;
}
/**
* @param highlightedNodeData The highlightedNodeData to set.
*/
public void setHighlightedNodeData(String highlightedNodeData)
{
this.highlightedNodeData = highlightedNodeData;
}
/**
* @return Returns the highlightedNodePath.
*/
public String getHighlightedNodePath()
{
return highlightedNodePath;
}
/**
* @param highlightedNodePath The highlightedNodePath to set.
*/
public void setHighlightedNodePath(String highlightedNodePath)
{
this.highlightedNodePath = highlightedNodePath;
}
/**
* Remove the highlighted node information from the manager
*
*/
public void removeHighlightedNodeData()
{
this.highlightedNodeData = null;
this.highlightedNodePath = null;
this.highlightedNodeData = null;
this.highlightedNodePopup = null;
}
/**
* Process the state of the tree after a user has performed either of the following actions in the tree -
* expanded a node, collapsed a node, zoomed in or out, paged through a window or selected a node.
* @param request The request object which would contain this information
*/
public void processState(HttpServletRequest request)
{
// check to ensure that expand all nodes (below a nodePath) is not called. If it is not invoked,
// the value will be null.
setExpandNodesFromPath(request.getParameter(name+"expandNodesFromPath"));
// if expand action was called on a node path, execute that
addNodeAsExpanded(request.getParameter(name+"expandNode"));
// if collapse action was called on a node, remove that node as expanded
removeNodeAsExpanded(request.getParameter(name+"collapseNode"));
// if a node was selected, mark it has highlighted, and also store the data field
// we only do this if there is a request to highlight a certain node. So the net effect
// is that a highlighted node is always sticky, it remains highlighted until somebody specifically
// unhighlights it, or over-writes it with a different highlighted node
if(!isEmpty(request, name+"highlightNodePath"))
{
setHighlightedNodePath(request.getParameter(name+"highlightNodePath"));
setHighlightedNodeData(request.getParameter(name+"highlightNodeData"));
setHighlightedNodeName(request.getParameter(name+"highlightNodeName"));
}
// set the popup item if they exists...
setPopupItems(request);
// if node is paginated, figure retrieve the associated data
retrievePaginationData(request);
}
/**
* Retrieve the popup items from the request.
* @param request
*/
private void setPopupItems(HttpServletRequest request)
{
if(!isEmpty(request, name + "popupName"))
{
highlightedNodePopup = new TreePopup(name + "popupName");
int i=0;
while(!isEmpty(request, name + "popup" + i + ".text"))
{
String text = request.getParameter(name + "popup" + i + ".text");
String action = request.getParameter(name + "popup" + i + ".action");
String imageSrc = request.getParameter(name + "popup" + i + ".imageSrc");
highlightedNodePopup.addPopupItem(text, action, imageSrc);
i++;
}
} else
{
highlightedNodePopup = null;
}
}
/** Retrieve pagination information from the request */
private void retrievePaginationData(HttpServletRequest request)
{
if(!isEmpty(request, name + "_pageRequestNodePath"))
{
PaginatedNodeData png = new PaginatedNodeData(request);
// store this object in the hashtable.
paginatedNodes.put(request.getParameter(name + "_pageRequestNodePath"), png);
}
}
/**
* Return whether or not the given node path is paginated or not.
* @param nodePath The path of the node
* @return true or false depending whether the node is paginated or not.
*/
public boolean isNodePathPaginated(String nodePath)
{
return paginatedNodes.get(nodePath) != null;
}
/**
* Force a particular node path to be paginated, if it is not already paginated.
* @param nodePath
* @return
*/
public void addNodePathAsPaginated(String nodePath)
{
if(!isNodePathPaginated(nodePath))
paginatedNodes.put(nodePath, new PaginatedNodeData(null));
}
/**
* Remove the given node as being paginated.
* @param node The tree node object
*/
public void removeNodePathAsPaginated(String nodePath)
{
if(isNodePathPaginated(nodePath))
paginatedNodes.remove(nodePath);
}
/**
* Return the data associated with the paginated node
* @param node The path of the tree node
* @return The paginated node data for the given tree node
*/
public PaginatedNodeData getPaginatedNodeData(String nodePath)
{
PaginatedNodeData pageNodeData = (PaginatedNodeData)paginatedNodes.get(nodePath);
return pageNodeData;
}
/**
* Marks all nodes below the given path to be expanded.
* @param nodePath The path to the tree node.
*/
public void setExpandNodesFromPath(String nodePath)
{
this.expandNodesFromPath = nodePath;
}
public String getExpandNodesFromPath()
{
return expandNodesFromPath;
}
/**
* Add a particular node, identified by its path as expanded in the tree.
* @param nodePath
*/
public void addNodeAsExpanded(String nodePath)
{
if(nodePath == null || nodePath.length() == 0)
return;
expandedNodes.put(nodePath, "true");
}
/**
* Indicate whether or not the given node, identified by its path is expanded or not
* @param nodePath The node path
* @return
*/
public boolean isNodeExpanded(String nodePath)
{
if(expandedNodes.get(nodePath) != null)
{
return true;
}
else if(getExpandNodesFromPath() != null && nodePath.startsWith(getExpandNodesFromPath()) )
{
addNodeAsExpanded(nodePath);
return true;
}
else
{
return false;
}
}
/**
* Return the Enumeration of the expanded nodes
* @return Enumeration of the expanded nodes containing key values.
*/
public Enumeration getExpandedNodes()
{
return expandedNodes.keys();
}
/**
* Reset the tree state manager to its default state - removing any expanded nodes, highlighted nodes,
* paginated nodes or user data.
*
*/
public void reset()
{
expandedNodes = new Hashtable();
paginatedNodes = new Hashtable();
userData = new Hashtable();
expandNodesFromPath = null;
highlightedNodePath = null;
highlightedNodeData = null; // the data field associated with the highlighted node
highlightedNodeName = null; // the name of the highlighted node
highlightedNodePopup = null; // the popup item associated with the selected node
}
/**
* Removes the node from the expanded node list in the tree (ie marks it as collapsed).
* @param nodePath
*/
public void removeNodeAsExpanded(String nodePath)
{
if(nodePath == null || nodePath.length() == 0)
return;
expandedNodes.remove(nodePath);
}
// helper method to make sure that the parameter in the request is not empty
private boolean isEmpty(HttpServletRequest request, String param)
{
return (request.getParameter(param) == null || request.getParameter(param).length() == 0);
}
/**
* Allow a user to store a custom object in the TreeStateManager. Please note that the key and the value
* objects should both be serializable.
* @param key The key to lookup the value ob
* @param value
*/
public void put(Object key, Object value)
{
userData.put(key, value);
}
/**
* Allow a user to remove a custom object in the TreeStateManager.
* @param key The key to remove
*/
public Object remove(Object key)
{
return userData.remove(key);
}
/**
* Retrieve data which was stored using the put method.
* @param key
* @return
*/
public Object get(Object key)
{
return userData.get(key);
}
}