/*
* Copyright (C) 2006 Methodhead Software LLC. All rights reserved.
*
* This file is part of TransferCM.
*
* TransferCM is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* TransferCM 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* TransferCM; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
* Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.methodhead.tree;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.tree.TreeNode;
/**
* <p>
* A <tt>TreeRenderer</tt> for trees whose state is maintained on the server.
* The renderer only renders those nodes that are visible, and a request must
* be made to open or close a node. A mechanism must exist on the server
* side to handle those requests. While more elaborate to implement, this
* approach makes it possible maintain a tree's state across requests.
* </p>
*/
public class ServerTreeRenderer
extends TreeRenderer {
// constructors /////////////////////////////////////////////////////////////
// constants ////////////////////////////////////////////////////////////////
// classes //////////////////////////////////////////////////////////////////
// methods //////////////////////////////////////////////////////////////////
/**
*
*/
public String renderTree(
FoldingTreeNode root )
throws
TreeException {
if ( openUrl_ == null )
throw new TreeException( "openUrl has not been set." );
if ( closeUrl_ == null )
throw new TreeException( "closeUrl has not been set." );
//
// set defaults
//
if ( getClosedHandleImage() == null )
closedHandleImageHtml_ = "+";
else
closedHandleImageHtml_ =
"<img border=\"0\" src=\"" + getClosedHandleImage() + "\">";
if ( getOpenedHandleImage() == null )
openedHandleImageHtml_ = "-";
else
openedHandleImageHtml_ =
"<img border=\"0\" src=\"" + getOpenedHandleImage() + "\">";
//
// get visible nodes
//
List nodes = new ArrayList();
getVisibleNodes( nodes, root );
//
// get maximum visible level
//
int maxVisibleLevel = getMaxLevel( nodes );
//
// render the tree
//
StringBuffer buf = new StringBuffer();
renderHeader( buf );
for ( Iterator iter = nodes.iterator(); iter.hasNext(); ) {
FoldingTreeNode node = ( FoldingTreeNode )iter.next();
renderNode( buf, maxVisibleLevel, node );
}
renderFooter( buf );
//
// return the html
//
return buf.toString();
}
/**
* Transforms the tree into a list of nodes that should be displayed.
*/
protected void getVisibleNodes(
List rows,
FoldingTreeNode node ) {
if ( !node.isRoot() || !isRootHidden() )
rows.add( node );
if ( !node.isLeaf() && node.getOpened() )
for ( int i = 0; i < node.getChildCount(); i++ )
getVisibleNodes( rows, ( FoldingTreeNode )node.getChildAt( i ) );
}
/**
* Returns the level of the deepest level node in <tt>nodes</tt>.
*/
protected int getMaxLevel(
List nodes ) {
int level = 0;
for ( Iterator iter = nodes.iterator(); iter.hasNext(); ) {
FoldingTreeNode node = ( FoldingTreeNode )iter.next();
int tmp = node.getLevel();
if ( tmp > level )
level = tmp;
}
return level;
}
/**
* Renders the header of the tree: a <tt>table</tt> tag.
*/
protected void renderHeader(
StringBuffer buf )
throws
TreeException {
buf.append( "<table>\n" );
}
/**
* Renders the footer of the tree.
*/
protected void renderFooter(
StringBuffer buf )
throws
TreeException {
buf.append( "</table>\n" );
}
/**
* Renders a node.
*/
protected void renderNode(
StringBuffer buf,
int maxVisibleLevel,
FoldingTreeNode node ) {
//
// if the root is hidden, it throws off most of these calculations by one;
// find this offset peppered through the code below
//
int hiddenRootOffset = 0;
if ( isRootHidden() )
hiddenRootOffset = 1;
//
// scratch strings
//
String s = null;
String t = null;
buf.append( "<tr>" );
//
// insert an empty cell for each level deep the node is
//
for ( int i = hiddenRootOffset; i < node.getLevel(); i++ )
buf.append( "<td> </td>" );
//
// render open/close link; leaf?
//
if ( node.isLeaf() ) {
buf.append(
"<td> </td>" );
}
else {
//
// opened?
//
if ( !node.getOpened() )
buf.append(
"<td><a href=\"" + openUrl_ +
node.hashCode() + "\">" + closedHandleImageHtml_ + "</a></td>" );
//
// closed
//
else
buf.append(
"<td><a href=\"" + closeUrl_ +
node.hashCode() + "\">" + openedHandleImageHtml_ + "</a></td>" );
}
//
// render icon
//
Map iconImages = getIconImages();
if ( iconImages != null ) {
s = ( String )iconImages.get( node.getIconHint() );
if ( s == null )
s = ( String )iconImages.get( DEFAULT_ICON );
if ( s == null ) {
buf.append( "<td> </td>" );
}
else {
if ( node.getUrl() == null )
buf.append( "<td><img src=\"" + s + "\"></td>" );
else
buf.append(
"<td><a href=\"" + node.getUrl() + "\"><img border=\"0\" src=\"" +
s + "\"></a></td>" );
}
}
//
// render label
//
if ( node.getUrl() == null )
buf.append(
"<td width=\"100%\" colspan=\"" +
( maxVisibleLevel - node.getLevel() + 1 ) + "\">" +
node.getLabel() + "</td>" );
else
buf.append(
"<td width=\"100%\" colspan=\"" +
( maxVisibleLevel - node.getLevel() + 1 ) +
"\"><a href=\"" + node.getUrl() + "\">" + node.getLabel() +
"</a></td>" );
buf.append( "</tr>\n" );
}
// properties ///////////////////////////////////////////////////////////////
/**
* Sets the url to open a node; the hash code of the node to be opened will
* be appended to the end of this url.
*/
public void setOpenUrl( String openUrl ) {
openUrl_ = openUrl;
}
/**
* Sets the url to close a node; the hash code of the node to be closed will
* be appended to the end of this url.
*/
public void setCloseUrl( String closeUrl ) {
closeUrl_ = closeUrl;
}
// attributes ///////////////////////////////////////////////////////////////
protected String openUrl_ = null;
protected String closeUrl_ = null;
private String openedHandleImageHtml_ = null;
private String closedHandleImageHtml_ = null;
}
|