diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/ApplyWorkflowFormSection.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/ApplyWorkflowFormSection.java
new file mode 100755
index 000000000..456382509
--- /dev/null
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/ApplyWorkflowFormSection.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. 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.authoring;
+
+import com.arsdigita.bebop.ColumnPanel;
+import com.arsdigita.bebop.Container;
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.FormSection;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.event.FormInitListener;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.ParameterEvent;
+import com.arsdigita.bebop.form.RadioGroup;
+import com.arsdigita.bebop.parameters.LongParameter;
+import com.arsdigita.bebop.parameters.NotNullValidationListener;
+
+import org.librecms.contentsection.ContentItem;
+import org.librecms.contentsection.ContentSection;
+import org.librecms.contentsection.ContentType;
+import org.librecms.contentsection.Folder;
+
+import com.arsdigita.cms.ui.workflow.WorkflowsOptionPrintListener;
+import com.arsdigita.globalization.GlobalizedMessage;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.libreccm.security.PermissionChecker;
+import org.libreccm.workflow.AssignableTask;
+import org.libreccm.workflow.AssignableTaskManager;
+import org.libreccm.workflow.Workflow;
+import org.libreccm.workflow.WorkflowManager;
+import org.libreccm.workflow.WorkflowTemplate;
+import org.libreccm.workflow.WorkflowTemplateRepository;
+import org.librecms.CmsConstants;
+import org.librecms.contentsection.privileges.ItemPrivileges;
+
+import java.util.List;
+import java.util.TooManyListenersException;
+
+/**
+ * A FormSection which will allow users with
+ * SecrityConstants.APPLY_ALTERNATE_WORFLOWS permission to choose a different
+ * workflow to apply to a new item.
+ *
+ * @author Stanislav Freidin (stas@arsdigita.com)
+ * @author Jens Pelzetter
+ */
+public class ApplyWorkflowFormSection
+ extends FormSection
+ implements FormInitListener {
+
+ private static final Logger LOGGER = LogManager
+ .getLogger(ApplyWorkflowFormSection.class);
+
+ private RadioGroup radioGroup;
+ private CreationSelector creationSelector;
+ private ContentType contentType;
+ private ApplyWorkflowPrintListener printListener;
+
+ /**
+ * Construct a new ApplyWorkflowFormSection
+ */
+ public ApplyWorkflowFormSection() {
+ this(null);
+ }
+
+ /**
+ * Construct a new ApplyWorkflowFormSection
+ *
+ * @param type
+ */
+ public ApplyWorkflowFormSection(final ContentType type) {
+ this(type, new ColumnPanel(2, true));
+ }
+
+ /**
+ * Construct a new ApplyWorkflowFormSection
+ *
+ * @param type
+ * @param panel Container to use for this FormSection
+ */
+ public ApplyWorkflowFormSection(final ContentType type,
+ final Container panel) {
+ super(panel);
+
+ radioGroup = new RadioGroup(new LongParameter("workflowSelect"));
+ radioGroup.setClassAttr("vertical");
+ contentType = type;
+ printListener = new ApplyWorkflowPrintListener();
+
+ try {
+ // should we filter on WorkflowDefinitions where this user
+ // is assigned to at least one initial task, or should we
+ // assume that users with "alternate workflow" permission
+ // are advanced enough to know what they're doing?
+ radioGroup.addPrintListener(printListener);
+ } catch (TooManyListenersException ex) {
+ LOGGER.error("Too many listeners", ex);
+ }
+
+ add(new Label(new GlobalizedMessage("cms.ui.authoring.workflow",
+ CmsConstants.CMS_BUNDLE)));
+ radioGroup.addValidationListener(new NotNullValidationListener() {
+
+ @Override
+ public void validate(final ParameterEvent event) {
+ final PageState state = event.getPageState();
+ if (!ApplyWorkflowFormSection.this.isVisible(state)) {
+ return;
+ }
+ super.validate(event);
+ }
+
+ });
+ add(radioGroup);
+ addInitListener(this);
+ }
+
+ /**
+ * Initialises the workflow selection widget to the default workflow for the
+ * content type.
+ *
+ * @param event
+ *
+ * @throws com.arsdigita.bebop.FormProcessException
+ */
+ @Override
+ public void init(final FormSectionEvent event) throws FormProcessException {
+
+ final PageState state = event.getPageState();
+ final ContentSection section = creationSelector.getContentSection(
+ state);
+ final WorkflowTemplate template = contentType.getDefaultWorkflow();
+ if (template != null) {
+ radioGroup.setValue(state, template.getWorkflowId());
+ }
+ }
+
+ /**
+ * Sets the CreationSelector which should be the same as that of the
+ * creation component. This cannot be set in the constructor since for most
+ * creation components, addWidgets() is called via the superclass
+ * constructor, so this member will not yet be set.
+ *
+ * @param creationSelector CreationSelector to use for this FormSection
+ */
+ public void setCreationSelector(final CreationSelector creationSelector) {
+ this.creationSelector = creationSelector;
+ }
+
+ /**
+ * Sets the ContentType for the creation component.
+ *
+ * @param contentType ContentType to use for this FormSection
+ */
+ public void setContentType(final ContentType contentType) {
+ this.contentType = contentType;
+ }
+
+ /**
+ * Whether or not this component is visible. The additional visibility
+ * requirement is that the user must have the
+ * SecurityConstants.APPLY_ALTERNATE_WORKFLOWS privilege on the parent
+ * folder.
+ *
+ * @param state The PageState
+ *
+ * @return
+ */
+ @Override
+ public boolean isVisible(final PageState state) {
+ boolean result = false;
+
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final PermissionChecker permissionChecker = cdiUtil
+ .findBean(PermissionChecker.class);
+ ;
+
+ if (super.isVisible(state)
+ && permissionChecker
+ .isPermitted(ItemPrivileges.APPLY_ALTERNATE_WORKFLOW,
+ creationSelector.getFolder(state))) {
+
+ return !printListener.getCollection(state).isEmpty();
+ }
+ return result;
+ }
+
+ /**
+ * Apply the proper initial workflow to the item. If the user has
+ * SecurityConstants.APPLY_ALTERNATE_WORKFLOWS permission on the parent
+ * folder and a workflow has been chosen, use this workflow.
+ * Otherwise use the default workflow for the content type.
+ *
+ * @param state The PageState
+ * @param item The new ContentItem
+ */
+ public void applyWorkflow(final PageState state, final ContentItem item) {
+
+ final Long flowId = (Long) radioGroup.getValue(state);
+ final ContentSection section = creationSelector.getContentSection(
+ state);
+ final Folder folder = creationSelector.getFolder(state);
+ final WorkflowTemplate template;
+
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final PermissionChecker permissionChecker = cdiUtil
+ .findBean(PermissionChecker.class);
+ final WorkflowTemplateRepository templateRepo = cdiUtil
+ .findBean(WorkflowTemplateRepository.class);
+
+ if (flowId != null
+ && permissionChecker.isPermitted(
+ ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, folder)) {
+ template = templateRepo
+ .findById(flowId)
+ .orElseThrow(() -> new IllegalArgumentException(String.format(
+ "No WorkflowTemplate with ID %d in database. "
+ + "Where did that ID come from?")));
+ } else {
+ template = item.getContentType().getDefaultWorkflow();
+ }
+
+ if (template != null) {
+
+ final WorkflowManager workflowManager = cdiUtil
+ .findBean(WorkflowManager.class);
+
+ final Workflow workflow = workflowManager.createWorkflow(template,
+ item);
+ workflowManager.start(workflow);
+
+ if (!workflow.getTasks().isEmpty()) {
+
+ if (workflow.getTasks().get(0) instanceof AssignableTask) {
+
+ final AssignableTaskManager taskManager = cdiUtil
+ .findBean(AssignableTaskManager.class);
+ final AssignableTask task = (AssignableTask) workflow
+ .getTasks()
+ .get(0);
+ taskManager.lockTask(task);
+ }
+ }
+ }
+
+ }
+
+ private class ApplyWorkflowPrintListener
+ extends WorkflowsOptionPrintListener {
+
+ @Override
+ protected ContentSection getContentSection(final PageState state) {
+ return creationSelector.getContentSection(state);
+ }
+
+ @Override
+ protected List getCollection(final PageState state) {
+ return super.getCollection(state);
+ }
+
+ }
+
+}
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicItemForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicItemForm.java
index f04ba2bb8..93eec9f44 100755
--- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicItemForm.java
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicItemForm.java
@@ -20,6 +20,7 @@ package com.arsdigita.cms.ui.authoring;
import com.arsdigita.bebop.ColumnPanel;
import com.arsdigita.bebop.Component;
+import com.arsdigita.bebop.FormData;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.FormSection;
import com.arsdigita.bebop.Label;
@@ -39,7 +40,12 @@ import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.web.Web;
import com.arsdigita.xml.Element;
+import org.libreccm.categorization.Category;
+import org.libreccm.categorization.CategoryRepository;
+import org.libreccm.cdi.utils.CdiUtil;
import org.librecms.CmsConstants;
+import org.librecms.contentsection.ContentItem;
+import org.librecms.contentsection.ContentItemRepository;
/**
* A form for editing subclasses of ContentItem. This is just a convenience
@@ -222,7 +228,7 @@ public abstract class BasicItemForm extends FormSection
}
/**
- * Perform form initialization. Children should override this this method to
+ * Perform form initialisation. Children should override this this method to
* pre-fill the widgets with data, instantiate the content item, etc.
*
* @param e
@@ -343,140 +349,64 @@ public abstract class BasicItemForm extends FormSection
* @param event the {@link FormSectionEvent} which was passed to the
* validation listener
*/
-// public void validateNameUniqueness(Category parent, FormSectionEvent event) {
-//
-// FormData data = event.getFormData();
-// String newName = (String) data.get(NAME);
-//
-// validateNameUniqueness(parent, event, newName);
-// }
+ public void validateNameUniqueness(final Category parent,
+ final FormSectionEvent event) {
+
+ final FormData data = event.getFormData();
+ final String newName = (String) data.get(NAME);
+
+ validateNameUniqueness(parent, event, newName);
+ }
+
/**
*
* @param parent
* @param event
* @param newName
*/
-// public void validateNameUniqueness(Category parent,
-// FormSectionEvent event,
-// String newName) {
-//
-// final String ERR_MSG = "cms.ui.authoring.an_item_with_this_name_exists";
-//
-// if (newName != null) {
-// final String query = "com.arsdigita.cms.validateUniqueItemName";
-// DataQuery dq = SessionManager.getSession().retrieveQuery(query);
-// dq.setParameter("parentId", parent.getID());
-// dq.setParameter("name", newName.toUpperCase());
-// FormData data = event.getFormData();
-// ParameterData name = data.getParameter(NAME);
-//
-// if (dq.size() > 0) {
-// // Try to get a currently selected content item
-// ContentItem item = null;
-// if (getItemSelectionModel() != null) {
-// item = (ContentItem) getItemSelectionModel()
-// .getSelectedObject(event.getPageState());
-// }
-// if (item == null) { // The content item being null
-// // means it is a creation form.
-// // Therefore finding any item of the same name is a fault.
-// data.addError(globalize(ERR_MSG));
-// return;
-// } else {
-// // means we are in a edit form.
-// // We need to add all of the items that are different
-// // versions of this item to the list so that we do not mark
-// // an error if those are the only problems.
-// BigDecimal itemID = null;
-// Collection list = getAllVersionIDs(item);
-// while (dq.next()) {
-// itemID = (BigDecimal) dq.get("itemID");
-// if (!list.contains(itemID)) {
-// String[] itemObj = new String[1];
-// itemObj[0] = itemID.toString();
-// dq.close();
-// data.addError(globalize(ERR_MSG, itemObj));
-// return;
-// }
-// }
-// }
-// }
-// }
-// }
- /**
- * NOT USED ANYMORE.
- *
- * Ensure that the name of an item is unique within a category. This should
- * only be called from the validation listener of an "edit" form.
- *
- * @param event the {@link FormSectionEvent} which was passed to the
- * validation listener
- * @param id The id of the item that is being checked. This must no be
- * null.
- *
- * @return
- *
- * @throws FormProcessException if the folder already contains an item with
- * the name the user provided on the input
- * form. / public void
- * validateNameUniquenessWithinCategory(FormSectionEvent
- * event, BigDecimal id) throws
- * FormProcessException { if (id == null) {
- * s_log.warn("Trying to validation the name
- * uniqueness without " + " a valid item is
- * invalid. This method should only " + " be
- * called in \"edit\" forms. The passed in id "
- * + " was null."); return; } // now we check
- * to make sure that the new name is valid //
- * within every category that the item is
- * mapped to // this is only necessary for
- * category browsing FormData data =
- * event.getFormData(); String url = (String)
- * data.get(NAME); if (url == null) { return; }
- * DataQuery query =
- * SessionManager.getSession().retrieveQuery(
- * "com.arsdigita.categorization.getAllItemURLsForCategoryFromItem");
- * query.setParameter("itemID", id);
- * query.addEqualsFilter("lower(url)",
- * url.toLowerCase()); if (query.size() > 0) {
- * // we need to make sure that the conflicting
- * item is not a // pending or live version of
- * the same item BigDecimal itemID = null;
- *
- * ContentItem item = (ContentItem)getItemSelectionModel()
- * .getSelectedObject(event.getPageState()); Collection list =
- * getAllVersionIDs(item); try { while (query.next()) { itemID =
- * (BigDecimal) query.get("itemID"); if (!list.contains(itemID)) { //
- * StringBuffer buffer = new StringBuffer((String) GlobalizationUtil //
- * .globalize("cms.ui.authoring.error_conflicts_with_this_url") //
- * .localize()); // buffer.append(url); String[] urlObj=new String[1];
- * urlObj[0]=url; throw new FormProcessException( "Error: Conflict with url:
- * "+url, globalize( "cms.ui.authoring.error_conflicts_with_this_url",
- * urlObj) ); } }
- *
- * } finally { query.close(); } } }
- */
- /**
- * Helper Method for name uniqueness validation.
- *
- * @param item
- *
- * @return
- */
-// public static Collection getAllVersionIDs(ContentItem item) {
-// // we need to add all of the items that are different versions
-// // of this item to the list so that we do not throw an error
-// // if those are the only problems
-// ArrayList list = new ArrayList();
-// list.add(item.getID());
-// ContentItem live = item.getLiveVersion();
-// if (live != null) {
-// list.add(live.getID());
-// }
-// ItemCollection collection = item.getPendingVersions();
-// while (collection.next()) {
-// list.add(collection.getID());
-// }
-// return list;
-// }
+ public void validateNameUniqueness(final Category parent,
+ final FormSectionEvent event,
+ final String newName) {
+
+ final String ERR_MSG = "cms.ui.authoring.an_item_with_this_name_exists";
+
+ if (newName != null) {
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final CategoryRepository categoryRepo = cdiUtil
+ .findBean(CategoryRepository.class);
+ final ContentItemRepository itemRepo = cdiUtil
+ .findBean(ContentItemRepository.class);
+
+ final long result = itemRepo.countByNameInFolder(parent, newName);
+
+ if (result > 0) {
+ // Try to get a currently selected content item
+ final ContentItem item;
+ if (getItemSelectionModel() == null) {
+ item = null;
+ } else {
+ item = getItemSelectionModel()
+ .getSelectedObject(event.getPageState());
+ }
+ if (item == null) { // The content item being null
+ // means it is a creation form.
+ // Therefore finding any item of the same name is a fault.
+ event.getFormData()
+ .addError(new GlobalizedMessage(ERR_MSG,
+ CmsConstants.CMS_BUNDLE));
+ } else {
+ // means we are in a edit form.
+ // We need to add all of the items that are different
+ // versions of this item to the list so that we do not mark
+ // an error if those are the only problems.
+ event.getFormData()
+ .addError(new GlobalizedMessage(
+ ERR_MSG,
+ CmsConstants.CMS_BUNDLE,
+ new Object[]{item.getUuid()}));
+ }
+ }
+ }
+ }
+
}
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicPageForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicPageForm.java
new file mode 100755
index 000000000..83397384e
--- /dev/null
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicPageForm.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2001-2004 Red Hat Inc. 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.authoring;
+
+import com.arsdigita.bebop.ColumnPanel;
+import com.arsdigita.bebop.FormData;
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.FormSection;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.ParameterEvent;
+import com.arsdigita.bebop.event.ParameterListener;
+import com.arsdigita.bebop.parameters.DateParameter;
+import com.arsdigita.bebop.parameters.ParameterData;
+import com.arsdigita.bebop.parameters.ParameterModel;
+
+import org.librecms.contentsection.ContentItem;
+import org.librecms.contentsection.ContentSection;
+import org.librecms.contentsection.Folder;
+
+import com.arsdigita.cms.ItemSelectionModel;
+import com.arsdigita.globalization.GlobalizedMessage;
+import com.arsdigita.kernel.KernelConfig;
+import com.arsdigita.util.Assert;
+
+import org.arsdigita.cms.CMSConfig;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.librecms.CmsConstants;
+import org.librecms.contentsection.ContentItemManager;
+import org.librecms.contentsection.ContentType;
+import org.librecms.contentsection.FolderManager;
+
+import javax.servlet.ServletException;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.Optional;
+
+/**
+ * A form for editing basic properties of documents (that is subclasses of class
+ * ContentPage).
+ *
+ * Document specific classes inherit from this class which provides the basic
+ * widgets for title, name launch date to use by those classes.
+ *
+ * This is just a convenience class. It uses parent class to construct the form
+ * including basic widgets (i.e. title and name/URL as well as save/cancel
+ * buttons) and adds optional launch date.
+ *
+ * Note: It is for editing existing content (specifically due to its validation
+ * method).
+ *
+ * @author Stanislav Freidin (stas@arsdigita.com)
+ * @author Jens Pelzetter
+ */
+public abstract class BasicPageForm extends BasicItemForm {
+
+ private static final String LAUNCH_DATE = "launch_date";
+
+ private FormSection widgetSection;
+
+ /**
+ * Construct a new BasicPageForm
+ *
+ * @param formName the name of this form
+ * @param itemModel The {@link ItemSelectionModel} which will be responsible
+ * for loading the current item
+ */
+ public BasicPageForm(final String formName,
+ final ItemSelectionModel itemModel) {
+
+ super(formName, itemModel);
+ }
+
+ /**
+ * Construct a new BasicPageForm with nothing on it
+ *
+ * @param formName the name of this form
+ * @param columnPanel the column panel of the form
+ * @param itemModel The {@link ItemSelectionModel} which will be
+ * responsible for loading the current item
+ */
+ public BasicPageForm(final String formName,
+ final ColumnPanel columnPanel,
+ final ItemSelectionModel itemModel) {
+
+ super(formName, columnPanel, itemModel);
+ }
+
+ /**
+ * Add various widgets to the form. Child classes should override this
+ * method to perform all their widget-adding needs
+ */
+ @Override
+ protected void addWidgets() {
+
+ /* Add basic widgets title/name which are part of any content item */
+ super.addWidgets();
+
+ final CMSConfig cmsConfig = CMSConfig.getConfig();
+
+ /* Optionally add Lunchdate */
+ if (!cmsConfig.isHideLaunchDate()) {
+ add(new Label(new GlobalizedMessage(
+ "cms.ui.authoring.page_launch_date",
+ CmsConstants.CMS_BUNDLE)));
+ final ParameterModel launchDateParam
+ = new DateParameter(LAUNCH_DATE);
+ com.arsdigita.bebop.form.Date launchDate
+ = new com.arsdigita.bebop.form.Date(
+ launchDateParam);
+ if (CMSConfig.getConfig().isRequireLaunchDate()) {
+ launchDate.addValidationListener(
+ new LaunchDateValidationListener());
+ // if launch date is required, help user by suggesting today's date
+ launchDateParam.setDefaultValue(new Date());
+ }
+ add(launchDate);
+ }
+ }
+
+ /**
+ * Utility method to initialise the name/title widgets. Child classes may
+ * call this method from the init listener
+ *
+ * @param event the {@link FormSectionEvent} which was passed to the init
+ * listener
+ *
+ * @return the ContentPage instance which was extracted from the
+ * ItemSelectionModel
+ */
+ public ContentItem initBasicWidgets(final FormSectionEvent event) {
+ Assert.exists(getItemSelectionModel());
+
+ final FormData data = event.getFormData();
+ final PageState state = event.getPageState();
+ final ContentItem item = getItemSelectionModel()
+ .getSelectedObject(state);
+
+ if (item != null) {
+ // Preset fields
+ data.put(CONTENT_ITEM_ID, Long.toString(item.getObjectId()));
+ data.put(NAME, item.getName());
+ data.put(TITLE, item.getTitle());
+ final CMSConfig cmsConfig = CMSConfig.getConfig();
+ if (!cmsConfig.isHideLaunchDate()) {
+ data.put(LAUNCH_DATE, item.getLaunchDate());
+ // if launch date is required, help user by suggesting today's date
+ if (cmsConfig.isRequireLaunchDate()
+ && item.getLaunchDate() == null) {
+ data.put(LAUNCH_DATE, new Date());
+ }
+ }
+ }
+
+ return item;
+ }
+
+ /**
+ * Class specific implementation of FormValidationListener interface
+ * (inherited from BasicItemForm).
+ *
+ * @param fse
+ *
+ * @throws FormProcessException
+ */
+ @Override
+ public void validate(final FormSectionEvent fse) throws FormProcessException {
+
+ super.validate(fse); //noop, BasicItemForm#validate does nothing
+
+ final ContentItem item = getItemSelectionModel()
+ .getSelectedItem(fse.getPageState());
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final ContentItemManager itemManager = cdiUtil
+ .findBean(ContentItemManager.class);
+
+ final Optional folder = itemManager.getItemFolder(item);
+ if (folder.isPresent()) {
+ final FormData data = fse.getFormData();
+ final String name = fse.getFormData().getString(NAME);
+ if (!item.getName()
+ .getValue(KernelConfig.getConfig().getDefaultLocale())
+ .equals(name)) {
+ validateNameUniqueness(folder.get(), fse);
+ }
+ }
+ }
+
+ /**
+ * Utility method to process the name/title widgets. Child classes may call
+ * this method from the process listener.
+ *
+ * @param event the {@link FormSectionEvent} which was passed to the process
+ * listener
+ *
+ * @return
+ */
+ public ContentItem processBasicWidgets(final FormSectionEvent event) {
+ Assert.exists(getItemSelectionModel());
+
+ final FormData data = event.getFormData();
+ final PageState state = event.getPageState();
+ final ContentItem item = getItemSelectionModel()
+ .getSelectedObject(state);
+
+ if (item != null) {
+ // Update attributes
+ final KernelConfig kernelConfig = KernelConfig.getConfig();
+ final Locale defaultLocale = kernelConfig.getDefaultLocale();
+ item.getName().addValue(defaultLocale, (String) data.get(NAME));
+ item.getTitle().addValue(defaultLocale, (String) data.get(TITLE));
+ if (!CMSConfig.getConfig().isHideLaunchDate()) {
+ item.setLaunchDate((Date) data.get(LAUNCH_DATE));
+ }
+ }
+
+ return item;
+ }
+
+ /**
+ * A utility method that will create a new item and tell the selection model
+ * to select the new item.
+ *
+ * Creation components may call this method in the process listener of their
+ * form. See {@link PageCreate} for an example.
+ *
+ * @param state
+ * @param name
+ * @param section
+ * @param folder
+ *
+ * @return the new content item (or a proper subclass thereof)
+ *
+ * @throws com.arsdigita.bebop.FormProcessException
+ */
+ public ContentItem createContentPage(final PageState state,
+ final String name,
+ final ContentSection section,
+ final Folder folder)
+ throws FormProcessException {
+
+ final ItemSelectionModel selectionModel = getItemSelectionModel();
+ final ContentType contentType = selectionModel.getContentType();
+
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final ContentItemManager itemManager = cdiUtil
+ .findBean(ContentItemManager.class);
+
+ // Create new item
+ final ContentItem item;
+ try {
+ @SuppressWarnings("unchecked")
+ final Class extends ContentItem> clazz
+ = (Class extends ContentItem>) Class
+ .forName(contentType.getContentItemClass());
+ item = itemManager.createContentItem(name, section, folder, clazz);
+ } catch (ClassNotFoundException ex) {
+ throw new FormProcessException(
+ "Couldn't create contentpage",
+ new GlobalizedMessage(
+ "cms.ui.authoring.couldnt_create_contentpage",
+ CmsConstants.CMS_BUNDLE),
+ ex);
+ }
+
+ // Create new item
+
+ // Make sure the item will be remembered across requests
+ selectionModel.setSelectedKey(state, item.getObjectId());
+
+ return item;
+ }
+
+ /**
+ * Constructs a new LaunchDateValidationListener.
+ */
+ private class LaunchDateValidationListener implements ParameterListener {
+
+ @Override
+ public void validate(final ParameterEvent event) {
+
+ final ParameterData data = event.getParameterData();
+ final Object value = data.getValue();
+
+ if (value == null) {
+ data.addError("launch date is required");
+ }
+ }
+
+ }
+
+}
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationComponent.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationComponent.java
new file mode 100755
index 000000000..b636a5d88
--- /dev/null
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationComponent.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. 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.authoring;
+
+import com.arsdigita.bebop.Container;
+import com.arsdigita.bebop.SaveCancelSection;
+import com.arsdigita.bebop.event.FormProcessListener;
+
+/**
+ * Interface which item creation components should implement. It's
+ * currently an optional interface, but user defined content types
+ * will not work unless they inherit from a type whose creation
+ * component implements this. This interface currently only defines
+ * methods which are essential to the operation of UDCT creation
+ * components.
+ *
+ * @author Scott Seago (sseago@redhat.com)
+ */
+public interface CreationComponent extends Container, FormProcessListener {
+
+ /**
+ * Instantiate and add the save/cancel section for this CreationComponent.
+ */
+ void addSaveCancelSection();
+
+ /**
+ * Return the save/cancel section for this CreationComponent.
+ *
+ * @return the save/cancel section for this CreationComponent.
+ */
+ SaveCancelSection getSaveCancelSection();
+
+ /**
+ * Removes the specified process listener from the
+ * list of process listeners (if it had previously been added).
+ *
+ * @param listener the process listener to remove
+ */
+ void removeProcessListener(FormProcessListener listener);
+
+ /**
+ * Return the ApplyWorkflowFormSection associated with this CreationComponent.
+ *
+ * @return the ApplyWorkflowFormSection associated with this CreationComponent.
+ */
+ ApplyWorkflowFormSection getWorkflowSection();
+
+}
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationSelector.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationSelector.java
index 632483511..8d6266389 100755
--- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationSelector.java
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationSelector.java
@@ -26,7 +26,6 @@ import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SingleSelectionModel;
import com.arsdigita.bebop.form.FormErrorDisplay;
-import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.bebop.parameters.LongParameter;
import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.cms.ui.ContentItemPage;
@@ -45,14 +44,12 @@ import org.librecms.contentsection.ContentType;
import org.librecms.contentsection.ContentTypeManager;
import org.librecms.contentsection.ContentTypeRepository;
import org.librecms.contentsection.Folder;
-import org.librecms.contenttypes.AuthoringKit;
import org.librecms.contenttypes.AuthoringKitInfo;
import org.librecms.contenttypes.ContentTypeInfo;
import org.librecms.contenttypes.ContentTypesManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import java.math.BigDecimal;
import java.util.Optional;
/**
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java
index 10dba3735..026da0a76 100755
--- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java
@@ -22,36 +22,28 @@ import com.arsdigita.bebop.BoxPanel;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
-import com.arsdigita.bebop.Text;
import com.arsdigita.bebop.event.PrintEvent;
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.bebop.form.Option;
import com.arsdigita.bebop.form.OptionGroup;
import com.arsdigita.bebop.form.SingleSelect;
import com.arsdigita.bebop.form.Submit;
-import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.bebop.parameters.LongParameter;
import com.arsdigita.cms.ui.ItemSearch;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.xml.Element;
-import java.math.BigDecimal;
-
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.security.PermissionChecker;
import org.librecms.CmsConstants;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentType;
import org.librecms.contentsection.ContentTypeRepository;
-import org.librecms.contentsection.privileges.TypePrivileges;
import java.util.List;
import java.util.TooManyListenersException;
-import java.util.stream.Collectors;
-import org.libreccm.l10n.GlobalizationHelper;
-import org.librecms.contentsection.ContentTypeManager;
import org.librecms.contenttypes.ContentTypeInfo;
import org.librecms.contenttypes.ContentTypesManager;
@@ -107,7 +99,7 @@ public abstract class NewItemForm extends Form {
createLabel.setIdAttr("create_label");
panel.add(createLabel);
- typeSelect = new SingleSelect(new BigDecimalParameter(TYPE_ID),
+ typeSelect = new SingleSelect(new LongParameter(TYPE_ID),
OptionGroup.SortMode.ALPHABETICAL_ASCENDING);
try {
typeSelect.addPrintListener(new PrintListener() {
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/PageCreate.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/PageCreate.java
new file mode 100755
index 000000000..a5a6247dc
--- /dev/null
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/PageCreate.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2001-2004 Red Hat Inc. 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.authoring;
+
+import com.arsdigita.bebop.ColumnPanel;
+import com.arsdigita.bebop.FormData;
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.FormSubmissionListener;
+
+import org.librecms.contentsection.ContentSection;
+import org.librecms.contentsection.ContentType;
+import org.librecms.contentsection.Folder;
+
+import com.arsdigita.cms.ItemSelectionModel;
+import com.arsdigita.globalization.GlobalizedMessage;
+import com.arsdigita.kernel.KernelConfig;
+import com.arsdigita.util.Assert;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.arsdigita.cms.CMSConfig;
+import org.librecms.CmsConstants;
+import org.librecms.contentsection.ContentItem;
+
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * A form which will create a new document (that is subclasses of class
+ * ContentPage).
+ *
+ * Used to create a new document / content item. Creates widgets to select the
+ * workflow, and language. It displays the type of document as well. Super class
+ * adds additional widgets (title and name/URL) to complete the form.
+ *
+ * It's a pane which is part of a more complex page, additionally containing
+ * folder structure, content items in the folder, permissions, etc.
+ *
+ * @author Stanislav Freidin (stas@arsdigita.com)
+ * @author Jens Pelzetter
+ */
+public class PageCreate
+ extends BasicPageForm
+ implements FormSubmissionListener, CreationComponent {
+
+ private final CreationSelector creationSelector;
+ private final ApplyWorkflowFormSection workflowSection;
+
+ /**
+ * The state parameter which specifies the content section
+ */
+ public static final String SECTION_ID = "sid";
+
+ /**
+ * Construct a new PageCreationForm
+ *
+ * @param itemModel The {@link ItemSelectionModel} which will be
+ * responsible for loading the current item
+ * @param creationSelector The {@link CreationSelector} parent. This class
+ * should call either the {@link
+ * CreationSelector#redirectBack(PageState)} or {@link
+ * CreationSelector#editItem(PageState, ContentItem)} methods on the parent
+ * eventually
+ */
+ public PageCreate(final ItemSelectionModel itemModel,
+ final CreationSelector creationSelector) {
+
+ super("PageCreate", itemModel);
+
+ this.creationSelector = creationSelector;
+
+ /* Retrieve Content Type */
+ final ContentType type = getItemSelectionModel().getContentType();
+ /* Add workflow selection based on configured Content Type */
+ workflowSection = new ApplyWorkflowFormSection(type);
+
+ workflowSection.setCreationSelector(creationSelector);
+ addSubmissionListener(this);
+
+ getSaveCancelSection().getSaveButton()
+ .setButtonLabel(new GlobalizedMessage("cms.ui.create",
+ CmsConstants.CMS_BUNDLE));
+ }
+
+ /**
+ * Add various widgets to the form. Child classes should override this
+ * method to perform all their widget-adding needs.
+ */
+ @Override
+ protected void addWidgets() {
+
+ add(workflowSection, ColumnPanel.INSERT);
+ /* content type */
+ add(new Label(new GlobalizedMessage("cms.ui.authoring.content_type",
+ CmsConstants.CMS_BUNDLE)));
+ /* Retrieve Content Type */
+ final ContentType type = getItemSelectionModel().getContentType();
+ add(new Label(type.getLabel().getValue(KernelConfig
+ .getConfig()
+ .getDefaultLocale())));
+ /* language selection */
+ add(new Label(new GlobalizedMessage("cms.ui.language.field",
+ CmsConstants.CMS_BUNDLE)));
+ add(new LanguageWidget(LANGUAGE));
+
+ /* Additional widgets from super type: title and name (url) */
+ super.addWidgets();
+ }
+
+ /**
+ * Return the ApplyWorkflowFormSection associated with this
+ * CreationComponent.
+ *
+ * @return the ApplyWorkflowFormSection associated with this
+ * CreationComponent.
+ */
+ @Override
+ public ApplyWorkflowFormSection getWorkflowSection() {
+ return workflowSection;
+ }
+
+ /**
+ * Create a new item id.
+ *
+ * @throws com.arsdigita.bebop.FormProcessException
+ */
+ @Override
+ public void init(final FormSectionEvent event) throws FormProcessException {
+ // this is currently a no-op
+ }
+
+ /**
+ * If the Cancel button was pressed, hide self and show the display
+ * component.
+ *
+ * @throws com.arsdigita.bebop.FormProcessException
+ */
+ @Override
+ public void submitted(final FormSectionEvent event)
+ throws FormProcessException {
+
+ final PageState state = event.getPageState();
+
+ if (getSaveCancelSection().getCancelButton().isSelected(state)) {
+ creationSelector.redirectBack(state);
+
+ throw new FormProcessException(
+ new GlobalizedMessage("cms.ui.authoring.submission_cancelled",
+ CmsConstants.CMS_BUNDLE));
+ }
+ }
+
+ /**
+ * Validate inputs to ensure name uniqueness. Note: We can't call
+ * {@code super.validate(FormSectionEvent)} here because the super method
+ * {@link BasicPageForm#validate(com.arsdigita.bebop.event.FormSectionEvent)}
+ * tries to access things which on existing yet.
+ *
+ * @param event
+ *
+ * @throws com.arsdigita.bebop.FormProcessException
+ */
+ @Override
+ public void validate(final FormSectionEvent event)
+ throws FormProcessException {
+
+ final Folder folder = creationSelector.getFolder(event.getPageState());
+ validateNameUniqueness(folder, event);
+ }
+
+ /**
+ * Class specific implementation if FormProcessListener (as inherited from
+ * BasicItemForm), saves fields to the database.
+ *
+ * @param event
+ *
+ * @throws FormProcessException
+ */
+ @Override
+ public void process(final FormSectionEvent event)
+ throws FormProcessException {
+
+ final FormData data = event.getFormData();
+ final PageState state = event.getPageState();
+ final ContentSection section = creationSelector.getContentSection(state);
+ final Folder folder = creationSelector.getFolder(state);
+
+ Assert.exists(section, ContentSection.class);
+
+ final ContentItem item = createContentPage(state,
+ (String) data.get(NAME),
+ section,
+ folder);
+ final Locale locale = new Locale((String) data.get(LANGUAGE));
+ item.getName().addValue(locale, (String) data.get(NAME));
+ item.getTitle().addValue(locale, (String) data.get(TITLE));
+
+ workflowSection.applyWorkflow(state, item);
+
+ creationSelector.editItem(state, item);
+ }
+
+}