/* * 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 2005 - 2008 Pentaho Corporation. All rights reserved. * * @created Mar 22, 2005 * @author James Dixon * */ package org.pentaho.platform.util.xml; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.transform.TransformerException; 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; 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$ 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$ 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$ } } }