diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/ComponentsTable.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/ComponentsTable.java new file mode 100644 index 000000000..6eacc8dca --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/ComponentsTable.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.ui.admin.pagemodels; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.ControlLink; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +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.globalization.GlobalizedMessage; +import com.arsdigita.ui.admin.AdminUiConstants; +import com.arsdigita.util.LockableImpl; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.pagemodel.ComponentModel; + +import java.util.Iterator; +import java.util.List; + +/** + * + * @author Jens Pelzetter + */ +class ComponentsTable extends Table { + + protected static final int COL_COMPONENT_KEY = 0; + protected static final int COL_COMPONENT_TYPE = 1; + protected static final int COL_EDIT = 2; + protected static final int COL_DELETE = 3; + + public ComponentsTable( + final PageModelTab pageModelTab, + final ParameterSingleSelectionModel selectedModelId, + final ParameterSingleSelectionModel selectedComponentId) { + + super(); + super.setIdAttr("pageModelComponentModelsTable"); + + super.setEmptyView(new Label(new GlobalizedMessage( + "ui.admin.pagemodels.componentmodels.none", + AdminUiConstants.ADMIN_BUNDLE))); + + final TableColumnModel columnModel = getColumnModel(); + columnModel.add(new TableColumn( + COL_COMPONENT_KEY, + new Label(new GlobalizedMessage( + "ui.admin.pagemodels.componentmodels.cols.key.heading", + AdminUiConstants.ADMIN_BUNDLE)))); + columnModel.add(new TableColumn( + COL_COMPONENT_TYPE, + new Label(new GlobalizedMessage( + "ui.admin.pagemodels.componentmodels.cols.type.heading", + AdminUiConstants.ADMIN_BUNDLE)))); + columnModel.add(new TableColumn( + COL_EDIT, + new Label(new GlobalizedMessage( + "ui.admin.pagemodels.componentmodels.cols.edit.heading", + AdminUiConstants.ADMIN_BUNDLE)))); + columnModel.add(new TableColumn( + COL_DELETE, + new Label(new GlobalizedMessage( + "ui.admin.pagemodels.componentmodels.cols.delete.heading", + AdminUiConstants.ADMIN_BUNDLE)))); + + columnModel.get(COL_EDIT).setCellRenderer( + new TableCellRenderer() { + + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + + final ControlLink link = new ControlLink((Component) value); + return link; + } + + }); + + columnModel.get(COL_DELETE).setCellRenderer( + new TableCellRenderer() { + + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + + final ControlLink link = new ControlLink((Component) value); + link.setConfirmation(new GlobalizedMessage( + "ui.admin.pagemodels.componentmodels.cols.delete.confirmation", + AdminUiConstants.ADMIN_BUNDLE)); + return link; + } + + }); + + super.addTableActionListener(new TableActionListener() { + + @Override + public void cellSelected(final TableActionEvent event) + throws FormProcessException { + + final PageState state = event.getPageState(); + final String selectedModelIdStr = selectedModelId + .getSelectedKey(state); + final String key = (String) event.getRowKey(); + + switch (event.getColumn()) { + case COL_EDIT: + selectedComponentId.setSelectedKey(state, key); + pageModelTab.showComponentForm(state); + break; + case COL_DELETE: + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PageModelsController controller = cdiUtil + .findBean(PageModelsController.class); + controller.removeComponentModel( + Long.parseLong(selectedModelIdStr), + Long.parseLong(key)); + break; + default: + throw new IllegalArgumentException( + "Invalid value for column"); + } + } + + @Override + public void headSelected(final TableActionEvent event) { + //Nothing + } + + }); + + super.setModelBuilder(new PageModelComponentsTableModelBuilder( + selectedModelId)); + } + + private class PageModelComponentsTableModelBuilder + extends LockableImpl + implements TableModelBuilder { + + private final ParameterSingleSelectionModel selectedModelId; + + public PageModelComponentsTableModelBuilder( + final ParameterSingleSelectionModel selectedModelId) { + + this.selectedModelId = selectedModelId; + } + + @Override + public TableModel makeModel(final Table table, + final PageState state) { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PageModelsController controller = cdiUtil + .findBean(PageModelsController.class); + + final String selectedModelIdStr = selectedModelId + .getSelectedKey(state); + + final List components = controller + .retrieveComponents(Long.parseLong(selectedModelIdStr)); + + return new PageModelComponentsTableModel(components); + } + + } + + private class PageModelComponentsTableModel implements TableModel { + + private final Iterator iterator; + private ComponentModel currentComponent; + + public PageModelComponentsTableModel( + final List components) { + + iterator = components.iterator(); + } + + @Override + public int getColumnCount() { + return 4; + } + + @Override + public boolean nextRow() { + + if (iterator.hasNext()) { + currentComponent = iterator.next(); + return true; + } else { + return false; + } + } + + @Override + public Object getElementAt(final int columnIndex) { + + switch (columnIndex) { + case ComponentsTable.COL_COMPONENT_KEY: + return currentComponent.getKey(); + case ComponentsTable.COL_COMPONENT_TYPE: + return currentComponent.getClass().getName(); + case ComponentsTable.COL_EDIT: + return new Label(new GlobalizedMessage( + "ui.admin.pagemodels.components.edit", + AdminUiConstants.ADMIN_BUNDLE)); + case ComponentsTable.COL_DELETE: + return new Label(new GlobalizedMessage( + "ui.admin.pagemodels.components.delete", + AdminUiConstants.ADMIN_BUNDLE)); + default: + throw new IllegalArgumentException( + "Not a valid column index"); + } + } + + @Override + public Object getKeyAt(final int columnIndex) { + + return currentComponent.getComponentModelId(); + } + + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelDetails.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelDetails.java new file mode 100644 index 000000000..44359b592 --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelDetails.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.ui.admin.pagemodels; + +import com.arsdigita.bebop.ActionLink; +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +import com.arsdigita.bebop.PropertySheet; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.ui.admin.AdminUiConstants; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.core.UnexpectedErrorException; +import org.libreccm.modules.ModuleManager; +import org.libreccm.pagemodel.ComponentModels; +import org.libreccm.pagemodel.PageModel; +import org.libreccm.pagemodel.PageModelRepository; + +import java.util.TooManyListenersException; + +/** + * + * @author Jens Pelzetter + */ +class PageModelDetails extends BoxPanel { + + public PageModelDetails( + final PageModelTab pageModelTab, + final ParameterSingleSelectionModel selectedModelId, + final ParameterSingleSelectionModel selectedComponentId) { + + super(BoxPanel.VERTICAL); + + final ActionLink backLink = new ActionLink(new GlobalizedMessage( + "ui.admin.pagemodels.details.back", + AdminUiConstants.ADMIN_BUNDLE)); + backLink.setClassAttr("back-link"); + backLink.addActionListener(event -> { + selectedModelId.clearSelection(event.getPageState()); + pageModelTab.showPageModelsTable(event.getPageState()); + }); + super.add(backLink); + + final Label heading = new Label(); + heading.setClassAttr("heading"); + heading.addPrintListener(event -> { + final PageState state = event.getPageState(); + final Label target = (Label) event.getTarget(); + final PageModelRepository pageModelRepo = CdiUtil + .createCdiUtil() + .findBean(PageModelRepository.class); + final PageModel pageModel = pageModelRepo + .findById(Long.parseLong(selectedModelId.getSelectedKey(state))) + .get(); + target.setLabel(new GlobalizedMessage( + "ui.admin.pagemodels.details.heading", + AdminUiConstants.ADMIN_BUNDLE, + new String[]{pageModel.getName()})); + }); + super.add(heading); + + final PropertySheet propertySheet = new PropertySheet( + new PageModelPropertySheetModelBuilder(selectedModelId)); + super.add(propertySheet); + + final ActionLink editProperties = new ActionLink(new GlobalizedMessage( + "ui.admin.pagemodels.details.edit_properties", + AdminUiConstants.ADMIN_BUNDLE)); + editProperties.addActionListener(event -> { + pageModelTab.showPageModelForm(event.getPageState()); + }); + super.add(editProperties); + + final ActionLink addComponent = new ActionLink(new GlobalizedMessage( + "ui.admin.pagemodels.details.add_component", + AdminUiConstants.ADMIN_BUNDLE)); + addComponent.addActionListener(event -> { + //pageModelTab.showNewComponentForm(state, componentModelClass); + }); + super.add(addComponent); + + final ComponentsTable componentsTable + = new ComponentsTable( + pageModelTab, selectedModelId, selectedComponentId); + super.add(componentsTable); + } + + private class AddComponentForm extends Form { + + private final SingleSelect selectType; + + public AddComponentForm() { + super("pagemodel_add_component_form"); + + selectType = new SingleSelect("select_component_type"); + try { + selectType.addPrintListener(event -> { + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ComponentModels componentModels = cdiUtil + .findBean(ComponentModels.class); + + + + }); + } catch (TooManyListenersException ex) { + throw new UnexpectedErrorException(ex); + } + + } + + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelForm.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelForm.java new file mode 100644 index 000000000..1cd36d3c8 --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelForm.java @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.ui.admin.pagemodels; + +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +import com.arsdigita.bebop.SaveCancelSection; +import com.arsdigita.bebop.Text; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.FormValidationListener; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.bebop.form.TextArea; +import com.arsdigita.bebop.form.TextField; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.kernel.KernelConfig; +import com.arsdigita.ui.admin.AdminUiConstants; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.configuration.ConfigurationManager; +import org.libreccm.core.UnexpectedErrorException; +import org.libreccm.pagemodel.PageModel; +import org.libreccm.pagemodel.PageModelManager; +import org.libreccm.pagemodel.PageModelRepository; +import org.libreccm.web.ApplicationRepository; +import org.libreccm.web.CcmApplication; + +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.TooManyListenersException; + +/** + * + * @author Jens Pelzetter + */ +class PageModelForm extends Form { + + private static final String MODEL_APPLICATION = "application"; + private static final String MODEL_NAME = "model_name"; + private static final String MODEL_TITLE = "model_title"; + private static final String MODEL_DESC = "model_desc"; + + private final PageModelTab pageModelTab; + private final ParameterSingleSelectionModel selectedModelId; + + private final TextField nameField; + private final TextField titleField; + private final TextArea descArea; + private final SingleSelect applicationSelect; + private final SaveCancelSection saveCancelSection; + + public PageModelForm( + final PageModelTab pageModelTab, + final ParameterSingleSelectionModel selectedModelId) { + + super("pagemodelsform"); + + this.pageModelTab = pageModelTab; + this.selectedModelId = selectedModelId; + + final Label heading = new Label(event -> { + + final PageState state = event.getPageState(); + final Label target = (Label) event.getTarget(); + + final String selectedModelIdStr = selectedModelId + .getSelectedKey(state); + if (selectedModelIdStr == null || selectedModelIdStr.isEmpty()) { + target.setLabel(new GlobalizedMessage( + "ui.admin.pagemodels.create_new", + AdminUiConstants.ADMIN_BUNDLE)); + } else { + target.setLabel(new GlobalizedMessage( + "ui.admin.pagemodels.edit", + AdminUiConstants.ADMIN_BUNDLE)); + } + }); + heading.setClassAttr("heading"); + super.add(heading); + + nameField = new TextField(MODEL_NAME); + nameField.setLabel(new GlobalizedMessage( + "ui.admin.pagemodels.name", + AdminUiConstants.ADMIN_BUNDLE)); + super.add(nameField); + + titleField = new TextField(MODEL_TITLE); + titleField.setLabel(new GlobalizedMessage( + "ui.admin.pagemodels.title", + AdminUiConstants.ADMIN_BUNDLE)); + super.add(titleField); + + descArea = new TextArea(MODEL_DESC); + descArea.setLabel(new GlobalizedMessage( + "ui.admin.pagemodels.desc", + AdminUiConstants.ADMIN_BUNDLE)); + super.add(descArea); + + applicationSelect = new SingleSelect(MODEL_APPLICATION); + applicationSelect.setLabel(new GlobalizedMessage( + "ui.admin.pagemodels.application", + AdminUiConstants.ADMIN_BUNDLE)); + super.add(applicationSelect); + try { + applicationSelect.addPrintListener(event -> { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ApplicationRepository applicationRepo = cdiUtil + .findBean(ApplicationRepository.class); + + final SingleSelect target = (SingleSelect) event.getTarget(); + target.clearOptions(); + + final List applications = applicationRepo + .findAll(); + applications.sort((app1, app2) -> { + return app1.getPrimaryUrl().compareTo(app2.getPrimaryUrl()); + }); + for (final CcmApplication app : applications) { + target.addOption(new Option(app.getPrimaryUrl(), + new Text(app.getPrimaryUrl()))); + } + }); + + } catch (TooManyListenersException ex) { + throw new UnexpectedErrorException(ex); + } + super.add(applicationSelect); + + saveCancelSection = new SaveCancelSection(); + super.add(saveCancelSection); + + super.addValidationListener(new ValidationListener()); + super.addInitListener(new InitListener()); + super.addProcessListener(new ProcessListener()); + } + + private class ValidationListener implements FormValidationListener { + + @Override + public void validate(final FormSectionEvent event) + throws FormProcessException { + + final PageState state = event.getPageState(); + + if (saveCancelSection.getSaveButton().isSelected(state)) { + + final FormData data = event.getFormData(); + final String nameValue = data.getString(MODEL_NAME); + final String titleValue = data.getString(MODEL_TITLE); + final String appValue = data.getString(MODEL_APPLICATION); + + final String selectedModelIdStr = selectedModelId + .getSelectedKey(state); + final boolean modelEditedOrNew; + + if (selectedModelIdStr == null || selectedModelIdStr.isEmpty()) { + modelEditedOrNew = true; + } else { + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ConfigurationManager confManager = cdiUtil + .findBean(ConfigurationManager.class); + final PageModelRepository pageModelRepo = cdiUtil + .findBean(PageModelRepository.class); + final PageModel pageModel = pageModelRepo + .findById(Long.parseLong(selectedModelIdStr)) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No PageModel with ID %s in the database.", + selectedModelIdStr))); + + final KernelConfig kernelConfig = confManager + .findConfiguration(KernelConfig.class); + + final boolean nameEdited = !pageModel + .getName() + .equals(nameValue); + final boolean titleEdited = !pageModel + .getTitle() + .getValue(kernelConfig.getDefaultLocale()) + .equals(titleValue); + final boolean appEdited = !pageModel + .getApplication() + .getPrimaryUrl() + .equals(appValue); + + modelEditedOrNew = nameEdited || titleEdited || appEdited; + } + + if (modelEditedOrNew) { + if (nameValue == null + || nameValue.isEmpty() + || nameValue.matches("\\s*")) { + + data.addError(MODEL_NAME, + new GlobalizedMessage( + "ui.admin.pagemodels.name.error.empty", + AdminUiConstants.ADMIN_BUNDLE)); + } + + if (titleValue == null + || titleValue.isEmpty() + || titleValue.matches("\\s*")) { + + data.addError(MODEL_TITLE, + new GlobalizedMessage( + "ui.admin.pagemodels.title.error.empty", + AdminUiConstants.ADMIN_BUNDLE)); + } + + if (appValue == null + || appValue.isEmpty() + || appValue.matches("\\s*")) { + + data.addError(MODEL_TITLE, + new GlobalizedMessage( + "ui.admin.pagemodels.application.error.empty", + AdminUiConstants.ADMIN_BUNDLE)); + } else { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ApplicationRepository appRepo = cdiUtil + .findBean(ApplicationRepository.class); + + final Optional application = appRepo + .retrieveApplicationForPath(appValue); + + if (!application.isPresent()) { + data.addError(MODEL_TITLE, + new GlobalizedMessage( + "ui.admin.pagemodels.application.error.invalid", + AdminUiConstants.ADMIN_BUNDLE)); + } + + } + } + + } + } + + } + + private class InitListener implements FormInitListener { + + @Override + public void init(final FormSectionEvent event) + throws FormProcessException { + + final PageState state = event.getPageState(); + + final String selectedModelIdStr = selectedModelId + .getSelectedKey(state); + + if (selectedModelIdStr != null && !selectedModelIdStr.isEmpty()) { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PageModelRepository pageModelRepo = cdiUtil + .findBean(PageModelRepository.class); + final ConfigurationManager confManager = cdiUtil + .findBean(ConfigurationManager.class); + final KernelConfig kernelConfig = confManager + .findConfiguration(KernelConfig.class); + final Locale defaultLocale = kernelConfig.getDefaultLocale(); + + final PageModel pageModel = pageModelRepo + .findById(Long.parseLong(selectedModelIdStr)) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No PageModel with ID %s in the database.", + selectedModelIdStr))); + + nameField.setValue(state, pageModel.getName()); + titleField.setValue(state, + pageModel.getTitle().getValue(defaultLocale)); + descArea + .setValue(state, + pageModel.getDescription().getValue(defaultLocale)); + applicationSelect + .setValue(state, + pageModel.getApplication().getPrimaryUrl()); + } + } + + } + + private class ProcessListener implements FormProcessListener { + + @Override + public void process(final FormSectionEvent event) + throws FormProcessException { + + final PageState state = event.getPageState(); + + if (saveCancelSection.getSaveButton().isSelected(state)) { + + final FormData data = event.getFormData(); + + final String nameValue = data.getString(MODEL_NAME); + final String titleValue = data.getString(MODEL_TITLE); + final String descValue = data.getString(MODEL_DESC); + final String appValue = data.getString(MODEL_APPLICATION); + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PageModelRepository pageModelRepo = cdiUtil + .findBean(PageModelRepository.class); + final ConfigurationManager confManager = cdiUtil + .findBean(ConfigurationManager.class); + final ApplicationRepository appRepo = cdiUtil + .findBean(ApplicationRepository.class); + final KernelConfig kernelConfig = confManager + .findConfiguration(KernelConfig.class); + final Locale defaultLocale = kernelConfig.getDefaultLocale(); + + final String selectedModelIdStr = selectedModelId + .getSelectedKey(state); + + final PageModel pageModel; + if (selectedModelIdStr == null || selectedModelIdStr.isEmpty()) { + pageModel = new PageModel(); + } else { + pageModel = pageModelRepo + .findById(Long.parseLong(selectedModelIdStr)) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No PageModel with ID %s in the database.", + selectedModelIdStr))); + } + + pageModel.setName(nameValue); + + pageModel.getTitle().addValue(defaultLocale, titleValue); + pageModel.getDescription().addValue(defaultLocale, descValue); + + final CcmApplication application = appRepo + .retrieveApplicationForPath(appValue) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No CcmApplication with primary URL \"%s\" in the " + + "database.", + appValue))); + + pageModel.setApplication(application); + + pageModelRepo.save(pageModel); + } + + pageModelTab.showPageModelDetails(state); + } + + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelPropertySheetModel.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelPropertySheetModel.java new file mode 100644 index 000000000..5e1da4f37 --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelPropertySheetModel.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.ui.admin.pagemodels; + +import com.arsdigita.bebop.PropertySheetModel; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.kernel.KernelConfig; +import com.arsdigita.ui.admin.AdminUiConstants; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.configuration.ConfigurationManager; +import org.libreccm.pagemodel.PageModel; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.Locale; + +/** + * + * @author Jens Pelzetter + */ +class PageModelPropertySheetModel implements PropertySheetModel { + + private static enum PageModelProperty { + MODEL_NAME, + MODEL_TITLE, + MODEL_APPLICATION, + MODEL_DESC + } + + private final PageModel pageModel; + private final Iterator propertyIterator; + private PageModelProperty currentProperty; + + public PageModelPropertySheetModel(final PageModel pageModel) { + + this.pageModel = pageModel; + propertyIterator = Arrays + .asList(PageModelProperty.values()) + .iterator(); + } + + @Override + public boolean nextRow() { + if (pageModel == null) { + return false; + } + + if (propertyIterator.hasNext()) { + currentProperty = propertyIterator.next(); + return true; + } else { + return false; + } + } + + @Override + public String getLabel() { + return currentProperty.toString(); + } + + @Override + public GlobalizedMessage getGlobalizedLabel() { + + final String key = String + .join("", + "ui.admin.pagemodels.details.", + currentProperty.toString().toLowerCase()); + return new GlobalizedMessage(key, AdminUiConstants.ADMIN_BUNDLE); + } + + @Override + public String getValue() { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ConfigurationManager confManager = cdiUtil + .findBean(ConfigurationManager.class); + final KernelConfig kernelConfig = confManager + .findConfiguration(KernelConfig.class); + final Locale defaultLocale = kernelConfig.getDefaultLocale(); + + switch (currentProperty) { + case MODEL_APPLICATION: + return pageModel.getApplication().getPrimaryUrl(); + case MODEL_DESC: + return pageModel.getDescription().getValue(defaultLocale); + case MODEL_NAME: + return pageModel.getName(); + case MODEL_TITLE: + return pageModel.getTitle().getValue(defaultLocale); + default: + return ""; + } + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelPropertySheetModelBuilder.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelPropertySheetModelBuilder.java new file mode 100644 index 000000000..6f6c48890 --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelPropertySheetModelBuilder.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.ui.admin.pagemodels; + +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +import com.arsdigita.bebop.PropertySheet; +import com.arsdigita.bebop.PropertySheetModel; +import com.arsdigita.util.LockableImpl; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.pagemodel.PageModel; +import org.libreccm.pagemodel.PageModelRepository; + +/** + * + * @author Jens Pelzetter + */ +class PageModelPropertySheetModelBuilder + extends LockableImpl + implements com.arsdigita.bebop.PropertySheetModelBuilder { + + private final ParameterSingleSelectionModel selectedModelId; + + public PageModelPropertySheetModelBuilder( + final ParameterSingleSelectionModel selectedModelId) { + + this.selectedModelId = selectedModelId; + } + + @Override + public PropertySheetModel makeModel(final PropertySheet sheet, + final PageState state) { + + final String selectedModelIdStr = selectedModelId.getSelectedKey( + state); + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PageModelRepository pageModelRepo = cdiUtil + .findBean(PageModelRepository.class); + final PageModel pageModel = pageModelRepo + .findById(Long.parseLong(selectedModelIdStr)) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No PageModel with ID %s in the database.", + selectedModelIdStr))); + + return new PageModelPropertySheetModel(pageModel); + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelTab.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelTab.java new file mode 100644 index 000000000..ae1a4d6bf --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelTab.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.ui.admin.pagemodels; + +import com.arsdigita.bebop.ActionLink; +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.MetaForm; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.toolbox.ui.LayoutPanel; +import com.arsdigita.ui.admin.AdminUiConstants; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.core.UnexpectedErrorException; +import org.libreccm.pagemodel.ComponentModel; + +import java.lang.reflect.InvocationTargetException; + +/** + * + * @author Jens Pelzetter + */ +public class PageModelTab extends LayoutPanel { + + private final ParameterSingleSelectionModel selectedModelId; + private final ParameterSingleSelectionModel selectedComponentId; + private final ActionLink addNewModel; + private final PageModelsTable pageModelsTable; + private final PageModelDetails pageModelDetails; + private final PageModelForm pageModelForm; + private final MetaForm componentForm; + + private Class componentModelClass; + + public PageModelTab() { + + super(); + + super.setClassAttr("sidebarNavPanel"); + + final BoxPanel left = new BoxPanel(BoxPanel.VERTICAL); + + selectedModelId = new ParameterSingleSelectionModel<>( + new StringParameter("selected_pagemodel_id")); + selectedComponentId = new ParameterSingleSelectionModel<>( + new StringParameter(("selected_pagemodel_component_id"))); + + pageModelsTable = new PageModelsTable(this, selectedModelId); + pageModelDetails = new PageModelDetails(this, + selectedModelId, + selectedComponentId); + pageModelForm = new PageModelForm(this, selectedModelId); + + addNewModel = new ActionLink(new GlobalizedMessage( + "ui.admin.pagemodels.add_new_pagemodel_link", + AdminUiConstants.ADMIN_BUNDLE)); + addNewModel.addActionListener(event -> { + showPageModelForm(event.getPageState()); + }); + + componentForm = new MetaForm("componentsForm") { + + @Override + public Form buildForm(final PageState state) { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PageModelsController controller = cdiUtil + .findBean(PageModelsController.class); + + try { + if (selectedComponentId.getSelectedKey(state) == null + || selectedComponentId.getSelectedKey(state) + .isEmpty()) { + + final Class formClass = controller + .getComponentModelForm(componentModelClass); + formClass + .getDeclaredConstructor() + .newInstance(); + } else { + + final Class formClass = controller + .getComponentModelForm(Long + .parseLong(selectedComponentId + .getSelectedKey(state))); + + return formClass + .getDeclaredConstructor( + ParameterSingleSelectionModel.class) + .newInstance(selectedComponentId); + } + } catch (InstantiationException + | InvocationTargetException + | IllegalAccessException + | NoSuchMethodException ex) { + throw new UnexpectedErrorException(ex); + } + + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + }; + + final BoxPanel right = new BoxPanel(BoxPanel.VERTICAL); + right.add(addNewModel); + right.add(pageModelsTable); + right.add(pageModelDetails); + right.add(pageModelForm); + right.add(componentForm); + + setLeft(left); + setRight(right); + } + + @Override + public void register(final Page page) { + + super.register(page); + + page.addGlobalStateParam(selectedModelId.getStateParameter()); + + page.setVisibleDefault(addNewModel, true); + page.setVisibleDefault(pageModelsTable, true); + page.setVisibleDefault(pageModelDetails, false); + page.setVisibleDefault(pageModelForm, false); + page.setVisibleDefault(componentForm, false); + } + + protected void showNewComponentForm( + final PageState state, + final Class componentModelClass) { + + this.componentModelClass = componentModelClass; + showComponentForm(state); + + } + + protected void showComponentForm(final PageState state) { + addNewModel.setVisible(state, false); + pageModelsTable.setVisible(state, false); + pageModelDetails.setVisible(state, true); + pageModelForm.setVisible(state, false); + componentForm.setVisible(state, false); + } + + protected void showPageModelDetails(final PageState state) { + addNewModel.setVisible(state, false); + pageModelsTable.setVisible(state, false); + pageModelDetails.setVisible(state, true); + pageModelForm.setVisible(state, false); + componentForm.setVisible(state, false); + } + + protected void showPageModelForm(final PageState state) { + addNewModel.setVisible(state, false); + pageModelsTable.setVisible(state, false); + pageModelDetails.setVisible(state, false); + pageModelForm.setVisible(state, true); + componentForm.setVisible(state, false); + } + + protected void showPageModelsTable(final PageState state) { + addNewModel.setVisible(state, true); + pageModelsTable.setVisible(state, true); + pageModelDetails.setVisible(state, false); + pageModelForm.setVisible(state, false); + componentForm.setVisible(state, false); + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelsController.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelsController.java new file mode 100644 index 000000000..f52a194b9 --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelsController.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.ui.admin.pagemodels; + +import com.arsdigita.bebop.Form; + +import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.pagemodel.ComponentModel; +import org.libreccm.pagemodel.ComponentModelRepository; +import org.libreccm.pagemodel.PageModel; +import org.libreccm.pagemodel.PageModelComponentModel; +import org.libreccm.pagemodel.PageModelManager; +import org.libreccm.pagemodel.PageModelRepository; +import org.libreccm.web.ApplicationRepository; +import org.libreccm.web.CcmApplication; + +import java.io.Serializable; +import java.util.List; +import java.util.stream.Collectors; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.transaction.Transactional; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +class PageModelsController implements Serializable { + + private static final long serialVersionUID = -5105462163244688201L; + + @Inject + private ApplicationRepository applicationRepo; + + @Inject + private ComponentModelRepository componentModelRepo; + + @Inject + private GlobalizationHelper globalizationHelper; + + @Inject + private PageModelManager pageModelManager; + + @Inject + private PageModelRepository pageModelRepo; + + @Transactional(Transactional.TxType.REQUIRED) + protected List findPageModels() { + + return pageModelRepo + .findAll() + .stream() + .map(this::buildRow) + .sorted() + .collect(Collectors.toList()); + } + + @Transactional(Transactional.TxType.REQUIRED) + protected boolean isUnique(final long applicationId, + final String name) { + + final CcmApplication application = applicationRepo + .findById(applicationId) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No CcmApplication with ID %d in the database.", + applicationId))); + + return !pageModelRepo + .findByApplicationAndName(application, name) + .isPresent(); + } + + @Transactional(Transactional.TxType.REQUIRED) + protected void deletePageModel(final long pageModelId) { + + final PageModel model = pageModelRepo + .findById(pageModelId) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No PageModel with ID %d in the database.", + pageModelId))); + + pageModelRepo.delete(model); + } + + private PageModelsTableRow buildRow(final PageModel model) { + + final PageModelsTableRow row = new PageModelsTableRow(); + + row.setModelId(model.getPageModelId()); + row.setName(model.getName()); + row.setTitle(globalizationHelper + .getValueFromLocalizedString(model.getTitle())); + row.setDescription(globalizationHelper + .getValueFromLocalizedString(model.getDescription())); + row.setApplicationName(model.getApplication().getPrimaryUrl()); + row.setLive(pageModelManager.isLive(model)); + + return row; + } + + protected Class getComponentModelForm( + final long componentModelId) { + + final ComponentModel componentModel = componentModelRepo + .findById(componentModelId) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No ComponentModel with ID %d in the database.", + componentModelId))); + + final Class clazz = componentModel + .getClass(); + + return getComponentModelForm(clazz); + } + + protected Class getComponentModelForm( + final Class clazz) { + + if (clazz.isAnnotationPresent(PageModelComponentModel.class)) { + + final PageModelComponentModel annotation = clazz + .getAnnotation(PageModelComponentModel.class); + + return annotation.editor(); + } else { + return null; + } + } + + @Transactional(Transactional.TxType.REQUIRED) + protected List retrieveComponents(final long pageModelId) { + + final PageModel model = pageModelRepo + .findById(pageModelId) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No PageModel with ID %d in the database.", + pageModelId))); + + return model.getComponents(); + } + + @Transactional(Transactional.TxType.REQUIRED) + protected void removeComponentModel(final long pageModelId, + final long componentModelId) { + + final PageModel model = pageModelRepo + .findById(pageModelId) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No PageModel with ID %d in the database.", + pageModelId))); + + final ComponentModel componentModel = componentModelRepo + .findById(componentModelId) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No ComponentModel with ID %d in the database.", + componentModelId))); + + pageModelManager.removeComponentModel(model, componentModel); + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelsTable.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelsTable.java new file mode 100644 index 000000000..b035f2410 --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelsTable.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.ui.admin.pagemodels; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.ControlLink; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +import com.arsdigita.bebop.Table; +import com.arsdigita.bebop.Text; +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.globalization.GlobalizedMessage; +import com.arsdigita.ui.admin.AdminUiConstants; +import com.arsdigita.util.LockableImpl; + +import org.libreccm.cdi.utils.CdiUtil; + +import java.util.Iterator; +import java.util.List; + +/** + * + * @author Jens Pelzetter + */ +class PageModelsTable extends Table { + + public static final int COL_MODEL_APPLICATION = 0; + public static final int COL_MODEL_NAME = 1; + public static final int COL_MODEL_TITLE = 2; + public static final int COL_MODEL_DESC = 3; + public static final int COL_REMOVE = 4; + + public PageModelsTable( + final PageModelTab parent, + final ParameterSingleSelectionModel selectedPageModelId) { + + super(); + + super.setIdAttr("pageModelsTable"); + super.setStyleAttr("wdith: 30em"); + + setEmptyView(new Label( + new GlobalizedMessage("ui.admin.pagemodels.table.empty_view", + AdminUiConstants.ADMIN_BUNDLE))); + + final TableColumnModel columnModel = getColumnModel(); + columnModel.add(new TableColumn( + COL_MODEL_APPLICATION, + new Label(new GlobalizedMessage( + "ui.admin.pagemodels.table.columns.headers.application", + AdminUiConstants.ADMIN_BUNDLE)) + )); + columnModel.add(new TableColumn( + COL_MODEL_NAME, + new Label(new GlobalizedMessage( + "ui.admin.pagemodels.table.columns.headers.name", + AdminUiConstants.ADMIN_BUNDLE)) + )); + columnModel.add(new TableColumn( + COL_MODEL_TITLE, + new Label(new GlobalizedMessage( + "ui.admin.pagemodels.table.columns.headers.title", + AdminUiConstants.ADMIN_BUNDLE)) + )); + columnModel.add(new TableColumn( + COL_MODEL_DESC, + new Label(new GlobalizedMessage( + "ui.admin.pagemodels.table.columns.headers.desc", + AdminUiConstants.ADMIN_BUNDLE)) + )); + columnModel.add(new TableColumn( + COL_REMOVE, + new Label(new GlobalizedMessage( + "ui.admin.pagemodels.table.columns.headers.remove", + AdminUiConstants.ADMIN_BUNDLE)) + )); + + columnModel + .get(COL_MODEL_NAME) + .setCellRenderer(new TableCellRenderer() { + + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + + return new ControlLink((String) value); + } + + }); + + columnModel + .get(COL_REMOVE) + .setCellRenderer(new TableCellRenderer() { + + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + + if (value == null) { + return new Text(""); + } else { + final ControlLink link = new ControlLink( + (Component) value); + link.setConfirmation(new GlobalizedMessage( + "ui.admin.pagemodels.delete.confirm", + AdminUiConstants.ADMIN_BUNDLE)); + return link; + } + } + + }); + + super.addTableActionListener(new TableActionListener() { + + @Override + public void cellSelected(final TableActionEvent event) + throws FormProcessException { + + final PageState state = event.getPageState(); + final String key = (String) event.getRowKey(); + + switch (event.getColumn()) { + case COL_MODEL_NAME: + selectedPageModelId.setSelectedKey(state, key); + parent.showPageModelDetails(state); + break; + case COL_REMOVE: + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PageModelsController controller = cdiUtil + .findBean(PageModelsController.class); + controller.deletePageModel(Long.parseLong(key)); + break; + default: + throw new IllegalArgumentException( + "Invalid value for column."); + } + + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void headSelected(final TableActionEvent event) { + + // Nothing + } + + }); + + super.setModelBuilder(new PageModelsTableModelBuilder()); + } + + private class PageModelsTableModelBuilder + extends LockableImpl + implements TableModelBuilder { + + @Override + public TableModel makeModel(final Table table, + final PageState state) { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PageModelsController controller = cdiUtil + .findBean(PageModelsController.class); + return new PageModelsTableModel(controller.findPageModels()); + } + + } + + private class PageModelsTableModel implements TableModel { + + private final Iterator iterator; + private PageModelsTableRow currentRow; + + public PageModelsTableModel(final List rows) { + iterator = rows.iterator(); + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public boolean nextRow() { + + if (iterator.hasNext()) { + currentRow = iterator.next(); + return true; + } else { + return false; + } + } + + @Override + public Object getElementAt(final int columnIndex) { + + switch (columnIndex) { + case COL_MODEL_APPLICATION: + return currentRow.getApplicationName(); + case COL_MODEL_DESC: + return currentRow.getDescription(); + case COL_MODEL_NAME: + return currentRow.getName(); + case COL_MODEL_TITLE: + return currentRow.getTitle(); + case COL_REMOVE: + return new Label(new GlobalizedMessage( + "ui.admin.pagemodels.table.columns.remove.label", + AdminUiConstants.ADMIN_BUNDLE)); + default: + throw new IllegalArgumentException("No a valid column index"); + } + } + + @Override + public Object getKeyAt(final int columnIndex) { + + return currentRow.getModelId(); + } + + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelsTableRow.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelsTableRow.java new file mode 100644 index 000000000..cb66163bb --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/pagemodels/PageModelsTableRow.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.ui.admin.pagemodels; + +import java.io.Serializable; + +/** + * + * @author Jens Pelzetter + */ +class PageModelsTableRow implements Comparable, + Serializable { + + private static final long serialVersionUID = 7497498047332094014L; + + private long modelId; + + private String name; + + private boolean live; + + private String title; + + private String description; + + private String applicationName; + + public long getModelId() { + return modelId; + } + + public void setModelId(final long modelId) { + this.modelId = modelId; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public boolean isLive() { + return live; + } + + public void setLive(final boolean live) { + this.live = live; + } + + public String getTitle() { + return title; + } + + public void setTitle(final String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public String getApplicationName() { + return applicationName; + } + + public void setApplicationName(final String applicationName) { + this.applicationName = applicationName; + } + + @Override + public int compareTo(final PageModelsTableRow other) { + + int result; + + result = applicationName.compareTo(other.getApplicationName()); + if (result != 0) { + return result; + } + + result = name.compareTo(other.getName()); + if (result != 0) { + return result; + } + + return title.compareTo(other.getTitle()); + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/sites/SitesForm.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/sites/SitesForm.java index 3e53aad4a..30c539761 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/sites/SitesForm.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/sites/SitesForm.java @@ -52,7 +52,7 @@ import static com.arsdigita.ui.admin.AdminUiConstants.*; * * @author Jens Pelzetter */ -public class SitesForm extends Form { +class SitesForm extends Form { private static final String DOMAIN_OF_SITE = "domainOfSite"; private static final String DEFAULT_SITE = "defaultSite"; diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/sites/SitesTable.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/sites/SitesTable.java index d2777e578..419ee4bdb 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/sites/SitesTable.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/sites/SitesTable.java @@ -47,7 +47,7 @@ import static com.arsdigita.ui.admin.AdminUiConstants.*; * * @author Jens Pelzetter */ -public class SitesTable extends Table { +class SitesTable extends Table { public static final int COL_SITE_DOMAIN = 0; public static final int COL_IS_DEFAULT_SITE = 1; diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/usersgroupsroles/roles/RoleDetails.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/usersgroupsroles/roles/RoleDetails.java index 2953661fb..4f5f723e4 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/usersgroupsroles/roles/RoleDetails.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/usersgroupsroles/roles/RoleDetails.java @@ -48,56 +48,58 @@ class RoleDetails extends BoxPanel { final ActionLink backLink = new ActionLink(new GlobalizedMessage( "ui.admin.role_details.back", ADMIN_BUNDLE)); backLink.setClassAttr("back-link"); - backLink.addActionListener(e -> { - roleAdmin.hideRoleDetails(e.getPageState()); + backLink.addActionListener(event -> { + roleAdmin.hideRoleDetails(event.getPageState()); }); - add(backLink); + super.add(backLink); final Label heading = new Label(); heading.setClassAttr("heading"); - heading.addPrintListener(e -> { - final PageState state = e.getPageState(); - final Label target = (Label) e.getTarget(); - final RoleRepository roleRepository = CdiUtil.createCdiUtil() + heading.addPrintListener(event -> { + final PageState state = event.getPageState(); + final Label target = (Label) event.getTarget(); + final RoleRepository roleRepository = CdiUtil + .createCdiUtil() .findBean(RoleRepository.class); - final Role role = roleRepository.findById(Long.parseLong( - selectedRoleId.getSelectedKey(state))).get(); + final Role role = roleRepository + .findById(Long.parseLong(selectedRoleId.getSelectedKey(state))) + .get(); target.setLabel(new GlobalizedMessage( "ui.admin.role_details.heading", ADMIN_BUNDLE, new String[]{role.getName()})); }); - add(heading); + super.add(heading); final PropertySheet propertySheet = new PropertySheet( new RolePropertySheetModelBuilder(selectedRoleId)); - add(propertySheet); + super.add(propertySheet); final BoxPanel links = new BoxPanel(BoxPanel.HORIZONTAL); final ActionLink editProperties = new ActionLink(new GlobalizedMessage( "ui.admin.role_details.edit_properties", ADMIN_BUNDLE)); - editProperties.addActionListener(e -> { - roleAdmin.showRoleForm(e.getPageState()); + editProperties.addActionListener(event -> { + roleAdmin.showRoleForm(event.getPageState()); }); links.add(editProperties); final ActionLink manageMembers = new ActionLink(new GlobalizedMessage( "ui.admin.role_details.manage_members", ADMIN_BUNDLE)); - manageMembers.addActionListener(e -> { - roleAdmin.showRoleMembersPanel(e.getPageState()); + manageMembers.addActionListener(event -> { + roleAdmin.showRoleMembersPanel(event.getPageState()); }); links.add(manageMembers); final ActionLink managePermissions = new ActionLink(new GlobalizedMessage( "ui.admin.role_details.manage_permissions", ADMIN_BUNDLE)); - managePermissions.addActionListener(e -> { - roleAdmin.showRolePermissionsPanel(e.getPageState()); + managePermissions.addActionListener(event -> { + roleAdmin.showRolePermissionsPanel(event.getPageState()); }); links.add(managePermissions); - add(links); + super.add(links); } } diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentModels.java b/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentModels.java new file mode 100644 index 000000000..193004aa8 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/ComponentModels.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.pagemodel; + +import org.libreccm.modules.CcmModule; +import org.libreccm.modules.Module; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.ServiceLoader; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; + +/** + * + * @author Jens Pelzetter + */ +@ApplicationScoped +public class ComponentModels { + + private final List availableComponentModels = new ArrayList<>(); + + @PostConstruct + private void init() { + + final ServiceLoader modules = ServiceLoader + .load(CcmModule.class); + + for (final CcmModule module : modules) { + + final Module moduleData = module + .getClass() + .getAnnotation(Module.class); + + final PageModelComponentModel[] componentModels = moduleData + .pageModelComponentModels(); + + for(final PageModelComponentModel componentModel : componentModels) { + availableComponentModels.add(componentModel); + } + } + } + + public List findAvailableComponentModels() { + return Collections.unmodifiableList(availableComponentModels); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/PageModel.java b/ccm-core/src/main/java/org/libreccm/pagemodel/PageModel.java index 0068b6485..38cea1aeb 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/PageModel.java +++ b/ccm-core/src/main/java/org/libreccm/pagemodel/PageModel.java @@ -270,7 +270,7 @@ public class PageModel implements Serializable { return application; } - protected void setApplication(final CcmApplication application) { + public void setApplication(final CcmApplication application) { this.application = application; } diff --git a/ccm-core/src/main/java/org/libreccm/theming/xslt/CcmUriResolver.java b/ccm-core/src/main/java/org/libreccm/theming/xslt/CcmUriResolver.java new file mode 100644 index 000000000..23b388c65 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/theming/xslt/CcmUriResolver.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.theming.xslt; + +import org.libreccm.theming.ThemeProvider; +import org.libreccm.theming.ThemeVersion; + +import java.io.InputStream; +import java.util.Objects; +import java.util.Optional; + +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.stream.StreamSource; + +/** + * + * @author Jens Pelzetter + */ +class CcmUriResolver implements URIResolver { + + private final String theme; + private final ThemeVersion version; + private final ThemeProvider themeProvider; + + protected CcmUriResolver(final String theme, + final ThemeVersion version, + final ThemeProvider themeProvider) { + + Objects.requireNonNull(theme); + Objects.requireNonNull(version); + Objects.requireNonNull(themeProvider); + + this.theme = theme; + this.version = version; + this.themeProvider = themeProvider; + } + + @Override + public Source resolve(final String href, + final String base) throws TransformerException { + + final String path; + if (base == null) { + path = href; + } else { + path = String.join("/", href, base); + } + + final InputStream inputStream = themeProvider + .getThemeFileAsStream(theme, version, path) + .orElseThrow(() -> new TransformerException(String + .format("Failed to resolve URI with href = \"%s\" and base = \"%s\" " + + "for theme \"%s\" (version = \"%s\" using " + + "ThemeProvider \"%s\".", + href, + base, + theme, + version, + themeProvider.getClass().getName()))); + + return new StreamSource(inputStream); + } + +} + diff --git a/ccm-core/src/main/java/org/libreccm/theming/xslt/XsltThemeProcessor.java b/ccm-core/src/main/java/org/libreccm/theming/xslt/XsltThemeProcessor.java index 3a7f4d71d..b6d6a81c7 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/xslt/XsltThemeProcessor.java +++ b/ccm-core/src/main/java/org/libreccm/theming/xslt/XsltThemeProcessor.java @@ -39,6 +39,7 @@ import javax.xml.parsers.ParserConfigurationException; import static org.libreccm.theming.ThemeConstants.*; +import org.libreccm.theming.ThemeVersion; import org.libreccm.theming.manifest.ThemeTemplate; import java.io.InputStream; @@ -49,6 +50,7 @@ import java.io.UnsupportedEncodingException; import java.util.Optional; import javax.xml.transform.Result; +import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; @@ -59,7 +61,7 @@ import javax.xml.transform.stream.StreamSource; /** * A {@link ThemeProcessor} implementation for XSLT based themes. - * + * * @author Jens Pelzetter */ @RequestScoped @@ -147,10 +149,13 @@ public class XsltThemeProcessor implements ThemeProcessor { final Transformer transformer; try { transformer = transformerFactory.newTransformer(xslFileStreamSource); + transformer.setURIResolver(new CcmUriResolver(theme.getName(), + theme.getVersion(), + themeProvider)); } catch (TransformerConfigurationException ex) { throw new UnexpectedErrorException(ex); } - + final StringWriter resultWriter = new StringWriter(); final Result result = new StreamResult(resultWriter); try { @@ -158,7 +163,7 @@ public class XsltThemeProcessor implements ThemeProcessor { } catch (TransformerException ex) { throw new UnexpectedErrorException(ex); } - + return resultWriter.toString(); } diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties index e5cbca0eb..6d9151634 100644 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties @@ -641,3 +641,17 @@ ui.admin.sites.created_new_site=Create new site "{0}" ui.admin.sites.saved_changes=Saved changes to site "{0}" ui.admin.sites.site_deleted=Site "{0}" deleted ui.admin.sites.site_delete.confirm=Are you sure to delete Site "{0}"? +ui.admin.pagemodels.name.error.empty=The name of a Page Model can't be empty. +ui.admin.pagemodels.title.error.empty=The title of a PageModel can't be empty. +ui.admin.pagemodels.application.error.empty=A PageModel must be assigned to an application +ui.admin.pagemodels.application.error.invalid=PageModel is not assigned to valid application. +ui.admin.pagemodels.details.back=Back to list of page models. +ui.admin.pagemodels.details.heading=Details of PageModel {0} +ui.admin.pagemodels.componentmodels.none=No components have been added to this PageModel. +ui.admin.pagemodels.componentmodels.cols.key.heading=Key +ui.admin.pagemodels.componentmodels.cols.type.heading=Type +ui.admin.pagemodels.componentmodels.cols.edit.heading=Edit +ui.admin.pagemodels.componentmodels.cols.delete.heading=Delete +ui.admin.pagemodels.components.edit=Edit +ui.admin.pagemodels.components.delete=Delete +ui.admin.pagemodels.details.add_component=Add Component diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties index 19518014f..1ed53072f 100644 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties @@ -645,3 +645,17 @@ ui.admin.sites.created_new_site=Neue Site "{0}" angelegt ui.admin.sites.saved_changes=\u00c4nderungen an Seite "{0}" gespeichert ui.admin.sites.site_deleted=Site "{0}" gel\u00f6scht ui.admin.sites.site_delete.confirm=Sind Sie sicher, dass Sie die Site "{0}" l\u00f6schen wollen? +ui.admin.pagemodels.name.error.empty=Der Name eines PageModels darf nicht leer sein. +ui.admin.pagemodels.title.error.empty=Der Titel eines PageModels darf nicht leer sein. +ui.admin.pagemodels.application.error.empty=Ein PageModel muss einer Applikation zugeordnet werden. +ui.admin.pagemodels.application.error.invalid=Das PageModel ist nicht einer g\u00fcltigen Anwendung zugeordnet. +ui.admin.pagemodels.details.back=Zur\u00fcck zur Liste der PageModels +ui.admin.pagemodels.details.heading=Details PageModel {0} +ui.admin.pagemodels.componentmodels.none=Diesem PageModel wurden noch keine Komponenten hinzugef\u00fcgt. +ui.admin.pagemodels.componentmodels.cols.key.heading=Key +ui.admin.pagemodels.componentmodels.cols.type.heading=Typ +ui.admin.pagemodels.componentmodels.cols.edit.heading=Bearbeiten +ui.admin.pagemodels.componentmodels.cols.delete.heading=Delete +ui.admin.pagemodels.components.edit=Bearbeiten +ui.admin.pagemodels.components.delete=L\u00f6schen +ui.admin.pagemodels.details.add_component=Komponente hinzuf\u00fcgen diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties index ead9a7111..1995b1cf8 100755 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties @@ -638,3 +638,17 @@ ui.admin.sites.created_new_site=Create new site "{0}" ui.admin.sites.saved_changes=Saved changes to site "{0}" ui.admin.sites.site_deleted=Site "{0}" deleted ui.admin.sites.site_delete.confirm=Are you sure to delete Site "{0}"? +ui.admin.pagemodels.name.error.empty=The name of a Page Model can't be empty. +ui.admin.pagemodels.title.error.empty=The title of a PageModel can't be empty. +ui.admin.pagemodels.application.error.empty=A PageModel must be assigned to an application +ui.admin.pagemodels.application.error.invalid=PageModel is not assigned to valid application. +ui.admin.pagemodels.details.back=Back to list of page models. +ui.admin.pagemodels.details.heading=Details of PageModel {0} +ui.admin.pagemodels.componentmodels.none=No components have been added to this PageModel. +ui.admin.pagemodels.componentmodels.cols.key.heading=Key +ui.admin.pagemodels.componentmodels.cols.type.heading=Type +ui.admin.pagemodels.componentmodels.cols.edit.heading=Edit +ui.admin.pagemodels.componentmodels.cols.delete.heading=Delete +ui.admin.pagemodels.components.edit=Edit +ui.admin.pagemodels.components.delete=Delete +ui.admin.pagemodels.details.add_component=Add Component diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties index a1aa11ce1..27aa0a203 100755 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties @@ -629,3 +629,17 @@ ui.admin.sites.created_new_site=Create new site "{0}" ui.admin.sites.saved_changes=Saved changes to site "{0}" ui.admin.sites.site_deleted=Site "{0}" deleted ui.admin.sites.site_delete.confirm=Are you sure to delete Site "{0}"? +ui.admin.pagemodels.name.error.empty=The name of a Page Model can't be empty. +ui.admin.pagemodels.title.error.empty=The title of a PageModel can't be empty. +ui.admin.pagemodels.application.error.empty=A PageModel must be assigned to an application +ui.admin.pagemodels.application.error.invalid=PageModel is not assigned to valid application. +ui.admin.pagemodels.details.back=Back to list of page models. +ui.admin.pagemodels.details.heading=Details of PageModel {0} +ui.admin.pagemodels.componentmodels.none=No components have been added to this PageModel. +ui.admin.pagemodels.componentmodels.cols.key.heading=Key +ui.admin.pagemodels.componentmodels.cols.type.heading=Type +ui.admin.pagemodels.componentmodels.cols.edit.heading=Edit +ui.admin.pagemodels.componentmodels.cols.delete.heading=Delete +ui.admin.pagemodels.components.edit=Edit +ui.admin.pagemodels.components.delete=Delete +ui.admin.pagemodels.details.add_component=Add Component