CCM NG: Migrated several classes from ccm-core to CCM NG. No finished, none finished classes as *.todo to avoid compilation failures.
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4457 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
45c8296282
commit
f63434ae80
|
|
@ -23,7 +23,6 @@ import com.arsdigita.bebop.SingleSelectionModel;
|
||||||
import com.arsdigita.bebop.parameters.LongParameter;
|
import com.arsdigita.bebop.parameters.LongParameter;
|
||||||
import com.arsdigita.ui.CcmObjectSelectionModel;
|
import com.arsdigita.ui.CcmObjectSelectionModel;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.libreccm.cdi.utils.CdiUtil;
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
import org.librecms.contentsection.ContentItem;
|
import org.librecms.contentsection.ContentItem;
|
||||||
import org.librecms.contentsection.ContentType;
|
import org.librecms.contentsection.ContentType;
|
||||||
|
|
@ -53,6 +52,14 @@ public class ItemSelectionModel extends CcmObjectSelectionModel<ContentItem> {
|
||||||
|
|
||||||
private Long typeId;
|
private Long typeId;
|
||||||
|
|
||||||
|
public ItemSelectionModel(final LongParameter parameter) {
|
||||||
|
super(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSelectionModel(final String parameterName) {
|
||||||
|
super(parameterName);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new <code>ItemSelectionModel</code>
|
* Construct a new <code>ItemSelectionModel</code>
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,8 @@ public class CMSForm extends Form implements Cancellable {
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @return true if the form is cancelled, false otherwise
|
* @return true if the form is cancelled, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isCancelled(PageState state) {
|
@Override
|
||||||
|
public boolean isCancelled(final PageState state) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.cms.CMS;
|
||||||
|
import com.arsdigita.cms.ContentItem;
|
||||||
|
import com.arsdigita.cms.ContentSection;
|
||||||
|
import com.arsdigita.cms.ContentType;
|
||||||
|
import com.arsdigita.cms.ItemSelectionModel;
|
||||||
|
import com.arsdigita.cms.Template;
|
||||||
|
import com.arsdigita.cms.PageLocations;
|
||||||
|
import com.arsdigita.web.ParameterMap;
|
||||||
|
import com.arsdigita.web.URL;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>The context bar of the content section UI.</p>
|
||||||
|
*
|
||||||
|
* @author Justin Ross <jross@redhat.com>
|
||||||
|
* @version $Id: ContentItemContextBar.java 287 2005-02-22 00:29:02Z sskracic $
|
||||||
|
*/
|
||||||
|
class ContentItemContextBar extends ContentSectionContextBar {
|
||||||
|
|
||||||
|
private static final Logger s_log = Logger.getLogger
|
||||||
|
(ContentItemContextBar.class);
|
||||||
|
|
||||||
|
private final ItemSelectionModel m_item;
|
||||||
|
|
||||||
|
ContentItemContextBar(final ItemSelectionModel item) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
m_item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final List entries(final PageState state) {
|
||||||
|
final List entries = super.entries(state);
|
||||||
|
final ContentItem item = (ContentItem) m_item.getSelectedObject(state);
|
||||||
|
final ContentSection section = CMS.getContext().getContentSection();
|
||||||
|
boolean isTemplate =
|
||||||
|
item.getContentType().equals(ContentType.findByAssociatedObjectType(Template.BASE_DATA_OBJECT_TYPE));
|
||||||
|
|
||||||
|
final URL url = URL.there
|
||||||
|
(state.getRequest(),
|
||||||
|
section.getPath() + "/" + PageLocations.ITEM_PAGE,
|
||||||
|
params(item));
|
||||||
|
|
||||||
|
StringBuffer title = new StringBuffer();
|
||||||
|
if (isTemplate) {
|
||||||
|
title.append(localize("cms.ui.template"));
|
||||||
|
} else {
|
||||||
|
title.append(localize("cms.ui.content_item"));
|
||||||
|
}
|
||||||
|
title.append(": ")
|
||||||
|
.append(item.getDisplayName());
|
||||||
|
String language = item.getLanguage();
|
||||||
|
if (language != null) {
|
||||||
|
title.append(" (")
|
||||||
|
.append(language)
|
||||||
|
.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.add(new Entry(title.toString(), url));
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ParameterMap params(final ContentItem item) {
|
||||||
|
final ParameterMap params = new ParameterMap();
|
||||||
|
|
||||||
|
params.setParameter(ContentItemPage.ITEM_ID, item.getID());
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String localize(final String key) {
|
||||||
|
return (String) ContentSectionPage.globalize(key).localize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,8 +24,10 @@ import com.arsdigita.bebop.FormProcessException;
|
||||||
import com.arsdigita.bebop.Label;
|
import com.arsdigita.bebop.Label;
|
||||||
import com.arsdigita.bebop.Link;
|
import com.arsdigita.bebop.Link;
|
||||||
import com.arsdigita.bebop.PageState;
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.ParameterSingleSelectionModel;
|
||||||
import com.arsdigita.bebop.Resettable;
|
import com.arsdigita.bebop.Resettable;
|
||||||
import com.arsdigita.bebop.SimpleContainer;
|
import com.arsdigita.bebop.SimpleContainer;
|
||||||
|
import com.arsdigita.bebop.SingleSelectionModel;
|
||||||
import com.arsdigita.bebop.TabbedPane;
|
import com.arsdigita.bebop.TabbedPane;
|
||||||
import com.arsdigita.bebop.event.ActionEvent;
|
import com.arsdigita.bebop.event.ActionEvent;
|
||||||
import com.arsdigita.bebop.event.ActionListener;
|
import com.arsdigita.bebop.event.ActionListener;
|
||||||
|
|
@ -33,9 +35,12 @@ import com.arsdigita.bebop.event.FormSectionEvent;
|
||||||
import com.arsdigita.bebop.event.FormValidationListener;
|
import com.arsdigita.bebop.event.FormValidationListener;
|
||||||
import com.arsdigita.bebop.event.PrintEvent;
|
import com.arsdigita.bebop.event.PrintEvent;
|
||||||
import com.arsdigita.bebop.event.PrintListener;
|
import com.arsdigita.bebop.event.PrintListener;
|
||||||
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
import com.arsdigita.bebop.parameters.LongParameter;
|
||||||
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||||
import com.arsdigita.bebop.parameters.StringParameter;
|
import com.arsdigita.bebop.parameters.StringParameter;
|
||||||
|
import com.arsdigita.cms.CMS;
|
||||||
|
import com.arsdigita.cms.ItemSelectionModel;
|
||||||
|
import com.arsdigita.cms.PageLocations;
|
||||||
import com.arsdigita.cms.ui.item.CustomizedPreviewLink;
|
import com.arsdigita.cms.ui.item.CustomizedPreviewLink;
|
||||||
import com.arsdigita.cms.dispatcher.CMSDispatcher;
|
import com.arsdigita.cms.dispatcher.CMSDispatcher;
|
||||||
import com.arsdigita.cms.dispatcher.CMSPage;
|
import com.arsdigita.cms.dispatcher.CMSPage;
|
||||||
|
|
@ -49,31 +54,43 @@ import com.arsdigita.cms.ui.revision.ItemRevisionAdminPane;
|
||||||
import com.arsdigita.cms.ui.templates.ItemTemplates;
|
import com.arsdigita.cms.ui.templates.ItemTemplates;
|
||||||
import com.arsdigita.cms.ui.workflow.ItemWorkflowAdminPane;
|
import com.arsdigita.cms.ui.workflow.ItemWorkflowAdminPane;
|
||||||
import com.arsdigita.globalization.GlobalizedMessage;
|
import com.arsdigita.globalization.GlobalizedMessage;
|
||||||
|
import com.arsdigita.kernel.KernelConfig;
|
||||||
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
|
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
|
||||||
import com.arsdigita.util.Assert;
|
import com.arsdigita.util.Assert;
|
||||||
|
import com.arsdigita.util.UncheckedWrapperException;
|
||||||
import com.arsdigita.xml.Document;
|
import com.arsdigita.xml.Document;
|
||||||
import com.arsdigita.xml.Element;
|
import com.arsdigita.xml.Element;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.util.Optional;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.arsdigita.cms.CMSConfig;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.librecms.CmsConstants;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contentsection.ContentItemRepository;
|
||||||
|
import org.librecms.contentsection.ContentItemVersion;
|
||||||
|
import org.librecms.contentsection.ContentSection;
|
||||||
|
import org.librecms.contentsection.ContentType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page for administering a content item.
|
* Page for administering a content item.
|
||||||
*
|
*
|
||||||
* @author Michael Pih
|
* @author Michael Pih
|
||||||
* @author Stanislav Freidin <sfreidin@redhat.com>
|
* @author <a href="mailto:sfreidin@redhat.com">Stanislav Freidin</a>
|
||||||
* @author Jack Chung
|
* @author Jack Chung
|
||||||
* @author Sören Bernstein <quasi@quasiweb.de>
|
* @author <a href="mailto:quasi@quasiweb.de">Sören Bernstein</a>
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
*
|
*
|
||||||
* @version $Id: ContentItemPage.java 2245 2011-11-15 08:03:57Z pboy $
|
|
||||||
*/
|
*/
|
||||||
public class ContentItemPage extends CMSPage implements ActionListener {
|
public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private Logger instance for debugging purpose.
|
* Private Logger instance for debugging purpose.
|
||||||
*/
|
*/
|
||||||
private static final Logger s_log = Logger.getLogger(ContentItemPage.class);
|
private static final Logger LOGGER = LogManager.getLogger(
|
||||||
|
ContentItemPage.class);
|
||||||
/**
|
/**
|
||||||
* The URL parameter that must be passed in in order to set the current tab.
|
* The URL parameter that must be passed in in order to set the current tab.
|
||||||
* This is a KLUDGE right now because the TabbedDialog's current tab is
|
* This is a KLUDGE right now because the TabbedDialog's current tab is
|
||||||
|
|
@ -81,11 +98,15 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
*/
|
*/
|
||||||
public static final String SET_TAB = "set_tab";
|
public static final String SET_TAB = "set_tab";
|
||||||
/**
|
/**
|
||||||
* The name of the global state parameter that holds the item id
|
* The name of the global state parameter that holds the item id.
|
||||||
*/
|
*/
|
||||||
public static final String ITEM_ID = "item_id";
|
public static final String ITEM_ID = "item_id";
|
||||||
/**
|
/**
|
||||||
* The name of the global state parameter which holds the return URL
|
* The name of th global state parameter that holds the selected language.
|
||||||
|
*/
|
||||||
|
public static final String SELECTED_LANGUAGE = "selected_language";
|
||||||
|
/**
|
||||||
|
* The name of the global state parameter which holds the return URL.
|
||||||
*/
|
*/
|
||||||
public static final String RETURN_URL = "return_url";
|
public static final String RETURN_URL = "return_url";
|
||||||
/**
|
/**
|
||||||
|
|
@ -96,43 +117,47 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
public static final String STREAMLINED_CREATION = "streamlined_creation";
|
public static final String STREAMLINED_CREATION = "streamlined_creation";
|
||||||
public static final String STREAMLINED_CREATION_ACTIVE = "active";
|
public static final String STREAMLINED_CREATION_ACTIVE = "active";
|
||||||
public static final String STREAMLINED_CREATION_INACTIVE = "active";
|
public static final String STREAMLINED_CREATION_INACTIVE = "active";
|
||||||
private static int s_tabOrder = 0;
|
|
||||||
/**
|
/**
|
||||||
* Index of the summary tab
|
* Index of the summary tab
|
||||||
*/
|
*/
|
||||||
public static final int SUMMARY_TAB = s_tabOrder++;
|
public static final int SUMMARY_TAB = 0;
|
||||||
/**
|
/**
|
||||||
* <p>The name of the state parameter which indicates the content type of
|
* <p>
|
||||||
* the item the user wishes to create. or edit.</p>
|
* The name of the state parameter which indicates the content type of the
|
||||||
|
* item the user wishes to create. or edit.</p>
|
||||||
*
|
*
|
||||||
* <p>The parameter must be a BigDecimalParameter which encodes the id of
|
* <p>
|
||||||
* the content type.</p>
|
* The parameter must be a BigDecimalParameter which encodes the id of the
|
||||||
|
* content type.</p>
|
||||||
*/
|
*/
|
||||||
public static final String CONTENT_TYPE = "content_type";
|
public static final String CONTENT_TYPE = "content_type";
|
||||||
public static final int AUTHORING_TAB = s_tabOrder++;
|
public static final int AUTHORING_TAB = 1;
|
||||||
public static final int LANGUAGE_TAB = s_tabOrder++;
|
public static final int LANGUAGE_TAB = 2;
|
||||||
public static final int WORKFLOW_TAB = s_tabOrder++;
|
public static final int WORKFLOW_TAB = 3;
|
||||||
public static final int PUBLISHING_TAB = s_tabOrder++;
|
public static final int PUBLISHING_TAB = 4;
|
||||||
public static final int HISTORY_TAB = s_tabOrder++;
|
public static final int HISTORY_TAB = 5;
|
||||||
public static final int TEMPLATES_TAB = s_tabOrder++;
|
public static final int TEMPLATES_TAB = 6;
|
||||||
private final TabbedPane m_tabbedPane;
|
|
||||||
private StringParameter m_returnURL;
|
private final TabbedPane tabbedPane;
|
||||||
private ItemSelectionModel m_itemModel;
|
private final StringParameter returnUrlParameter;
|
||||||
private ACSObjectSelectionModel m_typeModel;
|
private final ItemSelectionModel itemModel;
|
||||||
private ContentItemRequestLocal m_item;
|
private final SingleSelectionModel<String> selectedLanguageModel;
|
||||||
private Summary m_summaryPane;
|
private final ACSObjectSelectionModel typeModel;
|
||||||
private ItemWorkflowAdminPane m_workflowPane;
|
private final ContentItemRequestLocal itemRequestLocal;
|
||||||
private ItemLifecycleAdminPane m_lifecyclePane;
|
private final Summary summaryPane;
|
||||||
private WizardSelector m_wizardPane;
|
private final ItemWorkflowAdminPane workflowPane;
|
||||||
private ItemLanguages m_languagesPane;
|
private final ItemLifecycleAdminPane lifecyclePane;
|
||||||
private ItemRevisionAdminPane m_revisionsPane;
|
private final WizardSelector wizardPane;
|
||||||
private ItemTemplates m_templatesPane;
|
private final ItemLanguages languagesPane;
|
||||||
private Link m_previewLink;
|
private final ItemRevisionAdminPane revisionsPane;
|
||||||
private GlobalNavigation m_globalNavigation;
|
private final ItemTemplates templatesPane;
|
||||||
private ContentItemContextBar m_contextBar;
|
private final Link m_previewLink;
|
||||||
|
private final GlobalNavigation m_globalNavigation;
|
||||||
|
private final ContentItemContextBar m_contextBar;
|
||||||
|
|
||||||
private class ItemRequestLocal extends ContentItemRequestLocal {
|
private class ItemRequestLocal extends ContentItemRequestLocal {
|
||||||
|
|
||||||
|
@Override
|
||||||
protected final Object initialValue(final PageState state) {
|
protected final Object initialValue(final PageState state) {
|
||||||
return CMS.getContext().getContentItem();
|
return CMS.getContext().getContentItem();
|
||||||
}
|
}
|
||||||
|
|
@ -140,9 +165,11 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
|
|
||||||
private class TitlePrinter implements PrintListener {
|
private class TitlePrinter implements PrintListener {
|
||||||
|
|
||||||
public final void prepare(final PrintEvent e) {
|
@Override
|
||||||
final Label label = (Label) e.getTarget();
|
public final void prepare(final PrintEvent event) {
|
||||||
final ContentItem item = m_item.getContentItem(e.getPageState());
|
final Label label = (Label) event.getTarget();
|
||||||
|
final ContentItem item = itemRequestLocal.getContentItem(event.
|
||||||
|
getPageState());
|
||||||
|
|
||||||
label.setLabel(item.getDisplayName());
|
label.setLabel(item.getDisplayName());
|
||||||
}
|
}
|
||||||
|
|
@ -154,80 +181,88 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
public ContentItemPage() {
|
public ContentItemPage() {
|
||||||
super("", new SimpleContainer());
|
super("", new SimpleContainer());
|
||||||
|
|
||||||
m_item = new ItemRequestLocal();
|
itemRequestLocal = new ItemRequestLocal();
|
||||||
|
|
||||||
setClassAttr("cms-admin");
|
setClassAttr("cms-admin");
|
||||||
setTitle(new Label(new TitlePrinter()));
|
setTitle(new Label(new TitlePrinter()));
|
||||||
|
|
||||||
// Add the item id global state parameter
|
// Add the item id global state parameter
|
||||||
BigDecimalParameter itemId = new BigDecimalParameter(ITEM_ID);
|
final LongParameter itemId = new LongParameter(ITEM_ID);
|
||||||
itemId.addParameterListener(new NotNullValidationListener(ITEM_ID));
|
itemId.addParameterListener(new NotNullValidationListener(ITEM_ID));
|
||||||
addGlobalStateParam(itemId);
|
addGlobalStateParam(itemId);
|
||||||
m_itemModel = new ItemSelectionModel(itemId);
|
itemModel = new ItemSelectionModel(itemId);
|
||||||
|
|
||||||
|
// Add the selected item language as parameter
|
||||||
|
final StringParameter selectedLanguage = new StringParameter(
|
||||||
|
SELECTED_LANGUAGE);
|
||||||
|
selectedLanguage.addParameterListener(new NotNullValidationListener(
|
||||||
|
SELECTED_LANGUAGE));
|
||||||
|
addGlobalStateParam(selectedLanguage);
|
||||||
|
selectedLanguageModel = new ParameterSingleSelectionModel<>(
|
||||||
|
selectedLanguage);
|
||||||
|
|
||||||
// Add the content type global state parameter
|
// Add the content type global state parameter
|
||||||
BigDecimalParameter contentType = new BigDecimalParameter(CONTENT_TYPE);
|
final LongParameter contentType = new LongParameter(CONTENT_TYPE);
|
||||||
addGlobalStateParam(contentType);
|
addGlobalStateParam(contentType);
|
||||||
|
|
||||||
// Add the streamlined creation global state parameter
|
// Add the streamlined creation global state parameter
|
||||||
StringParameter streamlinedCreation = new StringParameter(
|
final StringParameter streamlinedCreation = new StringParameter(
|
||||||
STREAMLINED_CREATION);
|
STREAMLINED_CREATION);
|
||||||
addGlobalStateParam(streamlinedCreation);
|
addGlobalStateParam(streamlinedCreation);
|
||||||
|
|
||||||
m_typeModel = new ACSObjectSelectionModel(ContentType.class.getName(),
|
typeModel = new ACSObjectSelectionModel(ContentType.class.getName(),
|
||||||
ContentType.BASE_DATA_OBJECT_TYPE,
|
ContentType.class.getName(),
|
||||||
contentType);
|
contentType);
|
||||||
|
|
||||||
// Validate the item ID parameter (caches the validation).
|
// Validate the item ID parameter (caches the validation).
|
||||||
getStateModel().addValidationListener(new FormValidationListener() {
|
getStateModel().addValidationListener(
|
||||||
public void validate(FormSectionEvent event)
|
event -> validateItemID(event.getPageState()));
|
||||||
throws FormProcessException {
|
|
||||||
validateItemID(event.getPageState());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add the return url global state parameter
|
// Add the return url global state parameter
|
||||||
m_returnURL = new StringParameter(RETURN_URL);
|
returnUrlParameter = new StringParameter(RETURN_URL);
|
||||||
addGlobalStateParam(m_returnURL);
|
addGlobalStateParam(returnUrlParameter);
|
||||||
|
|
||||||
m_globalNavigation = new GlobalNavigation();
|
m_globalNavigation = new GlobalNavigation();
|
||||||
add(m_globalNavigation);
|
add(m_globalNavigation);
|
||||||
|
|
||||||
m_contextBar = new ContentItemContextBar(m_itemModel);
|
m_contextBar = new ContentItemContextBar(itemModel);
|
||||||
add(m_contextBar);
|
add(m_contextBar);
|
||||||
|
|
||||||
// Create panels.
|
// Create panels.
|
||||||
m_summaryPane = new Summary(m_itemModel);
|
summaryPane = new Summary(itemModel);
|
||||||
m_wizardPane = new WizardSelector(m_itemModel, m_typeModel);
|
wizardPane = new WizardSelector(itemModel, typeModel);
|
||||||
m_languagesPane = new ItemLanguages(m_itemModel);
|
languagesPane = new ItemLanguages(itemModel, selectedLanguageModel);
|
||||||
m_workflowPane = new ItemWorkflowAdminPane(itemId); // Make this use m_item XXX
|
workflowPane = new ItemWorkflowAdminPane(itemId); // Make this use m_item XXX
|
||||||
m_lifecyclePane = new ItemLifecycleAdminPane(m_item);
|
lifecyclePane = new ItemLifecycleAdminPane(itemRequestLocal);
|
||||||
m_revisionsPane = new ItemRevisionAdminPane(m_item);
|
revisionsPane = new ItemRevisionAdminPane(itemRequestLocal);
|
||||||
m_templatesPane = new ItemTemplates(m_itemModel);
|
templatesPane = new ItemTemplates(itemModel);
|
||||||
|
|
||||||
// Create tabbed pane.
|
// Create tabbed pane.
|
||||||
m_tabbedPane = new TabbedPane();
|
tabbedPane = new TabbedPane();
|
||||||
add(m_tabbedPane);
|
add(tabbedPane);
|
||||||
|
|
||||||
m_tabbedPane.setIdAttr("page-body");
|
tabbedPane.setIdAttr("page-body");
|
||||||
|
|
||||||
m_tabbedPane.addTab(new Label(gz("cms.ui.item.summary")), m_summaryPane);
|
tabbedPane.addTab(new Label(gz("cms.ui.item.summary")), summaryPane);
|
||||||
m_tabbedPane.addTab(new Label(gz("cms.ui.item.authoring")), m_wizardPane);
|
tabbedPane.
|
||||||
m_tabbedPane.addTab(new Label(gz("cms.ui.item.languages")),
|
addTab(new Label(gz("cms.ui.item.authoring")), wizardPane);
|
||||||
m_languagesPane);
|
tabbedPane.addTab(new Label(gz("cms.ui.item.languages")),
|
||||||
m_tabbedPane.addTab(new Label(gz("cms.ui.item.workflow")),
|
languagesPane);
|
||||||
m_workflowPane);
|
tabbedPane.addTab(new Label(gz("cms.ui.item.workflow")),
|
||||||
m_tabbedPane.addTab(new Label(gz("cms.ui.item.lifecycles")),
|
workflowPane);
|
||||||
m_lifecyclePane);
|
tabbedPane.addTab(new Label(gz("cms.ui.item.lifecycles")),
|
||||||
m_tabbedPane.addTab(new Label(gz("cms.ui.item.history")),
|
lifecyclePane);
|
||||||
m_revisionsPane);
|
tabbedPane.addTab(new Label(gz("cms.ui.item.history")),
|
||||||
m_tabbedPane.addTab(new Label(gz("cms.ui.item.templates")),
|
revisionsPane);
|
||||||
m_templatesPane);
|
tabbedPane.addTab(new Label(gz("cms.ui.item.templates")),
|
||||||
|
templatesPane);
|
||||||
|
|
||||||
m_tabbedPane.addActionListener(new ActionListener() {
|
tabbedPane.addActionListener(new ActionListener() {
|
||||||
public final void actionPerformed(final ActionEvent e) {
|
@Override
|
||||||
final PageState state = e.getPageState();
|
public final void actionPerformed(final ActionEvent event) {
|
||||||
final Component pane = m_tabbedPane.getCurrentPane(state);
|
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
final Component pane = tabbedPane.getCurrentPane(state);
|
||||||
|
|
||||||
if (pane instanceof Resettable) {
|
if (pane instanceof Resettable) {
|
||||||
((Resettable) pane).reset(state);
|
((Resettable) pane).reset(state);
|
||||||
|
|
@ -237,13 +272,15 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
|
|
||||||
// Build the preview link.
|
// Build the preview link.
|
||||||
m_previewLink = new Link(new Label(gz("cms.ui.preview")),
|
m_previewLink = new Link(new Label(gz("cms.ui.preview")),
|
||||||
new PrintListener() {
|
new PrintListener() {
|
||||||
public final void prepare(final PrintEvent e) {
|
@Override
|
||||||
final Link link = (Link) e.getTarget();
|
public final void prepare(final PrintEvent event) {
|
||||||
link.setTarget(getPreviewURL(e.getPageState()));
|
final Link link = (Link) event.getTarget();
|
||||||
link.setTargetFrame(Link.NEW_FRAME);
|
link.setTarget(getPreviewURL(event.
|
||||||
}
|
getPageState()));
|
||||||
});
|
link.setTargetFrame(Link.NEW_FRAME);
|
||||||
|
}
|
||||||
|
});
|
||||||
m_previewLink.setIdAttr("preview_link");
|
m_previewLink.setIdAttr("preview_link");
|
||||||
add(m_previewLink);
|
add(m_previewLink);
|
||||||
|
|
||||||
|
|
@ -251,21 +288,25 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
|
|
||||||
// Add validation to make sure we are not attempting to edit a live item
|
// Add validation to make sure we are not attempting to edit a live item
|
||||||
getStateModel().addValidationListener(new FormValidationListener() {
|
getStateModel().addValidationListener(new FormValidationListener() {
|
||||||
public void validate(FormSectionEvent e) throws FormProcessException {
|
|
||||||
PageState s = e.getPageState();
|
@Override
|
||||||
FormData data = e.getFormData();
|
public void validate(final FormSectionEvent event)
|
||||||
final ContentItem item = m_item.getContentItem(s);
|
throws FormProcessException {
|
||||||
if (item != null && ContentItem.LIVE.equals(item.getVersion())) {
|
|
||||||
s_log.error(String.format(
|
PageState s = event.getPageState();
|
||||||
"The item %d is live and cannot be edited.", item.getID()));
|
FormData data = event.getFormData();
|
||||||
// data.addError(err);
|
final ContentItem item = itemRequestLocal.getContentItem(s);
|
||||||
throw new FormProcessException(GlobalizationUtil.globalize(
|
if (item != null
|
||||||
"cms.ui.live_item_not_editable"));
|
&& ContentItemVersion.LIVE == item.getVersion()) {
|
||||||
|
LOGGER.error(String.format(
|
||||||
|
"The item %d is live and cannot be edited.", item.
|
||||||
|
getObjectId()));
|
||||||
|
throw new FormProcessException(new GlobalizedMessage(
|
||||||
|
"cms.ui.live_item_not_editable",
|
||||||
|
CmsConstants.CMS_BUNDLE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
add(new DebugPanel());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -276,12 +317,13 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
* @pre state != null
|
* @pre state != null
|
||||||
* @exception FormProcessException if the item_id is not valid
|
* @exception FormProcessException if the item_id is not valid
|
||||||
*/
|
*/
|
||||||
protected void validateItemID(PageState state) throws FormProcessException {
|
protected void validateItemID(final PageState state) throws
|
||||||
final ContentItem item = m_item.getContentItem(state);
|
FormProcessException {
|
||||||
|
final ContentItem item = itemRequestLocal.getContentItem(state);
|
||||||
|
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
throw new FormProcessException(GlobalizationUtil.globalize(
|
throw new FormProcessException(new GlobalizedMessage(
|
||||||
"cms.ui.invalid_item_id"));
|
"cms.ui.invalid_item_id", CmsConstants.CMS_BUNDLE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -294,7 +336,7 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
* @return The current content section
|
* @return The current content section
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ContentSection getContentSection(HttpServletRequest request) {
|
public ContentSection getContentSection(final HttpServletRequest request) {
|
||||||
// Resets all content sections associations.
|
// Resets all content sections associations.
|
||||||
ContentSection section = super.getContentSection(request);
|
ContentSection section = super.getContentSection(request);
|
||||||
Assert.exists(section);
|
Assert.exists(section);
|
||||||
|
|
@ -310,54 +352,49 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
* @return The current content item, null if there is none
|
* @return The current content item, null if there is none
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ContentItem getContentItem(PageState state) {
|
public ContentItem getContentItem(final PageState state) {
|
||||||
return (ContentItem) m_itemModel.getSelectedObject(state);
|
return (ContentItem) itemModel.getSelectedObject(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current tab, if necessary
|
* Set the current tab, if necessary
|
||||||
|
* @param event
|
||||||
*/
|
*/
|
||||||
public void actionPerformed(ActionEvent event) {
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent event) {
|
||||||
final PageState state = event.getPageState();
|
final PageState state = event.getPageState();
|
||||||
final String setTab = state.getRequest().getParameter(SET_TAB);
|
final String setTab = state.getRequest().getParameter(SET_TAB);
|
||||||
|
|
||||||
// Hide the templates tab, the workflow tab, and the preview
|
// Hide the templates tab, the workflow tab, and the preview
|
||||||
// link if the current item is a template.
|
// link if the current item is a template.
|
||||||
final ContentItem item = m_item.getContentItem(state);
|
final ContentItem item = itemRequestLocal.getContentItem(state);
|
||||||
|
|
||||||
if (item instanceof Template) {
|
|
||||||
m_tabbedPane.setTabVisible(state, m_templatesPane, false);
|
|
||||||
m_tabbedPane.setTabVisible(state, m_workflowPane, false);
|
|
||||||
m_tabbedPane.setTabVisible(state, m_languagesPane, false);
|
|
||||||
m_previewLink.setVisible(state, false);
|
|
||||||
} else {
|
|
||||||
m_tabbedPane.setTabVisible(state, m_templatesPane, !ContentSection.
|
|
||||||
getConfig().getHideTemplatesTab());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Added by: Sören Bernstein <quasi@quasiweb.de>
|
|
||||||
// If the content item is a language invariant content item, don't show
|
|
||||||
// the language pane
|
|
||||||
if (item instanceof LanguageInvariantContentItem) {
|
|
||||||
LanguageInvariantContentItem li_item = (LanguageInvariantContentItem) item;
|
|
||||||
if (li_item.isLanguageInvariant()) {
|
|
||||||
m_tabbedPane.setTabVisible(state, m_languagesPane, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// ToDo: Reable when Templates have been ported. Not clear yet if
|
||||||
|
// Templates will be ContentItems in LibreCMS...
|
||||||
|
// if (item instanceof Template) {
|
||||||
|
// tabbedPane.setTabVisible(state, templatesPane, false);
|
||||||
|
// tabbedPane.setTabVisible(state, workflowPane, false);
|
||||||
|
// tabbedPane.setTabVisible(state, languagesPane, false);
|
||||||
|
// m_previewLink.setVisible(state, false);
|
||||||
|
// } else {
|
||||||
|
// tabbedPane.setTabVisible(state,
|
||||||
|
// templatesPane,
|
||||||
|
// !ContentSectionConfig.getConfig().getHideTemplatesTab());
|
||||||
|
// }
|
||||||
// Set the current tab based on parameters
|
// Set the current tab based on parameters
|
||||||
if (setTab != null) {
|
if (setTab != null) {
|
||||||
Integer tab = null;
|
Integer tab;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
tab = Integer.valueOf(setTab);
|
tab = Integer.valueOf(setTab);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException ex) {
|
||||||
// Stop processing set_tab parameter.
|
// Stop processing set_tab parameter.
|
||||||
|
LOGGER.warn("Stopping processing of set_tab parameter.", ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tab.intValue() < m_tabbedPane.size()) {
|
if (tab < tabbedPane.size()) {
|
||||||
m_tabbedPane.setSelectedIndex(state, tab.intValue());
|
tabbedPane.setSelectedIndex(state, tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -368,10 +405,11 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
* @param nodeURL The URL where this page is mounted
|
* @param nodeURL The URL where this page is mounted
|
||||||
* @param itemId The id of the item to display
|
* @param itemId The id of the item to display
|
||||||
* @param tab The index of the tab to display
|
* @param tab The index of the tab to display
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public static String getItemURL(String nodeURL,
|
public static String getItemURL(final String nodeURL,
|
||||||
BigDecimal itemId,
|
final Long itemId,
|
||||||
int tab) {
|
final int tab) {
|
||||||
return getItemURL(nodeURL, itemId, tab, false);
|
return getItemURL(nodeURL, itemId, tab, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -382,33 +420,58 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
* @param itemId The id of the item to display
|
* @param itemId The id of the item to display
|
||||||
* @param tab The index of the tab to display
|
* @param tab The index of the tab to display
|
||||||
* @param streamlinedCreation Whether to activate Streamlined item authoring
|
* @param streamlinedCreation Whether to activate Streamlined item authoring
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public static String getItemURL(String nodeURL,
|
public static String getItemURL(final String nodeURL,
|
||||||
BigDecimal itemId,
|
final Long itemId,
|
||||||
int tab,
|
final int tab,
|
||||||
boolean streamlinedCreation) {
|
final boolean streamlinedCreation) {
|
||||||
StringBuffer url = new StringBuffer();
|
final StringBuilder urlBuilder = new StringBuilder();
|
||||||
|
|
||||||
url.append(nodeURL).append(PageLocations.ITEM_PAGE).append("?").append(
|
urlBuilder
|
||||||
ITEM_ID).append("=").append(itemId.toString()).append("&").
|
.append(nodeURL)
|
||||||
append(SET_TAB).append("=").append(tab);
|
.append(PageLocations.ITEM_PAGE)
|
||||||
|
.append("?")
|
||||||
|
.append(ITEM_ID)
|
||||||
|
.append("=")
|
||||||
|
.append(itemId.toString())
|
||||||
|
.append("&")
|
||||||
|
.append(SET_TAB)
|
||||||
|
.append("=")
|
||||||
|
.append(tab);
|
||||||
|
|
||||||
if (streamlinedCreation && ContentSection.getConfig().
|
if (streamlinedCreation
|
||||||
getUseStreamlinedCreation()) {
|
&& CMSConfig.getConfig().isUseStreamlinedCreation()) {
|
||||||
url.append("&").append(STREAMLINED_CREATION).append("=").append(
|
|
||||||
STREAMLINED_CREATION_ACTIVE);
|
urlBuilder
|
||||||
|
.append("&")
|
||||||
|
.append(STREAMLINED_CREATION)
|
||||||
|
.append("=")
|
||||||
|
.append(STREAMLINED_CREATION_ACTIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return url.toString();
|
return urlBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param itemId
|
||||||
|
* @param tab
|
||||||
|
* @return
|
||||||
* @deprecated Use getItemURL instead
|
* @deprecated Use getItemURL instead
|
||||||
*/
|
*/
|
||||||
public static String getRelativeItemURL(BigDecimal itemId, int tab) {
|
public static String getRelativeItemURL(final Long itemId, final int tab) {
|
||||||
StringBuffer url = new StringBuffer();
|
final StringBuilder url = new StringBuilder();
|
||||||
url.append(PageLocations.ITEM_PAGE).append("?").append(ITEM_ID).append("=").append(itemId.
|
url
|
||||||
toString()).append("&").append(SET_TAB).append("=").append(tab);
|
.append(PageLocations.ITEM_PAGE)
|
||||||
|
.append("?")
|
||||||
|
.append(ITEM_ID)
|
||||||
|
.append("=")
|
||||||
|
.append(itemId.toString())
|
||||||
|
.append("&")
|
||||||
|
.append(SET_TAB)
|
||||||
|
.append("=")
|
||||||
|
.append(tab);
|
||||||
|
|
||||||
return url.toString();
|
return url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,16 +480,18 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
*
|
*
|
||||||
* @param item the ContentItem object to display
|
* @param item the ContentItem object to display
|
||||||
* @param tab The index of the tab to display
|
* @param tab The index of the tab to display
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public static String getItemURL(ContentItem item, int tab) {
|
public static String getItemURL(final ContentItem item,
|
||||||
final ContentSection section = item.getContentSection();
|
final int tab) {
|
||||||
|
final ContentSection section = item.getContentType().getContentSection();
|
||||||
|
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
final String nodeURL = section.getPath() + "/";
|
final String nodeURL = section.getPrimaryUrl() + "/";
|
||||||
|
|
||||||
return getItemURL(nodeURL, item.getID(), tab);
|
return getItemURL(nodeURL, item.getObjectId(), tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -435,16 +500,20 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
*
|
*
|
||||||
* @param itemId the id of the ContentItem object to display
|
* @param itemId the id of the ContentItem object to display
|
||||||
* @param tab The index of the tab to display
|
* @param tab The index of the tab to display
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public static String getItemURL(long itemId, int tab) {
|
public static String getItemURL(final long itemId,
|
||||||
final ContentItem item =
|
final int tab) {
|
||||||
(ContentItem) DomainObjectFactory.newInstance(new OID(
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
ContentItem.BASE_DATA_OBJECT_TYPE, itemId));
|
final ContentItemRepository itemRepo = cdiUtil.findBean(
|
||||||
|
ContentItemRepository.class);
|
||||||
|
|
||||||
if (item == null) {
|
final Optional<ContentItem> item = itemRepo.findById(itemId);
|
||||||
return null;
|
|
||||||
|
if (item.isPresent()) {
|
||||||
|
return getItemURL(item.get(), tab);
|
||||||
} else {
|
} else {
|
||||||
return getItemURL(item, tab);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -454,12 +523,12 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
*
|
*
|
||||||
* @param state The current page state
|
* @param state The current page state
|
||||||
*/
|
*/
|
||||||
public void redirectBack(PageState state) {
|
public void redirectBack(final PageState state) {
|
||||||
try {
|
try {
|
||||||
String returnURL = (String) state.getValue(m_returnURL);
|
final String returnUrl = (String) state.getValue(returnUrlParameter);
|
||||||
state.getResponse().sendRedirect(returnURL);
|
state.getResponse().sendRedirect(returnUrl);
|
||||||
} catch (IOException e) {
|
} catch (IOException ex) {
|
||||||
s_log.error("IO Error redirecting back", e);
|
LOGGER.error("IO Error redirecting back", ex);
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -467,13 +536,13 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
/**
|
/**
|
||||||
* Fetch the preview URL.
|
* Fetch the preview URL.
|
||||||
*/
|
*/
|
||||||
private String getPreviewURL(PageState state) {
|
private String getPreviewURL(final PageState state) {
|
||||||
final ContentItem item = m_item.getContentItem(state);
|
final ContentItem item = itemRequestLocal.getContentItem(state);
|
||||||
|
|
||||||
if (item instanceof CustomizedPreviewLink) {
|
if (item instanceof CustomizedPreviewLink) {
|
||||||
final String previewLink = ((CustomizedPreviewLink) item).
|
final String previewLink = ((CustomizedPreviewLink) item).
|
||||||
getPreviewUrl(
|
getPreviewUrl(
|
||||||
state);
|
state);
|
||||||
if ((previewLink == null) || previewLink.isEmpty()) {
|
if ((previewLink == null) || previewLink.isEmpty()) {
|
||||||
return getDefaultPreviewLink(state, item);
|
return getDefaultPreviewLink(state, item);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -491,49 +560,66 @@ public class ContentItemPage extends CMSPage implements ActionListener {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private String getDefaultPreviewLink(final PageState state,
|
private String getDefaultPreviewLink(final PageState state,
|
||||||
final ContentItem item) {
|
final ContentItem item) {
|
||||||
final ContentSection section = CMS.getContext().getContentSection();
|
final ContentSection section = CMS.getContext().getContentSection();
|
||||||
//ContentSection section = getContentSection(state);
|
final ItemResolver itemResolver;
|
||||||
final ItemResolver itemResolver = section.getItemResolver();
|
try {
|
||||||
|
final Class<?> itemResolverClass = Class.forName(section.
|
||||||
|
getItemResolverClass());
|
||||||
|
itemResolver = (ItemResolver) itemResolverClass.newInstance();
|
||||||
|
} catch (ClassNotFoundException
|
||||||
|
| IllegalAccessException
|
||||||
|
| InstantiationException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
// Pass in the "Live" context since we need it for the preview
|
// Pass in the "Live" context since we need it for the preview
|
||||||
return itemResolver.generateItemURL(state, item, section,
|
return itemResolver.generateItemURL(state,
|
||||||
CMSDispatcher.PREVIEW);
|
item,
|
||||||
|
section,
|
||||||
|
CMSDispatcher.PREVIEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final static GlobalizedMessage gz(final String key) {
|
protected final static GlobalizedMessage gz(final String key) {
|
||||||
return GlobalizationUtil.globalize(key);
|
return new GlobalizedMessage(key, CmsConstants.CMS_BUNDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final static String lz(final String key) {
|
protected final static String lz(final String key) {
|
||||||
return (String) gz(key).localize();
|
return (String) gz(key).localize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isStreamlinedCreationActive(PageState state) {
|
public static boolean isStreamlinedCreationActive(final PageState state) {
|
||||||
return ContentSection.getConfig().getUseStreamlinedCreation()
|
return CMSConfig.getConfig().isUseStreamlinedCreation()
|
||||||
&& STREAMLINED_CREATION_ACTIVE.equals(state.getRequest().
|
&& STREAMLINED_CREATION_ACTIVE.equals(state.getRequest().
|
||||||
getParameter(STREAMLINED_CREATION));
|
getParameter(STREAMLINED_CREATION));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TabbedPane getTabbedPane() {
|
protected TabbedPane getTabbedPane() {
|
||||||
return m_tabbedPane;
|
return tabbedPane;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WizardSelector getWizardPane() {
|
protected WizardSelector getWizardPane() {
|
||||||
return m_wizardPane;
|
return wizardPane;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the content type to the output.
|
* Adds the content type to the output.
|
||||||
*
|
*
|
||||||
* @param state PageState
|
* @param state PageState
|
||||||
* @param parent Parent document
|
* @param parent Parent document
|
||||||
* @return page
|
* @return page
|
||||||
*/
|
*/
|
||||||
protected Element generateXMLHelper(PageState state, Document parent) {
|
@Override
|
||||||
Element page = super.generateXMLHelper(state, parent);
|
protected Element generateXMLHelper(final PageState state,
|
||||||
Element contenttype = page.newChildElement("bebop:contentType", BEBOP_XML_NS);
|
final Document parent) {
|
||||||
contenttype.setText(m_item.getContentItem(state).getContentType().getName());
|
final Element page = super.generateXMLHelper(state, parent);
|
||||||
|
final Element contenttype = page.newChildElement("bebop:contentType",
|
||||||
|
BEBOP_XML_NS);
|
||||||
|
|
||||||
|
contenttype.setText(itemRequestLocal
|
||||||
|
.getContentItem(state)
|
||||||
|
.getContentType()
|
||||||
|
.getLabel().getValue(KernelConfig.getConfig().getDefaultLocale()));
|
||||||
|
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,394 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.Component;
|
||||||
|
import com.arsdigita.bebop.Form;
|
||||||
|
import com.arsdigita.bebop.FormProcessException;
|
||||||
|
import com.arsdigita.bebop.FormSection;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.PropertyEditor;
|
||||||
|
import com.arsdigita.bebop.PropertyEditorModel;
|
||||||
|
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||||
|
import com.arsdigita.bebop.event.FormSubmissionListener;
|
||||||
|
import com.arsdigita.bebop.form.Submit;
|
||||||
|
import com.arsdigita.cms.dispatcher.Utilities;
|
||||||
|
import com.arsdigita.globalization.GlobalizedMessage;
|
||||||
|
import com.arsdigita.toolbox.ui.ComponentAccess;
|
||||||
|
import com.arsdigita.util.Assert;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.libreccm.security.PermissionChecker;
|
||||||
|
import org.librecms.CmsConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends {@link com.arsdigita.bebop.PropertyEditor} to provide access control
|
||||||
|
* features. Each link may be associated with a {@link
|
||||||
|
* com.arsdigita.toolbox.ui.ComponentAccess} object; if the current does not
|
||||||
|
* have sufficient privileges, the link will be hidden.
|
||||||
|
* <p>
|
||||||
|
* The simple use pattern for this component is as follows:
|
||||||
|
*
|
||||||
|
* <blockquote><pre><code>
|
||||||
|
* SecurityPropertyEditor editor = new SecurityPropertyEditor();
|
||||||
|
* editor.setDisplayComponent(new FooComponent());
|
||||||
|
* NameEditForm n = new NameEditForm();
|
||||||
|
* ComponentAccess ca1 = new ComponentAccess(n);
|
||||||
|
* ca1.addAccessCheck(WORKFLOW_ADMIN);
|
||||||
|
* ca1.addAccessCheck(CATEGORY_ADMIN);
|
||||||
|
* editor.add("name", "Edit Name", ca, n.getCancelButton());
|
||||||
|
* AddressEditForm a = new AddressEditForm();
|
||||||
|
* ComponentAccess ca2 = new ComponentAccess(a);
|
||||||
|
* editor.add("address", "Edit Address", ca2, a.getCancelButton());
|
||||||
|
* </code></pre></blockquote>
|
||||||
|
*
|
||||||
|
* @author Michael Pih (pihman@arsdigita.com)
|
||||||
|
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class SecurityPropertyEditor extends PropertyEditor {
|
||||||
|
|
||||||
|
private final Map<String, ComponentAccess> accessChecks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new, empty <code>PropertyEditor</code>. The {@link
|
||||||
|
* #setDisplayComponent(Component)} method must be called before this
|
||||||
|
* component is locked.
|
||||||
|
*/
|
||||||
|
public SecurityPropertyEditor() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new, <code>PropertyEditor</code> with the given display
|
||||||
|
* component
|
||||||
|
*
|
||||||
|
* @param display The display component
|
||||||
|
*/
|
||||||
|
public SecurityPropertyEditor(final Component display) {
|
||||||
|
super(display);
|
||||||
|
accessChecks = new HashMap<>();
|
||||||
|
setModelBuilder(new AccessListModelBuilder());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a component to the property editor. The component will be completely
|
||||||
|
* invisible; it is up to the user to call {@link #showComponent(PageState,
|
||||||
|
* String)} to display the component, and to call {@link
|
||||||
|
* #showDisplayPane(PageState)} when the component needs to be hidden.
|
||||||
|
*
|
||||||
|
* @param key The symbolic key for the component; must be unique for this
|
||||||
|
* <code>PropertyEditor</code>
|
||||||
|
* @param componentAccess The {@link ComponentAccess} object which contains
|
||||||
|
* the child component, along with security restrictions
|
||||||
|
*/
|
||||||
|
public void addComponent(final String key,
|
||||||
|
final ComponentAccess componentAccess) {
|
||||||
|
super.addComponent(key, componentAccess.getComponent());
|
||||||
|
accessChecks.put(key, componentAccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a component to the list of links. It is up to the component to
|
||||||
|
* correctly call showDisplayPane when it's done.
|
||||||
|
*
|
||||||
|
* @param key The symbolic key for the component; must be unique for this
|
||||||
|
* <code>PropertyEditor</code>
|
||||||
|
* @param label The label for the link
|
||||||
|
* @param componentAccess The component access
|
||||||
|
* @deprecated use addComponent(String,GlobalizedMessage,ComponentAccess)
|
||||||
|
* instead.
|
||||||
|
*/
|
||||||
|
public void addComponent(final String key,
|
||||||
|
final String label,
|
||||||
|
final ComponentAccess componentAccess) {
|
||||||
|
addComponent(key, componentAccess);
|
||||||
|
getLabelsMap().put(key, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a component to the list of links. It is up to the component to
|
||||||
|
* correctly call showDisplayPane when it's done.
|
||||||
|
*
|
||||||
|
* @param key The symbolic key for the component; must be unique for this
|
||||||
|
* <code>PropertyEditor</code>
|
||||||
|
* @param label The label for the link
|
||||||
|
* @param componentAccess The component access
|
||||||
|
*/
|
||||||
|
public void addComponent(final String key,
|
||||||
|
final GlobalizedMessage label,
|
||||||
|
final ComponentAccess componentAccess) {
|
||||||
|
addComponent(key, componentAccess);
|
||||||
|
getLabelsMap().put(key, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify a new {@link ComponentAccess} for a component which has already
|
||||||
|
* been added to the <code>SecurityPropertyEditor</code>.
|
||||||
|
*
|
||||||
|
* @param key the key under which the component was added
|
||||||
|
* @param componentAccess the <code>ComponentAccess</code> instance that
|
||||||
|
* will determine when the link for the specified component should be
|
||||||
|
* visible
|
||||||
|
* @pre access.getComponent() == m_forms.get(key)
|
||||||
|
*/
|
||||||
|
public void setComponentAccess(final String key,
|
||||||
|
final ComponentAccess componentAccess) {
|
||||||
|
Assert.isUnlocked(this);
|
||||||
|
final Component component = getComponent(key);
|
||||||
|
Assert.exists(component, "the specified component");
|
||||||
|
Assert.isTrue(componentAccess.getComponent().equals(component),
|
||||||
|
"The specified component does not match the component that"
|
||||||
|
+ " id already in the PropertyEditor");
|
||||||
|
accessChecks.put(key, componentAccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a form to the set of forms which could be used to edit the
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param key The symbolic key for the form; must be unique for this
|
||||||
|
* <code>PropertyEditor</code>
|
||||||
|
* @param label The label for the link to access the form
|
||||||
|
* @param componentAccess The form ComponentAccess
|
||||||
|
*
|
||||||
|
* @deprecated use add(String,GlobalizedMessage,ComponentAccess)
|
||||||
|
*/
|
||||||
|
public void add(final String key,
|
||||||
|
final String label,
|
||||||
|
final ComponentAccess componentAccess) {
|
||||||
|
final Component component = componentAccess.getComponent();
|
||||||
|
if (component instanceof Form) {
|
||||||
|
final Form form = (Form) component;
|
||||||
|
accessChecks.put(key, componentAccess);
|
||||||
|
add(key, label, form);
|
||||||
|
addSecurityListener(form);
|
||||||
|
} else if (component instanceof FormSection) {
|
||||||
|
final FormSection section = (FormSection) componentAccess.
|
||||||
|
getComponent();
|
||||||
|
accessChecks.put(key, componentAccess);
|
||||||
|
add(key, label, section);
|
||||||
|
addSecurityListener(section);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The ComponentAccess object does "
|
||||||
|
+ "not contain a form section.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a form to the set of forms which could be used to edit the
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param key The symbolic key for the form; must be unique for this
|
||||||
|
* <code>PropertyEditor</code>
|
||||||
|
* @param label The label for the link to access the form
|
||||||
|
* @param componentAccess The form ComponentAccess
|
||||||
|
*/
|
||||||
|
public void add(final String key,
|
||||||
|
final GlobalizedMessage label,
|
||||||
|
final ComponentAccess componentAccess) {
|
||||||
|
final Component component = componentAccess.getComponent();
|
||||||
|
if (component instanceof Form) {
|
||||||
|
final Form form = (Form) component;
|
||||||
|
accessChecks.put(key, componentAccess);
|
||||||
|
add(key, label, form);
|
||||||
|
addSecurityListener(form);
|
||||||
|
} else if (component instanceof FormSection) {
|
||||||
|
final FormSection section = (FormSection) componentAccess.
|
||||||
|
getComponent();
|
||||||
|
accessChecks.put(key, componentAccess);
|
||||||
|
add(key, label, section);
|
||||||
|
addSecurityListener(section);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The ComponentAccess object does "
|
||||||
|
+ "not contain a form section.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a form to the set of forms which could be used to edit the properties
|
||||||
|
*
|
||||||
|
* @param key The symbolic key for the form; must be unique for this
|
||||||
|
* <code>PropertyEditor</code>
|
||||||
|
* @param label The label for the link to access the form.
|
||||||
|
* @param componentAccess The form ComponentAccess
|
||||||
|
* @param cancelButton The Cancel button on the form.
|
||||||
|
*
|
||||||
|
* @deprecated use add(String,GlobalizedMessage,ComponentAccess,Submit)
|
||||||
|
* instead
|
||||||
|
*/
|
||||||
|
public void add(final String key,
|
||||||
|
final String label,
|
||||||
|
final ComponentAccess componentAccess,
|
||||||
|
final Submit cancelButton) {
|
||||||
|
add(key, label, componentAccess);
|
||||||
|
addCancelListener((FormSection) componentAccess.getComponent(),
|
||||||
|
cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a form to the set of forms which could be used to edit the properties
|
||||||
|
*
|
||||||
|
* @param key The symbolic key for the form; must be unique for this
|
||||||
|
* <code>PropertyEditor</code>
|
||||||
|
* @param label The label for the link to access the form.
|
||||||
|
* @param componentAccess The form ComponentAccess
|
||||||
|
* @param cancelButton The Cancel button on the form.
|
||||||
|
*/
|
||||||
|
public void add(final String key,
|
||||||
|
final GlobalizedMessage label,
|
||||||
|
final ComponentAccess componentAccess,
|
||||||
|
final Submit cancelButton) {
|
||||||
|
add(key, label, componentAccess);
|
||||||
|
addCancelListener((FormSection) componentAccess.getComponent(),
|
||||||
|
cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a submission listener to the form that will hide all components and
|
||||||
|
* show the display pane. This method should be used to add submission
|
||||||
|
* listeners to forms which are buried deep inside some component, and are
|
||||||
|
* not members of this <code>PropertyEditor</code>.
|
||||||
|
*
|
||||||
|
* @param form The form
|
||||||
|
*/
|
||||||
|
public void addSecurityListener(final FormSection form) {
|
||||||
|
form.addSubmissionListener(new FormSubmissionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void submitted(final FormSectionEvent event) throws
|
||||||
|
FormProcessException {
|
||||||
|
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
|
// Cancel the form if the user does not pass the access checks.
|
||||||
|
final String key = (String) getList().getSelectedKey(state);
|
||||||
|
final ComponentAccess componentAccess
|
||||||
|
= (ComponentAccess) accessChecks.get(key);
|
||||||
|
|
||||||
|
if (key == null || componentAccess == null) {
|
||||||
|
// no components currently selected and therefore
|
||||||
|
// no access checks to run for visibility
|
||||||
|
// or
|
||||||
|
// there are no access restrictions on the form
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!componentAccess.canAccess()) {
|
||||||
|
showDisplayPane(state);
|
||||||
|
throw new FormProcessException(new GlobalizedMessage(
|
||||||
|
"cms.ui.insufficient_privileges",
|
||||||
|
CmsConstants.CMS_BUNDLE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add all required listeners to the form to ensure that if the form is
|
||||||
|
* submitted successfully or cancelled, the display pane will be shown. This
|
||||||
|
* method should be used to add listeners to forms which are buried deep
|
||||||
|
* inside some component, and are not members of this
|
||||||
|
* <code>PropertyEditor</code>.
|
||||||
|
*
|
||||||
|
* @param form The form
|
||||||
|
* @param cancelButton the "Cancel" button on the form
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addListeners(final FormSection form,
|
||||||
|
final Submit cancelButton) {
|
||||||
|
addSecurityListener(form);
|
||||||
|
super.addListeners(form, cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the map of keys to access checks
|
||||||
|
*
|
||||||
|
* @return Map of keys to access check
|
||||||
|
*/
|
||||||
|
protected final Map<String, ComponentAccess> getAccessMap() {
|
||||||
|
return accessChecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link SecurityPropertyEditor.AccessListModel} during each
|
||||||
|
* request
|
||||||
|
*/
|
||||||
|
protected static class AccessListModelBuilder extends DefaultModelBuilder {
|
||||||
|
|
||||||
|
public AccessListModelBuilder() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertyEditorModel makeModel(
|
||||||
|
final PropertyEditor propertyEditor, final PageState state) {
|
||||||
|
|
||||||
|
return new AccessListModel(
|
||||||
|
getProperties(propertyEditor),
|
||||||
|
((SecurityPropertyEditor) propertyEditor).getAccessMap(),
|
||||||
|
state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs access checks for each property; skips the properties that the
|
||||||
|
* user is not allowed to access
|
||||||
|
*/
|
||||||
|
protected static class AccessListModel extends DefaultModel {
|
||||||
|
|
||||||
|
private final Map<String, ComponentAccess> accessMap;
|
||||||
|
private final PageState state;
|
||||||
|
|
||||||
|
public AccessListModel(final Iterator iter,
|
||||||
|
final Map<String, ComponentAccess> accessMap,
|
||||||
|
final PageState state) {
|
||||||
|
super(iter);
|
||||||
|
this.accessMap = accessMap;
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean next() {
|
||||||
|
|
||||||
|
while (super.next()) {
|
||||||
|
final Object key = getKey();
|
||||||
|
final ComponentAccess ca = accessMap.get(key.toString());
|
||||||
|
|
||||||
|
if (ca == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ca.canAccess()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, skip the property
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -43,6 +43,7 @@ import com.arsdigita.cms.ui.authoring.LanguageWidget;
|
||||||
import org.librecms.util.LanguageUtil;
|
import org.librecms.util.LanguageUtil;
|
||||||
|
|
||||||
import com.arsdigita.globalization.GlobalizedMessage;
|
import com.arsdigita.globalization.GlobalizedMessage;
|
||||||
|
import com.arsdigita.kernel.KernelConfig;
|
||||||
import com.arsdigita.toolbox.ui.ActionGroup;
|
import com.arsdigita.toolbox.ui.ActionGroup;
|
||||||
import com.arsdigita.toolbox.ui.LayoutPanel;
|
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||||
import com.arsdigita.toolbox.ui.Section;
|
import com.arsdigita.toolbox.ui.Section;
|
||||||
|
|
@ -60,8 +61,11 @@ import org.librecms.contentsection.ContentItemL10NManager;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.TooManyListenersException;
|
import java.util.TooManyListenersException;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import org.libreccm.configuration.ConfigurationManager;
|
||||||
|
import org.librecms.CmsConstants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the "Language instances" pane, with all the language instances in
|
* Displays the "Language instances" pane, with all the language instances in
|
||||||
|
|
@ -81,10 +85,10 @@ public class ItemLanguages extends LayoutPanel {
|
||||||
/**
|
/**
|
||||||
* Constructs a new <code>ItemLanguages</code>.
|
* Constructs a new <code>ItemLanguages</code>.
|
||||||
*
|
*
|
||||||
* @param selectionModel the {@link ItemSelectionModel} which will supply
|
* @param selectionModel the {@link ItemSelectionModel} which will supply
|
||||||
* the current item
|
* the current item
|
||||||
* @param selectedLanguage {@link SingleSelectionModel} for the selected
|
* @param selectedLanguage {@link SingleSelectionModel} for the selected
|
||||||
* language.
|
* language.
|
||||||
*/
|
*/
|
||||||
public ItemLanguages(final ItemSelectionModel selectionModel,
|
public ItemLanguages(final ItemSelectionModel selectionModel,
|
||||||
final SingleSelectionModel<String> selectedLanguage) {
|
final SingleSelectionModel<String> selectedLanguage) {
|
||||||
|
|
@ -141,22 +145,22 @@ public class ItemLanguages extends LayoutPanel {
|
||||||
|
|
||||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
final LanguageUtil languageUtil = cdiUtil.findBean(
|
final LanguageUtil languageUtil = cdiUtil.findBean(
|
||||||
LanguageUtil.class);
|
LanguageUtil.class);
|
||||||
final ContentItemL10NManager l10NManager = cdiUtil.findBean(
|
final ContentItemL10NManager l10NManager = cdiUtil.findBean(
|
||||||
ContentItemL10NManager.class);
|
ContentItemL10NManager.class);
|
||||||
|
|
||||||
final List<String> creatableLangs = l10NManager.creatableLocales(
|
final List<String> creatableLangs = l10NManager.creatableLocales(
|
||||||
item).stream()
|
item).stream()
|
||||||
.map(locale -> locale.toString())
|
.map(locale -> locale.toString())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
final List<Pair> languages = languageUtil.convertToG11N(
|
final List<Pair> languages = languageUtil.convertToG11N(
|
||||||
creatableLangs);
|
creatableLangs);
|
||||||
|
|
||||||
for(final Pair pair : languages) {
|
for (final Pair pair : languages) {
|
||||||
final String langCode = (String) pair.getKey();
|
final String langCode = (String) pair.getKey();
|
||||||
final GlobalizedMessage langName
|
final GlobalizedMessage langName
|
||||||
= (GlobalizedMessage) pair
|
= (GlobalizedMessage) pair
|
||||||
.getValue();
|
.getValue();
|
||||||
optionGroup.addOption(new Option(langCode, new Label(langName)));
|
optionGroup.addOption(new Option(langCode, new Label(langName)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -170,64 +174,46 @@ public class ItemLanguages extends LayoutPanel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void process(final FormSectionEvent event)
|
public final void process(final FormSectionEvent event)
|
||||||
throws FormProcessException {
|
throws FormProcessException {
|
||||||
PageState state = event.getPageState();
|
|
||||||
String lang = (String) languageWidget.getValue(state);
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
ContentPage item = (ContentPage) selectionModel.getSelectedItem(
|
|
||||||
state);
|
final PageState state = event.getPageState();
|
||||||
ContentBundle bundle = item.getContentBundle();
|
final String lang = (String) languageWidget.getValue(state);
|
||||||
String name = bundle.getName();
|
final ContentItem item = (ContentItem) selectionModel
|
||||||
|
.getSelectedItem(state);
|
||||||
|
|
||||||
|
final ConfigurationManager confManager = cdiUtil.findBean(
|
||||||
|
ConfigurationManager.class);
|
||||||
|
final KernelConfig kernelConfig = confManager.findConfiguration(
|
||||||
|
KernelConfig.class);
|
||||||
|
final Locale defaultLocale = kernelConfig.getDefaultLocale();
|
||||||
|
final String name = item.getName().getValue(defaultLocale);
|
||||||
|
|
||||||
if (createSubmit.isSelected(state)) {
|
if (createSubmit.isSelected(state)) {
|
||||||
ContentSection section = item.getContentSection();
|
final ContentSection section = item.getContentType().
|
||||||
|
getContentSection();
|
||||||
|
|
||||||
Assert.exists(section, ContentSection.class);
|
Assert.exists(section, ContentSection.class);
|
||||||
|
|
||||||
ContentType type = item.getContentType();
|
final ContentItemL10NManager l10NManager = cdiUtil.findBean(
|
||||||
|
ContentItemL10NManager.class);
|
||||||
item = (ContentPage) item.copy(lang);
|
l10NManager.addLanguage(item, new Locale(lang));
|
||||||
item.setLanguage(lang);
|
|
||||||
item.setName(name);
|
|
||||||
|
|
||||||
// Apply default workflow
|
|
||||||
WorkflowTemplate template
|
|
||||||
= ContentTypeWorkflowTemplate
|
|
||||||
.getWorkflowTemplate(section, type);
|
|
||||||
if (template != null) {
|
|
||||||
Workflow w = template.instantiateNewWorkflow();
|
|
||||||
w.setObjectID(item.getID());
|
|
||||||
w.start(Kernel.getContext().getUser());
|
|
||||||
w.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
selectionModel.setSelectedObject(state, item);
|
|
||||||
|
|
||||||
// redirect to ContentItemPage.AUTHORING_TAB of the new instance
|
// redirect to ContentItemPage.AUTHORING_TAB of the new instance
|
||||||
final String target = URL.getDispatcherPath() + ContentItemPage.
|
final String target = String.join(
|
||||||
getItemURL(item,
|
"", URL.getDispatcherPath(),
|
||||||
ContentItemPage.AUTHORING_TAB);
|
ContentItemPage.getItemURL(item,
|
||||||
|
ContentItemPage.AUTHORING_TAB));
|
||||||
|
|
||||||
throw new RedirectSignal(target, true);
|
throw new RedirectSignal(target, true);
|
||||||
} else if (changeSubmit.isSelected(state)) {
|
}
|
||||||
String oldLang = item.getLanguage();
|
|
||||||
item.setLanguage(lang);
|
|
||||||
// propagate language change to the Name attribute
|
|
||||||
item.setName(name);
|
|
||||||
item.save();
|
|
||||||
|
|
||||||
// if the item being changed is the default, update the bundle
|
|
||||||
// to keep this item as the default
|
|
||||||
if (bundle.getDefaultLanguage().equals(oldLang)) {
|
|
||||||
bundle.setDefaultLanguage(lang);
|
|
||||||
bundle.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final GlobalizedMessage gz(final String key) {
|
protected static final GlobalizedMessage gz(final String key) {
|
||||||
return GlobalizationUtil.globalize(key);
|
return new GlobalizedMessage(key, CmsConstants.CMS_BUNDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final String lz(final String key) {
|
protected static final String lz(final String key) {
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ public class ItemLanguagesTable extends Table {
|
||||||
final ContentItemL10NManager l10nManager = cdiUtil.findBean(
|
final ContentItemL10NManager l10nManager = cdiUtil.findBean(
|
||||||
ContentItemL10NManager.class);
|
ContentItemL10NManager.class);
|
||||||
|
|
||||||
l10nManager.removeLangauge(item, new Locale(selectedLang));
|
l10nManager.removeLanguage(item, new Locale(selectedLang));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,455 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.item;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.categorization.Category;
|
||||||
|
import com.arsdigita.categorization.CategoryCollection;
|
||||||
|
import com.arsdigita.cms.CMS;
|
||||||
|
import com.arsdigita.cms.ContentItem;
|
||||||
|
import com.arsdigita.cms.ContentPage;
|
||||||
|
import com.arsdigita.cms.ContentSection;
|
||||||
|
import com.arsdigita.cms.ItemSelectionModel;
|
||||||
|
import com.arsdigita.cms.SecurityManager;
|
||||||
|
import com.arsdigita.cms.dispatcher.CMSDispatcher;
|
||||||
|
import com.arsdigita.cms.lifecycle.Lifecycle;
|
||||||
|
import com.arsdigita.cms.ui.CMSContainer;
|
||||||
|
import com.arsdigita.cms.util.SecurityConstants;
|
||||||
|
import com.arsdigita.cms.workflow.CMSEngine;
|
||||||
|
import com.arsdigita.cms.workflow.CMSTask;
|
||||||
|
import com.arsdigita.domain.DataObjectNotFoundException;
|
||||||
|
import com.arsdigita.domain.DomainServiceInterfaceExposer;
|
||||||
|
import com.arsdigita.kernel.ACSObject;
|
||||||
|
import com.arsdigita.kernel.User;
|
||||||
|
import com.arsdigita.kernel.permissions.PermissionDescriptor;
|
||||||
|
import com.arsdigita.kernel.permissions.PermissionService;
|
||||||
|
import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
|
||||||
|
import com.arsdigita.persistence.Filter;
|
||||||
|
import com.arsdigita.toolbox.ui.FormatStandards;
|
||||||
|
import com.arsdigita.util.Assert;
|
||||||
|
import com.arsdigita.util.GraphSet;
|
||||||
|
import com.arsdigita.util.Graphs;
|
||||||
|
import com.arsdigita.util.UncheckedWrapperException;
|
||||||
|
import com.arsdigita.versioning.Transaction;
|
||||||
|
import com.arsdigita.versioning.TransactionCollection;
|
||||||
|
import com.arsdigita.versioning.Versions;
|
||||||
|
import com.arsdigita.web.RedirectSignal;
|
||||||
|
import com.arsdigita.web.Web;
|
||||||
|
import com.arsdigita.web.WebContext;
|
||||||
|
import com.arsdigita.workflow.simple.Engine;
|
||||||
|
import com.arsdigita.workflow.simple.Task;
|
||||||
|
import com.arsdigita.workflow.simple.TaskCollection;
|
||||||
|
import com.arsdigita.workflow.simple.TaskComment;
|
||||||
|
import com.arsdigita.workflow.simple.Workflow;
|
||||||
|
import com.arsdigita.workflow.simple.WorkflowTemplate;
|
||||||
|
import com.arsdigita.xml.Element;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* This panel displays basic details about a content item such as attributes and associations.</p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Container: {@link com.arsdigita.cms.ui.ContentItemPage}
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This panel uses an {@link com.arsdigita.cms.dispatcher.XMLGenerator} to convert content items
|
||||||
|
* into XML.</p>
|
||||||
|
*
|
||||||
|
* @author Michael Pih (pihman@arsdigita.com)
|
||||||
|
* @version $Id: Summary.java 1940 2009-05-29 07:15:05Z terry $
|
||||||
|
*/
|
||||||
|
public class Summary extends CMSContainer {
|
||||||
|
|
||||||
|
private static final String SUMMARY = "itemAdminSummary";
|
||||||
|
private static final String RESTART_WORKFLOW = "restartWorkflow";
|
||||||
|
|
||||||
|
private final ItemSelectionModel m_item;
|
||||||
|
|
||||||
|
public Summary(ItemSelectionModel m) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
m_item = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate XML representation of an item summary.
|
||||||
|
*
|
||||||
|
* @param state The page state
|
||||||
|
* @param parent The parent DOM element
|
||||||
|
*
|
||||||
|
* @pre ( state != null )
|
||||||
|
* @pre ( parent != null )
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void generateXML(PageState state, Element parent) {
|
||||||
|
if (isVisible(state)) {
|
||||||
|
|
||||||
|
// Determine the item's environment
|
||||||
|
ContentItem item = getContentItem(state);
|
||||||
|
ContentSection section = getContentSection(state);
|
||||||
|
User user = Web.getWebContext().getUser();
|
||||||
|
|
||||||
|
// Setup xml element for item's properties
|
||||||
|
Element itemElement = new Element("cms:itemSummary", CMS.CMS_XML_NS);
|
||||||
|
|
||||||
|
// Determine item's name / url stub
|
||||||
|
itemElement.addAttribute("name", item.getName());
|
||||||
|
|
||||||
|
// obviously getName() here gets the 'semantically meaningful name'
|
||||||
|
// from database using class DataType. It is not localizable! And
|
||||||
|
// it is not really 'semantically meaningful'
|
||||||
|
String objectType = item.getObjectType().getName();
|
||||||
|
|
||||||
|
// Quasimodo: ObjectType for summary
|
||||||
|
itemElement.addAttribute("objectType", objectType);
|
||||||
|
|
||||||
|
// NOT USED - CUSTOMIZED SUMMARY
|
||||||
|
// Take advantage of caching in the CMS Dispatcher.
|
||||||
|
// XMLGenerator xmlGenerator = section.getXMLGenerator();
|
||||||
|
// xmlGenerator.generateXML(state, parent, SUMMARY);
|
||||||
|
String descriptionAttribute = "";
|
||||||
|
if (objectType.equals("NewsItem") || objectType.equals("Article")) {
|
||||||
|
descriptionAttribute = "lead";
|
||||||
|
} else if (objectType.equals("FileStorageItem") || objectType.equals("Minutes")) {
|
||||||
|
descriptionAttribute = "description";
|
||||||
|
} else if (objectType.equals("Job")) {
|
||||||
|
descriptionAttribute = "jobDescription";
|
||||||
|
} else if (objectType.equals("MultiPartArticle") || objectType.equals("Agenda")
|
||||||
|
|| objectType.equals("PressRelease") || objectType.equals("Service")) {
|
||||||
|
descriptionAttribute = "summary";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!descriptionAttribute.equals("")) {
|
||||||
|
itemElement.addAttribute("description", (String) DomainServiceInterfaceExposer.get(
|
||||||
|
item, descriptionAttribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ContentPage page = new ContentPage(item.getID());
|
||||||
|
itemElement.addAttribute("title", page.getTitle());
|
||||||
|
} catch (DataObjectNotFoundException ex) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
// subject category
|
||||||
|
Element subjectsElement = new Element("cms:subjectCategories", CMS.CMS_XML_NS);
|
||||||
|
itemElement.addContent(subjectsElement);
|
||||||
|
Category itemCategory = null;
|
||||||
|
Category subjectCategory = Category.getRootForObject(section, "subject");
|
||||||
|
if (subjectCategory != null) {
|
||||||
|
CategoryCollection categories = item.getCategoryCollection();
|
||||||
|
while (categories.next()) {
|
||||||
|
Category category = categories.getCategory();
|
||||||
|
CategoryCollection parents = category.getDefaultAscendants();
|
||||||
|
parents.addOrder(Category.DEFAULT_ANCESTORS);
|
||||||
|
if (parents.next()) {
|
||||||
|
Category parentCategory = parents.getCategory();
|
||||||
|
if (parentCategory.equals(subjectCategory)) {
|
||||||
|
Element subjectElement = new Element("cms:subjectCategory",
|
||||||
|
CMS.CMS_XML_NS);
|
||||||
|
subjectElement.addAttribute("name", category.getName());
|
||||||
|
subjectElement.setText(category.getPreferredQualifiedName(" -> ",
|
||||||
|
true));
|
||||||
|
subjectsElement.addContent(subjectElement);
|
||||||
|
}
|
||||||
|
parents.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL
|
||||||
|
Element linkElement = new Element("cms:linkSummary", CMS.CMS_XML_NS);
|
||||||
|
try {
|
||||||
|
linkElement.addAttribute("url",
|
||||||
|
String.format("%s/redirect?oid=%s",
|
||||||
|
Web.getWebappContextPath(),
|
||||||
|
URLEncoder.encode(item.getDraftVersion()
|
||||||
|
.getOID()
|
||||||
|
.toString(), "utf-8")));
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
//"/redirect?oid=" + URLEncoder.encode(item.getDraftVersion().getOID().toString()));
|
||||||
|
// WORKFLOW
|
||||||
|
Element workflowElement = new Element("cms:workflowSummary", CMS.CMS_XML_NS);
|
||||||
|
Workflow workflow = Workflow.getObjectWorkflow(item);
|
||||||
|
|
||||||
|
SecurityManager sm = CMS.getContext().getSecurityManager();
|
||||||
|
if (canWorkflowBeExtended(user, item, workflow)) {
|
||||||
|
// control event for restarting workflow in edit mode
|
||||||
|
try {
|
||||||
|
state.setControlEvent(this, RESTART_WORKFLOW, item.getID().toString());
|
||||||
|
workflowElement.addAttribute("restartWorkflowURL", state.stateAsURL());
|
||||||
|
state.clearControlEvent();
|
||||||
|
} catch (java.io.IOException ex) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workflow == null) {
|
||||||
|
workflowElement.addAttribute("noWorkflow", "1");
|
||||||
|
} else {
|
||||||
|
workflowElement.addAttribute("name", workflow.getDisplayName());
|
||||||
|
|
||||||
|
TaskCollection tc = workflow.getTaskCollection();
|
||||||
|
GraphSet g = new GraphSet();
|
||||||
|
while (tc.next()) {
|
||||||
|
Task t = tc.getTask();
|
||||||
|
final TaskCollection deps = t.getRequiredTasks();
|
||||||
|
final StringBuffer buffer = new StringBuffer();
|
||||||
|
while (deps.next()) {
|
||||||
|
Task dep = deps.getTask();
|
||||||
|
g.addEdge(t, dep, null);
|
||||||
|
buffer.append(dep.getLabel() + ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
final int len = buffer.length();
|
||||||
|
if (len >= 2) {
|
||||||
|
buffer.setLength(len - 2);
|
||||||
|
} else {
|
||||||
|
g.addNode(t);
|
||||||
|
}
|
||||||
|
deps.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
List taskList = new ArrayList();
|
||||||
|
outer:
|
||||||
|
while (g.nodeCount() > 0) {
|
||||||
|
List l = Graphs.getSinkNodes(g);
|
||||||
|
for (Iterator it = l.iterator(); it.hasNext();) {
|
||||||
|
Task t = (Task) it.next();
|
||||||
|
taskList.add(0, t);
|
||||||
|
g.removeNode(t);
|
||||||
|
continue outer;
|
||||||
|
}
|
||||||
|
// break loop if no nodes removed
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Iterator tasks = taskList.iterator();
|
||||||
|
|
||||||
|
while (tasks.hasNext()) {
|
||||||
|
Task task = (Task) tasks.next();
|
||||||
|
Element taskElement = new Element("cms:task", CMS.CMS_XML_NS);
|
||||||
|
taskElement.addAttribute("name", task.getDisplayName());
|
||||||
|
taskElement.addAttribute("state", task.getStateString());
|
||||||
|
Iterator comments = task.getComments();
|
||||||
|
while (comments.hasNext()) {
|
||||||
|
TaskComment comment = (TaskComment) comments.next();
|
||||||
|
Element commentElement = new Element("cms:taskComment", CMS.CMS_XML_NS);
|
||||||
|
User author = comment.getUser();
|
||||||
|
String authorName = "Anonymous";
|
||||||
|
if (author != null) {
|
||||||
|
authorName = author.getDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
commentElement.addAttribute("author", authorName);
|
||||||
|
commentElement.addAttribute("comment", comment.getComment());
|
||||||
|
commentElement.addAttribute("date", FormatStandards.formatDate(comment
|
||||||
|
.getDate()));
|
||||||
|
|
||||||
|
taskElement.addContent(commentElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
workflowElement.addContent(taskElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// REVISION HISTORY
|
||||||
|
Element transactionElement = new Element("cms:transactionSummary", CMS.CMS_XML_NS);
|
||||||
|
transactionElement.addAttribute("creationDate", FormatStandards.formatDate(item
|
||||||
|
.getCreationDate()));
|
||||||
|
transactionElement.addAttribute("lastModifiedDate", FormatStandards.formatDate(item
|
||||||
|
.getLastModifiedDate()));
|
||||||
|
|
||||||
|
TransactionCollection transactions = Versions.getTaggedTransactions(item.getOID());
|
||||||
|
while (transactions.next()) {
|
||||||
|
Transaction transaction = transactions.getTransaction();
|
||||||
|
Element element = new Element("cms:transaction", CMS.CMS_XML_NS);
|
||||||
|
element.addAttribute("date", FormatStandards.formatDate(transaction.getTimestamp()));
|
||||||
|
String authorName = "Anonymous";
|
||||||
|
User author = transaction.getUser();
|
||||||
|
if (author != null) {
|
||||||
|
authorName = author.getDisplayName();
|
||||||
|
}
|
||||||
|
element.addAttribute("author", authorName);
|
||||||
|
|
||||||
|
String url = section.getItemResolver().generateItemURL(state, item, section,
|
||||||
|
CMSDispatcher.PREVIEW)
|
||||||
|
+ "?transID=" + transaction.getID();
|
||||||
|
element.addAttribute("url", url);
|
||||||
|
transactionElement.addContent(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
transactions.close();
|
||||||
|
|
||||||
|
// CATEGORY
|
||||||
|
Element categoryElement = new Element("cms:categorySummary", CMS.CMS_XML_NS);
|
||||||
|
|
||||||
|
CategoryCollection categories = item.getCategoryCollection();
|
||||||
|
while (categories.next()) {
|
||||||
|
Category category = categories.getCategory();
|
||||||
|
Element element = new Element("cms:category", CMS.CMS_XML_NS);
|
||||||
|
element.setText(category.getPreferredQualifiedName(" -> ", true));
|
||||||
|
categoryElement.addContent(element);
|
||||||
|
|
||||||
|
}
|
||||||
|
categories.close();
|
||||||
|
|
||||||
|
// LIFECYCLE
|
||||||
|
Element lifecycleElement = new Element("cms:lifecycleSummary", CMS.CMS_XML_NS);
|
||||||
|
|
||||||
|
Lifecycle lifecycle = item.getLifecycle();
|
||||||
|
if (lifecycle == null) {
|
||||||
|
lifecycleElement.addAttribute("noLifecycle", "1");
|
||||||
|
} else {
|
||||||
|
lifecycleElement.addAttribute("name", lifecycle.getLabel());
|
||||||
|
lifecycleElement.addAttribute("startDate", FormatStandards.formatDate(lifecycle
|
||||||
|
.getStartDate()));
|
||||||
|
|
||||||
|
java.util.Date endDate = lifecycle.getEndDate();
|
||||||
|
if (endDate == null) {
|
||||||
|
lifecycleElement.addAttribute("endDateString", "last forever");
|
||||||
|
} else {
|
||||||
|
lifecycleElement.addAttribute("endDateString", "expire on " + FormatStandards
|
||||||
|
.formatDate(endDate));
|
||||||
|
lifecycleElement.addAttribute("endDate", FormatStandards.formatDate(endDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleElement.addAttribute("hasBegun", (new Boolean(lifecycle.hasBegun()))
|
||||||
|
.toString());
|
||||||
|
lifecycleElement.addAttribute("hasEnded", (new Boolean(lifecycle.hasEnded()))
|
||||||
|
.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.addContent(itemElement);
|
||||||
|
parent.addContent(categoryElement);
|
||||||
|
parent.addContent(linkElement);
|
||||||
|
parent.addContent(lifecycleElement);
|
||||||
|
parent.addContent(workflowElement);
|
||||||
|
parent.addContent(transactionElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the selected content item.
|
||||||
|
*
|
||||||
|
* @param state The page state
|
||||||
|
*
|
||||||
|
* @return The selected item
|
||||||
|
*
|
||||||
|
* @pre ( state != null )
|
||||||
|
*/
|
||||||
|
protected ContentItem getContentItem(PageState state) {
|
||||||
|
ContentItem item = (ContentItem) m_item.getSelectedObject(state);
|
||||||
|
Assert.exists(item);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the current content section.
|
||||||
|
*
|
||||||
|
* @param state The page state
|
||||||
|
*
|
||||||
|
* @return The content section
|
||||||
|
*
|
||||||
|
* @pre ( state != null )
|
||||||
|
*/
|
||||||
|
protected ContentSection getContentSection(PageState state) {
|
||||||
|
ContentSection section = CMS.getContext().getContentSection();
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void respond(PageState state) throws ServletException {
|
||||||
|
String key = state.getControlEventName();
|
||||||
|
String value = state.getControlEventValue();
|
||||||
|
if (RESTART_WORKFLOW.equals(key)) {
|
||||||
|
User user = Web.getWebContext().getUser();
|
||||||
|
ContentItem item = getContentItem(state);
|
||||||
|
ContentSection section = item.getContentSection();
|
||||||
|
Workflow w = Workflow.getObjectWorkflow(item);
|
||||||
|
|
||||||
|
if (canWorkflowBeExtended(user, item, w)) {
|
||||||
|
WorkflowTemplate template = w.getWorkflowTemplate();
|
||||||
|
if (template != null) {
|
||||||
|
template.extendWorkflow(w);
|
||||||
|
w.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// lock the next task
|
||||||
|
Engine engine = Engine.getInstance(CMSEngine.CMS_ENGINE_TYPE);
|
||||||
|
Iterator i = engine.getEnabledTasks(user, w.getID()).iterator();
|
||||||
|
if (i.hasNext()) {
|
||||||
|
CMSTask task = (CMSTask) i.next();
|
||||||
|
|
||||||
|
if (!task.isLocked()) {
|
||||||
|
task.lock(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String redirectURL = Web.getConfig().getDispatcherServletPath() + item
|
||||||
|
.getContentSection().getPath() + "/admin/item.jsp?item_id=" + item.getID()
|
||||||
|
+ "&set_tab=1";
|
||||||
|
throw new RedirectSignal(redirectURL, true);
|
||||||
|
} else {
|
||||||
|
throw new ServletException("Unknown control event: " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks if workflow can be extended
|
||||||
|
*/
|
||||||
|
protected boolean canWorkflowBeExtended(User user, ContentItem item, Workflow workflow) {
|
||||||
|
boolean canBeExtended = true;
|
||||||
|
|
||||||
|
if (workflow == null) {
|
||||||
|
canBeExtended = false;
|
||||||
|
} else if (!workflow.isFinished()) {
|
||||||
|
canBeExtended = false;
|
||||||
|
} else if (workflow.getWorkflowTemplate() == null) {
|
||||||
|
canBeExtended = false;
|
||||||
|
} else {
|
||||||
|
TaskCollection templates = item.getContentSection().getWorkflowTemplates();
|
||||||
|
Filter f = templates.addInSubqueryFilter("id",
|
||||||
|
"com.arsdigita.cms.getWorkflowTemplateUserFilter");
|
||||||
|
f.set("userId", Web.getWebContext().getUser().getID());
|
||||||
|
templates.addEqualsFilter(ACSObject.ID, workflow.getWorkflowTemplate().getID());
|
||||||
|
|
||||||
|
PrivilegeDescriptor pd = PrivilegeDescriptor.get(SecurityConstants.CMS_WORKFLOW_ADMIN);
|
||||||
|
PermissionDescriptor perm = new PermissionDescriptor(pd, item, user);
|
||||||
|
if (!(templates.next() || PermissionService.checkPermission(perm))) {
|
||||||
|
canBeExtended = false;
|
||||||
|
}
|
||||||
|
templates.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return canBeExtended;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.lifecycle;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.ControlLink;
|
||||||
|
import com.arsdigita.bebop.Label;
|
||||||
|
import com.arsdigita.bebop.Page;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.event.ActionEvent;
|
||||||
|
import com.arsdigita.bebop.event.ActionListener;
|
||||||
|
import com.arsdigita.categorization.Category;
|
||||||
|
import com.arsdigita.categorization.CategoryCollection;
|
||||||
|
import com.arsdigita.cms.CMS;
|
||||||
|
import com.arsdigita.cms.CMSConfig;
|
||||||
|
import com.arsdigita.cms.ContentItem;
|
||||||
|
import com.arsdigita.cms.lifecycle.Lifecycle;
|
||||||
|
import com.arsdigita.cms.ui.BaseItemPane;
|
||||||
|
import com.arsdigita.cms.ui.ContentItemPage;
|
||||||
|
import com.arsdigita.cms.ui.item.ContentItemRequestLocal;
|
||||||
|
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||||
|
import com.arsdigita.web.RedirectSignal;
|
||||||
|
import com.arsdigita.web.URL;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Michael Pih
|
||||||
|
* @author Jack Chung
|
||||||
|
* @author Justin Ross <jross@redhat.com>
|
||||||
|
* @author Jens Pelzetter jens@jp-digital.de
|
||||||
|
* @version $Id: ItemLifecycleAdminPane.java 1942 2009-05-29 07:53:23Z terry $
|
||||||
|
*/
|
||||||
|
public class ItemLifecycleAdminPane extends BaseItemPane {
|
||||||
|
|
||||||
|
private static final Logger s_log = Logger.getLogger(
|
||||||
|
ItemLifecycleAdminPane.class);
|
||||||
|
private final ContentItemRequestLocal m_item;
|
||||||
|
private final LifecycleRequestLocal m_lifecycle;
|
||||||
|
private final LayoutPanel m_introPane;
|
||||||
|
private final LayoutPanel m_detailPane;
|
||||||
|
private final LayoutPanel m_selectPane;
|
||||||
|
private final LayoutPanel m_lockedPane;
|
||||||
|
private final LayoutPanel m_errorPane;
|
||||||
|
private final LayoutPanel m_cantPublishPane;
|
||||||
|
|
||||||
|
public ItemLifecycleAdminPane(final ContentItemRequestLocal item) {
|
||||||
|
m_item = item;
|
||||||
|
m_lifecycle = new ItemLifecycleRequestLocal();
|
||||||
|
|
||||||
|
m_introPane = new LayoutPanel();
|
||||||
|
add(m_introPane);
|
||||||
|
|
||||||
|
final Label message = new Label(gz("cms.ui.item.lifecycle.intro"));
|
||||||
|
m_introPane.setBody(message);
|
||||||
|
|
||||||
|
m_detailPane = new LayoutPanel();
|
||||||
|
add(m_detailPane);
|
||||||
|
|
||||||
|
final ItemLifecycleItemPane itemPane =
|
||||||
|
new ItemLifecycleItemPane(m_item,
|
||||||
|
m_lifecycle);
|
||||||
|
m_detailPane.setBody(itemPane);
|
||||||
|
|
||||||
|
m_selectPane = new LayoutPanel();
|
||||||
|
add(m_selectPane);
|
||||||
|
|
||||||
|
final ItemLifecycleSelectForm selectForm =
|
||||||
|
new ItemLifecycleSelectForm(m_item);
|
||||||
|
m_selectPane.setBody(selectForm);
|
||||||
|
|
||||||
|
m_lockedPane = new LayoutPanel();
|
||||||
|
add(m_lockedPane);
|
||||||
|
|
||||||
|
final Label lockedMsg = new Label(gz(
|
||||||
|
"cms.ui.item.lifecycle.publish_locked"));
|
||||||
|
m_lockedPane.setBody(lockedMsg);
|
||||||
|
final ControlLink lockedUpdateLink = new ControlLink(new Label(gz(
|
||||||
|
"cms.ui.item.lifecycle.publish_locked.update")));
|
||||||
|
lockedUpdateLink.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
public void actionPerformed(final ActionEvent event) {
|
||||||
|
throw new RedirectSignal(
|
||||||
|
URL.getDispatcherPath()
|
||||||
|
+ ContentItemPage.getItemURL(
|
||||||
|
item.getContentItem(event.getPageState()),
|
||||||
|
ContentItemPage.PUBLISHING_TAB),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
m_lockedPane.setBottom(lockedUpdateLink);
|
||||||
|
|
||||||
|
m_errorPane = new LayoutPanel();
|
||||||
|
add(m_errorPane);
|
||||||
|
|
||||||
|
final Label errorMsg = new Label(gz("cms.ui.lifecycle.publish.error"));
|
||||||
|
m_errorPane.setBody(errorMsg);
|
||||||
|
|
||||||
|
m_cantPublishPane = new LayoutPanel();
|
||||||
|
add(m_cantPublishPane);
|
||||||
|
|
||||||
|
final Label cantPublish = new Label(gz("cms.ui.lifecycle.publish.not_possible_abstract_category"));
|
||||||
|
m_cantPublishPane.setBody(cantPublish);
|
||||||
|
|
||||||
|
connect(selectForm, m_detailPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ItemLifecycleRequestLocal extends LifecycleRequestLocal {
|
||||||
|
|
||||||
|
protected final Object initialValue(final PageState state) {
|
||||||
|
final ContentItem item = m_item.getContentItem(state);
|
||||||
|
final Lifecycle lifecycle = item.getLifecycle();
|
||||||
|
|
||||||
|
s_log.debug("Returning lifecycle " + lifecycle);
|
||||||
|
|
||||||
|
return lifecycle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void register(final Page page) {
|
||||||
|
super.register(page);
|
||||||
|
|
||||||
|
page.addActionListener(new VisibilityListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class VisibilityListener implements ActionListener {
|
||||||
|
|
||||||
|
public final void actionPerformed(final ActionEvent e) {
|
||||||
|
s_log.debug("Determining which pane to show");
|
||||||
|
|
||||||
|
final PageState state = e.getPageState();
|
||||||
|
|
||||||
|
if (CMSConfig.getInstanceOf().getThreadedPublishing()
|
||||||
|
&& PublishLock.getInstance().isLocked(m_item.getContentItem(
|
||||||
|
state))) {
|
||||||
|
if (PublishLock.getInstance().hasError(m_item.getContentItem(
|
||||||
|
state))) {
|
||||||
|
push(state, m_errorPane);
|
||||||
|
} else {
|
||||||
|
push(state, m_lockedPane);
|
||||||
|
state.getResponse().addIntHeader("Refresh", 5);
|
||||||
|
}
|
||||||
|
} else if(isAssignedToAbstractCategory(m_item.getContentItem(state))) {
|
||||||
|
push(state, m_cantPublishPane);
|
||||||
|
} else {
|
||||||
|
if (state.isVisibleOnPage(ItemLifecycleAdminPane.this)) {
|
||||||
|
if (m_lifecycle.getLifecycle(state) == null) {
|
||||||
|
if (hasPermission(state)) {
|
||||||
|
push(state, m_selectPane);
|
||||||
|
} else {
|
||||||
|
push(state, m_introPane);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push(state, m_detailPane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasPermission(final PageState state) {
|
||||||
|
final ContentItem item = m_item.getContentItem(state);
|
||||||
|
|
||||||
|
return CMS.getContext().getSecurityManager().canAccess(
|
||||||
|
state.getRequest(), SCHEDULE_PUBLICATION, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the item is assigned to an abstract category.
|
||||||
|
*
|
||||||
|
* A category is abstract if not items can assigned to it.
|
||||||
|
*
|
||||||
|
* @param item
|
||||||
|
* @return {@code true} if assigned to a abstract category, {@code false} if not.
|
||||||
|
*/
|
||||||
|
private boolean isAssignedToAbstractCategory(final ContentItem item) {
|
||||||
|
|
||||||
|
final CategoryCollection categories = item.getCategoryCollection();
|
||||||
|
|
||||||
|
boolean result = false;
|
||||||
|
Category category;
|
||||||
|
while(categories.next()) {
|
||||||
|
category = categories.getCategory();
|
||||||
|
|
||||||
|
if (category.isAbstract()) {
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
categories.close();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,316 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.revision;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.ActionLink;
|
||||||
|
import com.arsdigita.bebop.Component;
|
||||||
|
import com.arsdigita.bebop.ControlLink;
|
||||||
|
import com.arsdigita.bebop.Form;
|
||||||
|
import com.arsdigita.bebop.GridPanel;
|
||||||
|
import com.arsdigita.bebop.Label;
|
||||||
|
import com.arsdigita.bebop.Link;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.Table;
|
||||||
|
import com.arsdigita.bebop.event.TableActionAdapter;
|
||||||
|
import com.arsdigita.bebop.event.TableActionEvent;
|
||||||
|
import com.arsdigita.bebop.form.Option;
|
||||||
|
import com.arsdigita.bebop.form.RadioGroup;
|
||||||
|
import com.arsdigita.bebop.form.Submit;
|
||||||
|
import com.arsdigita.bebop.table.DefaultTableCellRenderer;
|
||||||
|
import com.arsdigita.bebop.table.DefaultTableColumnModel;
|
||||||
|
import com.arsdigita.bebop.table.TableCellRenderer;
|
||||||
|
import com.arsdigita.bebop.table.TableColumn;
|
||||||
|
import com.arsdigita.bebop.table.TableColumnModel;
|
||||||
|
import com.arsdigita.cms.ContentItem;
|
||||||
|
import com.arsdigita.cms.ContentSection;
|
||||||
|
import com.arsdigita.cms.dispatcher.CMSDispatcher;
|
||||||
|
import com.arsdigita.cms.dispatcher.ItemResolver;
|
||||||
|
import com.arsdigita.cms.ui.BaseItemPane;
|
||||||
|
import com.arsdigita.cms.ui.item.ContentItemRequestLocal;
|
||||||
|
import com.arsdigita.toolbox.ui.ActionGroup;
|
||||||
|
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||||
|
import com.arsdigita.toolbox.ui.NullComponent;
|
||||||
|
import com.arsdigita.toolbox.ui.Section;
|
||||||
|
import com.arsdigita.versioning.Transaction;
|
||||||
|
import com.arsdigita.versioning.Versions;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @version $Id: ItemRevisionAdminPane.java 287 2005-02-22 00:29:02Z sskracic $
|
||||||
|
*/
|
||||||
|
public final class ItemRevisionAdminPane extends BaseItemPane {
|
||||||
|
|
||||||
|
private final ContentItemRequestLocal m_item;
|
||||||
|
|
||||||
|
private final RevisionTable m_revisions;
|
||||||
|
|
||||||
|
private final TransactionRequestLocal m_from;
|
||||||
|
private final TransactionRequestLocal m_to;
|
||||||
|
|
||||||
|
private final LayoutPanel m_selectPane;
|
||||||
|
private final DifferencePane m_diffPane;
|
||||||
|
|
||||||
|
public ItemRevisionAdminPane(final ContentItemRequestLocal item) {
|
||||||
|
m_item = item;
|
||||||
|
|
||||||
|
final RadioGroup fromSelect = new RadioGroup("from");
|
||||||
|
final RadioGroup toSelect = new RadioGroup("to");
|
||||||
|
|
||||||
|
m_from = new SelectionRequestLocal(fromSelect);
|
||||||
|
m_to = new SelectionRequestLocal(toSelect);
|
||||||
|
|
||||||
|
m_revisions = new RevisionTable(fromSelect, toSelect);
|
||||||
|
|
||||||
|
final RevisionForm form = new RevisionForm
|
||||||
|
(fromSelect, toSelect, m_revisions);
|
||||||
|
|
||||||
|
m_selectPane = new LayoutPanel();
|
||||||
|
add(m_selectPane);
|
||||||
|
setDefault(m_selectPane);
|
||||||
|
|
||||||
|
m_selectPane.setBody
|
||||||
|
(new Section(gz("cms.ui.item.revisions"), form));
|
||||||
|
|
||||||
|
final ActionLink returnLink = new ActionLink
|
||||||
|
(new Label(gz("cms.ui.item.revision.return")));
|
||||||
|
|
||||||
|
m_diffPane = new DifferencePane(m_item, m_from, m_to, returnLink);
|
||||||
|
add(m_diffPane);
|
||||||
|
|
||||||
|
connect(form, m_diffPane);
|
||||||
|
connect(returnLink, m_selectPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SelectionRequestLocal extends TransactionRequestLocal {
|
||||||
|
private final RadioGroup m_group;
|
||||||
|
|
||||||
|
SelectionRequestLocal(final RadioGroup group) {
|
||||||
|
m_group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Object initialValue(final PageState state) {
|
||||||
|
final Object id = m_group.getValue(state);
|
||||||
|
|
||||||
|
if (id == null || id.toString().equals("")) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return Transaction.retrieve(new BigInteger(id.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RevisionForm extends Form {
|
||||||
|
RevisionForm(final RadioGroup fromSelect,
|
||||||
|
final RadioGroup toSelect,
|
||||||
|
final RevisionTable revisions) {
|
||||||
|
super("revisions", new GridPanel(1));
|
||||||
|
|
||||||
|
setMethod("get");
|
||||||
|
|
||||||
|
add(fromSelect);
|
||||||
|
add(toSelect);
|
||||||
|
|
||||||
|
// Sets the 'to' revision to the dummy current revision
|
||||||
|
// and the 'from' revision to the dummy root revision.
|
||||||
|
fromSelect.setOptionSelected("");
|
||||||
|
toSelect.setOptionSelected("");
|
||||||
|
|
||||||
|
final ActionGroup group = new ActionGroup();
|
||||||
|
add(group);
|
||||||
|
|
||||||
|
group.setSubject(revisions);
|
||||||
|
|
||||||
|
group.addAction
|
||||||
|
(new Submit("diff",
|
||||||
|
gz("cms.ui.item.revision.difference.show")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RevisionTable extends Table {
|
||||||
|
// XXX Need to fix the static l18n stuff
|
||||||
|
|
||||||
|
private TableColumn m_from = new TableColumn
|
||||||
|
(RevisionTableModelBuilder.FROM, lz("cms.ui.item.revision.from"));
|
||||||
|
private TableColumn m_to = new TableColumn
|
||||||
|
(RevisionTableModelBuilder.TO, lz("cms.ui.item.revision.to"));
|
||||||
|
private TableColumn m_timestamp = new TableColumn
|
||||||
|
(RevisionTableModelBuilder.TIMESTAMP, lz("cms.ui.item.revision"));
|
||||||
|
private TableColumn m_user = new TableColumn
|
||||||
|
(RevisionTableModelBuilder.USER, lz("cms.ui.user"));
|
||||||
|
private TableColumn m_description = new TableColumn
|
||||||
|
(RevisionTableModelBuilder.DESCRIPTION, lz("cms.ui.description"));
|
||||||
|
private TableColumn m_preview = new TableColumn
|
||||||
|
(RevisionTableModelBuilder.PREVIEW, lz("cms.ui.item.revision.view"));
|
||||||
|
private TableColumn m_rollback = new TableColumn
|
||||||
|
(RevisionTableModelBuilder.ROLLBACK,
|
||||||
|
lz("cms.ui.item.revision.rollback"));
|
||||||
|
|
||||||
|
public RevisionTable(final RadioGroup fromSelect,
|
||||||
|
final RadioGroup toSelect) {
|
||||||
|
super(new RevisionTableModelBuilder(m_item),
|
||||||
|
new DefaultTableColumnModel());
|
||||||
|
|
||||||
|
final TableColumnModel columns = getColumnModel();
|
||||||
|
columns.add(m_from);
|
||||||
|
columns.add(m_to);
|
||||||
|
columns.add(m_timestamp);
|
||||||
|
columns.add(m_user);
|
||||||
|
columns.add(m_description);
|
||||||
|
columns.add(m_preview);
|
||||||
|
columns.add(m_rollback);
|
||||||
|
|
||||||
|
m_from.setCellRenderer(new RadioCellRenderer(fromSelect));
|
||||||
|
m_to.setCellRenderer(new RadioCellRenderer(toSelect));
|
||||||
|
m_timestamp.setCellRenderer(new DefaultTableCellRenderer(false));
|
||||||
|
m_user.setCellRenderer(new DefaultTableCellRenderer(false));
|
||||||
|
m_description.setCellRenderer(new DefaultTableCellRenderer(false));
|
||||||
|
m_preview.setCellRenderer(new ViewCellRenderer());
|
||||||
|
m_rollback.setCellRenderer(new RollbackCellRenderer());
|
||||||
|
|
||||||
|
setEmptyView(new Label(gz("cms.ui.item.revision.none")));
|
||||||
|
|
||||||
|
addTableActionListener(new RollbackActionListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
class RadioCellRenderer implements TableCellRenderer {
|
||||||
|
private final RadioGroup m_group;
|
||||||
|
|
||||||
|
RadioCellRenderer(final RadioGroup group) {
|
||||||
|
m_group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getComponent(final Table table,
|
||||||
|
final PageState state,
|
||||||
|
final Object value,
|
||||||
|
final boolean isSelected,
|
||||||
|
final Object key,
|
||||||
|
final int row, final int column) {
|
||||||
|
if (key.toString().equals("first")) {
|
||||||
|
if (column == RevisionTableModelBuilder.FROM) {
|
||||||
|
return new NullComponent();
|
||||||
|
} else {
|
||||||
|
final Option option = new Option("", "");
|
||||||
|
|
||||||
|
option.setGroup(m_group);
|
||||||
|
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
} else if (key.toString().equals("last")) {
|
||||||
|
if (column == RevisionTableModelBuilder.FROM) {
|
||||||
|
final Option option = new Option("", "");
|
||||||
|
|
||||||
|
option.setGroup(m_group);
|
||||||
|
|
||||||
|
return option;
|
||||||
|
} else {
|
||||||
|
return new NullComponent();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final Option option = new Option(key.toString(), "");
|
||||||
|
|
||||||
|
option.setGroup(m_group);
|
||||||
|
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewCellRenderer implements TableCellRenderer {
|
||||||
|
public Component getComponent(final Table table,
|
||||||
|
final PageState state,
|
||||||
|
final Object value,
|
||||||
|
final boolean isSelected,
|
||||||
|
final Object key,
|
||||||
|
final int row, final int column) {
|
||||||
|
if (key instanceof String) {
|
||||||
|
return new NullComponent();
|
||||||
|
} else {
|
||||||
|
final BigInteger transID = (BigInteger) key;
|
||||||
|
final ContentItem item = m_item.getContentItem(state);
|
||||||
|
final ContentSection section = item.getContentSection();
|
||||||
|
|
||||||
|
final ItemResolver itemResolver =
|
||||||
|
section.getItemResolver();
|
||||||
|
|
||||||
|
final StringBuffer url = new StringBuffer
|
||||||
|
(itemResolver.generateItemURL
|
||||||
|
(state, item, section, CMSDispatcher.PREVIEW));
|
||||||
|
|
||||||
|
// Cheesy code should be fixed
|
||||||
|
|
||||||
|
final String sep;
|
||||||
|
if (url.toString().indexOf('?') == -1) {
|
||||||
|
sep = "?";
|
||||||
|
} else {
|
||||||
|
sep = "&";
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fix this
|
||||||
|
//url.append(sep).append
|
||||||
|
// (HistoryCollection.TRANS_ID).append("=");
|
||||||
|
url.append(sep).append("transID").append("=");
|
||||||
|
url.append(transID.toString());
|
||||||
|
|
||||||
|
final Link link = new Link
|
||||||
|
(new Label(gz("cms.ui.item.revision.view")),
|
||||||
|
url.toString());
|
||||||
|
|
||||||
|
link.setTargetFrame(lz("cms.ui.item.revision.view"));
|
||||||
|
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RollbackActionListener extends TableActionAdapter {
|
||||||
|
public final void cellSelected(final TableActionEvent e) {
|
||||||
|
final PageState state = e.getPageState();
|
||||||
|
|
||||||
|
if (e.getColumn().intValue()
|
||||||
|
== RevisionTableModelBuilder.ROLLBACK) {
|
||||||
|
final ContentItem item = m_item.getContentItem(state);
|
||||||
|
|
||||||
|
Versions.rollback
|
||||||
|
(item.getOID(),
|
||||||
|
new BigInteger(e.getRowKey().toString()));
|
||||||
|
|
||||||
|
item.applyTag(lz("cms.ui.item.revision.rolled_back"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RollbackCellRenderer implements TableCellRenderer {
|
||||||
|
public Component getComponent(final Table table,
|
||||||
|
final PageState state,
|
||||||
|
final Object value,
|
||||||
|
final boolean isSelected,
|
||||||
|
final Object key,
|
||||||
|
final int row, final int column) {
|
||||||
|
if (key instanceof String) {
|
||||||
|
return new NullComponent();
|
||||||
|
} else {
|
||||||
|
return new ControlLink
|
||||||
|
(new Label(gz("cms.ui.item.revision.rollback")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.templates;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.Component;
|
||||||
|
import com.arsdigita.bebop.ControlLink;
|
||||||
|
import com.arsdigita.bebop.Label;
|
||||||
|
import com.arsdigita.bebop.Page;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.SegmentedPanel;
|
||||||
|
import com.arsdigita.bebop.SingleSelectionModel;
|
||||||
|
import com.arsdigita.bebop.Table;
|
||||||
|
import com.arsdigita.bebop.event.ActionEvent;
|
||||||
|
import com.arsdigita.bebop.event.ActionListener;
|
||||||
|
import com.arsdigita.bebop.event.PrintEvent;
|
||||||
|
import com.arsdigita.bebop.event.PrintListener;
|
||||||
|
import com.arsdigita.bebop.event.TableActionAdapter;
|
||||||
|
import com.arsdigita.bebop.event.TableActionEvent;
|
||||||
|
import com.arsdigita.bebop.table.TableCellRenderer;
|
||||||
|
import com.arsdigita.bebop.table.TableColumn;
|
||||||
|
import com.arsdigita.cms.CMS;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
|
||||||
|
import org.librecms.contentsection.ContentSection;
|
||||||
|
import org.librecms.contentsection.ContentType;
|
||||||
|
import com.arsdigita.cms.ItemSelectionModel;
|
||||||
|
import com.arsdigita.cms.Template;
|
||||||
|
import com.arsdigita.cms.TemplateCollection;
|
||||||
|
import com.arsdigita.cms.TemplateManagerFactory;
|
||||||
|
import com.arsdigita.cms.ui.SecurityPropertyEditor;
|
||||||
|
import com.arsdigita.cms.ui.workflow.WorkflowLockedComponentAccess;
|
||||||
|
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||||
|
import com.arsdigita.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component will eventually contain the full templates UI for
|
||||||
|
* content items. It is just a placeholder for now.
|
||||||
|
*
|
||||||
|
* @author Stanislav Freidin
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class ItemTemplates extends SecurityPropertyEditor {
|
||||||
|
private ItemSelectionModel m_itemModel;
|
||||||
|
|
||||||
|
public static final String ASSIGN_TEMPLATE = "assignTemplate";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new ItemTemplates component
|
||||||
|
*
|
||||||
|
* @param model the <code>ItemSelectionModel</code> that will supply the
|
||||||
|
* current content item
|
||||||
|
*/
|
||||||
|
public ItemTemplates(ItemSelectionModel model) {
|
||||||
|
super();
|
||||||
|
m_itemModel = model;
|
||||||
|
|
||||||
|
ItemTemplatesListingImpl l = new ItemTemplatesListingImpl(model);
|
||||||
|
|
||||||
|
final LayoutPanel layout = new LayoutPanel();
|
||||||
|
setDisplayComponent(layout);
|
||||||
|
|
||||||
|
SegmentedPanel st = new SegmentedPanel();
|
||||||
|
layout.setBody(st);
|
||||||
|
|
||||||
|
st.addSegment(new Label(GlobalizationUtil.globalize("cms.ui.templates.assigned_templates")), l);
|
||||||
|
|
||||||
|
SegmentedPanel sa = new SegmentedPanel();
|
||||||
|
Label assignLabel = new Label(GlobalizationUtil.globalize("cms.ui.templates.dummy"));
|
||||||
|
assignLabel.addPrintListener(new PrintListener() {
|
||||||
|
public void prepare(PrintEvent e) {
|
||||||
|
PageState s = e.getPageState();
|
||||||
|
Label targetLabel = (Label)e.getTarget();
|
||||||
|
ContentPage item = (ContentPage)m_itemModel.getSelectedItem(s);
|
||||||
|
Assert.exists(item, "item");
|
||||||
|
targetLabel.setLabel( (String) GlobalizationUtil.globalize("cms.ui.templates.assign_a_template_to").localize() + item.getTitle());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sa.addSegment(assignLabel,
|
||||||
|
new AvailableTemplatesListing(l.getRowSelectionModel()));
|
||||||
|
addComponent(ASSIGN_TEMPLATE, sa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a list of templates which are currently assigned to
|
||||||
|
* the current item
|
||||||
|
*/
|
||||||
|
protected class ItemTemplatesListingImpl extends ItemTemplatesListing {
|
||||||
|
|
||||||
|
private WorkflowLockedComponentAccess m_access;
|
||||||
|
|
||||||
|
public ItemTemplatesListingImpl(ItemSelectionModel model) {
|
||||||
|
super(model);
|
||||||
|
m_access = new WorkflowLockedComponentAccess(null, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void assignLinkClicked(PageState s,
|
||||||
|
ContentItem item,
|
||||||
|
String useContext) {
|
||||||
|
showComponent(s, ASSIGN_TEMPLATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(Page p) {
|
||||||
|
super.register(p);
|
||||||
|
// Hide action columns if user has no access
|
||||||
|
p.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
final PageState state = e.getPageState();
|
||||||
|
|
||||||
|
if (state.isVisibleOnPage(ItemTemplates.this)) {
|
||||||
|
if (m_access.canAccess
|
||||||
|
(state,
|
||||||
|
CMS.getContext().getSecurityManager())) {
|
||||||
|
getRemoveColumn().setVisible(state, true);
|
||||||
|
getAssignColumn().setVisible(state, true);
|
||||||
|
} else {
|
||||||
|
getRemoveColumn().setVisible(state, false);
|
||||||
|
getAssignColumn().setVisible(state, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a list of templates for the given content item in the
|
||||||
|
* given context, along with a link to select a template
|
||||||
|
*/
|
||||||
|
protected class AvailableTemplatesListing extends TemplatesListing {
|
||||||
|
|
||||||
|
TableColumn m_assignCol;
|
||||||
|
SingleSelectionModel m_contextModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new AvailableTemplatesListing
|
||||||
|
*
|
||||||
|
* @param contextModel the SingleSelectionModel that will define the
|
||||||
|
* current use context
|
||||||
|
*/
|
||||||
|
public AvailableTemplatesListing(SingleSelectionModel contextModel) {
|
||||||
|
super();
|
||||||
|
m_contextModel = contextModel;
|
||||||
|
|
||||||
|
// Add the "assign" column and corresponding action listener
|
||||||
|
m_assignCol = addColumn("Assign",
|
||||||
|
TemplateCollection.TEMPLATE, false,
|
||||||
|
new AssignCellRenderer());
|
||||||
|
|
||||||
|
addTableActionListener(new TableActionAdapter() {
|
||||||
|
public void cellSelected(TableActionEvent e) {
|
||||||
|
PageState s = e.getPageState();
|
||||||
|
TemplatesListing l = (TemplatesListing)e.getSource();
|
||||||
|
int i = e.getColumn().intValue();
|
||||||
|
TableColumn c = l.getColumnModel().get(i);
|
||||||
|
|
||||||
|
// Safe to check pointer equality since the column is
|
||||||
|
// created statically
|
||||||
|
if(c == m_assignCol) {
|
||||||
|
SectionTemplateMapping m =
|
||||||
|
(SectionTemplateMapping)getMappingModel().getSelectedObject(s);
|
||||||
|
assignTemplate(s, m.getTemplate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the templates for the given context in the current section
|
||||||
|
*/
|
||||||
|
protected TemplateCollection getTemplateCollection(PageState s) {
|
||||||
|
ContentSection sec = CMS.getContext().getContentSection();
|
||||||
|
|
||||||
|
ContentItem item = m_itemModel.getSelectedItem(s);
|
||||||
|
Assert.exists(item, "item");
|
||||||
|
|
||||||
|
ContentType type = item.getContentType();
|
||||||
|
Assert.exists(type, "content type");
|
||||||
|
|
||||||
|
MimeType mimeType = getMimeType(s);
|
||||||
|
TemplateCollection c =
|
||||||
|
TemplateManagerFactory.getInstance().getTemplates(sec, type);
|
||||||
|
if (mimeType != null) {
|
||||||
|
c.addEqualsFilter(TemplateCollection.TEMPLATE + "." +
|
||||||
|
Template.MIME_TYPE + "." +
|
||||||
|
MimeType.MIME_TYPE, mimeType.getMimeType());
|
||||||
|
}
|
||||||
|
c.addEqualsFilter(TemplateCollection.USE_CONTEXT,
|
||||||
|
getUseContext(s));
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this is a 100% convoluted interdependent mess that
|
||||||
|
// really needs to be reworked
|
||||||
|
/**
|
||||||
|
* Get the currently selected use context
|
||||||
|
*/
|
||||||
|
protected String getUseContext(PageState s) {
|
||||||
|
String c = (String)m_contextModel.getSelectedKey(s);
|
||||||
|
Assert.exists(c, "use context");
|
||||||
|
return ItemTemplatesListing.getUseContextFromKey(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MimeType getMimeType(PageState s) {
|
||||||
|
String key = (String)m_contextModel.getSelectedKey(s);
|
||||||
|
return ItemTemplatesListing.getMimeTypeFromKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign a template to the current item
|
||||||
|
*/
|
||||||
|
public void assignTemplate(PageState s, Template t) {
|
||||||
|
ContentItem item = m_itemModel.getSelectedItem(s);
|
||||||
|
Assert.exists(item, "item");
|
||||||
|
|
||||||
|
TemplateManagerFactory.getInstance()
|
||||||
|
.addTemplate(item, t, getUseContext(s));
|
||||||
|
|
||||||
|
showDisplayPane(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the "assign" link
|
||||||
|
*/
|
||||||
|
protected class AssignCellRenderer implements TableCellRenderer {
|
||||||
|
|
||||||
|
private ControlLink m_link;
|
||||||
|
|
||||||
|
public AssignCellRenderer() {
|
||||||
|
m_link = new ControlLink
|
||||||
|
(new Label(GlobalizationUtil.globalize
|
||||||
|
("cms.ui.templates.assign_this_template")));
|
||||||
|
m_link.setClassAttr("assignTemplateLink");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getComponent(Table table, PageState state, Object value,
|
||||||
|
boolean isSelected, Object key,
|
||||||
|
int row, int column) {
|
||||||
|
return m_link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -40,8 +40,6 @@ import org.libreccm.security.User;
|
||||||
import com.arsdigita.toolbox.ui.ActionGroup;
|
import com.arsdigita.toolbox.ui.ActionGroup;
|
||||||
import com.arsdigita.toolbox.ui.PropertyList;
|
import com.arsdigita.toolbox.ui.PropertyList;
|
||||||
import com.arsdigita.toolbox.ui.Section;
|
import com.arsdigita.toolbox.ui.Section;
|
||||||
import com.arsdigita.util.UncheckedWrapperException;
|
|
||||||
import com.arsdigita.web.Web;
|
|
||||||
|
|
||||||
import org.libreccm.cdi.utils.CdiUtil;
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
import org.libreccm.security.Shiro;
|
import org.libreccm.security.Shiro;
|
||||||
|
|
@ -49,48 +47,45 @@ import org.libreccm.workflow.Task;
|
||||||
import org.libreccm.workflow.TaskManager;
|
import org.libreccm.workflow.TaskManager;
|
||||||
import org.libreccm.workflow.TaskRepository;
|
import org.libreccm.workflow.TaskRepository;
|
||||||
import org.libreccm.workflow.Workflow;
|
import org.libreccm.workflow.Workflow;
|
||||||
import org.libreccm.workflow.WorkflowManager;
|
|
||||||
import org.librecms.CmsConstants;
|
|
||||||
import org.librecms.contentsection.privileges.AdminPrivileges;
|
import org.librecms.contentsection.privileges.AdminPrivileges;
|
||||||
import org.librecms.workflow.CmsTaskType;
|
import org.librecms.workflow.CmsTaskType;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
abstract class BaseWorkflowItemPane extends BaseItemPane {
|
abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
|
|
||||||
final WorkflowRequestLocal m_workflow;
|
final WorkflowRequestLocal workflowRequestLocal;
|
||||||
final TaskRequestLocal m_task;
|
final TaskRequestLocal taskRequestLocal;
|
||||||
|
|
||||||
ActionGroup m_actionGroup;
|
ActionGroup actionGroup;
|
||||||
final TaskTable m_tasks;
|
final TaskTable taskTable;
|
||||||
|
|
||||||
final SimpleContainer m_detailPane;
|
final SimpleContainer detailPane;
|
||||||
final TaskItemPane m_taskPane;
|
final TaskItemPane taskItemPane;
|
||||||
final SummarySection m_summarySection;
|
final SummarySection summarySection;
|
||||||
|
|
||||||
public BaseWorkflowItemPane(final WorkflowRequestLocal workflow,
|
public BaseWorkflowItemPane(final WorkflowRequestLocal workflow,
|
||||||
final ActionLink editLink,
|
final ActionLink editLink,
|
||||||
final ActionLink deleteLink) {
|
final ActionLink deleteLink) {
|
||||||
m_workflow = workflow;
|
workflowRequestLocal = workflow;
|
||||||
|
|
||||||
m_tasks = new TaskTable();
|
taskTable = new TaskTable();
|
||||||
m_task = new TaskSelectionRequestLocal();
|
taskRequestLocal = new TaskSelectionRequestLocal();
|
||||||
|
|
||||||
m_detailPane = new SimpleContainer();
|
detailPane = new SimpleContainer();
|
||||||
|
|
||||||
// Tasks
|
// Tasks
|
||||||
final FinishLink taskFinishLink = new FinishLink();
|
final FinishLink taskFinishLink = new FinishLink();
|
||||||
|
|
||||||
final ActionLink taskAddLink = new ActionLink(new Label(gz(
|
final ActionLink taskAddLink = new ActionLink(new Label(gz(
|
||||||
"cms.ui.workflow.task.add")));
|
"cms.ui.workflow.task.add")));
|
||||||
final TaskAddForm taskAddForm = new TaskAddForm(m_workflow, m_tasks
|
final TaskAddForm taskAddForm = new TaskAddForm(workflowRequestLocal, taskTable
|
||||||
.getRowSelectionModel());
|
.getRowSelectionModel());
|
||||||
|
|
||||||
final ActionLink taskEditLink = new ActionLink(new Label(gz(
|
final ActionLink taskEditLink = new ActionLink(new Label(gz(
|
||||||
"cms.ui.workflow.task.edit")));
|
"cms.ui.workflow.task.edit")));
|
||||||
final TaskEditForm taskEditForm = new TaskEditForm(m_workflow, m_task);
|
final TaskEditForm taskEditForm = new TaskEditForm(workflowRequestLocal, taskRequestLocal);
|
||||||
|
|
||||||
final ActionLink taskDeleteLink = new ActionLink(new Label(gz(
|
final ActionLink taskDeleteLink = new ActionLink(new Label(gz(
|
||||||
"cms.ui.workflow.task.delete")));
|
"cms.ui.workflow.task.delete")));
|
||||||
|
|
@ -100,31 +95,31 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
"cms.ui.workflow.task.return")));
|
"cms.ui.workflow.task.return")));
|
||||||
backLink.addActionListener(new ResetListener());
|
backLink.addActionListener(new ResetListener());
|
||||||
|
|
||||||
m_taskPane = new TaskItemPane(m_workflow, m_task,
|
taskItemPane = new TaskItemPane(workflowRequestLocal, taskRequestLocal,
|
||||||
taskFinishLink, taskEditLink,
|
taskFinishLink, taskEditLink,
|
||||||
taskDeleteLink, backLink);
|
taskDeleteLink, backLink);
|
||||||
|
|
||||||
m_summarySection = new SummarySection(editLink, deleteLink);
|
summarySection = new SummarySection(editLink, deleteLink);
|
||||||
m_detailPane.add(m_summarySection);
|
detailPane.add(summarySection);
|
||||||
m_detailPane.add(new TaskSection(taskAddLink));
|
detailPane.add(new TaskSection(taskAddLink));
|
||||||
|
|
||||||
add(m_detailPane);
|
add(detailPane);
|
||||||
setDefault(m_detailPane);
|
setDefault(detailPane);
|
||||||
add(m_taskPane);
|
add(taskItemPane);
|
||||||
add(taskAddForm);
|
add(taskAddForm);
|
||||||
add(taskEditForm);
|
add(taskEditForm);
|
||||||
add(taskDeleteForm);
|
add(taskDeleteForm);
|
||||||
|
|
||||||
connect(m_tasks, 0, m_taskPane);
|
connect(taskTable, 0, taskItemPane);
|
||||||
|
|
||||||
connect(taskAddLink, taskAddForm);
|
connect(taskAddLink, taskAddForm);
|
||||||
connect(taskAddForm, m_taskPane);
|
connect(taskAddForm, taskItemPane);
|
||||||
|
|
||||||
connect(taskEditLink, taskEditForm);
|
connect(taskEditLink, taskEditForm);
|
||||||
connect(taskEditForm);
|
connect(taskEditForm);
|
||||||
|
|
||||||
connect(taskDeleteLink, taskDeleteForm);
|
connect(taskDeleteLink, taskDeleteForm);
|
||||||
connect(taskDeleteForm, m_detailPane);
|
connect(taskDeleteForm, detailPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class AdminVisible extends VisibilityComponent {
|
protected class AdminVisible extends VisibilityComponent {
|
||||||
|
|
@ -146,7 +141,7 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean isVisible(final PageState state) {
|
public final boolean isVisible(final PageState state) {
|
||||||
final CmsTask task = m_task.getTask(state);
|
final CmsTask task = taskRequestLocal.getTask(state);
|
||||||
final User lockingUser = task.getLockingUser();
|
final User lockingUser = task.getLockingUser();
|
||||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
final Shiro shiro = cdiUtil.findBean(Shiro.class);
|
final Shiro shiro = cdiUtil.findBean(Shiro.class);
|
||||||
|
|
@ -165,7 +160,7 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
final TaskManager taskManager = cdiUtil.findBean(TaskManager.class);
|
final TaskManager taskManager = cdiUtil.findBean(TaskManager.class);
|
||||||
|
|
||||||
final Task task = m_task.getTask(state);
|
final Task task = taskRequestLocal.getTask(state);
|
||||||
taskManager.finish(task);
|
taskManager.finish(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,7 +172,7 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
public void reset(final PageState state) {
|
public void reset(final PageState state) {
|
||||||
super.reset(state);
|
super.reset(state);
|
||||||
|
|
||||||
m_tasks.getRowSelectionModel().clearSelection(state);
|
taskTable.getRowSelectionModel().clearSelection(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TaskDeleteForm extends BaseDeleteForm {
|
private class TaskDeleteForm extends BaseDeleteForm {
|
||||||
|
|
@ -197,10 +192,10 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
final TaskRepository taskRepo = cdiUtil.findBean(
|
final TaskRepository taskRepo = cdiUtil.findBean(
|
||||||
TaskRepository.class);
|
TaskRepository.class);
|
||||||
|
|
||||||
final Task task = m_task.getTask(state);
|
final Task task = taskRequestLocal.getTask(state);
|
||||||
taskRepo.delete(task);
|
taskRepo.delete(task);
|
||||||
|
|
||||||
m_tasks.getRowSelectionModel().clearSelection(state);
|
taskTable.getRowSelectionModel().clearSelection(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +204,7 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final Object initialValue(final PageState state) {
|
protected final Object initialValue(final PageState state) {
|
||||||
final String key = m_tasks.getRowSelectionModel().getSelectedKey(
|
final String key = taskTable.getRowSelectionModel().getSelectedKey(
|
||||||
state).toString();
|
state).toString();
|
||||||
|
|
||||||
return CmsTaskType.valueOf(key);
|
return CmsTaskType.valueOf(key);
|
||||||
|
|
@ -223,13 +218,13 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
final ActionLink deleteLink) {
|
final ActionLink deleteLink) {
|
||||||
setHeading(new Label(gz("cms.ui.workflow.details")));
|
setHeading(new Label(gz("cms.ui.workflow.details")));
|
||||||
|
|
||||||
m_actionGroup = new ActionGroup();
|
actionGroup = new ActionGroup();
|
||||||
setBody(m_actionGroup);
|
setBody(actionGroup);
|
||||||
|
|
||||||
m_actionGroup.setSubject(new Properties());
|
actionGroup.setSubject(new Properties());
|
||||||
m_actionGroup.addAction(new AdminVisible(editLink),
|
actionGroup.addAction(new AdminVisible(editLink),
|
||||||
ActionGroup.EDIT);
|
ActionGroup.EDIT);
|
||||||
m_actionGroup.addAction(new AdminVisible(deleteLink),
|
actionGroup.addAction(new AdminVisible(deleteLink),
|
||||||
ActionGroup.DELETE);
|
ActionGroup.DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,7 +234,7 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
protected final List<Property> properties(final PageState state) {
|
protected final List<Property> properties(final PageState state) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
final List<Property> props = super.properties(state);
|
final List<Property> props = super.properties(state);
|
||||||
final Workflow workflow = (Workflow) m_workflow.get(state);
|
final Workflow workflow = (Workflow) workflowRequestLocal.get(state);
|
||||||
|
|
||||||
final KernelConfig kernelConfig = KernelConfig.getConfig();
|
final KernelConfig kernelConfig = KernelConfig.getConfig();
|
||||||
final Locale defaultLocale = kernelConfig.getDefaultLocale();
|
final Locale defaultLocale = kernelConfig.getDefaultLocale();
|
||||||
|
|
@ -269,7 +264,7 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
final ActionGroup group = new ActionGroup();
|
final ActionGroup group = new ActionGroup();
|
||||||
setBody(group);
|
setBody(group);
|
||||||
|
|
||||||
group.setSubject(m_tasks);
|
group.setSubject(taskTable);
|
||||||
group.addAction(new AdminVisible(taskAddLink), ActionGroup.ADD);
|
group.addAction(new AdminVisible(taskAddLink), ActionGroup.ADD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,7 +281,7 @@ abstract class BaseWorkflowItemPane extends BaseItemPane {
|
||||||
private class TaskTable extends Table {
|
private class TaskTable extends Table {
|
||||||
|
|
||||||
public TaskTable() {
|
public TaskTable() {
|
||||||
super(new TaskTableModelBuilder(m_workflow), s_columns);
|
super(new TaskTableModelBuilder(workflowRequestLocal), s_columns);
|
||||||
|
|
||||||
setEmptyView(new Label(gz("cms.ui.workflow.task.none")));
|
setEmptyView(new Label(gz("cms.ui.workflow.task.none")));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.workflow;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.ActionLink;
|
||||||
|
import com.arsdigita.bebop.Label;
|
||||||
|
import com.arsdigita.bebop.Page;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.ParameterSingleSelectionModel;
|
||||||
|
import com.arsdigita.bebop.event.ActionEvent;
|
||||||
|
import com.arsdigita.bebop.event.ActionListener;
|
||||||
|
import com.arsdigita.bebop.parameters.LongParameter;
|
||||||
|
import com.arsdigita.cms.ui.BaseItemPane;
|
||||||
|
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.libreccm.workflow.WorkflowRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel for applying a workflow template to a content item. By
|
||||||
|
* default this panel display a list of workflows that can be applied
|
||||||
|
* to the content item. If a workflow is applied, it displays the item
|
||||||
|
* details page.
|
||||||
|
*
|
||||||
|
* @author Uday Mathur
|
||||||
|
* @author Michael Pih
|
||||||
|
* @author Justin Ross <jross@redhat.com>
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class ItemWorkflowAdminPane extends BaseItemPane {
|
||||||
|
|
||||||
|
private final ParameterSingleSelectionModel m_model;
|
||||||
|
private final WorkflowRequestLocal m_workflow;
|
||||||
|
|
||||||
|
private final LayoutPanel m_detailPane;
|
||||||
|
private final LayoutPanel m_selectPane;
|
||||||
|
|
||||||
|
public ItemWorkflowAdminPane(final LongParameter itemIdParameter) {
|
||||||
|
m_model = new ItemWorkflowSelectionModel(itemIdParameter);
|
||||||
|
m_workflow = new SelectionRequestLocal();
|
||||||
|
|
||||||
|
final ActionLink editLink = new ActionLink
|
||||||
|
(new Label(gz("cms.ui.workflow.edit")));
|
||||||
|
|
||||||
|
final WorkflowEditForm editForm = new WorkflowEditForm(m_workflow);
|
||||||
|
|
||||||
|
final ActionLink deleteLink = new ActionLink
|
||||||
|
(new Label(gz("cms.ui.workflow.delete")));
|
||||||
|
|
||||||
|
final WorkflowDeleteForm deleteForm = new WorkflowDeleteForm
|
||||||
|
(m_workflow);
|
||||||
|
|
||||||
|
m_detailPane = new LayoutPanel();
|
||||||
|
m_detailPane.setBody(new ItemWorkflowItemPane
|
||||||
|
(m_workflow, editLink, deleteLink));
|
||||||
|
|
||||||
|
final ItemWorkflowSelectForm workflowSelectForm =
|
||||||
|
new ItemWorkflowSelectForm();
|
||||||
|
|
||||||
|
m_selectPane = new LayoutPanel();
|
||||||
|
m_selectPane.setBody(workflowSelectForm);
|
||||||
|
|
||||||
|
add(m_detailPane);
|
||||||
|
setDefault(m_detailPane);
|
||||||
|
add(m_selectPane);
|
||||||
|
add(editForm);
|
||||||
|
add(deleteForm);
|
||||||
|
|
||||||
|
connect(workflowSelectForm, m_detailPane);
|
||||||
|
connect(editLink, editForm);
|
||||||
|
connect(deleteLink, deleteForm);
|
||||||
|
connect(deleteForm, m_selectPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SelectionRequestLocal extends WorkflowRequestLocal {
|
||||||
|
@Override
|
||||||
|
protected final Object initialValue(final PageState state) {
|
||||||
|
final String workflowId = m_model.getSelectedKey(state).toString();
|
||||||
|
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final WorkflowRepository workflowRepo = cdiUtil.findBean(WorkflowRepository.class);
|
||||||
|
return workflowRepo.findById(Long.parseLong(workflowId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void register(final Page page) {
|
||||||
|
super.register(page);
|
||||||
|
|
||||||
|
page.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public final void actionPerformed(final ActionEvent event) {
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
|
if (state.isVisibleOnPage(ItemWorkflowAdminPane.this)
|
||||||
|
&& m_model.getSelectedKey(state) == null) {
|
||||||
|
push(state, m_selectPane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.workflow;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.ActionLink;
|
||||||
|
import com.arsdigita.bebop.Label;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.event.ActionEvent;
|
||||||
|
import com.arsdigita.bebop.event.ActionListener;
|
||||||
|
import com.arsdigita.cms.CMS;
|
||||||
|
import org.librecms.workflow.CmsTask;
|
||||||
|
import com.arsdigita.web.Web;
|
||||||
|
import org.libreccm.workflow.Workflow;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.libreccm.security.PermissionChecker;
|
||||||
|
import org.libreccm.workflow.TaskRepository;
|
||||||
|
import org.libreccm.workflow.WorkflowManager;
|
||||||
|
import org.libreccm.workflow.WorkflowState;
|
||||||
|
import org.librecms.contentsection.ContentSection;
|
||||||
|
import org.librecms.contentsection.privileges.AdminPrivileges;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Justin Ross <jross@redhat.com>
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
final class ItemWorkflowItemPane extends BaseWorkflowItemPane {
|
||||||
|
|
||||||
|
private final AssignedTaskTable assignedTaskTable;
|
||||||
|
|
||||||
|
public ItemWorkflowItemPane(final WorkflowRequestLocal workflowRequestLocal,
|
||||||
|
final ActionLink editLink,
|
||||||
|
final ActionLink deleteLink) {
|
||||||
|
|
||||||
|
super(workflowRequestLocal, editLink, deleteLink);
|
||||||
|
|
||||||
|
actionGroup.addAction(new AdminVisible(new StartLink()));
|
||||||
|
actionGroup.addAction(new AdminVisible(new StopLink()));
|
||||||
|
|
||||||
|
assignedTaskTable = new AssignedTaskTable(workflowRequestLocal);
|
||||||
|
detailPane.add(new AssignedTaskSection(workflowRequestLocal,
|
||||||
|
assignedTaskTable));
|
||||||
|
|
||||||
|
final TaskFinishForm taskFinishForm = new TaskFinishForm(
|
||||||
|
new TaskSelectionRequestLocal());
|
||||||
|
add(taskFinishForm);
|
||||||
|
|
||||||
|
connect(assignedTaskTable, 2, taskFinishForm);
|
||||||
|
connect(taskFinishForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TaskSelectionRequestLocal extends TaskRequestLocal {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object initialValue(final PageState state) {
|
||||||
|
final String taskId = assignedTaskTable.getRowSelectionModel().
|
||||||
|
getSelectedKey(state).toString();
|
||||||
|
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final TaskRepository taskRepo = cdiUtil.findBean(
|
||||||
|
TaskRepository.class);
|
||||||
|
|
||||||
|
return (CmsTask) taskRepo.findById(Long.parseLong(taskId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAdmin(final PageState state) {
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||||
|
PermissionChecker.class);
|
||||||
|
|
||||||
|
final ContentSection section = CMS.getContext().getContentSection();
|
||||||
|
|
||||||
|
return permissionChecker.isPermitted(
|
||||||
|
AdminPrivileges.ADMINISTER_WORKFLOW, section);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StopLink extends ActionLink {
|
||||||
|
|
||||||
|
StopLink() {
|
||||||
|
super(new Label(gz("cms.ui.item.workflow.stop")));
|
||||||
|
|
||||||
|
addActionListener(new Listener());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isVisible(final PageState state) {
|
||||||
|
final Workflow workflow = workflowRequestLocal.getWorkflow(state);
|
||||||
|
|
||||||
|
return workflow.getState() == WorkflowState.STARTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Listener implements ActionListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void actionPerformed(final ActionEvent event) {
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
|
if (hasAdmin(state)) {
|
||||||
|
final Workflow workflow = workflowRequestLocal.getWorkflow(
|
||||||
|
state);
|
||||||
|
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final WorkflowManager workflowManager = cdiUtil.findBean(
|
||||||
|
WorkflowManager.class);
|
||||||
|
workflowManager.stop(workflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StartLink extends ActionLink {
|
||||||
|
|
||||||
|
StartLink() {
|
||||||
|
super(new Label(gz("cms.ui.item.workflow.start")));
|
||||||
|
|
||||||
|
addActionListener(new Listener());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isVisible(final PageState state) {
|
||||||
|
final Workflow workflow = workflowRequestLocal.getWorkflow(state);
|
||||||
|
|
||||||
|
// Start link should be visible if the workflow state is stopped
|
||||||
|
// or init
|
||||||
|
return workflow.getState() == WorkflowState.STOPPED
|
||||||
|
|| workflow.getState() == WorkflowState.INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Listener implements ActionListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void actionPerformed(final ActionEvent event) {
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
|
if (hasAdmin(state)) {
|
||||||
|
final Workflow workflow = workflowRequestLocal.getWorkflow(
|
||||||
|
state);
|
||||||
|
|
||||||
|
final CdiUtil cdiUtil =CdiUtil.createCdiUtil();
|
||||||
|
final WorkflowManager workflowManager = cdiUtil.findBean(
|
||||||
|
WorkflowManager.class);
|
||||||
|
workflowManager.start(workflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.workflow;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.FormProcessException;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.SimpleContainer;
|
||||||
|
import com.arsdigita.bebop.event.FormProcessListener;
|
||||||
|
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||||
|
import com.arsdigita.bebop.form.RadioGroup;
|
||||||
|
import com.arsdigita.bebop.form.Submit;
|
||||||
|
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
||||||
|
import com.arsdigita.bebop.parameters.NotNullValidationListener;
|
||||||
|
import com.arsdigita.cms.CMS;
|
||||||
|
import com.arsdigita.cms.ui.CMSForm;
|
||||||
|
import com.arsdigita.web.Web;
|
||||||
|
import org.libreccm.workflow.Workflow;
|
||||||
|
import org.libreccm.workflow.WorkflowTemplate;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.TooManyListenersException;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.libreccm.workflow.WorkflowManager;
|
||||||
|
import org.libreccm.workflow.WorkflowTemplateRepository;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This panel displays a radio group of available Workflow Templates in this
|
||||||
|
* content section that can be applied to this item.
|
||||||
|
*
|
||||||
|
* @author Uday Mathur
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
class ItemWorkflowSelectForm extends CMSForm {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(
|
||||||
|
ItemWorkflowSelectForm.class);
|
||||||
|
|
||||||
|
private RadioGroup radioGroup;
|
||||||
|
|
||||||
|
public ItemWorkflowSelectForm() {
|
||||||
|
super("applyWorkflow", new SimpleContainer());
|
||||||
|
|
||||||
|
addFormWidgets();
|
||||||
|
addProcessListener(new ProcessListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addFormWidgets() {
|
||||||
|
radioGroup = new RadioGroup(new BigDecimalParameter("workflowSelect"));
|
||||||
|
radioGroup.setClassAttr("vertical");
|
||||||
|
|
||||||
|
try {
|
||||||
|
radioGroup.addPrintListener(new WorkflowsOptionPrintListener());
|
||||||
|
} catch (TooManyListenersException t) {
|
||||||
|
LOGGER.error("Too many listeners", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
radioGroup.addValidationListener(new NotNullValidationListener());
|
||||||
|
add(radioGroup);
|
||||||
|
|
||||||
|
add(new Submit("apply_wf", "Apply Workflow"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a FormProcessListener to that applies a clone of the
|
||||||
|
* WorkflowTemplate to this ContentItem. In case of double-click, no change
|
||||||
|
* is made.
|
||||||
|
*/
|
||||||
|
private class ProcessListener implements FormProcessListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void process(final FormSectionEvent event)
|
||||||
|
throws FormProcessException {
|
||||||
|
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
final Long flowId = (Long) radioGroup.getValue(state);
|
||||||
|
|
||||||
|
final ContentItem item = CMS.getContext().getContentItem();
|
||||||
|
|
||||||
|
if (item.getWorkflow() == null) {
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final WorkflowTemplateRepository templateRepo = cdiUtil.
|
||||||
|
findBean(WorkflowTemplateRepository.class);
|
||||||
|
final WorkflowManager workflowManager = cdiUtil.findBean(
|
||||||
|
WorkflowManager.class);
|
||||||
|
|
||||||
|
final WorkflowTemplate template = templateRepo.findById(flowId);
|
||||||
|
workflowManager.createWorkflow(template, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.workflow;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.ParameterSingleSelectionModel;
|
||||||
|
import com.arsdigita.bebop.parameters.LongParameter;
|
||||||
|
import com.arsdigita.cms.ItemSelectionModel;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contentsection.ContentItemRepository;
|
||||||
|
|
||||||
|
class ItemWorkflowSelectionModel extends ParameterSingleSelectionModel {
|
||||||
|
|
||||||
|
private final ItemSelectionModel itemSelectionModel;
|
||||||
|
|
||||||
|
public ItemWorkflowSelectionModel(final LongParameter itemIdParameter) {
|
||||||
|
super(itemIdParameter);
|
||||||
|
itemSelectionModel = new ItemSelectionModel(itemIdParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemWorkflowSelectionModel(
|
||||||
|
final ItemSelectionModel itemSelectionModel) {
|
||||||
|
super(itemSelectionModel.getStateParameter());
|
||||||
|
this.itemSelectionModel = itemSelectionModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getSelectedKey(final PageState state) {
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final ContentItemRepository itemRepo = cdiUtil.findBean(ContentItemRepository.class);
|
||||||
|
final ContentItem item = itemRepo.findById((Long) super.getSelectedKey(
|
||||||
|
state));
|
||||||
|
|
||||||
|
return item.getWorkflow().getWorkflowId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSelectionModel getItemSelectionModel() {
|
||||||
|
return itemSelectionModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -179,7 +179,6 @@ public final class TaskFinishForm extends CommentAddForm {
|
||||||
final TaskManager taskManager = cdiUtil.findBean(TaskManager.class);
|
final TaskManager taskManager = cdiUtil.findBean(TaskManager.class);
|
||||||
final AssignableTaskManager assignableTaskManager = cdiUtil
|
final AssignableTaskManager assignableTaskManager = cdiUtil
|
||||||
.findBean(AssignableTaskManager.class);
|
.findBean(AssignableTaskManager.class);
|
||||||
final Shiro shiro = cdiUtil.findBean(Shiro.class);
|
|
||||||
final ConfigurationManager confManager = cdiUtil.findBean(
|
final ConfigurationManager confManager = cdiUtil.findBean(
|
||||||
ConfigurationManager.class);
|
ConfigurationManager.class);
|
||||||
final KernelConfig kernelConfig = confManager.findConfiguration(
|
final KernelConfig kernelConfig = confManager.findConfiguration(
|
||||||
|
|
@ -221,7 +220,6 @@ public final class TaskFinishForm extends CommentAddForm {
|
||||||
final TaskFinishFormController controller = cdiUtil.findBean(
|
final TaskFinishFormController controller = cdiUtil.findBean(
|
||||||
TaskFinishFormController.class);
|
TaskFinishFormController.class);
|
||||||
final Workflow workflow = task.getWorkflow();
|
final Workflow workflow = task.getWorkflow();
|
||||||
final User user = shiro.getUser();
|
|
||||||
final List<AssignableTask> tasks = controller.findEnabledTasks(
|
final List<AssignableTask> tasks = controller.findEnabledTasks(
|
||||||
workflow);
|
workflow);
|
||||||
for (final AssignableTask currentTask : tasks) {
|
for (final AssignableTask currentTask : tasks) {
|
||||||
|
|
@ -243,7 +241,7 @@ public final class TaskFinishForm extends CommentAddForm {
|
||||||
throw new RedirectSignal(
|
throw new RedirectSignal(
|
||||||
URL.there(state.getRequest(),
|
URL.there(state.getRequest(),
|
||||||
ContentItemPage.getItemURL(
|
ContentItemPage.getItemURL(
|
||||||
item,
|
item.get(),
|
||||||
ContentItemPage.PUBLISHING_TAB)),
|
ContentItemPage.PUBLISHING_TAB)),
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.workflow;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.FormProcessException;
|
||||||
|
import com.arsdigita.bebop.Label;
|
||||||
|
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||||
|
import com.arsdigita.cms.ui.BaseDeleteForm;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.libreccm.workflow.Workflow;
|
||||||
|
import org.libreccm.workflow.WorkflowRepository;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author Justin Ross <jross@redhat.com>
|
||||||
|
* @version $Id: WorkflowDeleteForm.java 287 2005-02-22 00:29:02Z sskracic $
|
||||||
|
*/
|
||||||
|
|
||||||
|
class WorkflowDeleteForm extends BaseDeleteForm {
|
||||||
|
|
||||||
|
final WorkflowRequestLocal m_workflow;
|
||||||
|
|
||||||
|
WorkflowDeleteForm(final WorkflowRequestLocal workflow) {
|
||||||
|
super(new Label(gz("cms.ui.workflow.delete_prompt")));
|
||||||
|
|
||||||
|
m_workflow = workflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void process(final FormSectionEvent event)
|
||||||
|
throws FormProcessException {
|
||||||
|
|
||||||
|
final Workflow workflow = m_workflow.getWorkflow(event.getPageState());
|
||||||
|
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final WorkflowRepository workflowRepo = cdiUtil.findBean(WorkflowRepository.class);
|
||||||
|
workflowRepo.delete(workflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.cms.ui.workflow;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.event.PrintEvent;
|
||||||
|
import com.arsdigita.bebop.event.PrintListener;
|
||||||
|
import com.arsdigita.bebop.form.Option;
|
||||||
|
import com.arsdigita.bebop.form.OptionGroup;
|
||||||
|
import com.arsdigita.cms.CMS;
|
||||||
|
import com.arsdigita.kernel.KernelConfig;
|
||||||
|
import java.util.List;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.librecms.contentsection.ContentSection;
|
||||||
|
import org.libreccm.workflow.Task;
|
||||||
|
import org.libreccm.workflow.WorkflowTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a list of workflow templates registered to the current content
|
||||||
|
* section.
|
||||||
|
*
|
||||||
|
* @author Uday Mathur (umathur@arsdigita.com)
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class WorkflowsOptionPrintListener implements PrintListener {
|
||||||
|
|
||||||
|
protected List<WorkflowTemplate> getCollection(final PageState state) {
|
||||||
|
final ContentSection section = getContentSection(state);
|
||||||
|
|
||||||
|
return section.getWorkflowTemplates();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ContentSection getContentSection(final PageState state) {
|
||||||
|
return CMS.getContext().getContentSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepare(final PrintEvent event) {
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
|
final OptionGroup target = (OptionGroup) event.getTarget();
|
||||||
|
target.clearOptions();
|
||||||
|
|
||||||
|
final List<WorkflowTemplate> templates = getCollection(state);
|
||||||
|
|
||||||
|
for (final WorkflowTemplate template : templates) {
|
||||||
|
target.addOption(new Option(
|
||||||
|
Long.toString(template.getWorkflowId()),
|
||||||
|
template.getName().getValue(KernelConfig
|
||||||
|
.getConfig()
|
||||||
|
.getDefaultLocale())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -308,7 +308,7 @@ public class ContentItemL10NManager {
|
||||||
*/
|
*/
|
||||||
@AuthorizationRequired
|
@AuthorizationRequired
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public void removeLangauge(
|
public void removeLanguage(
|
||||||
@RequiresPrivilege(ItemPrivileges.EDIT)
|
@RequiresPrivilege(ItemPrivileges.EDIT)
|
||||||
final ContentItem item,
|
final ContentItem item,
|
||||||
final Locale locale) {
|
final Locale locale) {
|
||||||
|
|
@ -330,7 +330,7 @@ public class ContentItemL10NManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
findLocalizedStringProperties(item)
|
findLocalizedStringProperties(item)
|
||||||
.forEach(property -> removeLanguage(item, locale, property));
|
.forEach(property -> ContentItemL10NManager.this.removeLanguage(item, locale, property));
|
||||||
|
|
||||||
itemRepo.save(item);
|
itemRepo.save(item);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ public class ContentItemL10NManagerTest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to remove language from a content item by using
|
* Tries to remove language from a content item by using
|
||||||
* {@link ContentItemL10NManager#removeLangauge(org.librecms.contentsection.ContentItem, java.util.Locale)}.
|
* {@link ContentItemL10NManager#removeLanguage(org.librecms.contentsection.ContentItem, java.util.Locale)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@InSequence(70)
|
@InSequence(70)
|
||||||
|
|
@ -313,12 +313,12 @@ public class ContentItemL10NManagerTest {
|
||||||
final Optional<ContentItem> item = itemRepo.findById(-10100L);
|
final Optional<ContentItem> item = itemRepo.findById(-10100L);
|
||||||
assertThat(item.isPresent(), is(true));
|
assertThat(item.isPresent(), is(true));
|
||||||
|
|
||||||
l10nManager.removeLangauge(item.get(), Locale.FRENCH);
|
l10nManager.removeLanguage(item.get(), Locale.FRENCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that
|
* Verifies that
|
||||||
* {@link ContentItemL10NManager#removeLangauge(org.librecms.contentsection.ContentItem, java.util.Locale)}
|
* {@link ContentItemL10NManager#removeLanguage(org.librecms.contentsection.ContentItem, java.util.Locale)}
|
||||||
* has not effect if called for not present language.
|
* has not effect if called for not present language.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -332,12 +332,12 @@ public class ContentItemL10NManagerTest {
|
||||||
final Optional<ContentItem> item = itemRepo.findById(-10100L);
|
final Optional<ContentItem> item = itemRepo.findById(-10100L);
|
||||||
assertThat(item.isPresent(), is(true));
|
assertThat(item.isPresent(), is(true));
|
||||||
|
|
||||||
l10nManager.removeLangauge(item.get(), Locale.GERMAN);
|
l10nManager.removeLanguage(item.get(), Locale.GERMAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that
|
* Verifies that
|
||||||
* {@link ContentItemL10NManager#removeLangauge(org.librecms.contentsection.ContentItem, java.util.Locale)}
|
* {@link ContentItemL10NManager#removeLanguage(org.librecms.contentsection.ContentItem, java.util.Locale)}
|
||||||
* throws an {@link IllegalArgumentException} if called with {@code null}
|
* throws an {@link IllegalArgumentException} if called with {@code null}
|
||||||
* for the item.
|
* for the item.
|
||||||
*/
|
*/
|
||||||
|
|
@ -352,12 +352,12 @@ public class ContentItemL10NManagerTest {
|
||||||
public void removeLanguageItemIsNull() {
|
public void removeLanguageItemIsNull() {
|
||||||
final ContentItem item = null;
|
final ContentItem item = null;
|
||||||
|
|
||||||
l10nManager.removeLangauge(item, Locale.GERMAN);
|
l10nManager.removeLanguage(item, Locale.GERMAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that
|
* Verifies that
|
||||||
* {@link ContentItemL10NManager#removeLangauge(org.librecms.contentsection.ContentItem, java.util.Locale)}
|
* {@link ContentItemL10NManager#removeLanguage(org.librecms.contentsection.ContentItem, java.util.Locale)}
|
||||||
* throws an {@link IllegalArgumentException} if called with {@code null}
|
* throws an {@link IllegalArgumentException} if called with {@code null}
|
||||||
* for the language.
|
* for the language.
|
||||||
*/
|
*/
|
||||||
|
|
@ -373,7 +373,7 @@ public class ContentItemL10NManagerTest {
|
||||||
final Optional<ContentItem> item = itemRepo.findById(-10100L);
|
final Optional<ContentItem> item = itemRepo.findById(-10100L);
|
||||||
assertThat(item.isPresent(), is(true));
|
assertThat(item.isPresent(), is(true));
|
||||||
|
|
||||||
l10nManager.removeLangauge(item.get(), null);
|
l10nManager.removeLanguage(item.get(), null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,815 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.bebop;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.event.ActionEvent;
|
||||||
|
import com.arsdigita.bebop.event.ChangeEvent;
|
||||||
|
import com.arsdigita.bebop.event.ActionListener;
|
||||||
|
import com.arsdigita.bebop.event.ChangeListener;
|
||||||
|
import com.arsdigita.bebop.event.FormProcessListener;
|
||||||
|
import com.arsdigita.bebop.event.FormSubmissionListener;
|
||||||
|
import com.arsdigita.bebop.list.DefaultListCellRenderer;
|
||||||
|
import com.arsdigita.bebop.list.ListModelBuilder;
|
||||||
|
import com.arsdigita.bebop.list.ListModel;
|
||||||
|
import com.arsdigita.bebop.util.GlobalizationUtil;
|
||||||
|
import com.arsdigita.util.Assert;
|
||||||
|
import com.arsdigita.util.LockableImpl;
|
||||||
|
import com.arsdigita.util.SequentialMap;
|
||||||
|
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||||
|
import com.arsdigita.bebop.form.FormErrorDisplay;
|
||||||
|
import com.arsdigita.bebop.form.Submit;
|
||||||
|
import com.arsdigita.globalization.GlobalizedMessage;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maintains a set of forms that are used when editing the
|
||||||
|
* properties of some object. The component maintains a single
|
||||||
|
* display pane and a list of forms that are selectable by links.
|
||||||
|
* <p>
|
||||||
|
* By default, the component looks something like this:
|
||||||
|
* <blockquote><pre><code>
|
||||||
|
* +----------------+
|
||||||
|
* | |
|
||||||
|
* | Display Pane |
|
||||||
|
* | |
|
||||||
|
* +----------------+
|
||||||
|
* [link to form1]
|
||||||
|
* [link to form2]
|
||||||
|
* [link to form3]
|
||||||
|
* </code></pre></blockquote>
|
||||||
|
*
|
||||||
|
* When the user clicks on a link, the display pane is hidden and the
|
||||||
|
* corresponding form is shown.
|
||||||
|
*
|
||||||
|
* <blockquote><pre><code>
|
||||||
|
* Enter foo: [ ]
|
||||||
|
* Enter bar: [ ]
|
||||||
|
*
|
||||||
|
* [Save] [Cancel]
|
||||||
|
* </code></pre></blockquote>
|
||||||
|
*
|
||||||
|
* When the user clicks the Save or Cancel button on the form, the form
|
||||||
|
* is hidden and the display pane (with its list of links)
|
||||||
|
* is shown once again.
|
||||||
|
* <p>
|
||||||
|
* The simple usage pattern for this class is as follows:
|
||||||
|
*
|
||||||
|
* <blockquote><pre><code>
|
||||||
|
* PropertyEditor editor = new PropertyEditor();
|
||||||
|
* editor.setDisplayComponent(new FooComponent());
|
||||||
|
* NameEditForm n = new NameEditForm();
|
||||||
|
* editor.add("name", "Edit Name", n, n.getCancelButton());
|
||||||
|
* AddressEditForm a = new AddressEditForm();
|
||||||
|
* editor.add("address", "Edit Address", a, a.getCancelButton());
|
||||||
|
* </code></pre></blockquote>
|
||||||
|
*
|
||||||
|
* The <code>PropertyEditor</code> will automatically add the right
|
||||||
|
* listeners to the forms.
|
||||||
|
* <p>
|
||||||
|
* This class is used extensively in the default authoring kit steps,
|
||||||
|
* especially <code>PageEdit</code> and <code>TextPageBody</code> in CMS.
|
||||||
|
* <p>
|
||||||
|
* <b>Advanced Usage</b>:<br>
|
||||||
|
* The <code>PropertyEditor</code> may be used to maintain
|
||||||
|
* visibility of any components, not just forms. The
|
||||||
|
* {@link #addComponent(String, String, Component)} method
|
||||||
|
* can be used to add an arbitrary component to the editor. The
|
||||||
|
* component will be shown in the list of links, along with other components
|
||||||
|
* and/or forms. The component will be shown as usual when the user clicks
|
||||||
|
* on a link. However, you must be sure to include a call to
|
||||||
|
* {@link #showDisplayPane(PageState)} when the component needs to be hidden.
|
||||||
|
* <p>
|
||||||
|
* In addition, it is possible to manually generate {@link ActionLink}s
|
||||||
|
* that will display the right components in the editor. The
|
||||||
|
* {@link #addComponent(String, Component)} method can be used to add
|
||||||
|
* a component to the <code>PropertyEditor</code> without automatically
|
||||||
|
* generating the link for it. The {@link #addVisibilityListener(ActionLink, String)}
|
||||||
|
* method can then be used to add an appropriate {@link ActionListener} to any
|
||||||
|
* {@link ActionLink}. For example:
|
||||||
|
*
|
||||||
|
* <blockquote><pre><code>// Add a form
|
||||||
|
* Form fooForm = new FooForm();
|
||||||
|
* editor.addComponent(FOO_FORM, fooForm);
|
||||||
|
* editor.addListeners(fooForm, fooForm.getCancelButton());
|
||||||
|
* // Create a link that shows the form
|
||||||
|
* fooLink = new ActionLink("Edit the Foo property");
|
||||||
|
* editor.addVisibilityListener(fooLink, FOO_FORM);</code></pre></blockquote>
|
||||||
|
*
|
||||||
|
* Note that the visibility of the form will be handled automatically. There
|
||||||
|
* is no need to show or hide it manually. This approach allows
|
||||||
|
* greater flexibility in placing links on a page. The links may be
|
||||||
|
* part of the editor's display pane, but they do not have to be.
|
||||||
|
* <p>
|
||||||
|
* <b>More-advanced Usage</b>:<br>
|
||||||
|
* The <code>PropertyEditor</code> is backed by a
|
||||||
|
* {@link PropertyEditorModel} through a {@link PropertyEditorModelBuilder}.
|
||||||
|
* Therefore, the <code>PropertyEditor</code> is a model-backed component,
|
||||||
|
* as described in the Bebop tutorials. This means that the list
|
||||||
|
* of properties for the editor could be generated dynamically during
|
||||||
|
* each request. The {@link #setModelBuilder(PropertyEditorModelBuilder)} method
|
||||||
|
* can be used to set a specialized {@link PropertyEditorModelBuilder} for the
|
||||||
|
* editor. In order to write the model builder, you may choose to extend the
|
||||||
|
* protected inner classes {@link PropertyEditor.DefaultModelBuilder} and
|
||||||
|
* {@link PropertyEditor.DefaultModel}. It is also possible to write the model
|
||||||
|
* builder and the corresponding model from scratch. However, most people won't
|
||||||
|
* need to do this.
|
||||||
|
* <p>
|
||||||
|
* For example, <code>SecurityPropertyEditor</code> uses a custom
|
||||||
|
* {@link PropertyEditorModelBuilder} in order to hide the links for properties
|
||||||
|
* which the web user is not allowed to edit.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* @author Stanislav Freidin
|
||||||
|
* @version $Id: PropertyEditor.java 1638 2007-09-17 11:48:34Z chrisg23 $
|
||||||
|
*/
|
||||||
|
public class PropertyEditor extends SimpleContainer {
|
||||||
|
|
||||||
|
private SequentialMap m_forms;
|
||||||
|
private SequentialMap m_labels;
|
||||||
|
private Component m_display;
|
||||||
|
private Container m_displayPane;
|
||||||
|
private List m_list;
|
||||||
|
private PropertyEditorModelBuilder m_builder;
|
||||||
|
private RequestLocal m_model;
|
||||||
|
private java.util.List m_additionalDisplayComponents = new ArrayList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new, empty <code>PropertyEditor</code>.
|
||||||
|
* The {@link #setDisplayComponent(Component)} method must be called before
|
||||||
|
* this component is locked.
|
||||||
|
*/
|
||||||
|
public PropertyEditor() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new <code>PropertyEditor</code> with the given
|
||||||
|
* display component. The pane defaults to a {@link
|
||||||
|
* com.arsdigita.bebop.SimpleContainer}.
|
||||||
|
*
|
||||||
|
* @param display the display component
|
||||||
|
*/
|
||||||
|
public PropertyEditor(Component display) {
|
||||||
|
this(display, new SimpleContainer());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new <code>PropertyEditor</code> with the given
|
||||||
|
* display component and display pane.
|
||||||
|
*
|
||||||
|
* @param display the display component
|
||||||
|
* @param pane the display pane. The caller should pass in a
|
||||||
|
* freshly allocated Container.
|
||||||
|
*/
|
||||||
|
public PropertyEditor(Component display, Container pane) {
|
||||||
|
super();
|
||||||
|
setClassAttr("propertyEditor");
|
||||||
|
m_forms = new SequentialMap();
|
||||||
|
m_labels = new SequentialMap();
|
||||||
|
m_display = null;
|
||||||
|
|
||||||
|
m_displayPane = pane;
|
||||||
|
super.add(m_displayPane);
|
||||||
|
|
||||||
|
m_list = new List();
|
||||||
|
m_list.setCellRenderer(new IdentityCellRenderer());
|
||||||
|
|
||||||
|
// Change listener: reset visibility
|
||||||
|
// Should a ComponentSelectionModel be used here instead ? It's tempting,
|
||||||
|
// but there doesn't seem to be a real need for it
|
||||||
|
m_list.addChangeListener(new ChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void stateChanged(ChangeEvent e) {
|
||||||
|
PageState state = e.getPageState();
|
||||||
|
|
||||||
|
// Get the visible component
|
||||||
|
Component c = null;
|
||||||
|
if ( !m_list.isSelected(state) ) {
|
||||||
|
// Select the display pane
|
||||||
|
c = m_displayPane;
|
||||||
|
} else {
|
||||||
|
c = getComponent(getSelectedComponentKey(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the forms
|
||||||
|
for(Iterator i = m_forms.values().iterator(); i.hasNext(); ) {
|
||||||
|
Component f = (Component)i.next();
|
||||||
|
f.setVisible(state, (f == c));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_displayPane.setVisible(state, (m_displayPane == c));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Don't add the list yet; add it when we add the display
|
||||||
|
// component
|
||||||
|
|
||||||
|
if(display != null)
|
||||||
|
setDisplayComponent(display);
|
||||||
|
|
||||||
|
// Prepare the model builder
|
||||||
|
setModelBuilder(new DefaultModelBuilder());
|
||||||
|
|
||||||
|
m_model = new RequestLocal() {
|
||||||
|
@Override
|
||||||
|
protected Object initialValue(PageState s) {
|
||||||
|
return getModelBuilder().makeModel(PropertyEditor.this, s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the display component visible by default, and the
|
||||||
|
* form(s) invisible by default.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void register(Page p) {
|
||||||
|
Assert.exists(m_display, "display component");
|
||||||
|
|
||||||
|
p.setVisibleDefault(m_displayPane, true);
|
||||||
|
|
||||||
|
for(Iterator i = m_forms.values().iterator(); i.hasNext(); ) {
|
||||||
|
p.setVisibleDefault((Component)i.next(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides the form(s) and shows the display pane.
|
||||||
|
*
|
||||||
|
* @param state the page state
|
||||||
|
*/
|
||||||
|
public void showDisplayPane(PageState state) {
|
||||||
|
m_list.clearSelection(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the component that is identified by the specified key.
|
||||||
|
*
|
||||||
|
* @param state the page state
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
public void showComponent(PageState state, String key) {
|
||||||
|
m_list.setSelectedKey(state, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key of the currently visible component, or null if
|
||||||
|
* the display pane is currently visible.
|
||||||
|
* @param state the page state
|
||||||
|
*
|
||||||
|
* @return the key of the currently visible component, or null if the
|
||||||
|
* display pane is visible.
|
||||||
|
*/
|
||||||
|
public String getSelectedComponentKey(PageState state) {
|
||||||
|
return (String)m_list.getSelectedKey(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add an additional component below the list of links
|
||||||
|
* @param c
|
||||||
|
*/
|
||||||
|
public void addDisplayComponent(Component c) {
|
||||||
|
m_additionalDisplayComponents.add(c);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds the display component if it has not been added already.
|
||||||
|
*
|
||||||
|
* @param c the display component to add
|
||||||
|
*/
|
||||||
|
public void setDisplayComponent(Component c) {
|
||||||
|
if(m_display != null) {
|
||||||
|
throw new IllegalStateException("Display component has already been set");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_displayPane.add(c);
|
||||||
|
m_displayPane.add(m_list);
|
||||||
|
Iterator it = m_additionalDisplayComponents.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
m_displayPane.add((Component)it.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_display = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a component to the property editor. The component will be
|
||||||
|
* completely invisible. It is up to the user to call
|
||||||
|
* {@link #showComponent(PageState, String)} to display the component and to
|
||||||
|
* call {@link #showDisplayPane(PageState)} when the component needs to be hidden.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the component (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param c the component
|
||||||
|
*/
|
||||||
|
public void addComponent(String key, Component c) {
|
||||||
|
m_forms.put(key, c);
|
||||||
|
super.add(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a component to the list of links. It is up to the component to
|
||||||
|
* correctly call {@link #showDisplayPane(PageState)} when it is done.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the component (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link
|
||||||
|
* @param c the component
|
||||||
|
* @deprecated use addComponent(String,GlobalizedMessage,Component) instead
|
||||||
|
*/
|
||||||
|
public void addComponent(String key, String label, Component c) {
|
||||||
|
addComponent(key, c);
|
||||||
|
m_labels.put(key, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a component to the list of links. It is up to the component to
|
||||||
|
* correctly call {@link #showDisplayPane(PageState)} when it is done.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the component (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link
|
||||||
|
* @param c the component
|
||||||
|
*/
|
||||||
|
public void addComponent(String key, GlobalizedMessage label, Component c) {
|
||||||
|
addComponent(key, c);
|
||||||
|
m_labels.put(key, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a form to the set of forms that can be used to edit the
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the form (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link
|
||||||
|
* @param form the form component
|
||||||
|
* @deprecated use add(String,GlobalizedMessage,Form) instead.
|
||||||
|
*/
|
||||||
|
public void add(String key, String label, Form form) {
|
||||||
|
addComponent(key, label, form);
|
||||||
|
addProcessListener(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a form to the set of forms that can be used to edit the
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the form (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link
|
||||||
|
* @param form the form component
|
||||||
|
*/
|
||||||
|
public void add(String key, GlobalizedMessage label, Form form) {
|
||||||
|
addComponent(key, label, form);
|
||||||
|
addProcessListener(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a form to the set of forms that can be used to edit the
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the form (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link
|
||||||
|
* @param form the form component
|
||||||
|
* @param cancelButton the Cancel button on the form
|
||||||
|
* @deprecated use add(String,GlobalizedMessage,Form,Submit) instead.
|
||||||
|
*/
|
||||||
|
public void add(String key, String label, Form form, Submit cancelButton) {
|
||||||
|
add(key, label, form);
|
||||||
|
addListeners(form, cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a form to the set of forms that can be used to edit the
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the form (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link
|
||||||
|
* @param form the form component
|
||||||
|
* @param cancelButton the Cancel button on the form
|
||||||
|
*/
|
||||||
|
public void add(String key, GlobalizedMessage label, Form form, Submit cancelButton) {
|
||||||
|
add(key, label, form);
|
||||||
|
addListeners(form, cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a form to the set of forms that can be used to edit the
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the form (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link
|
||||||
|
* @param formSection the form component
|
||||||
|
*
|
||||||
|
* @pre !(formSection instanceof Form)
|
||||||
|
* @deprecated use add(String,GlobalizedMessage,FormSection) instead.
|
||||||
|
*/
|
||||||
|
public void add(String key, String label, FormSection formSection) {
|
||||||
|
if (formSection instanceof Form) {
|
||||||
|
throw new IllegalArgumentException("formSection is an instance of Form");
|
||||||
|
}
|
||||||
|
Form form = new Form("property" + key);
|
||||||
|
form.add(new FormErrorDisplay(form), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
|
||||||
|
form.add(formSection);
|
||||||
|
form.setMethod(Form.POST);
|
||||||
|
form.setEncType("multipart/form-data");
|
||||||
|
add(key, label , form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a form to the set of forms that can be used to edit the
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the form (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link
|
||||||
|
* @param formSection the form component
|
||||||
|
*
|
||||||
|
* @pre !(formSection instanceof Form)
|
||||||
|
*/
|
||||||
|
public void add(String key, GlobalizedMessage label, FormSection formSection) {
|
||||||
|
if (formSection instanceof Form) {
|
||||||
|
throw new IllegalArgumentException("formSection is an instance of Form");
|
||||||
|
}
|
||||||
|
Form form = new Form("property" + key);
|
||||||
|
form.add(new FormErrorDisplay(form), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
|
||||||
|
form.add(formSection);
|
||||||
|
form.setMethod(Form.POST);
|
||||||
|
form.setEncType("multipart/form-data");
|
||||||
|
add(key, label , form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a form to the set of forms that can be used to edit the properties.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the form (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link
|
||||||
|
* @param formSection the form component
|
||||||
|
* @param cancelButton the Cancel button on the form
|
||||||
|
* @deprecated use add(String,GlobalizedMessage,FormSection,Submit) instead.
|
||||||
|
*/
|
||||||
|
public void add(String key,
|
||||||
|
String label,
|
||||||
|
FormSection formSection,
|
||||||
|
Submit cancelButton) {
|
||||||
|
Form form = new Form("property" + key);
|
||||||
|
form.add(new FormErrorDisplay(form), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
|
||||||
|
form.add(formSection);
|
||||||
|
form.setMethod(Form.POST);
|
||||||
|
form.setEncType("multipart/form-data");
|
||||||
|
add(key, label , form, cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a form to the set of forms that can be used to edit the
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param key the symbolic key for the form (must be unique
|
||||||
|
* for this <code>PropertyEditor</code>)
|
||||||
|
* @param label the label for the link as a GlobalizedMessage
|
||||||
|
* @param formSection the form component
|
||||||
|
* @param cancelButton the Cancel button on the form
|
||||||
|
*/
|
||||||
|
public void add(String key,
|
||||||
|
GlobalizedMessage label,
|
||||||
|
FormSection formSection,
|
||||||
|
Submit cancelButton) {
|
||||||
|
Form form = new Form("property" + key);
|
||||||
|
form.add(new FormErrorDisplay(form), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
|
||||||
|
form.add(formSection);
|
||||||
|
form.setMethod(Form.POST);
|
||||||
|
form.setEncType("multipart/form-data");
|
||||||
|
add(key, label , form, cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the component at the specified key.
|
||||||
|
*
|
||||||
|
* @param key the key of the component to retrieve
|
||||||
|
* @return a component that has been added to this
|
||||||
|
* <code>PropertyEditor</code> at the specified key, or null
|
||||||
|
* if no such component exists.
|
||||||
|
*/
|
||||||
|
public Component getComponent(String key) {
|
||||||
|
return (Component)m_forms.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a submission listener to the form that will hide all components
|
||||||
|
* and show the display pane. This method should be used to add
|
||||||
|
* submission listeners to forms that are buried deep inside some
|
||||||
|
* component and are not members of this <code>PropertyEditor</code>.
|
||||||
|
*
|
||||||
|
* @param form the form
|
||||||
|
* @param cancelButton the Cancel button on the form
|
||||||
|
*/
|
||||||
|
public void addCancelListener(FormSection form, Submit cancelButton) {
|
||||||
|
// Add a different submission listener for each form since the
|
||||||
|
// cancel button may be different
|
||||||
|
final Submit theButton = cancelButton;
|
||||||
|
|
||||||
|
form.addSubmissionListener(new FormSubmissionListener() {
|
||||||
|
@Override
|
||||||
|
public void submitted(FormSectionEvent e) throws FormProcessException {
|
||||||
|
PageState state = e.getPageState();
|
||||||
|
if(theButton.isSelected(state)) {
|
||||||
|
showDisplayPane(state);
|
||||||
|
throw new FormProcessException(
|
||||||
|
"Submission Cancelled",
|
||||||
|
GlobalizationUtil.globalize("bebop.cancel.msg"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a process listener to the form that will hide all components
|
||||||
|
* and show the display pane. This method should be used to add
|
||||||
|
* process listeners to forms that are buried deep inside some
|
||||||
|
* component and are not members of this <code>PropertyEditor</code>.
|
||||||
|
*
|
||||||
|
* @param form the form
|
||||||
|
*/
|
||||||
|
public void addProcessListener(FormSection form) {
|
||||||
|
form.addProcessListener(new FormProcessListener() {
|
||||||
|
@Override
|
||||||
|
public void process(FormSectionEvent e) throws FormProcessException {
|
||||||
|
PageState state = e.getPageState();
|
||||||
|
showDisplayPane(state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds all required listeners to the form to ensure that
|
||||||
|
* if the form is either submitted successfully or cancelled,
|
||||||
|
* the display pane will be shown. This method should be used
|
||||||
|
* to add listeners to forms that are buried deep inside some
|
||||||
|
* component, and are not members of this <code>PropertyEditor</code>.
|
||||||
|
*
|
||||||
|
* @param form the form
|
||||||
|
* @param cancelButton the Cancel button on the form
|
||||||
|
*/
|
||||||
|
public void addListeners(FormSection form, Submit cancelButton) {
|
||||||
|
addCancelListener(form, cancelButton);
|
||||||
|
addProcessListener(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method can be used to add an {@link ActionListener} to any
|
||||||
|
* {@link ActionLink}, causing the action link to show the specified
|
||||||
|
* component when it is clicked. For example, this method may be useful
|
||||||
|
* if the {@link ActionLink} that is supposed to show the component is
|
||||||
|
* buried somewhere deep within the UI.
|
||||||
|
*
|
||||||
|
* @param l the {@link ActionLink}
|
||||||
|
* @param key the key of the component that will be shown when the link
|
||||||
|
* is clicked, as specified in the
|
||||||
|
* {@link #addComponent(String, Component)} method
|
||||||
|
* @see #addComponent(String, Component)
|
||||||
|
*/
|
||||||
|
public void addVisibilityListener(ActionLink l, String key) {
|
||||||
|
final String t_key = key;
|
||||||
|
l.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
showComponent(e.getPageState(), t_key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link List} that contains all the links.
|
||||||
|
* @return the {@link List} that contains all the links.
|
||||||
|
*/
|
||||||
|
public List getList() {
|
||||||
|
return m_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link PropertyEditorModelBuilder} that supplies this
|
||||||
|
* property editor with its {@link PropertyEditorModel} during each
|
||||||
|
* request.
|
||||||
|
*
|
||||||
|
* @return the {@link PropertyEditorModelBuilder} for this component.
|
||||||
|
*/
|
||||||
|
protected final PropertyEditorModelBuilder getModelBuilder() {
|
||||||
|
return m_builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link PropertyEditorModelBuilder} that will supply this
|
||||||
|
* property editor with its {@link PropertyEditorModel} during each
|
||||||
|
* request.
|
||||||
|
* @param b the property editor model builder
|
||||||
|
*/
|
||||||
|
protected final void setModelBuilder(PropertyEditorModelBuilder b) {
|
||||||
|
Assert.isUnlocked(this);
|
||||||
|
m_builder = b;
|
||||||
|
m_list.setModelBuilder(new BuilderAdapter(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link PropertyEditorModel} in use during the current
|
||||||
|
* request.
|
||||||
|
*
|
||||||
|
* @param s represents the current request
|
||||||
|
* @return the {@link PropertyEditorModel} that supplies the properties
|
||||||
|
* for the current request.
|
||||||
|
*/
|
||||||
|
protected final PropertyEditorModel getModel(PageState s) {
|
||||||
|
return (PropertyEditorModel)m_model.get(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the display component.
|
||||||
|
* @return the display component.
|
||||||
|
*/
|
||||||
|
public Component getDisplayComponent() {
|
||||||
|
return m_display;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the display pane (component + list).
|
||||||
|
* @return the display pane (component + list).
|
||||||
|
*/
|
||||||
|
public Container getDisplayPane() {
|
||||||
|
return m_displayPane;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the map of labels.
|
||||||
|
* @return the map of labels.
|
||||||
|
*/
|
||||||
|
protected SequentialMap getLabelsMap() {
|
||||||
|
return m_labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks this component.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void lock() {
|
||||||
|
getModelBuilder().lock();
|
||||||
|
super.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the components generated by the model directly
|
||||||
|
*/
|
||||||
|
protected static class IdentityCellRenderer extends DefaultListCellRenderer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getComponent(List list, PageState state, Object value,
|
||||||
|
String key, int index, boolean isSelected) {
|
||||||
|
return (Component)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of the {@link PropertyEditorModelBuilder}.
|
||||||
|
* Takes in a SequentialMap of key->label, and constructs a ControlLink for each
|
||||||
|
* label.
|
||||||
|
*/
|
||||||
|
protected static class DefaultModelBuilder
|
||||||
|
extends LockableImpl implements PropertyEditorModelBuilder {
|
||||||
|
|
||||||
|
public DefaultModelBuilder() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an iterator of all properties of the specified property
|
||||||
|
* editor. These properties should be passed into the constructor
|
||||||
|
* of the {@link PropertyEditor.DefaultModel}
|
||||||
|
* @param p
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Iterator getProperties(PropertyEditor p) {
|
||||||
|
return p.getLabelsMap().entrySet().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a {@link PropertyEditorModel} for the current
|
||||||
|
* request.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PropertyEditorModel makeModel(PropertyEditor p, PageState s) {
|
||||||
|
return new DefaultModel(getProperties(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class with default implementation of the {@link PropertyEditorModel}.
|
||||||
|
* Takes in an iterator of key->label pairs, and constructs a ControlLink
|
||||||
|
* for each label.
|
||||||
|
*/
|
||||||
|
protected static class DefaultModel implements PropertyEditorModel {
|
||||||
|
|
||||||
|
protected Iterator m_iter;
|
||||||
|
protected Map.Entry m_entry;
|
||||||
|
|
||||||
|
public DefaultModel(Iterator iter) {
|
||||||
|
m_iter = iter;
|
||||||
|
m_entry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean next() {
|
||||||
|
if(!m_iter.hasNext()) {
|
||||||
|
m_entry = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_entry = (Map.Entry)m_iter.next();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actually retrieve action link and label. Will be executed at each
|
||||||
|
* request to ensure proper localization.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Component getComponent() {
|
||||||
|
Assert.exists(m_entry);
|
||||||
|
if ( m_entry.getValue() instanceof GlobalizedMessage ) {
|
||||||
|
ControlLink l = new ControlLink(new
|
||||||
|
Label((GlobalizedMessage)m_entry.getValue()));
|
||||||
|
l.setClassAttr("actionLink");
|
||||||
|
return l;
|
||||||
|
} else {
|
||||||
|
ControlLink l = new ControlLink(new Label((String)m_entry.getValue()));
|
||||||
|
|
||||||
|
l.setClassAttr("actionLink");
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getKey() {
|
||||||
|
Assert.exists(m_entry);
|
||||||
|
return m_entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts a {@link PropertyEditorModelBuilder} to a {@link ListModelBuilder}
|
||||||
|
*/
|
||||||
|
private static final class BuilderAdapter extends LockableImpl
|
||||||
|
implements ListModelBuilder {
|
||||||
|
|
||||||
|
private final PropertyEditor m_parent;
|
||||||
|
|
||||||
|
public BuilderAdapter(PropertyEditor parent) {
|
||||||
|
super();
|
||||||
|
m_parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListModel makeModel(List l, PageState state) {
|
||||||
|
return new ModelAdapter(m_parent.getModel(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts a {@link PropertyEditorModel} to a {@link ListModel}
|
||||||
|
*/
|
||||||
|
private static final class ModelAdapter implements ListModel {
|
||||||
|
|
||||||
|
private final PropertyEditorModel m_model;
|
||||||
|
|
||||||
|
public ModelAdapter(PropertyEditorModel model) {
|
||||||
|
m_model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean next() { return m_model.next(); }
|
||||||
|
@Override
|
||||||
|
public Object getElement() { return m_model.getComponent(); }
|
||||||
|
@Override
|
||||||
|
public String getKey() { return m_model.getKey().toString(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.bebop;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides properties for the {@link PropertyEditor} during
|
||||||
|
* each request. This class is intended for advanced users only.
|
||||||
|
*
|
||||||
|
* @author Stanislav Freidin
|
||||||
|
* @version $Id: PropertyEditorModel.java 287 2005-02-22 00:29:02Z sskracic $
|
||||||
|
* @see PropertyEditorModelBuilder
|
||||||
|
*/
|
||||||
|
public interface PropertyEditorModel {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances to the next property, if possible.
|
||||||
|
*
|
||||||
|
* @return <code>false</code> if there are no more properties;
|
||||||
|
* <code>true</code> otherwise.
|
||||||
|
*/
|
||||||
|
boolean next();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the component that should act as a "button" for editing the
|
||||||
|
* property. Typically, this method returns a {@link ControlLink}
|
||||||
|
* of some sort. When the link is clicked, the {@link PropertyEditor}
|
||||||
|
* will display the pane for editing the property.
|
||||||
|
*
|
||||||
|
* @return a component (usually a {@link ControlLink}) that will act
|
||||||
|
* as the "button" for editing the property.
|
||||||
|
*/
|
||||||
|
Component getComponent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unique key of the current property, usually
|
||||||
|
* a simple String.
|
||||||
|
*
|
||||||
|
* @return the key of the current property.
|
||||||
|
*/
|
||||||
|
Object getKey();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.bebop;
|
||||||
|
|
||||||
|
import com.arsdigita.util.Lockable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a {@link PropertyEditorModel} for the {@link PropertyEditor}
|
||||||
|
* during each request. This class is intended for advanced users only.
|
||||||
|
*
|
||||||
|
* @author Stanislav Freidin
|
||||||
|
* @version $Id: PropertyEditorModelBuilder.java 287 2005-02-22 00:29:02Z sskracic $
|
||||||
|
* @see PropertyEditor
|
||||||
|
*/
|
||||||
|
public interface PropertyEditorModelBuilder extends Lockable {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a {@link PropertyEditorModel} for the current request.
|
||||||
|
* @param p the parent {@link PropertyEditor}
|
||||||
|
* @param s represents the current request
|
||||||
|
* @return the {@link PropertyEditorModel} for the current request.
|
||||||
|
*/
|
||||||
|
PropertyEditorModel makeModel(PropertyEditor p, PageState s);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,7 @@ import com.arsdigita.bebop.PageState;
|
||||||
import com.arsdigita.bebop.parameters.ParameterModel;
|
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||||
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
||||||
import com.arsdigita.bebop.event.ChangeListener;
|
import com.arsdigita.bebop.event.ChangeListener;
|
||||||
|
import com.arsdigita.bebop.parameters.LongParameter;
|
||||||
|
|
||||||
import com.arsdigita.util.Assert;
|
import com.arsdigita.util.Assert;
|
||||||
import com.arsdigita.util.UncheckedWrapperException;
|
import com.arsdigita.util.UncheckedWrapperException;
|
||||||
|
|
@ -40,20 +41,26 @@ import org.libreccm.core.CcmObject;
|
||||||
import org.libreccm.core.CcmObjectRepository;
|
import org.libreccm.core.CcmObjectRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a subclass of an ACSObject from the database.
|
* Loads a subclass of an ACSObject from the database. By default, uses a
|
||||||
* By default, uses a BigDecimal state parameter in order to
|
* <del>BigDecimal</del> {@code Long} state parameter in order to store and
|
||||||
* store and retrieve the item id.
|
* retrieve the item id.
|
||||||
|
*
|
||||||
|
* <strong>
|
||||||
|
* This class has been edited to work with {@link CcmObject} instead of
|
||||||
|
* {@code ACSObject}. Most methods etc. are the the same. This should work as
|
||||||
|
* before. Also variable names etc. have been changed to match the common Java
|
||||||
|
* styles.
|
||||||
|
* </strong>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The <code>getSelectedKey(PageState state)</code> method will return the
|
* The <code>getSelectedKey(PageState state)</code> method will return the
|
||||||
* BigDecimal id of the currently selected object. This method
|
* BigDecimal id of the currently selected object. This method will return the
|
||||||
* will return the id even if the object with this id does not
|
* id even if the object with this id does not actually exist.
|
||||||
* actually exist.
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The <code>getSelectedObject(PageState state)</code> method will return the
|
* The <code>getSelectedObject(PageState state)</code> method will return the
|
||||||
* object whose id is <code>getSelectedKey(PageState state)</code>. If the
|
* object whose id is <code>getSelectedKey(PageState state)</code>. If the
|
||||||
* object does not actually exist, the method will return null
|
* object does not actually exist, the method will return null
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Thus, it is possible to implement the following pattern:
|
* Thus, it is possible to implement the following pattern:
|
||||||
|
|
@ -78,227 +85,225 @@ import org.libreccm.core.CcmObjectRepository;
|
||||||
* }
|
* }
|
||||||
*}</code></pre></blockquote>
|
*}</code></pre></blockquote>
|
||||||
*
|
*
|
||||||
* Naturally, the <code>ACSObjectSelectionModel</code> could also be passed
|
* Naturally, the <code>ACSObjectSelectionModel</code> could also be passed in
|
||||||
* in as a parameter in the <code>MyComponent</code> constructor. In this
|
* as a parameter in the <code>MyComponent</code> constructor. In this case, it
|
||||||
* case, it should be up to the parent of <code>MyComponent</code> to
|
* should be up to the parent of <code>MyComponent</code> to register the
|
||||||
* register the model's state parameter.
|
* model's state parameter.
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Advanced Usage</b>: The <code>ACSObjectSelectionModel</code>
|
* <b>Advanced Usage</b>: The <code>ACSObjectSelectionModel</code> is actually
|
||||||
* is actually just a wrapper for a {@link SingleSelectionModel}
|
* just a wrapper for a {@link SingleSelectionModel} which maintains the
|
||||||
* which maintains the currently selected object's ID as a
|
* currently selected object's ID as a {@link BigDecimal}. By default, a new
|
||||||
* {@link BigDecimal}. By default, a new
|
* {@link ParameterSingleSelectionModel} is wrapped in this way; however, any
|
||||||
* {@link ParameterSingleSelectionModel} is wrapped in this way;
|
* {@link SingleSelectionModel} may be wrapped. Thus, it becomes possible to use
|
||||||
* however, any {@link SingleSelectionModel} may be wrapped.
|
* the <code>ACSObjectSelectionModel</code> even if the currently selected ID is
|
||||||
* Thus, it becomes possible to use the <code>ACSObjectSelectionModel</code>
|
* not stored in a state parameter.
|
||||||
* even if the currently selected ID is not stored in a state parameter.
|
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Persistence Details:</b> The default constructor of
|
* <b>Persistence Details:</b> The default constructor of
|
||||||
* <code>ACSObjectSelectionModel</code> will attempt to use the
|
* <code>ACSObjectSelectionModel</code> will attempt to use the
|
||||||
* {@link DomainObjectFactory} to automatically instantiate the correct Java
|
* {@link DomainObjectFactory} to automatically instantiate the correct Java
|
||||||
* subclass of {@link ACSObject}. However, it is also possible to use an
|
* subclass of {@link ACSObject}. However, it is also possible to use an
|
||||||
* alternate constructor in order to force the <code>ACSObjectSelectionModel</code>
|
* alternate constructor in order to force the
|
||||||
* to manually instantiate the objects:
|
* <code>ACSObjectSelectionModel</code> to manually instantiate the objects:
|
||||||
*
|
*
|
||||||
* <blockquote><pre><code>
|
* <blockquote><pre><code>
|
||||||
* ACSObjectSelectionModel model =
|
* ACSObjectSelectionModel model =
|
||||||
* new ACSObjectSelectionModel("com.arsdigita.cms.Article",
|
* new ACSObjectSelectionModel("com.arsdigita.cms.Article",
|
||||||
* "com.arsdigita.cms.Article", "item_id");
|
* "com.arsdigita.cms.Article", "item_id");
|
||||||
* </code></pre></blockquote>
|
* </code></pre></blockquote>
|
||||||
*
|
*
|
||||||
* In this case, the model will attempt to use reflection to instantiate the
|
* In this case, the model will attempt to use reflection to instantiate the
|
||||||
* correct subclass of <code>ACSObject</code>. In addition, the supplementary
|
* correct subclass of <code>ACSObject</code>. In addition, the supplementary
|
||||||
* constructor makes it possible to create new objects in the database
|
* constructor makes it possible to create new objects in the database using the
|
||||||
* using the {@link #createACSObject(BigDecimal)} method.
|
* {@link #createACSObject(BigDecimal)} method.
|
||||||
*
|
*
|
||||||
* @see com.arsdigita.bebop.SingleSelectionModel
|
* @see com.arsdigita.bebop.SingleSelectionModel
|
||||||
* @see com.arsdigita.bebop.ParameterSingleSelectionModel
|
* @see com.arsdigita.bebop.ParameterSingleSelectionModel
|
||||||
*
|
*
|
||||||
* @author Stanislav Freidin
|
* @author Stanislav Freidin
|
||||||
* @version $Id$
|
* @author Jens Pelzetter
|
||||||
*/
|
*/
|
||||||
public class ACSObjectSelectionModel implements SingleSelectionModel {
|
public class ACSObjectSelectionModel implements SingleSelectionModel {
|
||||||
|
|
||||||
private static final Logger s_log =
|
private RequestLocal loaded;
|
||||||
Logger.getLogger(ACSObjectSelectionModel.class);
|
private Class javaClassName;
|
||||||
|
// private Constructor constructor;
|
||||||
private RequestLocal m_loaded;
|
private String objectType;
|
||||||
private Class m_javaClass;
|
private SingleSelectionModel selectionModel;
|
||||||
private Constructor m_constructor;
|
|
||||||
private String m_objectType;
|
|
||||||
private SingleSelectionModel m_model;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new <code>ACSObjectSelectionModel</code>.
|
* Construct a new <code>ACSObjectSelectionModel</code>. This model will
|
||||||
* This model will produce instances of <code>ACSObject</code>
|
* produce instances of <code>ACSObject</code> by automatically
|
||||||
* by automatically instantiating the correct Java subclass using
|
* instantiating the correct Java subclass using the
|
||||||
* the {@link DomainObjectFactory}.
|
* {@link DomainObjectFactory}.
|
||||||
*
|
*
|
||||||
* @param parameter The state parameter which should be used to store
|
* @param parameter The state parameter which should be used to store the
|
||||||
* the object ID
|
* object ID
|
||||||
*/
|
*/
|
||||||
public ACSObjectSelectionModel(BigDecimalParameter parameter) {
|
public ACSObjectSelectionModel(final LongParameter parameter) {
|
||||||
this(null, null, parameter);
|
this(null, null, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new <code>ACSObjectSelectionModel</code>.
|
* Construct a new <code>ACSObjectSelectionModel</code>. This model will
|
||||||
* This model will produce instances of <code>ACSObject</code>
|
* produce instances of <code>ACSObject</code> by automatically
|
||||||
* by automatically instantiating the correct Java subclass using
|
* instantiating the correct Java subclass using the
|
||||||
* the {@link DomainObjectFactory}.
|
* {@link DomainObjectFactory}.
|
||||||
*
|
*
|
||||||
* @param parameterName The name of the state parameter which will
|
* @param parameterName The name of the state parameter which will be used
|
||||||
* be used to store the object ID.
|
* to store the object ID.
|
||||||
*/
|
*/
|
||||||
public ACSObjectSelectionModel(String parameterName) {
|
public ACSObjectSelectionModel(final String parameterName) {
|
||||||
this(null, null, new BigDecimalParameter(parameterName));
|
this(null, null, new LongParameter(parameterName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new <code>ACSObjectSelectionModel</code>.
|
* Construct a new <code>ACSObjectSelectionModel</code>. This model will
|
||||||
* This model will produce instances of <code>ACSObject</code>
|
* produce instances of <code>ACSObject</code> by automatically
|
||||||
* by automatically instantiating the correct Java subclass using
|
* instantiating the correct Java subclass using the
|
||||||
* the {@link DomainObjectFactory}.
|
* {@link DomainObjectFactory}.
|
||||||
*
|
*
|
||||||
* @param model The {@link SingleSelectionModel} which will supply
|
* @param model The {@link SingleSelectionModel} which will supply a
|
||||||
* a {@link BigDecimal} ID of the currently selected object
|
* {@link BigDecimal} ID of the currently selected object
|
||||||
*/
|
*/
|
||||||
public ACSObjectSelectionModel(SingleSelectionModel model) {
|
public ACSObjectSelectionModel(final SingleSelectionModel model) {
|
||||||
this(null, null, model);
|
this(null, null, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new <code>ACSObjectSelectionModel</code>
|
* Construct a new <code>ACSObjectSelectionModel</code>
|
||||||
*
|
*
|
||||||
* @param javaClass The name of the Java class which represents
|
* @param javaClass The name of the Java class which represents the object.
|
||||||
* the object. Must be a subclass of {@link ACSObject}. In
|
* Must be a subclass of {@link ACSObject}. In addition, the class must have
|
||||||
* addition, the class must have a constructor with a single
|
* a constructor with a single {@link OID} parameter.
|
||||||
* {@link OID} parameter.
|
* @param objectType The name of the persistence metadata object type which
|
||||||
* @param objectType The name of the persistence metadata object type
|
* represents the ACS object. In practice, will often be the same as the
|
||||||
* which represents the ACS object. In practice, will often be
|
* javaClass.
|
||||||
* the same as the javaClass.
|
* @param parameterName The name of the state parameter which will be used
|
||||||
* @param parameterName The name of the state parameter which will
|
* to store the object ID.
|
||||||
* be used to store the object ID.
|
|
||||||
*/
|
*/
|
||||||
public ACSObjectSelectionModel( String javaClass,
|
public ACSObjectSelectionModel(final String javaClass,
|
||||||
String objectType,
|
final String objectType,
|
||||||
String parameterName ) {
|
final String parameterName) {
|
||||||
this(javaClass, objectType, new BigDecimalParameter(parameterName));
|
this(javaClass, objectType, new LongParameter(parameterName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new <code>ACSObjectSelectionModel</code>
|
* Construct a new <code>ACSObjectSelectionModel</code>
|
||||||
*
|
*
|
||||||
* @param javaClass The name of the Java class which represents
|
* @param javaClass The name of the Java class which represents the object.
|
||||||
* the object. Must be a subclass of {@link ACSObject}. In
|
* Must be a subclass of {@link ACSObject}. In addition, the class must have
|
||||||
* addition, the class must have a constructor with a single
|
* a constructor with a single {@link OID} parameter.
|
||||||
* {@link OID} parameter.
|
* @param objectType The name of the persistence metadata object type which
|
||||||
* @param objectType The name of the persistence metadata object type
|
* represents the ACS object. In practice, will often be the same as the
|
||||||
* which represents the ACS object. In practice, will often be
|
* javaClass.
|
||||||
* the same as the javaClass.
|
* @param parameter The state parameter which should be used to store the
|
||||||
* @param parameter The state parameter which should be used to store
|
* object ID
|
||||||
* the object ID
|
|
||||||
*/
|
*/
|
||||||
public ACSObjectSelectionModel( String javaClass,
|
public ACSObjectSelectionModel(final String javaClass,
|
||||||
String objectType,
|
final String objectType,
|
||||||
BigDecimalParameter parameter ) {
|
final LongParameter parameter) {
|
||||||
this(javaClass, objectType,
|
this(javaClass,
|
||||||
|
objectType,
|
||||||
new ParameterSingleSelectionModel(parameter));
|
new ParameterSingleSelectionModel(parameter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new <code>ACSObjectSelectionModel</code>
|
* Construct a new <code>ACSObjectSelectionModel</code>
|
||||||
*
|
*
|
||||||
* @param javaClass The name of the Java class which represents
|
* @param javaClass The name of the Java class which represents the object.
|
||||||
* the object. Must be a subclass of {@link ACSObject}. In
|
* Must be a subclass of {@link ACSObject}. In addition, the class must have
|
||||||
* addition, the class must have a constructor with a single
|
* a constructor with a single {@link OID} parameter.
|
||||||
* {@link OID} parameter.
|
* @param objectType The name of the persistence metadata object type which
|
||||||
* @param objectType The name of the persistence metadata object type
|
* represents the ACS object. In practice, will often be the same as the
|
||||||
* which represents the ACS object. In practice, will often be
|
* javaClass.
|
||||||
* the same as the javaClass.
|
* @param model The {@link SingleSelectionModel} which will supply a
|
||||||
* @param model The {@link SingleSelectionModel} which will supply
|
* {@link BigDecimal} ID of the currently selected object
|
||||||
* a {@link BigDecimal} ID of the currently selected object
|
|
||||||
*/
|
*/
|
||||||
public ACSObjectSelectionModel( String javaClass,
|
public ACSObjectSelectionModel(final String javaClass,
|
||||||
String objectType,
|
final String objectType,
|
||||||
SingleSelectionModel model ) {
|
final SingleSelectionModel model) {
|
||||||
m_loaded = new RequestLocal() {
|
loaded = new RequestLocal() {
|
||||||
protected Object initialValue(PageState state) {
|
@Override
|
||||||
return Boolean.FALSE;
|
protected Object initialValue(final PageState state) {
|
||||||
}
|
return Boolean.FALSE;
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (javaClass != null) {
|
if (javaClass != null) {
|
||||||
// Cache the Class object and the constructor for further use
|
// Cache the Class object and the constructor for further use
|
||||||
try {
|
try {
|
||||||
m_javaClass = Class.forName(javaClass);
|
this.javaClassName = Class.forName(javaClass);
|
||||||
m_constructor = m_javaClass.getConstructor();
|
// this.constructor = javaClassName.getConstructor();
|
||||||
} catch (Exception e) {
|
} catch (ClassNotFoundException | SecurityException ex) {
|
||||||
throw new UncheckedWrapperException( "Problem loading class "
|
throw new UncheckedWrapperException(String.format(
|
||||||
+ javaClass, e );
|
"Problem loading class %s", javaClass),
|
||||||
|
ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_objectType = objectType;
|
this.objectType = objectType;
|
||||||
m_model = model;
|
this.selectionModel = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the ID of the current object. The next time
|
* Set the ID of the current object. The next time
|
||||||
* {@link #getSelectedObject(PageState)} is called, the object
|
* {@link #getSelectedObject(PageState)} is called, the object with the
|
||||||
* with the specified ID will be loaded from the database.
|
* specified ID will be loaded from the database.
|
||||||
*
|
*
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @param key A {@link BigDecimal} primary key for the object,
|
* @param key A {@link BigDecimal} primary key for the object, or a String
|
||||||
* or a String representation of a BigDecimal, such as "42".
|
* representation of a BigDecimal, such as "42".
|
||||||
*/
|
*/
|
||||||
public void setSelectedKey(PageState state, Object key) {
|
@Override
|
||||||
|
public void setSelectedKey(final PageState state, final Object key) {
|
||||||
//BigDecimal newKey = convertToBigDecimal(key);
|
//BigDecimal newKey = convertToBigDecimal(key);
|
||||||
|
|
||||||
m_loaded.set(state, Boolean.FALSE);
|
loaded.set(state, Boolean.FALSE);
|
||||||
m_model.setSelectedKey(state, key);
|
selectionModel.setSelectedKey(state, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the object which was selected and loaded from the database,
|
* Return the object which was selected and loaded from the database, using
|
||||||
* using the values supplied in the page state. May return <code>null</code>
|
* the values supplied in the page state. May return <code>null</code> if
|
||||||
* if <code>isSelected(state) == false</code>, or if the object was not found.
|
* <code>isSelected(state) == false</code>, or if the object was not found.
|
||||||
*
|
*
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @return The currently selected domain object, or null if no object is
|
* @return The currently selected domain object, or null if no object is
|
||||||
* selected.
|
* selected.
|
||||||
*/
|
*/
|
||||||
public CcmObject getSelectedObject(PageState state) {
|
public CcmObject getSelectedObject(final PageState state) {
|
||||||
|
|
||||||
Long id = convertToLong(getSelectedKey(state));
|
Long id = convertToLong(getSelectedKey(state));
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadACSObject(state, id);
|
return loadACSObject(state, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the selected object for the first time. Child classes
|
* Load the selected object for the first time. Child classes may choose to
|
||||||
* may choose to override this method in order to load the object
|
* override this method in order to load the object in nonstandard ways. The
|
||||||
* in nonstandard ways. The default implementation merely
|
* default implementation merely instantiates an {@link ACSObject} whose ID
|
||||||
* instantiates an {@link ACSObject} whose ID is the passed-in key.
|
* is the passed-in key.
|
||||||
*
|
*
|
||||||
* @param state the current page state
|
* @param state the current page state
|
||||||
* @param key the currently selected key; guaranteed to be non-null
|
* @param key the currently selected key; guaranteed to be non-null
|
||||||
* @return the object identified by the specified key
|
* @return the object identified by the specified key
|
||||||
* @pre key != null
|
|
||||||
*/
|
*/
|
||||||
protected CcmObject loadACSObject(PageState state, Object key) {
|
protected CcmObject loadACSObject(final PageState state, final Object key) {
|
||||||
CcmObject item = null;
|
|
||||||
|
|
||||||
// Cheesy back-and-forth conversion to ensure that
|
// Cheesy back-and-forth conversion to ensure that
|
||||||
// the result will be a BigDecimal, not a String or
|
// the result will be a BigDecimal, not a String or
|
||||||
// something else. Should go away when ListModel.getKey is
|
// something else. Should go away when ListModel.getKey is
|
||||||
// changed to return an Object.
|
// changed to return an Object.
|
||||||
Long id = convertToLong(key);
|
final Long objectId = convertToLong(key);
|
||||||
|
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final CcmObjectRepository repository = cdiUtil.findBean(
|
||||||
|
CcmObjectRepository.class);
|
||||||
|
|
||||||
|
return repository.findById(objectId);
|
||||||
|
|
||||||
return CdiUtil.createCdiUtil().findBean(CcmObjectRepository.class).findById(id);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -307,127 +312,121 @@ public class ACSObjectSelectionModel implements SingleSelectionModel {
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @param object The content item to set
|
* @param object The content item to set
|
||||||
*/
|
*/
|
||||||
public void setSelectedObject(PageState state, CcmObject object) {
|
public void setSelectedObject(final PageState state,
|
||||||
|
final CcmObject object) {
|
||||||
CcmObject item = object;
|
CcmObject item = object;
|
||||||
|
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
m_loaded.set(state, Boolean.FALSE);
|
loaded.set(state, Boolean.FALSE);
|
||||||
m_model.setSelectedKey(state, null);
|
selectionModel.setSelectedKey(state, null);
|
||||||
} else {
|
} else {
|
||||||
m_loaded.set(state, Boolean.TRUE);
|
loaded.set(state, Boolean.TRUE);
|
||||||
m_model.setSelectedKey(state, item.getObjectId());
|
selectionModel.setSelectedKey(state, item.getObjectId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the attempt to load the selected object has
|
* Determine if the attempt to load the selected object has been made yet.
|
||||||
* been made yet. Child classes may use this method to
|
* Child classes may use this method to perform request-local
|
||||||
* perform request-local initialization.
|
* initialisation.
|
||||||
*
|
*
|
||||||
* @param state the page state
|
* @param state the page state
|
||||||
* @return true if the attempt to load the selected object has
|
* @return true if the attempt to load the selected object has already been
|
||||||
* already been made, false otherwise
|
* made, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isInitialized(PageState state) {
|
public boolean isInitialized(final PageState state) {
|
||||||
return ((Boolean)m_loaded.get(state)).booleanValue();
|
return ((Boolean) loaded.get(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility function which creates a new object with the given ID.
|
* A utility function which creates a new object with the given ID. Uses
|
||||||
* Uses reflection to create the instance of the class supplied
|
* reflection to create the instance of the class supplied in the
|
||||||
* in the constructor to this <code>ACSObjectSelectionModel</code>.
|
* constructor to this <code>ACSObjectSelectionModel</code>. If no class
|
||||||
* If no classname was supplied in the constructor, an assertion
|
* name was supplied in the constructor, an assertion failure will occur.
|
||||||
* failure will occur.
|
|
||||||
*
|
*
|
||||||
* @param id The id of the new item - this is ignored and the object
|
* @param id The id of the new item - this is ignored and the object will
|
||||||
* will have a different id
|
* have a different id
|
||||||
* @return The newly created item
|
* @return The newly created item
|
||||||
|
* @throws javax.servlet.ServletException
|
||||||
* @post return != null
|
* @post return != null
|
||||||
* @deprecated This ignores the ID since ACSObject.setID is a no-op
|
* @deprecated This ignores the ID since ACSObject.setID is a no-op
|
||||||
*/
|
*/
|
||||||
public CcmObject createACSObject(Long id) throws ServletException {
|
public CcmObject createACSObject(final Long id) throws ServletException {
|
||||||
return createACSObject();
|
return createACSObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility function which creates a new object with the given ID.
|
* A utility function which creates a new object with the given ID. Uses
|
||||||
* Uses reflection to create the instance of the class supplied
|
* reflection to create the instance of the class supplied in the
|
||||||
* in the constructor to this <code>ACSObjectSelectionModel</code>.
|
* constructor to this <code>ACSObjectSelectionModel</code>. If no class
|
||||||
* If no classname was supplied in the constructor, an assertion
|
* name was supplied in the constructor, an assertion failure will occur.
|
||||||
* failure will occur.
|
|
||||||
*
|
*
|
||||||
* @param id The id of the new item
|
|
||||||
* @return The newly created item
|
* @return The newly created item
|
||||||
|
* @throws javax.servlet.ServletException
|
||||||
* @post return != null
|
* @post return != null
|
||||||
*/
|
*/
|
||||||
public CcmObject createACSObject() throws ServletException {
|
public CcmObject createACSObject() throws ServletException {
|
||||||
Assert.exists(m_javaClass, Class.class);
|
Assert.exists(javaClassName, Class.class);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CcmObject item = (CcmObject)m_javaClass.newInstance();
|
final CcmObject object = (CcmObject) javaClassName.newInstance();
|
||||||
return item;
|
return object;
|
||||||
} catch (InstantiationException e) {
|
} catch (InstantiationException | IllegalAccessException ex) {
|
||||||
throw new ServletException(e);
|
throw new ServletException(ex);
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new ServletException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the Class of the content items which are produced
|
* @return the Class of the content items which are produced by this model
|
||||||
* by this model
|
|
||||||
*/
|
*/
|
||||||
public Class getJavaClass() {
|
public Class getJavaClass() {
|
||||||
return m_javaClass;
|
return javaClassName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The name of the object type of the
|
* @return The name of the object type of the content items which are
|
||||||
* content items which are produced by this model
|
* produced by this model
|
||||||
*/
|
*/
|
||||||
public String getObjectType() {
|
public String getObjectType() {
|
||||||
return m_objectType;
|
return objectType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the underlying {@link SingleSelectionModel} which
|
* @return the underlying {@link SingleSelectionModel} which maintains the
|
||||||
* maintains the ID of the selected object
|
* ID of the selected object
|
||||||
*/
|
*/
|
||||||
public SingleSelectionModel getSingleSelectionModel() {
|
public SingleSelectionModel getSingleSelectionModel() {
|
||||||
return m_model;
|
return selectionModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////
|
////////////////////////
|
||||||
//
|
//
|
||||||
// Passthrough methods
|
// Passthrough methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return <code>true</code> if there is a selected object.
|
* Return <code>true</code> if there is a selected object.
|
||||||
*
|
*
|
||||||
* @param state represents the state of the current request
|
* @param state represents the state of the current request
|
||||||
* @return <code>true</code> if there is a selected component.
|
* @return <code>true</code> if there is a selected component.
|
||||||
*/
|
*/
|
||||||
public boolean isSelected(PageState state) {
|
@Override
|
||||||
return m_model.isSelected(state);
|
public boolean isSelected(final PageState state) {
|
||||||
|
return selectionModel.isSelected(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the key that identifies the selected object.
|
* Return the key that identifies the selected object.
|
||||||
*
|
*
|
||||||
* @param state the current page state
|
* @param state the current page state
|
||||||
* @return the {@link BigDecimal} ID of the currently selected
|
* @return the <del>{@link BigDecimal}</del> {@link Long} ID of the
|
||||||
* object, or null if no object is selected.
|
* currently selected object, or null if no object is selected.
|
||||||
* @post return instanceof BigDecimal
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public Object getSelectedKey(PageState state) {
|
@Override
|
||||||
Object key = m_model.getSelectedKey(state);
|
public Object getSelectedKey(final PageState state) {
|
||||||
|
Object key = selectionModel.getSelectedKey(state);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the selection.
|
* Clear the selection.
|
||||||
*
|
*
|
||||||
|
|
@ -435,50 +434,54 @@ public class ACSObjectSelectionModel implements SingleSelectionModel {
|
||||||
* @post ! isSelected(state)
|
* @post ! isSelected(state)
|
||||||
* @post ! isInitialized(state)
|
* @post ! isInitialized(state)
|
||||||
*/
|
*/
|
||||||
public void clearSelection(PageState state) {
|
@Override
|
||||||
m_model.clearSelection(state);
|
public void clearSelection(final PageState state) {
|
||||||
m_loaded.set(state, Boolean.FALSE);
|
selectionModel.clearSelection(state);
|
||||||
|
loaded.set(state, Boolean.FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a change listener to the model. The listener's
|
* Add a change listener to the model. The listener's
|
||||||
* <code>stateChanged</code> is called whenever the selected key changes.
|
* <code>stateChanged</code> is called whenever the selected key changes.
|
||||||
*
|
*
|
||||||
* @param l a listener to notify when the selected key changes
|
* @param listener a listener to notify when the selected key changes
|
||||||
*/
|
*/
|
||||||
public void addChangeListener(ChangeListener l) {
|
@Override
|
||||||
m_model.addChangeListener(l);
|
public void addChangeListener(final ChangeListener listener) {
|
||||||
|
selectionModel.addChangeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a change listener from the model.
|
* Remove a change listener from the model.
|
||||||
*
|
*
|
||||||
* @param l the listener to remove.
|
* @param listener the listener to remove.
|
||||||
*/
|
*/
|
||||||
public void removeChangeListener(ChangeListener l) {
|
@Override
|
||||||
m_model.removeChangeListener(l);
|
public void removeChangeListener(final ChangeListener listener) {
|
||||||
|
selectionModel.removeChangeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the state parameter which will be used to keep track
|
* Return the state parameter which will be used to keep track of the
|
||||||
* of the currently selected key. Most likely, the parameter will
|
* currently selected key. Most likely, the parameter will be a
|
||||||
* be a {@link BigDecimalParameter}.
|
* {@link BigDecimalParameter}.
|
||||||
*
|
*
|
||||||
* @return The state parameter which should be used to keep
|
* @return The state parameter which should be used to keep track of the ID
|
||||||
* track of the ID of the currently selected object, or null
|
* of the currently selected object, or null if the ID is computed in some
|
||||||
* if the ID is computed in some other way
|
* other way
|
||||||
* @see SingleSelectionModel#getStateParameter()
|
* @see SingleSelectionModel#getStateParameter()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public ParameterModel getStateParameter() {
|
public ParameterModel getStateParameter() {
|
||||||
return m_model.getStateParameter();
|
return selectionModel.getStateParameter();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Long convertToLong(Object value) {
|
private static Long convertToLong(final Object value) {
|
||||||
Long newValue = null;
|
Long newValue = null;
|
||||||
|
|
||||||
if ( value instanceof Long ) {
|
if (value instanceof Long) {
|
||||||
newValue = (Long) value;
|
newValue = (Long) value;
|
||||||
} else if ( value != null ) {
|
} else if (value != null) {
|
||||||
newValue = Long.parseLong(value.toString());
|
newValue = Long.parseLong(value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.arsdigita.toolbox.ui;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.Component;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
|
||||||
|
import org.libreccm.security.Party;
|
||||||
|
import org.libreccm.security.PermissionChecker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Wrapper class that registers access checks (actions) to a Bebop
|
||||||
|
* component.</p>
|
||||||
|
*
|
||||||
|
* @author Michael Pih
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class ComponentAccess {
|
||||||
|
|
||||||
|
private Component component;
|
||||||
|
private List<String> accessCheckList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param component The component
|
||||||
|
*/
|
||||||
|
public ComponentAccess(final Component component) {
|
||||||
|
accessCheckList = new ArrayList();
|
||||||
|
this.component = component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param component The component
|
||||||
|
* @param check An access check
|
||||||
|
*/
|
||||||
|
public ComponentAccess(final Component component, final String check) {
|
||||||
|
this(component);
|
||||||
|
accessCheckList.add(check);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an access check to this component.
|
||||||
|
*
|
||||||
|
* @param check The access check
|
||||||
|
*/
|
||||||
|
public void addAccessCheck(final String check) {
|
||||||
|
accessCheckList.add(check);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the access checks.
|
||||||
|
*
|
||||||
|
* @return The list of access checks
|
||||||
|
*/
|
||||||
|
public List<String> getAccessCheckList() {
|
||||||
|
return accessCheckList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the component.
|
||||||
|
*
|
||||||
|
* @return The component
|
||||||
|
*/
|
||||||
|
public Component getComponent() {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do all the access checks registered to the component pass?
|
||||||
|
*
|
||||||
|
* @return true if all the access checks pass, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean canAccess() {
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||||
|
PermissionChecker.class);
|
||||||
|
|
||||||
|
final Optional<Boolean> canAccess = accessCheckList.stream()
|
||||||
|
.map(accessCheck -> permissionChecker.isPermitted(accessCheck))
|
||||||
|
.reduce((result1, result2) -> result1 && result2);
|
||||||
|
|
||||||
|
return canAccess.orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue