/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) 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 org.opencms.workplace.list;
import org.opencms.main.CmsIllegalStateException;
import org.opencms.util.CmsStringUtil;
import org.opencms.workplace.tools.CmsIdentifiableObjectContainer;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* This is class contains all the information for defining a whole html list.<p>
*
* @since 6.0.0
*/
public class CmsListMetadata {
/** the html id for the input element of the search bar. */
public static final String SEARCH_BAR_INPUT_ID = "listSearchFilter";
/** Container for column definitions. */
private CmsIdentifiableObjectContainer<CmsListColumnDefinition> m_columns = new CmsIdentifiableObjectContainer<CmsListColumnDefinition>(
true,
false);
/** Container for of independent actions. */
private CmsIdentifiableObjectContainer<I_CmsListAction> m_indepActions = new CmsIdentifiableObjectContainer<I_CmsListAction>(
true,
false);
/** Container for item detail definitions. */
private CmsIdentifiableObjectContainer<CmsListItemDetails> m_itemDetails = new CmsIdentifiableObjectContainer<CmsListItemDetails>(
true,
false);
/** The id of the list. */
private String m_listId;
/** Container for multi actions. */
private CmsIdentifiableObjectContainer<CmsListMultiAction> m_multiActions = new CmsIdentifiableObjectContainer<CmsListMultiAction>(
true,
false);
/** Search action. */
private CmsListSearchAction m_searchAction;
/** if the data is self managed (sorted and filtered by {@link A_CmsListDialog#getListItems()} method). */
private boolean m_selfManaged;
/** if this metadata object should not be cached.<p>. */
private boolean m_volatile;
/** The related workplace dialog object. */
private transient A_CmsListDialog m_wp;
/**
* Default Constructor.<p>
*
* @param listId the id of the list
*/
public CmsListMetadata(String listId) {
m_listId = listId;
}
/**
* Adds a new column definition at the end.<p>
*
* By default a column is printable if it is the first column in the list,
* or if it is sorteable.<p>
*
* If you want to override this behaviour, use the
* {@link CmsListColumnDefinition#setPrintable(boolean)}
* method after calling this one.
*
* @param listColumn the column definition
*
* @see CmsIdentifiableObjectContainer
*/
public void addColumn(CmsListColumnDefinition listColumn) {
addColumn(listColumn, m_columns.elementList().size());
}
/**
* Adds a new column definition at the given position.<p>
*
* By default a column is printable if it is the first column in the list,
* or if it is sorteable.<p>
*
* If you want to override this behaviour, use the
* {@link CmsListColumnDefinition#setPrintable(boolean)}
* method after calling this one.
*
* @param listColumn the column definition
* @param position the position
*
* @see CmsIdentifiableObjectContainer
*/
public void addColumn(CmsListColumnDefinition listColumn, int position) {
setListIdForColumn(listColumn);
if (m_columns.elementList().isEmpty()) {
listColumn.setPrintable(true);
} else {
listColumn.setPrintable(listColumn.isSorteable());
}
if ((listColumn.getName() == null) && listColumn.isPrintable()) {
listColumn.setPrintable(false);
}
m_columns.addIdentifiableObject(listColumn.getId(), listColumn, position);
}
/**
* Adds a list item independent action.<p>
*
* @param action the action
*/
public void addIndependentAction(I_CmsListAction action) {
action.setListId(getListId());
m_indepActions.addIdentifiableObject(action.getId(), action);
}
/**
* Adds a new item detail definition at the end.<p>
*
* @param itemDetail the item detail definition
*
* @see CmsIdentifiableObjectContainer
*/
public void addItemDetails(CmsListItemDetails itemDetail) {
itemDetail.setListId(getListId());
m_itemDetails.addIdentifiableObject(itemDetail.getId(), itemDetail);
}
/**
* Adds a new item detail definition at the given position.<p>
*
* @param itemDetail the item detail definition
* @param position the position
*
* @see CmsIdentifiableObjectContainer
*/
public void addItemDetails(CmsListItemDetails itemDetail, int position) {
itemDetail.setListId(getListId());
m_itemDetails.addIdentifiableObject(itemDetail.getId(), itemDetail, position);
}
/**
* Adds an action applicable to more than one list item at once.<p>
*
* It will be executed with a list of <code>{@link CmsListItem}</code>s.<p>
*
* @param multiAction the action
*/
public void addMultiAction(CmsListMultiAction multiAction) {
multiAction.setListId(getListId());
m_multiActions.addIdentifiableObject(multiAction.getId(), multiAction);
}
/**
* Generates the csv output for an empty table.<p>
*
* @return csv output
*/
public String csvEmptyList() {
StringBuffer html = new StringBuffer(512);
html.append("\n");
return html.toString();
}
/**
* Returns the csv output for the header of the list.<p>
*
* @return csv output
*/
public String csvHeader() {
StringBuffer csv = new StringBuffer(1024);
Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
while (itCols.hasNext()) {
CmsListColumnDefinition col = itCols.next();
if (!col.isVisible()) {
continue;
}
csv.append(col.csvHeader());
csv.append("\t");
}
csv.append("\n\n");
return csv.toString();
}
/**
* Returns the csv output for a list item.<p>
*
* @param item the list item to render
*
* @return csv output
*/
public String csvItem(CmsListItem item) {
StringBuffer csv = new StringBuffer(1024);
Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
while (itCols.hasNext()) {
CmsListColumnDefinition col = itCols.next();
if (!col.isVisible()) {
continue;
}
csv.append(col.csvCell(item));
csv.append("\t");
}
csv.append("\n");
return csv.toString();
}
/**
* Returns a column definition object for a given column id.<p>
*
* @param columnId the column id
*
* @return the column definition, or <code>null</code> if not present
*/
public CmsListColumnDefinition getColumnDefinition(String columnId) {
return m_columns.getObject(columnId);
}
/**
* Returns all columns definitions.<p>
*
* @return a list of <code>{@link CmsListColumnDefinition}</code>s.
*/
public List<CmsListColumnDefinition> getColumnDefinitions() {
return m_columns.elementList();
}
/**
* Returns an independent action object for a given id.<p>
*
* @param actionId the id
*
* @return the independent action, or <code>null</code> if not present
*/
public I_CmsListAction getIndependentAction(String actionId) {
return m_indepActions.getObject(actionId);
}
/**
* Returns the list of independent actions.<p>
*
* @return a list of <code>{@link I_CmsListAction}</code>s
*/
public List<I_CmsListAction> getIndependentActions() {
return m_indepActions.elementList();
}
/**
* Returns the item details definition object for a given id.<p>
*
* @param itemDetailId the id
*
* @return the item details definition, or <code>null</code> if not present
*/
public CmsListItemDetails getItemDetailDefinition(String itemDetailId) {
return m_itemDetails.getObject(itemDetailId);
}
/**
* Returns all detail definitions.<p>
*
* @return a list of <code>{@link CmsListItemDetails}</code>.
*/
public List<CmsListItemDetails> getItemDetailDefinitions() {
return m_itemDetails.elementList();
}
/**
* Returns the id of the list.<p>
*
* @return the id of list
*/
public String getListId() {
return m_listId;
}
/**
* Returns a multi action object for a given id.<p>
*
* @param actionId the id
*
* @return the multi action, or <code>null</code> if not present
*/
public CmsListMultiAction getMultiAction(String actionId) {
return m_multiActions.getObject(actionId);
}
/**
* Returns the list of multi actions.<p>
*
* @return a list of <code>{@link CmsListMultiAction}</code>s
*/
public List<CmsListMultiAction> getMultiActions() {
return m_multiActions.elementList();
}
/**
* Returns the search action.<p>
*
* @return the search action
*/
public CmsListSearchAction getSearchAction() {
return m_searchAction;
}
/**
* Returns the total number of displayed columns.<p>
*
* @return the total number of displayed columns
*/
public int getWidth() {
return m_columns.elementList().size() + (hasCheckMultiActions() ? 1 : 0);
}
/**
* Returns the related workplace dialog.<p>
*
* @return the related workplace dialog
*/
public A_CmsListDialog getWp() {
return m_wp;
}
/**
* Returns <code>true</code> if the list definition contains an action.<p>
*
* @return <code>true</code> if the list definition contains an action
*/
public boolean hasActions() {
return !m_indepActions.elementList().isEmpty();
}
/**
* Returns <code>true</code> if at least 'check' multiaction has been set.<p>
*
* @return <code>true</code> if at least 'check' multiaction has been set
*/
public boolean hasCheckMultiActions() {
Iterator<CmsListMultiAction> it = m_multiActions.elementList().iterator();
while (it.hasNext()) {
CmsListMultiAction action = it.next();
if (!(action instanceof CmsListRadioMultiAction)) {
return true;
}
}
return false;
}
/**
* Returns <code>true</code> if the list definition contains a multi action.<p>
*
* @return <code>true</code> if the list definition contains a multi action
*/
public boolean hasMultiActions() {
return !m_multiActions.elementList().isEmpty();
}
/**
* Returns <code>true</code> if any column definition contains a single action.<p>
*
* @return <code>true</code> if any column definition contains a single action
*/
public boolean hasSingleActions() {
Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
while (itCols.hasNext()) {
CmsListColumnDefinition col = itCols.next();
if (!col.getDefaultActions().isEmpty() || !col.getDirectActions().isEmpty()) {
return true;
}
}
return false;
}
/**
* Returns the html code for the action bar.<p>
*
* @return html code
*/
public String htmlActionBar() {
StringBuffer html = new StringBuffer(1024);
html.append("<td class='misc'>\n");
html.append("\t<div>\n");
Iterator<CmsListItemDetails> itDetails = m_itemDetails.elementList().iterator();
while (itDetails.hasNext()) {
I_CmsListAction detailAction = itDetails.next().getAction();
html.append("\t\t");
html.append(detailAction.buttonHtml());
if (itDetails.hasNext()) {
html.append(" ");
}
html.append("\n");
}
Iterator<I_CmsListAction> itActions = m_indepActions.elementList().iterator();
while (itActions.hasNext()) {
I_CmsListAction indepAction = itActions.next();
html.append("\t\t");
html.append(" ");
html.append(indepAction.buttonHtml());
html.append("\n");
}
html.append("\t</div>\n");
html.append("</td>\n");
return html.toString();
}
/**
* Generates the hml code for an empty table.<p>
*
* @return html code
*/
public String htmlEmptyTable() {
StringBuffer html = new StringBuffer(512);
html.append("<tr class='oddrowbg'>\n");
html.append("\t<td align='center' colspan='");
html.append(getWidth());
html.append("'>\n");
html.append(Messages.get().getBundle(getWp().getLocale()).key(Messages.GUI_LIST_EMPTY_0));
html.append("\t</td>\n");
html.append("</tr>\n");
return html.toString();
}
/**
* Returns the html code for the header of the list.<p>
*
* @param list the list to generate the code for
*
* @return html code
*/
public String htmlHeader(CmsHtmlList list) {
StringBuffer html = new StringBuffer(1024);
html.append("<tr>\n");
Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
while (itCols.hasNext()) {
CmsListColumnDefinition col = itCols.next();
if (!col.isVisible() && !list.isPrintable()) {
continue;
}
if (!col.isPrintable() && list.isPrintable()) {
continue;
}
html.append(col.htmlHeader(list));
}
if (!list.isPrintable() && hasCheckMultiActions()) {
html.append("\t<th width='0' class='select'>\n");
html.append("\t\t<input type='checkbox' class='checkbox' name='listSelectAll' value='true' onClick=\"listSelect('");
html.append(list.getId());
html.append("')\">\n");
html.append("\t</th>\n");
}
html.append("</tr>\n");
return html.toString();
}
/**
* Returns the html code for a list item.<p>
*
* @param item the list item to render
* @param odd if the position is odd or even
* @param isPrintable if the list is to be printed
*
* @return html code
*/
public String htmlItem(CmsListItem item, boolean odd, boolean isPrintable) {
StringBuffer html = new StringBuffer(1024);
html.append("<tr ");
if (!isPrintable) {
html.append("class='");
html.append(odd ? "oddrowbg" : (getWp().useNewStyle() ? "evenrowbg" : "evenrowbgnew"));
html.append("'");
}
html.append(">\n");
Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
int width = 0;
while (itCols.hasNext()) {
CmsListColumnDefinition col = itCols.next();
if (!col.isVisible() && !isPrintable) {
continue;
}
if (!col.isPrintable() && isPrintable) {
continue;
}
width++;
StringBuffer style = new StringBuffer(64);
html.append("<td");
CmsListColumnAlignEnum align = col.getAlign();
if ((align != CmsListColumnAlignEnum.ALIGN_LEFT) && CmsStringUtil.isNotEmpty(align.toString())) {
style.append("text-align: ");
style.append(col.getAlign());
style.append("; ");
}
if (col.isTextWrapping()) {
style.append("white-space: normal;");
}
if (isPrintable) {
style.append("border-top: 1px solid black;");
}
if (style.length() > 0) {
html.append(" style='");
html.append(style);
html.append("'");
}
html.append(">\n");
html.append(col.htmlCell(item, isPrintable));
html.append("</td>\n");
}
if (!isPrintable && hasCheckMultiActions()) {
width++;
html.append("\t<td class='select' style='text-align: center'>\n");
html.append("\t\t<input type='checkbox' class='checkbox' name='listMultiAction' value='");
html.append(item.getId());
html.append("'>\n");
html.append("\t</td>\n");
}
html.append("</tr>\n");
Iterator<CmsListItemDetails> itDet = m_itemDetails.elementList().iterator();
while (itDet.hasNext()) {
CmsListItemDetails lid = itDet.next();
if (!lid.isVisible() && !isPrintable) {
continue;
}
if (!lid.isPrintable() && isPrintable) {
continue;
}
if ((item.get(lid.getId()) != null)
&& CmsStringUtil.isNotEmptyOrWhitespaceOnly(item.get(lid.getId()).toString())) {
int padCols = 0;
itCols = m_columns.elementList().iterator();
while (itCols.hasNext()) {
CmsListColumnDefinition col = itCols.next();
if (col.getId().equals(lid.getAtColumn())) {
break;
}
if (!col.isVisible() && !isPrintable) {
continue;
}
if (!col.isPrintable() && isPrintable) {
continue;
}
padCols++;
}
int spanCols = width - padCols;
html.append("<tr ");
if (!isPrintable) {
html.append("class='");
html.append(odd ? "oddrowbg" : (getWp().useNewStyle() ? "evenrowbg" : "evenrowbgnew"));
html.append("'");
}
html.append(">\n");
if (padCols > 0) {
html.append("<td colspan='");
html.append(padCols);
html.append("'> </td>\n");
}
html.append("<td colspan='");
html.append(spanCols);
html.append("' style='padding-left: 20px; white-space:normal;'>\n");
html.append(lid.htmlCell(item, isPrintable));
html.append("\n</td>\n");
html.append("\n");
html.append("</tr>\n");
}
}
return html.toString();
}
/**
* Returns the html code for the multi action bar.<p>
*
* @return html code
*/
public String htmlMultiActionBar() {
StringBuffer html = new StringBuffer(1024);
html.append("<td class='misc'>\n");
html.append("\t<div>\n");
Iterator<CmsListMultiAction> itActions = m_multiActions.elementList().iterator();
while (itActions.hasNext()) {
CmsListMultiAction multiAction = itActions.next();
html.append("\t\t");
html.append(multiAction.buttonHtml());
if (itActions.hasNext()) {
html.append(" ");
}
html.append("\n");
}
html.append("\t</div>\n");
html.append("</td>\n");
return html.toString();
}
/**
* Generates the html code for the search bar.<p>
*
* @return html code
*/
public String htmlSearchBar() {
if (!isSearchable()) {
return "";
}
StringBuffer html = new StringBuffer(1024);
html.append("<td class='main'>\n");
html.append("\t<div>\n");
html.append("\t\t<input type='text' name='listSearchFilter' id='"
+ SEARCH_BAR_INPUT_ID
+ "' value='' size='20' maxlength='245' style='vertical-align: bottom;'>\n");
html.append(m_searchAction.buttonHtml());
I_CmsListAction showAllAction = m_searchAction.getShowAllAction();
if (showAllAction != null) {
html.append(" ");
html.append(showAllAction.buttonHtml());
}
html.append("\t</div>\n");
html.append("</td>\n");
return html.toString();
}
/**
* Returns <code>true</code> if the list is searchable.<p>
*
* @return <code>true</code> if the list is searchable
*/
public boolean isSearchable() {
return m_searchAction != null;
}
/**
* Returns the self Managed flag.<p>
*
* @return the self Managed flag
*/
public boolean isSelfManaged() {
return m_selfManaged;
}
/**
* Returns <code>true</code> if any column is sorteable.<p>
*
* @return <code>true</code> if any column is sorteable
*/
public boolean isSorteable() {
Iterator<CmsListColumnDefinition> itCols = m_columns.elementList().iterator();
while (itCols.hasNext()) {
CmsListColumnDefinition col = itCols.next();
if (col.isSorteable()) {
return true;
}
}
return false;
}
/**
* Returns <code>true</code> if this metadata object should not be cached.<p>
*
* @return <code>true</code> if this metadata object should not be cached.<p>
*/
public boolean isVolatile() {
return m_volatile;
}
/**
* Sets the search action.<p>
*
* @param searchAction the search action to set
*/
public void setSearchAction(CmsListSearchAction searchAction) {
m_searchAction = searchAction;
if (m_searchAction != null) {
m_searchAction.setListId(getListId());
}
}
/**
* Sets the self Managed flag.<p>
*
* @param selfManaged the self Managed flag to set
*/
public void setSelfManaged(boolean selfManaged) {
this.m_selfManaged = selfManaged;
}
/**
* Sets the volatile flag.<p>
*
* @param volatileFlag the volatile flag to set
*/
public void setVolatile(boolean volatileFlag) {
m_volatile = volatileFlag;
}
/**
* Sets the related workplace dialog.<p>
*
* @param wp the related workplace dialog to set
*/
public void setWp(A_CmsListDialog wp) {
m_wp = wp;
Iterator<CmsListColumnDefinition> itCols = getColumnDefinitions().iterator();
while (itCols.hasNext()) {
CmsListColumnDefinition column = itCols.next();
column.setWp(wp);
}
Iterator<CmsListItemDetails> itDets = getItemDetailDefinitions().iterator();
while (itDets.hasNext()) {
CmsListItemDetails detail = itDets.next();
detail.setWp(wp);
}
Iterator<CmsListMultiAction> itMultiActs = getMultiActions().iterator();
while (itMultiActs.hasNext()) {
CmsListMultiAction action = itMultiActs.next();
action.setWp(wp);
}
Iterator<I_CmsListAction> itIndActs = getIndependentActions().iterator();
while (itIndActs.hasNext()) {
I_CmsListAction action = itIndActs.next();
action.setWp(wp);
}
if (m_searchAction != null) {
m_searchAction.setWp(wp);
}
}
/**
* Toggles the given item detail state from visible to hidden or
* from hidden to visible.<p>
*
* @param itemDetailId the item detail id
*/
public void toogleDetailState(String itemDetailId) {
CmsListItemDetails lid = m_itemDetails.getObject(itemDetailId);
lid.setVisible(!lid.isVisible());
}
/**
* Throws a runtime exception if there are 2 identical ids.<p>
*
* This includes:<p>
* <ul>
* <li><code>{@link CmsListIndependentAction}</code>s</li>
* <li><code>{@link CmsListMultiAction}</code>s</li>
* <li><code>{@link CmsListItemDetails}</code></li>
* <li><code>{@link CmsListColumnDefinition}</code>s</li>
* <li><code>{@link CmsListDefaultAction}</code>s</li>
* <li><code>{@link CmsListDirectAction}</code>s</li>
* </ul>
*/
/*package*/void checkIds() {
Set<String> ids = new TreeSet<String>();
// indep actions
Iterator<I_CmsListAction> itIndepActions = getIndependentActions().iterator();
while (itIndepActions.hasNext()) {
String id = itIndepActions.next().getId();
if (ids.contains(id)) {
throw new CmsIllegalStateException(Messages.get().container(Messages.ERR_DUPLICATED_ID_1, id));
}
ids.add(id);
}
// multi actions
Iterator<CmsListMultiAction> itMultiActions = getMultiActions().iterator();
while (itMultiActions.hasNext()) {
String id = itMultiActions.next().getId();
if (ids.contains(id)) {
throw new CmsIllegalStateException(Messages.get().container(Messages.ERR_DUPLICATED_ID_1, id));
}
ids.add(id);
}
// details
Iterator<CmsListItemDetails> itItemDetails = getItemDetailDefinitions().iterator();
while (itItemDetails.hasNext()) {
String id = itItemDetails.next().getId();
if (ids.contains(id)) {
throw new CmsIllegalStateException(Messages.get().container(Messages.ERR_DUPLICATED_ID_1, id));
}
ids.add(id);
}
// columns
Iterator<CmsListColumnDefinition> itColumns = getColumnDefinitions().iterator();
while (itColumns.hasNext()) {
CmsListColumnDefinition col = itColumns.next();
if (ids.contains(col.getId())) {
throw new CmsIllegalStateException(Messages.get().container(Messages.ERR_DUPLICATED_ID_1, col.getId()));
}
ids.add(col.getId());
// default actions
Iterator<CmsListDefaultAction> itDefaultActions = col.getDefaultActions().iterator();
while (itDefaultActions.hasNext()) {
CmsListDefaultAction action = itDefaultActions.next();
if (ids.contains(action.getId())) {
throw new CmsIllegalStateException(Messages.get().container(
Messages.ERR_DUPLICATED_ID_1,
action.getId()));
}
ids.add(action.getId());
}
// direct actions
Iterator<I_CmsListDirectAction> itDirectActions = col.getDirectActions().iterator();
while (itDirectActions.hasNext()) {
I_CmsListDirectAction action = itDirectActions.next();
if (ids.contains(action.getId())) {
throw new CmsIllegalStateException(Messages.get().container(
Messages.ERR_DUPLICATED_ID_1,
action.getId()));
}
ids.add(action.getId());
}
}
}
/**
* Sets the list id for all column single actions.<p>
*
* @param col the column to set the list id for
*/
private void setListIdForColumn(CmsListColumnDefinition col) {
col.setListId(getListId());
// default actions
Iterator<CmsListDefaultAction> itDefaultActions = col.getDefaultActions().iterator();
while (itDefaultActions.hasNext()) {
itDefaultActions.next().setListId(getListId());
}
// direct actions
Iterator<I_CmsListDirectAction> itDirectActions = col.getDirectActions().iterator();
while (itDirectActions.hasNext()) {
itDirectActions.next().setListId(getListId());
}
}
}