From a7aff821200dd43645b4f1b0b8464e887bc91657 Mon Sep 17 00:00:00 2001 From: jensp Date: Mon, 11 Sep 2017 16:38:56 +0000 Subject: [PATCH] CCM NG/ccm-cms: Vaadin Prototype git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4996 8810af33-2d31-482b-a856-94f89814c4df Former-commit-id: cdf420fed064ca482af69aa2fc86163d9e9bd840 --- .../contentsection/ContentSectionConfig.java | 9 +- .../org/librecms/contentsection/Folder.java | 19 +- .../contentsection/FolderRepository.java | 25 + .../contentsection/rs/ContentSections.java | 1 + .../contenttypes/ContentTypesManager.java | 2 + .../java/org/librecms/ui/BrowseDocuments.java | 112 ++++ .../ui/BrowseDocumentsDataProvider.java | 498 ++++++++++++++++++ ...BrowseDocumentsFolderTreeDataProvider.java | 129 +++++ .../org/librecms/ui/BrowseDocumentsItem.java | 204 +++++++ .../org/librecms/ui/ContentSectionView.java | 31 +- .../ui/ContentSectionViewController.java | 52 +- .../librecms/ui/ContentSectionViewState.java | 44 ++ .../org/librecms/CmsResources.properties | 2 + .../org/librecms/CmsResources_de.properties | 2 + .../org/librecms/CmsResources_fr.properties | 2 + .../content-section/admin/load-cat.jsp | 23 + pom.xml | 2 +- 17 files changed, 1133 insertions(+), 24 deletions(-) create mode 100644 ccm-cms/src/main/java/org/librecms/ui/BrowseDocuments.java create mode 100644 ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsDataProvider.java create mode 100644 ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsFolderTreeDataProvider.java create mode 100644 ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsItem.java create mode 100644 ccm-cms/src/main/java/org/librecms/ui/ContentSectionViewState.java create mode 100644 ccm-cms/src/main/resources/templates/ccm-cms/content-section/admin/load-cat.jsp diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentSectionConfig.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentSectionConfig.java index 08d12639a..9204d3e71 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentSectionConfig.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentSectionConfig.java @@ -18,6 +18,7 @@ */ package org.librecms.contentsection; +import com.arsdigita.cms.ui.authoring.ItemCategoryStep; import com.arsdigita.cms.ui.authoring.assets.relatedinfo.RelatedInfoStep; import com.arsdigita.cms.ui.authoring.assets.images.ImageStep; @@ -123,6 +124,7 @@ public class ContentSectionConfig { @Setting private List defaultAuthoringSteps = Arrays .asList(new String[]{ + ItemCategoryStep.class.getName(), ImageStep.class.getName(), RelatedInfoStep.class.getName()}); @@ -175,12 +177,13 @@ public class ContentSectionConfig { public void setMaxAlerts(final int maxAlerts) { this.maxAlerts = maxAlerts; } - + public List getDefaultAuthoringSteps() { return new ArrayList<>(defaultAuthoringSteps); } - - public void setDefaultAuthoringSteps(final List defaultAuthoringSteps) { + + public void setDefaultAuthoringSteps( + final List defaultAuthoringSteps) { this.defaultAuthoringSteps = new ArrayList<>(defaultAuthoringSteps); } diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/Folder.java b/ccm-cms/src/main/java/org/librecms/contentsection/Folder.java index 7a1f35071..33bc11ffe 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/Folder.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/Folder.java @@ -60,18 +60,19 @@ import static org.librecms.CmsConstants.*; , @NamedQuery( name = "Folder.findSubFolders", - query = "SELECT f FROM Folder f WHERE f.parentCategory = :parent " - + "AND LOWER(f.name) LIKE :term " + query = "SELECT f " + + "FROM Folder f" + + " WHERE f.parentCategory = :parent " + "ORDER BY f.name" ) , -// @NamedQuery( -// name = "Folder.countSubFolders", -// query -// = "SELECT COUNT(f) FROM Folder f WHERE f.parentCategory = :parent " -// + "AND LOWER(f.name) LIKE :term" -// ) -// , + @NamedQuery( + name = "Folder.countSubFolders", + query = "SELECT COUNT(f) " + + "FROM Folder f " + + "WHERE f.parentCategory = :parent" + ) + , // @NamedQuery( // name = "Folder.findItems", // query = "SELECT c.categorizedObject " diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/FolderRepository.java b/ccm-cms/src/main/java/org/librecms/contentsection/FolderRepository.java index 7fe2dbfb0..a82a65192 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/FolderRepository.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/FolderRepository.java @@ -183,6 +183,31 @@ public class FolderRepository extends AbstractEntityRepository { return Optional.of(current); } + /** + * Counts the subfolders of a folder. + * + * @param parent The folder. + * + * @return The number of subfolders in the folder. + */ + public long countSubFolders(final Folder parent) { + + final TypedQuery query = getEntityManager() + .createNamedQuery("Folder.countSubFolders", Long.class); + query.setParameter("parent", parent); + + return query.getSingleResult(); + } + + public List findSubFolders(final Folder parent) { + + final TypedQuery query = getEntityManager() + .createNamedQuery("Folder.findSubFolders", Folder.class); + query.setParameter("parent", parent); + + return query.getResultList(); + } + @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) @Override diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/rs/ContentSections.java b/ccm-cms/src/main/java/org/librecms/contentsection/rs/ContentSections.java index 129a6287e..8505452dd 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/rs/ContentSections.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/rs/ContentSections.java @@ -37,6 +37,7 @@ public class ContentSections extends Application{ final Set> classes = new HashSet<>(); classes.add(Assets.class); + classes.add(ContentItems.class); classes.add(Images.class); return classes; diff --git a/ccm-cms/src/main/java/org/librecms/contenttypes/ContentTypesManager.java b/ccm-cms/src/main/java/org/librecms/contenttypes/ContentTypesManager.java index 56574a1f9..605fcd2fb 100644 --- a/ccm-cms/src/main/java/org/librecms/contenttypes/ContentTypesManager.java +++ b/ccm-cms/src/main/java/org/librecms/contenttypes/ContentTypesManager.java @@ -33,6 +33,7 @@ import java.util.stream.Collectors; import javax.annotation.PostConstruct; import javax.enterprise.context.RequestScoped; +import javax.transaction.Transactional; /** * Provides informations about the available content types. @@ -291,6 +292,7 @@ public class ContentTypesManager { * * @return A {@link ContentTypeInfo} describing the content type. */ + @Transactional(Transactional.TxType.REQUIRED) public ContentTypeInfo getContentTypeInfo(final ContentType contentType) { return getContentTypeInfo(contentType.getContentItemClass()); } diff --git a/ccm-cms/src/main/java/org/librecms/ui/BrowseDocuments.java b/ccm-cms/src/main/java/org/librecms/ui/BrowseDocuments.java new file mode 100644 index 000000000..10bcbf9a0 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/BrowseDocuments.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui; + +import com.vaadin.ui.CustomComponent; +import com.vaadin.ui.Grid; +import com.vaadin.ui.HorizontalSplitPanel; +import com.vaadin.ui.ItemCollapseAllowedProvider; +import com.vaadin.ui.Tree; +import org.librecms.contentsection.Folder; + +/** + * + * @author Jens Pelzetter + */ +public class BrowseDocuments extends CustomComponent { + + private static final long serialVersionUID = -7241214812224026430L; + + private static final String COL_DOCUMENT_CREATED = "created"; + private static final String COL_DOCUMENT_LAST_MODIFIED = "lastmodified"; + private static final String COL_DOCUMENT_NAME = "name"; + private static final String COL_DOCUMENT_TITLE = "title"; + private static final String COL_DOCUMENT_TYPE = "ttype"; + + private final ContentSectionViewController controller; + + private final Tree folderTree; + private final Grid documentsGrid; + private final BrowseDocumentsDataProvider documentsDataProvider; + private final BrowseDocumentsFolderTreeDataProvider folderTreeDataProvider; + + public BrowseDocuments(final ContentSectionViewController controller) { + + super(); + + this.controller = controller; + + folderTreeDataProvider = controller.getFolderTreeDataProvider(); + folderTree = new Tree<>(folderTreeDataProvider); + folderTree.setItemCaptionGenerator(folder -> { + return controller + .getGlobalizationHelper() + .getValueFromLocalizedString(folder.getTitle()); + }); + + documentsGrid = new Grid<>(); + documentsGrid + .addColumn(BrowseDocumentsItem::getName) + .setCaption("Name") + .setId(COL_DOCUMENT_NAME); + documentsGrid + .addColumn(BrowseDocumentsItem::getTitle) + .setCaption("Title") + .setId(COL_DOCUMENT_TITLE); + documentsGrid + .addColumn(BrowseDocumentsItem::getType) + .setCaption("Type") + .setId(COL_DOCUMENT_TYPE); + documentsGrid + .addColumn(BrowseDocumentsItem::getCreationDate) + .setCaption("Created") + .setId(COL_DOCUMENT_CREATED); + documentsGrid + .addColumn(BrowseDocumentsItem::getLastModified) + .setCaption("Last modified") + .setId(COL_DOCUMENT_LAST_MODIFIED); + documentsDataProvider = controller.getBrowseDocumentsDataProvider(); + documentsGrid.setDataProvider(documentsDataProvider); + documentsGrid.setWidth("100%"); + documentsGrid.setHeight("100%"); + + folderTree.addItemClickListener(event -> { + documentsDataProvider.setCurrentFolder(event.getItem()); + documentsDataProvider.refreshAll(); + }); + folderTree.setItemCollapseAllowedProvider(folder -> { + return folder.getParentCategory() != null; + }); + + final HorizontalSplitPanel splitPanel = new HorizontalSplitPanel( + folderTree, documentsGrid); + splitPanel.setSplitPosition(17.5f, Unit.PERCENTAGE); + splitPanel.setHeight("100%"); + super.setCompositionRoot(splitPanel); + } + + public Tree getFolderTree() { + return folderTree; + } + + public Grid getDocumentsGrid() { + return documentsGrid; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsDataProvider.java b/ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsDataProvider.java new file mode 100644 index 000000000..f7437efce --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsDataProvider.java @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui; + +import com.vaadin.cdi.ViewScoped; +import com.vaadin.data.provider.AbstractBackEndDataProvider; +import com.vaadin.data.provider.Query; +import org.libreccm.categorization.Categorization; +import org.libreccm.core.CcmObject; +import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.l10n.LocalizedTextsUtil; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.Folder; +import org.librecms.contenttypes.ContentTypeInfo; +import org.librecms.contenttypes.ContentTypesManager; + +import java.util.stream.Stream; + +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; +import javax.persistence.criteria.Subquery; +import javax.transaction.Transactional; + +/** + * + * @author Jens Pelzetter + */ +@ViewScoped +class BrowseDocumentsDataProvider + extends AbstractBackEndDataProvider { + + private static final long serialVersionUID = 7693820518000376630L; + + @Inject + private ContentSectionViewState contentSectionViewState; + + @Inject + private EntityManager entityManager; + + @Inject + private ContentTypesManager typesManager; + + @Inject + private GlobalizationHelper globalizationHelper; + + private Folder currentFolder; + + + protected Folder getCurrentFolder() { + return currentFolder; + } + + protected void setCurrentFolder(final Folder currentFolder) { + this.currentFolder = currentFolder; + } + + @Transactional(Transactional.TxType.REQUIRED) + @Override + protected Stream fetchFromBackEnd( + final Query query) { + + final Folder folder; + if (currentFolder == null) { + folder = contentSectionViewState + .getSelectedContentSection() + .getRootDocumentsFolder(); + } else { + folder = currentFolder; + } + + final CriteriaBuilder criteriaBuilder = entityManager + .getCriteriaBuilder(); + + final CriteriaQuery criteriaQuery = criteriaBuilder + .createQuery(CcmObject.class); + + final Subquery folderQuery = criteriaQuery + .subquery(Folder.class); + final Root fromFolder = folderQuery.from(Folder.class); + folderQuery.select(fromFolder); + if (query.getFilter().isPresent()) { + final String filter = query.getFilter().get(); + folderQuery.where(criteriaBuilder + .and( + criteriaBuilder.equal(fromFolder.get("parentCategory"), + folder), + criteriaBuilder.or( + criteriaBuilder.like(fromFolder.get("name"), + String.format("%s%%", filter)), + criteriaBuilder.like(fromFolder.get("displayName"), + String.format("%s%%", filter))))); + } else { + folderQuery + .where(criteriaBuilder.equal(fromFolder.get("parentCategory"), + folder)); + } + + final Subquery itemQuery = criteriaQuery + .subquery(ContentItem.class); + final Root fromItem = itemQuery.from(ContentItem.class); + final Join joinCat = fromItem + .join("categories"); + itemQuery.select(fromItem); + if (query.getFilter().isPresent()) { + final String filter = query.getFilter().get(); + itemQuery + .where(criteriaBuilder.and( + criteriaBuilder.equal(joinCat.get("category"), folder), + criteriaBuilder.or( + criteriaBuilder.like(fromItem.get("displayName"), + String.format("%s%%", filter)), + criteriaBuilder.like(fromItem.get("name"), + String.format("%s%%", filter)) + ) + )); + } else { + itemQuery + .where(criteriaBuilder.equal(joinCat.get("category"), folder)); + } + + final Root from = criteriaQuery.from(CcmObject.class); + criteriaQuery.select(from); + + criteriaQuery.where( + criteriaBuilder.or( + criteriaBuilder.in(from).value(folderQuery), + criteriaBuilder.in(from).value(itemQuery) + )); + + return entityManager + .createQuery(criteriaQuery) + .setMaxResults(query.getLimit()) + .setFirstResult(query.getOffset()) + .getResultList() + .stream() + .map(this::buildRow); + } + + private BrowseDocumentsItem buildRow(final CcmObject object) { + + final BrowseDocumentsItem row = new BrowseDocumentsItem(); + if (object instanceof Folder) { + + final Folder folder = (Folder) object; + row.setFolder(true); + row.setItemId(folder.getObjectId()); + row.setName(folder.getName()); + row.setTitle(globalizationHelper + .getValueFromLocalizedString(folder.getTitle())); + } else if (object instanceof ContentItem) { + + final ContentItem item = (ContentItem) object; + row.setCreationDate(((ContentItem) object).getCreationDate()); + row.setFolder(false); + row.setItemId(item.getObjectId()); + row.setLastModified(item.getLastModified()); + row.setName(globalizationHelper + .getValueFromLocalizedString(item.getName())); + row.setTitle(globalizationHelper + .getValueFromLocalizedString(item.getTitle())); + + final ContentTypeInfo typeInfo = typesManager + .getContentTypeInfo(item.getClass()); + final LocalizedTextsUtil textsUtil = globalizationHelper + .getLocalizedTextsUtil(typeInfo.getLabelBundle()); + row.setType(textsUtil.getText(typeInfo.getLabelKey())); + } else { + + row.setFolder(false); + row.setItemId(object.getObjectId()); + row.setName(object.getDisplayName()); + } + + return row; + } + + @Transactional(Transactional.TxType.REQUIRED) + @Override + protected int sizeInBackEnd( + final Query query) { + + final Folder folder; + if (currentFolder == null) { + folder = contentSectionViewState + .getSelectedContentSection() + .getRootDocumentsFolder(); + } else { + folder = currentFolder; + } + + final CriteriaBuilder criteriaBuilder = entityManager + .getCriteriaBuilder(); + + final CriteriaQuery criteriaQuery = criteriaBuilder + .createQuery(Long.class); + + final Subquery folderQuery = criteriaQuery + .subquery(Folder.class); + final Root fromFolder = folderQuery.from(Folder.class); + folderQuery.select(fromFolder); + if (query.getFilter().isPresent()) { + final String filter = query.getFilter().get(); + folderQuery.where(criteriaBuilder + .and( + criteriaBuilder.equal(fromFolder.get("parentCategory"), + folder), + criteriaBuilder.or( + criteriaBuilder.like(fromFolder.get("name"), + String.format("%s%%", filter)), + criteriaBuilder.like(fromFolder.get("displayName"), + String.format("%s%%", filter))))); + } else { + folderQuery + .where(criteriaBuilder.equal(fromFolder.get("parentCategory"), + folder)); + } + + final Subquery itemQuery = criteriaQuery + .subquery(ContentItem.class); + final Root fromItem = itemQuery.from(ContentItem.class); + final Join joinCat = fromItem + .join("categories"); + itemQuery.select(fromItem); + if (query.getFilter().isPresent()) { + final String filter = query.getFilter().get(); + itemQuery + .where(criteriaBuilder.and( + criteriaBuilder.equal(joinCat.get("category"), folder), + criteriaBuilder.or( + criteriaBuilder.like(fromItem.get("displayName"), + String.format("%s%%", filter)), + criteriaBuilder.like(fromItem.get("name"), + String.format("%s%%", filter)) + ) + )); + } else { + itemQuery + .where(criteriaBuilder.equal(joinCat.get("category"), folder)); + } + + final Root from = criteriaQuery.from(CcmObject.class); + criteriaQuery.select(criteriaBuilder.count(from)); + + criteriaQuery.where( + criteriaBuilder.or( + criteriaBuilder.in(from).value(folderQuery), + criteriaBuilder.in(from).value(itemQuery) + )); + + return entityManager + .createQuery(criteriaQuery) + .getSingleResult() + .intValue(); + } + +// @Override +// protected Stream fetchFromBackEnd( +// final Query query) { +// +// final int subFoldersCount = countSubFolder(currentFolder, +// query.getFilter()); +// final int itemsCount = countItems(currentFolder, query.getFilter()); +// +// final int limit = query.getLimit(); +// final int offset = query.getOffset(); +// +// final int subFoldersLimit; +// final int subFoldersOffset; +// final int itemsLimit; +// final int itemsOffset; +// if (subFoldersCount > (limit + offset)) { +// +// subFoldersLimit = limit; +// +// +// } else { +// +// } +// +// final List subFolders = fetchSubFolders(currentFolder, +// query.getFilter(), +// query.getLimit(), +// query.getOffset()); +// final List items = fetchItems(currentFolder, +// query.getFilter()); +// +// final List subFolderItems = subFolders +// .stream() +// .map(this::createBrowseDocumentsItem) +// .collect(Collectors.toList()); +// +// final List itemList = items +// .stream() +// .map(this::createBrowseDocumentsItem) +// .collect(Collectors.toList()); +// +// final List rows = new ArrayList<>(); +// rows.addAll(subFolderItems); +// rows.addAll(itemList); +// +// return rows.stream(); +// } +// +// private List fetchSubFolders(final Folder folder, +// final Optional filter, +// final int limit, +// final int offset) { +// +// final CriteriaBuilder builder = entityManager +// .getCriteriaBuilder(); +// final CriteriaQuery query = builder.createQuery(Folder.class); +// final Root from = query.from(Folder.class); +// +// if (filter.isPresent()) { +// query.where(builder +// .and(builder.equal(from.get("parentCategory"), folder), +// builder.or( +// builder.like(builder.lower(from.get("name")), +// String.format("%s%%", filter.get())), +// builder.like(builder.lower(from.get("displayName")), +// String.format("%s%%", filter.get()))))); +// } else { +// query.where(builder.equal(from.get("parentCategory"), folder)); +// } +// +// query.orderBy(builder.asc(from.get("name")), +// builder.asc(from.get("displayName"))); +// +// return entityManager +// .createQuery(query) +// .setMaxResults(limit) +// .setFirstResult(offset) +// .getResultList(); +// } +// +// private List fetchItems(final Folder folder, +// final Optional filter) { +// +// final CriteriaBuilder builder = entityManager +// .getCriteriaBuilder(); +// final CriteriaQuery query = builder +// .createQuery(ContentItem.class); +// final Root from = query.from(ContentItem.class); +// final Join join = from.join("categories"); +// +// if (filter.isPresent()) { +// query.where(builder +// .and(builder.equal(join.get("category"), folder), +// builder.or( +// builder.like(builder.lower(from.get("name")), +// String.format("%s%%", filter.get())), +// builder.like(builder.lower(from.get("displayName")), +// String.format("%s%%", filter.get()))))); +// +// } else { +// query.where(builder.equal(join.get("category"), folder)); +// } +// +// return entityManager +// .createQuery(query) +// .getResultList(); +// } +// +// private BrowseDocumentsItem createBrowseDocumentsItem( +// final Folder fromFolder) { +// +// final BrowseDocumentsItem item = new BrowseDocumentsItem(); +// item.setItemId(fromFolder.getObjectId()); +// item.setName(fromFolder.getName()); +// item.setTitle(fromFolder +// .getTitle() +// .getValue(controller.getGlobalizationHelper().getNegotiatedLocale())); +// item.setFolder(true); +// +// return item; +// } +// +// private BrowseDocumentsItem createBrowseDocumentsItem( +// final ContentItem fromItem) { +// +// final BrowseDocumentsItem item = new BrowseDocumentsItem(); +// item.setCreationDate(fromItem.getCreationDate()); +// item.setFolder(false); +// item.setItemId(fromItem.getObjectId()); +// item.setLastChanged(fromItem.getLastModified()); +// item.setName(item.getName()); +// item.setTitle(fromItem +// .getTitle() +// .getValue(controller.getGlobalizationHelper().getNegotiatedLocale())); +// +// final ContentTypesManager typesManager = controller +// .getContentTypesManager(); +// final ContentTypeInfo typeInfo = typesManager +// .getContentTypeInfo(fromItem.getContentType()); +// final LocalizedTextsUtil textsUtil = controller +// .getGlobalizationHelper() +// .getLocalizedTextsUtil(typeInfo.getLabelBundle()); +// item.setType(textsUtil.getText(typeInfo.getLabelKey())); +// +// return item; +// } +// +// @Transactional(Transactional.TxType.REQUIRED) +// @Override +// protected int sizeInBackEnd(final Query query) { +// +// final Folder folder; +// if (currentFolder == null) { +// folder = controller.getCurrentSection().getRootDocumentsFolder(); +// } else { +// folder = currentFolder; +// } +// +// final int subFolderCount = countSubFolder(folder, query.getFilter()); +// final int itemCount = countItems(folder, query.getFilter()); +// +// return subFolderCount + itemCount; +// } +// +// private int countSubFolder(final Folder folder, +// final Optional filter) { +// +// final CriteriaBuilder builder = entityManager +// .getCriteriaBuilder(); +// final CriteriaQuery query = builder.createQuery(Long.class); +// final Root from = query.from(Folder.class); +// +// query.select(builder.count(from)); +// +// if (filter.isPresent()) { +// query.where(builder +// .and(builder.equal(from.get("parentCategory"), folder), +// builder.or( +// builder.like(builder.lower(from.get("name")), +// String.format("%s%%", filter.get())), +// builder.like(builder.lower(from.get("displayName")), +// String.format("%s%%", filter.get()))))); +// } else { +// query.where(builder.equal(from.get("parentCategory"), folder)); +// } +// +// return entityManager +// .createQuery(query) +// .getSingleResult() +// .intValue(); +// } +// +// private int countItems(final Folder folder, +// final Optional filter) { +// +// final CriteriaBuilder builder = entityManager +// .getCriteriaBuilder(); +// final CriteriaQuery query = builder.createQuery(Long.class); +// final Root from = query.from(ContentItem.class); +// final Join join = from.join("categories"); +// +// query.select(builder.count(from)); +// +// if (filter.isPresent()) { +// query.where(builder +// .and(builder.equal(join.get("category"), folder), +// builder.or( +// builder.like(builder.lower(from.get("name")), +// String.format("%s%%", filter.get())), +// builder.like(builder.lower(from.get("displayName")), +// String.format("%s%%", filter.get()))))); +// +// } else { +// query.where(builder.equal(join.get("category"), folder)); +// } +// +// return entityManager +// .createQuery(query) +// .getSingleResult() +// .intValue(); +// } +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsFolderTreeDataProvider.java b/ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsFolderTreeDataProvider.java new file mode 100644 index 000000000..c48a6f252 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsFolderTreeDataProvider.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui; + +import com.vaadin.cdi.ViewScoped; +import com.vaadin.data.provider.AbstractBackEndHierarchicalDataProvider; +import com.vaadin.data.provider.HierarchicalQuery; +import org.libreccm.core.UnexpectedErrorException; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.ContentSectionRepository; +import org.librecms.contentsection.Folder; +import org.librecms.contentsection.FolderRepository; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +import javax.inject.Inject; +import javax.transaction.Transactional; + +/** + * Data provider for the tree component of the {@link BrowseDocuments} + * component. + * + * @author Jens Pelzetter + */ +@ViewScoped +public class BrowseDocumentsFolderTreeDataProvider + extends AbstractBackEndHierarchicalDataProvider { + + private static final long serialVersionUID = 5330319780008907163L; + + @Inject + private ContentSectionViewState contentSectionViewState; + + @Inject + private FolderRepository folderRepo; + + @Inject + private ContentSectionRepository sectionRepo; + + @Override + protected Stream fetchChildrenFromBackEnd( + HierarchicalQuery query) { + + final Optional selectedParent = query.getParentOptional(); + + final Folder parent; + if (selectedParent.isPresent()) { + parent = folderRepo + .findById(selectedParent.get().getObjectId()) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No folder with ID %d in the database.", + selectedParent.get().getObjectId()))); + + return folderRepo.findSubFolders(parent).stream(); + } else { + final ContentSection section = sectionRepo + .findById(contentSectionViewState + .getSelectedContentSection() + .getObjectId()) + .orElseThrow(() -> new UnexpectedErrorException(String + .format("No ContentSection with ID %d in the database.", + contentSectionViewState + .getSelectedContentSection() + .getObjectId()))); + + final List result = new ArrayList<>(); + result.add(section.getRootDocumentsFolder()); + return result.stream(); + } + + } + + @Transactional(Transactional.TxType.REQUIRED) + @Override + public int getChildCount( + final HierarchicalQuery query) { + + final Optional selectedParent = query.getParentOptional(); + + final Folder parent; + if (selectedParent.isPresent()) { + parent = folderRepo + .findById(selectedParent.get().getObjectId()) + .orElseThrow(() -> new IllegalArgumentException(String + .format("No folder with ID %d in the database.", + selectedParent.get().getObjectId()))); + } else { + final ContentSection section = sectionRepo + .findById(contentSectionViewState + .getSelectedContentSection() + .getObjectId()) + .orElseThrow(() -> new UnexpectedErrorException(String + .format("No ContentSection with ID %d in the database.", + contentSectionViewState + .getSelectedContentSection() + .getObjectId()))); + + parent = section.getRootDocumentsFolder(); + } + + return (int) folderRepo.countSubFolders(parent); + + } + + @Override + public boolean hasChildren(final Folder item) { + return folderRepo.countSubFolders(item) > 0; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsItem.java b/ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsItem.java new file mode 100644 index 000000000..e9d961ced --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/BrowseDocumentsItem.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui; + +import java.util.Date; +import java.util.Objects; + +/** + * + * @author Jens Pelzetter + */ +public final class BrowseDocumentsItem implements + Comparable { + + private long itemId; + + private String name; + + private String title; + + private String type; + + private boolean folder; + + private Date creationDate; + + private Date lastModified; + + public long getItemId() { + return itemId; + } + + public void setItemId(final long itemId) { + this.itemId = itemId; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getTitle() { + return title; + } + + public void setTitle(final String title) { + this.title = title; + } + + public String getType() { + return type; + } + + public void setType(final String type) { + this.type = type; + } + + public boolean isFolder() { + return folder; + } + + public void setFolder(final boolean folder) { + this.folder = folder; + } + + public Date getCreationDate() { + if (creationDate == null) { + return null; + } else { + return new Date(creationDate.getTime()); + } + } + + public void setCreationDate(final Date creationDate) { + if (creationDate != null) { + this.creationDate = new Date(creationDate.getTime()); + } + } + + public Date getLastModified() { + if (lastModified == null) { + return null; + } else { + return new Date(lastModified.getTime()); + } + } + + public void setLastModified(final Date lastModified) { + if (lastModified != null) { + this.lastModified = new Date(lastModified.getTime()); + } + } + + @Override + public int compareTo(final BrowseDocumentsItem other) { + + int result = title.compareTo(other.getTitle()); + if (result != 0) { + return result; + } + + result = name.compareTo(other.getName()); + if (result != 0) { + return result; + } + + result = type.compareTo(other.getType()); + if (result != 0) { + return result; + } + + result = lastModified.compareTo(other.getLastModified()); + if (result != 0) { + return result; + } + + return creationDate.compareTo(other.getCreationDate()); + } + + @Override + public int hashCode() { + int hash = 3; + hash = 53 * hash + (int) (itemId ^ (itemId >>> 32)); + hash = 53 * hash + Objects.hashCode(name); + hash = 53 * hash + Objects.hashCode(title); + hash = 53 * hash + Objects.hashCode(type); + hash = 53 * hash + (folder ? 1 : 0); + hash = 53 * hash + Objects.hashCode(creationDate); + hash = 53 * hash + Objects.hashCode(lastModified); + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof BrowseDocumentsItem)) { + return false; + } + final BrowseDocumentsItem other = (BrowseDocumentsItem) obj; + if (itemId != other.getItemId()) { + return false; + } + if (folder != other.isFolder()) { + return false; + } + if (!Objects.equals(name, other.getName())) { + return false; + } + if (!Objects.equals(title, other.getTitle())) { + return false; + } + if (!Objects.equals(type, other.getType())) { + return false; + } + if (!Objects.equals(creationDate, other.getCreationDate())) { + return false; + } + return Objects.equals(lastModified, other.getLastModified()); + } + + @Override + public String toString() { + return String.format("%s{ " + + "itemId = %d, " + + "name = \"%s\", " + + "title = \"%s\", " + + "type = \"%s\", " + + "creationDate = %s, " + + "lastChanged = %s" + + " }", + super.toString(), + itemId, + name, + title, + type, + Objects.toString(creationDate), + Objects.toString(lastModified)); + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/ContentSectionView.java b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionView.java index fe7952393..93358911d 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/ContentSectionView.java +++ b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionView.java @@ -21,9 +21,11 @@ package org.librecms.ui; import com.vaadin.cdi.CDIView; import com.vaadin.navigator.View; import com.vaadin.navigator.ViewChangeListener; +import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; import com.vaadin.ui.TabSheet; +import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.ValoTheme; import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSectionRepository; @@ -38,7 +40,7 @@ import javax.inject.Inject; */ @CDIView(value = ContentSectionView.VIEWNAME, uis = {CmsUI.class}) -class ContentSectionView implements View { +class ContentSectionView extends CustomComponent implements View { private static final long serialVersionUID = 602851260519364741L; @@ -58,10 +60,26 @@ class ContentSectionView implements View { this.controller = controller; + final BrowseDocuments browseDocuments = new BrowseDocuments(controller); + tabSheet = new TabSheet(); + tabSheet.addTab(browseDocuments, "Documents"); + tabSheet.addTab(new Label("Search placeholder"), "Search"); + tabSheet.addTab(new Label("Media & Records placeholder"), + "Media & Records"); + tabSheet.addTab(new Label("Roles placeholder"), "Roles"); + tabSheet.addTab(new Label("Workflows Placeholder"), "Workflows"); + tabSheet.addTab(new Label("Lifecycles placeholder"), "Lifecycles"); + tabSheet.addTab(new Label("Document types placeholder"), + "Documents types"); noSectionPanel = new Panel(); noSectionPanel.setVisible(false); + + final VerticalLayout layout = new VerticalLayout(tabSheet, + noSectionPanel); + + super.setCompositionRoot(layout); } @Override @@ -71,18 +89,21 @@ class ContentSectionView implements View { if (parameters == null || parameters.trim().isEmpty()) { tabSheet.setVisible(false); - noSectionPanel.setCaption("No content section selected"); - noSectionPanel.setContent(new Label("No content section selected")); - noSectionPanel.setVisible(true); + noSectionPanel.setCaption("No content section selected"); + noSectionPanel.setContent(new Label("No content section selected")); + noSectionPanel.setVisible(true); } else { final ContentSectionRepository sectionRepo = controller - .getSectionRepo(); + .getSectionRepository(); final Optional contentSection = sectionRepo .findByLabel(parameters); if (contentSection.isPresent()) { selectedSection = contentSection.get(); + controller + .getContentSectionViewState() + .setSelectedContentSection(selectedSection); } else { tabSheet.setVisible(false); noSectionPanel.setCaption(String diff --git a/ccm-cms/src/main/java/org/librecms/ui/ContentSectionViewController.java b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionViewController.java index 6603e656a..5c101a266 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/ContentSectionViewController.java +++ b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionViewController.java @@ -21,7 +21,10 @@ package org.librecms.ui; import com.vaadin.cdi.ViewScoped; import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.security.PermissionChecker; +import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSectionRepository; +import org.librecms.contentsection.FolderRepository; +import org.librecms.contenttypes.ContentTypesManager; import javax.inject.Inject; @@ -30,7 +33,19 @@ import javax.inject.Inject; * @author Jens Pelzetter */ @ViewScoped -class ContentSectionViewController { +public class ContentSectionViewController { + + @Inject + private BrowseDocumentsDataProvider browseDocumentsDataProvider; + + @Inject + private BrowseDocumentsFolderTreeDataProvider folderTreeDataProvider; + + @Inject + private ContentTypesManager contentTypesManager; + + @Inject + private FolderRepository folderRepository; @Inject private GlobalizationHelper globalizationHelper; @@ -39,18 +54,43 @@ class ContentSectionViewController { private PermissionChecker permissionChecker; @Inject - private ContentSectionRepository sectionRepo; + private ContentSectionRepository sectionRepository; + + @Inject + private ContentSectionViewState contentSectionViewState; + + protected BrowseDocumentsDataProvider getBrowseDocumentsDataProvider() { + return browseDocumentsDataProvider; + } - public GlobalizationHelper getGlobalizationHelper() { + protected BrowseDocumentsFolderTreeDataProvider getFolderTreeDataProvider() { + return folderTreeDataProvider; + } + + protected ContentTypesManager getContentTypesManager() { + return contentTypesManager; + } + + protected FolderRepository getFolderRepository() { + return folderRepository; + } + + protected GlobalizationHelper getGlobalizationHelper() { return globalizationHelper; } - public PermissionChecker getPermissionChecker() { + protected PermissionChecker getPermissionChecker() { return permissionChecker; } - public ContentSectionRepository getSectionRepo() { - return sectionRepo; + protected ContentSectionRepository getSectionRepository() { + return sectionRepository; } + + protected ContentSectionViewState getContentSectionViewState() { + return contentSectionViewState; + } + + } diff --git a/ccm-cms/src/main/java/org/librecms/ui/ContentSectionViewState.java b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionViewState.java new file mode 100644 index 000000000..f59e7b461 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/ContentSectionViewState.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui; + +import com.vaadin.cdi.ViewScoped; +import org.librecms.contentsection.ContentSection; + +/** + * + * @author Jens Pelzetter + */ +@ViewScoped +class ContentSectionViewState { + + private ContentSection selectedContentSection; + + protected ContentSection getSelectedContentSection() { + return selectedContentSection; + } + + protected void setSelectedContentSection( + final ContentSection selectedContentSection) { + this.selectedContentSection = selectedContentSection; + } + + + +} diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources.properties index 171de3721..faed06b8d 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources.properties @@ -444,3 +444,5 @@ cms.ui.authoring.assets.related_info_step.attachment.move\ \t=Move cms.ui.authoring.assets.related_info_step.add_internal_link=Add internal link cms.ui.authoring.assets.related_info_step.internal_link.title=Title cms.ui.authoring.assets.related_info_step.internal_link.target_item=Target +item_category_step.label=Assigned categories +related_info_step.description=Assign this item to categories diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties index 8f603d8ee..631f8819d 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties @@ -441,3 +441,5 @@ cms.ui.authoring.assets.related_info_step.attachment.move\ \t=Verschieben cms.ui.authoring.assets.related_info_step.add_internal_link=Internen Link hinzuf\u00fcgen cms.ui.authoring.assets.related_info_step.internal_link.title=Titel cms.ui.authoring.assets.related_info_step.internal_link.target_item=Ziel +item_category_step.label=Zugewiesene Kategorien +related_info_step.description=Dieses Dokument Kategorien zuweisen diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties index fb162c6b8..02259fd67 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties @@ -400,3 +400,5 @@ cms.ui.authoring.assets.related_info_step.attachment.move\ \t=Move cms.ui.authoring.assets.related_info_step.add_internal_link=Add internal link cms.ui.authoring.assets.related_info_step.internal_link.title=Title cms.ui.authoring.assets.related_info_step.internal_link.target_item=Target +item_category_step.label=Assigned categories +related_info_step.description=Assign this item to categories diff --git a/ccm-cms/src/main/resources/templates/ccm-cms/content-section/admin/load-cat.jsp b/ccm-cms/src/main/resources/templates/ccm-cms/content-section/admin/load-cat.jsp new file mode 100644 index 000000000..6e555992d --- /dev/null +++ b/ccm-cms/src/main/resources/templates/ccm-cms/content-section/admin/load-cat.jsp @@ -0,0 +1,23 @@ + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 0e921540a..794de8f36 100644 --- a/pom.xml +++ b/pom.xml @@ -230,7 +230,7 @@ de.jpdigital hibernate50-ddl-maven-plugin - 2.0.4 + 2.1.0-SNAPSHOT org.jacoco