/*
* 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;
}
}