CCM NG/ccm-cms: Next part of AssetPane

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4652 8810af33-2d31-482b-a856-94f89814c4df
ccm-docs
jensp 2017-03-29 18:21:41 +00:00
parent f72473954a
commit 6a0e01e6f7
10 changed files with 955 additions and 199 deletions

View File

@ -0,0 +1,111 @@
/*
* Copyright (C) 2017 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Paginator;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.bebop.table.DefaultTableColumnModel;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.cms.ui.folder.FolderSelectionModel;
import com.arsdigita.globalization.GlobalizedMessage;
import javafx.scene.control.Pagination;
import org.librecms.CmsConstants;
/**
* Browse folder and assets.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class AssetFolderBrowser extends Table {
protected static final String SORT_ACTION_UP = "sortActionUp";
protected static final String SORT_ACTION_DOWN = "sortActionDown";
protected final static String SORT_KEY_NAME = "name";
protected final static String SORT_KEY_TITLE = "title";
protected final static String SORT_KEY_TYPE = "type";
protected final static String SORT_KEY_LAST_MODIFIED_DATE = "lastModified";
protected final static String SORT_KEY_CREATION_DATE = "creationDate";
private final FolderSelectionModel folderSelectionModel;
private TableActionListener folderChanger;
private TableActionListener tableDeleter;
private TableColumn nameColumn;
private TableColumn deleteColumn;
private final StringParameter sortTypeParameter = new StringParameter(
"sortType");
private final StringParameter sortDirectionParameter = new StringParameter(
"sortDir");
private Paginator paginator;
private long folderSize;
public AssetFolderBrowser(final FolderSelectionModel folderSelectionModel) {
super();
sortTypeParameter.setDefaultValue(SORT_KEY_NAME);
sortDirectionParameter.setDefaultValue(SORT_ACTION_UP);
this.folderSelectionModel = folderSelectionModel;
initComponents();
}
protected FolderSelectionModel getFolderSelectionModel() {
return folderSelectionModel;
}
protected Paginator getPaginator() {
return paginator;
}
protected String getSortType(final PageState state) {
return (String) state.getValue(sortTypeParameter);
}
protected String getSortDirection(final PageState state) {
return (String) state.getValue(sortDirectionParameter);
}
private void initComponents() {
setModelBuilder(new AssetFolderBrowserTableModelBuilder());
final GlobalizedMessage[] headers = {
globalize("cms.ui.folder.name"),
globalize("cms.ui.folder.languages"),
globalize("cms.ui.folder.title"),
globalize("cms.ui.folder.type"),
globalize("cms.ui.folder.creation_date"),
globalize("cms.ui.folder.last_modified"),
globalize("cms.ui.folder.action")};
}
/**
* Getting the GlobalizedMessage using a CMS Class targetBundle.
*
* @param key The resource key
*/
private GlobalizedMessage globalize(final String key) {
return new GlobalizedMessage(key, CmsConstants.CMS_FOLDER_BUNDLE);
}
}

View File

@ -0,0 +1,276 @@
/*
* Copyright (C) 2017 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets;
import com.arsdigita.cms.ui.folder.FolderBrowser;
import com.arsdigita.kernel.KernelConfig;
import org.libreccm.categorization.Category;
import org.libreccm.categorization.CategoryManager;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.CmsConstants;
import org.librecms.assets.AssetTypeInfo;
import org.librecms.assets.AssetTypesManager;
import org.librecms.contentsection.Asset;
import org.librecms.contentsection.ContentType;
import org.librecms.contentsection.Folder;
import org.librecms.contenttypes.ContentTypeInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class AssetFolderBrowserController {
@Inject
private EntityManager entityManager;
@Inject
private ConfigurationManager confManager;
@Inject
private CategoryManager categoryManager;
@Inject
private AssetTypesManager typesManager;
@Inject
private GlobalizationHelper globalizationHelper;
private Locale defaultLocale;
/**
* Initialisation method called by the CDI-Container after an instance of
* this class has be created by the container. Sets the
* {@link #defaultLocale} property using the the value from the
* {@link KernelConfig}.
*/
@PostConstruct
private void init() {
final KernelConfig kernelConfig = confManager.findConfiguration(
KernelConfig.class);
defaultLocale = kernelConfig.getDefaultLocale();
}
@Transactional(Transactional.TxType.REQUIRED)
List<AssetFolderBrowserTableRow> getAssetRows(final Folder folder,
final String orderBy,
final String orderDirection,
final int firstResult,
final int maxResults) {
final List<Folder> subFolders = findSubFolders(folder,
orderBy,
orderDirection,
firstResult,
maxResults);
final List<AssetFolderBrowserTableRow> subFolderRows = subFolders
.stream()
.map(subFolder -> buildRow(subFolder))
.collect(Collectors.toList());
if (subFolders.size() > maxResults) {
return subFolderRows;
} else {
final int maxAssets = maxResults - subFolders.size();
final int firstItem = firstResult - subFolders.size();
final List<Asset> assets = findAssetsInFolder(folder,
orderBy,
orderDirection,
firstResult,
maxResults);
final List<AssetFolderBrowserTableRow> assetRows = assets
.stream()
.map(asset -> buildRow(asset))
.collect(Collectors.toList());
final List<AssetFolderBrowserTableRow> rows = new ArrayList<>();
rows.addAll(subFolderRows);
rows.addAll(assetRows);
return rows;
}
}
private AssetFolderBrowserTableRow buildRow(final Folder folder) {
final AssetFolderBrowserTableRow row = new AssetFolderBrowserTableRow();
row.setObjectId(folder.getObjectId());
row.setObjectUuid(folder.getUuid());
row.setName(folder.getName());
if (folder.getTitle().hasValue(globalizationHelper
.getNegotiatedLocale())) {
row.setTitle(folder.getTitle().getValue(globalizationHelper
.getNegotiatedLocale()));
} else {
row.setTitle(folder.getTitle().getValue(defaultLocale));
}
row.setFolder(true);
row.setDeletable(!categoryManager.hasSubCategories(folder)
&& !categoryManager.hasObjects(folder));
return row;
}
private AssetFolderBrowserTableRow buildRow(final Asset asset) {
final AssetFolderBrowserTableRow row = new AssetFolderBrowserTableRow();
row.setObjectId(asset.getObjectId());
row.setObjectUuid(asset.getUuid());
row.setName(asset.getDisplayName());
if (asset.getTitle().hasValue(globalizationHelper
.getNegotiatedLocale())) {
row.setTitle(asset.getTitle().getValue(globalizationHelper
.getNegotiatedLocale()));
} else {
row.setTitle(asset.getTitle().getValue(defaultLocale));
}
final AssetTypeInfo typeInfo = typesManager
.getAssetTypeInfo(asset.getClass());
row.setTypeLabelBundle(typeInfo.getLabelBundle());
row.setTypeLabelKey(typeInfo.getLabelKey());
row.setFolder(false);
return row;
}
private List<Folder> findSubFolders(final Folder folder,
final String orderBy,
final String orderDirection,
final int firstResult,
final int maxResults) {
final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
final CriteriaQuery<Folder> criteria = builder
.createQuery(Folder.class);
final Root<Folder> from = criteria.from(Folder.class);
final Order order;
if (AssetFolderBrowser.SORT_KEY_NAME.equals(orderBy)
&& AssetFolderBrowser.SORT_ACTION_DOWN.equals(orderDirection)) {
order = builder.desc(from.get("name"));
} else {
order = builder.asc(from.get("name"));
}
final TypedQuery<Folder> query = entityManager
.createQuery(
criteria.where(
builder.equal(from.get("parentCategory"), folder)
)
.orderBy(order)
);
if (firstResult >= 0) {
query.setFirstResult(firstResult);
}
if (maxResults >= 0) {
query.setMaxResults(maxResults);
}
return query.getResultList();
}
private List<Asset> findAssetsInFolder(final Folder folder,
final String orderBy,
final String orderDirection,
final int firstResult,
final int maxResults) {
final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
final CriteriaQuery<Asset> criteria = builder.createQuery(Asset.class);
final Root<Asset> fromAsset = criteria.from(Asset.class);
final Join<Asset, Category> join = fromAsset.join("categories");
final Path<?> orderPath;
switch (orderBy) {
case AssetFolderBrowser.SORT_KEY_NAME:
orderPath = fromAsset.get("displayName");
break;
case AssetFolderBrowser.SORT_KEY_CREATION_DATE:
orderPath = fromAsset.get("creationDate");
break;
case AssetFolderBrowser.SORT_KEY_LAST_MODIFIED_DATE:
orderPath = fromAsset.get("lastModifed");
break;
default:
orderPath = fromAsset.get("displayName");
break;
}
final Order order;
if (AssetFolderBrowser.SORT_ACTION_DOWN.equals(orderDirection)) {
order = builder.desc(orderPath);
} else {
order = builder.asc(orderPath);
}
final TypedQuery<Asset> query = entityManager
.createQuery(
criteria.select(fromAsset)
.where(
builder.and(
builder.equal(join.get("category"), folder),
builder.equal(join.get("type"),
CmsConstants.CATEGORIZATION_TYPE_FOLDER)
)
)
.orderBy(order)
);
if (firstResult >= 0) {
query.setFirstResult(firstResult);
}
if (maxResults >= 0) {
query.setMaxResults(maxResults);
}
return query.getResultList();
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2017 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.globalization.GlobalizedMessage;
import org.librecms.CmsConstants;
import java.util.Iterator;
import java.util.List;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class AssetFolderBrowserTableModel implements TableModel {
private static final int COL_NAME = 0;
private static final int COL_TITLE = 1;
private static final int COL_TYPE = 2;
private static final int COL_CREATION_DATE = 3;
private static final int COL_LAST_MODIFIED = 4;
private static final int COL_DELETEABLE = 5;
private final Iterator<AssetFolderBrowserTableRow> iterator;
private AssetFolderBrowserTableRow currentRow;
public AssetFolderBrowserTableModel(
final List<AssetFolderBrowserTableRow> rows) {
iterator = rows.iterator();
}
@Override
public int getColumnCount() {
return 6;
}
@Override
public boolean nextRow() {
if (iterator.hasNext()) {
currentRow = iterator.next();
return true;
} else {
return false;
}
}
@Override
public Object getElementAt(final int columnIndex) {
switch(columnIndex) {
case COL_NAME:
return currentRow.getName();
case COL_TITLE:
return currentRow.getTitle();
case COL_TYPE:
final String typeLabelBundle = currentRow.getTypeLabelBundle();
final String typeLabelKey = currentRow.getTypeLabelKey();
if (typeLabelKey == null) {
return new GlobalizedMessage("empty_text",
CmsConstants.CMS_BUNDLE);
} else {
return new GlobalizedMessage(typeLabelKey, typeLabelBundle);
}
case COL_CREATION_DATE:
return currentRow.getCreated();
case COL_LAST_MODIFIED:
return currentRow.getLastModified();
case COL_DELETEABLE:
return currentRow.isDeletable();
default:
throw new IllegalArgumentException(String.format(
"Illegal column index %d.", columnIndex));
}
}
@Override
public Object getKeyAt(final int columnIndex) {
if (currentRow.isFolder()) {
return String.format("folder-%d", currentRow.getObjectId());
} else {
return String.format("item-%d", currentRow.getObjectId());
}
// return currentRow.getObjectId();
}
public boolean isFolder() {
return currentRow.isFolder();
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2017 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Paginator;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.cms.ui.folder.FolderSelectionModel;
import com.arsdigita.util.LockableImpl;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.cdi.utils.CdiUtil;
import org.librecms.contentsection.Folder;
import java.util.List;
/**
* Creates the {@link TableModel} for the {@link AssetFolderBrowser}.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
class AssetFolderBrowserTableModelBuilder
extends LockableImpl
implements TableModelBuilder {
private static final Logger LOGGER = LogManager
.getLogger(AssetFolderBrowserTableModelBuilder.class);
@Override
public TableModel makeModel(final Table table,
final PageState state) {
if (!(table instanceof AssetFolderBrowser)) {
throw new IllegalArgumentException("The "
+ "AssetFolderBrowserTableModelBuilder can only be used for the "
+ "AssetFolderBrowser.");
}
final AssetFolderBrowser assetFolderBrowser = (AssetFolderBrowser) table;
final FolderSelectionModel folderSelectionModel = assetFolderBrowser
.getFolderSelectionModel();
final Folder folder = folderSelectionModel.getSelectedObject(state);
if (folder == null) {
return Table.EMPTY_MODEL;
} else {
assetFolderBrowser.getRowSelectionModel().clearSelection(state);
final Paginator paginator = assetFolderBrowser.getPaginator();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final AssetFolderBrowserController controller = cdiUtil
.findBean(AssetFolderBrowserController.class);
final String orderBy;
if (assetFolderBrowser.getSortType(state) == null) {
orderBy = AssetFolderBrowser.SORT_KEY_NAME;
} else {
orderBy = assetFolderBrowser.getSortType(state);
}
final String orderDirection;
if (assetFolderBrowser.getSortDirection(state) == null) {
orderDirection = AssetFolderBrowser.SORT_ACTION_UP;
} else {
orderDirection = assetFolderBrowser.getSortDirection(state);
}
final int first = paginator.getFirst(state);
final int pageSize = paginator.getPageSize(state);
final long start = System.nanoTime();
LOGGER.debug("Retrieving table rows...");
final List<AssetFolderBrowserTableRow> rows = controller
.getAssetRows(folder,
orderBy,
orderDirection,
first - 1,
pageSize);
LOGGER.debug("Retrieve table rows in {} ms.",
(System.nanoTime() - start) / 1000);
return new AssetFolderBrowserTableModel(rows);
}
}
}

View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2017 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets;
import java.util.Date;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
class AssetFolderBrowserTableRow {
private long objectId;
private String objectUuid;
private String name;
private String title;
private String typeLabelBundle;
private String typeLabelKey;
private Date created;
private Date lastModified;
private boolean deletable;
private boolean folder;
public long getObjectId() {
return objectId;
}
public void setObjectId(final long objectId) {
this.objectId = objectId;
}
public String getObjectUuid() {
return objectUuid;
}
public void setObjectUuid(final String objectUuid) {
this.objectUuid = objectUuid;
}
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 getTypeLabelBundle() {
return typeLabelBundle;
}
public void setTypeLabelBundle(final String typeLabelBundle) {
this.typeLabelBundle = typeLabelBundle;
}
public String getTypeLabelKey() {
return typeLabelKey;
}
public void setTypeLabelKey(final String typeLabelKey) {
this.typeLabelKey = typeLabelKey;
}
public Date getCreated() {
if (created == null) {
return null;
} else {
return new Date(created.getTime());
}
}
protected void setCreated(final Date created) {
if (created == null) {
this.created = null;
} else {
this.created = new Date(created.getTime());
}
}
public Date getLastModified() {
if (lastModified == null) {
return null;
} else {
return new Date(lastModified.getTime());
}
}
protected void setLastModified(final Date lastModified) {
if (lastModified == null) {
this.lastModified = null;
} else {
this.lastModified = new Date(lastModified.getTime());
}
}
public boolean isDeletable() {
return deletable;
}
public void setDeletable(final boolean deletable) {
this.deletable = deletable;
}
public boolean isFolder() {
return folder;
}
public void setFolder(final boolean folder) {
this.folder = folder;
}
}

View File

@ -37,6 +37,7 @@ import com.arsdigita.bebop.event.PrintEvent;
import com.arsdigita.bebop.event.PrintListener; import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.cms.CMS; import com.arsdigita.cms.CMS;
import com.arsdigita.cms.ui.BaseTree; import com.arsdigita.cms.ui.BaseTree;
import com.arsdigita.cms.ui.folder.FolderBrowser;
import com.arsdigita.cms.ui.folder.FolderCreateForm; import com.arsdigita.cms.ui.folder.FolderCreateForm;
import com.arsdigita.cms.ui.folder.FolderEditorForm; import com.arsdigita.cms.ui.folder.FolderEditorForm;
import com.arsdigita.cms.ui.folder.FolderRequestLocal; import com.arsdigita.cms.ui.folder.FolderRequestLocal;
@ -143,6 +144,7 @@ public class AssetPane extends LayoutPanel implements Resettable {
browseSegment = panel.addSegment(); browseSegment = panel.addSegment();
browseSegment.setIdAttr("folder-browse"); browseSegment.setIdAttr("folder-browse");
final ActionGroup actions = new ActionGroup(); final ActionGroup actions = new ActionGroup();
browseSegment.add(actions); browseSegment.add(actions);

View File

@ -522,7 +522,7 @@ public class FolderBrowser extends Table {
/** /**
* Getting the GlobalizedMessage using a CMS Class targetBundle. * Getting the GlobalizedMessage using a CMS Class targetBundle.
* *
* @param key The resource key @pre ( key != null ) * @param key The resource key
*/ */
private static GlobalizedMessage globalize(String key) { private static GlobalizedMessage globalize(String key) {
return new GlobalizedMessage(key, CmsConstants.CMS_FOLDER_BUNDLE); return new GlobalizedMessage(key, CmsConstants.CMS_FOLDER_BUNDLE);

View File

@ -125,7 +125,7 @@ public class FolderBrowserController {
@PostConstruct @PostConstruct
private void init() { private void init() {
final KernelConfig kernelConfig = confManager.findConfiguration( final KernelConfig kernelConfig = confManager.findConfiguration(
KernelConfig.class); KernelConfig.class);
defaultLocale = kernelConfig.getDefaultLocale(); defaultLocale = kernelConfig.getDefaultLocale();
} }
@ -135,7 +135,7 @@ public class FolderBrowserController {
* @param folder The folder. * @param folder The folder.
* *
* @return The number of objects (subfolders and content items) in the * @return The number of objects (subfolders and content items) in the
* provided {@code folder}. * provided {@code folder}.
*/ */
public long countObjects(final Folder folder) { public long countObjects(final Folder folder) {
return countObjects(folder, "%"); return countObjects(folder, "%");
@ -145,11 +145,12 @@ public class FolderBrowserController {
* Count all objects (subfolders and content items) in the provided folder * Count all objects (subfolders and content items) in the provided folder
* which match the provided filter term. * which match the provided filter term.
* *
* @param folder The folder. * @param folder The folder.
* @param filterTerm The filter term. * @param filterTerm The filter term.
* *
* @return The number of objects (subfolders and content items) in the * @return The number of objects (subfolders and content items) in the
* provided {@code folder} which match the provided {@code filterTerm}. * provided {@code folder} which match the provided
* {@code filterTerm}.
*/ */
public long countObjects(final Folder folder, public long countObjects(final Folder folder,
final String filterTerm) { final String filterTerm) {
@ -183,8 +184,8 @@ public class FolderBrowserController {
criteriaQuery = criteriaQuery.where(from.in(subFolders)); criteriaQuery = criteriaQuery.where(from.in(subFolders));
} else { } else {
criteriaQuery = criteriaQuery.where(builder.or( criteriaQuery = criteriaQuery.where(builder.or(
from.in(subFolders), from.in(subFolders),
from.in(items))); from.in(items)));
} }
return entityManager.createQuery(criteriaQuery).getSingleResult(); return entityManager.createQuery(criteriaQuery).getSingleResult();
@ -194,13 +195,13 @@ public class FolderBrowserController {
* Create {@link FolderBrowserTableRow} objects for all objects in the * Create {@link FolderBrowserTableRow} objects for all objects in the
* provided folder. * provided folder.
* *
* @param folder The folder which contains the objects. * @param folder The folder which contains the objects.
* @param orderBy The field used to order the objects. * @param orderBy The field used to order the objects.
* @param orderDirection The direction for ordering the objects. * @param orderDirection The direction for ordering the objects.
* *
* @return A list with {@link FolderBrowserTableRow} objects for each object * @return A list with {@link FolderBrowserTableRow} objects for each object
* in the provided {@code folder} ordered by the provided field and in the * in the provided {@code folder} ordered by the provided field and
* provided direction. * in the provided direction.
*/ */
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
List<FolderBrowserTableRow> getObjectRows(final Folder folder, List<FolderBrowserTableRow> getObjectRows(final Folder folder,
@ -213,15 +214,15 @@ public class FolderBrowserController {
* Create {@link FolderBrowserTableRow} objects for all objects in the * Create {@link FolderBrowserTableRow} objects for all objects in the
* provided folder which match provided filter term. * provided folder which match provided filter term.
* *
* @param folder The folder which contains the objects. * @param folder The folder which contains the objects.
* @param filterTerm The filter term. * @param filterTerm The filter term.
* @param orderBy The field used to order the objects. * @param orderBy The field used to order the objects.
* @param orderDirection The direction for ordering the objects. * @param orderDirection The direction for ordering the objects.
* *
* @return A list with {@link FolderBrowserTableRow} objects for each object * @return A list with {@link FolderBrowserTableRow} objects for each object
* in the provided {@code folder} which matches the provided * in the provided {@code folder} which matches the provided
* {@code filterTerm}, ordered by the provided field and in the provided * {@code filterTerm}, ordered by the provided field and in the
* direction. * provided direction.
*/ */
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
List<FolderBrowserTableRow> getObjectRows(final Folder folder, List<FolderBrowserTableRow> getObjectRows(final Folder folder,
@ -241,17 +242,17 @@ public class FolderBrowserController {
* provided folder which are in the range provided by {@code firstResult} * provided folder which are in the range provided by {@code firstResult}
* and {@code maxResult} * and {@code maxResult}
* *
* @param folder The folder which contains the objects. * @param folder The folder which contains the objects.
* @param orderBy The field used to order the objects. * @param orderBy The field used to order the objects.
* @param orderDirection The direction for ordering the objects. * @param orderDirection The direction for ordering the objects.
* @param firstResult The index of the first object to use. * @param firstResult The index of the first object to use.
* @param maxResults The maximum number of objects to retrieve. * @param maxResults The maximum number of objects to retrieve.
* *
* @return A list with {@link FolderBrowserTableRow} objects for each object * @return A list with {@link FolderBrowserTableRow} objects for each object
* in the provided {@code folder} ordered by the provided field and in the * in the provided {@code folder} ordered by the provided field and
* provided direction. The list will start with the object with index * in the provided direction. The list will start with the object
* provided as {@code firstResult} and contain at most {@code maxResults} * with index provided as {@code firstResult} and contain at most
* items. * {@code maxResults} items.
*/ */
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
List<FolderBrowserTableRow> getObjectRows(final Folder folder, List<FolderBrowserTableRow> getObjectRows(final Folder folder,
@ -272,18 +273,19 @@ public class FolderBrowserController {
* provided folder which match the provided filter term and which are in the * provided folder which match the provided filter term and which are in the
* range provided by {@code firstResult} and {@code maxResult} * range provided by {@code firstResult} and {@code maxResult}
* *
* @param folder The folder which contains the objects. * @param folder The folder which contains the objects.
* @param filterTerm The filter term. * @param filterTerm The filter term.
* @param orderBy The field used to order the objects. * @param orderBy The field used to order the objects.
* @param orderDirection The direction for ordering the objects. * @param orderDirection The direction for ordering the objects.
* @param firstResult The index of the first object to use. * @param firstResult The index of the first object to use.
* @param maxResults The maximum number of objects to retrieve. * @param maxResults The maximum number of objects to retrieve.
* *
* @return A list with {@link FolderBrowserTableRow} objects for each object * @return A list with {@link FolderBrowserTableRow} objects for each object
* in the provided {@code folder} which matches the provided * in the provided {@code folder} which matches the provided
* {@code filterTerm}, ordered by the provided field and in the provided * {@code filterTerm}, ordered by the provided field and in the
* direction. The list will start with the object with index provided as * provided direction. The list will start with the object with
* {@code firstResult} and contain at most {@code maxResults} items. * index provided as {@code firstResult} and contain at most
* {@code maxResults} items.
*/ */
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
List<FolderBrowserTableRow> getObjectRows(final Folder folder, List<FolderBrowserTableRow> getObjectRows(final Folder folder,
@ -298,9 +300,10 @@ public class FolderBrowserController {
orderDirection, orderDirection,
firstResult, firstResult,
maxResults); maxResults);
final List<FolderBrowserTableRow> subFolderRows = subFolders.stream() final List<FolderBrowserTableRow> subFolderRows = subFolders
.map(subFolder -> buildRow(subFolder)) .stream()
.collect(Collectors.toList()); .map(subFolder -> buildRow(subFolder))
.collect(Collectors.toList());
if (subFolders.size() > maxResults) { if (subFolders.size() > maxResults) {
return subFolderRows; return subFolderRows;
@ -315,10 +318,10 @@ public class FolderBrowserController {
firstItem, firstItem,
maxItems); maxItems);
final List<FolderBrowserTableRow> itemRows = items.stream() final List<FolderBrowserTableRow> itemRows = items.stream()
.map(item -> buildRow(item)) .map(item -> buildRow(item))
.collect(Collectors.toList()); .collect(Collectors.toList());
final ArrayList<FolderBrowserTableRow> rows = new ArrayList<>(); final List<FolderBrowserTableRow> rows = new ArrayList<>();
rows.addAll(subFolderRows); rows.addAll(subFolderRows);
rows.addAll(itemRows); rows.addAll(itemRows);
@ -331,10 +334,10 @@ public class FolderBrowserController {
* {@link Folder}. * {@link Folder}.
* *
* @param folder The {@link Folder} to use for building the * @param folder The {@link Folder} to use for building the
* {@link FolderBrowserTableRow}. * {@link FolderBrowserTableRow}.
* *
* @return A {@link FolderBrowserTableRow} containing the data needed by the * @return A {@link FolderBrowserTableRow} containing the data needed by the
* {@link FolderBrowser} to display the provided {@code folder}. * {@link FolderBrowser} to display the provided {@code folder}.
*/ */
private FolderBrowserTableRow buildRow(final Folder folder) { private FolderBrowserTableRow buildRow(final Folder folder) {
@ -345,15 +348,15 @@ public class FolderBrowserController {
row.setName(folder.getName()); row.setName(folder.getName());
row.setLanguages(Collections.emptyList()); row.setLanguages(Collections.emptyList());
if (folder.getTitle().hasValue(globalizationHelper if (folder.getTitle().hasValue(globalizationHelper
.getNegotiatedLocale())) { .getNegotiatedLocale())) {
row.setTitle(folder.getTitle().getValue(globalizationHelper row.setTitle(folder.getTitle().getValue(globalizationHelper
.getNegotiatedLocale())); .getNegotiatedLocale()));
} else { } else {
row.setTitle(folder.getTitle().getValue(defaultLocale)); row.setTitle(folder.getTitle().getValue(defaultLocale));
} }
row.setFolder(true); row.setFolder(true);
row.setDeletable(!categoryManager.hasSubCategories(folder) row.setDeletable(!categoryManager.hasSubCategories(folder)
&& !categoryManager.hasObjects(folder)); && !categoryManager.hasObjects(folder));
return row; return row;
} }
@ -363,10 +366,10 @@ public class FolderBrowserController {
* {@link ContentItem}. * {@link ContentItem}.
* *
* @param item The {@link ContentItem} to use for building the * @param item The {@link ContentItem} to use for building the
* {@link FolderBrowserTableRow}. * {@link FolderBrowserTableRow}.
* *
* @return A {@link FolderBrowserTableRow} containing the data needed by the * @return A {@link FolderBrowserTableRow} containing the data needed by the
* {@link FolderBrowser} to display the provided {@code item}. * {@link FolderBrowser} to display the provided {@code item}.
*/ */
private FolderBrowserTableRow buildRow(final ContentItem item) { private FolderBrowserTableRow buildRow(final ContentItem item) {
@ -376,20 +379,20 @@ public class FolderBrowserController {
row.setObjectUuid(item.getItemUuid()); row.setObjectUuid(item.getItemUuid());
row.setName(item.getName().getValue(defaultLocale)); row.setName(item.getName().getValue(defaultLocale));
final List<Locale> languages = new ArrayList<>(itemL10NManager final List<Locale> languages = new ArrayList<>(itemL10NManager
.availableLanguages(item)); .availableLanguages(item));
languages.sort((lang1, lang2) -> lang1.toString().compareTo( languages.sort((lang1, lang2) -> lang1.toString().compareTo(
lang2.toString())); lang2.toString()));
row.setLanguages(languages); row.setLanguages(languages);
if (item.getTitle().hasValue(globalizationHelper if (item.getTitle().hasValue(globalizationHelper
.getNegotiatedLocale())) { .getNegotiatedLocale())) {
row.setTitle(item.getTitle().getValue(globalizationHelper row.setTitle(item.getTitle().getValue(globalizationHelper
.getNegotiatedLocale())); .getNegotiatedLocale()));
} else { } else {
row.setTitle(item.getTitle().getValue(defaultLocale)); row.setTitle(item.getTitle().getValue(defaultLocale));
} }
final ContentType type = item.getContentType(); final ContentType type = item.getContentType();
final ContentTypeInfo typeInfo = typesManager.getContentTypeInfo( final ContentTypeInfo typeInfo = typesManager.getContentTypeInfo(
type); type);
row.setTypeLabelBundle(typeInfo.getLabelBundle()); row.setTypeLabelBundle(typeInfo.getLabelBundle());
row.setTypeLabelKey(typeInfo.getLabelKey()); row.setTypeLabelKey(typeInfo.getLabelKey());
@ -415,21 +418,21 @@ public class FolderBrowserController {
if (objectId.startsWith("folder-")) { if (objectId.startsWith("folder-")) {
final long folderId = Long.parseLong( final long folderId = Long.parseLong(
objectId.substring("folder-".length())); objectId.substring("folder-".length()));
folderRepo folderRepo
.findById(folderId) .findById(folderId)
.ifPresent(folderRepo::delete); .ifPresent(folderRepo::delete);
} else if (objectId.startsWith("item-")) { } else if (objectId.startsWith("item-")) {
final long itemId = Long.parseLong( final long itemId = Long.parseLong(
objectId.substring("item-".length())); objectId.substring("item-".length()));
itemRepo itemRepo
.findById(itemId) .findById(itemId)
.ifPresent(itemRepo::delete); .ifPresent(itemRepo::delete);
} else { } else {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"The objectId is expected to start with 'folder-' or 'item.'."); "The objectId is expected to start with 'folder-' or 'item.'.");
} }
} }
@ -445,20 +448,21 @@ public class FolderBrowserController {
* name in ascending and descending order depending on the value of * name in ascending and descending order depending on the value of
* {@code orderDirection}. * {@code orderDirection}.
* *
* @param folder The folder which contains the subfolders. * @param folder The folder which contains the subfolders.
* @param filterTerm The filter term. * @param filterTerm The filter term.
* @param orderBy Field to use for ordering. If the value is negative the * @param orderBy Field to use for ordering. If the value is negative
* parameter is ignored. * the parameter is ignored.
* @param orderDirection Direction for ordering. If the value is negative * @param orderDirection Direction for ordering. If the value is negative
* the parameter is ignored. * the parameter is ignored.
* @param firstResult Index of the first result to retrieve. * @param firstResult Index of the first result to retrieve.
* @param maxResults Maxium number of results to retrieve. * @param maxResults Maxium number of results to retrieve.
* *
* *
* @return A list of the subfolders of the provided {@code folder} which * @return A list of the subfolders of the provided {@code folder} which
* match the provided {@code filterTerm}. The list is ordered as described * match the provided {@code filterTerm}. The list is ordered as
* above. The list will contain at most {@code maxResults} starting with the * described above. The list will contain at most {@code maxResults}
* result with the index provided as {@code firstResult}. * starting with the result with the index provided as
* {@code firstResult}.
*/ */
private List<Folder> findSubFolders(final Folder folder, private List<Folder> findSubFolders(final Folder folder,
final String filterTerm, final String filterTerm,
@ -466,28 +470,33 @@ public class FolderBrowserController {
final String orderDirection, final String orderDirection,
final int firstResult, final int firstResult,
final int maxResults) { final int maxResults) {
final CriteriaBuilder builder = entityManager
.getCriteriaBuilder();
final CriteriaQuery<Folder> criteria = builder.createQuery( final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
Folder.class);
final CriteriaQuery<Folder> criteria = builder
.createQuery(Folder.class);
final Root<Folder> from = criteria.from(Folder.class); final Root<Folder> from = criteria.from(Folder.class);
final Order order; final Order order;
if (FolderBrowser.SORT_KEY_NAME.equals(orderBy) if (FolderBrowser.SORT_KEY_NAME.equals(orderBy)
&& FolderBrowser.SORT_ACTION_DOWN.equals(orderDirection)) { && FolderBrowser.SORT_ACTION_DOWN.equals(orderDirection)) {
order = builder.desc(from.get("name")); order = builder.desc(from.get("name"));
} else { } else {
order = builder.asc(from.get("name")); order = builder.asc(from.get("name"));
} }
final TypedQuery<Folder> query = entityManager.createQuery( final TypedQuery<Folder> query = entityManager
criteria.where(builder.and( .createQuery(
criteria.where(
builder.and(
builder.equal(from.get("parentCategory"), folder), builder.equal(from.get("parentCategory"), folder),
builder builder
.like(builder.lower(from.get("name")), .like(builder.lower(from.get("name")),
filterTerm))) filterTerm)
.orderBy(order)); )
)
.orderBy(order)
);
if (firstResult >= 0) { if (firstResult >= 0) {
query.setFirstResult(firstResult); query.setFirstResult(firstResult);
@ -502,21 +511,22 @@ public class FolderBrowserController {
/** /**
* Retrieves all items of a folder matching the provided filter term. * Retrieves all items of a folder matching the provided filter term.
* *
* @param folder The folder which contains the subfolders. * @param folder The folder which contains the subfolders.
* @param filterTerm The filter term. * @param filterTerm The filter term.
* @param orderBy Field to use for ordering. If the value is negative the * @param orderBy Field to use for ordering. If the value is negative
* parameter is ignored. * the parameter is ignored.
* @param orderDirection Direction for ordering. If the value is negative * @param orderDirection Direction for ordering. If the value is negative
* the parameter is ignored. * the parameter is ignored.
* @param firstResult Index of the first result to retrieve. * @param firstResult Index of the first result to retrieve.
* @param maxResults Maxium number of results to retrieve. * @param maxResults Maxium number of results to retrieve.
* *
* *
* @return A list of the subfolders of the provided {@code folder} which * @return A list of the subfolders of the provided {@code folder} which
* match the provided {@code filterTerm}. The list is ordered the field * match the provided {@code filterTerm}. The list is ordered the
* provided as {@code orderBy} in the direction provided by * field provided as {@code orderBy} in the direction provided by
* {@code orderDirection}. The list will contain at most {@code maxResults} * {@code orderDirection}. The list will contain at most
* starting with the result with the index provided as {@code firstResult}. * {@code maxResults} starting with the result with the index
* provided as {@code firstResult}.
*/ */
private List<ContentItem> findItemsInFolder(final Folder folder, private List<ContentItem> findItemsInFolder(final Folder folder,
final String filterTerm, final String filterTerm,
@ -525,14 +535,13 @@ public class FolderBrowserController {
final int firstResult, final int firstResult,
final int maxResults) { final int maxResults) {
final CriteriaBuilder builder = entityManager final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
.getCriteriaBuilder();
final CriteriaQuery<ContentItem> criteria = builder.createQuery( final CriteriaQuery<ContentItem> criteria = builder
ContentItem.class); .createQuery(ContentItem.class);
final Root<ContentItem> fromItem = criteria.from(ContentItem.class); final Root<ContentItem> fromItem = criteria.from(ContentItem.class);
final Join<ContentItem, Categorization> join = fromItem.join( final Join<ContentItem, Categorization> join = fromItem
"categories"); .join("categories");
final Path<?> orderPath; final Path<?> orderPath;
switch (orderBy) { switch (orderBy) {
@ -543,7 +552,7 @@ public class FolderBrowserController {
orderPath = fromItem.get("creationDate"); orderPath = fromItem.get("creationDate");
break; break;
case FolderBrowser.SORT_KEY_LAST_MODIFIED_DATE: case FolderBrowser.SORT_KEY_LAST_MODIFIED_DATE:
orderPath = fromItem.get("lastModified"); orderPath = fromItem.get("lastModifed");
break; break;
default: default:
orderPath = fromItem.get("displayName"); orderPath = fromItem.get("displayName");
@ -557,17 +566,22 @@ public class FolderBrowserController {
order = builder.asc(orderPath); order = builder.asc(orderPath);
} }
final TypedQuery<ContentItem> query = entityManager.createQuery(criteria final TypedQuery<ContentItem> query = entityManager
.select(fromItem) .createQuery(
.where(builder.and( criteria.select(fromItem)
builder.equal(join.get("category"), folder), .where(
builder.equal(join.get("type"), builder.and(
CmsConstants.CATEGORIZATION_TYPE_FOLDER), builder.equal(join.get("category"), folder),
builder.equal(fromItem.get("version"), builder.equal(join.get("type"),
ContentItemVersion.DRAFT), CmsConstants.CATEGORIZATION_TYPE_FOLDER),
builder.like(fromItem.get("displayName"), builder.equal(fromItem.get("version"),
filterTerm))) ContentItemVersion.DRAFT),
.orderBy(order)); builder.like(fromItem.get("displayName"),
filterTerm)
)
)
.orderBy(order)
);
if (firstResult >= 0) { if (firstResult >= 0) {
query.setFirstResult(firstResult); query.setFirstResult(firstResult);
@ -585,7 +599,7 @@ public class FolderBrowserController {
* @param folder The folder to check for live items. * @param folder The folder to check for live items.
* *
* @return {@code true} if the {@code folder} or on of its subfolders * @return {@code true} if the {@code folder} or on of its subfolders
* contains at least one live item, {@code false} otherwise. * contains at least one live item, {@code false} otherwise.
*/ */
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public boolean hasLiveItems(final Folder folder) { public boolean hasLiveItems(final Folder folder) {
@ -595,24 +609,24 @@ public class FolderBrowserController {
//Ensure that we use an non detached entity. //Ensure that we use an non detached entity.
final Folder theFolder = folderRepo.findById(folder.getObjectId()) final Folder theFolder = folderRepo.findById(folder.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No folder with id %s in the database. Where did that ID come from?", "No folder with id %s in the database. Where did that ID come from?",
folder.getObjectId()))); folder.getObjectId())));
final boolean hasLiveItem = theFolder.getObjects() final boolean hasLiveItem = theFolder.getObjects()
.stream() .stream()
.map(categorization -> categorization.getCategorizedObject()) .map(categorization -> categorization.getCategorizedObject())
.filter(object -> object instanceof ContentItem) .filter(object -> object instanceof ContentItem)
.map(object -> (ContentItem) object) .map(object -> (ContentItem) object)
.filter(item -> itemManager.isLive(item)) .filter(item -> itemManager.isLive(item))
.anyMatch(item -> itemManager.isLive(item)); .anyMatch(item -> itemManager.isLive(item));
if (hasLiveItem) { if (hasLiveItem) {
return true; return true;
} else { } else {
return theFolder.getSubFolders() return theFolder.getSubFolders()
.stream() .stream()
.anyMatch(currentFolder -> hasLiveItems(currentFolder)); .anyMatch(currentFolder -> hasLiveItems(currentFolder));
} }
} }
@ -620,6 +634,7 @@ public class FolderBrowserController {
* Get the IDs of the folders invalid for copy/move actions. * Get the IDs of the folders invalid for copy/move actions.
* *
* @param sources * @param sources
*
* @return * @return
*/ */
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
@ -628,20 +643,20 @@ public class FolderBrowserController {
Objects.requireNonNull(sources); Objects.requireNonNull(sources);
final List<String> sourceFolderIds = sources final List<String> sourceFolderIds = sources
.stream() .stream()
.filter(source -> source.startsWith( .filter(source -> source.startsWith(
FOLDER_BROWSER_KEY_PREFIX_FOLDER)) FOLDER_BROWSER_KEY_PREFIX_FOLDER))
.collect(Collectors.toList()); .collect(Collectors.toList());
final List<String> parentFolderIds = sourceFolderIds final List<String> parentFolderIds = sourceFolderIds
.stream() .stream()
.map(sourceFolderId -> findParentFolderId(sourceFolderId)) .map(sourceFolderId -> findParentFolderId(sourceFolderId))
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get) .map(Optional::get)
.collect(Collectors.toList()); .collect(Collectors.toList());
final List<List<String>> subFolderIds = sourceFolderIds final List<List<String>> subFolderIds = sourceFolderIds
.stream() .stream()
.map(sourceFolderId -> findSubFolderIds(sourceFolderId)) .map(sourceFolderId -> findSubFolderIds(sourceFolderId))
.collect(Collectors.toList()); .collect(Collectors.toList());
final List<String> invalidTargetIds = new ArrayList<>(); final List<String> invalidTargetIds = new ArrayList<>();
invalidTargetIds.addAll(sourceFolderIds); invalidTargetIds.addAll(sourceFolderIds);
@ -659,26 +674,26 @@ public class FolderBrowserController {
if (!folderId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { if (!folderId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"Provided string '%s' is not an ID of a folder.", "Provided string '%s' is not an ID of a folder.",
folderId)); folderId));
} }
final long objectId = Long.parseLong(folderId.substring( final long objectId = Long.parseLong(folderId.substring(
FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())); FOLDER_BROWSER_KEY_PREFIX_FOLDER.length()));
final Folder folder = folderRepo.findById(objectId) final Folder folder = folderRepo.findById(objectId)
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No folder with ID %d found in database. " "No folder with ID %d found in database. "
+ "Where did that ID come form?", + "Where did that ID come form?",
objectId))); objectId)));
final Optional<Folder> parentFolder = folderManager.getParentFolder( final Optional<Folder> parentFolder = folderManager.getParentFolder(
folder); folder);
if (parentFolder.isPresent()) { if (parentFolder.isPresent()) {
return Optional.empty(); return Optional.empty();
} else { } else {
return Optional.ofNullable(String.format( return Optional.ofNullable(String.format(
"%s%d", "%s%d",
FOLDER_BROWSER_KEY_PREFIX_FOLDER, FOLDER_BROWSER_KEY_PREFIX_FOLDER,
parentFolder.get().getObjectId())); parentFolder.get().getObjectId()));
} }
} }
@ -688,23 +703,23 @@ public class FolderBrowserController {
if (!folderId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { if (!folderId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"Provided string '%s' is not the ID of a folder.", "Provided string '%s' is not the ID of a folder.",
folderId)); folderId));
} }
final long objectId = Long.parseLong(folderId.substring( final long objectId = Long.parseLong(folderId.substring(
FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())); FOLDER_BROWSER_KEY_PREFIX_FOLDER.length()));
final Folder folder = folderRepo.findById(objectId) final Folder folder = folderRepo.findById(objectId)
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No folder with ID %d found in database. " "No folder with ID %d found in database. "
+ "Where did that ID come form?", + "Where did that ID come form?",
objectId))); objectId)));
return findSubFolders(folder) return findSubFolders(folder)
.stream() .stream()
.map(subFolder -> String.format("%s%d", .map(subFolder -> String.format("%s%d",
FOLDER_BROWSER_KEY_PREFIX_FOLDER, FOLDER_BROWSER_KEY_PREFIX_FOLDER,
subFolder.getObjectId())) subFolder.getObjectId()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
private List<Folder> findSubFolders(final Folder folder) { private List<Folder> findSubFolders(final Folder folder) {
@ -712,7 +727,7 @@ public class FolderBrowserController {
Objects.requireNonNull(folder); Objects.requireNonNull(folder);
if (folder.getSubFolders() == null if (folder.getSubFolders() == null
|| folder.getSubFolders().isEmpty()) { || folder.getSubFolders().isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -736,17 +751,17 @@ public class FolderBrowserController {
if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) {
moveFolder(targetFolder, moveFolder(targetFolder,
Long.parseLong(objectId.substring( Long.parseLong(objectId.substring(
FOLDER_BROWSER_KEY_PREFIX_FOLDER.length()))); FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())));
} else if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_ITEM)) { } else if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_ITEM)) {
moveItem(targetFolder, moveItem(targetFolder,
Long.parseLong(objectId.substring( Long.parseLong(objectId.substring(
FOLDER_BROWSER_KEY_PREFIX_ITEM.length()))); FOLDER_BROWSER_KEY_PREFIX_ITEM.length())));
} else { } else {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"ID '%s' does not start with '%s' or '%s'.", "ID '%s' does not start with '%s' or '%s'.",
objectId, objectId,
FOLDER_BROWSER_KEY_PREFIX_FOLDER, FOLDER_BROWSER_KEY_PREFIX_FOLDER,
FOLDER_BROWSER_KEY_PREFIX_ITEM)); FOLDER_BROWSER_KEY_PREFIX_ITEM));
} }
} }
} }
@ -756,10 +771,10 @@ public class FolderBrowserController {
Objects.requireNonNull(targetFolder); Objects.requireNonNull(targetFolder);
final Folder folder = folderRepo.findById(folderId) final Folder folder = folderRepo.findById(folderId)
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No folder with ID %d in the database. " "No folder with ID %d in the database. "
+ "Where did that ID come from?", + "Where did that ID come from?",
folderId))); folderId)));
folderManager.moveFolder(folder, targetFolder); folderManager.moveFolder(folder, targetFolder);
} }
@ -769,10 +784,10 @@ public class FolderBrowserController {
Objects.requireNonNull(targetFolder); Objects.requireNonNull(targetFolder);
final ContentItem item = itemRepo.findById(itemId) final ContentItem item = itemRepo.findById(itemId)
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No content item with ID %d in the database. " "No content item with ID %d in the database. "
+ "Where did that ID come from?", + "Where did that ID come from?",
itemId))); itemId)));
itemManager.move(item, targetFolder); itemManager.move(item, targetFolder);
} }
@ -788,17 +803,17 @@ public class FolderBrowserController {
if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) { if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_FOLDER)) {
copyFolder(targetFolder, copyFolder(targetFolder,
Long.parseLong(objectId.substring( Long.parseLong(objectId.substring(
FOLDER_BROWSER_KEY_PREFIX_FOLDER.length()))); FOLDER_BROWSER_KEY_PREFIX_FOLDER.length())));
} else if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_ITEM)) { } else if (objectId.startsWith(FOLDER_BROWSER_KEY_PREFIX_ITEM)) {
copyItem(targetFolder, copyItem(targetFolder,
Long.parseLong(objectId.substring( Long.parseLong(objectId.substring(
FOLDER_BROWSER_KEY_PREFIX_ITEM.length()))); FOLDER_BROWSER_KEY_PREFIX_ITEM.length())));
} else { } else {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"ID '%s' does not start with '%s' or '%s'.", "ID '%s' does not start with '%s' or '%s'.",
objectId, objectId,
FOLDER_BROWSER_KEY_PREFIX_FOLDER, FOLDER_BROWSER_KEY_PREFIX_FOLDER,
FOLDER_BROWSER_KEY_PREFIX_ITEM)); FOLDER_BROWSER_KEY_PREFIX_ITEM));
} }
} }
} }
@ -809,10 +824,10 @@ public class FolderBrowserController {
Objects.requireNonNull(targetFolder); Objects.requireNonNull(targetFolder);
final Folder folder = folderRepo.findById(folderId) final Folder folder = folderRepo.findById(folderId)
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No folder with ID %d in the database. " "No folder with ID %d in the database. "
+ "Where did that ID come from?", + "Where did that ID come from?",
folderId))); folderId)));
folderManager.copyFolder(folder, targetFolder); folderManager.copyFolder(folder, targetFolder);
} }
@ -823,10 +838,10 @@ public class FolderBrowserController {
Objects.requireNonNull(targetFolder); Objects.requireNonNull(targetFolder);
final ContentItem item = itemRepo.findById(itemId) final ContentItem item = itemRepo.findById(itemId)
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No content item with ID %d in the database. " "No content item with ID %d in the database. "
+ "Where did that ID come from?", + "Where did that ID come from?",
itemId))); itemId)));
itemManager.copy(item, targetFolder); itemManager.copy(item, targetFolder);
} }

View File

@ -53,7 +53,7 @@ class FolderBrowserTableModel implements TableModel {
@Override @Override
public int getColumnCount() { public int getColumnCount() {
return 6; return 7;
} }
@Override @Override

View File

@ -37,7 +37,8 @@ import java.util.List;
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
class FolderBrowserTableModelBuilder extends LockableImpl class FolderBrowserTableModelBuilder
extends LockableImpl
implements TableModelBuilder { implements TableModelBuilder {
private final static Logger LOGGER = LogManager.getLogger( private final static Logger LOGGER = LogManager.getLogger(
@ -48,7 +49,8 @@ class FolderBrowserTableModelBuilder extends LockableImpl
final PageState state) { final PageState state) {
if (!(table instanceof FolderBrowser)) { if (!(table instanceof FolderBrowser)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"The FolderBrowserTableModelBuilder can be used for the FolderBrowser."); "The FolderBrowserTableModelBuilder can only be used for the "
+ "FolderBrowser.");
} }
final FolderBrowser folderBrowser = (FolderBrowser) table; final FolderBrowser folderBrowser = (FolderBrowser) table;
final FolderSelectionModel folderSelectionModel = folderBrowser final FolderSelectionModel folderSelectionModel = folderBrowser
@ -60,8 +62,8 @@ class FolderBrowserTableModelBuilder extends LockableImpl
folderBrowser.getRowSelectionModel().clearSelection(state); folderBrowser.getRowSelectionModel().clearSelection(state);
final Paginator paginator = folderBrowser.getPaginator(); final Paginator paginator = folderBrowser.getPaginator();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final FolderBrowserController controller = cdiUtil.findBean( final FolderBrowserController controller = cdiUtil
FolderBrowserController.class); .findBean(FolderBrowserController.class);
final String filter = folderBrowser.getFilter(state); final String filter = folderBrowser.getFilter(state);
final String orderBy; final String orderBy;
if (folderBrowser.getSortType(state) == null) { if (folderBrowser.getSortType(state) == null) {