CCM NG: Next part of migration of ItemCategoryStep

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4997 8810af33-2d31-482b-a856-94f89814c4df
ccm-docs
jensp 2017-09-13 15:36:54 +00:00
parent 3f38ed9fb9
commit 31cdeeeb7c
9 changed files with 1062 additions and 51 deletions

View File

@ -0,0 +1,39 @@
/*
* 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.cms.ui.authoring;
import com.arsdigita.bebop.SimpleComponent;
/**
* NOOP base implementation of category authoring step extension.
* Summary component returned by #getSummary() is show on category summary page,
* usually an ActionLink which activates the Form component returned by #getForm().
*
* @author Alan Pevec
*/public class ItemCategoryExtension {
public SimpleComponent[] getSummary() {
return new SimpleComponent[0];
}
public SimpleComponent[] getForm() {
return new SimpleComponent[0];
}
}

View File

@ -29,43 +29,41 @@ import com.arsdigita.bebop.Resettable;
import com.arsdigita.bebop.parameters.LongParameter;
import com.arsdigita.web.RedirectSignal;
import com.arsdigita.cms.CMS;
import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.util.Classes;
import org.arsdigita.cms.CMSConfig;
import org.libreccm.core.UnexpectedErrorException;
import org.librecms.CmsConstants;
import org.librecms.ui.authoring.ContentItemAuthoringStep;
import java.math.BigDecimal;
@ContentItemAuthoringStep(
labelBundle = CmsConstants.CMS_BUNDLE,
labelKey = "item_category_step.label",
descriptionBundle = CmsConstants.CMS_BUNDLE,
descriptionKey = "item_category_step.description"
)
public class ItemCategoryStep extends SimpleContainer implements Resettable{
public class ItemCategoryStep extends SimpleContainer implements Resettable {
private final LongParameter rootParameter;
private final StringParameter modeParameter;
private final ItemCategorySummary itemCategorySummary;
private final SimpleComponent addComponent;
// private SimpleComponent[] extensionSummaries;
// private SimpleComponent[] extensionForms;
// private int extensionsCount;
public ItemCategoryStep(final ItemSelectionModel itemSelectionModel,
private final ItemCategorySummary itemCategorySummary;
private final SimpleComponent addComponent;
private final SimpleComponent[] extensionSummaries;
private final SimpleComponent[] extensionForms;
private int extensionsCount;
public ItemCategoryStep(final ItemSelectionModel itemSelectionModel,
final AuthoringKitWizard authoringKitWizard,
final StringParameter selectedLanguage) {
super("cms:categoryStep", CMS.CMS_XML_NS);
rootParameter = new LongParameter("root");
@ -73,43 +71,63 @@ public class ItemCategoryStep extends SimpleContainer implements Resettable{
itemCategorySummary = new ItemCategorySummary();
itemCategorySummary.registerAction(ItemCategorySummary.ACTION_ADD,
new AddActionListener("plain"));
new AddActionListener("plain"));
itemCategorySummary.registerAction(ItemCategorySummary.ACTION_ADD_JS,
new AddActionListener("javascript"));
new AddActionListener("javascript"));
// Class addForm = CMSConfig.getConfig().getCategoryAuthoringAddForm();
// addComponent = (SimpleComponent)
// Classes.newInstance(addForm,
// new Class[] { BigDecimalParameter.class,
// StringParameter.class },
// new Object[] { rootParameter, modeParameter });
addComponent = new ItemCategoryForm(rootParameter, modeParameter);
final String addFormClassName = CMSConfig
.getConfig()
.getCategoryAuthoringAddForm();
final Class<?> addFormClass;
try {
addFormClass = Class.forName(addFormClassName);
} catch (ClassNotFoundException ex) {
throw new UnexpectedErrorException(ex);
}
addComponent = (SimpleComponent) Classes
.newInstance(addFormClass,
new Class<?>[]{LongParameter.class,
StringParameter.class},
new Object[]{rootParameter, modeParameter});
addComponent.addCompletionListener(new ResetListener());
// Class extensionClass = ContentSection.getConfig().getCategoryAuthoringExtension();
// ItemCategoryExtension extension = (ItemCategoryExtension)
// Classes.newInstance(extensionClass);
//
// extensionSummaries = extension.getSummary();
// extensionForms = extension.getForm();
// int nSummaries = extensionSummaries.length;
// int nForms= extensionForms.length;
// Assert.isTrue(nSummaries==nForms, "invalid CategoryStep extension");
// extensionsCount = nForms;
// for (int i=0;i<extensionsCount;i++) {
// extensionSummaries[i].addCompletionListener(new ExtensionListener(i));
// extensionForms[i].addCompletionListener(new ResetListener());
// add(extensionSummaries[i]);
// add(extensionForms[i]);
// }
add(itemCategorySummary);
add(addComponent);
final String extensionClassName = CMSConfig
.getConfig()
.getCategoryAuthoringExtension();
final Class<?> extensionClass;
try {
extensionClass = Class.forName(extensionClassName);
} catch (ClassNotFoundException ex) {
throw new UnexpectedErrorException(ex);
}
final ItemCategoryExtension extension = (ItemCategoryExtension) Classes
.newInstance(extensionClass);
extensionSummaries = extension.getSummary();
extensionForms = extension.getForm();
int nSummaries = extensionSummaries.length;
int nForms = extensionForms.length;
if (nSummaries != nForms) {
throw new UnexpectedErrorException(
"Invalid category step extension.");
}
extensionsCount = nForms;
for (int i = 0; i < extensionsCount; i++) {
extensionSummaries[i]
.addCompletionListener(new ExtensionListener(i));
extensionForms[i].addCompletionListener(new ResetListener());
super.add(extensionSummaries[i]);
super.add(extensionForms[i]);
}
super.add(itemCategorySummary);
super.add(addComponent);
}
@Override
public void register(Page p) {
public void register(Page p
) {
super.register(p);
p.setVisibleDefault(addComponent, false);
// for (int i=0;i<extensionsCount;i++) {
// p.setVisibleDefault(extensionForms[i], false);
@ -119,10 +137,11 @@ public class ItemCategoryStep extends SimpleContainer implements Resettable{
}
@Override
public void reset(PageState state) {
public void reset(PageState state
) {
state.setValue(rootParameter, null);
state.setValue(modeParameter, null);
itemCategorySummary.setVisible(state, true);
addComponent.setVisible(state, false);
// for (int i=0;i<extensionsCount;i++) {
@ -132,6 +151,7 @@ public class ItemCategoryStep extends SimpleContainer implements Resettable{
}
private class AddActionListener implements ActionListener {
private String m_mode;
public AddActionListener(String mode) {
@ -141,7 +161,7 @@ public class ItemCategoryStep extends SimpleContainer implements Resettable{
@Override
public void actionPerformed(ActionEvent e) {
PageState state = e.getPageState();
state.setValue(rootParameter,
new BigDecimal(state.getControlEventValue()));
@ -155,22 +175,28 @@ public class ItemCategoryStep extends SimpleContainer implements Resettable{
// extensionForms[i].setVisible(state, false);
// }
}
}
private class ResetListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
PageState state = e.getPageState();
reset(state);
throw new RedirectSignal(state.toURL(), true);
}
}
private class ExtensionListener implements ActionListener {
int extensionIndex;
public ExtensionListener(int i) {
extensionIndex = i;
}
@Override
public void actionPerformed(ActionEvent e) {
PageState state = e.getPageState();
@ -181,6 +207,7 @@ public class ItemCategoryStep extends SimpleContainer implements Resettable{
// }
// extensionForms[extensionIndex].setVisible(state, true);
}
}
}

View File

@ -0,0 +1,198 @@
/*
* 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.london.terms.ui;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.parameters.LongParameter;
import com.arsdigita.categorization.ui.ACSObjectCategoryForm;
import org.apache.logging.log4j.LogManager;
import org.libreccm.categorization.Domain;
import org.apache.logging.log4j.Logger;
import org.libreccm.categorization.DomainRepository;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.core.CcmObject;
import java.util.Optional;
/**
* abstracted from original version of c.ad.aplaws.ui.ItemCategoryPicker r1297
*
* @author Chris Gilbert
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
// NON JavaDoc:
// copied from c.ad.aplaws.ui (module ccm-ldn-aplaws) in order to avoid a
// dependency from the integration layer for forum-categorised. Otherwise you
// have had to specify the specific integration layer (i.e. ccm-???-aplaws) in
// application.xml for compiling, which may be different for each installation.
public abstract class ACSObjectCategoryPicker extends SimpleContainer {
private static final Logger LOGGER = LogManager
.getLogger(ACSObjectCategoryPicker.class);
private final ACSObjectCategoryForm form;
private final LongParameter rootParam;
public ACSObjectCategoryPicker(final LongParameter rootParam,
final StringParameter mode) {
form = getForm(rootParam, mode);
this.rootParam = rootParam;
super.add(form);
form.addCompletionListener(new ItemCategoryFormCompletion());
}
protected abstract ACSObjectCategoryForm getForm(LongParameter root,
StringParameter mode);
protected abstract CcmObject getObject(PageState state);
// protected List<Long> getCurrentCategories(final Domain domain,
// final CcmObject object) {
//
// LOGGER.debug("Getting terms from {} to {}", domain, object);
// final List<Category> terms = domain.getRoot().getSubCategories();
// terms.addEqualsFilter("model.childObjects.id", object.getID());
// terms.addPath("model.id");
//
// List<Long> current = new ArrayList<>();
// while (terms.next()) {
// if (LOGGER.isDebugEnabled()) {
// LOGGER.debug("Got term " + terms.get("model.id"));
// }
// current.add(terms.get("model.id"));
// }
// return current;
// }
// TODO move out of UI code
// public static Collection getCurrentTerms(Domain domain, ACSObject object) {
// if (LOGGER.isDebugEnabled()) {
// LOGGER.debug("Getting terms from " + domain + " to " + object);
// }
// Collection current = new LinkedList();
// DomainCollection terms = domain.getTerms();
// terms.addEqualsFilter("model.childObjects.id", object.getID());
// terms.addPath("model.id");
// while (terms.next()) {
// if (LOGGER.isDebugEnabled()) {
// LOGGER.debug("Got term " + terms.get("model.id"));
// }
// current.add(terms.getDomainObject());
// }
// return current;
// }
//
// // TODO move out of UI code
// public static Collection getRelatedTerms(Collection src, Domain domain) {
// if (LOGGER.isDebugEnabled()) {
// LOGGER.debug("Getting related terms to " + domain);
//
// }
// if (src.isEmpty()) {
// // this is a hack, it would be better not to use a completion event listener as
// // this is called even when the form is cancelled...
// return new LinkedList();
// }
// DomainCollection terms = domain.getTerms();
// // these next two lines build the query
// terms.addEqualsFilter("model.parents.link.relationType", "related");
// terms.addFilter("model.parents.id in :ids").set("ids", src);
//
// Collection related = new LinkedList();
// while (terms.next()) {
// if (LOGGER.isDebugEnabled()) {
// LOGGER.debug("Got term " + terms.getDomainObject());
// }
// related.add(terms.getDomainObject());
// }
// return related;
// }
// protected void clearTerms(Domain domain, ACSObject object) {
// if (LOGGER.isDebugEnabled()) {
// LOGGER.debug("Removing terms from " + domain + " to " + object);
// }
// Iterator terms = getCurrentTerms(domain, object).iterator();
// while (terms.hasNext()) {
// Term term = (Term) terms.next();
// if (LOGGER.isDebugEnabled()) {
// LOGGER.debug("Removing term " + term + " from " + object);
// }
// term.removeObject(object);
// }
// }
// // TODO move out of UI code
// public static void assignTerms(Collection terms, ACSObject object) {
// if (LOGGER.isDebugEnabled()) {
// LOGGER.debug("Assigning terms to " + object);
// }
// Iterator i = terms.iterator();
// while (i.hasNext()) {
// Term term = (Term) i.next();
// if (LOGGER.isDebugEnabled()) {
// LOGGER.debug("Assigning term " + term + " to " + object);
// }
// term.addObject(object);
// }
// }
protected Domain getDomain(final PageState state) {
LOGGER.debug("Getting domain for {}", state.getValue(rootParam));
final Long domainId = (Long) state.getValue(rootParam);
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final DomainRepository domainRepo = cdiUtil
.findBean(DomainRepository.class);
final Optional<Domain> domain = domainRepo
.findById(domainId);
if (domain.isPresent()) {
return domain.get();
} else {
LOGGER.warn("No Domain for ID {} found.", domainId);
return null;
}
}
/**
*
*/
private class ItemCategoryFormCompletion implements ActionListener {
@Override
public void actionPerformed(final ActionEvent event) {
final PageState state = event.getPageState();
final Domain domain = getDomain(state);
final String domainKey = domain.getDomainKey();
LOGGER.debug("Saving categories in: {}", domainKey);
fireCompletionEvent(state);
}
}
}

View File

@ -0,0 +1,217 @@
/*
* 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.london.terms.ui;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.categorization.Categorization;
import org.libreccm.categorization.CategorizationConstants;
import org.libreccm.categorization.CategorizationMarshaller;
import org.libreccm.categorization.Category;
import org.libreccm.categorization.CategoryManager;
import org.libreccm.categorization.CategoryRepository;
import org.libreccm.categorization.Domain;
import org.libreccm.categorization.DomainManager;
import org.libreccm.categorization.DomainRepository;
import org.libreccm.categorization.ObjectNotAssignedToCategoryException;
import org.libreccm.core.CcmObject;
import org.libreccm.core.CcmObjectRepository;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
class CategoryPickerController {
private final static Logger LOGGER = LogManager
.getLogger(CategoryPickerController.class);
@Inject
private CategoryManager categoryManager;
@Inject
private CategoryRepository categoryRepo;
@Inject
private CcmObjectRepository ccmObjectRepo;
@Inject
private DomainRepository domainRepo;
@Inject
private DomainManager domainManager;
@Transactional(Transactional.TxType.REQUIRED)
protected List<Category> getCurrentCategories(final Domain domain,
final CcmObject object) {
Objects.requireNonNull(domain);
Objects.requireNonNull(object);
final Domain catDomain = domainRepo
.findById(domain.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Domain with ID %d in the database.",
domain.getObjectId())));
final CcmObject ccmObject = ccmObjectRepo
.findById(object.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No CcmObject with ID %d in the database.",
object.getObjectId())));
final Category root = catDomain.getRoot();
return collectAssignedCategories(ccmObject, root);
}
private List<Category> collectAssignedCategories(final CcmObject object,
final Category root) {
final List<Category> categories = new ArrayList<>();
if (categoryManager.isAssignedToCategory(root, object)) {
categories.add(root);
}
if (!root.getSubCategories().isEmpty()) {
for (final Category subCategory : root.getSubCategories()) {
categories.addAll(collectAssignedCategories(object,
subCategory));
}
}
return categories;
}
@Transactional(Transactional.TxType.REQUIRED)
protected void clearCategories(final Domain domain, final CcmObject object) {
Objects.requireNonNull(domain);
Objects.requireNonNull(object);
final Domain catDomain = domainRepo
.findById(domain.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Domain with ID %d in the database.",
domain.getObjectId())));
final CcmObject ccmObject = ccmObjectRepo
.findById(object.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No CcmObject with ID %d in the database.",
object.getObjectId())));
final Category root = catDomain.getRoot();
final List<Category> assignedCategories = collectAssignedCategories(
ccmObject, root);
for (final Category category : assignedCategories) {
try {
categoryManager.removeObjectFromCategory(ccmObject, category);
} catch (ObjectNotAssignedToCategoryException ex) {
LOGGER.warn("Tried to remove category {} from object {} but "
+ "the object was not assigned to that category.",
Objects.toString(category),
Objects.toString(ccmObject));
}
}
}
@Transactional(Transactional.TxType.REQUIRED)
protected void assignCategories(final List<Category> categories,
final CcmObject object) {
Objects.requireNonNull(categories);
Objects.requireNonNull(object);
final CcmObject ccmObject = ccmObjectRepo
.findById(object.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No CcmObject with ID %d in the database.",
object.getObjectId())));
for (final Category category : categories) {
final Category cat = categoryRepo
.findById(category.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Category with ID %d in the database.",
category.getObjectId())));
categoryManager.addObjectToCategory(ccmObject, category, "");
}
}
@Transactional(Transactional.TxType.REQUIRED)
protected Category getDomainModelCategory(final Domain domain) {
Objects.requireNonNull(domain);
final Domain catDomain = domainRepo
.findById(domain.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Domain with ID %d in the database.",
domain.getObjectId())));
return catDomain.getRoot();
}
@Transactional(Transactional.TxType.REQUIRED)
protected List<Category> getRootCategories(final Domain domain) {
return getDomainModelCategory(domain).getSubCategories();
}
@Transactional(Transactional.TxType.REQUIRED)
protected List<Category> getSubCategories(final Category category) {
Objects.requireNonNull(category);
final Category cat = categoryRepo
.findById(category.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Category with ID %d in the database.",
category.getObjectId())));
return cat.getSubCategories();
}
@Transactional(Transactional.TxType.REQUIRED)
protected Category getParentCategory(final Category category) {
Objects.requireNonNull(category);
final Category cat = categoryRepo
.findById(category.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String
.format("No Category with ID %d in the database.",
category.getObjectId())));
return cat.getParentCategory();
}
}

View File

@ -0,0 +1,79 @@
/*
* 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.london.terms.ui;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.bebop.parameters.LongParameter;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.categorization.ui.ACSObjectCategoryForm;
import com.arsdigita.cms.CMS;
import org.librecms.contentsection.ContentItem;
import com.arsdigita.cms.ui.authoring.ItemCategoryForm;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.core.CcmObject;
/**
* Replacement for cms authoring ItemCategoryForm which replaces the category
* widget with a terms based widget.
*
* Provides a ccm-cms specific concrete implementation of
* {@link com.arsdigita.london.terms.ui.ACSObjectCategoryPicker}.
*
* Is is activated / used by pointing the parameter
* {@code com.arsdigita.cms.category_authoring_add_form} to it.
*/
public class ItemCategoryPicker extends ACSObjectCategoryPicker {
private static final Logger LOGGER = LogManager
.getLogger(ItemCategoryPicker.class);
public ItemCategoryPicker(final LongParameter root,
final StringParameter mode) {
super(root, mode);
LOGGER.debug("instantiating ItemCategoryPicker");
}
/*
* @see com.arsdigita.london.terms.ui.ACSObjectCategoryPicker#getForm(
* com.arsdigita.bebop.parameters.BigDecimalParameter,
* com.arsdigita.bebop.parameters.StringParameter)
*/
@Override
protected ACSObjectCategoryForm getForm(final LongParameter root,
final StringParameter mode) {
LOGGER.debug("getForm");
return new ItemCategoryForm(root, mode, new TermWidget(mode, this));
}
/*
* @see com.arsdigita.london.terms.ui.ACSObjectCategoryPicker#getObject()
*/
@Override
protected CcmObject getObject(final PageState state) {
return CMS.getContext().getContentItem();
}
}

View File

@ -0,0 +1,372 @@
/*
* Copyright (C) 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.london.terms.ui;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.form.Widget;
import com.arsdigita.bebop.parameters.ArrayParameter;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.bebop.parameters.StringParameter;
import org.libreccm.categorization.Category;
import com.arsdigita.cms.CMS;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentSection;
import org.libreccm.categorization.Domain;
import com.arsdigita.xml.Element;
import com.arsdigita.xml.XML;
import org.arsdigita.cms.CMSConfig;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.l10n.GlobalizationHelper;
import java.util.ArrayList;
/**
* A Widget for selecting Terms. Based heavily on CategoryWidget.
*
* @author mbooth@redhat.com
* @author Chris Gilbert
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*
* Chris Gilbert - updated to identify each node uniquely (correct behaviour for
* polyhierarchical trees) - also, allow ajax update on all branches or just top
* level branch
*
* nb - widget applies to allocation of categories to any ACSObject hence xml
* prefix should be more generic eg bebop rather than cms. cms retained for
* compatibility with existing stylesheets
*
* Jens Pelzetter: Variable naming etc changed to comply with usual Java
* conventions. Adapted to CCM NG.
*/
// NON Javadoc comment:
// Copied from c.ad.aplaws.ui in order to make forum-categorised independend from
// a specific ccm-???-aplaws, i.e. a specific integration layer.
public class TermWidget extends Widget {
private final StringParameter mode;
private final ACSObjectCategoryPicker picker;
public TermWidget(final StringParameter mode,
final ACSObjectCategoryPicker picker) {
super(new ArrayParameter(new BigDecimalParameter("category")));
this.mode = mode;
this.picker = picker;
}
@Override
protected String getType() {
return "category";
}
@Override
public boolean isCompound() {
return false;
}
@Override
protected void generateWidget(final PageState state, final Element parent) {
final Domain domain = picker.getDomain(state);
final Element widget = parent.newChildElement("cms:categoryWidget",
CMS.CMS_XML_NS);
exportAttributes(widget);
widget.addAttribute("mode", (String) state.getValue(mode));
widget.addAttribute("name", getName());
final Set<Long> selectedCats = new HashSet<>();
//jensp 2015-03-12: In same cases we need to be able to pass the
//selected categories *and* the selected roots for displaying the
//categories nicely. To maintain backwards
//compatibility we check the type of the value and work either with the
//selected categories only or with the selected categories and their
//roots.
final Set<Long> selectedAncestors = new HashSet<>();
final Long[] values;
final Long[] selAncestorsValues; //selectedAncestors
final Object valueObj = getValue(state);
if (valueObj instanceof Long[][]) {
if (((Long[][]) valueObj).length >= 1) {
values = ((Long[][]) valueObj)[0];
} else {
throw new IllegalArgumentException(
"Value of TermWidget is of type BigDecimal[][] but the array is empty.");
}
if (((Long[][]) valueObj).length >= 2) {
selAncestorsValues = ((Long[][]) valueObj)[1];
} else {
selAncestorsValues = null;
}
} else if (valueObj instanceof Long[]) {
values = (Long[]) valueObj;
selAncestorsValues = null;
} else {
throw new IllegalArgumentException(
"Value of TermWidget is not of type BigDecimal[] or BigDecimal[][]");
}
//BigDecimal[] values = (BigDecimal[]) getValue(state);
if (values != null) {
selectedCats.addAll(Arrays.asList(values));
}
if (selAncestorsValues != null) {
selectedAncestors.addAll(Arrays.asList(selAncestorsValues));
}
final Element selEl = widget.newChildElement(
"cms:selectedCategories", CMS.CMS_XML_NS);
selEl.addAttribute("name", getName());
final Iterator<Long> selCats = selectedCats.iterator();
// while (selCats.hasNext()) {
// final Element selCat = selEl.newChildElement("cms:category",
// CMS.CMS_XML_NS);
// selCat.addAttribute("id", selCats.next().toString());
// }
for (Long selectedCat : selectedCats) {
final Element selectedCatElem = selEl.newChildElement(
"cms:category", CMS.CMS_XML_NS);
selectedCatElem.addAttribute("id", selectedCat.toString());
}
final Element selAncestorsElem = widget.newChildElement(
"cms:selectedAncestorCategories", CMS.CMS_XML_NS);
selAncestorsElem.addAttribute("name", getName());
for (Long selAncestor : selectedAncestors) {
final Element selAncestorElem = selAncestorsElem.newChildElement(
"cms:category", CMS.CMS_XML_NS);
selAncestorElem.addAttribute("id", selAncestor.toString());
}
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final CategoryPickerController controller = cdiUtil
.findBean(CategoryPickerController.class);
// only root terms at first, the rest is loaded on-demand via AJAX
final List<Category> roots = controller.getRootCategories(domain);
final Element element = generateCategory(
widget,
controller.getDomainModelCategory(domain),
selectedCats,
null);
if (CMSConfig.getConfig().isCategoryPickerAjaxExpandAll()) {
// add attribute to the parent node, so that in stylesheet
// we can look for any ancestor with this attribute (can't
// add attribute to categoryWidget element as that is not
// visible when subbranches are transformed)
element.addAttribute("expand", "all");
}
for (final Category category : roots) {
generateRootTerm(element,
category,
selectedCats,
category.getCategoryOrder());
}
}
public static Element generateCategory(final Element parent,
final Category category,
final Set<Long> selected,
final Long sortKey) {
final Element element = parent.newChildElement("cms:category",
CMS.CMS_XML_NS);
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final GlobalizationHelper globalizationHelper = cdiUtil
.findBean(GlobalizationHelper.class);
element.addAttribute("id", XML.format(category.getObjectId()));
element.addAttribute("name", category.getName());
element.addAttribute(
"description",
globalizationHelper.getValueFromLocalizedString(category
.getDescription()));
if (selected.contains(category.getObjectId())) {
element.addAttribute("isSelected", "1");
} else {
element.addAttribute("isSelected", "0");
}
if (category.isAbstractCategory()) {
element.addAttribute("isAbstract", "1");
} else {
element.addAttribute("isAbstract", "0");
}
if (category.isEnabled()) {
element.addAttribute("isEnabled", "1");
} else {
element.addAttribute("isEnabled", "0");
}
if (sortKey != null) {
element.addAttribute("sortKey", sortKey.toString());
}
// sort order attribute added to every node so that we can
// correctly transform xml fragments returned by ajax
element.addAttribute("order", "sortKey");
element.addAttribute("genCat", "true");
StringBuilder path = new StringBuilder(parent.getAttribute("fullname"));
if (path.length() > 0) {
path.append(" > ");
}
path.append(category.getName());
element.addAttribute("fullname", path.toString());
// need to uniquely identify each node in polyhierarchical trees
// so that expand/contract is applied to the correct node by
// javascript getElementByID function
StringBuilder nodeID = new StringBuilder(parent.getAttribute("node-id"));
if (nodeID.length() > 0) {
nodeID.append("-");
}
nodeID.append(category.getObjectId());
element.addAttribute("node-id", nodeID.toString());
return element;
}
public static Element generateTerm(final Element parent,
final Category category,
final Set<Long> selected,
final Long sortKey) {
final Element element = generateCategory(parent,
category,
selected,
sortKey);
element.addAttribute("pid", category.getUniqueId());
return element;
}
private static void generateRootTerm(final Element parent,
final Category term,
final Set<Long> selected,
final Long sortKey) {
final Element element = generateTerm(parent, term, selected, sortKey);
element.addAttribute("root", "1");
}
public static void generateSubtree(final Element parent,
final Category root,
final Set<Long> ids) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final CategoryPickerController controller = cdiUtil
.findBean(CategoryPickerController.class);
final List<Category> terms = controller.getSubCategories(root);
final Map<Long, List<Category>> children = new HashMap<>();
for (final Category term : terms) {
final Long parentId = controller
.getParentCategory(term)
.getObjectId();
final List<Category> childList;
if (children.containsKey(parentId)) {
childList = children.get(parentId);
} else {
childList = new ArrayList<>();
children.put(parentId, childList);
}
childList.add(term);
}
final Element element = generateCategory(parent, root, ids, null);
element.addAttribute("fullname", root.getName());
element.addAttribute("node-id", Long.toString(root.getObjectId()));
element.addAttribute("order", "sortKey");
if (CMSConfig.getConfig().isCategoryPickerAjaxExpandAll()) {
//recognisable attribute has to be in the XML for each snippet that
//is transformed, hence add it to the parent
element.addAttribute("expand", "all");
}
if (children.containsKey(root.getObjectId())) {
final List<Category> roots = children.get(root.getObjectId());
for (final Category category : roots) {
generateTermWithChildren(element,
category,
ids,
category.getCategoryOrder(),
children);
}
}
}
private static void generateTermWithChildren(
final Element parent,
final Category category,
final Set<Long> selected,
final Long sortKey,
final Map<Long, List<Category>> children) {
final Element element = generateCategory(parent,
category,
selected,
sortKey);
element.addAttribute("pid", category.getUniqueId());
if (children.containsKey(category.getObjectId())) {
final List<Category> childs = children.get(category.getObjectId());
for (final Category child : childs) {
if (CMSConfig.getConfig().isCategoryPickerAjaxExpandAll()) {
generateTerm(element,
child,
selected,
child.getCategoryOrder());
} else {
generateTermWithChildren(element,
child,
selected,
child.getCategoryOrder(),
children);
}
}
}
}
}

View File

@ -19,6 +19,8 @@
package org.arsdigita.cms;
import com.arsdigita.bebop.form.DHTMLEditor;
import com.arsdigita.cms.ui.authoring.ItemCategoryExtension;
import com.arsdigita.cms.ui.authoring.ItemCategoryForm;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.configuration.Configuration;
@ -369,6 +371,16 @@ public class CMSConfig {
@Setting
private int xmlCacheAge = 60 * 60 * 24;
@Setting
private String categoryAuthoringAddForm = ItemCategoryForm.class.getName();
@Setting
private String categoryAuthoringExtension = ItemCategoryExtension.class
.getName();
@Setting
private boolean categoryPickerAjaxExpandAll = false;
/**
* Max length of the description of a link (in database max length are 4000
* characters)
@ -929,4 +941,32 @@ public class CMSConfig {
this.linkDescMaxLength = linkDescMaxLength;
}
public String getCategoryAuthoringAddForm() {
return categoryAuthoringAddForm;
}
public void setCategoryAuthoringAddForm(
final String categoryAuthoringAddForm) {
this.categoryAuthoringAddForm = categoryAuthoringAddForm;
}
public String getCategoryAuthoringExtension() {
return categoryAuthoringExtension;
}
public void setCategoryAuthoringExtension(
final String categoryAuthoringExtension) {
this.categoryAuthoringExtension = categoryAuthoringExtension;
}
public boolean isCategoryPickerAjaxExpandAll() {
return categoryPickerAjaxExpandAll;
}
public void setCategoryPickerAjaxExpandAll(
final boolean categoryPickerAjaxExpandAll) {
this.categoryPickerAjaxExpandAll = categoryPickerAjaxExpandAll;
}
}

View File

@ -28,10 +28,10 @@ import org.libreccm.l10n.LocalizedString;
import org.libreccm.portation.Portable;
import org.libreccm.security.RecursivePermissions;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
@ -41,6 +41,22 @@ import java.util.Objects;
import static org.libreccm.categorization.CategorizationConstants.CAT_XML_NS;
import static org.libreccm.core.CoreConstants.DB_SCHEMA;
import javax.persistence.AssociationOverride;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.NamedEntityGraphs;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* The category entity represents a single category. Each category is part of a
* {@link Domain}. A category can be assigned to multiple {@link CcmObject}s.

View File

@ -30,17 +30,40 @@ import org.libreccm.portation.Portable;
import org.libreccm.security.RecursivePermissions;
import org.libreccm.web.CcmApplication;
import javax.persistence.*;
import javax.validation.constraints.Pattern;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.*;
import static org.libreccm.categorization.CategorizationConstants.CAT_XML_NS;
import static org.libreccm.core.CoreConstants.DB_SCHEMA;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.persistence.AssociationOverride;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.NamedEntityGraphs;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.NamedSubgraph;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
* A domain is collection of categories designed a specific purpose. This entity
* replaces the {@code Domain} entity from the old {@code ccm-ldn-terms} module