CCM NG/ccm-cms: More forms and related classes
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4451 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
a124b1ebd8
commit
e2765a9109
|
|
@ -23,7 +23,7 @@ import com.arsdigita.cms.CMS;
|
||||||
import com.arsdigita.cms.ContentCenter;
|
import com.arsdigita.cms.ContentCenter;
|
||||||
import com.arsdigita.util.Assert;
|
import com.arsdigita.util.Assert;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.libreccm.categorization.Category;
|
import org.libreccm.categorization.Category;
|
||||||
import org.librecms.contentsection.ContentItem;
|
import org.librecms.contentsection.ContentItem;
|
||||||
import org.librecms.contentsection.ContentSection;
|
import org.librecms.contentsection.ContentSection;
|
||||||
|
|
@ -36,11 +36,18 @@ import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.librecms.CmsConstants;
|
||||||
|
import org.librecms.contentsection.ContentItemRepository;
|
||||||
|
import org.librecms.contentsection.ContentItemVersion;
|
||||||
|
import org.librecms.contentsection.Folder;
|
||||||
|
import org.librecms.contentsection.FolderManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves items to URLs and URLs to items for multiple language
|
* Resolves items to URLs and URLs to items for multiple language variants.
|
||||||
* variants.
|
|
||||||
*
|
*
|
||||||
* Created Mon Jan 20 14:30:03 2003.
|
* Created Mon Jan 20 14:30:03 2003.
|
||||||
*
|
*
|
||||||
|
|
@ -50,106 +57,92 @@ import java.util.StringTokenizer;
|
||||||
public class MultilingualItemResolver
|
public class MultilingualItemResolver
|
||||||
extends AbstractItemResolver implements ItemResolver {
|
extends AbstractItemResolver implements ItemResolver {
|
||||||
|
|
||||||
private static final Logger s_log = Logger.getLogger
|
private static final Logger LOGGER = LogManager.getLogger(
|
||||||
(MultilingualItemResolver.class);
|
MultilingualItemResolver.class);
|
||||||
|
|
||||||
private static MasterPage s_masterP = null;
|
private static MasterPage s_masterP = null;
|
||||||
private static final String ADMIN_PREFIX = "admin";
|
private static final String ADMIN_PREFIX = "admin";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The string identifying an item's ID in the query string of a
|
* The string identifying an item's ID in the query string of a URL.
|
||||||
* URL.
|
|
||||||
*/
|
*/
|
||||||
protected static final String ITEM_ID = "item_id";
|
protected static final String ITEM_ID = "item_id";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The separator used in URL query strings; should be either "&"
|
* The separator used in URL query strings; should be either "&" or ";".
|
||||||
* or ";".
|
|
||||||
*/
|
*/
|
||||||
protected static final String SEPARATOR = "&";
|
protected static final String SEPARATOR = "&";
|
||||||
|
|
||||||
public MultilingualItemResolver() {
|
public MultilingualItemResolver() {
|
||||||
s_log.debug("Undergoing creation");
|
LOGGER.debug("Undergoing creation");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a content item based on section, url, and use context.
|
* Returns a content item based on section, url, and use context.
|
||||||
*
|
*
|
||||||
* @param section The current content section
|
* @param section The current content section
|
||||||
* @param url The section-relative URL
|
* @param itemUrl The section-relative URL
|
||||||
* @param context The use context,
|
* @param context The use context, e.g. <code>ContentItem.LIVE</code>,
|
||||||
* e.g. <code>ContentItem.LIVE</code>,
|
* <code>CMSDispatcher.PREVIEW</code> or <code>ContentItem.DRAFT</code>. See {@link
|
||||||
* <code>CMSDispatcher.PREVIEW</code> or
|
|
||||||
* <code>ContentItem.DRAFT</code>. See {@link
|
|
||||||
* #getCurrentContext}.
|
* #getCurrentContext}.
|
||||||
* @return The content item, or null if no such item exists
|
* @return The content item, or null if no such item exists
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ContentItem getItem(final ContentSection section,
|
public ContentItem getItem(final ContentSection section,
|
||||||
String url,
|
final String itemUrl,
|
||||||
final String context) {
|
final String context) {
|
||||||
if (s_log.isDebugEnabled()) {
|
LOGGER.debug("Resolving the item in content section \"{}\" at URL "
|
||||||
s_log.debug("Resolving the item in content section " + section +
|
+ "\"{}\" for context \"{}\"...",
|
||||||
" at URL '" + url + "' for context " + context);
|
section.getLabel(),
|
||||||
}
|
itemUrl,
|
||||||
|
context);
|
||||||
|
|
||||||
Assert.exists(section, "ContentSection section");
|
Assert.exists(section, "ContentSection section");
|
||||||
Assert.exists(url, "String url");
|
Assert.exists(itemUrl, "String url");
|
||||||
Assert.exists(context, "String context");
|
Assert.exists(context, "String context");
|
||||||
|
|
||||||
Category rootFolder = section.getRootDocumentsFolder();
|
final Folder rootFolder = section.getRootDocumentsFolder();
|
||||||
url = stripTemplateFromURL(url);
|
String url = stripTemplateFromURL(itemUrl);
|
||||||
|
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
|
||||||
|
if (rootFolder == null) {
|
||||||
// nothing to do, if root folder is null
|
// nothing to do, if root folder is null
|
||||||
if (rootFolder == null) {
|
LOGGER.debug("The root folder is null; returning no item");
|
||||||
s_log.debug("The root folder is null; returning no item");
|
|
||||||
} else {
|
} else {
|
||||||
if (s_log.isDebugEnabled()) {
|
LOGGER.debug("Using root folder {}...",
|
||||||
s_log.debug("Using root folder " + rootFolder);
|
Objects.toString(rootFolder));
|
||||||
}
|
|
||||||
|
|
||||||
if ("live".equals(context)) {
|
if (ContentItemVersion.LIVE.toString().equals(context)) {
|
||||||
s_log.debug("The use context is 'live'");
|
LOGGER.debug("The use context is 'live'");
|
||||||
|
|
||||||
// We allow for returning null, so the root folder may
|
LOGGER.debug("The root folder has a live version; recursing");
|
||||||
// not be live.
|
|
||||||
//Assert.isTrue(rootFolder.isLive(),
|
|
||||||
// "live context - root folder of secion must be live");
|
|
||||||
|
|
||||||
// If the context is 'live', we need the live item.
|
final FolderManager folderManager = cdiUtil.findBean(
|
||||||
|
FolderManager.class);
|
||||||
rootFolder = (Folder) rootFolder.getLiveVersion();
|
final String prefix = String.join(
|
||||||
|
"",
|
||||||
if (rootFolder == null) {
|
section.getPrimaryUrl(),
|
||||||
s_log.debug("The live version of the root folder is " +
|
folderManager.getFolderPath(rootFolder));
|
||||||
"null; returning no item");
|
|
||||||
} else {
|
|
||||||
s_log.debug("The root folder has a live version; " +
|
|
||||||
"recursing");
|
|
||||||
|
|
||||||
final String prefix =
|
|
||||||
section.getURL() + rootFolder.getPath();
|
|
||||||
|
|
||||||
if (url.startsWith(prefix)) {
|
if (url.startsWith(prefix)) {
|
||||||
if (s_log.isDebugEnabled()) {
|
LOGGER.
|
||||||
s_log.debug("The URL starts with prefix '" +
|
debug("The starts with prefix \"{}\"; removing it...",
|
||||||
prefix + "'; removing it");
|
prefix);
|
||||||
}
|
|
||||||
|
|
||||||
url = url.substring(prefix.length());
|
url = url.substring(prefix.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
final ContentItem item = getItemFromLiveURL(url, rootFolder);
|
final ContentItem item = getItemFromLiveURL(url, rootFolder);
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
LOGGER.debug("Resolved URL \"{}\" to item {}...",
|
||||||
s_log.debug("Resolved URL '" + url + "' to item " +
|
url,
|
||||||
item);
|
Objects.toString(item));
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
|
||||||
} else if (ContentItem.DRAFT.equals(context)) {
|
} else if (ContentItemVersion.DRAFT.toString().equals(context)) {
|
||||||
s_log.debug("The use context is 'draft'");
|
LOGGER.debug("The use context is 'draft'");
|
||||||
|
|
||||||
// For 'draft' items, 'generateUrl()' method returns
|
// For 'draft' items, 'generateUrl()' method returns
|
||||||
// URL like this
|
// URL like this
|
||||||
|
|
@ -158,48 +151,46 @@ public class MultilingualItemResolver
|
||||||
// 'item_id', then try to instanciate item_id value
|
// 'item_id', then try to instanciate item_id value
|
||||||
// and return FIXME: Please hack this if there is
|
// and return FIXME: Please hack this if there is
|
||||||
// more graceful solution. [aavetyan]
|
// more graceful solution. [aavetyan]
|
||||||
|
|
||||||
if (Assert.isEnabled()) {
|
if (Assert.isEnabled()) {
|
||||||
Assert.isTrue
|
Assert.isTrue(url.contains(ITEM_ID),
|
||||||
(url.indexOf(ITEM_ID) >= 0,
|
String.format("url must contain parameter %s",
|
||||||
"url must contain parameter " + ITEM_ID);
|
ITEM_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
final ContentItem item = getItemFromDraftURL(url);
|
final ContentItem item = getItemFromDraftURL(url);
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
LOGGER.debug("Resolved URL \"{}\" to item {}.",
|
||||||
s_log.debug("Resolved URL '" + url + "' to item " + item);
|
url,
|
||||||
}
|
Objects.toString(item));
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
} else if (CMSDispatcher.PREVIEW.equals(context)) {
|
} else if (CMSDispatcher.PREVIEW.equals(context)) {
|
||||||
s_log.debug("The use context is 'preview'");
|
LOGGER.debug("The use context is 'preview'");
|
||||||
|
|
||||||
final String prefix = CMSDispatcher.PREVIEW + "/";
|
final String prefix = CMSDispatcher.PREVIEW + "/";
|
||||||
|
|
||||||
if (url.startsWith(prefix)) {
|
if (url.startsWith(prefix)) {
|
||||||
if (s_log.isDebugEnabled()) {
|
LOGGER.debug(
|
||||||
s_log.debug("The URL starts with prefix '" +
|
"The URL starts with prefix \"{}\"; removing it",
|
||||||
prefix + "'; removing it");
|
prefix);
|
||||||
}
|
|
||||||
|
|
||||||
url = url.substring(prefix.length());
|
url = url.substring(prefix.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
final ContentItem item = getItemFromLiveURL(url, rootFolder);
|
final ContentItem item = getItemFromLiveURL(url, rootFolder);
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
LOGGER.debug("Resolved URL \"{}\" to item {}.",
|
||||||
s_log.debug("Resolved URL '" + url + "' to item " + item);
|
url,
|
||||||
}
|
Objects.toString(item));
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException
|
throw new IllegalArgumentException(String.format(
|
||||||
("Invalid item resolver context " + context);
|
"Invalid item resolver context \"%s\".", context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_log.debug("No item resolved; returning null");
|
LOGGER.debug("No item resolved; returning null");
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -212,23 +203,23 @@ public class MultilingualItemResolver
|
||||||
* <code>ContentItem.LIVE</code> or <code>ContentItem.DRAFT</code>
|
* <code>ContentItem.LIVE</code> or <code>ContentItem.DRAFT</code>
|
||||||
* @see ContentItem#LIVE
|
* @see ContentItem#LIVE
|
||||||
* @see ContentItem#DRAFT
|
* @see ContentItem#DRAFT
|
||||||
|
*
|
||||||
|
* ToDo: Refactor to use the {@link ContentItemVersion} directly.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getCurrentContext(final PageState state) {
|
public String getCurrentContext(final PageState state) {
|
||||||
s_log.debug("Getting the current context");
|
LOGGER.debug("Getting the current context");
|
||||||
|
|
||||||
// XXX need to use Web.getWebContext().getRequestURL() here.
|
// XXX need to use Web.getWebContext().getRequestURL() here.
|
||||||
String url = state.getRequest().getRequestURI();
|
String url = state.getRequest().getRequestURI();
|
||||||
|
|
||||||
final ContentSection section =
|
final ContentSection section = CMS.getContext().getContentSection();
|
||||||
CMS.getContext().getContentSection();
|
|
||||||
|
|
||||||
// If this page is associated with a content section,
|
// If this page is associated with a content section,
|
||||||
// transform the URL so that it is relative to the content
|
// transform the URL so that it is relative to the content
|
||||||
// section site node.
|
// section site node.
|
||||||
|
|
||||||
if (section != null) {
|
if (section != null) {
|
||||||
final String sectionURL = section.getURL();
|
final String sectionURL = section.getPrimaryUrl();
|
||||||
|
|
||||||
if (url.startsWith(sectionURL)) {
|
if (url.startsWith(sectionURL)) {
|
||||||
url = url.substring(sectionURL.length());
|
url = url.substring(sectionURL.length());
|
||||||
|
|
@ -238,15 +229,14 @@ public class MultilingualItemResolver
|
||||||
// Remove any template-specific URL components (will only work
|
// Remove any template-specific URL components (will only work
|
||||||
// if they're first in the URL at this point; verify). XXX but
|
// if they're first in the URL at this point; verify). XXX but
|
||||||
// we don't actually verify?
|
// we don't actually verify?
|
||||||
|
|
||||||
url = stripTemplateFromURL(url);
|
url = stripTemplateFromURL(url);
|
||||||
|
|
||||||
// Determine if we are under the admin UI.
|
// Determine if we are under the admin UI.
|
||||||
|
if (url.startsWith(ADMIN_PREFIX)
|
||||||
if (url.startsWith(ADMIN_PREFIX) || url.startsWith(ContentCenter.getURL())) {
|
|| url.startsWith(CmsConstants.CONTENT_CENTER_URL)) {
|
||||||
return ContentItem.DRAFT;
|
return ContentItemVersion.DRAFT.toString();
|
||||||
} else {
|
} else {
|
||||||
return ContentItem.LIVE;
|
return ContentItemVersion.LIVE.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,8 +247,7 @@ public class MultilingualItemResolver
|
||||||
* @param name The name of the content page
|
* @param name The name of the content page
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @param section the content section to which the item belongs
|
* @param section the content section to which the item belongs
|
||||||
* @param context the context of the URL, such as "live" or
|
* @param context the context of the URL, such as "live" or "admin"
|
||||||
* "admin"
|
|
||||||
* @return The URL of the item
|
* @return The URL of the item
|
||||||
* @see #getCurrentContext
|
* @see #getCurrentContext
|
||||||
*/
|
*/
|
||||||
|
|
@ -278,10 +267,8 @@ public class MultilingualItemResolver
|
||||||
* @param name The name of the content page
|
* @param name The name of the content page
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @param section the content section to which the item belongs
|
* @param section the content section to which the item belongs
|
||||||
* @param context the context of the URL, such as "live" or
|
* @param context the context of the URL, such as "live" or "admin"
|
||||||
* "admin"
|
* @param templateContext the context for the URL, such as "public"
|
||||||
* @param templateContext the context for the URL, such as
|
|
||||||
* "public"
|
|
||||||
* @return The URL of the item
|
* @return The URL of the item
|
||||||
* @see #getCurrentContext
|
* @see #getCurrentContext
|
||||||
*/
|
*/
|
||||||
|
|
@ -292,17 +279,21 @@ public class MultilingualItemResolver
|
||||||
final ContentSection section,
|
final ContentSection section,
|
||||||
final String context,
|
final String context,
|
||||||
final String templateContext) {
|
final String templateContext) {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Generating an item URL for item id " + itemId +
|
LOGGER.debug("Generating an item URL for item id " + itemId
|
||||||
", section " + section + ", and context '" +
|
+ ", section " + section + ", and context '"
|
||||||
context + "' with name '" + name + "'");
|
+ context
|
||||||
|
+ "' with name '" + name + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.exists(itemId, "BigDecimal itemId");
|
Assert.exists(itemId, "BigDecimal itemId");
|
||||||
Assert.exists(context, "String context");
|
Assert.exists(context, "String context");
|
||||||
Assert.exists(section, "ContentSection section");
|
Assert.exists(section, "ContentSection section");
|
||||||
|
|
||||||
if (ContentItem.DRAFT.equals(context)) {
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final ContentItemRepository itemRepo = cdiUtil.findBean(ContentItemRepository.class);
|
||||||
|
|
||||||
|
if (ContentItemVersion.DRAFT.toString().equals(context)) {
|
||||||
// No template context here.
|
// No template context here.
|
||||||
return generateDraftURL(section, itemId);
|
return generateDraftURL(section, itemId);
|
||||||
} else if (CMSDispatcher.PREVIEW.equals(context)) {
|
} else if (CMSDispatcher.PREVIEW.equals(context)) {
|
||||||
|
|
@ -315,14 +306,14 @@ public class MultilingualItemResolver
|
||||||
if (Assert.isEnabled()) {
|
if (Assert.isEnabled()) {
|
||||||
Assert.exists(item, "item");
|
Assert.exists(item, "item");
|
||||||
Assert.isTrue(ContentItem.LIVE.equals(item.getVersion()),
|
Assert.isTrue(ContentItem.LIVE.equals(item.getVersion()),
|
||||||
"Generating " + ContentItem.LIVE + " " +
|
"Generating " + ContentItem.LIVE + " "
|
||||||
"URL; this item must be the live version");
|
+ "URL; this item must be the live version");
|
||||||
}
|
}
|
||||||
|
|
||||||
return generateLiveURL(section, item, templateContext);
|
return generateLiveURL(section, item, templateContext);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException
|
throw new IllegalArgumentException("Unknown context '" + context
|
||||||
("Unknown context '" + context + "'");
|
+ "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,8 +323,7 @@ public class MultilingualItemResolver
|
||||||
* @param item The item
|
* @param item The item
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @param section the content section to which the item belongs
|
* @param section the content section to which the item belongs
|
||||||
* @param context the context of the URL, such as "live" or
|
* @param context the context of the URL, such as "live" or "admin"
|
||||||
* "admin"
|
|
||||||
* @return The URL of the item
|
* @return The URL of the item
|
||||||
* @see #getCurrentContext
|
* @see #getCurrentContext
|
||||||
*/
|
*/
|
||||||
|
|
@ -351,10 +341,8 @@ public class MultilingualItemResolver
|
||||||
* @param item The item
|
* @param item The item
|
||||||
* @param state The page state
|
* @param state The page state
|
||||||
* @param section the content section to which the item belongs
|
* @param section the content section to which the item belongs
|
||||||
* @param context the context of the URL, such as "live" or
|
* @param context the context of the URL, such as "live" or "admin"
|
||||||
* "admin"
|
* @param templateContext the context for the URL, such as "public"
|
||||||
* @param templateContext the context for the URL, such as
|
|
||||||
* "public"
|
|
||||||
* @return The URL of the item
|
* @return The URL of the item
|
||||||
* @see #getCurrentContext
|
* @see #getCurrentContext
|
||||||
*/
|
*/
|
||||||
|
|
@ -364,10 +352,10 @@ public class MultilingualItemResolver
|
||||||
ContentSection section,
|
ContentSection section,
|
||||||
final String context,
|
final String context,
|
||||||
final String templateContext) {
|
final String templateContext) {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Generating an item URL for item " + item +
|
LOGGER.debug("Generating an item URL for item " + item
|
||||||
", section " + section + ", and context " +
|
+ ", section "
|
||||||
context);
|
+ section + ", and context " + context);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.exists(item, "ContentItem item");
|
Assert.exists(item, "ContentItem item");
|
||||||
|
|
@ -380,8 +368,8 @@ public class MultilingualItemResolver
|
||||||
if (ContentItem.DRAFT.equals(context)) {
|
if (ContentItem.DRAFT.equals(context)) {
|
||||||
if (Assert.isEnabled()) {
|
if (Assert.isEnabled()) {
|
||||||
Assert.isTrue(ContentItem.DRAFT.equals(item.getVersion()),
|
Assert.isTrue(ContentItem.DRAFT.equals(item.getVersion()),
|
||||||
"Generating " + ContentItem.DRAFT +
|
"Generating " + ContentItem.DRAFT
|
||||||
" url: item must be draft version");
|
+ " url: item must be draft version");
|
||||||
}
|
}
|
||||||
|
|
||||||
return generateDraftURL(section, item.getID());
|
return generateDraftURL(section, item.getID());
|
||||||
|
|
@ -390,8 +378,8 @@ public class MultilingualItemResolver
|
||||||
} else if (ContentItem.LIVE.equals(context)) {
|
} else if (ContentItem.LIVE.equals(context)) {
|
||||||
if (Assert.isEnabled()) {
|
if (Assert.isEnabled()) {
|
||||||
Assert.isTrue(ContentItem.LIVE.equals(item.getVersion()),
|
Assert.isTrue(ContentItem.LIVE.equals(item.getVersion()),
|
||||||
"Generating " + ContentItem.LIVE +
|
"Generating " + ContentItem.LIVE
|
||||||
" url: item must be live version");
|
+ " url: item must be live version");
|
||||||
}
|
}
|
||||||
|
|
||||||
return generateLiveURL(section, item, templateContext);
|
return generateLiveURL(section, item, templateContext);
|
||||||
|
|
@ -401,8 +389,7 @@ public class MultilingualItemResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a master page based on page state (and content
|
* Returns a master page based on page state (and content section).
|
||||||
* section).
|
|
||||||
*
|
*
|
||||||
* @param item The content item
|
* @param item The content item
|
||||||
* @param request The HTTP request
|
* @param request The HTTP request
|
||||||
|
|
@ -413,8 +400,8 @@ public class MultilingualItemResolver
|
||||||
public CMSPage getMasterPage(final ContentItem item,
|
public CMSPage getMasterPage(final ContentItem item,
|
||||||
final HttpServletRequest request)
|
final HttpServletRequest request)
|
||||||
throws ServletException {
|
throws ServletException {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Getting the master page for item " + item);
|
LOGGER.debug("Getting the master page for item " + item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// taken from SimpleItemResolver
|
// taken from SimpleItemResolver
|
||||||
|
|
@ -423,8 +410,8 @@ public class MultilingualItemResolver
|
||||||
s_masterP.init();
|
s_masterP.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Returning master page " + s_masterP);
|
LOGGER.debug("Returning master page " + s_masterP);
|
||||||
}
|
}
|
||||||
|
|
||||||
return s_masterP;
|
return s_masterP;
|
||||||
|
|
@ -439,50 +426,51 @@ public class MultilingualItemResolver
|
||||||
*/
|
*/
|
||||||
protected String generateDraftURL(final ContentSection section,
|
protected String generateDraftURL(final ContentSection section,
|
||||||
final BigDecimal itemId) {
|
final BigDecimal itemId) {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Generating draft URL for item ID " + itemId +
|
LOGGER.debug("Generating draft URL for item ID " + itemId
|
||||||
" and section " + section);
|
+ " and section " + section);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Assert.isEnabled()) {
|
if (Assert.isEnabled()) {
|
||||||
Assert.isTrue(section != null && itemId != null,
|
Assert.isTrue(section != null && itemId != null,
|
||||||
"get draft url: neither secion nor item " +
|
"get draft url: neither secion nor item "
|
||||||
"can be null");
|
+ "can be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
final String url = ContentItemPage.getItemURL
|
final String url = ContentItemPage.getItemURL(section.getPath() + "/",
|
||||||
(section.getPath() + "/", itemId, ContentItemPage.AUTHORING_TAB);
|
itemId,
|
||||||
|
ContentItemPage.AUTHORING_TAB);
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Generated draft URL " + url);
|
LOGGER.debug("Generated draft URL " + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a <em>language-independent</em> URL to the
|
* Generate a <em>language-independent</em> URL to the <code>item</code> in
|
||||||
* <code>item</code> in the given section.<p> When a client
|
* the given section.<p>
|
||||||
* retrieves this URL, the URL is resolved to point to a specific
|
* When a client retrieves this URL, the URL is resolved to point to a
|
||||||
* language instance of the item referenced here, i.e. this URL
|
* specific language instance of the item referenced here, i.e. this URL
|
||||||
* will be resolved to a <em>language-specific</em> URL
|
* will be resolved to a <em>language-specific</em> URL internally.
|
||||||
* internally.
|
|
||||||
*
|
*
|
||||||
* @param section the <code>ContentSection</code> that contains this item
|
* @param section the <code>ContentSection</code> that contains this item
|
||||||
* @param item <code>ContentItem</code> for which a URL should be
|
* @param item <code>ContentItem</code> for which a URL should be
|
||||||
* constructed.
|
* constructed.
|
||||||
* @param templateContext template context; will be ignored if <code>null</code>
|
* @param templateContext template context; will be ignored if
|
||||||
|
* <code>null</code>
|
||||||
*
|
*
|
||||||
* @return a <em>language-independent</em> URL to the
|
* @return a <em>language-independent</em> URL to the <code>item</code> in
|
||||||
* <code>item</code> in the given <code>section</code>, which will
|
* the given <code>section</code>, which will be presented within the given
|
||||||
* be presented within the given <code>templateContext</code>
|
* <code>templateContext</code>
|
||||||
*/
|
*/
|
||||||
protected String generateLiveURL(final ContentSection section,
|
protected String generateLiveURL(final ContentSection section,
|
||||||
final ContentItem item,
|
final ContentItem item,
|
||||||
final String templateContext) {
|
final String templateContext) {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Generating live URL for item " + item + " in " +
|
LOGGER.debug("Generating live URL for item " + item + " in "
|
||||||
"section " + section);
|
+ "section " + section);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -499,7 +487,8 @@ public class MultilingualItemResolver
|
||||||
// This is breaking URL's...not sure why it's here. XXX
|
// This is breaking URL's...not sure why it's here. XXX
|
||||||
// this should work with the appropriate logic. trying again.
|
// this should work with the appropriate logic. trying again.
|
||||||
if (!(templateContext == null || templateContext.length() == 0)) {
|
if (!(templateContext == null || templateContext.length() == 0)) {
|
||||||
url.append(TEMPLATE_CONTEXT_PREFIX).append(templateContext).append("/");
|
url.append(TEMPLATE_CONTEXT_PREFIX).append(templateContext).append(
|
||||||
|
"/");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to retrieve the bundle.
|
// Try to retrieve the bundle.
|
||||||
|
|
@ -514,23 +503,22 @@ public class MultilingualItemResolver
|
||||||
* ContentItem.
|
* ContentItem.
|
||||||
*/
|
*/
|
||||||
if (bundle != null && bundle instanceof ContentBundle) {
|
if (bundle != null && bundle instanceof ContentBundle) {
|
||||||
s_log.debug("Found a bundle; building its file name");
|
LOGGER.debug("Found a bundle; building its file name");
|
||||||
|
|
||||||
final String fname = bundle.getPath();
|
final String fname = bundle.getPath();
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Appending the bundle's file name '" +
|
LOGGER.debug("Appending the bundle's file name '" + fname + "'");
|
||||||
fname + "'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
url.append(fname);
|
url.append(fname);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
s_log.debug("No bundle found; using the item's path directly");
|
LOGGER.debug("No bundle found; using the item's path directly");
|
||||||
|
|
||||||
url.append(item.getPath());
|
url.append(item.getPath());
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* This will append the language to the url, which will in turn render
|
* This will append the language to the url, which will in turn render
|
||||||
* the language negotiation inoperative
|
* the language negotiation inoperative
|
||||||
final String language = item.getLanguage();
|
final String language = item.getLanguage();
|
||||||
|
|
@ -548,27 +536,25 @@ public class MultilingualItemResolver
|
||||||
if (s_log.isDebugEnabled()) {
|
if (s_log.isDebugEnabled()) {
|
||||||
s_log.debug("Generated live URL " + url.toString());
|
s_log.debug("Generated live URL " + url.toString());
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
return url.toString();
|
return url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a URL which can be used to preview the
|
* Generate a URL which can be used to preview the <code>item</code>, using
|
||||||
* <code>item</code>, using the given
|
* the given <code>templateContext</code>.<p>
|
||||||
* <code>templateContext</code>.<p> Only a specific language
|
* Only a specific language instance can be previewed, meaning there
|
||||||
* instance can be previewed, meaning there <em>no</em> language
|
* <em>no</em> language negotiation is involved when a request is made to a
|
||||||
* negotiation is involved when a request is made to a URL that
|
* URL that has been generated by this method.
|
||||||
* has been generated by this method.
|
|
||||||
*
|
*
|
||||||
* @param section The <code>ContentSection</code> which contains
|
* @param section The <code>ContentSection</code> which contains the
|
||||||
* the <code>item</code>
|
|
||||||
* @param item The <code>ContentItem</code> for which a URL should
|
|
||||||
* be generated.
|
|
||||||
* @param templateContext the context that determines which
|
|
||||||
* template should render the item when it is previewed; ignored
|
|
||||||
* if the argument given here is <code>null</code>
|
|
||||||
* @return a URL which can be used to preview the given
|
|
||||||
* <code>item</code>
|
* <code>item</code>
|
||||||
|
* @param item The <code>ContentItem</code> for which a URL should be
|
||||||
|
* generated.
|
||||||
|
* @param templateContext the context that determines which template should
|
||||||
|
* render the item when it is previewed; ignored if the argument given here
|
||||||
|
* is <code>null</code>
|
||||||
|
* @return a URL which can be used to preview the given <code>item</code>
|
||||||
*/
|
*/
|
||||||
protected String generatePreviewURL(ContentSection section,
|
protected String generatePreviewURL(ContentSection section,
|
||||||
ContentItem item,
|
ContentItem item,
|
||||||
|
|
@ -587,7 +573,8 @@ public class MultilingualItemResolver
|
||||||
// This is breaking URL's...not sure why it's here. XXX
|
// This is breaking URL's...not sure why it's here. XXX
|
||||||
// this should work with the appropriate logic. trying again.
|
// this should work with the appropriate logic. trying again.
|
||||||
if (!(templateContext == null || templateContext.length() == 0)) {
|
if (!(templateContext == null || templateContext.length() == 0)) {
|
||||||
url.append(TEMPLATE_CONTEXT_PREFIX).append(templateContext).append("/");
|
url.append(TEMPLATE_CONTEXT_PREFIX).append(templateContext).append(
|
||||||
|
"/");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to retrieve the bundle.
|
// Try to retrieve the bundle.
|
||||||
|
|
@ -601,11 +588,11 @@ public class MultilingualItemResolver
|
||||||
* ContentItem.
|
* ContentItem.
|
||||||
*/
|
*/
|
||||||
if (bundle != null && bundle instanceof ContentBundle) {
|
if (bundle != null && bundle instanceof ContentBundle) {
|
||||||
s_log.debug("Found a bundle; using its path");
|
LOGGER.debug("Found a bundle; using its path");
|
||||||
|
|
||||||
url.append(bundle.getPath());
|
url.append(bundle.getPath());
|
||||||
} else {
|
} else {
|
||||||
s_log.debug("No bundle found; using the item's path directly");
|
LOGGER.debug("No bundle found; using the item's path directly");
|
||||||
|
|
||||||
url.append(item.getPath());
|
url.append(item.getPath());
|
||||||
}
|
}
|
||||||
|
|
@ -613,35 +600,34 @@ public class MultilingualItemResolver
|
||||||
final String language = item.getLanguage();
|
final String language = item.getLanguage();
|
||||||
|
|
||||||
if (language == null) {
|
if (language == null) {
|
||||||
s_log.debug("The item has no language; omitting the " +
|
LOGGER.debug("The item has no language; omitting the "
|
||||||
"language encoding");
|
+ "language encoding");
|
||||||
} else {
|
} else {
|
||||||
s_log.debug("Encoding the language of the item passed in, '" +
|
LOGGER.debug("Encoding the language of the item passed in, '"
|
||||||
language + "'");
|
+ language + "'");
|
||||||
|
|
||||||
url.append(".").append(language);
|
url.append(".").append(language);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Generated preview URL " + url.toString());
|
LOGGER.debug("Generated preview URL " + url.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return url.toString();
|
return url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves <code>ITEM_ID</code> parameter from URL and
|
* Retrieves <code>ITEM_ID</code> parameter from URL and instantiates item
|
||||||
* instantiates item according to this ID.
|
* according to this ID.
|
||||||
*
|
*
|
||||||
* @param url URL that indicates which item should be retrieved;
|
* @param url URL that indicates which item should be retrieved; must
|
||||||
* must contain the <code>ITEM_ID</code> parameter
|
* contain the <code>ITEM_ID</code> parameter
|
||||||
* @return the <code>ContentItem</code> the given <code>url</code>
|
* @return the <code>ContentItem</code> the given <code>url</code> points
|
||||||
* points to, or <code>null</code> if no ID has been found in the
|
* to, or <code>null</code> if no ID has been found in the <code>url</code>
|
||||||
* <code>url</code>
|
|
||||||
*/
|
*/
|
||||||
protected ContentItem getItemFromDraftURL(final String url) {
|
protected ContentItem getItemFromDraftURL(final String url) {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Looking up the item from draft URL " + url);
|
LOGGER.debug("Looking up the item from draft URL " + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pos = url.indexOf(ITEM_ID);
|
int pos = url.indexOf(ITEM_ID);
|
||||||
|
|
@ -660,7 +646,7 @@ public class MultilingualItemResolver
|
||||||
if (pos != ITEM_ID.length()) {
|
if (pos != ITEM_ID.length()) {
|
||||||
// item_id seems to be something like ITEM_IDFOO=
|
// item_id seems to be something like ITEM_IDFOO=
|
||||||
|
|
||||||
s_log.debug("No suitable item_id parameter found; returning null");
|
LOGGER.debug("No suitable item_id parameter found; returning null");
|
||||||
|
|
||||||
return null; // no ID found
|
return null; // no ID found
|
||||||
}
|
}
|
||||||
|
|
@ -669,44 +655,44 @@ public class MultilingualItemResolver
|
||||||
|
|
||||||
// ID is the string between the equal (at pos) and the next separator
|
// ID is the string between the equal (at pos) and the next separator
|
||||||
int i = item_id.indexOf(SEPARATOR);
|
int i = item_id.indexOf(SEPARATOR);
|
||||||
item_id = item_id.substring(pos, Math.min(i, item_id.length() -1));
|
item_id = item_id.substring(pos, Math.min(i, item_id.length() - 1));
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Looking up item using item ID " + item_id);
|
LOGGER.debug("Looking up item using item ID " + item_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
OID oid = new OID(ContentItem.BASE_DATA_OBJECT_TYPE, new BigDecimal(item_id));
|
OID oid = new OID(ContentItem.BASE_DATA_OBJECT_TYPE, new BigDecimal(
|
||||||
final ContentItem item = (ContentItem) DomainObjectFactory.newInstance
|
item_id));
|
||||||
(oid);
|
final ContentItem item = (ContentItem) DomainObjectFactory.newInstance(
|
||||||
|
oid);
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Returning item " + item);
|
LOGGER.debug("Returning item " + item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a content item based on URL relative to the root
|
* Returns a content item based on URL relative to the root folder.
|
||||||
* folder.
|
|
||||||
*
|
*
|
||||||
* @param url The content item url
|
* @param url The content item url
|
||||||
* @param parentFolder The parent folder object, url must be relevant to it
|
* @param parentFolder The parent folder object, url must be relevant to it
|
||||||
* @return The Content Item instance, it can also be either Bundle
|
* @return The Content Item instance, it can also be either Bundle or Folder
|
||||||
* or Folder objects, depending on URL and file language extension
|
* objects, depending on URL and file language extension
|
||||||
*/
|
*/
|
||||||
protected ContentItem getItemFromLiveURL(String url,
|
protected ContentItem getItemFromLiveURL(String url,
|
||||||
Folder parentFolder) {
|
Folder parentFolder) {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Resolving the item for live URL " + url +
|
LOGGER.debug("Resolving the item for live URL " + url
|
||||||
" and parent folder " + parentFolder);
|
+ " and parent folder " + parentFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parentFolder == null || url == null || url.equals("")) {
|
if (parentFolder == null || url == null || url.equals("")) {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("The url is null or parent folder was null " +
|
LOGGER.debug("The url is null or parent folder was null "
|
||||||
"or something else is wrong, so just return " +
|
+ "or something else is wrong, so just return "
|
||||||
"the parent folder");
|
+ "the parent folder");
|
||||||
}
|
}
|
||||||
|
|
||||||
return parentFolder;
|
return parentFolder;
|
||||||
|
|
@ -716,38 +702,38 @@ public class MultilingualItemResolver
|
||||||
int index = url.indexOf('/');
|
int index = url.indexOf('/');
|
||||||
|
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
s_log.debug("The URL starts with a slash; paring off the first " +
|
LOGGER.debug("The URL starts with a slash; paring off the first "
|
||||||
"URL element and recursing");
|
+ "URL element and recursing");
|
||||||
|
|
||||||
// If we got first slash (index == 0), ignore it and go
|
// If we got first slash (index == 0), ignore it and go
|
||||||
// on, sample '/foo/bar/item.html.en', in next recursion
|
// on, sample '/foo/bar/item.html.en', in next recursion
|
||||||
// will have deal with 'foo' folder.
|
// will have deal with 'foo' folder.
|
||||||
|
|
||||||
String name = index > 0 ? url.substring(0, index) : "";
|
String name = index > 0 ? url.substring(0, index) : "";
|
||||||
parentFolder = "".equals(name) ? parentFolder
|
parentFolder = "".equals(name) ? parentFolder
|
||||||
: (Folder) parentFolder.getItem(URLEncoder.encode(name), true);
|
: (Folder) parentFolder.getItem(URLEncoder.encode(
|
||||||
|
name), true);
|
||||||
url = index + 1 < len ? url.substring(index + 1) : "";
|
url = index + 1 < len ? url.substring(index + 1) : "";
|
||||||
|
|
||||||
return getItemFromLiveURL(url, parentFolder);
|
return getItemFromLiveURL(url, parentFolder);
|
||||||
} else {
|
} else {
|
||||||
s_log.debug("Found a file element in the URL");
|
LOGGER.debug("Found a file element in the URL");
|
||||||
|
|
||||||
String[] nameAndLang = getNameAndLangFromURLFrag(url);
|
String[] nameAndLang = getNameAndLangFromURLFrag(url);
|
||||||
String name = nameAndLang[0];
|
String name = nameAndLang[0];
|
||||||
String lang = nameAndLang[1];
|
String lang = nameAndLang[1];
|
||||||
|
|
||||||
ContentItem item = parentFolder.getItem(URLEncoder.encode(name), false);
|
ContentItem item = parentFolder.getItem(URLEncoder.encode(name),
|
||||||
|
false);
|
||||||
return getItemFromLangAndBundle(lang, item);
|
return getItemFromLangAndBundle(lang, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array containing the the item's name and lang based
|
* Returns an array containing the the item's name and lang based on the URL
|
||||||
* on the URL fragment.
|
* fragment.
|
||||||
*
|
*
|
||||||
* @return a two-element string array, the first element
|
* @return a two-element string array, the first element containing the
|
||||||
* containing the bundle name, and the second element containing
|
* bundle name, and the second element containing the lang string
|
||||||
* the lang string
|
|
||||||
*/
|
*/
|
||||||
protected String[] getNameAndLangFromURLFrag(String url) {
|
protected String[] getNameAndLangFromURLFrag(String url) {
|
||||||
String name = null;
|
String name = null;
|
||||||
|
|
@ -763,7 +749,6 @@ public class MultilingualItemResolver
|
||||||
* from a bundle
|
* from a bundle
|
||||||
* 2b if no match is found
|
* 2b if no match is found
|
||||||
*/
|
*/
|
||||||
|
|
||||||
final ArrayList exts = new ArrayList(5);
|
final ArrayList exts = new ArrayList(5);
|
||||||
final StringTokenizer tok = new StringTokenizer(url, ".");
|
final StringTokenizer tok = new StringTokenizer(url, ".");
|
||||||
|
|
||||||
|
|
@ -772,9 +757,9 @@ public class MultilingualItemResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exts.size() > 0) {
|
if (exts.size() > 0) {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Found some file extensions to look at; they " +
|
LOGGER.debug("Found some file extensions to look at; they "
|
||||||
"are " + exts);
|
+ "are " + exts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -784,21 +769,20 @@ public class MultilingualItemResolver
|
||||||
* support 2-letter language codes!).
|
* support 2-letter language codes!).
|
||||||
* If so, use this as the language to look for.
|
* If so, use this as the language to look for.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First element is the NAME of the item, not an extension!
|
* First element is the NAME of the item, not an extension!
|
||||||
*/
|
*/
|
||||||
name = (String) exts.get(0);
|
name = (String) exts.get(0);
|
||||||
String ext = null;
|
String ext = null;
|
||||||
Collection supportedLangs =
|
Collection supportedLangs
|
||||||
LanguageUtil.getSupportedLanguages2LA();
|
= LanguageUtil.getSupportedLanguages2LA();
|
||||||
Iterator supportedLangIt = null;
|
Iterator supportedLangIt = null;
|
||||||
|
|
||||||
for (int i = 1; i < exts.size(); i++) {
|
for (int i = 1; i < exts.size(); i++) {
|
||||||
ext = (String) exts.get(i);
|
ext = (String) exts.get(i);
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Examining extension " + ext);
|
LOGGER.debug("Examining extension " + ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -817,23 +801,23 @@ public class MultilingualItemResolver
|
||||||
while (supportedLangIt.hasNext()) {
|
while (supportedLangIt.hasNext()) {
|
||||||
if (ext.equals(supportedLangIt.next())) {
|
if (ext.equals(supportedLangIt.next())) {
|
||||||
lang = ext;
|
lang = ext;
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Found a match; using " +
|
LOGGER.debug("Found a match; using "
|
||||||
"language " + lang);
|
+ "language " + lang);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Discarding extension " + ext + "; " +
|
LOGGER.debug("Discarding extension " + ext + "; "
|
||||||
"it is too short");
|
+ "it is too short");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s_log.debug("The file has no extensions; no language was " +
|
LOGGER.debug("The file has no extensions; no language was "
|
||||||
"encoded");
|
+ "encoded");
|
||||||
name = url; // no extension, so we just have a name here
|
name = url; // no extension, so we just have a name here
|
||||||
lang = null; // no extension, so we cannot guess the language
|
lang = null; // no extension, so we cannot guess the language
|
||||||
}
|
}
|
||||||
|
|
@ -843,9 +827,9 @@ public class MultilingualItemResolver
|
||||||
Assert.exists(lang == null || lang.length() == 2);
|
Assert.exists(lang == null || lang.length() == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("File name resolved to " + name);
|
LOGGER.debug("File name resolved to " + name);
|
||||||
s_log.debug("File language resolved to " + lang);
|
LOGGER.debug("File language resolved to " + lang);
|
||||||
}
|
}
|
||||||
String[] returnArray = new String[2];
|
String[] returnArray = new String[2];
|
||||||
returnArray[0] = name;
|
returnArray[0] = name;
|
||||||
|
|
@ -853,10 +837,9 @@ public class MultilingualItemResolver
|
||||||
return returnArray;
|
return returnArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a language instance of a content item given the bundle,
|
* Finds a language instance of a content item given the bundle, name, and
|
||||||
* name, and lang string
|
* lang string
|
||||||
*
|
*
|
||||||
* @param lang The lang string from the URL
|
* @param lang The lang string from the URL
|
||||||
* @param item The content bundle
|
* @param item The content bundle
|
||||||
|
|
@ -865,19 +848,20 @@ public class MultilingualItemResolver
|
||||||
*/
|
*/
|
||||||
protected ContentItem getItemFromLangAndBundle(String lang, ContentItem item) {
|
protected ContentItem getItemFromLangAndBundle(String lang, ContentItem item) {
|
||||||
if (item != null && item instanceof ContentBundle) {
|
if (item != null && item instanceof ContentBundle) {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Found content bundle " + item);
|
LOGGER.debug("Found content bundle " + item);
|
||||||
}
|
}
|
||||||
if (lang == null) {
|
if (lang == null) {
|
||||||
s_log.debug("The URL has no language encoded in it; " +
|
LOGGER.debug("The URL has no language encoded in it; "
|
||||||
"negotiating the language");
|
+ "negotiating the language");
|
||||||
// There is no language, so we get the negotiated locale and call
|
// There is no language, so we get the negotiated locale and call
|
||||||
// this method again with a proper language
|
// this method again with a proper language
|
||||||
return this.getItemFromLangAndBundle(GlobalizationHelper.getNegotiatedLocale().getLanguage(), item);
|
return this.getItemFromLangAndBundle(GlobalizationHelper.
|
||||||
|
getNegotiatedLocale().getLanguage(), item);
|
||||||
} else {
|
} else {
|
||||||
s_log.debug("The URL is encoded with a langauge; " +
|
LOGGER.debug("The URL is encoded with a langauge; "
|
||||||
"fetching the appropriate item from " +
|
+ "fetching the appropriate item from "
|
||||||
"the bundle");
|
+ "the bundle");
|
||||||
/*
|
/*
|
||||||
* So the request contains a language code as an
|
* So the request contains a language code as an
|
||||||
* extension of the "name" ==>go ahead and try to
|
* extension of the "name" ==>go ahead and try to
|
||||||
|
|
@ -886,18 +870,19 @@ public class MultilingualItemResolver
|
||||||
* given language.
|
* given language.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
final ContentItem resolved =
|
final ContentItem resolved
|
||||||
((ContentBundle) item).getInstance(lang);
|
= ((ContentBundle) item).getInstance(lang);
|
||||||
|
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("Resolved URL to item " + resolved);
|
LOGGER.debug("Resolved URL to item " + resolved);
|
||||||
}
|
}
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (s_log.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_log.debug("I expected to get a content bundle; I got " +
|
LOGGER.
|
||||||
item);
|
debug("I expected to get a content bundle; I got "
|
||||||
|
+ item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -908,7 +893,6 @@ public class MultilingualItemResolver
|
||||||
*
|
*
|
||||||
* NOTE: This should never happen :-)
|
* NOTE: This should never happen :-)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return item; // might be null
|
return item; // might be null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,684 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.authoring;
|
|
||||||
|
|
||||||
import com.arsdigita.bebop.Component;
|
|
||||||
import com.arsdigita.bebop.ControlLink;
|
|
||||||
import com.arsdigita.bebop.FormProcessException;
|
|
||||||
import com.arsdigita.bebop.GridPanel;
|
|
||||||
import com.arsdigita.bebop.List;
|
|
||||||
import com.arsdigita.bebop.Page;
|
|
||||||
import com.arsdigita.bebop.PageState;
|
|
||||||
import com.arsdigita.bebop.Resettable;
|
|
||||||
import com.arsdigita.bebop.SimpleContainer;
|
|
||||||
import com.arsdigita.bebop.SingleSelectionModel;
|
|
||||||
import com.arsdigita.bebop.event.ActionEvent;
|
|
||||||
import com.arsdigita.bebop.event.ActionListener;
|
|
||||||
import com.arsdigita.bebop.event.ChangeEvent;
|
|
||||||
import com.arsdigita.bebop.event.ChangeListener;
|
|
||||||
import com.arsdigita.bebop.event.FormProcessListener;
|
|
||||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
|
||||||
import com.arsdigita.bebop.Label;
|
|
||||||
import com.arsdigita.bebop.list.ListCellRenderer;
|
|
||||||
import org.librecms.contentsection.ContentSection;
|
|
||||||
import org.librecms.contentsection.ContentType;
|
|
||||||
import com.arsdigita.cms.ItemSelectionModel;
|
|
||||||
import com.arsdigita.cms.ui.ContentItemPage;
|
|
||||||
import com.arsdigita.cms.ui.item.ItemWorkflowRequestLocal;
|
|
||||||
import com.arsdigita.cms.ui.workflow.AssignedTaskSection;
|
|
||||||
import com.arsdigita.cms.ui.workflow.AssignedTaskTable;
|
|
||||||
import com.arsdigita.cms.ui.workflow.TaskFinishForm;
|
|
||||||
import com.arsdigita.cms.ui.workflow.TaskRequestLocal;
|
|
||||||
import com.arsdigita.cms.ui.workflow.WorkflowRequestLocal;
|
|
||||||
import com.arsdigita.cms.util.GlobalizationUtil;
|
|
||||||
import com.arsdigita.cms.workflow.CMSTask;
|
|
||||||
import com.arsdigita.globalization.GlobalizedMessage;
|
|
||||||
import com.arsdigita.persistence.metadata.MetadataRoot;
|
|
||||||
import com.arsdigita.persistence.metadata.ObjectType;
|
|
||||||
import com.arsdigita.toolbox.ui.LayoutPanel;
|
|
||||||
import com.arsdigita.toolbox.ui.ModalPanel;
|
|
||||||
import com.arsdigita.toolbox.ui.Section;
|
|
||||||
import com.arsdigita.util.Assert;
|
|
||||||
import com.arsdigita.util.SequentialMap;
|
|
||||||
import com.arsdigita.util.UncheckedWrapperException;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.librecms.contenttypes.AuthoringKitInfo;
|
|
||||||
import org.librecms.contenttypes.ContentTypeInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a single authoring kit. The wizard accepts a
|
|
||||||
* {@link ContentType} in the constructor; it then extracts
|
|
||||||
* the {@link AuthoringKit} for the content type, and creates the
|
|
||||||
* components for all the steps in the kit.</p>
|
|
||||||
*
|
|
||||||
* Note that the individual authoring kit steps must provide the following
|
|
||||||
* constructor:
|
|
||||||
*
|
|
||||||
* <blockquote><pre><code>
|
|
||||||
* public TheClass(ItemSelectionModel model, AuthoringKitWizard parent) { ... }
|
|
||||||
* </code></pre></blockquote>
|
|
||||||
*
|
|
||||||
* This constructor will be called when the component is automatically
|
|
||||||
* instantiated by the <code>AuthoringKitWizard</code>.</p>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class AuthoringKitWizard extends LayoutPanel implements Resettable {
|
|
||||||
|
|
||||||
/** Private Logger instance for this class */
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(
|
|
||||||
AuthoringKitWizard.class);
|
|
||||||
private static Class[] s_args = new Class[]{
|
|
||||||
ItemSelectionModel.class,
|
|
||||||
AuthoringKitWizard.class
|
|
||||||
};
|
|
||||||
private static Class[] s_userDefinedArgs = new Class[]{
|
|
||||||
ItemSelectionModel.class,
|
|
||||||
AuthoringKitWizard.class,
|
|
||||||
ContentType.class
|
|
||||||
};
|
|
||||||
//private static final ArrayList s_assets = new ArrayList();
|
|
||||||
private static final java.util.List<AssetStepEntry> s_assets = new
|
|
||||||
ArrayList<AssetStepEntry>();
|
|
||||||
private final Object[] m_vals;
|
|
||||||
private final ContentTypeInfo m_type;
|
|
||||||
private final AuthoringKitInfo m_kit;
|
|
||||||
private final ItemSelectionModel m_sel;
|
|
||||||
private final WorkflowRequestLocal m_workflow;
|
|
||||||
private final AssignedTaskTable m_tasks;
|
|
||||||
private final SequentialMap m_labels;
|
|
||||||
private final List m_list;
|
|
||||||
private String m_defaultKey;
|
|
||||||
private final GridPanel m_left;
|
|
||||||
private final ModalPanel m_body;
|
|
||||||
private final SimpleContainer m_steps;
|
|
||||||
private final TaskFinishForm m_taskFinishForm;
|
|
||||||
/**
|
|
||||||
* The name of the state parameter that determines whether the
|
|
||||||
* wizard is in item creation mode or item editing mode.
|
|
||||||
*/
|
|
||||||
public static final String IS_EDITING = "is_edit";
|
|
||||||
/**
|
|
||||||
* The key for the item creation step.
|
|
||||||
*/
|
|
||||||
public static final String CREATION = "_creation_";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new AuthoringKitWizard. Add all the steps in the
|
|
||||||
* authoring kit to the wizard.
|
|
||||||
*
|
|
||||||
* @param type The content type of the items that this wizard will
|
|
||||||
* handle
|
|
||||||
* @param model
|
|
||||||
*/
|
|
||||||
public AuthoringKitWizard(final ContentTypeInfo type,
|
|
||||||
final ItemSelectionModel model) {
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug("Authoring kit wizard for type " + type + " "
|
|
||||||
+ "undergoing creation");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_type = type;
|
|
||||||
m_kit = type.getAuthoringKit();
|
|
||||||
m_sel = model;
|
|
||||||
m_vals = new Object[]{m_sel, this};
|
|
||||||
m_workflow = new ItemWorkflowRequestLocal();
|
|
||||||
m_labels = new SequentialMap();
|
|
||||||
|
|
||||||
m_left = new GridPanel(1);
|
|
||||||
setLeft(m_left);
|
|
||||||
|
|
||||||
m_tasks = new AssignedTaskTable(m_workflow);
|
|
||||||
|
|
||||||
m_left.add(new AssignedTaskSection(m_workflow, m_tasks));
|
|
||||||
|
|
||||||
final Section stepSection = new Section(gz("cms.ui.authoring.steps"));
|
|
||||||
m_left.add(stepSection);
|
|
||||||
|
|
||||||
m_list = new List();
|
|
||||||
stepSection.setBody(m_list);
|
|
||||||
|
|
||||||
m_list.setListData(m_labels);
|
|
||||||
m_list.setCellRenderer(new ListCellRenderer() {
|
|
||||||
|
|
||||||
public Component getComponent(
|
|
||||||
List list,
|
|
||||||
PageState state,
|
|
||||||
Object value,
|
|
||||||
String key,
|
|
||||||
int index,
|
|
||||||
boolean isSelected) {
|
|
||||||
Label l = null;
|
|
||||||
if (value instanceof GlobalizedMessage) {
|
|
||||||
l = new Label((GlobalizedMessage) value);
|
|
||||||
} else {
|
|
||||||
l = new Label((String) value);
|
|
||||||
}
|
|
||||||
if (isSelected) {
|
|
||||||
l.setFontWeight(Label.BOLD);
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
return new ControlLink(l);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
m_body = new ModalPanel();
|
|
||||||
setBody(m_body);
|
|
||||||
|
|
||||||
m_steps = new SimpleContainer();
|
|
||||||
m_body.add(m_steps);
|
|
||||||
m_body.setDefault(m_steps);
|
|
||||||
|
|
||||||
final AuthoringStepCollection steps = m_kit.getSteps();
|
|
||||||
|
|
||||||
if (Assert.isEnabled()) {
|
|
||||||
Assert.isTrue(!steps.isEmpty(),
|
|
||||||
"The authoring kit for " + type.getID() + " "
|
|
||||||
+ "(java class " + type.getClassName() + ") "
|
|
||||||
+ "has no steps.");
|
|
||||||
}
|
|
||||||
|
|
||||||
StepComponent panel = null;
|
|
||||||
while (steps.next()) {
|
|
||||||
final AuthoringStep step = steps.getAuthoringStep();
|
|
||||||
final String key = step.getID().toString();
|
|
||||||
|
|
||||||
if (m_defaultKey == null) {
|
|
||||||
m_defaultKey = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The "label" and "description" are only here for backwards
|
|
||||||
* compatibility
|
|
||||||
*/
|
|
||||||
final String label = step.getLabel();
|
|
||||||
final String labelKey = step.getLabelKey();
|
|
||||||
final String labelBundle = step.getLabelBundle();
|
|
||||||
final String description = step.getDescription();
|
|
||||||
final String descriptionKey = step.getDescription();
|
|
||||||
final String descriptionBundle = step.getDescription();
|
|
||||||
final String str = step.getComponent();
|
|
||||||
|
|
||||||
if (panel != null) {
|
|
||||||
panel.setNextStepKey(step.getID());
|
|
||||||
}
|
|
||||||
panel = new StepComponent(step.getID());
|
|
||||||
m_steps.add(panel);
|
|
||||||
final Component comp;
|
|
||||||
|
|
||||||
if (str.equals("com.arsdigita.cms.ui.authoring."
|
|
||||||
+ "SecondaryPageEditDynamic")
|
|
||||||
|| str.equals("com.arsdigita.cms.ui.authoring."
|
|
||||||
+ "PageEditDynamic")) {
|
|
||||||
comp = instantiateUserDefinedStep(str, m_type);
|
|
||||||
} else {
|
|
||||||
comp = instantiateStep(str);
|
|
||||||
}
|
|
||||||
panel.add(comp);
|
|
||||||
// XXX should be optional
|
|
||||||
if (comp instanceof AuthoringStepComponent) {
|
|
||||||
((AuthoringStepComponent) comp).addCompletionListener(
|
|
||||||
new StepCompletionListener());
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalizedMessage gzLabel = null;
|
|
||||||
if (labelKey != null) {
|
|
||||||
if (labelBundle == null) {
|
|
||||||
gzLabel = gz(labelKey);
|
|
||||||
} else {
|
|
||||||
gzLabel = new GlobalizedMessage(labelKey, labelBundle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_labels.put(key,
|
|
||||||
gzLabel == null ? (Object) label : (Object) gzLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectType thisType = MetadataRoot.getMetadataRoot().getObjectType(type.
|
|
||||||
getAssociatedObjectType());
|
|
||||||
Collection skipSteps = ContentSection.getConfig().getAssetStepsToSkip(
|
|
||||||
type);
|
|
||||||
Iterator it = skipSteps.iterator();
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
while (it.hasNext()) {
|
|
||||||
LOGGER.debug("skip step " + it.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Iterator assets = s_assets.iterator();
|
|
||||||
Iterator<AssetStepEntry> assets = s_assets.iterator();
|
|
||||||
while (assets.hasNext()) {
|
|
||||||
//Object[] data = (Object[]) assets.next();
|
|
||||||
final AssetStepEntry data = assets.next();
|
|
||||||
//String baseObjectType = (String) data[0];
|
|
||||||
final String baseObjectType = data.getBaseDataObjectType();
|
|
||||||
//Class step = (Class) data[1];
|
|
||||||
Class step = data.getStep();
|
|
||||||
LOGGER.debug("possibly adding asset step " + step.getName());
|
|
||||||
if (!skipSteps.contains(step.getName())) {
|
|
||||||
//GlobalizedMessage label = (GlobalizedMessage) data[2];
|
|
||||||
GlobalizedMessage label = data.getLabel();
|
|
||||||
|
|
||||||
if (!thisType.isSubtypeOf(baseObjectType)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (panel != null) {
|
|
||||||
panel.setNextStepKey(step);
|
|
||||||
}
|
|
||||||
panel = new StepComponent(step);
|
|
||||||
m_steps.add(panel);
|
|
||||||
|
|
||||||
Component comp = instantiateStep(step.getName());
|
|
||||||
if (comp instanceof AuthoringStepComponent) {
|
|
||||||
((AuthoringStepComponent) comp).addCompletionListener(
|
|
||||||
new StepCompletionListener());
|
|
||||||
}
|
|
||||||
panel.add(comp);
|
|
||||||
|
|
||||||
m_labels.put(step, label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_list.addChangeListener(new StepListener());
|
|
||||||
|
|
||||||
m_taskFinishForm = new TaskFinishForm(new TaskSelectionRequestLocal());
|
|
||||||
m_body.add(m_taskFinishForm);
|
|
||||||
|
|
||||||
m_body.connect(m_tasks, 2, m_taskFinishForm);
|
|
||||||
m_body.connect(m_taskFinishForm);
|
|
||||||
|
|
||||||
m_taskFinishForm.addProcessListener(new FormProcessListener() {
|
|
||||||
|
|
||||||
public final void process(final FormSectionEvent e)
|
|
||||||
throws FormProcessException {
|
|
||||||
final PageState state = e.getPageState();
|
|
||||||
|
|
||||||
m_tasks.getRowSelectionModel().clearSelection(state);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private final class StepListener implements ChangeListener {
|
|
||||||
|
|
||||||
public final void stateChanged(final ChangeEvent e) {
|
|
||||||
final PageState state = e.getPageState();
|
|
||||||
final String key = m_list.getSelectedKey(state).toString();
|
|
||||||
|
|
||||||
final Iterator iter = m_steps.children();
|
|
||||||
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
final StepComponent step = (StepComponent) iter.next();
|
|
||||||
|
|
||||||
if (step.getStepKey().toString().equals(key)) {
|
|
||||||
step.setVisible(state, true);
|
|
||||||
} else {
|
|
||||||
step.setVisible(state, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private final class StepCompletionListener implements ActionListener {
|
|
||||||
|
|
||||||
public final void actionPerformed(final ActionEvent e) {
|
|
||||||
final PageState state = e.getPageState();
|
|
||||||
if (ContentItemPage.isStreamlinedCreationActive(state)) {
|
|
||||||
final String key = m_list.getSelectedKey(state).toString();
|
|
||||||
|
|
||||||
final Iterator iter = m_steps.children();
|
|
||||||
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
final StepComponent step = (StepComponent) iter.next();
|
|
||||||
if (step.getStepKey().toString().equals(key)) {
|
|
||||||
Object nextStep = step.getNextStepKey();
|
|
||||||
if (nextStep != null) {
|
|
||||||
m_list.getSelectionModel().setSelectedKey(state,
|
|
||||||
nextStep.
|
|
||||||
toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param page
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void register(final Page page) {
|
|
||||||
super.register(page);
|
|
||||||
|
|
||||||
final Iterator iter = m_steps.children();
|
|
||||||
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
final StepComponent child = (StepComponent) iter.next();
|
|
||||||
|
|
||||||
page.setVisibleDefault(child, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
page.addActionListener(new ActionListener() {
|
|
||||||
|
|
||||||
public final void actionPerformed(final ActionEvent e) {
|
|
||||||
final PageState state = e.getPageState();
|
|
||||||
|
|
||||||
if (state.isVisibleOnPage(AuthoringKitWizard.this)) {
|
|
||||||
final SingleSelectionModel model =
|
|
||||||
m_list.getSelectionModel();
|
|
||||||
|
|
||||||
if (!model.isSelected(state)) {
|
|
||||||
model.setSelectedKey(state, m_defaultKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param baseObjectType
|
|
||||||
* @param step
|
|
||||||
* @param label
|
|
||||||
* @param description
|
|
||||||
* @param sortKey
|
|
||||||
*/
|
|
||||||
public static void registerAssetStep(String baseObjectType,
|
|
||||||
Class step,
|
|
||||||
GlobalizedMessage label,
|
|
||||||
GlobalizedMessage description,
|
|
||||||
int sortKey) {
|
|
||||||
// cg - allow registered steps to be overridden by registering a step with the same label
|
|
||||||
// this is a bit of a hack used specifically for creating a specialised version of image
|
|
||||||
// step. There is no straightforward way of preventing the original image step from being
|
|
||||||
// registered, but I needed the image step to use a different step class if the specialised
|
|
||||||
// image step application was loaded. Solution is to ensure initialiser in new project
|
|
||||||
// runs after original ccm-ldn-image-step initializer and override the registered step here
|
|
||||||
LOGGER.debug(
|
|
||||||
"registering asset step - label: "
|
|
||||||
+ label.localize()
|
|
||||||
+ " step class: "
|
|
||||||
+ step.getName());
|
|
||||||
|
|
||||||
//Iterator assets = s_assets.iterator();
|
|
||||||
Iterator<AssetStepEntry> assets = s_assets.iterator();
|
|
||||||
while (assets.hasNext()) {
|
|
||||||
//Object[] data = (Object[]) assets.next();
|
|
||||||
//String thisObjectType = (String) data[0];
|
|
||||||
//GlobalizedMessage thisLabel = (GlobalizedMessage) data[2];
|
|
||||||
|
|
||||||
final AssetStepEntry data = assets.next();
|
|
||||||
String thisObjectType = data.getBaseDataObjectType();
|
|
||||||
GlobalizedMessage thisLabel = data.getLabel();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* jensp 2011-11-14: The code above was only testing for the same
|
|
||||||
* label, but not for the same object type. I don't think that
|
|
||||||
* this was indented since this made it impossible to attach the
|
|
||||||
* same step to different object types.
|
|
||||||
* The orginal line was
|
|
||||||
* if (thisLabel.localize().equals(label.localize())) {
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if ((thisObjectType.equals(baseObjectType))
|
|
||||||
&& (thisLabel.localize().equals(label.localize()))) {
|
|
||||||
LOGGER.debug(
|
|
||||||
"registering authoring step with same label as previously registered step");
|
|
||||||
s_assets.remove(data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s_assets.add(new AssetStepEntry(baseObjectType, step, label, description, sortKey));
|
|
||||||
Collections.sort(s_assets);
|
|
||||||
//s_assets.add(new Object[]{baseObjectType, step, label, description});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class AssetStepEntry implements Comparable<AssetStepEntry> {
|
|
||||||
private String baseDataObjectType;
|
|
||||||
private Class step;
|
|
||||||
private GlobalizedMessage label;
|
|
||||||
private GlobalizedMessage description;
|
|
||||||
private Integer sortKey;
|
|
||||||
|
|
||||||
public AssetStepEntry() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public AssetStepEntry(final String baseDataObjectType,
|
|
||||||
final Class step,
|
|
||||||
final GlobalizedMessage label,
|
|
||||||
final GlobalizedMessage description,
|
|
||||||
final Integer sortKey) {
|
|
||||||
this.baseDataObjectType = baseDataObjectType;
|
|
||||||
this.step = step;
|
|
||||||
this.label = label;
|
|
||||||
this.description = description;
|
|
||||||
this.sortKey = sortKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBaseDataObjectType() {
|
|
||||||
return baseDataObjectType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBaseDataObjectType(final String baseDataObjectType) {
|
|
||||||
this.baseDataObjectType = baseDataObjectType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class getStep() {
|
|
||||||
return step;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStep(final Class step) {
|
|
||||||
this.step = step;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GlobalizedMessage getLabel() {
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLabel(final GlobalizedMessage label) {
|
|
||||||
this.label = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GlobalizedMessage getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescription(final GlobalizedMessage description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getSortKey() {
|
|
||||||
return sortKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSortKey(final Integer sortKey) {
|
|
||||||
this.sortKey = sortKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int compareTo(final AssetStepEntry other) {
|
|
||||||
if (sortKey == other.getSortKey()) {
|
|
||||||
return step.getName().compareTo(other.getStep().getName());
|
|
||||||
} else {
|
|
||||||
return sortKey.compareTo(other.getSortKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The content type handled by this wizard
|
|
||||||
*/
|
|
||||||
public ContentType getContentType() {
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List getList() {
|
|
||||||
return m_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The authoring kit which is represented by this wizard
|
|
||||||
*/
|
|
||||||
public AuthoringKit getAuthoringKit() {
|
|
||||||
return m_kit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The ItemSelectionModel used by the steps in this wizard
|
|
||||||
*/
|
|
||||||
public ItemSelectionModel getItemSelectionModel() {
|
|
||||||
return m_sel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate the specified authoring kit step. Will throw a
|
|
||||||
* RuntimeException on failure.
|
|
||||||
*
|
|
||||||
* @param className The Java class name of the step
|
|
||||||
*/
|
|
||||||
protected Component instantiateStep(String name) {
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
|
||||||
LOGGER.debug("Instantiating kit wizard '" + name + "' with "
|
|
||||||
+ "arguments " + s_args);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object[] vals;
|
|
||||||
try {
|
|
||||||
// Get the creation component
|
|
||||||
Class createClass = Class.forName(name);
|
|
||||||
Constructor constr = createClass.getConstructor(s_args);
|
|
||||||
Component c = (Component) constr.newInstance(m_vals);
|
|
||||||
return c;
|
|
||||||
} catch (Exception e) {
|
|
||||||
Throwable cause = e.getCause(); // JDK1.4
|
|
||||||
if (cause == null) {
|
|
||||||
cause = e;
|
|
||||||
}
|
|
||||||
throw new UncheckedWrapperException(
|
|
||||||
"Failed to instantiate authoring kit component " + m_kit.
|
|
||||||
getCreateComponent() + ": " + e.getMessage(), cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate the specified authoring kit step for a user defined content type.
|
|
||||||
* Will throw a
|
|
||||||
* RuntimeException on failure.
|
|
||||||
*
|
|
||||||
* @param className The Java class name of the step
|
|
||||||
* @param description The step description, which for dynamically generated
|
|
||||||
* steps will be the object type which originally defined the step.
|
|
||||||
*/
|
|
||||||
protected Component instantiateUserDefinedStep(String name,
|
|
||||||
ContentType originatingType) {
|
|
||||||
Object[] vals;
|
|
||||||
try {
|
|
||||||
// Get the creation component
|
|
||||||
Class createClass = Class.forName(name);
|
|
||||||
Constructor constr = createClass.getConstructor(s_userDefinedArgs);
|
|
||||||
Object[] userDefinedVals =
|
|
||||||
new Object[]{m_sel, this, originatingType};
|
|
||||||
Component c = (Component) constr.newInstance(userDefinedVals);
|
|
||||||
return c;
|
|
||||||
} catch (ClassNotFoundException cnfe) {
|
|
||||||
throw new UncheckedWrapperException(cnfe);
|
|
||||||
} catch (NoSuchMethodException nsme) {
|
|
||||||
throw new UncheckedWrapperException(nsme);
|
|
||||||
} catch (InstantiationException ie) {
|
|
||||||
throw new UncheckedWrapperException(ie);
|
|
||||||
} catch (IllegalAccessException iae) {
|
|
||||||
throw new UncheckedWrapperException(iae);
|
|
||||||
} catch (InvocationTargetException ite) {
|
|
||||||
throw new UncheckedWrapperException(ite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Tell the parent page to redirect back to its return URL
|
|
||||||
// *
|
|
||||||
// * @param state The page state
|
|
||||||
// */
|
|
||||||
// public static void redirectBack(PageState state) {
|
|
||||||
// ((ContentItemPage)state.getPage()).redirectBack(state);
|
|
||||||
// }
|
|
||||||
/**
|
|
||||||
* Reset the state of this wizard
|
|
||||||
*/
|
|
||||||
public final void reset(PageState state) {
|
|
||||||
m_list.setSelectedKey(state, m_defaultKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class StepComponent extends SimpleContainer {
|
|
||||||
|
|
||||||
private final Object m_key;
|
|
||||||
private Object m_nextKey;
|
|
||||||
|
|
||||||
|
|
||||||
public StepComponent(Object key) {
|
|
||||||
m_key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getStepKey() {
|
|
||||||
return m_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getNextStepKey() {
|
|
||||||
return m_nextKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNextStepKey(Object nextKey) {
|
|
||||||
m_nextKey = nextKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class TaskSelectionRequestLocal extends TaskRequestLocal {
|
|
||||||
|
|
||||||
protected final Object initialValue(final PageState state) {
|
|
||||||
final String id = m_tasks.getRowSelectionModel().getSelectedKey(
|
|
||||||
state).toString();
|
|
||||||
|
|
||||||
return new CMSTask(new BigDecimal(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final static GlobalizedMessage gz(final String key) {
|
|
||||||
return GlobalizationUtil.globalize(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final static String lz(final String key) {
|
|
||||||
return (String) gz(key).localize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,684 @@
|
||||||
|
/*
|
||||||
|
* 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.authoring;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.Component;
|
||||||
|
import com.arsdigita.bebop.ControlLink;
|
||||||
|
import com.arsdigita.bebop.FormProcessException;
|
||||||
|
import com.arsdigita.bebop.GridPanel;
|
||||||
|
import com.arsdigita.bebop.List;
|
||||||
|
import com.arsdigita.bebop.Page;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.Resettable;
|
||||||
|
import com.arsdigita.bebop.SimpleContainer;
|
||||||
|
import com.arsdigita.bebop.SingleSelectionModel;
|
||||||
|
import com.arsdigita.bebop.event.ActionEvent;
|
||||||
|
import com.arsdigita.bebop.event.ActionListener;
|
||||||
|
import com.arsdigita.bebop.event.ChangeEvent;
|
||||||
|
import com.arsdigita.bebop.event.ChangeListener;
|
||||||
|
import com.arsdigita.bebop.event.FormProcessListener;
|
||||||
|
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||||
|
import com.arsdigita.bebop.Label;
|
||||||
|
import com.arsdigita.bebop.list.ListCellRenderer;
|
||||||
|
import org.librecms.contentsection.ContentType;
|
||||||
|
import com.arsdigita.cms.ItemSelectionModel;
|
||||||
|
import com.arsdigita.cms.ui.ContentItemPage;
|
||||||
|
import com.arsdigita.cms.ui.item.ItemWorkflowRequestLocal;
|
||||||
|
import com.arsdigita.cms.ui.workflow.AssignedTaskSection;
|
||||||
|
import com.arsdigita.cms.ui.workflow.AssignedTaskTable;
|
||||||
|
import com.arsdigita.cms.ui.workflow.TaskFinishForm;
|
||||||
|
import com.arsdigita.cms.ui.workflow.TaskRequestLocal;
|
||||||
|
import com.arsdigita.cms.ui.workflow.WorkflowRequestLocal;
|
||||||
|
import com.arsdigita.globalization.GlobalizedMessage;
|
||||||
|
import com.arsdigita.kernel.KernelConfig;
|
||||||
|
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||||
|
import com.arsdigita.toolbox.ui.ModalPanel;
|
||||||
|
import com.arsdigita.toolbox.ui.Section;
|
||||||
|
import com.arsdigita.util.Assert;
|
||||||
|
import com.arsdigita.util.SequentialMap;
|
||||||
|
import com.arsdigita.util.UncheckedWrapperException;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.arsdigita.cms.CMSConfig;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
import org.libreccm.configuration.ConfigurationManager;
|
||||||
|
import org.librecms.CmsConstants;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contenttypes.AuthoringKit;
|
||||||
|
import org.librecms.contenttypes.AuthoringKitInfo;
|
||||||
|
import org.librecms.contenttypes.AuthoringStepInfo;
|
||||||
|
import org.librecms.contenttypes.ContentTypeInfo;
|
||||||
|
import org.librecms.workflow.CmsTaskType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a single authoring kit. The wizard accepts a
|
||||||
|
* {@link ContentType} in the constructor; it then extracts the
|
||||||
|
* {@link AuthoringKit} for the content type, and creates the components for all
|
||||||
|
* the steps in the kit.
|
||||||
|
*
|
||||||
|
* Note that the individual authoring kit steps must provide the following
|
||||||
|
* constructor:
|
||||||
|
*
|
||||||
|
* <blockquote><pre><code>
|
||||||
|
* public TheClass(ItemSelectionModel model, AuthoringKitWizard parent) { ... }
|
||||||
|
* </code></pre></blockquote>
|
||||||
|
*
|
||||||
|
* This constructor will be called when the component is automatically
|
||||||
|
* instantiated by the <code>AuthoringKitWizard</code>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AuthoringKitWizard extends LayoutPanel implements Resettable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private Logger instance for this class
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(
|
||||||
|
AuthoringKitWizard.class);
|
||||||
|
private static Class[] arguments = new Class[]{
|
||||||
|
ItemSelectionModel.class,
|
||||||
|
AuthoringKitWizard.class
|
||||||
|
};
|
||||||
|
private static Class[] userDefinedArgs = new Class[]{
|
||||||
|
ItemSelectionModel.class,
|
||||||
|
AuthoringKitWizard.class,
|
||||||
|
ContentType.class
|
||||||
|
};
|
||||||
|
private static final java.util.List<AssetStepEntry> ASSETS = new ArrayList<AssetStepEntry>();
|
||||||
|
private final Object[] values;
|
||||||
|
private final ContentTypeInfo typeInfo;
|
||||||
|
private final AuthoringKitInfo kitInfo;
|
||||||
|
private final ItemSelectionModel selectionModel;
|
||||||
|
private final WorkflowRequestLocal workflowRequestLocal;
|
||||||
|
private final AssignedTaskTable assignedTaskTable;
|
||||||
|
private final SequentialMap labels;
|
||||||
|
private final List list;
|
||||||
|
private String defaultKey;
|
||||||
|
private final GridPanel leftPanel;
|
||||||
|
private final ModalPanel bodyPanel;
|
||||||
|
private final SimpleContainer stepsContainer;
|
||||||
|
private final TaskFinishForm m_taskFinishForm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the state parameter that determines whether the wizard is in
|
||||||
|
* item creation mode or item editing mode.
|
||||||
|
*/
|
||||||
|
public static final String IS_EDITING = "is_edit";
|
||||||
|
/**
|
||||||
|
* The key for the item creation step.
|
||||||
|
*/
|
||||||
|
public static final String CREATION = "_creation_";
|
||||||
|
|
||||||
|
private final static String SEC_PAGE_EDIT_DYN = "com.arsdigita.cms.ui.authoring.SecondaryPageEditDynamic";
|
||||||
|
private final static String PAGE_EDIT_DYN = "com.arsdigita.cms.ui.authoring.PageEditDynamic";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new AuthoringKitWizard. Add all the steps in the authoring
|
||||||
|
* kit to the wizard.
|
||||||
|
*
|
||||||
|
* @param typeInfo The content type of the items that this wizard will
|
||||||
|
* handle
|
||||||
|
* @param selectionModel
|
||||||
|
*/
|
||||||
|
public AuthoringKitWizard(final ContentTypeInfo typeInfo,
|
||||||
|
final ItemSelectionModel selectionModel) {
|
||||||
|
LOGGER.debug("Authoring kit wizard for type {} undergoing creation...",
|
||||||
|
Objects.toString(typeInfo));
|
||||||
|
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final ConfigurationManager confManager = cdiUtil.findBean(
|
||||||
|
ConfigurationManager.class);
|
||||||
|
|
||||||
|
this.typeInfo = typeInfo;
|
||||||
|
kitInfo = typeInfo.getAuthoringKit();
|
||||||
|
this.selectionModel = selectionModel;
|
||||||
|
values = new Object[]{selectionModel, this};
|
||||||
|
workflowRequestLocal = new ItemWorkflowRequestLocal();
|
||||||
|
labels = new SequentialMap();
|
||||||
|
|
||||||
|
leftPanel = new GridPanel(1);
|
||||||
|
setLeft(leftPanel);
|
||||||
|
|
||||||
|
assignedTaskTable = new AssignedTaskTable(workflowRequestLocal);
|
||||||
|
|
||||||
|
leftPanel.add(new AssignedTaskSection(workflowRequestLocal,
|
||||||
|
assignedTaskTable));
|
||||||
|
|
||||||
|
final Section stepSection = new Section(gz("cms.ui.authoring.steps"));
|
||||||
|
leftPanel.add(stepSection);
|
||||||
|
|
||||||
|
list = new List();
|
||||||
|
stepSection.setBody(list);
|
||||||
|
|
||||||
|
list.setListData(labels);
|
||||||
|
list.setCellRenderer(new ListCellRenderer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getComponent(List list,
|
||||||
|
PageState state,
|
||||||
|
Object value,
|
||||||
|
String key,
|
||||||
|
int index,
|
||||||
|
boolean isSelected) {
|
||||||
|
final Label label;
|
||||||
|
if (value instanceof GlobalizedMessage) {
|
||||||
|
label = new Label((GlobalizedMessage) value);
|
||||||
|
} else {
|
||||||
|
label = new Label((String) value);
|
||||||
|
}
|
||||||
|
if (isSelected) {
|
||||||
|
label.setFontWeight(Label.BOLD);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
return new ControlLink(label);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bodyPanel = new ModalPanel();
|
||||||
|
setBody(bodyPanel);
|
||||||
|
|
||||||
|
stepsContainer = new SimpleContainer();
|
||||||
|
bodyPanel.add(stepsContainer);
|
||||||
|
bodyPanel.setDefault(stepsContainer);
|
||||||
|
|
||||||
|
final java.util.List<AuthoringStepInfo> steps = kitInfo.
|
||||||
|
getAuthoringSteps();
|
||||||
|
|
||||||
|
if (Assert.isEnabled()) {
|
||||||
|
Assert.isTrue(!steps.isEmpty(),
|
||||||
|
String.format("The authoring kit for content type "
|
||||||
|
+ "s\"%s\" has no steps.",
|
||||||
|
typeInfo.getContentItemClass().getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
final CMSConfig cmsConfig = confManager.findConfiguration(
|
||||||
|
CMSConfig.class);
|
||||||
|
|
||||||
|
StepComponent panel = null;
|
||||||
|
for (final AuthoringStepInfo step : steps) {
|
||||||
|
final String key = step.getComponent().getName();
|
||||||
|
|
||||||
|
if (defaultKey == null) {
|
||||||
|
defaultKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "label" and "description" are only here for backwards
|
||||||
|
* compatibility
|
||||||
|
*/
|
||||||
|
final ResourceBundle labelBundle = ResourceBundle.getBundle(step.
|
||||||
|
getLabelBundle());
|
||||||
|
final ResourceBundle descBundle = ResourceBundle.getBundle(step.
|
||||||
|
getDescriptionBundle());
|
||||||
|
final String labelKey = step.getLabelKey();
|
||||||
|
final String label = labelBundle.getString(labelKey);
|
||||||
|
final String descriptionKey = step.getDescriptionKey();
|
||||||
|
final String description = descBundle.getString(descriptionKey);
|
||||||
|
|
||||||
|
final Class<? extends Component> componentClass = step.
|
||||||
|
getComponent();
|
||||||
|
final String compClassName = componentClass.getName();
|
||||||
|
|
||||||
|
if (panel != null) {
|
||||||
|
panel.setNextStepKey(step.getClass().getName());
|
||||||
|
}
|
||||||
|
panel = new StepComponent(compClassName);
|
||||||
|
stepsContainer.add(panel);
|
||||||
|
final Component comp;
|
||||||
|
|
||||||
|
if (compClassName.equals(SEC_PAGE_EDIT_DYN)
|
||||||
|
|| compClassName.equals(PAGE_EDIT_DYN)) {
|
||||||
|
comp = instantiateUserDefinedStep(compClassName, typeInfo);
|
||||||
|
} else {
|
||||||
|
comp = instantiateStep(compClassName);
|
||||||
|
}
|
||||||
|
panel.add(comp);
|
||||||
|
// XXX should be optional
|
||||||
|
if (comp instanceof AuthoringStepComponent) {
|
||||||
|
((AuthoringStepComponent) comp).addCompletionListener(
|
||||||
|
new StepCompletionListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
final GlobalizedMessage gzLabel;
|
||||||
|
if (labelKey != null) {
|
||||||
|
if (step.getLabelBundle() == null) {
|
||||||
|
gzLabel = gz(labelKey);
|
||||||
|
} else {
|
||||||
|
gzLabel = new GlobalizedMessage(labelKey,
|
||||||
|
step.getLabelBundle());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gzLabel = null;
|
||||||
|
}
|
||||||
|
if (gzLabel == null) {
|
||||||
|
labels.put(key, label);
|
||||||
|
} else {
|
||||||
|
labels.put(key, gzLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Class<? extends ContentItem> typeClass = typeInfo.
|
||||||
|
getContentItemClass();
|
||||||
|
|
||||||
|
final java.util.List<String> skipSteps = cmsConfig.getSkipAssetSteps();
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
for (final String step : skipSteps) {
|
||||||
|
LOGGER.debug("skip step \"{}\"...", step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final AssetStepEntry data : ASSETS) {
|
||||||
|
|
||||||
|
final Class<?> baseObjectType;
|
||||||
|
try {
|
||||||
|
baseObjectType = Class.forName(data.getBaseDataObjectType());
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
}
|
||||||
|
//Class step = (Class) data[1];
|
||||||
|
Class step = data.getStep();
|
||||||
|
LOGGER.debug("possibly adding asset step " + step.getName());
|
||||||
|
if (!skipSteps.contains(step.getName())) {
|
||||||
|
GlobalizedMessage label = data.getLabel();
|
||||||
|
|
||||||
|
if (!typeClass.isAssignableFrom(baseObjectType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (panel != null) {
|
||||||
|
panel.setNextStepKey(step);
|
||||||
|
}
|
||||||
|
panel = new StepComponent(step);
|
||||||
|
stepsContainer.add(panel);
|
||||||
|
|
||||||
|
Component comp = instantiateStep(step.getName());
|
||||||
|
if (comp instanceof AuthoringStepComponent) {
|
||||||
|
((AuthoringStepComponent) comp).addCompletionListener(
|
||||||
|
new StepCompletionListener());
|
||||||
|
}
|
||||||
|
panel.add(comp);
|
||||||
|
|
||||||
|
labels.put(step, label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list.addChangeListener(new StepListener());
|
||||||
|
|
||||||
|
m_taskFinishForm = new TaskFinishForm(new TaskSelectionRequestLocal());
|
||||||
|
bodyPanel.add(m_taskFinishForm);
|
||||||
|
|
||||||
|
bodyPanel.connect(assignedTaskTable, 2, m_taskFinishForm);
|
||||||
|
bodyPanel.connect(m_taskFinishForm);
|
||||||
|
|
||||||
|
m_taskFinishForm.addProcessListener(new FormProcessListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void process(final FormSectionEvent event)
|
||||||
|
throws FormProcessException {
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
|
assignedTaskTable.getRowSelectionModel().clearSelection(state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class StepListener implements ChangeListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void stateChanged(final ChangeEvent event) {
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
final String key = list.getSelectedKey(state).toString();
|
||||||
|
|
||||||
|
final Iterator iter = stepsContainer.children();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
final StepComponent step = (StepComponent) iter.next();
|
||||||
|
|
||||||
|
if (step.getStepKey().toString().equals(key)) {
|
||||||
|
step.setVisible(state, true);
|
||||||
|
} else {
|
||||||
|
step.setVisible(state, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private final class StepCompletionListener implements ActionListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void actionPerformed(final ActionEvent event) {
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
if (ContentItemPage.isStreamlinedCreationActive(state)) {
|
||||||
|
final String key = list.getSelectedKey(state).toString();
|
||||||
|
|
||||||
|
final Iterator iter = stepsContainer.children();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
final StepComponent step = (StepComponent) iter.next();
|
||||||
|
if (step.getStepKey().toString().equals(key)) {
|
||||||
|
Object nextStep = step.getNextStepKey();
|
||||||
|
if (nextStep != null) {
|
||||||
|
list.getSelectionModel().setSelectedKey(
|
||||||
|
state, nextStep.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void register(final Page page) {
|
||||||
|
super.register(page);
|
||||||
|
|
||||||
|
final Iterator iter = stepsContainer.children();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
final StepComponent child = (StepComponent) iter.next();
|
||||||
|
|
||||||
|
page.setVisibleDefault(child, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
page.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void actionPerformed(final ActionEvent event) {
|
||||||
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
|
if (state.isVisibleOnPage(AuthoringKitWizard.this)) {
|
||||||
|
final SingleSelectionModel model = list.
|
||||||
|
getSelectionModel();
|
||||||
|
|
||||||
|
if (!model.isSelected(state)) {
|
||||||
|
model.setSelectedKey(state, defaultKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerAssetStep(final String baseObjectType,
|
||||||
|
final Class step,
|
||||||
|
final GlobalizedMessage label,
|
||||||
|
final GlobalizedMessage description,
|
||||||
|
final int sortKey) {
|
||||||
|
// cg - allow registered steps to be overridden by registering a step with the same label
|
||||||
|
// this is a bit of a hack used specifically for creating a specialised version of image
|
||||||
|
// step. There is no straightforward way of preventing the original image step from being
|
||||||
|
// registered, but I needed the image step to use a different step class if the specialised
|
||||||
|
// image step application was loaded. Solution is to ensure initialiser in new project
|
||||||
|
// runs after original ccm-ldn-image-step initializer and override the registered step here
|
||||||
|
LOGGER.debug("registering asset step - label: \"{}\"; "
|
||||||
|
+ "step class: \"%s\"",
|
||||||
|
label.localize(),
|
||||||
|
step.getName());
|
||||||
|
|
||||||
|
for (final AssetStepEntry data : ASSETS) {
|
||||||
|
|
||||||
|
final String thisObjectType = data.getBaseDataObjectType();
|
||||||
|
final GlobalizedMessage thisLabel = data.getLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jensp 2011-11-14: The code above was only testing for the same
|
||||||
|
* label, but not for the same object type. I don't think that this
|
||||||
|
* was indented since this made it impossible to attach the same
|
||||||
|
* step to different object types. The orginal line was if
|
||||||
|
* (thisLabel.localize().equals(label.localize())) {
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if ((thisObjectType.equals(baseObjectType))
|
||||||
|
&& (thisLabel.localize().equals(label.localize()))) {
|
||||||
|
LOGGER.debug(
|
||||||
|
"registering authoring step with same label as previously registered step");
|
||||||
|
ASSETS.remove(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSETS.add(
|
||||||
|
new AssetStepEntry(baseObjectType, step, label, description,
|
||||||
|
sortKey));
|
||||||
|
Collections.sort(ASSETS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AssetStepEntry implements Comparable<AssetStepEntry> {
|
||||||
|
|
||||||
|
private String baseDataObjectType;
|
||||||
|
private Class step;
|
||||||
|
private GlobalizedMessage label;
|
||||||
|
private GlobalizedMessage description;
|
||||||
|
private Integer sortKey;
|
||||||
|
|
||||||
|
public AssetStepEntry() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssetStepEntry(final String baseDataObjectType,
|
||||||
|
final Class step,
|
||||||
|
final GlobalizedMessage label,
|
||||||
|
final GlobalizedMessage description,
|
||||||
|
final Integer sortKey) {
|
||||||
|
this.baseDataObjectType = baseDataObjectType;
|
||||||
|
this.step = step;
|
||||||
|
this.label = label;
|
||||||
|
this.description = description;
|
||||||
|
this.sortKey = sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBaseDataObjectType() {
|
||||||
|
return baseDataObjectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBaseDataObjectType(final String baseDataObjectType) {
|
||||||
|
this.baseDataObjectType = baseDataObjectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getStep() {
|
||||||
|
return step;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStep(final Class step) {
|
||||||
|
this.step = step;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalizedMessage getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(final GlobalizedMessage label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalizedMessage getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(final GlobalizedMessage description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSortKey() {
|
||||||
|
return sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortKey(final Integer sortKey) {
|
||||||
|
this.sortKey = sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(final AssetStepEntry other) {
|
||||||
|
if ((int) sortKey == (int) other.getSortKey()) {
|
||||||
|
return step.getName().compareTo(other.getStep().getName());
|
||||||
|
} else {
|
||||||
|
return sortKey.compareTo(other.getSortKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The content type handled by this wizard
|
||||||
|
*/
|
||||||
|
public ContentTypeInfo getContentType() {
|
||||||
|
return typeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List getList() {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The authoring kit which is represented by this wizard
|
||||||
|
*/
|
||||||
|
public AuthoringKitInfo getAuthoringKit() {
|
||||||
|
return kitInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The ItemSelectionModel used by the steps in this wizard
|
||||||
|
*/
|
||||||
|
public ItemSelectionModel getItemSelectionModel() {
|
||||||
|
return selectionModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate the specified authoring kit step. Will throw a
|
||||||
|
* RuntimeException on failure.
|
||||||
|
*
|
||||||
|
* @param className The Java class name of the step
|
||||||
|
* @return The instance of the component.
|
||||||
|
*/
|
||||||
|
protected Component instantiateStep(final String className) {
|
||||||
|
LOGGER.debug("Instantiating kit wizard \"{}\" with arguments {}...",
|
||||||
|
className,
|
||||||
|
arguments);
|
||||||
|
|
||||||
|
Object[] vals;
|
||||||
|
try {
|
||||||
|
// Get the creation component
|
||||||
|
final Class createClass = Class.forName(className);
|
||||||
|
final Constructor constr = createClass.getConstructor(arguments);
|
||||||
|
final Component component = (Component) constr.newInstance(values);
|
||||||
|
|
||||||
|
return component;
|
||||||
|
} catch (ClassNotFoundException
|
||||||
|
| IllegalAccessException
|
||||||
|
| IllegalArgumentException
|
||||||
|
| InstantiationException
|
||||||
|
| InvocationTargetException
|
||||||
|
| NoSuchMethodException
|
||||||
|
| SecurityException ex) {
|
||||||
|
throw new UncheckedWrapperException(String.format(
|
||||||
|
"Failed to instantiate authoring kit component \"{}\".",
|
||||||
|
className),
|
||||||
|
ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate the specified authoring kit step for a user defined content
|
||||||
|
* type. Will throw a RuntimeException on failure.
|
||||||
|
*
|
||||||
|
* @param className The Java class name of the step
|
||||||
|
* @param originatingType
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected Component instantiateUserDefinedStep(
|
||||||
|
final String className, final ContentTypeInfo originatingType) {
|
||||||
|
|
||||||
|
Object[] vals;
|
||||||
|
try {
|
||||||
|
// Get the creation component
|
||||||
|
final Class createClass = Class.forName(className);
|
||||||
|
final Constructor constr = createClass.getConstructor(
|
||||||
|
userDefinedArgs);
|
||||||
|
final Object[] userDefinedVals = new Object[]{selectionModel,
|
||||||
|
this,
|
||||||
|
originatingType};
|
||||||
|
final Component component = (Component) constr.newInstance(
|
||||||
|
userDefinedVals);
|
||||||
|
|
||||||
|
return component;
|
||||||
|
} catch (ClassNotFoundException | NoSuchMethodException
|
||||||
|
| InstantiationException | IllegalAccessException
|
||||||
|
| InvocationTargetException ex) {
|
||||||
|
throw new UncheckedWrapperException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the state of this wizard
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final void reset(final PageState state) {
|
||||||
|
list.setSelectedKey(state, defaultKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class StepComponent extends SimpleContainer {
|
||||||
|
|
||||||
|
private final Object key;
|
||||||
|
private Object nextKey;
|
||||||
|
|
||||||
|
public StepComponent(final Object key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getStepKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getNextStepKey() {
|
||||||
|
return nextKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNextStepKey(final Object nextKey) {
|
||||||
|
this.nextKey = nextKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TaskSelectionRequestLocal extends TaskRequestLocal {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Object initialValue(final PageState state) {
|
||||||
|
final String key = assignedTaskTable
|
||||||
|
.getRowSelectionModel()
|
||||||
|
.getSelectedKey(state)
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
return CmsTaskType.valueOf(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final static GlobalizedMessage gz(final String key) {
|
||||||
|
return new GlobalizedMessage(key, CmsConstants.CMS_BUNDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final static String lz(final String key) {
|
||||||
|
return (String) gz(key).localize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.authoring;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.event.ActionListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface which authoring step components should implement. It's
|
||||||
|
* currently an optional interface.
|
||||||
|
*
|
||||||
|
* @author Scott Seago (sseago@redhat.com)
|
||||||
|
* @version $Revision: #4 $ $DateTime: 2004/08/17 23:15:09 $
|
||||||
|
*/
|
||||||
|
public interface AuthoringStepComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a completion listener to this component
|
||||||
|
*/
|
||||||
|
void addCompletionListener(ActionListener listener);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.authoring;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.Label;
|
||||||
|
import com.arsdigita.bebop.form.Option;
|
||||||
|
import com.arsdigita.bebop.form.SingleSelect;
|
||||||
|
import com.arsdigita.bebop.parameters.ParameterModel;
|
||||||
|
import com.arsdigita.bebop.parameters.StringParameter;
|
||||||
|
import org.librecms.util.LanguageUtil;
|
||||||
|
import com.arsdigita.globalization.GlobalizedMessage;
|
||||||
|
import com.arsdigita.util.Pair;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.libreccm.cdi.utils.CdiUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Language picker for the multilingual content items.
|
||||||
|
*/
|
||||||
|
public class LanguageWidget extends SingleSelect {
|
||||||
|
|
||||||
|
public LanguageWidget(String name) {
|
||||||
|
this(new StringParameter(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public LanguageWidget(ParameterModel model) {
|
||||||
|
super(model);
|
||||||
|
setupOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds list of languages. Default version shows all supported languages for
|
||||||
|
* this CMS installation, as defined in the enterprise.init:
|
||||||
|
* com.arsdigita.cms.installer.Initializer: languages
|
||||||
|
*/
|
||||||
|
protected void setupOptions() {
|
||||||
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
|
final LanguageUtil languageUtil = cdiUtil.findBean(LanguageUtil.class);
|
||||||
|
final List<Pair> languages = languageUtil.convertToG11N(languageUtil.
|
||||||
|
getSupportedLanguages2LA());
|
||||||
|
for(final Pair pair : languages) {
|
||||||
|
final String langCode = (String) pair.getKey();
|
||||||
|
final GlobalizedMessage langName = (GlobalizedMessage) pair.getValue();
|
||||||
|
|
||||||
|
addOption(new Option(langCode, new Label(langName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -57,7 +57,7 @@ import java.math.BigDecimal;
|
||||||
public class WizardSelector extends AuthoringKitSelector
|
public class WizardSelector extends AuthoringKitSelector
|
||||||
implements Resettable {
|
implements Resettable {
|
||||||
|
|
||||||
private ItemSelectionModel itemSelectionModel;
|
private final ItemSelectionModel itemSelectionModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new WizardSelector. Load all the possible authoring kits from
|
* Construct a new WizardSelector. Load all the possible authoring kits from
|
||||||
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
* 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.item;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.BoxPanel;
|
||||||
|
import com.arsdigita.bebop.Form;
|
||||||
|
import com.arsdigita.bebop.FormProcessException;
|
||||||
|
import com.arsdigita.bebop.Label;
|
||||||
|
import com.arsdigita.bebop.PageState;
|
||||||
|
import com.arsdigita.bebop.event.FormProcessListener;
|
||||||
|
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||||
|
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.bebop.form.Submit;
|
||||||
|
import org.librecms.contentsection.ContentItem;
|
||||||
|
import org.librecms.contentsection.ContentSection;
|
||||||
|
import org.librecms.contentsection.ContentType;
|
||||||
|
import com.arsdigita.cms.ItemSelectionModel;
|
||||||
|
import com.arsdigita.cms.ui.ContentItemPage;
|
||||||
|
import com.arsdigita.cms.ui.authoring.LanguageWidget;
|
||||||
|
import org.librecms.util.LanguageUtil;
|
||||||
|
import com.arsdigita.globalization.GlobalizedMessage;
|
||||||
|
import com.arsdigita.toolbox.ui.ActionGroup;
|
||||||
|
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||||
|
import com.arsdigita.toolbox.ui.Section;
|
||||||
|
import com.arsdigita.util.Assert;
|
||||||
|
import com.arsdigita.util.Pair;
|
||||||
|
import com.arsdigita.util.UncheckedWrapperException;
|
||||||
|
import com.arsdigita.web.RedirectSignal;
|
||||||
|
import com.arsdigita.web.URL;
|
||||||
|
import org.libreccm.workflow.Workflow;
|
||||||
|
import org.libreccm.workflow.WorkflowTemplate;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.TooManyListenersException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the "Language instances" pane, with all the language instances in
|
||||||
|
* the Bundle.
|
||||||
|
*
|
||||||
|
* @author Alan Pevec (apevec@redhat.com)
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
public class ItemLanguages extends LayoutPanel {
|
||||||
|
|
||||||
|
private final ItemSelectionModel selectionModel;
|
||||||
|
private final LanguageWidget languageWidget;
|
||||||
|
private final Submit changeSubmit;
|
||||||
|
private final Submit createSubmit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new <code>ItemLanguages</code>.
|
||||||
|
*
|
||||||
|
* @param selectionModel the {@link ItemSelectionModel} which will supply the current
|
||||||
|
* item
|
||||||
|
*/
|
||||||
|
public ItemLanguages(final ItemSelectionModel selectionModel) {
|
||||||
|
this.selectionModel = selectionModel;
|
||||||
|
|
||||||
|
final Section section = new Section(gz("cms.ui.item.languages"));
|
||||||
|
setBody(section);
|
||||||
|
|
||||||
|
final ActionGroup group = new ActionGroup();
|
||||||
|
section.setBody(group);
|
||||||
|
|
||||||
|
group.setSubject(new ItemLanguagesTable(selectionModel));
|
||||||
|
|
||||||
|
final Form form = new Form("newLanguage", new BoxPanel(
|
||||||
|
BoxPanel.HORIZONTAL));
|
||||||
|
group.addAction(form);
|
||||||
|
|
||||||
|
form.setRedirecting(true);
|
||||||
|
languageWidget = new LanguageWidget(ContentItem.LANGUAGE) {
|
||||||
|
protected void setupOptions() {
|
||||||
|
// Don't do anything.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
languageWidget.addPrintListener(new OptionPrinter());
|
||||||
|
} catch (TooManyListenersException tmle) {
|
||||||
|
new UncheckedWrapperException(tmle);
|
||||||
|
}
|
||||||
|
|
||||||
|
form.add(languageWidget);
|
||||||
|
changeSubmit = new Submit("change", gz("cms.ui.item.language.change"));
|
||||||
|
form.add(changeSubmit);
|
||||||
|
createSubmit = new Submit("create", gz("cms.ui.item.language.add"));
|
||||||
|
form.add(createSubmit);
|
||||||
|
form.addProcessListener(new ProcessListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers only languages not yet present in the bundle.
|
||||||
|
*/
|
||||||
|
private class OptionPrinter implements PrintListener {
|
||||||
|
|
||||||
|
public final void prepare(final PrintEvent e) {
|
||||||
|
final PageState state = e.getPageState();
|
||||||
|
final OptionGroup optionGroup = (OptionGroup) e.getTarget();
|
||||||
|
final ContentPage item = (ContentPage) selectionModel.
|
||||||
|
getSelectedItem(state);
|
||||||
|
final Collection languages = LanguageUtil.convertToG11N(
|
||||||
|
LanguageUtil.getCreatableLanguages(item));
|
||||||
|
|
||||||
|
for (Iterator iter = languages.iterator(); iter.hasNext();) {
|
||||||
|
final Pair pair = (Pair) iter.next();
|
||||||
|
final String langCode = (String) pair.getKey();
|
||||||
|
final GlobalizedMessage langName
|
||||||
|
= (GlobalizedMessage) pair.getValue();
|
||||||
|
optionGroup.addOption(new Option(langCode, new Label(langName)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new language instance to the bundle.
|
||||||
|
*/
|
||||||
|
private class ProcessListener implements FormProcessListener {
|
||||||
|
|
||||||
|
public final void process(final FormSectionEvent e)
|
||||||
|
throws FormProcessException {
|
||||||
|
PageState state = e.getPageState();
|
||||||
|
String lang = (String) languageWidget.getValue(state);
|
||||||
|
ContentPage item = (ContentPage) selectionModel.getSelectedItem(state);
|
||||||
|
ContentBundle bundle = item.getContentBundle();
|
||||||
|
String name = bundle.getName();
|
||||||
|
|
||||||
|
if (createSubmit.isSelected(state)) {
|
||||||
|
ContentSection section = item.getContentSection();
|
||||||
|
|
||||||
|
Assert.exists(section, ContentSection.class);
|
||||||
|
|
||||||
|
ContentType type = item.getContentType();
|
||||||
|
|
||||||
|
item = (ContentPage) item.copy(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
|
||||||
|
final String target = URL.getDispatcherPath() + ContentItemPage.
|
||||||
|
getItemURL(item,
|
||||||
|
ContentItemPage.AUTHORING_TAB);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return GlobalizationUtil.globalize(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final String lz(final String key) {
|
||||||
|
return (String) gz(key).localize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
/*
|
||||||
|
* 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.item;
|
||||||
|
|
||||||
|
import com.arsdigita.bebop.*;
|
||||||
|
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.ItemSelectionModel;
|
||||||
|
import com.arsdigita.cms.dispatcher.MultilingualItemResolver;
|
||||||
|
import com.arsdigita.cms.ui.ContentItemPage;
|
||||||
|
import org.librecms.util.LanguageUtil;
|
||||||
|
import com.arsdigita.toolbox.ui.DataTable;
|
||||||
|
import com.arsdigita.util.LockableImpl;
|
||||||
|
import com.arsdigita.web.RedirectSignal;
|
||||||
|
import com.arsdigita.web.URL;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a list of all language instances of an item.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ItemLanguagesTable extends DataTable {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ItemLanguagesTable.class);
|
||||||
|
private final ItemSelectionModel m_model;
|
||||||
|
private final TableColumn m_deleteColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new
|
||||||
|
* <code>ItemHistoryTable</code>
|
||||||
|
*
|
||||||
|
* @param model the ItemSelectionModel that supplies the current item
|
||||||
|
*/
|
||||||
|
public ItemLanguagesTable(ItemSelectionModel model) {
|
||||||
|
super(new LanguagesBuilder(model));
|
||||||
|
m_model = model;
|
||||||
|
|
||||||
|
addColumn("cms.ui.language.header",
|
||||||
|
ContentPage.LANGUAGE,
|
||||||
|
false,
|
||||||
|
new LanguageCellRenderer(m_model));
|
||||||
|
addColumn("cms.ui.title",
|
||||||
|
ContentPage.TITLE);
|
||||||
|
m_deleteColumn = addColumn("cms.ui.action", new ActionCellRenderer(
|
||||||
|
m_model));
|
||||||
|
setResourceBundle(GlobalizationUtil.getBundleName());
|
||||||
|
addTableActionListener(new InstanceDeleter(m_model));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the query for all the language instances in the current Bundle
|
||||||
|
*/
|
||||||
|
private static class LanguagesBuilder extends LockableImpl
|
||||||
|
implements DataQueryBuilder {
|
||||||
|
|
||||||
|
ItemSelectionModel m_model;
|
||||||
|
|
||||||
|
public LanguagesBuilder(ItemSelectionModel model) {
|
||||||
|
super();
|
||||||
|
m_model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataQuery makeDataQuery(DataTable t, PageState s) {
|
||||||
|
ContentPage multiLingual =
|
||||||
|
(ContentPage) m_model.getSelectedObject(s);
|
||||||
|
DataQuery q = SessionManager.getSession().retrieveQuery(
|
||||||
|
"com.arsdigita.cms.getBundledItems");
|
||||||
|
q.setParameter("bundleID", multiLingual.getContentBundle().getID());
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyColumn() {
|
||||||
|
return ContentPage.ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the full language name.
|
||||||
|
*/
|
||||||
|
private static class LanguageCellRenderer implements TableCellRenderer {
|
||||||
|
|
||||||
|
private ItemSelectionModel m_model;
|
||||||
|
|
||||||
|
public LanguageCellRenderer(ItemSelectionModel model) {
|
||||||
|
m_model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getComponent(Table table, PageState state, Object value,
|
||||||
|
boolean isSelected, Object key,
|
||||||
|
int row, int column) {
|
||||||
|
|
||||||
|
BigDecimal id = (BigDecimal) key;
|
||||||
|
ContentPage cp;
|
||||||
|
|
||||||
|
try {
|
||||||
|
cp = new ContentPage(id);
|
||||||
|
} catch (DataObjectNotFoundException ex) {
|
||||||
|
// Content item was not found, return nothing
|
||||||
|
return new Label();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBundle bundle = cp.getContentBundle();
|
||||||
|
|
||||||
|
if (bundle != null
|
||||||
|
&& !(cp instanceof LanguageInvariantContentItem
|
||||||
|
&& ((LanguageInvariantContentItem) cp).isLanguageInvariant())) {
|
||||||
|
|
||||||
|
StringBuilder fontWeight = new StringBuilder(2);
|
||||||
|
StringBuilder classes = new StringBuilder(20);
|
||||||
|
|
||||||
|
if (cp.isLive()) {
|
||||||
|
fontWeight.append(Label.BOLD);
|
||||||
|
classes.append("live ");
|
||||||
|
}
|
||||||
|
if (bundle.getPrimaryInstance().equals(cp)) {
|
||||||
|
fontWeight.append(Label.ITALIC);
|
||||||
|
classes.append("primaryInstance");
|
||||||
|
}
|
||||||
|
|
||||||
|
String target = ContentItemPage.getItemURL(cp, ContentItemPage.AUTHORING_TAB);
|
||||||
|
Label langLabel = new Label(LanguageUtil.getLangFull((String) value));
|
||||||
|
|
||||||
|
langLabel.setFontWeight(fontWeight.toString().trim());
|
||||||
|
langLabel.setClassAttr(classes.toString().trim());
|
||||||
|
|
||||||
|
if (m_model.getSelectedKey(state).equals(key)) {
|
||||||
|
// Current instance: no link
|
||||||
|
return langLabel;
|
||||||
|
} else {
|
||||||
|
return new Link(langLabel, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Label();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete language instance action link.
|
||||||
|
*/
|
||||||
|
private static class ActionCellRenderer implements TableCellRenderer {
|
||||||
|
|
||||||
|
private static final Logger logger =
|
||||||
|
Logger.getLogger(ActionCellRenderer.class);
|
||||||
|
private static final Label s_noAction;
|
||||||
|
private static final Label s_primary;
|
||||||
|
private static final ControlLink s_link;
|
||||||
|
|
||||||
|
static {
|
||||||
|
logger.debug("Static initializer is starting...");
|
||||||
|
s_noAction = new Label(" ", false);
|
||||||
|
s_noAction.lock();
|
||||||
|
s_primary = new Label(GlobalizationUtil.globalize(
|
||||||
|
"cms.ui.primary_instance"), false);
|
||||||
|
s_primary.lock();
|
||||||
|
s_link = new ControlLink(new Label(GlobalizationUtil.globalize(
|
||||||
|
"cms.ui.delete")));
|
||||||
|
s_link.setConfirmation(GlobalizationUtil.globalize(
|
||||||
|
"cms.ui.delete_confirmation"));
|
||||||
|
logger.debug("Static initalizer finished.");
|
||||||
|
}
|
||||||
|
private ItemSelectionModel m_model;
|
||||||
|
|
||||||
|
public ActionCellRenderer(ItemSelectionModel model) {
|
||||||
|
m_model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getComponent(Table table, PageState state, Object value,
|
||||||
|
boolean isSelected, Object key,
|
||||||
|
int row, int column) {
|
||||||
|
// check if primary instance
|
||||||
|
BigDecimal id = new BigDecimal(key.toString());
|
||||||
|
OID oid = new OID(ContentPage.BASE_DATA_OBJECT_TYPE, id);
|
||||||
|
try {
|
||||||
|
ContentPage item = (ContentPage) DomainObjectFactory.newInstance(oid);
|
||||||
|
if (item.getLanguage().equals(
|
||||||
|
item.getContentBundle().getDefaultLanguage())) {
|
||||||
|
return s_primary;
|
||||||
|
} else if (item.isLive()) {
|
||||||
|
return s_noAction;
|
||||||
|
}
|
||||||
|
} catch (DataObjectNotFoundException ex) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Could not get item with id " + id);
|
||||||
|
}
|
||||||
|
return s_noAction;
|
||||||
|
}
|
||||||
|
return s_link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete one language instance
|
||||||
|
private class InstanceDeleter extends TableActionAdapter {
|
||||||
|
|
||||||
|
private ItemSelectionModel m_model;
|
||||||
|
|
||||||
|
public InstanceDeleter(ItemSelectionModel model) {
|
||||||
|
m_model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cellSelected(TableActionEvent e) {
|
||||||
|
int col = e.getColumn().intValue();
|
||||||
|
|
||||||
|
if (m_deleteColumn != getColumn(col)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PageState s = e.getPageState();
|
||||||
|
BigDecimal id = new BigDecimal(e.getRowKey().toString());
|
||||||
|
|
||||||
|
OID oid = new OID(ContentPage.BASE_DATA_OBJECT_TYPE, id);
|
||||||
|
try {
|
||||||
|
ContentPage item =
|
||||||
|
(ContentPage) DomainObjectFactory.newInstance(oid);
|
||||||
|
ContentBundle bundle = item.getContentBundle();
|
||||||
|
bundle.removeInstance(item);
|
||||||
|
item.delete();
|
||||||
|
|
||||||
|
if (m_model.getSelectedKey(s).equals(id)) {
|
||||||
|
throw new RedirectSignal(
|
||||||
|
URL.there((new MultilingualItemResolver()
|
||||||
|
.generateItemURL(s,
|
||||||
|
bundle.getPrimaryInstance(),
|
||||||
|
bundle.getContentSection(),
|
||||||
|
ContentItem.DRAFT)),
|
||||||
|
null),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
} catch (com.arsdigita.domain.DataObjectNotFoundException ex) {
|
||||||
|
// Object not found is ok, it has probably been deleted already
|
||||||
|
}
|
||||||
|
((Table) e.getSource()).clearSelection(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -135,6 +135,13 @@ public class ContentItemL10NManager {
|
||||||
return collectLanguages(item).contains(locale);
|
return collectLanguages(item).contains(locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public Set<Locale> creatableLocales(final ContentItem item) {
|
||||||
|
return supportedLocales.stream()
|
||||||
|
.filter(locale -> hasLanguage(item, locale))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a language to a content item. The method will retrieve all fields of
|
* Adds a language to a content item. The method will retrieve all fields of
|
||||||
* the type {@link LocalizedString} from the item and add a new entry for
|
* the type {@link LocalizedString} from the item and add a new entry for
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue