/*
Copyright (c) 2003 eInnovation Inc. All rights reserved
This library is free software; you can redistribute it and/or modify it under the terms
of the GNU Lesser General Public License as published by the Free Software Foundation;
either version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
*/
/*
* Created on May 29, 2003
*/
package com.openedit.webui.tree;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.openedit.util.PathUtilities;
/**
* This is the base implemation of a JavaScript renderer for output to the web.
*
* @author Matt Avery
*/
public abstract class BaseTreeRenderer implements TreeRenderer
{
protected WebTree fieldWebTree;
protected String fieldHome;
protected String fieldImageDir = "/openedit/images/tree";
protected Set fieldExpandedNodes;
protected Object fieldSelectedNode;
protected Object fieldLastCutoffNode;
protected String fieldUrlPrefix = "";
protected String fieldUrlPostfix = "";
protected boolean fieldFoldersLinked;
protected boolean fieldRenderLeaves = true;
protected boolean fieldAllowSelections = false;
protected Set fieldSelectedNodes;
protected boolean fieldEditable;
public boolean isEditable()
{
return fieldEditable;
}
public void setEditable(boolean inEditable)
{
fieldEditable = inEditable;
}
public BaseTreeRenderer()
{
}
public boolean isAllowSelections()
{
return fieldAllowSelections;
}
public void setAllowSelections(boolean inAllowSelections)
{
fieldAllowSelections = inAllowSelections;
}
public Set getSelectedNodes()
{
if (fieldSelectedNodes == null)
{
fieldSelectedNodes = new HashSet();
}
return fieldSelectedNodes;
}
public boolean isIdSelected(String inNodeId)
{
return getSelectedNodes().contains(inNodeId);
}
public boolean isNodeSelected(Object inNode)
{
if( inNode == getSelectedNode() )
{
return true;
}
String inId = getId(inNode);
return getSelectedNodes().contains(inId);
}
protected String getId(Object inNode)
{
return getWebTree().getModel().getId(inNode);
}
public void setSelectedNodes(Set inSelectedNodes)
{
fieldSelectedNodes = inSelectedNodes;
}
public void selectNode(Object inNode)
{
if( inNode != null )
{
getSelectedNodes().add(getId(inNode));
Object parent = getWebTree().getModel().getParent(inNode);
if( parent != null )
{
expandNode(parent);
}
}
}
public void unSelectNode(Object inNode)
{
getSelectedNodes().remove(getId(inNode));
}
public void selectNodes(Collection inNodes)
{
Set newselection = new HashSet();
for (Iterator iterator = inNodes.iterator(); iterator.hasNext();)
{
Object object = (Object) iterator.next();
newselection.add(getId(object));
Object parent = getWebTree().getModel().getParent(object);
if( parent != null )
{
expandNode(parent);
}
}
setSelectedNodes(newselection);
}
public boolean isRenderLeaves()
{
return fieldRenderLeaves;
}
public void setRenderLeaves(boolean inRenderLeaves)
{
fieldRenderLeaves = inRenderLeaves;
}
public BaseTreeRenderer(WebTree inWebTree)
{
fieldWebTree = inWebTree;
}
public String getHome()
{
if ( fieldHome == null )
{
fieldHome = "";
}
return fieldHome;
}
public void setHome(String inHome)
{
fieldHome = inHome;
}
public String getExpandNodeCommand()
{
return "WebTree.expandTreeNode";
}
public String getImageDir()
{
return fieldImageDir;
}
public void setImageDir(String inImageDir)
{
fieldImageDir = inImageDir;
}
public void setWebTree(WebTree tree)
{
fieldWebTree = tree;
}
public WebTree getWebTree()
{
return fieldWebTree;
}
protected Set getExpandedNodes()
{
if (fieldExpandedNodes == null)
{
fieldExpandedNodes = new HashSet();
}
return fieldExpandedNodes;
}
@Override
public void toggleNode(Object inNode)
{
if( hasBeenExpanded(inNode) )
{
collapseNode(inNode);
}
else
{
expandNode(inNode);
}
}
public void expandNode(Object inNode)
{
String path = toUrl(inNode);
if ( !getExpandedNodes().contains(path))
{
getExpandedNodes().add(path);
//get all the parents somehow
Object parent = getWebTree().getModel().getParent( inNode);
if ( parent != null)
{
expandNode(parent);
}
}
}
/* (non-javadoc)
* @see com.openedit.webui.tree.TreeRenderer#collapseNode(java.lang.Object)
*/
public void collapseNode(Object inNode)
{
String path = toUrl(inNode);
getExpandedNodes().remove(path);
}
public boolean hasBeenExpanded(Object inNode)
{
//Make sure it is expanded
Object parent = inNode;
while( parent != null)
{
String path = toUrl(inNode);
if( getExpandedNodes().contains(path) )
{
parent = getWebTree().getModel().getParent(parent);
//If we get to the root and it is selected still then we are ok!
if( parent == null)
{
return true;
}
}
else
{
return false;
}
}
return false;
}
protected String quotes(String inString)
{
inString = inString.replace("\"", "\\\"");
return "\"" + inString + "\"";
}
public String renderAsString()
{
StringBuffer js = new StringBuffer( "var tree = new Tree( \n" );
// Ensure the root node is always expanded.
expandNode( getWebTree().getModel().getRoot() );
js.append( renderNewFolder( getWebTree().getModel().getRoot()));
js.append( ", " );
js.append( quotes(getWebTree().getId()) );
js.append( ", \"" );
js.append( getHome() );
js.append( getImageDir() + "/\" );\n");
if ( getUrlPrefix() != null)
{
js.append( "tree.setViewerUrl( '" + getHome() + getUrlPrefix() + "' );\n" );
}
if ( getUrlPostfix() != null)
{
js.append( "tree.setViewerUrlEnding( '" + getUrlPostfix() + "' );\n" );
}
js.append( "tree.showFolderData= " + isFoldersLinked() + ";\n");
if ( getSelectedNode() != null)
{
js.append("tree.setSelectedNodeById(" );
js.append(quotes(getWebTree().getModel().getId( getSelectedNode() ) ));
js.append(");\n");
}
return js.toString();
}
public String renderAsString(String inNodeId)
{
return null;
}
public Object setSelectedNodeByUrl(String inPath)
{
if ( inPath == null)
{
return null;
}
if ( inPath.endsWith("/") && inPath.length() > 1 )
{
inPath = inPath.substring(0, inPath.length() - 1);
}
Object node = null;
String root = toUrl( getWebTree().getModel().getRoot() );
if ( PathUtilities.match(root, inPath ) )
{
node = getWebTree().getModel().getRoot();
}
else
{
node = findNodeByUrl(getWebTree().getModel().getRoot(), inPath);
}
setSelectedNode(node);
if ( node != null)
{
//expand the parent
Object parent = getWebTree().getModel().getParent(node);
if ( parent != null)
{
expandNode(parent);
}
}
return node;
}
public Object findNodeByUrl(Object inRoot, String inUrl)
{
if(inUrl == null){
return null;
}
int count = getWebTree().getModel().getChildCount(inRoot);
for (int i = 0; i < count; i++)
{
Object child = getWebTree().getModel().getChild(inRoot,i);
String test = toUrl( child );
if ( PathUtilities.match(test,inUrl ) )
{
return child;
}
//this test must be a directory
if( !inUrl.startsWith(test))
{
continue;
}
child = findNodeByUrl(child,inUrl);
if ( child != null)
{
return child;
}
}
return null;
}
public void setSelectedNodeById(String inId)
{
if ( inId == null)
{
return;
}
Object node = getWebTree().getModel().getChildById(inId);
setSelectedNode(node);
if ( node != null)
{
//expand the parent
node = getWebTree().getModel().getParent(node);
if ( node != null)
{
expandNode(node);
}
}
}
protected String renderNewFolder(Object inNode)
{
StringBuffer js = new StringBuffer(
"new Node( " + quotes( toName( inNode ) ) + ", " + quotes( toUrl( inNode ) ) + ", ");
js.append(quotes(getWebTree().getModel().getId(inNode)));
if ( getWebTree().getModel().isLeaf( inNode ) )
{
js.append(",null");
}
else
{
js.append(renderChildren(inNode));
}
js.append( "," + getWebTree().getModel().isLeaf( inNode ) );
String iconsset = customIconSet(inNode);
if( iconsset != null )
{
js.append(',');
js.append("\"" + iconsset + "\")");
}
else
{
js.append(")");
}
return js.toString();
}
/**
* Allows a certain node to have a custom icon set. Icon sets can be defined in the tree.js
* @param inNode
* @return
*/
protected String customIconSet(Object inNode)
{
return null;
}
protected String renderChildren(Object inNode)
{
// Use null for our folder icon, and the JavaScript tree will substitute either folder.gif or
// folderopen.gif, depending on whether the node is open or closed.
StringBuffer js = new StringBuffer();
if ( hasBeenExpanded( inNode ) )
{
// String collapseUrl = quotes("?" + "WebTreeName=" + getWebTree().getName() + "&oe-action=" +
// getCollapseNodeCommand() + "&nodeID=" + getWebTree().getModel().getId(inNode));
// js.append(collapseUrl +", new Array(\n");
js.append(", new Array(\n");
int c = getWebTree().getModel().getChildCount( inNode );
for (int i = 0; i < c; i++ )
{
if ( i > 0 )
{
js.append(",\n");
}
Object childNode = getWebTree().getModel().getChild( inNode, i );
js.append(renderNewFolder(childNode));
}
js.append(" ) ");
}
else
{
// String expandUrl = quotes("?" + "WebTreeName=" + getWebTree().getName() + "&oe-action=" +
// getExpandNodeCommand() + "&nodeID=" + getWebTree().getModel().getId(inNode));
// Might need to make this configurable later on.
// Different controllers may want to use different commands here.
js.append(",null " );
// js.append(
// quotes("?" + "WebTreeName=" + getWebTree().getName() + "&oe-action=" +
// getExpandNodeCommand() + "&nodeID=" + getWebTree().getModel().getId(inNode)) + ", null, ");
}
return js.toString();
}
/**
* The name is used on the tree display
* @param inNode
* @return
*/
public abstract String toName(Object inNode);
/**
* The url will be triggered when a node is clicked
* @param inNode
* @return
*/
public abstract String toUrl(Object inNode);
public String getCollapseNodeCommand()
{
return "WebTree.collapseTreeNode";
}
public String getUrlPrefix()
{
return fieldUrlPrefix;
}
public void setUrlPrefix(String inUrlPrefix)
{
fieldUrlPrefix = inUrlPrefix;
}
public boolean isFoldersLinked()
{
return fieldFoldersLinked;
}
public void setFoldersLinked(boolean inFoldersLinked)
{
fieldFoldersLinked = inFoldersLinked;
}
public Object getSelectedNode()
{
return fieldSelectedNode;
}
public String getSelectedId()
{
Object selected = getSelectedNode();
if( selected == null)
{
return null;
}
return getWebTree().getModel().getId(selected);
}
public void setSelectedNode(Object inSelectedNode)
{
fieldSelectedNode = inSelectedNode;
Object parent = getWebTree().getModel().getParent(inSelectedNode);
if( parent != null )
{
expandNode(parent);
}
}
public String getUrlPostfix()
{
return fieldUrlPostfix;
}
public void setUrlPostfix(String inUrlPostfix)
{
fieldUrlPostfix = inUrlPostfix;
}
public Object getLastCutoffNode()
{
return fieldLastCutoffNode;
}
public void setLastCutoffNode(Object inLastCutoffNode)
{
fieldLastCutoffNode = inLastCutoffNode;
}
public boolean isShowPathInfo(Object inNode)
{
//inNode == /a/b/c.html
//Cutoff == /a
//First make sure it is not expanded
Object container = inNode;
if( getWebTree().getModel().isLeaf(container) )
{
container = getWebTree().getModel().getParent(container);
}
if( hasBeenExpanded(container))
{
return false;
}
//See if we are below the cut off. If we are below or equal then show the node (return true)
if( fieldLastCutoffNode != null)
{
Object parent = inNode;
while( parent != null)
{
if( parent == fieldLastCutoffNode)
{
return true;
}
parent = getWebTree().getModel().getParent(parent);
}
return false;
}
return true; //Show it since it is not expanded
}
}