The ItemResolver is responsible for mapping a URL in a
- * particular content section to a content item.
+ *
+ * The ItemResolver is responsible for mapping a URL in a particular
+ * content section to a content item.
*
- *
As an example, here is the item resolution process for a request to
+ *
+ * As an example, here is the item resolution process for a request to
* http://yourserver/cms/cheese:
*
- *
The item resolver would be asked to map the URL stub /cheese
- * in the content section mounted at /cms to a content item. To
- * this end, the dispatcher calls the getItem method, passing in
- * the {@link com.arsdigita.cms.ContentSection} and the URL stub for the
- * item within the section, /cheese in our example. As a final
- * argument, the dispatcher passes either ContentItem.DRAFT or
- * ContentItem.LIVE to the ItemResolver, depending on
- * whether the returned item should be the live version (for public pages)
- * or the draft version (for previewing).
+ *
+ * The item resolver would be asked to map the URL stub /cheese
+ * in the content section mounted at /cms to a content item. To this
+ * end, the dispatcher calls the getItem method, passing in the
+ * {@link com.arsdigita.cms.ContentSection} and the URL stub for the item within
+ * the section, /cheese in our example. As a final argument, the
+ * dispatcher passes either ContentItem.DRAFT or
+ * ContentItem.LIVE to the ItemResolver, depending on whether
+ * the returned item should be the live version (for public pages) or the draft
+ * version (for previewing).
*
* @author Michael Pih (pihman@arsdigita.com)
* @author Stanislav Freidin (sfreidin@arsdigita.com)
@@ -60,7 +63,8 @@ public interface ItemResolver {
* @param context The use context
* @return The content item, or null if no such item exists
*/
- public ContentItem getItem(ContentSection section, String url,
+ public ContentItem getItem(ContentSection section,
+ String url,
String context);
/**
@@ -82,10 +86,11 @@ public interface ItemResolver {
* @return The URL of the item
* @see #getCurrentContext
*/
- public String generateItemURL (
- PageState state, BigDecimal itemId, String name,
- ContentSection section, String context
- );
+ public String generateItemURL(PageState state,
+ Long itemId,
+ String name,
+ ContentSection section,
+ String context);
/**
* Generates a URL for a content item.
@@ -99,10 +104,13 @@ public interface ItemResolver {
* @return The URL of the item
* @see #getCurrentContext
*/
- public String generateItemURL (
- PageState state, BigDecimal itemId, String name,
- ContentSection section, String context, String templateContext
- );
+ public String generateItemURL(PageState state,
+ Long itemId,
+ String name,
+ ContentSection section,
+ String context,
+ String templateContext
+ );
/**
* Generates a URL for a content item.
@@ -114,9 +122,10 @@ public interface ItemResolver {
* @return The URL of the item
* @see #getCurrentContext
*/
- public String generateItemURL (
- PageState state, ContentItem item, ContentSection section, String context
- );
+ public String generateItemURL(PageState state,
+ ContentItem item,
+ ContentSection section,
+ String context);
/**
* Generates a URL for a content item.
@@ -129,21 +138,22 @@ public interface ItemResolver {
* @return The URL of the item
* @see #getCurrentContext
*/
- public String generateItemURL (
- PageState state, ContentItem item, ContentSection section, String context,
- String templateContext
- );
+ public String generateItemURL(PageState state,
+ ContentItem item,
+ ContentSection section,
+ String context,
+ String templateContext);
/**
* Return a master page based on page state (and content section).
*
- * @param item The content item
+ * @param item The content item
* @param request The HTTP request
* @return The master page
*/
public CMSPage getMasterPage(ContentItem item, HttpServletRequest request)
- throws ServletException;
-
+ throws ServletException;
+
/*
* Having to stick the following methods, getTemplateFromURL, and
@@ -152,16 +162,16 @@ public interface ItemResolver {
* to be cleaned up to fix this. As it is, ItemResolver parses URL's for
* template contexts, and TemplateResolver sets the actual template contexts
* in the request.
- */
-
+ */
/**
* Finds the template context from the URL and returns it, if it is there.
* Otherwise, returns null.
+ *
* @param inUrl the URL from which to get the template context
* @return the template context, or null if there is no template context
- */
- public String getTemplateFromURL(String inUrl);
-
+ */
+ public String getTemplateFromURL(String inUrl);
+
/**
* Removes the template context from the inUrl.
*
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowser.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowser.java
new file mode 100755
index 000000000..57999f3a6
--- /dev/null
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowser.java
@@ -0,0 +1,881 @@
+/*
+ * 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.folder;
+
+import com.arsdigita.bebop.Component;
+import com.arsdigita.bebop.ControlLink;
+import com.arsdigita.bebop.Image;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.Link;
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.PaginationModelBuilder;
+import com.arsdigita.bebop.Paginator;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.bebop.Table;
+import com.arsdigita.bebop.event.ActionEvent;
+import com.arsdigita.bebop.event.ActionListener;
+import com.arsdigita.bebop.event.TableActionAdapter;
+import com.arsdigita.bebop.event.TableActionEvent;
+import com.arsdigita.bebop.event.TableActionListener;
+import com.arsdigita.bebop.parameters.StringParameter;
+import com.arsdigita.bebop.table.AbstractTableModelBuilder;
+import com.arsdigita.bebop.table.DefaultTableCellRenderer;
+import com.arsdigita.bebop.table.DefaultTableColumnModel;
+import com.arsdigita.bebop.table.TableCellRenderer;
+import com.arsdigita.bebop.table.TableColumn;
+import com.arsdigita.bebop.table.TableHeader;
+import com.arsdigita.bebop.table.TableModel;
+import com.arsdigita.cms.*;
+import com.arsdigita.cms.dispatcher.ItemResolver;
+import com.arsdigita.globalization.GlobalizedMessage;
+import com.arsdigita.kernel.KernelConfig;
+import com.arsdigita.toolbox.ui.FormatStandards;
+import com.arsdigita.util.Assert;
+
+import org.apache.log4j.Logger;
+import org.libreccm.auditing.CcmRevision;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import javax.servlet.ServletException;
+
+import org.libreccm.categorization.Categorization;
+import org.libreccm.categorization.Category;
+import org.libreccm.categorization.CategoryManager;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.libreccm.configuration.ConfigurationManager;
+import org.libreccm.core.CcmObject;
+import org.libreccm.security.PermissionChecker;
+import org.librecms.CmsConstants;
+import org.librecms.contentsection.ContentItem;
+import org.librecms.contentsection.ContentItemManager;
+import org.librecms.contentsection.ContentItemRepository;
+import org.librecms.contentsection.ContentSection;
+import org.librecms.contentsection.ContentSectionManager;
+
+import java.util.Date;
+
+/**
+ * Browse folders and items. If the user clicks on a folder, the folder
+ * selection model is updated. If the user clicks on any other item, an separate
+ * item selection model is updated.
+ *
+ * @author Jens Pelzetter
+ * @author Sören Bernstein
+ * @author David Lutterkort
+ */
+public class FolderBrowser extends Table {
+
+ private static final Logger s_log = Logger.getLogger(FolderBrowser.class);
+ private static GlobalizedMessage[] s_headers = {
+ globalize("cms.ui.folder.name"),
+ globalize("cms.ui.folder.languages"),
+ globalize("cms.ui.folder.title"),
+ globalize("cms.ui.folder.additionalInfo"),
+ globalize("cms.ui.folder.type"),
+ globalize("cms.ui.folder.creation_date"),
+ globalize("cms.ui.folder.last_modified"),
+ globalize("cms.ui.folder.action"),
+ globalize("cms.ui.folder.index")};
+ private static GlobalizedMessage[] s_noIndexHeaders = {
+ globalize("cms.ui.folder.name"),
+ globalize("cms.ui.folder.languages"),
+ globalize("cms.ui.folder.title"),
+ globalize("cms.ui.folder.additionalInfo"),
+ globalize("cms.ui.folder.type"),
+ globalize("cms.ui.folder.creation_date"),
+ globalize("cms.ui.folder.last_modified"),
+ globalize("cms.ui.folder.action")};
+ private static final String SORT_ACTION_UP = "sortActionUp";
+ private static final String SORT_ACTION_DOWN = "sortActionDown";
+ private FolderSelectionModel m_currentFolder;
+ private TableActionListener m_folderChanger;
+ private TableActionListener m_deleter;
+ private TableActionListener m_indexChanger;
+ private TableColumn m_nameColumn;
+ private TableColumn m_deleteColumn;
+ private TableColumn m_indexColumn;
+ private final static String SORT_KEY_NAME = "name";
+ private final static String SORT_KEY_TITLE = "title";
+ private final static String SORT_KEY_LAST_MODIFIED_DATE = "lastModified";
+ private final static String SORT_KEY_CREATION_DATE = "creationDate";
+ private StringParameter m_sortType = new StringParameter("sortType");
+ private StringParameter m_sortDirection = new StringParameter("sortDirn");
+ private StringParameter m_aToZfilter = null;
+ private StringParameter m_filter = null;
+ private FolderManipulator.FilterForm m_filterForm;
+ private long m_folderSize;
+
+ public FolderBrowser(FolderSelectionModel currentFolder) {
+ //super(new FolderTableModelBuilder(), s_headers);
+ super();
+ m_sortType.setDefaultValue(SORT_KEY_NAME);
+ m_sortDirection.setDefaultValue(SORT_ACTION_UP);
+
+ setModelBuilder(new FolderTableModelBuilder(currentFolder));
+ setColumnModel(new DefaultTableColumnModel(hideIndexColumn()
+ ? s_noIndexHeaders
+ : s_headers));
+ setHeader(new TableHeader(getColumnModel()));
+
+ m_currentFolder = currentFolder;
+
+ /*
+ *
+ * This code should be uncommented if the desired behaviour is for a
+ * change of folder to cause reversion to default ordering of contained
+ * items (by name ascending). Our feeling is that the user selected
+ * ordering should be retained for the duration of the folder browsing
+ * session. If anyone wants this alternative behaviour it should be
+ * brought in under the control of a config parameter.
+ *
+ * m_currentFolder.addChangeListener(new ChangeListener() {
+ *
+ * public void stateChanged(ChangeEvent e) { PageState state =
+ * e.getPageState(); state.setValue(m_sortType,
+ * m_sortType.getDefaultValue()); state.setValue(m_sortDirection,
+ * m_sortDirection.getDefaultValue());
+ *
+ * }});
+ */
+ setClassAttr("dataTable");
+
+ getHeader().setDefaultRenderer(
+ new com.arsdigita.cms.ui.util.DefaultTableCellRenderer());
+
+ m_nameColumn = getColumn(0);
+ m_nameColumn.setCellRenderer(new NameCellRenderer());
+ m_nameColumn.setHeaderRenderer(new HeaderCellRenderer(SORT_KEY_NAME));
+ getColumn(1).setCellRenderer(new LanguagesCellRenderer());
+ getColumn(2).setHeaderRenderer(new HeaderCellRenderer(SORT_KEY_TITLE));
+ getColumn(5).setHeaderRenderer(new HeaderCellRenderer(
+ SORT_KEY_CREATION_DATE));
+ getColumn(6).setHeaderRenderer(new HeaderCellRenderer(
+ SORT_KEY_LAST_MODIFIED_DATE));
+ m_deleteColumn = getColumn(7);
+ m_deleteColumn.setCellRenderer(new ActionCellRenderer());
+ m_deleteColumn.setAlign("center");
+ m_folderChanger = new FolderChanger();
+ addTableActionListener(m_folderChanger);
+
+ m_deleter = new ItemDeleter();
+ addTableActionListener(m_deleter);
+
+ setEmptyView(new Label(globalize("cms.ui.folder.no_items")));
+
+ Assert.exists(m_currentFolder.getStateParameter());
+ }
+
+ @Override
+ public void register(Page p) {
+ super.register(p);
+
+ p.addComponentStateParam(this, m_currentFolder.getStateParameter());
+ p.addComponentStateParam(this, m_sortType);
+ p.addComponentStateParam(this, m_sortDirection);
+ p.addActionListener(new ActionListener() {
+
+ public void actionPerformed(ActionEvent e) {
+ final PageState state = e.getPageState();
+
+ if (state.isVisibleOnPage(FolderBrowser.this)) {
+ showHideFolderActions(state);
+ }
+ }
+
+ });
+ }
+
+ private void showHideFolderActions(PageState state) {
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final PermissionChecker permissionChecker = cdiUtil.findBean(
+ PermissionChecker.class);
+ Category folder = (Category) m_currentFolder.getSelectedObject(state);
+ Assert.exists(folder);
+
+ final boolean canDelete = permissionChecker.isPermitted(
+ CmsConstants.PRIVILEGE_ITEMS_DELETE, folder);
+ m_deleteColumn.setVisible(state, canDelete);
+ }
+
+ @Override
+ public void respond(PageState state) throws ServletException {
+ String key = state.getControlEventName();
+ String value = state.getControlEventValue();
+ if (SORT_ACTION_UP.equals(key)) {
+ state.setValue(m_sortType, value);
+ state.setValue(m_sortDirection, SORT_ACTION_UP);
+ } else if (SORT_ACTION_DOWN.equals(key)) {
+ state.setValue(m_sortType, value);
+ state.setValue(m_sortDirection, SORT_ACTION_DOWN);
+ } else {
+ super.respond(state);
+ //throw new ServletException("Unknown control event: " + key);
+ }
+ }
+
+ public FolderSelectionModel getFolderSelectionModel() {
+ return m_currentFolder;
+ }
+
+ protected void setFilterForm(FolderManipulator.FilterForm filterForm) {
+ m_filterForm = filterForm;
+ }
+
+ protected void setAtoZfilterParameter(StringParameter aToZfilter) {
+ m_aToZfilter = aToZfilter;
+ }
+
+ protected void setFilterParameter(StringParameter filter) {
+ m_filter = filter;
+ }
+
+ protected long getFolderSize() {
+ return m_folderSize;
+ }
+
+ private class FolderTableModelBuilder
+ extends AbstractTableModelBuilder
+ implements PaginationModelBuilder,
+ FolderManipulator.FilterFormModelBuilder {
+
+ private final FolderSelectionModel folderModel;
+ private final FolderBrowser folderBrowser;
+ private final ContentItemRepository itemRepo;
+ private final ConfigurationManager confManager;
+ private final ContentSectionManager sectionManager;
+
+ public FolderTableModelBuilder(final FolderSelectionModel folderModel) {
+ this(folderModel, null);
+ }
+
+ public FolderTableModelBuilder(final FolderSelectionModel folderModel,
+ final FolderBrowser folderBrowser) {
+ this.folderModel = folderModel;
+ this.folderBrowser = folderBrowser;
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ itemRepo = cdiUtil.findBean(ContentItemRepository.class);
+ confManager = cdiUtil.findBean(ConfigurationManager.class);
+ sectionManager = cdiUtil.findBean(ContentSectionManager.class);
+ }
+
+ @Override
+ public TableModel makeModel(final Table table, final PageState state) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public int getTotalSize(final Paginator paginator,
+ final PageState state) {
+ final Category folder = (Category) folderModel.getSelectedObject(
+ state);
+
+
+ /*
+ SELECT c.categorizedObject FROM Categorization c "
+ + "WHERE c.category = :folder "
+ + "AND TYPE(c.categorizedObject) IN ContentItem"
+ + "AND (LOWER(c.categorizationObject.displayName) LIKE CONCAT(LOWER(:name), '%') "
+ 44+ "OR LOWER(c.categorizedObject.name.value) LIKE CONCAT(:name), '%')
+ */
+ final CriteriaBuilder criteriaBuilder = itemRepo.
+ getCriteriaBuilder();
+ final CriteriaQuery query = criteriaBuilder.
+ createQuery(ContentItem.class);
+ final Root root = query.from(Categorization.class);
+ final Root itemRoot = query.from(ContentItem.class);
+ //final List predicates = new ArrayList<>();
+ final Predicate categoryPredicate = criteriaBuilder.equal(
+ root.get("Categorization.category"), folder);
+ final Predicate typePredicate = criteriaBuilder.equal(
+ itemRoot.type(), ContentItem.class);
+ final List filters = new ArrayList<>();
+ final KernelConfig kernelConfig = confManager.findConfiguration(
+ KernelConfig.class);
+ final Locale defaultLocale = new Locale(kernelConfig.
+ getDefaultLanguage());
+ if (state.getValue(m_aToZfilter) != null) {
+ filters.add(criteriaBuilder.like(criteriaBuilder.lower(
+ root.get("Categorization.categorizedObject.displayName")),
+ String.format("%s%%",
+ ((String) state.
+ getValue(
+ m_aToZfilter)).
+ toLowerCase(
+ defaultLocale))));
+ filters.add(criteriaBuilder.like(criteriaBuilder.lower(
+ root.get("Categorization.categoriziedObject.name.value")),
+ String.format("%s%%",
+ (String) state.
+ getValue(
+ m_aToZfilter))
+ .toLowerCase(defaultLocale)));
+ }
+
+ if (state.getValue(m_filter) != null) {
+ filters.add(criteriaBuilder.like(criteriaBuilder.lower(
+ root.get("Categorization.categorizedObject.displayName")),
+ String.format("%s%%",
+ ((String) state.
+ getValue(
+ m_filter)))));
+ filters.add(criteriaBuilder.like(criteriaBuilder.lower(
+ root.get("Categorization.categorizedObject.name.value")),
+ String.format("%s%%",
+ ((String) state.
+ getValue(
+ m_filter)))));
+ }
+
+ final Predicate filtersPredicate = criteriaBuilder.or(filters.
+ toArray(new Predicate[filters.size()]));
+ final Predicate predicates = criteriaBuilder.and(categoryPredicate,
+ typePredicate,
+ filtersPredicate);
+
+ query.where(predicates).select(itemRoot);
+
+ return itemRepo.executeCriteriaQuery(query.where(predicates).select(
+ itemRoot)).size();
+ }
+
+ @Override
+ public boolean isVisible(final PageState state) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public long getFolderSize(final PageState state) {
+ return itemRepo.countItemsInFolder((Category) folderModel.
+ getSelectedObject(state));
+ }
+
+ }
+
+ private class HeaderCellRenderer
+ extends com.arsdigita.cms.ui.util.DefaultTableCellRenderer {
+
+ private String m_key;
+
+ public HeaderCellRenderer(String key) {
+ super(true);
+ m_key = key;
+ }
+
+ @Override
+ public Component getComponent(final Table table, final PageState state,
+ Object value,
+ boolean isSelected, Object key,
+ int row, int column) {
+ String headerName = (String) ((GlobalizedMessage) value).localize();
+ String sortKey = (String) state.getValue(m_sortType);
+ final boolean isCurrentKey = sortKey.equals(m_key);
+ final String currentSortDirection = (String) state.getValue(
+ m_sortDirection);
+ String imageURLStub;
+
+ if (SORT_ACTION_UP.equals(currentSortDirection)) {
+ imageURLStub = "gray-triangle-up.gif";
+ } else {
+ imageURLStub = "gray-triangle-down.gif";
+ }
+
+ ControlLink cl = new ControlLink(headerName) {
+
+ @Override
+ public void setControlEvent(PageState ps) {
+ String sortDirectionAction;
+ // by default, everything sorts "up" unless it
+ // is the current key and it is already pointing up
+ if (SORT_ACTION_UP.equals(currentSortDirection)
+ && isCurrentKey) {
+ sortDirectionAction = SORT_ACTION_DOWN;
+ } else {
+ sortDirectionAction = SORT_ACTION_UP;
+ }
+ ps.setControlEvent(table,
+ sortDirectionAction,
+ m_key);
+ }
+
+ };
+ Label l = new Label();
+ l.setLabel(headerName);
+ l.setClassAttr("folderBrowserLink");
+ l.setOutputEscaping(false);
+ l.setFontWeight(Label.BOLD);
+
+ SimpleContainer container = new SimpleContainer();
+ container.add(l);
+ if (isCurrentKey) {
+ Image image = new Image("/assets/" + imageURLStub);
+ image.setBorder("0");
+ container.add(image);
+ }
+ cl.setChild(container);
+ return cl;
+ }
+
+ }
+
+ /**
+ * Produce links to view an item or control links for folders to change into
+ * the folder.
+ */
+ private class NameCellRenderer extends DefaultTableCellRenderer {
+
+ public NameCellRenderer() {
+ super(true);
+ }
+
+ @Override
+ public Component getComponent(Table table,
+ PageState state,
+ Object value,
+ boolean isSelected,
+ Object key,
+ int row,
+ int column) {
+
+ final ContentItem item = (ContentItem) value;
+ String name = item.getDisplayName();
+// final ContentSection section = item.getContentType().
+// getContentSection();
+ final ContentSection section = CMS.getContext().getContentSection();
+ final ContentSectionManager sectionManager = CdiUtil.createCdiUtil()
+ .findBean(ContentSectionManager.class);
+ final ItemResolver itemResolver = sectionManager.getItemResolver(
+ section);
+
+ return new Link(name,
+ itemResolver.generateItemURL(
+ state,
+ item.getObjectId(),
+ name,
+ section,
+ item.getVersion().name()));
+
+ }
+
+ }
+
+ /**
+ * Added by: Sören Bernstein
+ *
+ * Produce links to view an item in a specific language and show all
+ * existing language version and the live status in the folder browser.
+ */
+ private class LanguagesCellRenderer extends DefaultTableCellRenderer {
+
+ public LanguagesCellRenderer() {
+ super(true);
+ }
+
+ @Override
+ public Component getComponent(Table table,
+ PageState state,
+ Object value,
+ boolean isSelected,
+ Object key,
+ int row,
+ int column) {
+
+ final ContentItem item = (ContentItem) value;
+ String name = item.getDisplayName();
+
+ final SimpleContainer container = new SimpleContainer();
+ final ContentSection section = CMS.getContext().getContentSection();
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final ContentItemManager itemManager = cdiUtil.findBean(
+ ContentItemManager.class);
+ final ContentSectionManager sectionManager = cdiUtil.findBean(
+ ContentSectionManager.class);
+ final ItemResolver itemResolver = sectionManager.getItemResolver(
+ section);
+
+ item.getName().getAvailableLocales().forEach(locale -> {
+ final String lang = locale.toString();
+ final StringBuilder fontWeight = new StringBuilder(2);
+ final StringBuilder styleClasses = new StringBuilder(20);
+ if (itemManager.isLive(item)) {
+ fontWeight.append(Label.BOLD);
+ styleClasses.append("live ");
+ }
+
+ final Label langLabel = new Label(lang);
+ langLabel.setFontWeight(fontWeight.toString().trim());
+ langLabel.setClassAttr(styleClasses.toString().trim());
+
+ container.add(new Link(
+ langLabel,
+ itemResolver.generateItemURL(state,
+ item.getObjectId(),
+ name,
+ section,
+ item.getVersion().name())));
+ });
+
+ return container;
+ }
+
+ }
+
+ /**
+ * Produce delete links for items and non-empty folders.
+ */
+ private static class ActionCellRenderer implements TableCellRenderer {
+
+ private static final Label s_noAction;
+ private static final ControlLink s_link;
+ private static final Logger logger = Logger.getLogger(
+ ActionCellRenderer.class);
+
+ static {
+ logger.debug("Static initializer is starting...");
+ s_noAction = new Label(" ", false);
+ s_noAction.lock();
+ s_link = new ControlLink(
+ new Label(globalize("cms.ui.folder.delete")));
+ s_link.setConfirmation(
+ globalize("cms.ui.folder.delete_confirmation"));
+ logger.debug("Static initializer finished.");
+ }
+
+ @Override
+ public Component getComponent(Table table, PageState state, Object value,
+ boolean isSelected, Object key,
+ int row, int column) {
+ if (((Boolean) value)) {
+ return s_link;
+ } else {
+ return s_noAction;
+ }
+ }
+
+ }
+
+ private final class IndexToggleRenderer implements TableCellRenderer {
+
+ @Override
+ public Component getComponent(Table table,
+ PageState state,
+ Object value,
+ boolean isSelected,
+ Object key,
+ int row,
+ int column) {
+
+ if (value == null) {
+ return new Label(new GlobalizedMessage(
+ "cms.ui.folder.na",
+ CmsConstants.CMS_FOLDER_BUNDLE));
+ }
+ ControlLink link = new ControlLink("");
+
+ if (((Boolean) value)) {
+ link.setClassAttr("checkBoxChecked");
+ } else {
+ link.setClassAttr("checkBoxUnchecked");
+ }
+
+ return link;
+ }
+
+ }
+
+// Deletes an item
+ private class ItemDeleter extends TableActionAdapter {
+
+ @Override
+ public void cellSelected(TableActionEvent e) {
+ int col = e.getColumn();
+
+ if (m_deleteColumn != getColumn(col)) {
+ return;
+ }
+
+ PageState s = e.getPageState();
+ long itemId = Long.parseLong(e.getRowKey().toString());
+
+ final ContentItemRepository itemRepo = CdiUtil.createCdiUtil().
+ findBean(ContentItemRepository.class);
+ final Optional item = itemRepo.findById(itemId);
+ if (item.isPresent()) {
+ itemRepo.delete(item.get());
+ }
+
+ ((Table) e.getSource()).clearSelection(s);
+ }
+
+ }
+
+ /**
+ * Table model around ItemCollection
+ */
+ private static class FolderTableModel implements TableModel {
+
+ private static final int NAME = 0;
+ private static final int LANGUAGES = 1;
+ private static final int TITLE = 2;
+ private static final int ADDITIONAL_INFO = 3;
+ private static final int TYPE = 4;
+ private static final int CREATION_DATE = 5;
+ private static final int LAST_MODIFIED = 6;
+ private static final int DELETABLE = 7;
+ private static final int IS_INDEX = 8;
+ private PageState m_state;
+ private FolderBrowser m_table;
+ private List m_itemColl;
+ private Category m_fol;
+ private Long m_folIndexID;
+ private final ContentItemRepository itemRepo;
+ private final ContentItemManager itemManager;
+ private final CategoryManager categoryManager;
+ private int index = -1;
+
+ //old constructor before using paginator
+ //public FolderTableModel(Folder folder) {
+ //m_itemColl = folder.getItems();
+ //}
+ public FolderTableModel(FolderBrowser table,
+ PageState state,
+ List itemColl) {
+ m_state = state;
+ m_table = table;
+ m_itemColl = itemColl;
+
+ m_fol = (Category) table.getFolderSelectionModel()
+ .getSelectedObject(state);
+
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ itemRepo = cdiUtil.findBean(ContentItemRepository.class);
+ itemManager = cdiUtil.findBean(ContentItemManager.class);
+ categoryManager = cdiUtil.findBean(CategoryManager.class);
+
+ if (!hideIndexColumn()) {
+ final Optional indexItem = categoryManager
+ .getIndexObject(m_fol);
+ if (indexItem.isPresent()) {
+ m_folIndexID = indexItem.get().getObjectId();
+ } else {
+ m_folIndexID = null;
+ }
+ }
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 7;
+ }
+
+ @Override
+ public boolean nextRow() {
+ index++;
+ return index < m_itemColl.size();
+ }
+
+ @Override
+ public Object getElementAt(int columnIndex) {
+ switch (columnIndex) {
+ case NAME:
+ return m_itemColl.get(index);
+ case LANGUAGES:
+ return m_itemColl.get(index);
+ case TITLE:
+ return m_itemColl.get(index).getDisplayName();
+ case ADDITIONAL_INFO:
+ return "";
+ case TYPE:
+ return m_itemColl.get(index).getContentType().getLabel()
+ .getValue();
+ case CREATION_DATE: {
+ final CcmRevision firstRevision = itemRepo
+ .retrieveFirstRevision(
+ m_itemColl.get(index), m_itemColl.get(index)
+ .getObjectId());
+ if (firstRevision == null) {
+ return "--";
+ } else {
+ return FormatStandards.formatDate(new Date(firstRevision
+ .getTimestamp()));
+ }
+ }
+ case LAST_MODIFIED: {
+ final CcmRevision currentRevision = itemRepo
+ .retrieveCurrentRevision(
+ m_itemColl.get(index),
+ m_itemColl.get(index).getObjectId());
+ if (currentRevision == null) {
+ return "--";
+ } else {
+ return FormatStandards.formatDate(new Date(
+ currentRevision.getTimestamp()));
+ }
+ }
+ case DELETABLE:
+ return isDeletable();
+ case IS_INDEX: {
+ if (hideIndexColumn()) {
+ throw new IndexOutOfBoundsException(
+ "Column index " + columnIndex
+ + " not in table model.");
+ }
+ if (m_folIndexID == null) {
+ return false;
+ }
+ return m_folIndexID.compareTo(
+ m_itemColl.get(index).getObjectId()) == 0;
+ }
+ default:
+ throw new IndexOutOfBoundsException("Column index "
+ + columnIndex
+ + " not in table model.");
+ }
+ }
+
+ public boolean isDeletable() {
+ if (s_log.isDebugEnabled()) {
+ s_log.debug("Checking to see if " + this + " is deletable");
+ }
+
+// if (m_itemColl.isFolder()) {
+//
+// if (!m_itemColl.hasChildren()) {
+// if (s_log.isDebugEnabled()) {
+// s_log.debug(
+// "The item is an empty folder; it may be deleted");
+// }
+// return true;
+//
+// } else {
+//
+// if (s_log.isDebugEnabled()) {
+// s_log.debug(
+// "The folder is not empty; it cannot be deleted");
+// }
+// return false;
+//
+// }
+// } else
+ if (itemManager.isLive(m_itemColl.get(index))) {
+
+ if (s_log.isDebugEnabled()) {
+ s_log.debug(
+ "This item has a live instance; it cannot be deleted");
+ }
+ return false;
+ }
+
+ if (s_log.isDebugEnabled()) {
+ s_log.debug(
+ "The item is not a folder and doesn't have a live instance; it may be deleted");
+ }
+ return true;
+ }
+
+ public Object getKeyAt(int columnIndex) {
+ // Note: Folders were marked by negative IDs
+ return m_itemColl.get(index).getObjectId();
+ }
+
+ }
+
+ private class FolderChanger extends TableActionAdapter {
+
+ @Override
+ public void cellSelected(TableActionEvent e) {
+ PageState s = e.getPageState();
+ int col = e.getColumn().intValue();
+
+ if (m_nameColumn != getColumn(col)) {
+ return;
+ }
+ String key = (String) e.getRowKey();
+ if (key.startsWith("-")) { // XXX dirty dirty
+ clearSelection(s);
+ getFolderSelectionModel().setSelectedKey(
+ s, Long.parseLong(key.substring(1)));
+ }
+ }
+
+ }
+
+// private class IndexChanger extends TableActionAdapter {
+//
+// private FolderSelectionModel m_fol;
+//
+// public IndexChanger(FolderSelectionModel fol) {
+// super();
+// m_fol = fol;
+// }
+//
+// @Override
+// public void cellSelected(TableActionEvent e) {
+// PageState state = e.getPageState();
+//
+// BigDecimal rowkey = new BigDecimal((String) e.getRowKey());
+// if (rowkey == null) {
+// return;
+// }
+//
+// try {
+// ContentBundle contentItem = new ContentBundle(rowkey);
+//
+// Folder folder = (Folder) m_fol.getSelectedObject(state);
+//
+// ContentBundle currentIndexItem = (ContentBundle) folder.
+// getIndexItem();
+// if (currentIndexItem == null || (currentIndexItem.getID().
+// compareTo(contentItem.getID())
+// != 0)) {
+// folder.setIndexItem(contentItem);
+// } else {
+// folder.removeIndexItem();
+// }
+// folder.save();
+// } catch (DataObjectNotFoundException donfe) {
+// // Do nothing
+// }
+// }
+//
+// }
+
+ /**
+ * Getting the GlobalizedMessage using a CMS Class targetBundle.
+ *
+ * @param key The resource key @pre ( key != null )
+ */
+ private static GlobalizedMessage globalize(String key) {
+ return new GlobalizedMessage(key, CmsConstants.CMS_FOLDER_BUNDLE);
+
+ }
+
+ private static boolean hideIndexColumn() {
+ return true;
+ }
+
+}
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java
similarity index 68%
rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java.off
rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java
index 896819431..63209561f 100755
--- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java.off
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderManipulator.java
@@ -61,36 +61,11 @@ import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.tree.TreeCellRenderer;
import com.arsdigita.cms.CMS;
-import com.arsdigita.cms.CMSConfig;
-import com.arsdigita.cms.ContentBundle;
-import com.arsdigita.cms.ContentItem;
-import com.arsdigita.cms.ContentSection;
-import com.arsdigita.cms.ContentTypeLifecycleDefinition;
-import com.arsdigita.cms.Folder;
-import com.arsdigita.cms.ItemCollection;
-import com.arsdigita.cms.SecurityManager;
-import com.arsdigita.cms.lifecycle.LifecycleDefinition;
-import com.arsdigita.cms.ui.lifecycle.PublishLock;
-import com.arsdigita.cms.util.GlobalizationUtil;
-import com.arsdigita.domain.DataObjectNotFoundException;
-import com.arsdigita.domain.DomainObjectFactory;
-import com.arsdigita.kernel.ACSObject;
-import com.arsdigita.kernel.Party;
-import com.arsdigita.kernel.PartyCollection;
-import com.arsdigita.kernel.User;
-import com.arsdigita.notification.Notification;
-import com.arsdigita.persistence.CompoundFilter;
-import com.arsdigita.persistence.DataCollection;
-import com.arsdigita.persistence.Filter;
-import com.arsdigita.persistence.OID;
-import com.arsdigita.persistence.SessionManager;
-import com.arsdigita.toolbox.GlobalisationUtil;
+import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.toolbox.ui.ActionGroup;
import com.arsdigita.util.Assert;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.web.Web;
-import com.arsdigita.workflow.simple.TaskException;
-import com.arsdigita.workflow.simple.Workflow;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
@@ -99,24 +74,37 @@ import org.apache.log4j.Logger;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import javax.persistence.TypedQuery;
+import org.arsdigita.cms.CMSConfig;
+import org.libreccm.categorization.Category;
+import org.libreccm.categorization.CategoryManager;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.libreccm.security.PermissionChecker;
+import org.libreccm.security.Shiro;
+import org.libreccm.security.User;
+import org.librecms.CmsConstants;
+import org.librecms.contentsection.ContentItem;
+import org.librecms.contentsection.ContentItemManager;
+import org.librecms.contentsection.ContentItemRepository;
+import org.librecms.contentsection.ContentSectionConfig;
/**
* Browse folders and manipulate them with various actions (move/copy/delete).
*
* @author David Lutterkort
- * @version $Id: FolderManipulator.java 1940 2009-05-29 07:15:05Z terry $
+ * @version $Id$
*/
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
public class FolderManipulator extends SimpleContainer implements
- //FormProcessListener,
- //FormValidationListener,
- //FormSubmissionListener,
- Resettable {
+ //FormProcessListener,
+ //FormValidationListener,
+ //FormSubmissionListener,
+ Resettable {
//public static final String RESOURCE_BUNDLE = "com.arsdigita.cms.ui.folder.CMSFolderResources";
- private final GlobalisationUtil globalizationUtil = new com.arsdigita.toolbox.GlobalisationUtil(
- "com.arsdigita.cms.ui.folder.CMSFolderResources");
- private static final Logger LOGGER = Logger.getLogger(FolderManipulator.class);
+ private static final Logger LOGGER = Logger.getLogger(
+ FolderManipulator.class);
private static final String ATOZ_FILTER_PARAM = "aToZfilter";
private static final String ACTION_PARAM = "act";
private static final String FILTER_PARAM = "filter";
@@ -128,7 +116,7 @@ public class FolderManipulator extends SimpleContainer implements
//private static final String UNPUBLISH = "UnPublish";
private final ArrayParameter sourcesParam = new ArrayParameter(
- new BigDecimalParameter(SOURCES_PARAM));
+ new BigDecimalParameter(SOURCES_PARAM));
private final StringParameter actionParam = new StringParameter(ACTION_PARAM);
;
/**
@@ -138,9 +126,10 @@ public class FolderManipulator extends SimpleContainer implements
private final ItemView itemView;
private final TargetSelector targetSelector = new TargetSelector();
//private final PublishDialog publishDialog = new PublishDialog();
-
+
private FilterForm filterForm;
- private final StringParameter atozFilterParam = new StringParameter(ATOZ_FILTER_PARAM);
+ private final StringParameter atozFilterParam = new StringParameter(
+ ATOZ_FILTER_PARAM);
private final StringParameter filterParam = new StringParameter(FILTER_PARAM);
public FolderManipulator(final FolderSelectionModel folderModel) {
@@ -154,12 +143,13 @@ public class FolderManipulator extends SimpleContainer implements
add(itemView);
targetSelector.addProcessListener(new TargetSelectorProcessListener());
- targetSelector.addValidationListener(new TargetSelectorValidationListener());
- targetSelector.addSubmissionListener(new TargetSelectorSubmissionListener());
+ targetSelector.addValidationListener(
+ new TargetSelectorValidationListener());
+ targetSelector.addSubmissionListener(
+ new TargetSelectorSubmissionListener());
add(targetSelector);
//publishDialog.addProcessListener(new PublishDialogProcessListener());
-
}
@Override
@@ -175,13 +165,13 @@ public class FolderManipulator extends SimpleContainer implements
}
- public final BigDecimal[] getSources(final PageState state) {
+ public final Long[] getSources(final PageState state) {
- final BigDecimal[] result = (BigDecimal[]) state.getValue(sourcesParam);
+ final Long[] result = (Long[]) state.getValue(sourcesParam);
//Return empty array instead of null.
if (result == null) {
- return new BigDecimal[0];
+ return new Long[0];
} else {
return result;
}
@@ -191,7 +181,7 @@ public class FolderManipulator extends SimpleContainer implements
return sourceFolderModel;
}
- public final Folder getTarget(final PageState state) {
+ public final Category getTarget(final PageState state) {
return targetSelector.getTarget(state);
}
@@ -210,61 +200,58 @@ public class FolderManipulator extends SimpleContainer implements
// protected final boolean isUnPublish(final PageState state) {
// return UNPUBLISH.equals(getAction(state));
// }
-
private String getAction(final PageState state) {
return (String) state.getValue(actionParam);
}
- protected void moveItems(final Folder target, final BigDecimal[] itemIds) {
+ protected void moveItems(final Category target,
+ final Long[] itemIds) {
- for (BigDecimal itemId : itemIds) {
- try {
- changeItemParent(itemId, target);
- } catch (DataObjectNotFoundException e) {
- LOGGER.warn("object not found in content move", e);
- throw new IllegalStateException(String.format("Item '%s' to move not found.",
- itemId.toString()));
+ for (Long itemId : itemIds) {
+
+ changeItemParent(itemId, target);
- }
}
}
- private void changeItemParent(final BigDecimal itemId, final Folder newParent)
- throws DataObjectNotFoundException {
+ private void changeItemParent(final Long itemId, final Category newParent) {
- final ContentItem item = new ContentItem(itemId);
- item.setParent(newParent);
- item.save();
+ //ToDo
+ throw new UnsupportedOperationException();
+// final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+// final ContentItemRepository itemRepo = cdiUtil.findBean(
+// ContentItemRepository.class);
+// final ContentItemManager itemManager = cdiUtil.findBean(
+// ContentItemManager.class);
+// final CategoryManager categoryManager = cdiUtil.findBean(
+// CategoryManager.class);
+// final ContentItem item = itemRepo.findById(itemId);
+// final Category itemFolder = itemManager.getItemFolders(item).
+// item.addCategory(newParent);
+// item.setParent(newParent);
+// item.save();
}
- protected void copyItems(final Folder target,
- final BigDecimal[] itemIds) {
+ protected void copyItems(final Category target,
+ final Long[] itemIds) {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Copying items " + Arrays.asList(itemIds) + " to " + target);
- }
- for (BigDecimal itemId : itemIds) {
-
-// ContentItem source = (ContentItem) DomainObjectFactory.newInstance(
-// new OID(ContentItem.BASE_DATA_OBJECT_TYPE, itemId));
-// Assert.exists(source, ContentItem.class);
+ //ToDo
+ throw new UnsupportedOperationException();
//
-// final ACSObject parent = source.getParent();
-// if (parent instanceof ContentBundle) {
-// source = (ContentBundle) parent;
-// }
+// if (LOGGER.isDebugEnabled()) {
+// LOGGER.debug("Copying items " + Arrays.asList(itemIds) + " to "
+// + target);
+// }
+// for (BigDecimal itemId : itemIds) {
//
-// if (LOGGER.isDebugEnabled()) {
-// LOGGER.debug("Copying item " + source);
-// }
- final ContentItem source = retrieveSourceItem(itemId);
-
- final ContentItem newItem = source.copy(target, true);
- Assert.isEqual(target, newItem.getParent());
-
- }
+// final ContentItem source = retrieveSourceItem(itemId);
+//
+// final ContentItem newItem = source.copy(target, true);
+// Assert.isEqual(target, newItem.getParent());
+//
+// }
}
// protected void publishItems(final BigDecimal[] itemIds) {
@@ -291,7 +278,6 @@ public class FolderManipulator extends SimpleContainer implements
//
// }
// }
-
// private void publish(final BigDecimal itemId) {
//
// }
@@ -385,27 +371,26 @@ public class FolderManipulator extends SimpleContainer implements
//
// thread.start();
// }
-
- private ContentItem retrieveSourceItem(final BigDecimal itemToCopyId) {
-
- ContentItem source = (ContentItem) DomainObjectFactory.newInstance(
- new OID(ContentItem.BASE_DATA_OBJECT_TYPE, itemToCopyId));
- Assert.exists(source, ContentItem.class);
-
- final ACSObject parent = source.getParent();
- if (parent instanceof ContentBundle) {
- source = (ContentBundle) parent;
- }
-
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Copying item " + source);
- }
-
- return source;
- }
-
+// private ContentItem retrieveSourceItem(final BigDecimal itemToCopyId) {
+//
+// ContentItem source = (ContentItem) DomainObjectFactory.newInstance(
+// new OID(ContentItem.BASE_DATA_OBJECT_TYPE, itemToCopyId));
+// Assert.exists(source, ContentItem.class);
+//
+// final ACSObject parent = source.getParent();
+// if (parent instanceof ContentBundle) {
+// source = (ContentBundle) parent;
+// }
+//
+// if (LOGGER.isDebugEnabled()) {
+// LOGGER.debug("Copying item " + source);
+// }
+//
+// return source;
+// }
/**
- * Returns the form that contains the folder browser and the move/copy dropdown.
+ * Returns the form that contains the folder browser and the move/copy
+ * dropdown.
*
* @return The form containing the folder browser and dropdown menu
*/
@@ -438,7 +423,8 @@ public class FolderManipulator extends SimpleContainer implements
}
@Override
- public void process(final FormSectionEvent event) throws FormProcessException {
+ public void process(final FormSectionEvent event) throws
+ FormProcessException {
final PageState state = event.getPageState();
itemView.setVisible(state, false);
@@ -455,15 +441,16 @@ public class FolderManipulator extends SimpleContainer implements
}
@Override
- public void process(final FormSectionEvent event) throws FormProcessException {
+ public void process(final FormSectionEvent event) throws
+ FormProcessException {
final PageState state = event.getPageState();
itemView.setVisible(state, true);
targetSelector.setVisible(state, false);
- final Folder folder = targetSelector.getTarget(state);
- final BigDecimal[] itemIds = getSources(state);
+ final Category folder = targetSelector.getTarget(state);
+ final Long[] itemIds = getSources(state);
if (isCopy(state)) {
copyItems(folder, itemIds);
@@ -503,7 +490,6 @@ public class FolderManipulator extends SimpleContainer implements
// }
//
// }
-
private class ItemViewValidationListener implements FormValidationListener {
public ItemViewValidationListener() {
@@ -511,26 +497,30 @@ public class FolderManipulator extends SimpleContainer implements
}
@Override
- public void validate(final FormSectionEvent event) throws FormProcessException {
+ public void validate(final FormSectionEvent event) throws
+ FormProcessException {
final PageState state = event.getPageState();
final FormData data = event.getFormData();
if (getSources(state).length <= 0) {
- data.addError(globalizationUtil.globalize("cms.ui.folder.must_select_item"));
+ data.addError("cms.ui.folder.must_select_item",
+ CmsConstants.CMS_FOLDER_BUNDLE);
}
}
}
- private class TargetSelectorValidationListener implements FormValidationListener {
+ private class TargetSelectorValidationListener implements
+ FormValidationListener {
public TargetSelectorValidationListener() {
//Nothing
}
@Override
- public void validate(final FormSectionEvent event) throws FormProcessException {
+ public void validate(final FormSectionEvent event) throws
+ FormProcessException {
final PageState state = event.getPageState();
@@ -538,70 +528,82 @@ public class FolderManipulator extends SimpleContainer implements
throw new IllegalStateException("No source items specified");
}
- final Folder target = targetSelector.getTarget(state);
+ final Category target = targetSelector.getTarget(state);
final FormData data = event.getFormData();
if (target == null) {
- data.addError(globalizationUtil.globalize(
- "cms.ui.folder.need_select_target_folder"));
+ data.addError(new GlobalizedMessage(
+ "cms.ui.folder.need_select_target_folder",
+ CmsConstants.CMS_FOLDER_BUNDLE));
//If the target is null, we can skip the rest of the checks
return;
}
if (target.equals(sourceFolderModel.getSelectedObject(state))) {
- data.addError(globalizationUtil.globalize("cms.ui.folder.not_within_same_folder"));
+ data.addError(new GlobalizedMessage(
+ "cms.ui.folder.not_within_same_folder",
+ CmsConstants.CMS_FOLDER_BUNDLE));
}
// check create item permission
- final User user = Web.getWebContext().getUser();
- final SecurityManager securityManager = CMS.getSecurityManager(state);
- if (!securityManager.canAccess(user, SecurityManager.NEW_ITEM, target)) {
- data.addError(globalizationUtil.globalize("cms.ui.folder.no_permission_for_item"));
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final Shiro shiro = cdiUtil.findBean(Shiro.class);
+ final PermissionChecker permissionChecker = cdiUtil.findBean(
+ PermissionChecker.class);
+ if (!permissionChecker.isPermitted(
+ CmsConstants.PRIVILEGE_ITEMS_CREATE_NEW, target)) {
+ data.addError("cms.ui.folder.no_permission_for_item",
+ CmsConstants.CMS_FOLDER_BUNDLE);
}
- for (BigDecimal source : getSources(state)) {
- try {
- validateItem(source, target, state, data);
- } catch (DataObjectNotFoundException ex) {
- LOGGER.warn("Object not found in validation", ex);
- throw new IllegalStateException(String.format(
- "There is no item with the id '%s'", source.toString()));
- }
+ for (Long source : getSources(state)) {
+
+ validateItem(source, target, state, data);
+
}
}
- private void validateItem(final BigDecimal itemId,
- final Folder target,
+ private void validateItem(final Long itemId,
+ final Category target,
final PageState state,
final FormData data) {
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final ContentItemRepository itemRepo = cdiUtil.findBean(
+ ContentItemRepository.class);
+ final ContentItemManager itemManager = cdiUtil.findBean(
+ ContentItemManager.class);
+ final PermissionChecker permissionChecker = cdiUtil.findBean(
+ PermissionChecker.class);
- final ContentItem item = new ContentItem(itemId);
- final String name = item.getName();
+ final ContentItem item = itemRepo.findById(itemId);
+ final String name = item.getDisplayName();
- final ItemCollection items = target.getItems();
- items.addNameFilter(name);
- if (items.next()) {
+ final long count = itemRepo.countByNameInFolder(target, name);
+ if (count > 0) {
// there is an item in the target folder that already has this name
addErrorMessage(data, "cms.ui.folder.item_already_exists", name);
}
- items.close();
- if (item.isLive() && isMove(state)) {
+ if (itemManager.isLive(item) && isMove(state)) {
addErrorMessage(data, "cms.ui.folder.item_is_live", name);
}
- final SecurityManager securityManager = CMS.getSecurityManager(state);
- final User user = Web.getWebContext().getUser();
- if ((!securityManager.canAccess(user, SecurityManager.DELETE_ITEM, item))
- && isMove(state)) {
- addErrorMessage(data, "cms.ui.folder.no_permission_for_item", name);
+ if (!(permissionChecker.isPermitted(
+ CmsConstants.PRIVILEGE_ITEMS_DELETE, item))
+ && isMove(state)) {
+ addErrorMessage(data, "cms.ui.folder.no_permission_for_item",
+ name);
}
}
}
- private void addErrorMessage(final FormData data, final String message, final String itemName) {
- data.addError(globalizationUtil.globalize(message, new Object[]{itemName}));
+ private void addErrorMessage(final FormData data,
+ final String message,
+ final String itemName) {
+ data.addError(new GlobalizedMessage(message,
+ CmsConstants.CMS_FOLDER_BUNDLE,
+ new Object[]{itemName}));
}
// @Override
@@ -615,20 +617,24 @@ public class FolderManipulator extends SimpleContainer implements
//
// }
// }
- private class TargetSelectorSubmissionListener implements FormSubmissionListener {
+ private class TargetSelectorSubmissionListener implements
+ FormSubmissionListener {
public TargetSelectorSubmissionListener() {
//Nothing
}
@Override
- public void submitted(final FormSectionEvent event) throws FormProcessException {
+ public void submitted(final FormSectionEvent event) throws
+ FormProcessException {
final PageState state = event.getPageState();
if (targetSelector.isCancelled(state)) {
reset(state);
- throw new FormProcessException(GlobalizationUtil.globalize("cms.ui.folder.cancelled"));
+ throw new FormProcessException(new GlobalizedMessage(
+ "cms.ui.folder.cancelled",
+ CmsConstants.CMS_FOLDER_BUNDLE));
}
}
@@ -671,15 +677,26 @@ public class FolderManipulator extends SimpleContainer implements
final PageState state = event.getPageState();
final Label label = (Label) event.getTarget();
final int numberOfItems = getSources(state).length;
- final Folder folder = (Folder) sourceFolderModel.getSelectedObject(state);
+ final Category folder = (Category) sourceFolderModel.
+ getSelectedObject(state);
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final CategoryManager categoryManager = cdiUtil.
+ findBean(CategoryManager.class);
+
if (isMove(state)) {
- label.setLabel(globalizationUtil.globalize(
- "cms.ui.folder.move", new Object[]{numberOfItems,
- folder.getPathNoJsp()}));
+
+ label.setLabel(new GlobalizedMessage(
+ "cms.ui.folder.move",
+ CmsConstants.CMS_FOLDER_BUNDLE,
+ new Object[]{numberOfItems,
+ categoryManager.getCategoryPath(
+ folder)}));
} else if (isCopy(state)) {
- label.setLabel(globalizationUtil.globalize(
- "cms.ui.folder.copy", new Object[]{numberOfItems,
- folder.getPathNoJsp()}));
+ label.setLabel(new GlobalizedMessage(
+ "cms.ui.folder.copy",
+ new Object[]{numberOfItems,
+ categoryManager.getCategoryPath(
+ folder)}));
}
}
@@ -702,14 +719,21 @@ public class FolderManipulator extends SimpleContainer implements
// Set things up the first time the selector gets visible
public void expose(final PageState state) {
- final Folder folder = (Folder) sourceFolderModel.getSelectedObject(state);
+ final Category folder = (Category) sourceFolderModel.
+ getSelectedObject(
+ state);
targetModel.clearSelection(state);
if (folder != null) {
- final ItemCollection items = folder.getPathInfo(true);
- while (items.next()) {
- folderTree.expand(items.getID().toString(), state);
- }
- items.close();
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final ContentItemManager itemManager = cdiUtil.findBean(
+ ContentItemManager.class);
+
+ //ToDo
+// final ItemCollection items = folder.getPathInfo(true);
+// while (items.next()) {
+// folderTree.expand(items.getID().toString(), state);
+// }
+// items.close();
}
}
@@ -718,11 +742,12 @@ public class FolderManipulator extends SimpleContainer implements
folderTree.clearSelection(state);
// FIXME: add a reset method to Tree and call that instead of this
// hack
- state.setValue(folderTree.getSelectionModel().getStateParameter(), null);
+ state.setValue(folderTree.getSelectionModel().getStateParameter(),
+ null);
}
- public Folder getTarget(final PageState state) {
- return (Folder) targetModel.getSelectedObject(state);
+ public Category getTarget(final PageState state) {
+ return (Category) targetModel.getSelectedObject(state);
}
public boolean isCancelled(final PageState state) {
@@ -769,7 +794,6 @@ public class FolderManipulator extends SimpleContainer implements
// }
//
// }
-
// The form containing the browser and the drop down for selecting an
// action
private class ItemView extends Form implements Resettable {
@@ -797,13 +821,15 @@ public class FolderManipulator extends SimpleContainer implements
folderBrowser.setAtoZfilterParameter(atozFilterParam);
folderBrowser.setFilterParameter(filterParam);
folderBrowser.setFilterForm(filterForm);
- paginator = new Paginator((PaginationModelBuilder) folderBrowser.getModelBuilder(),
- ContentSection.getConfig().getFolderBrowseListSize());
+ paginator = new Paginator(
+ (PaginationModelBuilder) folderBrowser.getModelBuilder(),
+ CMSConfig.getConfig().getFolderBrowseListSize());
panel.add(paginator);
panel.add(folderBrowser);
LOGGER.debug("Adding filter form...");
- filterForm = new FilterForm((FilterFormModelBuilder) folderBrowser.getModelBuilder());
+ filterForm = new FilterForm((FilterFormModelBuilder) folderBrowser.
+ getModelBuilder());
FolderManipulator.this.add(filterForm);
checkboxGroup = new CheckboxGroup(sourcesParam);
@@ -814,14 +840,20 @@ public class FolderManipulator extends SimpleContainer implements
final Container container = new SimpleContainer();
group.addAction(container);
- container.add(new Label(globalizationUtil.globalize("cms.ui.folder.edit_selection")));
+ container.add(new Label(new GlobalizedMessage(
+ "cms.ui.folder.edit_selection",
+ CmsConstants.CMS_FOLDER_BUNDLE)));
actionSelect = new SingleSelect(actionParam);
- actionSelect.addOption(new Option(COPY,
- new Label(globalizationUtil.globalize(
- "cms.ui.folder.copy.action"))));
- actionSelect.addOption(new Option(MOVE,
- new Label(globalizationUtil.globalize(
- "cms.ui.folder.move.action"))));
+ actionSelect.addOption(
+ new Option(COPY,
+ new Label(new GlobalizedMessage(
+ "cms.ui.folder.copy.action",
+ CmsConstants.CMS_FOLDER_BUNDLE))));
+ actionSelect.addOption(
+ new Option(MOVE,
+ new Label(new GlobalizedMessage(
+ "cms.ui.folder.move.action",
+ CmsConstants.CMS_FOLDER_BUNDLE))));
//Publishing in the folder browser only works if threaded publishing is active
// if (CMSConfig.getInstanceOf().getThreadedPublishing()) {
// actionSelect.addOption(new Option(PUBLISH,
@@ -832,7 +864,10 @@ public class FolderManipulator extends SimpleContainer implements
// "cms.ui.folder.unpublish.action"))));
// }
container.add(actionSelect);
- submit = new Submit("Go", globalizationUtil.globalize("cms.ui.folder.go"));
+ submit = new Submit("Go",
+ new GlobalizedMessage(
+ "cms.ui.folder.go",
+ CmsConstants.CMS_FOLDER_BUNDLE));
container.add(submit);
// Add a new first column to the table
@@ -872,7 +907,8 @@ public class FolderManipulator extends SimpleContainer implements
final int row,
final int column) {
final BigDecimal n = (BigDecimal) key;
- Option result = new Option(sourcesParam.marshalElement(n.abs()), "");
+ Option result = new Option(sourcesParam.marshalElement(n.abs()),
+ "");
result.setGroup(checkboxGroup);
return result;
}
@@ -904,7 +940,8 @@ public class FolderManipulator extends SimpleContainer implements
panel = new BoxPanel(BoxPanel.HORIZONTAL);
final ActionLink allLink = new ActionLink(
- globalizationUtil.globalize("cms.ui.folder.filter.all"));
+ new GlobalizedMessage("cms.ui.folder.filter.all",
+ CmsConstants.CMS_FOLDER_BUNDLE));
allLink.addActionListener(new ActionListener() {
@Override
@@ -929,11 +966,15 @@ public class FolderManipulator extends SimpleContainer implements
// });
// panel.add(link);
// }
- panel.add(new Label(globalizationUtil.globalize("cms.ui.folder.filter")));
+ panel.add(new Label(new GlobalizedMessage(
+ "cms.ui.folder.filter",
+ CmsConstants.CMS_FOLDER_BUNDLE)));
filterField = new TextField(filterParam);
panel.add(filterField);
panel.add(new Submit("filterFolderSubmit",
- globalizationUtil.globalize("cms.ui.folder.filter_do")));
+ new GlobalizedMessage(
+ "cms.ui.folder.filter_do",
+ CmsConstants.CMS_FOLDER_BUNDLE)));
add(panel);
@@ -944,25 +985,29 @@ public class FolderManipulator extends SimpleContainer implements
}
@Override
- public void process(final FormSectionEvent event) throws FormProcessException {
+ public void process(final FormSectionEvent event) throws
+ FormProcessException {
//Nothing
}
@Override
- public void init(final FormSectionEvent event) throws FormProcessException {
+ public void init(final FormSectionEvent event) throws
+ FormProcessException {
//fse.getPageState().setValue(FolderManipulator.this.m_filter, null);
//filterField.setValue(fse.getPageState(), null);
}
@Override
- public void submitted(final FormSectionEvent event) throws FormProcessException {
+ public void submitted(final FormSectionEvent event) throws
+ FormProcessException {
}
@Override
public boolean isVisible(PageState state) {
if (super.isVisible(state)
- && (modelBuilder.getFolderSize(state)
- >= CMSConfig.getInstanceOf().getFolderAtoZShowLimit())) {
+ && (modelBuilder.getFolderSize(state)
+ >= CMSConfig.getConfig().
+ getFolderAtoZShowLimit())) {
return true;
} else {
return false;
@@ -996,9 +1041,10 @@ public class FolderManipulator extends SimpleContainer implements
private RequestLocal m_invalidFolders = new RequestLocal();
/**
- * Render the folders appropriately. The selected folder is a bold label. Invalid folders
- * are plain labels. Unselected, valid folders are control links. Invalid folders are: the
- * parent folder of the sources, any of the sources, and any subfolders of the sources.
+ * Render the folders appropriately. The selected folder is a bold
+ * label. Invalid folders are plain labels. Unselected, valid folders
+ * are control links. Invalid folders are: the parent folder of the
+ * sources, any of the sources, and any subfolders of the sources.
*/
@Override
public Component getComponent(final Tree tree,
@@ -1012,60 +1058,52 @@ public class FolderManipulator extends SimpleContainer implements
// Get the list of invalid folders once per request.
ArrayList invalidFolders = (ArrayList) m_invalidFolders.get(state);
- if (invalidFolders == null) {
- // The list of invalid folders has not been set for this
- // request. Setting now.
- invalidFolders = new ArrayList();
-
- final DataCollection collection = SessionManager.getSession().retrieve(
- ContentItem.BASE_DATA_OBJECT_TYPE);
- CompoundFilter filter = collection.getFilterFactory().or();
- // The sources themselves are not valid.
- final BigDecimal[] sources = getSources(state);
-
- for (int i = 0; i < sources.length; i++) {
- invalidFolders.add(sources[i].toString());
-
- final Filter temp = filter.addFilter("id = :id" + i);
- temp.set("id" + i, sources[i]);
- }
- collection.addFilter(filter);
-
- final DataCollection folders = SessionManager.getSession().retrieve(
- Folder.BASE_DATA_OBJECT_TYPE);
- folders.addEqualsFilter(Folder.IS_DELETED, Boolean.FALSE);
-
- filter = collection.getFilterFactory().or();
- int count = 0;
- while (collection.next()) {
- filter.addFilter(Folder.ANCESTORS + " like :ancestors"
- + count + " || '%'");
- filter.set("ancestors" + count,
- collection.get(ContentItem.ANCESTORS));
- count++;
- }
- folders.addFilter(filter);
-
- while (folders.next()) {
- invalidFolders.add(folders.get(Folder.ID).toString());
- }
-
- // Get all subfolders of the sources. These are also not valid.
- /*
- DataQuery dq = SessionManager.getSession().retrieveQuery("com.arsdigita.cms.FoldersAndAllSubFolders");
- dq.setParameter("item_list", invalidFolders);
-
- while (dq.next()) {
- invalidFolders.add (dq.get("folder_id").toString());
- }
- */
- // The folder from which the sources are being moved/copied is
- // not allowed.
- invalidFolders.add(sourceFolderModel.getSelectedKey(state).toString());
-
- // Save the invalid folder list
- m_invalidFolders.set(state, invalidFolders);
- }
+// if (invalidFolders == null) {
+// // The list of invalid folders has not been set for this
+// // request. Setting now.
+// invalidFolders = new ArrayList();
+//
+// final DataCollection collection = SessionManager.getSession().
+// retrieve(
+// ContentItem.BASE_DATA_OBJECT_TYPE);
+// CompoundFilter filter = collection.getFilterFactory().or();
+// // The sources themselves are not valid.
+// final Long[] sources = getSources(state);
+//
+// for (int i = 0; i < sources.length; i++) {
+// invalidFolders.add(sources[i].toString());
+//
+// final Filter temp = filter.addFilter("id = :id" + i);
+// temp.set("id" + i, sources[i]);
+// }
+// collection.addFilter(filter);
+//
+// final DataCollection folders = SessionManager.getSession().
+// retrieve(
+// Folder.BASE_DATA_OBJECT_TYPE);
+// folders.addEqualsFilter(Folder.IS_DELETED, Boolean.FALSE);
+//
+// filter = collection.getFilterFactory().or();
+// int count = 0;
+// while (collection.next()) {
+// filter.addFilter(Folder.ANCESTORS + " like :ancestors"
+// + count + " || '%'");
+// filter.set("ancestors" + count,
+// collection.get(ContentItem.ANCESTORS));
+// count++;
+// }
+// folders.addFilter(filter);
+//
+// while (folders.next()) {
+// invalidFolders.add(folders.get(Folder.ID).toString());
+// }
+//
+// invalidFolders.add(sourceFolderModel.getSelectedKey(state).
+// toString());
+//
+// // Save the invalid folder list
+// m_invalidFolders.set(state, invalidFolders);
+// }
final Label label = new Label(value.toString());
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderTree.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderTree.java
new file mode 100755
index 000000000..df6599e5f
--- /dev/null
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderTree.java
@@ -0,0 +1,30 @@
+/*
+ * 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.folder;
+
+import com.arsdigita.bebop.Tree;
+
+public class FolderTree extends Tree {
+
+ public FolderTree(FolderSelectionModel folderSel) {
+ super(new FolderTreeModelBuilder());
+ setSelectionModel(folderSel);
+ }
+
+}
diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/util/DefaultTableCellRenderer.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/util/DefaultTableCellRenderer.java
new file mode 100755
index 000000000..4e2f3ba7e
--- /dev/null
+++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/util/DefaultTableCellRenderer.java
@@ -0,0 +1,152 @@
+/*
+ * 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.util;
+
+import com.arsdigita.bebop.Component;
+import com.arsdigita.bebop.ControlLink;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Table;
+import com.arsdigita.bebop.table.TableCellRenderer;
+import com.arsdigita.globalization.GlobalizedMessage;
+import com.arsdigita.util.Assert;
+import com.arsdigita.util.LockableImpl;
+import org.librecms.CmsConstants;
+
+/**
+ * The default renderer for table cells. This renderer is used by the
+ * {@link com.arsdigita.bebop.Table} component for rendering the table headers
+ * and cells if no other renderer is specified.
+ *
+ *
+ * This renderer can operate in two different modes: active
+ * and inactive mode. In inactive mode, all objects are rendered by
+ * converting them to a string and enclosing that string in a {@link
+ * com.arsdigita.bebop.Label}. If the renderer is in active mode, this label is
+ * further enclosed in a control link. When the user clicks on this link, the
+ * table will fire an TableActionEvent whose getKey()
+ * and getColumn() method return the values of the key
+ * and column parameters that were passed into
+ * {@link #getComponent getComponent}.
+ *
+ *
+ * In a nutshell, an active renderer will let the user click a link that causes
+ * a TableActionEvent for the corresponding cell, while an inactive
+ * renderer will display the values just as strings, thus making it impossible
+ * for the user to cause such an event.
+ *
+ * @author David Lutterkort
+ * @author Michael Pih (pihman@arsdigita.com)
+ * @see com.arsdigita.bebop.Table
+ * @see com.arsdigita.bebop.event.TableActionEvent
+ *
+ * @version $Id: DefaultTableCellRenderer.java 287 2005-02-22 00:29:02Z sskracic
+ * $
+ */
+public class DefaultTableCellRenderer extends LockableImpl
+ implements TableCellRenderer {
+
+ private boolean m_active;
+ private ThreadLocal m_label;
+ private ThreadLocal m_controlLink;
+
+ /**
+ * Creates a new table cell renderer. The table cell renderer is in inactive
+ * mode.
+ */
+ public DefaultTableCellRenderer() {
+ this(false);
+ }
+
+ /**
+ * Creates a new table cell renderer. The active argument
+ * specifies whether the renderer should be active or not.
+ *
+ * @param active true if the renderer should generate links
+ * instead of just static labels.
+ */
+ public DefaultTableCellRenderer(boolean active) {
+ m_active = active;
+ m_label = new ThreadLocal() {
+ protected Object initialValue() {
+ return new Label("");
+ }
+ };
+ m_controlLink = new ThreadLocal() {
+ protected Object initialValue() {
+ return new ControlLink((Label) m_label.get());
+ }
+ };
+ }
+
+ /**
+ * Return true if the renderer is in active mode. A rendererin
+ * active mode will enclose the objects it renders in links that, when
+ * clicked, will cause the containing table to fire a
+ * TableActionEvent.
+ *
+ * @return true if the renderer is in active mode.
+ */
+ public final boolean isActive() {
+ return m_active;
+ }
+
+ /**
+ * Set the renderer to active or inactive mode.
+ *
+ * @param v true if the renderer should operate in active mode.
+ * @pre ! isLocked()
+ */
+ public void setActive(boolean v) {
+ Assert.isUnlocked(this);
+ m_active = v;
+ }
+
+ /**
+ * Return the component that should be used to render the given
+ * value. Returns a {@link com.arsdigita.bebop.Label} if the
+ * renderer is active, and a {@link com.arsdigita.bebop.ControlLink} if the
+ * renderer is inactive.
+ *
+ * @pre table == null || table != null
+ */
+ public Component getComponent(Table table, PageState state, Object value,
+ boolean isSelected, Object key,
+ int row, int column) {
+ if (!isLocked() && table != null && table.isLocked()) {
+ lock();
+ }
+
+ Label l = (Label) m_label.get();
+ if (value == null) {
+ l.setLabel(new GlobalizedMessage("cms.ui.util.",
+ CmsConstants.CMS_BUNDLE));
+ l.setOutputEscaping(false);
+ } else {
+ l.setLabel((GlobalizedMessage) value);
+ l.setOutputEscaping(true);
+ }
+ l.setFontWeight((isSelected && m_active) ? Label.BOLD : null);
+ if (m_active && !isSelected) {
+ return (ControlLink) m_controlLink.get();
+ } else {
+ return l;
+ }
+ }
+}
diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItem.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItem.java
index 8d06dc080..4aae3c743 100644
--- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItem.java
+++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItem.java
@@ -70,8 +70,47 @@ import static org.librecms.CmsConstants.*;
@NamedQuery(
name = "ContentItem.findByFolder",
query = "SELECT c.categorizedObject FROM Categorization c "
- + "WHERE c.category = :folder"
- )
+ + "WHERE c.category = :folder "
+ + "AND TYPE(c.categorizedObject) IN ContentItem"),
+ @NamedQuery(
+ name = "ContentItem.countItemsInFolder",
+ query = "SELECT COUNT(c) FROM Categorization c "
+ + "WHERE c.category = :folder "
+ + "AND TYPE(c.categorizedObject) IN ContentItem"),
+ @NamedQuery(
+ name = "ContentItem.countByNameInFolder",
+ query = "SELECT count(c) FROM Categorization c "
+ + "WHERE c.category = :folder "
+ + "AND c.categorizedObject.displayName = :name"),
+ @NamedQuery(
+ name = "ContentItem.filterByNameAndFolder",
+ query = "SELECT c.categorizedObject FROM Categorization c "
+ + "WHERE c.category = :folder "
+ + "AND TYPE(c.categorizedObject) IN (ContentItem)"
+ + "AND (LOWER(c.categorizedObject.displayName) LIKE CONCAT(LOWER(:name), '%') "),
+ @NamedQuery(
+ name = "ContentItem.countFilterByNameAndFolder",
+ query = "SELECT count(c) FROM Categorization c "
+ + "WHERE c.category = :folder "
+ + "AND TYPE(c.categorizedObject) IN (ContentItem)"
+ + "AND LOWER(c.categorizedObject.displayName) LIKE CONCAT(LOWER(:name), '%s') "),
+ @NamedQuery(
+ name = "ContentItem.hasLiveVersion",
+ query = "SELECT (CASE WHEN COUNT(i) > 0 THEN true ELSE false END) "
+ + "FROM ContentItem i "
+ + "WHERE i.uuid = :uuid "
+ + "AND i.version = \"LIVE\""),
+ @NamedQuery(
+ name = "ContentItem.findDraftVersion",
+ query = "SELECT i FROM ContentItem i "
+ + "WHERE i.uuid = :uuid "
+ + "AND i.version = \"DRAFT\""),
+ @NamedQuery(
+ name = "ContentItem.findLiveVersion",
+ query = "SELECT i FROM ContentItem i "
+ + "WHERE i.uuid = :uuid "
+ + "AND i.version = \"LIVE\"")
+
})
public class ContentItem extends CcmObject implements Serializable,
InheritsPermissions {
@@ -258,7 +297,8 @@ public class ContentItem extends CcmObject implements Serializable,
@Override
public Optional getParent() {
final List result = getCategories().stream().filter(
- categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER.equals(
+ categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER.
+ equals(
categorization.getType()))
.collect(Collectors.toList());
diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java
index 4591657d5..c942ac4a8 100644
--- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java
+++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java
@@ -18,8 +18,14 @@
*/
package org.librecms.contentsection;
+import com.arsdigita.kernel.KernelConfig;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
import java.util.ArrayList;
import java.util.Collections;
+
import org.libreccm.categorization.Category;
import org.libreccm.workflow.WorkflowTemplate;
import org.librecms.lifecycle.LifecycleDefinition;
@@ -30,8 +36,31 @@ import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
+
import org.libreccm.categorization.Categorization;
+import org.libreccm.categorization.CategoryManager;
+import org.libreccm.categorization.ObjectNotAssignedToCategoryException;
+import org.libreccm.configuration.ConfigurationManager;
+import org.libreccm.l10n.LocalizedString;
+import org.libreccm.workflow.Workflow;
+import org.libreccm.workflow.WorkflowManager;
import org.librecms.CmsConstants;
+import org.librecms.lifecycle.Lifecycle;
+import org.librecms.lifecycle.LifecycleManager;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import javax.transaction.Transactional;
/**
*
@@ -40,6 +69,18 @@ import org.librecms.CmsConstants;
@RequestScoped
public class ContentItemManager {
+ private static final Logger LOGGER = LogManager.getLogger(
+ ContentItemManager.class);
+
+ @Inject
+ private EntityManager entityManager;
+
+ @Inject
+ private ConfigurationManager confManager;
+
+ @Inject
+ private CategoryManager categoryManager;
+
@Inject
private ContentItemRepository contentItemRepo;
@@ -49,6 +90,12 @@ public class ContentItemManager {
@Inject
private ContentSectionManager sectionManager;
+ @Inject
+ private LifecycleManager lifecycleManager;
+
+ @Inject
+ private WorkflowManager workflowManager;
+
/**
* Creates a new content item in the provided content section and folder
* with the default lifecycle and workflow.
@@ -65,6 +112,7 @@ public class ContentItemManager {
*
* @return The new content item.
*/
+ @Transactional(Transactional.TxType.REQUIRED)
public T createContentItem(
final String name,
final ContentSection section,
@@ -112,6 +160,7 @@ public class ContentItemManager {
*
* @return The new content item.
*/
+ @Transactional(Transactional.TxType.REQUIRED)
public T createContentItem(
final String name,
final ContentSection section,
@@ -119,7 +168,47 @@ public class ContentItemManager {
final WorkflowTemplate workflowTemplate,
final LifecycleDefinition lifecycleDefinition,
final Class type) {
- throw new UnsupportedOperationException();
+
+ final Optional contentType = typeRepo
+ .findByContentSectionAndClass(section, type);
+
+ if (!contentType.isPresent()) {
+ throw new IllegalArgumentException(String.format(
+ "ContentSection \"%s\" has no content type for \"%s\".",
+ section.getLabel(),
+ type.getName()));
+ }
+
+ final Lifecycle lifecycle = lifecycleManager.createLifecycle(
+ lifecycleDefinition);
+ final Workflow workflow = workflowManager.createWorkflow(
+ workflowTemplate);
+
+ final T item;
+ try {
+ item = type.newInstance();
+ } catch (InstantiationException | IllegalAccessException ex) {
+ LOGGER.error("Failed to create new content item of type \"{}\" "
+ + "in content section \"{}\".",
+ type.getName(),
+ section.getLabel());
+ throw new RuntimeException(ex);
+ }
+
+ final KernelConfig kernelConfig = confManager.findConfiguration(
+ KernelConfig.class);
+
+ item.setDisplayName(name);
+ item.getName().addValue(new Locale(kernelConfig.getDefaultLanguage()),
+ name);
+ item.setLifecycle(lifecycle);
+ item.setWorkflow(workflow);
+
+ categoryManager.addObjectToCategory(item, folder);
+
+ contentItemRepo.save(item);
+
+ return item;
}
/**
@@ -130,8 +219,22 @@ public class ContentItemManager {
* @param item The item to move.
* @param targetFolder The folder to which the item is moved.
*/
+ @Transactional(Transactional.TxType.REQUIRED)
public void move(final ContentItem item, final Category targetFolder) {
- throw new UnsupportedOperationException();
+ final ContentItem draftItem = getDraftVersion(item, item.getClass());
+ final Optional currentFolder = getItemFolder(item);
+
+ if (currentFolder.isPresent()) {
+ try {
+ categoryManager.removeObjectFromCategory(draftItem,
+ currentFolder.get());
+ } catch (ObjectNotAssignedToCategoryException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ categoryManager.addObjectToCategory(draftItem, targetFolder);
+
}
/**
@@ -144,10 +247,190 @@ public class ContentItemManager {
* original item an index is appended to the name of the
* item.
*/
+ @SuppressWarnings("unchecked")
public void copy(final ContentItem item, final Category targetFolder) {
+ final Optional contentType = typeRepo
+ .findByContentSectionAndClass(
+ item.getContentType().getContentSection(), item.getClass());
+
+ if (!contentType.isPresent()) {
+ throw new IllegalArgumentException(String.format(
+ "ContentSection \"%s\" has no content type for \"%s\".",
+ item.getContentType().getContentSection(),
+ item.getClass().getName()));
+ }
+
+ final ContentItem draftItem = getDraftVersion(item, item.getClass());
+
+ final ContentItem copy;
+ try {
+ copy = item.getClass().newInstance();
+ } catch (InstantiationException | IllegalAccessException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ copy.setContentType(contentType.get());
+
+ final Lifecycle lifecycle = lifecycleManager.createLifecycle(
+ contentType.get().getDefaultLifecycle());
+ final Workflow workflow = workflowManager.createWorkflow(contentType
+ .get().getDefaultWorkflow());
+
+ copy.setLifecycle(lifecycle);
+ copy.setWorkflow(workflow);
+
+ draftItem.getCategories().forEach(categorization -> categoryManager
+ .addObjectToCategory(copy, categorization.getCategory()));
+
+ final Optional itemFolder = getItemFolder(draftItem);
+ if (itemFolder.isPresent()) {
+ try {
+ categoryManager.removeObjectFromCategory(
+ copy, getItemFolder(draftItem).get());
+ } catch (ObjectNotAssignedToCategoryException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ categoryManager.addObjectToCategory(
+ copy,
+ targetFolder,
+ CmsConstants.CATEGORIZATION_TYPE_FOLDER);
+
+ // !!!!!!!!!!!!!!!!!!!!!
+ // ToDo copy Attachments
+ // !!!!!!!!!!!!!!!!!!!!!
+ //
+ //
+ final BeanInfo beanInfo;
+ try {
+ beanInfo = Introspector.getBeanInfo(item.getClass());
+ } catch (IntrospectionException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ for (final PropertyDescriptor propertyDescriptor : beanInfo
+ .getPropertyDescriptors()) {
+ if (propertyIsExcluded(propertyDescriptor.getName())) {
+ continue;
+ }
+
+ final Class> propType = propertyDescriptor.getPropertyType();
+ final Method readMethod = propertyDescriptor.getReadMethod();
+ final Method writeMethod = propertyDescriptor.getWriteMethod();
+
+ if (LocalizedString.class.equals(propType)) {
+ final LocalizedString source;
+ final LocalizedString target;
+ try {
+ source = (LocalizedString) readMethod.invoke(draftItem);
+ target = (LocalizedString) readMethod.invoke(copy);
+ } catch (IllegalAccessException |
+ IllegalArgumentException |
+ InvocationTargetException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ source.getAvailableLocales().forEach(
+ locale -> target.addValue(locale, source.getValue(locale)));
+ } else if (propType != null
+ && propType.isAssignableFrom(ContentItem.class)) {
+
+ final ContentItem linkedItem;
+ try {
+ linkedItem = (ContentItem) readMethod.invoke(draftItem);
+ } catch (IllegalAccessException |
+ IllegalArgumentException |
+ InvocationTargetException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ final ContentItem linkedDraftItem = getDraftVersion(
+ linkedItem, linkedItem.getClass());
+
+ try {
+ writeMethod.invoke(copy, linkedDraftItem);
+ } catch (IllegalAccessException |
+ IllegalArgumentException |
+ InvocationTargetException ex) {
+ throw new RuntimeException(ex);
+ }
+ } else if (propType != null
+ && propType.isAssignableFrom(List.class)) {
+ final List