CCM NG/ccm-cms: First part of migration the ReportPane

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4520 8810af33-2d31-482b-a856-94f89814c4df
jensp 2017-01-16 20:03:20 +00:00
parent 8ac6b655a0
commit b061e0e50b
9 changed files with 836 additions and 173 deletions

View File

@ -24,21 +24,18 @@ import com.arsdigita.bebop.list.ListModelBuilder;
import com.arsdigita.bebop.tree.TreeModelBuilder; import com.arsdigita.bebop.tree.TreeModelBuilder;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.toolbox.ui.SelectionPanel; import com.arsdigita.toolbox.ui.SelectionPanel;
import org.apache.log4j.Logger;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
/** /**
* A base component for use in CMS admin panes. * A base component for use in CMS admin panes.
* *
* @param <T> Type managed by the {@link SingleSelectionModel} used by instances
* of this class.
*
* @author Justin Ross &lt;jross@redhat.com&gt; * @author Justin Ross &lt;jross@redhat.com&gt;
*/ */
public abstract class BaseAdminPane extends SelectionPanel { public abstract class BaseAdminPane<T> extends SelectionPanel<T> {
/** Internal logger instance to faciliate debugging. Enable logging output
* by editing /WEB-INF/conf/log4j.properties int the runtime environment
* and set com.arsdigita.cms.ui.BaseAdminPane=DEBUG
* by uncommenting or adding the line. */
private static final Logger s_log = Logger.getLogger(BaseAdminPane.class);
protected BaseAdminPane() { protected BaseAdminPane() {
super(); super();
@ -56,13 +53,13 @@ public abstract class BaseAdminPane extends SelectionPanel {
protected BaseAdminPane(final Component title, protected BaseAdminPane(final Component title,
final Component selector, final Component selector,
final SingleSelectionModel model) { final SingleSelectionModel<T> model) {
super(title, selector, model); super(title, selector, model);
} }
protected BaseAdminPane(final GlobalizedMessage title, protected BaseAdminPane(final GlobalizedMessage title,
final Component selector, final Component selector,
final SingleSelectionModel model) { final SingleSelectionModel<T> model) {
super(title, selector, model); super(title, selector, model);
} }
@ -93,4 +90,5 @@ public abstract class BaseAdminPane extends SelectionPanel {
protected static String lz(final String key) { protected static String lz(final String key) {
return (String) gz(key).localize(); return (String) gz(key).localize();
} }
} }

View File

@ -15,7 +15,6 @@
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
package com.arsdigita.cms.ui; package com.arsdigita.cms.ui;
import java.util.ArrayList; import java.util.ArrayList;
@ -40,119 +39,133 @@ import com.arsdigita.toolbox.ui.Section;
import com.arsdigita.util.LockableImpl; import com.arsdigita.util.LockableImpl;
/** /**
* A pane that shows selectable reports and their results. * A pane that shows selectable reports and their results. A selectable list of
* A selectable list of reports is shown on the left-hand side, a selected report is shown as * reports is shown on the left-hand side, a selected report is shown as body.
* body. *
* * @author
* @author <a href="https://sourceforge.net/users/thomas-buckel/">thomas-buckel</a> * <a href="https://sourceforge.net/users/thomas-buckel/">thomas-buckel</a>
* @author <a href="https://sourceforge.net/users/tim-permeance/">tim-permeance</a> * @author
* <a href="https://sourceforge.net/users/tim-permeance/">tim-permeance</a>
* @author <a href="jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class ReportPane extends BaseAdminPane { public class ReportPane extends BaseAdminPane<String> {
private final SingleSelectionModel m_selectionModel; private final SingleSelectionModel<String> selectionModel;
private final java.util.List<Report> m_availableReports; private final java.util.List<Report> availableReports;
public ReportPane() { public ReportPane() {
m_availableReports = getReports(); availableReports = getReports();
m_selectionModel = new ParameterSingleSelectionModel(new StringParameter(List.SELECTED));
m_selectionModel.addChangeListener(new SelectionListener());
setSelectionModel(m_selectionModel);
List m_reports = new List(new ReportListModelBuilder(m_availableReports)); selectionModel = new ParameterSingleSelectionModel<>(
m_reports.setSelectionModel(m_selectionModel); new StringParameter(List.SELECTED));
selectionModel.addChangeListener(new SelectionListener());
setSelectionModel(selectionModel);
final ReportsListSection reportsListSection = new ReportsListSection(m_reports); List m_reports = new List(new ReportListModelBuilder(availableReports));
m_reports.setSelectionModel(selectionModel);
final ReportsListSection reportsListSection = new ReportsListSection(
m_reports);
setLeft(reportsListSection); setLeft(reportsListSection);
// Register the actual components of the reports for later usage // Register the actual components of the reports for later usage
for (Report report : m_availableReports) { for (Report report : availableReports) {
getBody().add(report.getComponent()); getBody().add(report.getComponent());
} }
setIntroPane(new Label(gz("cms.ui.reports.intro"))); setIntroPane(new Label(gz("cms.ui.reports.intro")));
} }
/** /**
* @return List of available reports. * @return List of available reports.
*/ */
private java.util.List<Report> getReports() { private java.util.List<Report> getReports() {
java.util.List<Report> reports = new ArrayList<Report>(); java.util.List<Report> reports = new ArrayList<>();
reports.add(new Report("cms.ui.reports.css.reportName", new ContentSectionSummaryTable())); reports.add(new Report("cms.ui.reports.css.reportName",
// Add other reports as required new ContentSectionSummaryTable()));
// Add other reports as required
Collections.sort(reports, new Comparator<Report>() {
@Override Collections.sort(
public int compare(Report r1, Report r2) { reports,
return r1.getName().compareTo(r2.getName()); (r1, r2) -> r1.getName().compareTo(r2.getName()));
}
}); return reports;
return reports;
} }
/** /**
* Get the report model that matches the given key. * Get the report model that matches the given key.
* @param key Key to match. *
* @return Report model that matches that given key, null if no matching report was found. * @param key Key to match.
*
* @return Report model that matches that given key, null if no matching
* report was found.
*/ */
private Report getReportByKey(String key) { private Report getReportByKey(final String key) {
for (Report report : m_availableReports) { for (Report report : availableReports) {
if (report.getKey().equals(key)) { if (report.getKey().equals(key)) {
return report; return report;
} }
} }
return null; return null;
} }
/** /**
* UI section for left-hand list of reports. * UI section for left-hand list of reports.
*/ */
private class ReportsListSection extends Section { private class ReportsListSection extends Section {
ReportsListSection(List reports) {
ReportsListSection(final List reports) {
setHeading(gz("cms.ui.reports.header")); setHeading(gz("cms.ui.reports.header"));
ActionGroup group = new ActionGroup(); ActionGroup group = new ActionGroup();
setBody(group); setBody(group);
group.setSubject(reports); group.setSubject(reports);
} }
} }
/** /**
* SelectionListener for selected report. It shows the selected report in the body of this * SelectionListener for selected report. It shows the selected report in
* component. * the body of this component.
*/ */
private class SelectionListener implements ChangeListener { private class SelectionListener implements ChangeListener {
public final void stateChanged(final ChangeEvent e) {
final PageState state = e.getPageState(); @Override
public final void stateChanged(final ChangeEvent event) {
final PageState state = event.getPageState();
getBody().reset(state); getBody().reset(state);
if (m_selectionModel.isSelected(state)) { if (selectionModel.isSelected(state)) {
Report selectedReport = getReportByKey(m_selectionModel.getSelectedKey(state).toString()); Report selectedReport = getReportByKey(selectionModel
if (selectedReport != null) { .getSelectedKey(state).toString());
getBody().push(state, selectedReport.getComponent()); if (selectedReport != null) {
} getBody().push(state, selectedReport.getComponent());
}
} }
} }
} }
/** /**
* ListModelBuilder creating a ReportListModel for a list of reports. * ListModelBuilder creating a ReportListModel for a list of reports.
*/ */
private static class ReportListModelBuilder extends LockableImpl implements ListModelBuilder { private static class ReportListModelBuilder
extends LockableImpl
private java.util.List<Report> reports; implements ListModelBuilder {
private ReportListModelBuilder(java.util.List<Report> reports) { private final java.util.List<Report> reports;
this.reports = reports;
} private ReportListModelBuilder(final java.util.List<Report> reports) {
this.reports = reports;
}
@Override
public final ListModel makeModel(final List list, public final ListModel makeModel(final List list,
final PageState state) { final PageState state) {
return new ReportListModel(reports); return new ReportListModel(reports);
} }
} }
} }

View File

@ -0,0 +1,215 @@
/*
* 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.report;
import com.arsdigita.bebop.table.RowData;
import org.libreccm.categorization.Categorization;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionRepository;
import org.librecms.contentsection.ContentType;
import org.librecms.contentsection.Folder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class ContentSectionSummaryController {
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private ContentItemManager itemManager;
@Inject
private GlobalizationHelper globalizationHelper;
@Transactional(Transactional.TxType.REQUIRED)
public List<RowData<Long>> createReportData(final ContentSection section) {
final ContentSection contentSection = sectionRepo.findById(
section.getObjectId());
final List<Folder> rootFolders = contentSection.getRootDocumentsFolder()
.getSubFolders();
final List<RowData<Long>> data = new ArrayList<>();
for (final Folder folder : rootFolders) {
data.addAll(createFolderData(folder));
}
return data;
}
private List<RowData<Long>> createFolderData(final Folder folder) {
final List<RowData<Long>> data = new ArrayList<>();
final long subFolderCount = countSubFolders(folder);
final List<ContentTypeFolderInfo> contentTypeInfo = generateContentTypeInfoForFolder(
folder);
final RowData<Long> firstRow = new RowData<>(5);
firstRow.setRowKey(-1L);
firstRow.setColData(ContentSectionSummaryTable.COL_FOLDER_NAME,
folder.getDisplayName());
firstRow.setColData(ContentSectionSummaryTable.COL_SUBFOLDER_COUNT,
Long.toString(subFolderCount));
firstRow.setColData(ContentSectionSummaryTable.COL_CONTENT_TYPE,
contentTypeInfo.get(0).getTypeName());
firstRow.setColData(ContentSectionSummaryTable.COL_CONTENT_TYPE,
Long.toString(contentTypeInfo.get(0).getDraftCount()));
firstRow.setColData(ContentSectionSummaryTable.COL_CONTENT_TYPE,
Long.toString(contentTypeInfo.get(0).getLiveCount()));
data.add(firstRow);
for(int i = 1; i < contentTypeInfo.size(); i++) {
data.add(createRow(contentTypeInfo.get(i)));
}
return data;
}
private RowData<Long> createRow(final ContentTypeFolderInfo info) {
final RowData<Long> row = new RowData<>(5);
row.setRowKey(-1L);
row.setColData(ContentSectionSummaryTable.COL_FOLDER_NAME, "");
row.setColData(ContentSectionSummaryTable.COL_SUBFOLDER_COUNT, "");
row.setColData(ContentSectionSummaryTable.COL_CONTENT_TYPE,
info.getTypeClassName());
row.setColData(ContentSectionSummaryTable.COL_DRAFT_COUNT,
Long.toString(info.getDraftCount()));
row.setColData(ContentSectionSummaryTable.COL_LIVE_COUNT,
Long.toString(info.getLiveCount()));
return row;
}
private long countSubFolders(final Folder folder) {
long count = 0;
for (final Folder subFolder : folder.getSubFolders()) {
count++;
count += countSubFolders(subFolder);
}
return count;
}
private List<ContentTypeFolderInfo> generateContentTypeInfoForFolder(
final Folder folder) {
final Map<String, ContentTypeFolderInfo> dataMap = new HashMap<>();
generateContentTypeInfoForFolder(folder, dataMap);
final List<ContentTypeFolderInfo> data = new ArrayList<>(dataMap
.values());
Collections.sort(
data,
(info1, info2) -> {
return info1.getTypeName().compareTo(info2.getTypeName());
});
return data;
}
private void generateContentTypeInfoForFolder(
final Folder folder, final Map<String, ContentTypeFolderInfo> data) {
for (final Categorization categorization : folder.getObjects()) {
if (!(categorization.getCategorizedObject() instanceof ContentItem)) {
continue;
}
final ContentItem item = (ContentItem) categorization
.getCategorizedObject();
final ContentType type = item.getContentType();
final ContentTypeFolderInfo info;
if (data.containsKey(type.getContentItemClass())) {
info = data.get(type.getContentItemClass());
} else {
info = new ContentTypeFolderInfo(
type.getContentItemClass(),
type.getLabel().getValue(globalizationHelper
.getNegotiatedLocale()));
}
info.increaseDraftCount();
if (itemManager.isLive(item)) {
info.increaseLiveCount();
}
}
for (final Folder subFolder : folder.getSubFolders()) {
generateContentTypeInfoForFolder(subFolder, data);
}
}
private class ContentTypeFolderInfo {
private final String typeClassName;
private final String typeName;
private long draftCount = 0;
private long liveCount = 0;
public ContentTypeFolderInfo(final String typeClassName,
final String typeName) {
this.typeClassName = typeClassName;
this.typeName = typeName;
}
public String getTypeClassName() {
return typeClassName;
}
public String getTypeName() {
return typeName;
}
public long getDraftCount() {
return draftCount;
}
public void increaseDraftCount() {
draftCount++;
}
public long getLiveCount() {
return liveCount;
}
public void increaseLiveCount() {
liveCount++;
}
}
}

View File

@ -0,0 +1,251 @@
/*
* Copyright (C) 2009 Permeance Technologies Pty Ltd. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.arsdigita.cms.ui.report;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.table.AbstractTableModelBuilder;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.cms.CMS;
import org.librecms.contentsection.Folder;
/**
* TableModelBuilder that creates a model for the content section summary
* report.
*
* @author
* <a href="https://sourceforge.net/users/thomas-buckel/">thomas-buckel</a>
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ContentSectionSummaryReportTableModelBuilder
extends AbstractTableModelBuilder {
@Override
public TableModel makeModel(final Table table, final PageState state) {
Session session = SessionManager.getSession();
DataQuery query = session.retrieveQuery(
"com.arsdigita.cms.getContentSectionSummary");
query.setParameter("sectionId", CMS.getContext().getContentSection()
.getID());
return new CSSRModel(new DataQueryDataCollectionAdapter(query, "folder"));
}
/**
* Generates a table model by combining a list of top level folder (content
* items) with statistics about content items with in the folder in draft
* and live versions.
*/
private class CSSRModel implements TableModel {
private final DataCollection m_folders;
private String m_folderName;
private BigDecimal m_subfolderCount;
private ContentTypeStatistics m_currentStatsRow;
private Iterator<ContentTypeStatistics> m_contentTypeStatIter;
CSSRModel(DataCollection folders) {
m_folders = folders;
}
@Override
public final int getColumnCount() {
return 5;
}
/**
* Combines an 'outer' iterator over the given DataCollection with an
* 'inner' iterator that contains rows for each row of the outer
* collection. {@inheritDoc}
*/
@Override
public final boolean nextRow() {
if ((m_contentTypeStatIter == null) && m_folders.next()) {
m_folderName = (String) m_folders.get("folder");
m_subfolderCount = (BigDecimal) m_folders.get("subfolderCount");
Folder draftFolder = new Folder((BigDecimal) m_folders.get(
"folderId"));
m_contentTypeStatIter = retrieveContentTypeStats(draftFolder);
if (m_contentTypeStatIter.hasNext()) {
m_currentStatsRow = m_contentTypeStatIter.next();
} else {
// Rather than recursing into nextRow() again, a m_currentStatsRow == null
// is rendered to show one row for the folder but with no content type or values.
m_contentTypeStatIter = null;
m_currentStatsRow = null;
}
return true;
} else if (m_contentTypeStatIter != null) {
if (m_contentTypeStatIter.hasNext()) {
m_currentStatsRow = m_contentTypeStatIter.next();
} else {
m_contentTypeStatIter = null;
return nextRow();
}
return true;
} else {
m_folders.close();
return false;
}
}
@Override
public final Object getKeyAt(final int column) {
return -1;
}
@Override
public final Object getElementAt(final int column) {
switch (column) {
case 0:
return m_folderName;
case 1:
return m_subfolderCount.toString();
case 2:
return (m_currentStatsRow != null) ? m_currentStatsRow
.getContentType() : "N/A";
case 3:
return (m_currentStatsRow != null) ? m_currentStatsRow
.getDraftCount() : "N/A";
case 4:
return (m_currentStatsRow != null) ? m_currentStatsRow
.getLiveCount() : "N/A";
default:
throw new IllegalArgumentException("Illegal column index "
+ column);
}
}
/**
* Retrieve a list of content types used within a folder and for each
* content type the number of draft and live content items of this type.
*
* @param draftFolder Draft folder to retrieve stats for.
*
* @return Iterator over the retrieved statistics. Empty iterator with
* no results where found.
*/
private Iterator<ContentTypeStatistics> retrieveContentTypeStats(
Folder draftFolder) {
Session session = SessionManager.getSession();
// Query the number of content items per content type for drafts
DataQuery query = session.retrieveQuery(
"com.arsdigita.cms.getContentTypeCountPerFolder");
query.setParameter("folderId", draftFolder.getID());
DataCollection types = new DataQueryDataCollectionAdapter(query,
"types");
Map<String, Long> draftContentTypeCounts
= new HashMap<String, Long>();
try {
while (types.next()) {
draftContentTypeCounts
.put((String) types.get("contentType"), (Long) types
.get("typeCount"));
}
} finally {
types.close();
}
// If there's a live version of the folder, query the number of content items per content type for it
// and merge both draft and live numbers
List<ContentTypeStatistics> result
= new ArrayList<ContentTypeStatistics>();
Folder liveFolder = (Folder) draftFolder.getLiveVersion();
if (liveFolder != null) {
query = session.retrieveQuery(
"com.arsdigita.cms.getContentTypeCountPerFolder");
query.setParameter("folderId", liveFolder.getID());
types = new DataQueryDataCollectionAdapter(query, "types");
try {
while (types.next()) {
String contentType = (String) types.get("contentType");
long draftCount = (draftContentTypeCounts.get(
contentType) != null)
? draftContentTypeCounts
.get(contentType) : 0;
long liveCount = (Long) types.get("typeCount");
result.add(new ContentTypeStatistics(contentType,
draftCount,
liveCount));
draftContentTypeCounts.remove(contentType);
}
} finally {
types.close();
}
}
// Add all draft stats that haven't been merged
for (Map.Entry<String, Long> draftCount : draftContentTypeCounts
.entrySet()) {
result.add(new ContentTypeStatistics(draftCount.getKey(),
draftCount.getValue(), 0));
}
return result.iterator();
}
}
/**
* Value object that holds content type statistics for a folder.
*/
private static class ContentTypeStatistics {
private final String m_contentType;
private final long m_draftCount;
private final long m_liveCount;
public ContentTypeStatistics(String contentType, long draftCount,
long liveCount) {
m_contentType = contentType;
m_draftCount = draftCount;
m_liveCount = liveCount;
}
public String getContentType() {
return m_contentType;
}
public long getDraftCount() {
return m_draftCount;
}
public long getLiveCount() {
return m_liveCount;
}
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2009 Permeance Technologies Pty Ltd. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.arsdigita.cms.ui.report;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Table;
/**
* Table component for content section summary report.
*
* @author
* <a href="https://sourceforge.net/users/thomas-buckel/">thomas-buckel</a>
*/
public class ContentSectionSummaryTable extends Table {
public static final int COL_FOLDER_NAME = 0;
public static final int COL_SUBFOLDER_COUNT = 1;
public static final int COL_CONTENT_TYPE = 2;
public static final int COL_DRAFT_COUNT = 3;
public static final int COL_LIVE_COUNT = 4;
private static final String[] s_fixedReportColumns = new String[]{
lz("cms.ui.reports.css.folder"),
lz("cms.ui.reports.css.subfolderCount"),
lz("cms.ui.reports.css.contentType"),
lz("cms.ui.reports.css.draft"),
lz("cms.ui.reports.css.live"),};
public ContentSectionSummaryTable() {
super(new ContentSectionSummaryReportTableModelBuilder(),
s_fixedReportColumns);
setEmptyView(new Label(lz("cms.ui.reports.css.emptyResult")));
}
private static String lz(final String key) {
return (String) GlobalizationUtil.globalize(key).localize();
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2009 Permeance Technologies Pty Ltd. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.arsdigita.cms.ui.report;
import com.arsdigita.bebop.Component;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.Assert;
import org.librecms.CmsConstants;
/**
* UI model for a report.
* A report has a name and a component that displays the report.
*
* @author <a href="https://sourceforge.net/users/thomas-buckel/">thomas-buckel</a>
* @author <a href="https://sourceforge.net/users/tim-permeance/">tim-permeance</a>
* @author <a href="jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class Report {
private final String key;
private final String name;
private final Component component;
public Report(final String key, final Component component) {
Assert.exists(key, "Key for report is required");
Assert.isTrue(key.length() > 0, "Key for report must not be empty");
Assert.exists(component, "Component for report is required");
this.key = key;
name = gz(key).localize().toString();
this.component = component;
}
public String getKey() {
return key;
}
public String getName() {
return name;
}
public Component getComponent() {
return component;
}
protected final static GlobalizedMessage gz(final String key) {
return new GlobalizedMessage(key, CmsConstants.CMS_BUNDLE);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2009 Permeance Technologies Pty Ltd. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.arsdigita.cms.ui.report;
import java.util.List;
import com.arsdigita.bebop.list.ListModel;
import com.arsdigita.util.Assert;
/**
* ListModel for Reports.
*
* @author <a href="https://sourceforge.net/users/thomas-buckel/">thomas-buckel</a>
* @author <a href="https://sourceforge.net/users/tim-permeance/">tim-permeance</a>
*/
public class ReportListModel implements ListModel {
private int m_index = -1;
private final List<Report> m_reports;
public ReportListModel(List<Report> reports) {
Assert.exists(reports);
m_reports = reports;
}
@Override
public Object getElement() {
return m_reports.get(m_index).getName();
}
@Override
public String getKey() {
return m_reports.get(m_index).getKey();
}
@Override
public boolean next() {
m_index++;
return (m_reports.size() > m_index);
}
}

View File

@ -54,7 +54,8 @@ import static org.librecms.CmsConstants.*;
name = "Folder.rootFolders", name = "Folder.rootFolders",
query = "SELECT f FROM Folder f " query = "SELECT f FROM Folder f "
+ "WHERE f.parentCategory IS NULL " + "WHERE f.parentCategory IS NULL "
+ " AND f.type = :type"), + " AND f.type = :type")
,
@NamedQuery( @NamedQuery(
name = "Folder.findByName", name = "Folder.findByName",
query = "SELECT f FROM Folder f WHERE f.name = :name") query = "SELECT f FROM Folder f WHERE f.name = :name")
@ -92,7 +93,7 @@ public class Folder extends Category implements InheritsPermissions,
protected void setType(final FolderType type) { protected void setType(final FolderType type) {
this.type = type; this.type = type;
} }
@Override @Override
public Optional<CcmObject> getParent() { public Optional<CcmObject> getParent() {
if (getParentFolder() == null) { if (getParentFolder() == null) {
@ -110,10 +111,10 @@ public class Folder extends Category implements InheritsPermissions,
public List<Folder> getSubFolders() { public List<Folder> getSubFolders() {
return Collections.unmodifiableList( return Collections.unmodifiableList(
getSubCategories() getSubCategories()
.stream() .stream()
.filter(subCategory -> subCategory instanceof Folder) .filter(subCategory -> subCategory instanceof Folder)
.map(subCategory -> (Folder) subCategory) .map(subCategory -> (Folder) subCategory)
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
public Folder getParentFolder() { public Folder getParentFolder() {

View File

@ -33,69 +33,73 @@ import com.arsdigita.bebop.list.ListModelBuilder;
import com.arsdigita.bebop.tree.TreeModelBuilder; import com.arsdigita.bebop.tree.TreeModelBuilder;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.Assert; import com.arsdigita.util.Assert;
import org.apache.log4j.Logger;
/** import org.apache.logging.log4j.LogManager;
* TODO Needs description import org.apache.logging.log4j.Logger;
/**
* @param <T> Type managed by the {@link SingleSelectionModel} used in instances
* of this class.
*
* @author unknown
* @author <a href="jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class SelectionPanel extends LayoutPanel implements Resettable { public class SelectionPanel<T> extends LayoutPanel implements Resettable {
private static final Logger s_log = Logger.getLogger(SelectionPanel.class); private static final Logger LOGGER = LogManager.getLogger(
SelectionPanel.class);
private SingleSelectionModel<Long> m_model; private SingleSelectionModel<T> selectionModel;
private Component m_selector; private Component selector;
private ActionGroup m_group; private ActionGroup actionGroup;
private final ModalPanel m_body; private final ModalPanel body;
private Component m_introPane; private Component introPane;
private Component m_itemPane; private Component itemPane;
private ActionLink m_addLink; private ActionLink addLink;
private Form m_addForm; private Form addForm;
private ActionLink m_editLink; private ActionLink editLink;
private Form m_editForm; private Form editForm;
private ActionLink m_deleteLink; private ActionLink deleteLink;
private Form m_deleteForm; private Form deleteForm;
protected void build(final Component title, protected void build(final Component title,
final Component selector, final Component selector,
final SingleSelectionModel<Long> model) { final SingleSelectionModel<T> model) {
m_model = model; selectionModel = model;
m_selector = selector; this.selector = selector;
final Section section = new Section(); final Section section = new Section();
setLeft(section); setLeft(section);
section.setHeading(title); section.setHeading(title);
m_group = new ActionGroup(); actionGroup = new ActionGroup();
section.setBody(m_group); section.setBody(actionGroup);
m_group.setSubject(selector); actionGroup.setSubject(selector);
} }
protected SelectionPanel() { protected SelectionPanel() {
m_body = new ModalPanel(); body = new ModalPanel();
setBody(m_body); setBody(body);
m_introPane = new NullComponent(); introPane = new NullComponent();
m_body.add(m_introPane); body.add(introPane);
m_body.setDefault(m_introPane); body.setDefault(introPane);
m_itemPane = new NullComponent(); itemPane = new NullComponent();
m_body.add(m_itemPane); body.add(itemPane);
m_addLink = null; addLink = null;
m_addForm = null; addForm = null;
m_editLink = null; editLink = null;
m_editForm = null; editForm = null;
m_deleteLink = null; deleteLink = null;
m_deleteForm = null; deleteForm = null;
} }
/**
* @pre selector instanceof Tree || selector instanceof List
*/
public SelectionPanel(final Component title, public SelectionPanel(final Component title,
final Component selector) { final Component selector) {
this(); this();
@ -107,7 +111,6 @@ public class SelectionPanel extends LayoutPanel implements Resettable {
} }
// Making up now for some untoward modeling in Bebop. // Making up now for some untoward modeling in Bebop.
if (selector instanceof List) { if (selector instanceof List) {
final List list = (List) selector; final List list = (List) selector;
@ -125,7 +128,7 @@ public class SelectionPanel extends LayoutPanel implements Resettable {
public SelectionPanel(final Component title, public SelectionPanel(final Component title,
final Component selector, final Component selector,
final SingleSelectionModel model) { final SingleSelectionModel<T> model) {
this(); this();
if (Assert.isEnabled()) { if (Assert.isEnabled()) {
@ -143,7 +146,7 @@ public class SelectionPanel extends LayoutPanel implements Resettable {
public SelectionPanel(final GlobalizedMessage title, public SelectionPanel(final GlobalizedMessage title,
final Component selector, final Component selector,
final SingleSelectionModel model) { final SingleSelectionModel<T> model) {
this(new Label(title), selector, model); this(new Label(title), selector, model);
} }
@ -169,12 +172,12 @@ public class SelectionPanel extends LayoutPanel implements Resettable {
@Override @Override
public void reset(final PageState state) { public void reset(final PageState state) {
s_log.debug("Resetting to default initial state"); LOGGER.debug("Resetting to default initial state");
if (m_selector instanceof Resettable) { if (selector instanceof Resettable) {
((Resettable) m_selector).reset(state); ((Resettable) selector).reset(state);
} else { } else {
m_model.clearSelection(state); selectionModel.clearSelection(state);
} }
// The SelectionListener, on hearing the clearSelection event, // The SelectionListener, on hearing the clearSelection event,
@ -182,35 +185,35 @@ public class SelectionPanel extends LayoutPanel implements Resettable {
} }
public final void addAction(final Component action) { public final void addAction(final Component action) {
m_group.addAction(action); actionGroup.addAction(action);
} }
public final void addAction(final Component action, final String clacc) { public final void addAction(final Component action, final String clacc) {
m_group.addAction(action, clacc); actionGroup.addAction(action, clacc);
} }
public final Component getSelector() { public final Component getSelector() {
return m_selector; return selector;
} }
protected final void setSelector(Component selector) { protected final void setSelector(final Component selector) {
m_selector = selector; this.selector = selector;
} }
public final void setSelectionModel(final SingleSelectionModel<Long> model) { public final void setSelectionModel(final SingleSelectionModel<T> model) {
m_model = model; selectionModel = model;
} }
public final SingleSelectionModel<Long> getSelectionModel() { public final SingleSelectionModel<T> getSelectionModel() {
return m_model; return selectionModel;
} }
public final ActionLink getAddLink() { public final ActionLink getAddLink() {
return m_addLink; return addLink;
} }
public final Form getAddForm() { public final Form getAddForm() {
return m_addForm; return addForm;
} }
public final void setAdd(final GlobalizedMessage message, public final void setAdd(final GlobalizedMessage message,
@ -224,20 +227,20 @@ public class SelectionPanel extends LayoutPanel implements Resettable {
Assert.exists(form, "Form form"); Assert.exists(form, "Form form");
Assert.isUnlocked(this); Assert.isUnlocked(this);
m_addForm = form; addForm = form;
m_body.add(m_addForm); body.add(addForm);
m_addLink = addLink; this.addLink = addLink;
m_body.connect(m_addLink, m_addForm); body.connect(addLink, addForm);
} }
public final ActionLink getEditLink() { public final ActionLink getEditLink() {
return m_editLink; return editLink;
} }
public final Form getEditForm() { public final Form getEditForm() {
return m_editForm; return editForm;
} }
public final void setEdit(final GlobalizedMessage message, public final void setEdit(final GlobalizedMessage message,
@ -251,21 +254,21 @@ public class SelectionPanel extends LayoutPanel implements Resettable {
Assert.exists(form, "Form form"); Assert.exists(form, "Form form");
Assert.isUnlocked(this); Assert.isUnlocked(this);
m_editForm = form; editForm = form;
m_body.add(m_editForm); body.add(editForm);
m_editLink = editLink; this.editLink = editLink;
m_body.connect(m_editLink, m_editForm); body.connect(editLink, editForm);
m_body.connect(m_editForm); body.connect(editForm);
} }
public final ActionLink getDeleteLink() { public final ActionLink getDeleteLink() {
return m_deleteLink; return deleteLink;
} }
public final Form getDeleteForm() { public final Form getDeleteForm() {
return m_deleteForm; return deleteForm;
} }
public final void setDelete(final GlobalizedMessage message, public final void setDelete(final GlobalizedMessage message,
@ -279,59 +282,62 @@ public class SelectionPanel extends LayoutPanel implements Resettable {
Assert.exists(form, "Form form"); Assert.exists(form, "Form form");
Assert.isUnlocked(this); Assert.isUnlocked(this);
m_deleteForm = form; deleteForm = form;
m_body.add(m_deleteForm); body.add(deleteForm);
m_deleteLink = deleteLink; this.deleteLink = deleteLink;
m_body.connect(m_deleteLink, m_deleteForm); body.connect(deleteLink, deleteForm);
} }
public final ModalPanel getBody() { public final ModalPanel getBody() {
return m_body; return body;
} }
public final Component getIntroPane() { public final Component getIntroPane() {
return m_introPane; return introPane;
} }
public final void setIntroPane(final Component pane) { public final void setIntroPane(final Component pane) {
Assert.exists(pane, Component.class); Assert.exists(pane, Component.class);
Assert.isUnlocked(this); Assert.isUnlocked(this);
m_introPane = pane; introPane = pane;
m_body.add(m_introPane); body.add(introPane);
m_body.setDefault(m_introPane); body.setDefault(introPane);
} }
public final Component getItemPane() { public final Component getItemPane() {
return m_itemPane; return itemPane;
} }
public final void setItemPane(final Component pane) { public final void setItemPane(final Component pane) {
Assert.exists(pane, "Component pane"); Assert.exists(pane, "Component pane");
Assert.isUnlocked(this); Assert.isUnlocked(this);
m_itemPane = pane; itemPane = pane;
m_body.add(m_itemPane); body.add(itemPane);
} }
public class SelectionListener implements ChangeListener { public class SelectionListener implements ChangeListener {
@Override @Override
public final void stateChanged(final ChangeEvent e) { public final void stateChanged(final ChangeEvent e) {
s_log.debug("Selection state changed; I may change " + LOGGER.debug("Selection state changed; I may change "
"the body's visible pane"); + "the body's visible pane");
final PageState state = e.getPageState(); final PageState state = e.getPageState();
m_body.reset(state); body.reset(state);
if (m_model.isSelected(state)) { if (selectionModel.isSelected(state)) {
s_log.debug("The selection model is selected; displaying " + LOGGER.debug("The selection model is selected; displaying "
"the item pane"); + "the item pane");
m_body.push(state, m_itemPane); body.push(state, itemPane);
} }
} }
} }
} }