/* * File : $Source: /usr/local/cvs/alkacon/com.alkacon.opencms.formgenerator/src/com/alkacon/opencms/formgenerator/CmsTableField.java,v $ * Date : $Date: 2011-03-09 15:14:34 $ * Version: $Revision: 1.6 $ * * This library is part of OpenCms - * the Open Source Content Mananagement System * * Copyright (C) 2010 Alkacon Software GmbH (http://www.alkacon.com) * * 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. * * For further information about Alkacon Software GmbH, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.alkacon.opencms.formgenerator; import org.opencms.configuration.CmsConfigurationException; import org.opencms.i18n.CmsMessages; import org.opencms.main.CmsLog; import org.opencms.util.CmsStringUtil; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.apache.commons.logging.Log; import org.antlr.stringtemplate.StringTemplate; /** * Represents a table with input fields.<p> * * This field can not be shown in the two column design.<p> * * @author Anja Roettgers * * @version $Revision: 1.6 $ * * @since 7.0.4 */ public class CmsTableField extends A_CmsField { /** The log object for this class. */ private static final Log LOG = CmsLog.getLog(CmsTableField.class); /** HTML field type: table field. */ private static final String TYPE = "table"; /** The list of all column frontend labels. */ private List<String> m_cols; /** The list of all column backend labels. */ private List<String> m_dbcols; /** The list of all row backend labels. */ private List<String> m_dbrows; /** The list of all row frontend labels. */ private List<String> m_rows; /** The items. */ private Map<String, CmsFieldItem> m_tableItems; /** * Returns the type of the input field, e.g. "text" or "select".<p> * * @return the type of the input field */ public static String getStaticType() { return TYPE; } /** * * @see com.alkacon.opencms.formgenerator.I_CmsField#buildHtml(CmsFormHandler, CmsMessages, String, boolean, String) */ @Override public String buildHtml( CmsFormHandler formHandler, CmsMessages messages, String errorKey, boolean showMandatory, String infoKey) { String errorMessage = createStandardErrorMessage(errorKey, messages); Map<String, Object> stAttributes = new HashMap<String, Object>(); stAttributes.put("rows", getRowsEscaped()); stAttributes.put("cols", getColumnsEscaped()); stAttributes.put("rowswithitems", getRowsWithItems()); stAttributes.put("editable", Boolean.TRUE); return createHtml(formHandler, messages, stAttributes, getType(), null, errorMessage, showMandatory); } /** * Returns the labels of the table field for usage in email texts.<p> * * @param formHandler the handler of the current form * @return the HTML with the specific label */ public String buildLabel(CmsFormHandler formHandler) { StringTemplate sTemplate = formHandler.getOutputTemplate("field_table_labels"); // set necessary template attributes sTemplate.setAttribute("field", this); sTemplate.setAttribute("formconfig", formHandler.getFormConfiguration()); sTemplate.setAttribute("errormessage", null); sTemplate.setAttribute("mandatory", null); sTemplate.setAttribute("rows", getRowsEscaped()); return sTemplate.toString(); } /** * Returns the rows of the table field for usage in email texts.<p> * * @param formHandler the handler of the current form * @return the HTML with a table where each cell is a input field */ public String buildRows(CmsFormHandler formHandler) { StringTemplate sTemplate = formHandler.getOutputTemplate("field_table_fields"); // set necessary template attributes sTemplate.setAttribute("formconfig", formHandler.getFormConfiguration()); sTemplate.setAttribute("cols", getColumnsEscaped()); sTemplate.setAttribute("rowswithitems", getRowsWithItems()); sTemplate.setAttribute("editable", Boolean.FALSE); return sTemplate.toString(); } /** * Returns a table without HTML like "col_row:value".<p> * * @param frontend if frontend or backend labels should be used * * @return the table without using HTML needed for email */ public String buildText(boolean frontend) { StringBuffer result = new StringBuffer(); List<String> rows = frontend ? m_rows : m_dbrows; List<String> cols = frontend ? m_cols : m_dbcols; for (int i = 0; i < rows.size(); i++) { String row = rows.get(i); for (int j = 0; j < cols.size(); j++) { String col = cols.get(j); String key = getKey(m_dbcols.get(j), m_dbrows.get(i), false); if (m_tableItems.containsKey(key)) { CmsFieldItem item = m_tableItems.get(key); result.append(getKey(col, row, frontend)).append(":\t"); result.append(item.getValue()).append("\n"); } } } return result.toString(); } /** * @see com.alkacon.opencms.formgenerator.A_CmsField#getItems() */ @Override public List<CmsFieldItem> getItems() { return new ArrayList<CmsFieldItem>(m_tableItems.values()); } /** * @see com.alkacon.opencms.formgenerator.I_CmsField#getType() */ public String getType() { return TYPE; } /** * @see com.alkacon.opencms.formgenerator.A_CmsField#needsItems() */ @Override public boolean needsItems() { return true; } /** * Reads from the default value the configuration of the rows and columns and fills * it with the values from the parameter if its exists.<p> * * @param defaultValue the default value with the configuration of the rows and columns * @param parameter the map of the requested parameter * * @throws CmsConfigurationException if no rows or columns are defined */ public void parseDefault(String defaultValue, Map<String, String[]> parameter) throws CmsConfigurationException { m_tableItems = new HashMap<String, CmsFieldItem>(); // check if the default value is empty if (CmsStringUtil.isEmptyOrWhitespaceOnly(defaultValue)) { throw new CmsConfigurationException(Messages.get().container( Messages.ERR_INIT_INPUT_FIELD_MISSING_ITEM_2, getName(), getType())); } String backend = defaultValue; String frontend = defaultValue; // parse the default value, it should look like '%(ColumnA,ColumnB|RowA,RowB)dbcola,dbcolb|dbrowa,dbrowb' Matcher regex = Pattern.compile("^(%\\()(.*)(\\)).*").matcher(backend); if (regex.matches()) { // a frontend exists frontend = regex.group(2); backend = backend.substring(regex.end(2) + 1, backend.length()); if (CmsStringUtil.isEmpty(backend)) { backend = frontend; } } else { frontend = backend; } List<String> cells = CmsStringUtil.splitAsList(frontend, "|"); List<String> dbcells = CmsStringUtil.splitAsList(backend, "|"); // get the columns and rows from the default value List<String> testRow = new ArrayList<String>(); List<String> testCol = new ArrayList<String>(); m_cols = CmsStringUtil.splitAsList(cells.get(0), ","); m_dbcols = CmsStringUtil.splitAsList(dbcells.get(0), ",", true); m_rows = CmsStringUtil.splitAsList(cells.get(1), ","); m_dbrows = CmsStringUtil.splitAsList(dbcells.get(1), ",", true); // test if the frontend and backend columns are in the size identical if (m_cols.size() != m_dbcols.size()) { throw new CmsConfigurationException(Messages.get().container(Messages.ERR_INIT_TABLE_FIELD_UNEQUAL_0)); } // test if the frontend and backend rows are in the size identical if (m_rows.size() != m_dbrows.size()) { throw new CmsConfigurationException(Messages.get().container(Messages.ERR_INIT_TABLE_FIELD_UNEQUAL_0)); } for (int i = 0; i < m_dbrows.size(); i++) { // look if the row not already exists String dbrow = m_dbrows.get(i); if (testRow.contains(dbrow)) { throw new CmsConfigurationException(Messages.get().container( Messages.ERR_INIT_TABLE_FIELD_UNIQUE_1, dbrow)); } // for each column generate the item for (int j = 0; j < m_dbcols.size(); j++) { // look if the column not already exists String dbcol = m_dbcols.get(j); if ((i == 0) && testCol.contains(dbcol)) { throw new CmsConfigurationException(Messages.get().container( Messages.ERR_INIT_TABLE_FIELD_UNIQUE_1, dbcol)); } // get the parameter of the cell String key = getKey(dbcol, dbrow, false); Object param = parameter.get(getName() + key); String[] value = new String[] {""}; if (param != null) { value = (String[])param; } // add the cell m_tableItems.put(key, new CmsFieldItem(value[0], getKey(dbcol, dbrow, true), key, false, false)); testCol.add(dbcol); } testRow.add(dbrow); } if (m_tableItems.size() <= 0) { throw new CmsConfigurationException(Messages.get().container( Messages.ERR_INIT_INPUT_FIELD_MISSING_ITEM_2, getName(), getType())); } } /** * Returns the HTML escaped column names.<p> * * @return the HTML escaped column names */ protected List<String> getColumnsEscaped() { List<String> result = new ArrayList<String>(m_cols.size()); for (int i = 0; i < m_cols.size(); i++) { String col = m_cols.get(i); result.add(CmsStringUtil.escapeHtml(col)); } return result; } /** * Returns the HTML escaped row names.<p> * * @return the HTML escaped row names */ protected List<String> getRowsEscaped() { List<String> result = new ArrayList<String>(m_cols.size()); for (int i = 0; i < m_rows.size(); i++) { String row = m_rows.get(i); result.add(CmsStringUtil.escapeHtml(row)); } return result; } /** * Returns a list of the table field rows, containig a list of field items representing the column.<p> * * @return a list of the table field rows, containig a list of field items representing the column */ protected List<List<CmsFieldItem>> getRowsWithItems() { List<List<CmsFieldItem>> result = new ArrayList<List<CmsFieldItem>>(); for (int i = 0; i < m_dbrows.size(); i++) { String row = m_dbrows.get(i); List<CmsFieldItem> items = new ArrayList<CmsFieldItem>(m_dbcols.size()); for (int j = 0; j < m_dbcols.size(); j++) { String col = m_dbcols.get(j); String key = getKey(col, row, false); if (m_tableItems.containsKey(key)) { CmsFieldItem item = m_tableItems.get(key); item.setName(getName() + key); items.add(item); } } result.add(items); } return result; } /** * Validate each item in the table.<p> * * @see com.alkacon.opencms.formgenerator.A_CmsField#validateConstraints() */ @Override protected String validateConstraints() { if (!isMandatory()) { return null; } // check if the field has a value for (int i = 0; i < m_dbcols.size(); i++) { String col = m_dbcols.get(i); for (int j = 0; j < m_dbrows.size(); j++) { String row = m_dbrows.get(j); String key = getKey(col, row, false); if (!m_tableItems.containsKey(key)) { return CmsFormHandler.ERROR_MANDATORY; } CmsFieldItem item = m_tableItems.get(key); // check if the field has been filled out if (CmsStringUtil.isEmpty(item.getValue())) { return CmsFormHandler.ERROR_MANDATORY; } } } return null; } /** * Validate each item in the table.<p> * * @see com.alkacon.opencms.formgenerator.A_CmsField#validateValue() */ @Override protected String validateValue() { if (CmsStringUtil.isEmptyOrWhitespaceOnly(getValidationExpression())) { return null; } Pattern pattern = Pattern.compile(getValidationExpression()); List<CmsFieldItem> items = getItems(); for (int i = 0; i < items.size(); i++) { try { CmsFieldItem item = items.get(i); if (CmsStringUtil.isNotEmpty(item.getValue()) && !pattern.matcher(item.getValue()).matches()) { return CmsFormHandler.ERROR_VALIDATION; } } catch (PatternSyntaxException e) { // syntax error in regular expression, log to opencms.log if (LOG.isErrorEnabled()) { LOG.error(Messages.get().getBundle().key(Messages.LOG_ERR_PATTERN_SYNTAX_0), e); } } } return null; } /** * Returns the key used to identify a single field, like when accessing the {@link #m_tableItems} map.<p> * * @param col the col label * @param row the row label * @param frontend if for frontend purposes * * @return the key */ private String getKey(String col, String row, boolean frontend) { return frontend ? col + " - " + row : col + "_" + row; } }