/******************************************************************************* * Copyright (c) 2002-2006 Innoopract Informationssysteme GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Innoopract Informationssysteme GmbH - initial API and implementation ******************************************************************************/ package com.w4t.dhtml.treenodekit; import java.io.IOException; import org.eclipse.rwt.internal.lifecycle.HtmlResponseWriter; import org.eclipse.rwt.internal.util.HTML; import com.w4t.LifeCycleHelper; import com.w4t.WebComponent; import com.w4t.dhtml.*; import com.w4t.dhtml.event.WebTreeNodeCollapsedEvent; import com.w4t.dhtml.event.WebTreeNodeExpandedEvent; import com.w4t.dhtml.renderinfo.TreeNodeInfo; /** * <p> The superclass for all renderers for org.eclipse.rap.dhtml.TreeNode on more * recent browsers that support javascript and restructuring of html documents * via DOM. </p> * <p> Note that this is not an actual renderer but encapsulates common * functionality for browser-specific renderers. </p> */ public abstract class TreeNodeRenderer_DOM_Script extends TreeNodeRenderer_Base_Script { private static final String PLACEHOLDER_TEXT = "Loading..."; // we pass these as bit keys to the eventhandling js private static final int EVT_TYPE_ACTION = 1; private static final int EVT_TYPE_DRAGDROP = 2; public void scheduleRendering( final WebComponent component ) { TreeNode treeNode = ( TreeNode )component; if( !renderPlaceHolder( treeNode ) ) { for( int i = 0; i < treeNode.getItemCount(); i++ ) { if( treeNode.getItem( i ).isVisible() ) { getRenderingSchedule().schedule( treeNode.getItem( i ) ); } } } } public void render( final WebComponent component ) throws IOException { TreeNode treeNode = ( TreeNode )component; fillBuffers( treeNode ); HtmlResponseWriter out = getResponseWriter(); out.startElement( HTML.DIV, null ); out.writeAttribute( HTML.ID, treeNode.getUniqueID(), null ); createNodeContent( treeNode ); createBranchOpen( treeNode ); prepare( treeNode ); if( renderPlaceHolder( treeNode ) ) { createPlaceHolder( treeNode ); } else { createChildren( treeNode ); } createBranchClose(); postpare( treeNode ); createBranchClose(); restoreFromBuffers( treeNode ); } private void createChildren( final TreeNode treeNode ) throws IOException { TreeNodeInfo info = TreeNodeRendererUtil.getInfo( treeNode ); for( int i = 0; i < info.getNodeCount(); i++ ) { TreeNode childNode = info.getNode( i ); getShift( treeNode ).setLastChild( i == info.getNodeCount() - 1 && info.getLeafCount() == 0 ); if( isScheduled( childNode ) ) { LifeCycleHelper.render( childNode ); } } for( int i = 0; i < info.getLeafCount(); i++ ) { TreeLeaf leaf = info.getLeaf( i ); getShift( treeNode ).setLastChild( i == info.getLeafCount() - 1 ); if( isScheduled( leaf ) ) { LifeCycleHelper.render( leaf ); } } } static boolean isScheduled( final WebComponent component ) { return getRenderingSchedule().isScheduled( component ); } private void createPlaceHolder( final TreeNode treeNode ) throws IOException { TreeLeaf placeHolder = new TreeLeaf(); placeHolder.setLabel( PLACEHOLDER_TEXT ); getShift( treeNode ).setLastChild( true ); treeNode.addItem( placeHolder ); LifeCycleHelper.render( placeHolder ); placeHolder.remove(); } void fillBuffers( final TreeNode treeNode ) { super.fillBuffers( treeNode ); TreeNodeInfo info = TreeNodeRendererUtil.getInfo( treeNode ); info.removeToggleLoadingListener(); if( renderPlaceHolder( treeNode ) ) { info.addToggleLoadingListener(); } } void prepare( final TreeNode treeNode ) throws IOException { TreeNodeRendererUtil.getInfo( treeNode ).clearStateInfoFields(); createStateInfoField( treeNode ); if( hasChildren( treeNode ) ) { if( isLastChildBuffer( treeNode ) ) { addEmptyImage( treeNode ); } else { addLineImage( treeNode ); } } } /** <p>helping method for performRendering();</p> * <p> There must be a hidden input field for this TreeNode, which contains * info about whether this TreeNode is expanded or collapsed; this is rendered * by the root, we tell it what to render.</p> */ void createStateInfoField( final TreeNode treeNode ) throws IOException { // need this because of bug in IExplorer (must not be newline here!) String absoluteNecessaryBlank = " "; TreeNodeInfo info = TreeNodeRendererUtil.getInfo( treeNode ); StringBuffer hiddenField = new StringBuffer(); hiddenField.append( "<input type=\"hidden\" " ); hiddenField.append( "name=\"" ); String name = TreeNodeRendererUtil.getStateInfoId( treeNode.getUniqueID() ); hiddenField.append( name ); hiddenField.append( "\" value=\"" ); hiddenField.append( info.getExpansion() ); hiddenField.append( "\" />" ); hiddenField.append( absoluteNecessaryBlank ); info.appendStateInfoField( hiddenField.toString() ); } void postpare( final TreeNode treeNode ) { if( hasChildren( treeNode ) ) { getShift( treeNode ).remove(); } TreeNodeRendererUtil.getInfo( treeNode ).appendStateInfoFields(); } private void createNodeContent( final TreeNode treeNode ) throws IOException { HtmlResponseWriter out = getResponseWriter(); int size = getShift( treeNode ).getSize(); createOpenNodeContent( treeNode ); for( int i = 0; i < size; i++ ) { String imageName = getShift( treeNode ).getImageName( i ); createImageTag( treeNode, imageName ); } if( treeNode.isExpanded() ) { createExpandedNode( treeNode ); } else { createCollapsedNode( treeNode ); } createLabelContent( treeNode ); out.endElement( HTML.DIV ); } void createOpenNodeContent( final TreeNode treeNode ) throws IOException { StringBuffer buffer = new StringBuffer(); buffer.append( "node_" ); buffer.append( treeNode.getUniqueID() ); HtmlResponseWriter out = getResponseWriter(); out.startElement( HTML.DIV, null ); out.writeAttribute( HTML.CLASS, out.registerCssClass( ItemUtil.STYLE_CONTENT ), null ); out.writeAttribute( HTML.ID, buffer, null ); } private void createLabelContent( final TreeNode treeNode ) throws IOException { if( !TreeNodeRendererUtil.isDragDropActive( treeNode ) ) { createLabelContentWithoutDD( treeNode ); } else { createLabelContentWithDD( treeNode ); } } /** build the actual label entry string for the label entry if no DnD * listener is set. </p> * @throws IOException */ private void createLabelContentWithoutDD( final TreeNode treeNode ) throws IOException { HtmlResponseWriter out = getResponseWriter(); String cursorBuffer = getStyle( treeNode ).getCursor(); getStyle( treeNode ).setCursor( "default" ); out.startElement( HTML.SPAN, null ); TreeNodeRendererUtil.writeClickHandler( out, treeNode ); TreeNodeRendererUtil.writeDoubleClickHandler( out, treeNode ); createUniversalAttributes( treeNode ); out.writeAttribute( "unselectable", "on", null ); out.writeNBSP(); out.writeNBSP(); out.writeText( getLabel( treeNode ), null ); out.endElement( HTML.SPAN ); getStyle( treeNode ).setCursor( cursorBuffer ); } private void createLabelContentWithDD( final TreeNode treeNode ) throws IOException { String cursorBuffer = getStyle( treeNode ).getCursor(); String compID = treeNode.getUniqueID(); String evtType = createDDEventType( treeNode ); getStyle( treeNode ).setCursor( "default" ); HtmlResponseWriter out = getResponseWriter(); createSpan( treeNode ); out.startElement( HTML.SPAN, null ); TreeNodeRendererUtil.writeClickHandler( out, treeNode ); TreeNodeRendererUtil.writeDoubleClickHandler( out, treeNode ); StringBuffer buffer = new StringBuffer(); buffer.append( "dragDropHandler.mouseDown( '" ); buffer.append( compID ); buffer.append( "', " ); buffer.append( evtType ); buffer.append( " );" ); out.writeAttribute( HTML.ON_MOUSE_DOWN, buffer, null ); buffer.setLength( 0 ); buffer.append( "dragDropHandler.mouseUp( '" ); buffer.append( compID ); buffer.append( "', " ); buffer.append( evtType ); buffer.append( " );" ); out.writeAttribute( HTML.ON_MOUSE_UP, buffer, null ); createUniversalAttributes( treeNode ); out.writeText( getLabel( treeNode ), null ); out.endElement( HTML.SPAN ); getStyle( treeNode ).setCursor( cursorBuffer ); } private void createSpan( final TreeNode treeNode ) throws IOException { HtmlResponseWriter out = getResponseWriter(); out.startElement( HTML.SPAN, null ); createUniversalAttributes( treeNode ); out.writeNBSP(); out.writeNBSP(); out.endElement( HTML.SPAN ); } private String createDDEventType( final TreeNode treeNode ) { return !TreeNodeRendererUtil.hasActionListener( treeNode ) ? String.valueOf( EVT_TYPE_DRAGDROP ) : String.valueOf( EVT_TYPE_DRAGDROP + EVT_TYPE_ACTION ); } void createImageTag( final TreeNode treeNode, final String imageName ) throws IOException { createToggleHandlerOpen( treeNode, imageName ); createToggleImage( treeNode, imageName ); createToggleHandlerClose( treeNode, imageName ); createIconImage( treeNode, imageName ); } private void createToggleImage( final TreeNode treeNode, final String imageName ) throws IOException { HtmlResponseWriter out = getResponseWriter(); out.startElement( HTML.IMG, null ); createID( treeNode, imageName, "tog" ); out.writeAttribute( HTML.SRC, imageName, null ); out.writeAttribute( HTML.BORDER, "0", null ); } private void createIconImage( final TreeNode treeNode, final String imageName ) throws IOException { if( !isShiftImage( imageName ) ) { String name = createIconName( treeNode ); HtmlResponseWriter out = getResponseWriter(); out.startElement( HTML.IMG, null ); TreeNodeRendererUtil.writeClickHandler( out, treeNode ); TreeNodeRendererUtil.writeDoubleClickHandler( out, treeNode ); createID( treeNode, imageName, "ico" ); out.writeAttribute( HTML.SRC, name, null ); out.writeAttribute( HTML.BORDER, "0", null ); } } private String createIconName( final TreeNode treeNode ) { String result = getCollapsedIcon( treeNode ); if( treeNode.isExpanded() ) { result = hasChildren( treeNode ) ? getExpandedWithChildrenIcon( treeNode ) : getExpandedWithoutChildrenIcon( treeNode ); } return result; } private void createToggleHandlerOpen( final TreeNode treeNode, final String imageName ) throws IOException { if( isToggleable( treeNode, imageName ) ) { int lsnr = 0; lsnr += ( WebTreeNodeExpandedEvent.hasListener( treeNode ) || renderPlaceHolder( treeNode ) ) ? 2 : 0; lsnr += WebTreeNodeCollapsedEvent.hasListener( treeNode ) ? 1 : 0; String hasEvent = String.valueOf( lsnr ); HtmlResponseWriter out = getResponseWriter(); StringBuffer buffer = new StringBuffer(); buffer.append( "treeViewHandler.toggle( '" ); buffer.append( treeNode.getUniqueID() ); buffer.append( "', " ); buffer.append( hasEvent ); buffer.append( ", '" ); buffer.append( treeNode.getImageSetName() ); buffer.append( "', " ); buffer.append( String.valueOf( isLastChildBuffer( treeNode ) ) ); buffer.append( " )" ); out.startElement( HTML.A, null ); out.writeAttribute( HTML.ON_CLICK, buffer, null ); } } private void createToggleHandlerClose( final TreeNode treeNode, final String imageName ) throws IOException { if( isToggleable( treeNode, imageName ) ){ HtmlResponseWriter out = getResponseWriter(); out.endElement( HTML.A ); } } private void createID( final TreeNode treeNode, final String imageName, final String prefix ) throws IOException { HtmlResponseWriter out = getResponseWriter(); if( isToggleable( treeNode, imageName ) ) { StringBuffer buffer = new StringBuffer(); buffer.append( prefix ); buffer.append( treeNode.getUniqueID() ); out.writeAttribute( HTML.ID, buffer, null ); } } // helping methods ////////////////// private static boolean isToggleable( final TreeNode treeNode, final String imageName ) { return treeNode.isEnabled() && isToggleImage( imageName ); } private static boolean isToggleImage( final String imageName ) { return imageName.indexOf( "_Minus" ) != -1 || imageName.indexOf( "_Plus" ) != -1; } private static boolean isShiftImage( final String imageName ) { return imageName.indexOf( "_Empty" ) != -1 || imageName.indexOf( "_Line" ) != -1; } static boolean renderPlaceHolder( final TreeNode treeNode ) { return !treeNode.isExpanded() && ( reloadAlways( treeNode ) || loadDynamic( treeNode ) ); } private static boolean reloadAlways( final TreeNode treeNode ) { return treeNode.getDynLoading().equals( TreeNode.DYNLOAD_ALWAYS ); } private static boolean loadDynamic( final TreeNode treeNode ) { return treeNode.getDynLoading().equals( TreeNode.DYNLOAD_DYNAMIC ) && treeNode.getChildCount() >= treeNode.getMinChildsDynLoad(); } }