diff --git a/ccm-cms-types-baseContact/src/com/arsdigita/cms/contenttypes/ui/BaseContactEntriesTable.java b/ccm-cms-types-baseContact/src/com/arsdigita/cms/contenttypes/ui/BaseContactEntriesTable.java new file mode 100644 index 000000000..e54aee8d6 --- /dev/null +++ b/ccm-cms-types-baseContact/src/com/arsdigita/cms/contenttypes/ui/BaseContactEntriesTable.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2008 Sören Bernstein All Rights Reserved. + * + * 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. + * + * 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.arsdigita.cms.ui.category; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.ControlLink; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SingleSelectionModel; +import com.arsdigita.bebop.Table; +import com.arsdigita.bebop.event.TableActionEvent; +import com.arsdigita.bebop.event.TableActionListener; +import com.arsdigita.bebop.table.TableCellRenderer; +import com.arsdigita.bebop.table.TableColumn; +import com.arsdigita.bebop.table.TableColumnModel; +import com.arsdigita.bebop.table.TableModel; +import com.arsdigita.bebop.table.TableModelBuilder; +import com.arsdigita.categorization.Category; +import com.arsdigita.categorization.CategoryLocalization; +import com.arsdigita.categorization.CategoryLocalizationCollection; +import com.arsdigita.cms.SecurityManager; +import com.arsdigita.cms.dispatcher.Utilities; +import com.arsdigita.cms.util.GlobalizationUtil; +import com.arsdigita.util.LockableImpl; +import java.math.BigDecimal; +import java.util.Locale; + +/** + * Lists all existing contact entries for a selected contact. + * + * @author Sören Bernstein (quasimodo) quasi@barkhof.uni-bremen.de + */ +public class BaseContactEntriesTable extends Table { + + + private final String TABLE_COL_EDIT = "table_col_lang"; + private final String TABLE_COL_DEL = "table_col_del"; + + /** + * Creates a new instance of BaseContactEntriesTable + */ + public BaseContactEntriesTable(final ItemSelectionModel itemModel, AuthoringKitWizard parent) { + + super(); + this.m_itemModel = itemModel; + + // if table is empty: + setEmptyView(new Label(GlobalizationUtil.globalize("cms.contenttypes.ui.baseContact.contactentries.none"))); + TableColumnModel tab_model = getColumnModel(); + + // define columns + // XXX globalize + tab_model.add(new TableColumn(0, GlobalizationUtil.globalize("cms.contenttypes.ui.baseContact.contactentries.key").localize(), TABLE_COL_EDIT)); + tab_model.add(new TableColumn(1, GlobalizationUtil.globalize("cms.contenttypes.ui.baseContact.contactentries.value").localize())); + tab_model.add(new TableColumn(2, GlobalizationUtil.globalize("cms.contenttypes.ui.baseContact.contactentries.delete").localize(), TABLE_COL_DEL)); + + setModelBuilder(new BaseContactTableModelBuilder()); + + tab_model.get(0).setCellRenderer(new EditCellRenderer()); + tab_model.get(2).setCellRenderer(new DeleteCellRenderer()); + + addTableActionListener(this); + + } + + /** + * XXXX + * + */ + private class BaseContactTableModelBuilder extends LockableImpl implements TableModelBuilder { + + public TableModel makeModel(Table table, PageState state) { +//XXX + final BaseContact baseContact = m_category.getCategory(state); + + if (baseContact != null && baseContact.hasContactEntries()) { + return new BaseContactTableModel(table, state, category); + } else { + return Table.EMPTY_MODEL; + } + } + } + + /** + * XXX + * + */ + private class BaseContactTableModel implements TableModel { + + final private int MAX_DESC_LENGTH = 25; + + private Table m_table; + private BaseContactEntryCollection m_baseContactEntryCollection; + private BaseContactEntry m_baseContactEntry; + + private BaseContactTableModel(Table t, PageState ps, BaseContact baseContact) { + m_table = t; + m_baseContactEntryColletion = new BaseContactEntryCollection(baseContact); + } + + public int getColumnCount() { + return m_table.getColumnModel().size(); + } + + /** + * Check collection for the existence of another row. + * + * If exists, fetch the value of current BaseContactEntryCollection object + * into m_baseContactEntry class variable. + */ + public boolean nextRow() { + + if(m_baseContactEntryCollection != null && m_baseContactEntryCollection.next()){ + m_baseContactEntry = m_baseContactEntryCollection.getBaseContactEntry(); + return true; + + } else { + + return false; + + } + } + + /** + * Return the + * @see com.arsdigita.bebop.table.TableModel#getElementAt(int) + */ + public Object getElementAt(int columnIndex) { + switch (columnIndex){ + case 0: + return m_baseContactEntry.getKey(); + case 1: + return m_baseContactEntry.getValue(); + case 2: + return GlobalizationUtil.globalize("cms.ui.delete").localize(); + default: + return null; + } + } + + /** + * + * @see com.arsdigita.bebop.table.TableModel#getKeyAt(int) + */ + public Object getKeyAt(int columnIndex) { + return m_baseContactEntry.getID(); + } + + } + + /** + * Check for the permissions to edit item and put either a Label or + * a ControlLink accordingly. + */ + private class EditCellRenderer extends LockableImpl implements TableCellRenderer { + + public Component getComponent(Table table, PageState state, Object value, + boolean isSelected, Object key, + int row, int column) { + + SecurityManager sm = Utilities.getSecurityManager(state); +// CategoryLocalization cl = +// (CategoryLocalization) m_clSel.getSelectedObject(state); + +// boolean canEdit = sm.canAccess(state.getRequest(), +// SecurityManager.DELETE_ITEM, +// cl); +// if(canEdit) { + if(true) { + ControlLink link = new ControlLink(value.toString()); + return link; + } else { + return new Label(value.toString()); + } + } + } + + /** + * Check for the permissions to delete item and put either a Label or + * a ControlLink accordingly. + */ + private class DeleteCellRenderer extends LockableImpl implements TableCellRenderer { + + public Component getComponent(Table table, PageState state, Object value, + boolean isSelected, Object key, + int row, int column) { + +// SecurityManager sm = Utilities.getSecurityManager(state); +// CategoryLocalization categoryLocalization = +// new CategoryLocalization(new BigDecimal(evt.getRowKey().toString())); + +// boolean canDelete = sm.canAccess(state.getRequest(), +// SecurityManager.DELETE_ITEM, +// categoryLocalization); +// if(canDelete) { + if(true) { + ControlLink link = new ControlLink(value.toString()); + link.setConfirmation((String) GlobalizationUtil.globalize( + "cms.ui.category.localization.confirm_delete").localize()); + return link; + } else { + return new Label(value.toString()); + } + } + } + + /** + * Provide implementation to TableActionListener method. + * Code that comes into picture when a link on the table is clicked. + * Handles edit and delete event. + */ + public void cellSelected(TableActionEvent evt) { + + PageState state = evt.getPageState(); + + // Get selected BaseContactEntry + BaseContactEntry baseContactEntry = + new BaseContactEntry(new BigDecimal(evt.getRowKey().toString())); + + // Get BaseContact +// XXX + BaseContact baseContact = m_baseContact.getCategory(state); + + // Get selected column + TableColumn col = getColumnModel().get(evt.getColumn().intValue()); + + // Edit + if(col.getHeaderKey().toString().equals(TABLE_COL_EDIT)) { + + } + + // Delete + if(col.getHeaderKey().toString().equals(TABLE_COL_DEL)) { + baseContact.delContactEntry(baseContactEntry.getID()); + } + + } + + /** + * provide Implementation to TableActionListener method. + * Does nothing in our case. + */ + public void headSelected(TableActionEvent e) { + throw new UnsupportedOperationException("Not Implemented"); + } + + +} diff --git a/ccm-cms-types-baseContact/src/com/arsdigita/cms/contenttypes/ui/BaseContactEntryAddForm.java b/ccm-cms-types-baseContact/src/com/arsdigita/cms/contenttypes/ui/BaseContactEntryAddForm.java new file mode 100644 index 000000000..bb94a55c9 --- /dev/null +++ b/ccm-cms-types-baseContact/src/com/arsdigita/cms/contenttypes/ui/BaseContactEntryAddForm.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2008 Sören Bernstein All Rights Reserved. + * + * 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. + * + * 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.arsdigita.cms.ui.category; + + +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.categorization.CategorizationConfig; +import com.arsdigita.categorization.Category; +import com.arsdigita.dispatcher.AccessDeniedException; +import com.arsdigita.cms.util.GlobalizationUtil; +import java.util.Locale; +import java.util.StringTokenizer; + +import org.apache.log4j.Logger; + +/** + * Generates a form for creating new localisations for the given category. + * + * This class is part of the admin GUI of CCM and extends the standard form + * in order to present forms for managing the multi-language categories. + * + * @author Sören Bernstein (quasimodo) quasi@zes.uni-bremen.de + */ +public class CategoryLocalizationAddForm extends CategoryLocalizationForm { + + public static final String versionId = + "$Id: CategoryLocalizationAddForm.java 287 2005-02-22 00:29:02Z sskracic $" + + "$Author: sskracic $" + + "$DateTime: 2004/08/17 23:15:09 $"; + + private static final Logger s_log = Logger.getLogger + (CategoryAddForm.class); + + /** Creates a new instance of CategoryLocalizationAddForm */ + public CategoryLocalizationAddForm(final CategoryRequestLocal category) { + + super("AddCategoryLocalization", + gz("cms.ui.category.localization.add"), category); + + addInitListener(new InitListener()); + addProcessListener(new ProcessListener()); + + } + + // Deaktivate this widget, if category is root +// public boolean isVisible(PageState state) { +// return !m_category.getCategory(state).isRoot(); +// } + + private class InitListener implements FormInitListener { + public final void init(final FormSectionEvent e) + throws FormProcessException { + + final PageState state = e.getPageState(); + final Category category = m_category.getCategory(state); + + // Select one entry + m_locale.addOption(new Option("", + new Label((String) GlobalizationUtil.globalize( + "cms.ui.select_one").localize())), state); + + // all supported languages (by registry entry) + CategorizationConfig catConfig = new CategorizationConfig(); + StringTokenizer strTok = catConfig.getSupportedLanguages(); + + while(strTok.hasMoreTokens()) { + + String code = strTok.nextToken(); + + // If lanuage exists, remove it from the selection list + if(!category.getCategoryLocalizationCollection(). + localizationExists(code)) { + m_locale.addOption(new Option(code, + new Locale(code).getDisplayLanguage()), state); + } + } + } + } + + + private final class ProcessListener implements FormProcessListener { + public final void process(final FormSectionEvent e) + throws FormProcessException { + s_log.debug("Adding a categoryLocalization to category " + m_category); + + final PageState state = e.getPageState(); + + final Category category = m_category.getCategory(state); + final String locale = (String) m_locale.getValue(state); + final String name = (String) m_name.getValue(state); + final String description = (String) m_description.getValue(state); + final String url = (String) m_url.getValue(state); + final String isEnabled = (String) m_isEnabled.getValue(state); + + // Was soll das?? + //Assert.assertNotNull(parent, "Category parent"); + + if (s_log.isDebugEnabled()) { + s_log.debug("Adding localization for locale " + locale + + " to category " + category); + } + + if (category.canEdit()) { + category.addLanguage(locale, name, description, url); + category.setEnabled("yes".equals(isEnabled), locale); + category.save(); + + } else { + // XXX user a better exception here. + // PermissionException doesn't work for this case. + throw new AccessDeniedException(); + } + } + } +} diff --git a/ccm-cms-types-baseContact/src/com/arsdigita/cms/contenttypes/ui/BaseContactEntryForm.java b/ccm-cms-types-baseContact/src/com/arsdigita/cms/contenttypes/ui/BaseContactEntryForm.java new file mode 100644 index 000000000..28c979602 --- /dev/null +++ b/ccm-cms-types-baseContact/src/com/arsdigita/cms/contenttypes/ui/BaseContactEntryForm.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2008 Sören Bernstein All Rights Reserved. + * + * 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. + * + * 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.arsdigita.cms.ui.category; + +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.event.ParameterEvent; +import com.arsdigita.bebop.event.ParameterListener; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.bebop.form.RadioGroup; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.bebop.form.TextArea; +import com.arsdigita.bebop.form.TextField; +import com.arsdigita.bebop.form.Widget; +import com.arsdigita.bebop.parameters.NotNullValidationListener; +import com.arsdigita.bebop.parameters.ParameterData; +import com.arsdigita.bebop.parameters.ParameterModel; +import com.arsdigita.bebop.parameters.StringInRangeValidationListener; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.bebop.parameters.TrimmedStringParameter; +import com.arsdigita.categorization.Category; +import com.arsdigita.categorization.CategoryCollection; +import com.arsdigita.cms.ui.BaseForm; +import com.arsdigita.cms.util.GlobalizationUtil; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.xml.Element; + +/** + * Base class for CategoryLocalizationAddForm and CategoryLocalizationEditForm. + * + * This class is part of the admin GUI of CCM and extends the standard form + * in order to present forms for managing the multi-language categories. + * + * @author Sören Bernstein (quasimodo) quasi@zes.uni-bremen.de + */ +public class CategoryLocalizationForm extends BaseForm { + + final CategoryRequestLocal m_category; + final SingleSelect m_locale; + final TextField m_name; + final TextArea m_description; + final TextField m_url; + final RadioGroup m_isEnabled; + private Label m_script = new Label( + "", false); + + private final static String LOCALE = "locale"; + private final static String NAME = "name"; + private final static String DESCRIPTION = "description"; + private final static String URL = "url"; + private final static String IS_ENABLED = "isEnabled"; + + /** + * Creates a new instance of CategoryLocalizationForm. + * + */ + public CategoryLocalizationForm(final String key, + final GlobalizedMessage heading, + final CategoryRequestLocal category) { + + super(key, heading); + + m_category = category; + + // Parameter-Model for SingleSelect + ParameterModel localeParam = new StringParameter(LOCALE); + localeParam.addParameterListener(new StringInRangeValidationListener(0, 2)); + + m_locale = new SingleSelect(localeParam); + m_locale.addValidationListener(new ParameterListener() { + + public void validate(ParameterEvent e) throws FormProcessException { + + // the --select one-- option is not allowed + ParameterData data = e.getParameterData(); + String code = (String) data.getValue() ; + if (code == null || code.length() == 0) { + data.addError( + (String)GlobalizationUtil.globalize( + "cms.ui.category.localization.error_locale").localize()); + } + } + }); + + addField(gz("cms.ui.category.localization.locale"), m_locale); + + m_name = new TextField(new TrimmedStringParameter(NAME)); + addField(gz("cms.ui.name"), m_name); + + m_name.setSize(30); + m_name.setMaxLength(200); + m_name.addValidationListener(new NotNullValidationListener()); + m_name.setOnFocus("if (this.form." + URL + ".value == '') { " + + " defaulting = true; this.form." + URL + + ".value = urlize(this.value); }"); + m_name.setOnKeyUp("if (defaulting) { this.form." + URL + + ".value = urlize(this.value) }"); + + // is enabled? + m_isEnabled = new RadioGroup(IS_ENABLED); + m_isEnabled.addOption(new Option("no", new Label(gz("cms.ui.no")))); + m_isEnabled.addOption(new Option("yes", new Label(gz("cms.ui.yes")))); + addField(gz("cms.ui.category.is_enabled"),m_isEnabled); + + m_description = new TextArea + (new TrimmedStringParameter(DESCRIPTION)); + addField(gz("cms.ui.description"), m_description); + + m_description.setWrap(TextArea.SOFT); + m_description.setRows(5); + m_description.setCols(40); + + // URL + // JavaScript auto-url generation is off by default. + // It is turned on under the following circumstances + // + // * If the url is null, upon starting edit of the title + // * If the url is null, upon finishing edit of name + // + // The rationale is that, auto-url generation is useful + // if the url is currently null, but once a name has been + // created you don't want to subsequently change it since + // it breaks URLs & potentially overwrites the user's + // customizations. + m_url = new TextField(new TrimmedStringParameter(URL)); + m_url.setSize(30); + m_url.setMaxLength(200); + m_url.addValidationListener(new NotNullValidationListener()); + m_url.setOnFocus("defaulting = false"); + m_url.setOnBlur("if (this.value == '') " + + "{ defaulting = true; this.value = urlize(this.form." + NAME + + ".value) }"); + addField(gz("cms.ui.category.url"),m_url); + + addAction(new Finish()); + addAction(new Cancel()); + + } + + public void generateXML(PageState ps, Element parent) { + m_script.generateXML(ps, parent); + super.generateXML(ps, parent); + } + + /** + * Purpose: + * + * XXXToDo: Should be extended with the function: + * Names have to be unambiguous in the selected language + */ + class NameUniqueListener implements ParameterListener { + private final CategoryRequestLocal m_category; + private final Widget m_widget; + private final int m_type; + public final static int NAME_FIELD = 1; + public final static int URL_FIELD = 2; + + NameUniqueListener(final CategoryRequestLocal category) { + this(category,m_name,NAME_FIELD); + } + NameUniqueListener(final CategoryRequestLocal category, + Widget widget, int type) { + m_category = category; + m_widget = widget; + m_type = type; + } + + + /** + * Purpose: + * + * XXX provisional, has to be adapted + * + * @param e + * @throws com.arsdigita.bebop.FormProcessException + */ + public final void validate(final ParameterEvent e) + throws FormProcessException { + final PageState state = e.getPageState(); + final String title = (String) m_widget.getValue(state); + + final Category category = m_category.getCategory(state); + + final CategoryCollection children = category.getChildren(); + + while (children.next()) { + final Category child = children.getCategory(); + String compField = + (m_type == URL_FIELD) ? child.getURL() : child.getName(); + if (compField.equalsIgnoreCase(title) + && (m_category == null + || !m_category.getCategory(state).equals(child))) { + throw new FormProcessException + (lz("cms.ui.category.name_not_unique")); + } + } + } + } +}