/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.platform.util.xml;
import org.dom4j.Node;
import org.pentaho.platform.api.engine.IDocumentResourceLoader;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.util.messages.LocaleHelper;
import javax.xml.transform.TransformerException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class XForm {
// TODO sbarkdull, make this an enumerated type
public static final int TYPE_RADIO = 1;
public static final int TYPE_SELECT = 2;
public static final int TYPE_LIST = 3;
public static final int TYPE_LIST_MULTI = 4;
public static final int TYPE_CHECK_MULTI = 5;
public static final int TYPE_CHECK_MULTI_SCROLL = 6;
public static final int TYPE_CHECK_MULTI_SCROLL_2_COLUMN = 7;
public static final int TYPE_CHECK_MULTI_SCROLL_3_COLUMN = 8;
public static final int TYPE_CHECK_MULTI_SCROLL_4_COLUMN = 9;
public static final int TYPE_TEXT = 10;
// TODO sbarkdull make this an enumerated type
public static final int OUTPUT_XFORM = 1;
public static final int OUTPUT_HTML = 2;
public static final int OUTPUT_HTML_PAGE = 3;
public static String transformSnippet( final Node xForm, final IPentahoSession session,
final IDocumentResourceLoader loader ) throws TransformerException {
return XForm.transformSnippet( xForm.asXML(), null, session, loader );
}
/**
* Using html4.xsl, wrap the XForm String in xFormSnippet in a <pho:snippet>, and transform the wrapped XSL
* into an HTML form snippet.
*
* @param xFormSnippet
* The xml snippet being transformed.
* @param method
* HTML form method, generally either "post" or "get".
* @param session
* @return HTML form snippet, null on error.
* @throws TransformerException
* if the transform fails.
*/
public static String transformSnippet( final String xFormSnippet, final String method, final IPentahoSession session,
final IDocumentResourceLoader loader ) throws TransformerException {
StringBuffer xForm = null;
xForm =
new StringBuffer().append( "<?xml version=\"1.0\" encoding=\"" + LocaleHelper.getSystemEncoding() + "\" ?>" ) //$NON-NLS-1$ //$NON-NLS-2$
.append(
"<pho:snippet xmlns:xf=\"http://www.w3.org/2002/xforms\" xmlns:pho=\"http://www.w3.org/1999/homl\">" ) //$NON-NLS-1$
.append( xFormSnippet ).append( "</pho:snippet>" ); //$NON-NLS-1$
String html = XForm.transform( xForm.toString(), method, session, loader );
// This is required so that we don't get a new form for each control
// TODO fix the transform so that this code is not required...
int pos1 = html.indexOf( "<form name=\"pentaho-form\"" ); //$NON-NLS-1$
int pos2 = html.indexOf( "enctype=\"application/x-www-form-urlencoded\">", pos1 ); //$NON-NLS-1$
if ( pos2 > 0 ) {
html = html.substring( pos2 + 44 );
pos2 = html.indexOf( "</form>" ); //$NON-NLS-1$
if ( pos2 > 0 ) {
html = html.substring( 0, pos2 );
}
}
return html;
}
/**
* Using html4.xsl, transform the xml in the xForm string to an HTML form snippet.
*
* @param xForm
* The xml string being transformed.
* @param method
* HTML form method, generally either "post" or "get".
* @param session
* @return HTML form snippet, null on error.
* @throws TransformerException
* if the transform fails.
*/
public static String transform( final String xForm, final String method, final IPentahoSession session,
final IDocumentResourceLoader loader ) throws TransformerException {
HashMap<String, String> parameters = new HashMap<String, String>();
if ( method != null ) {
parameters.put( "form-method", method ); //$NON-NLS-1$
} else {
parameters.put( "form-method", "GET" ); //$NON-NLS-1$ //$NON-NLS-2$
}
// TODO: Why isn't the parameters map above being passed in as the 4th parameter?
return XmlHelper.transformXml( "html4.xsl", null, xForm, null, loader ).toString(); //$NON-NLS-1$
}
public static void createXFormHeader( final String formName, final StringBuffer xformHeader ) {
xformHeader.append( "<head>" ) //$NON-NLS-1$
.append( "<link rel=\"stylesheet\" type=\"text/css\" href=\"/pentaho-style/active/default.css\" />" ) //$NON-NLS-1$
.append( "<xf:model id=\"" ).append( formName ).append( "\">" ) //$NON-NLS-1$ //$NON-NLS-2$
.append( "<xf:instance>" ); //$NON-NLS-1$
}
public static void completeXFormHeader( final String formName, final StringBuffer xformHeader ) {
xformHeader
.append( "</xf:instance>" ) //$NON-NLS-1$
.append( "<xf:submission action=\"\" separator=\"&\" method=\"urlencoded-get\" id=\"" ).append( formName ).append( "\" />" ) //$NON-NLS-1$ //$NON-NLS-2$
.append( "</xf:model>" ) //$NON-NLS-1$
.append( "</head>" ); //$NON-NLS-1$
}
public static void createXFormSubmit( final String formName, final StringBuffer xformBody, final String buttonText ) {
xformBody
.append( "<xf:submit id=\"" ).append( formName ).append( "\" submission=\"" ).append( formName ).append( "\">" ) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
.append( "<xf:label>" ).append( buttonText ).append( "</xf:label>" ) //$NON-NLS-1$ //$NON-NLS-2$
.append( "</xf:submit>" ); //$NON-NLS-1$
}
public static String completeXForm( final int outputType, final String formName, final StringBuffer xformHeader,
final StringBuffer xformBody, final IPentahoSession session, final IDocumentResourceLoader loader )
throws TransformerException {
xformHeader
.append( "</xf:instance>" ) //$NON-NLS-1$
.append( "<xf:submission action=\"\" separator=\"&\" method=\"urlencoded-get\" id=\"" ).append( formName ).append( "\" />" ) //$NON-NLS-1$ //$NON-NLS-2$
.append( "</xf:model>" ) //$NON-NLS-1$
.append( "</head>" ); //$NON-NLS-1$
if ( outputType == XForm.OUTPUT_XFORM ) {
xformHeader.append( xformBody );
return xformHeader.toString();
} else if ( outputType == XForm.OUTPUT_HTML ) {
xformHeader.append( "<body dir=\"" ).append( LocaleHelper.getTextDirection() ).append( "\">" ); //$NON-NLS-1$ //$NON-NLS-2$
xformHeader.append( xformBody );
xformHeader.append( "</body>" ); //$NON-NLS-1$
return XForm.transformSnippet( xformHeader.toString(), "GET", session, loader ); //$NON-NLS-1$
} else if ( outputType == XForm.OUTPUT_HTML_PAGE ) {
StringBuffer xForm = new StringBuffer();
xForm
.append( "<html xmlns=\"http://www.w3.org/2002/06/xhtml2\" xmlns:xf=\"http://www.w3.org/2002/xforms\" xmlns:pho=\"http://www.w3.org/2002/xhoml\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" ); //$NON-NLS-1$
if ( xformBody.indexOf( "{xform-header}" ) > -1 ) { //$NON-NLS-1$
String header = xformHeader.toString();
header = header.replaceFirst( "<head>", "" ); //$NON-NLS-1$ //$NON-NLS-2$
header = header.replaceFirst( "</head>", "" ); //$NON-NLS-1$ //$NON-NLS-2$
String tmp = xformBody.toString();
tmp = tmp.replaceFirst( "\\{xform-header\\}", header ); //$NON-NLS-1$
String html = XForm.transform( tmp, "GET", session, loader ); //$NON-NLS-1$
return html;
} else {
xForm.append( xformHeader );
xForm.append( xformBody );
xForm.append( "</html>" ); //$NON-NLS-1$
String html = XForm.transform( xForm.toString(), "GET", session, loader ); //$NON-NLS-1$
return "<html><body dir=\"" + LocaleHelper.getTextDirection() + "\">" + html + "</body></html>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
} else {
return null;
}
}
public static void createXFormControl( final String fieldName, final Object defaultValues, final String formName,
final StringBuffer xformHeader, final StringBuffer xformBody, final boolean visible ) {
// create some xform to represent this parameter...
if ( xformHeader.length() == 0 ) {
// this is the first parameter, need to create the header...
XForm.createXFormHeader( formName, xformHeader );
}
XForm.setDefaultValues( fieldName, defaultValues, xformHeader );
if ( visible ) {
xformBody
.append( "<xf:input model=\"" ).append( formName ).append( "\" id=\"" ).append( fieldName ).append( "\" ref=\"" ).append( fieldName ).append( "\"></xf:input>" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
}
private static void setDefaultValues( final String fieldName, final Object defaultValues,
final StringBuffer xformHeader ) {
xformHeader.append( "<data xmlns=\"\">" ); //$NON-NLS-1$
if ( defaultValues instanceof String ) {
xformHeader
.append( "<" ).append( fieldName ).append( ">" ).append( XmlHelper.encode( (String) defaultValues ) ).append( "</" ).append( fieldName ).append( ">" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
} else if ( defaultValues instanceof String[] ) {
String[] values = (String[]) defaultValues;
for ( String element : values ) {
xformHeader
.append( "<" ).append( fieldName ).append( ">" ).append( XmlHelper.encode( element ) ).append( "</" ).append( fieldName ).append( ">" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
} else if ( defaultValues instanceof Object[] ) {
Object[] values = (String[]) defaultValues;
for ( Object element : values ) {
xformHeader
.append( "<" ).append( fieldName ).append( ">" ).append( XmlHelper.encode( element.toString() ) ).append( "</" ).append( fieldName ).append( ">" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
} else if ( defaultValues == null ) {
xformHeader.append( "<" ).append( fieldName ).append( "></" ).append( fieldName ).append( ">" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} else {
xformHeader
.append( "<" ).append( fieldName ).append( ">" ).append( XmlHelper.encode( defaultValues.toString() ) ).append( "</" ).append( fieldName ).append( ">" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
xformHeader.append( "</data>" ); //$NON-NLS-1$
}
public static void createXFormControl( final int type, final String fieldName, Object defaultValues,
final List values, final Map displayNames, final String formName, final StringBuffer xformHeader,
final StringBuffer xformBody ) {
// If displaying a text box value might be null and we still want to display the text box
if ( ( type != XForm.TYPE_TEXT ) && ( values == null ) ) {
return;
}
// create some xform to represent this parameter...
if ( xformHeader.length() == 0 ) {
// this is the first parameter, need to create the header...
XForm.createXFormHeader( formName, xformHeader );
}
// If the values is not null and if there is only one item in the list make it the default
if ( ( values != null ) && ( values.size() == 1 ) ) {
defaultValues = XmlHelper.encode( values.get( 0 ).toString() );
}
XForm.setDefaultValues( fieldName, defaultValues, xformHeader );
String appearance = ""; //$NON-NLS-1$
if ( type == XForm.TYPE_TEXT ) {
xformBody
.append( "<xf:input model=\"" ).append( formName ).append( "\" id=\"" ).append( fieldName ).append( "\" ref=\"" ).append( fieldName ).append( "\"></xf:input>" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
} else if ( ( type == XForm.TYPE_RADIO ) || ( type == XForm.TYPE_SELECT ) || ( type == XForm.TYPE_LIST ) ) {
switch ( type ) {
case TYPE_RADIO:
appearance = "appearance=\"full\"";
break; //$NON-NLS-1$
case TYPE_SELECT:
appearance = "";
break; //$NON-NLS-1$
case TYPE_LIST:
appearance = "appearance=\"compact\"";
break; //$NON-NLS-1$
}
xformBody
.append( "<xf:select1 " ).append( appearance ).append( " model=\"" ).append( formName ).append( "\" id=\"" ).append( fieldName ).append( "\" ref=\"" ).append( fieldName ).append( "\">" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
if ( values != null ) {
Iterator listIterator = values.iterator();
while ( listIterator.hasNext() ) {
String value = XmlHelper.encode( listIterator.next().toString() );
String displayValue =
( displayNames != null ) ? XmlHelper.encode( (String) displayNames.get( value ) ) : value;
if ( displayValue == null ) {
displayValue = value;
}
xformBody
.append( "<xf:item><xf:label>" ).append( displayValue ).append( "</xf:label><xf:value>" ).append( value ).append( "</xf:value></xf:item>" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
xformBody.append( "</xf:select1>" ); //$NON-NLS-1$
} else if ( ( type == XForm.TYPE_LIST_MULTI ) || ( type == XForm.TYPE_CHECK_MULTI )
|| ( type == XForm.TYPE_CHECK_MULTI_SCROLL ) || ( type == XForm.TYPE_CHECK_MULTI_SCROLL_2_COLUMN )
|| ( type == XForm.TYPE_CHECK_MULTI_SCROLL_3_COLUMN ) || ( type == XForm.TYPE_CHECK_MULTI_SCROLL_4_COLUMN ) ) {
switch ( type ) {
case TYPE_CHECK_MULTI:
appearance = "appearance=\"full\"";
break; //$NON-NLS-1$
case TYPE_LIST_MULTI:
appearance = "appearance=\"compact\"";
break; //$NON-NLS-1$
case TYPE_CHECK_MULTI_SCROLL:
appearance = "appearance=\"full-scroll\" columns=\"1\"";
break; //$NON-NLS-1$
case TYPE_CHECK_MULTI_SCROLL_2_COLUMN:
appearance = "appearance=\"full-scroll\" columns=\"2\"";
break; //$NON-NLS-1$
case TYPE_CHECK_MULTI_SCROLL_3_COLUMN:
appearance = "appearance=\"full-scroll\" columns=\"3\"";
break; //$NON-NLS-1$
case TYPE_CHECK_MULTI_SCROLL_4_COLUMN:
appearance = "appearance=\"full-scroll\" columns=\"4\"";
break; //$NON-NLS-1$
}
xformBody
.append( "<xf:select " ).append( appearance ).append( " model=\"" ).append( formName ).append( "\" id=\"" ).append( fieldName ).append( "\" ref=\"" ).append( fieldName ).append( "\">" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
if ( values != null ) {
Iterator listIterator = values.iterator();
while ( listIterator.hasNext() ) {
String value = XmlHelper.encode( listIterator.next().toString() );
String displayValue =
( displayNames != null ) ? XmlHelper.encode( (String) displayNames.get( value ) ) : value;
if ( displayValue == null ) {
displayValue = value;
}
xformBody
.append( "<xf:item><xf:label>" ).append( displayValue ).append( "</xf:label><xf:value>" ).append( value ).append( "</xf:value></xf:item>" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
xformBody.append( "</xf:select>" ); //$NON-NLS-1$
}
}
}