- The list of content types on the NewItemForm is now sorted by the localised

names of the content types
- The length of the description of (releated) link is now limited. The limit 
  can be configured using the com.arsdigita.cms.link_description_max_length 
  property in CMSConfig. The default value are 400 characters.


git-svn-id: https://svn.libreccm.org/ccm/trunk@2769 8810af33-2d31-482b-a856-94f89814c4df
master
jensp 2014-07-22 08:46:01 +00:00
parent 725f60d768
commit 9b70cf8018
12 changed files with 1653 additions and 1516 deletions

View File

@ -42,43 +42,41 @@ import com.arsdigita.util.Assert;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
/** /**
* Form to edit the basic properties of a RelatedLink. This form * Form to edit the basic properties of a RelatedLink. This form extends LinkPropertyForm in order
* extends LinkPropertyForm in order to create items of the correct * to create items of the correct subclass and set the linkOwner property. Users have found the
* subclass and set the linkOwner property. Users have found the additional * additional fields confusing at authoring time (resourceSize and resourceType) so we have added a
* fields confusing at authoring time (resourceSize and resourceType) so we * configuration parameter that allows us to hide them on a site wide basis.
* have added a configuration parameter that allows us to hide them on a *
* site wide basis.
* @version $Revision: #3 $ $Date: 2004/03/30 $ * @version $Revision: #3 $ $Date: 2004/03/30 $
* @author Scott Seago (sseago@redhat.com) * @author Scott Seago (sseago@redhat.com)
*/ */
public class RelatedLinkPropertyForm extends LinkPropertyForm { public class RelatedLinkPropertyForm extends LinkPropertyForm {
private static final Logger logger = Logger.getLogger( private static final Logger logger = Logger.getLogger(
RelatedLinkPropertyForm.class); RelatedLinkPropertyForm.class);
private static boolean isHideNewTargetWindow = private static boolean isHideNewTargetWindow = RelatedLinkConfig.getInstance()
RelatedLinkConfig.getInstance() .isHideNewTargetWindow();
.isHideNewTargetWindow(); private static boolean isHideAdditionalResourceFields = RelatedLinkConfig.getInstance()
private static boolean isHideAdditionalResourceFields = .isHideAdditionalResourceFields();
RelatedLinkConfig.getInstance()
.isHideAdditionalResourceFields();
private String m_linkListName; private String m_linkListName;
/** /**
* Creates a new form to edit the RelatedLink object specified * Creates a new form to edit the RelatedLink object specified by the item selection model
* by the item selection model passed in. * passed in.
* @param itemModel The ItemSelectionModel to use to obtain the *
* ContentItem to which this link is (or will be) attached * @param itemModel The ItemSelectionModel to use to obtain the ContentItem to which this link
* @param link The LinkSelectionModel to use to obtain the * is (or will be) attached
* Link to work on * @param link The LinkSelectionModel to use to obtain the Link to work on
*/ */
public RelatedLinkPropertyForm(ItemSelectionModel itemModel, public RelatedLinkPropertyForm(ItemSelectionModel itemModel,
LinkSelectionModel link, String linkListName) { LinkSelectionModel link, String linkListName) {
this(itemModel, link, linkListName, null); this(itemModel, link, linkListName, null);
} }
public RelatedLinkPropertyForm(ItemSelectionModel itemModel, public RelatedLinkPropertyForm(ItemSelectionModel itemModel,
LinkSelectionModel link, String linkListName, ContentType contentType) { LinkSelectionModel link, String linkListName,
ContentType contentType) {
super(itemModel, link, contentType); super(itemModel, link, contentType);
logger.debug(String.format("linkListName = %s", linkListName)); logger.debug(String.format("linkListName = %s", linkListName));
@ -110,27 +108,25 @@ public class RelatedLinkPropertyForm extends LinkPropertyForm {
// Do nothing except protect the poor users from themselves. // Do nothing except protect the poor users from themselves.
} else { } else {
add(new Label(RelatedLinkGlobalizationUtil.globalize( add(new Label(RelatedLinkGlobalizationUtil.globalize(
"cms.contentassets.ui.related_link.resource_size"))); "cms.contentassets.ui.related_link.resource_size")));
TextField resSize = new TextField(new TextField resSize = new TextField(new StringParameter(RelatedLink.RESOURCE_SIZE));
StringParameter(RelatedLink.RESOURCE_SIZE));
add(resSize); add(resSize);
add(new Label(RelatedLinkGlobalizationUtil.globalize( add(new Label(RelatedLinkGlobalizationUtil.globalize(
"cms.contentassets.ui.related_link.resource_type"))); "cms.contentassets.ui.related_link.resource_type")));
SingleSelect resType = new SingleSelect(new SingleSelect resType = new SingleSelect(new StringParameter(RelatedLink.RESOURCE_TYPE));
StringParameter(RelatedLink.RESOURCE_TYPE));
addMimeOptions(resType); addMimeOptions(resType);
add(resType); add(resType);
} }
Hidden linkListName = new Hidden(new StringParameter( Hidden linkListName = new Hidden(new StringParameter(
RelatedLink.LINK_LIST_NAME)); RelatedLink.LINK_LIST_NAME));
add(linkListName); add(linkListName);
} }
/** /**
* Add mime-type options to the option group by loading all mime * Add mime-type options to the option group by loading all mime types which match a certain
* types which match a certain prefix from the database * prefix from the database
* *
* @param w The mime type widget to which options should be added * @param w The mime type widget to which options should be added
* *
@ -145,10 +141,11 @@ public class RelatedLinkPropertyForm extends LinkPropertyForm {
} }
/** /**
* Take care of basic RelatedLink creation steps. Creates the * Take care of basic RelatedLink creation steps. Creates the RelatedLink and sets the linkOwner
* RelatedLink and sets the linkOwner property. * property.
* *
* @param s the PageState * @param s the PageState
*
* @return the newly-created RelatedLink * @return the newly-created RelatedLink
*/ */
@Override @Override
@ -166,8 +163,8 @@ public class RelatedLinkPropertyForm extends LinkPropertyForm {
} }
/** /**
* Over-ride super class method to initialize addtional fields specific * Over-ride super class method to initialize addtional fields specific to
* to <code>RelatedLink</code> content asset. * <code>RelatedLink</code> content asset.
*/ */
@Override @Override
public void init(FormSectionEvent fse) throws FormProcessException { public void init(FormSectionEvent fse) throws FormProcessException {
@ -197,8 +194,7 @@ public class RelatedLinkPropertyForm extends LinkPropertyForm {
} }
/** /**
* over-ride super class method to set extended properties for * over-ride super class method to set extended properties for <code>RelatedLink</code>.
* <code>RelatedLink</code>.
*/ */
@Override @Override
protected void setLinkProperties(Link link, FormSectionEvent fse) { protected void setLinkProperties(Link link, FormSectionEvent fse) {
@ -217,10 +213,11 @@ public class RelatedLinkPropertyForm extends LinkPropertyForm {
rl.setLinkListName((String) data.get(RelatedLink.LINK_LIST_NAME)); rl.setLinkListName((String) data.get(RelatedLink.LINK_LIST_NAME));
DataCollection links = RelatedLink.getRelatedLinks( DataCollection links = RelatedLink.getRelatedLinks(
getContentItem(fse.getPageState()), getContentItem(fse.getPageState()),
m_linkListName); m_linkListName);
rl.setOrder((int) links.size() + 1); rl.setOrder((int) links.size() + 1);
super.setLinkProperties(link, fse); super.setLinkProperties(link, fse);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -355,3 +355,8 @@ com.arsdigita.cms.xml.cache.age.title=Maximum age of an entry in the XML cache
com.arsdigita.cms.xml.cache.age.purpose=Maximum age of an entry in the XML cache com.arsdigita.cms.xml.cache.age.purpose=Maximum age of an entry in the XML cache
com.arsdigita.cms.xml.cache.age.example=60*60*24 com.arsdigita.cms.xml.cache.age.example=60*60*24
com.arsdigita.cms.xml.cache.age.format=[integer] com.arsdigita.cms.xml.cache.age.format=[integer]
com.arsdigita.cms.link_description_max_length.title=Maximum length of the description of a link.
com.arsdigita.cms.link_description_max_length.purpose=Maximum length of the description of a link.
com.arsdigita.cms.link_description_max_length.example=400
com.arsdigita.cms.link_description_max_length.format={Integer]

View File

@ -41,6 +41,8 @@ import com.arsdigita.bebop.form.Fieldset;
import com.arsdigita.bebop.form.TextArea; import com.arsdigita.bebop.form.TextArea;
import com.arsdigita.bebop.form.TextField; import com.arsdigita.bebop.form.TextField;
import com.arsdigita.bebop.parameters.NotNullValidationListener; import com.arsdigita.bebop.parameters.NotNullValidationListener;
import com.arsdigita.bebop.parameters.StringLengthValidationListener;
import com.arsdigita.cms.CMSConfig;
import com.arsdigita.cms.ContentBundle; import com.arsdigita.cms.ContentBundle;
import com.arsdigita.util.Assert; import com.arsdigita.util.Assert;
import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.util.UncheckedWrapperException;
@ -60,20 +62,22 @@ import java.net.URL;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
/** /**
* Form to edit the basic properties of an Link. This form can be extended to * Form to edit the basic properties of an Link. This form can be extended to create forms for Link
* create forms for Link subclasses. * subclasses.
* *
* @version $Revision: #5 $ $Date: 2004/08/17 $ * @version $Revision: #5 $ $Date: 2004/08/17 $
* @author Nobuko Asakai (nasakai@redhat.com) * @author Nobuko Asakai (nasakai@redhat.com)
* @author Sören Bernstein <quasi@quasiweb.de> * @author Sören Bernstein <quasi@quasiweb.de>
*/ */
public class LinkPropertyForm extends FormSection public class LinkPropertyForm extends FormSection
implements FormInitListener, FormProcessListener, implements FormInitListener, FormProcessListener,
FormValidationListener, FormSubmissionListener { FormValidationListener, FormSubmissionListener {
private static final Logger s_log = Logger.getLogger(LinkPropertyForm.class); private static final Logger s_log = Logger.getLogger(LinkPropertyForm.class);
/** Name of this form */ /**
* Name of this form
*/
public static final String ID = "link_edit"; public static final String ID = "link_edit";
public static final String SSL_PROTOCOL = "https://"; public static final String SSL_PROTOCOL = "https://";
public static final String HTTP_PROTOCOL = "http://"; public static final String HTTP_PROTOCOL = "http://";
@ -90,14 +94,13 @@ public class LinkPropertyForm extends FormSection
private ContentType m_contentType; private ContentType m_contentType;
protected final String ITEM_SEARCH = "contentItem"; protected final String ITEM_SEARCH = "contentItem";
/** /**
* Constructor creates a new form to edit the Link object specified by the * Constructor creates a new form to edit the Link object specified by the item selection model
* item selection model passed in. * passed in.
* *
* @param itemModel The ItemSelectionModel to use to obtain the ContentItem * @param itemModel The ItemSelectionModel to use to obtain the ContentItem to which this link
* to which this link is (or will be) attached * is (or will be) attached
* @param link The LinkSelectionModel to use to obtain the Link to work on * @param link The LinkSelectionModel to use to obtain the Link to work on
*/ */
public LinkPropertyForm(ItemSelectionModel itemModel, public LinkPropertyForm(ItemSelectionModel itemModel,
LinkSelectionModel link) { LinkSelectionModel link) {
@ -105,8 +108,8 @@ public class LinkPropertyForm extends FormSection
} }
/** /**
* Constructor creates a new form to edit the Link object specified by the * Constructor creates a new form to edit the Link object specified by the item selection model
* item selection model passed in. * passed in.
* *
* @param itemModel * @param itemModel
* @param link * @param link
@ -149,13 +152,15 @@ public class LinkPropertyForm extends FormSection
m_description = new TextArea("description"); m_description = new TextArea("description");
m_description.setCols(40); m_description.setCols(40);
m_description.setRows(5); m_description.setRows(5);
m_description.addValidationListener(new StringLengthValidationListener(CMSConfig
.getInstanceOf().getLinkDescMaxLength()));
add(new Label(GlobalizationUtil.globalize( add(new Label(GlobalizationUtil.globalize(
"cms.contenttypes.ui.description"))); "cms.contenttypes.ui.description")));
add(m_description); add(m_description);
//add(new Label( //add(new Label(
add(new Embedded( add(new Embedded(
"<script language=\"javascript\">\n" "<script language=\"javascript\">\n"
+ "<!-- \n" + "<!-- \n"
+ "function toggle_link_fields(status) { \n" + "function toggle_link_fields(status) { \n"
+ "// document.forms['linkEditForm'].targetURI.disabled = status; \n" + "// document.forms['linkEditForm'].targetURI.disabled = status; \n"
@ -183,11 +188,11 @@ public class LinkPropertyForm extends FormSection
+ "} \n" + "} \n"
+ "// -->\n" + "// -->\n"
+ "</script>\n", + "</script>\n",
false)); false));
/* Sub-title external URL / internal URL (content item) */ /* Sub-title external URL / internal URL (content item) */
add(new Label(GlobalizationUtil.globalize( add(new Label(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.link_type_subtitle"), "cms.contenttyes.link.ui.link_type_subtitle"),
Label.BOLD), Label.BOLD),
ColumnPanel.FULL_WIDTH); ColumnPanel.FULL_WIDTH);
@ -195,15 +200,15 @@ public class LinkPropertyForm extends FormSection
m_linkType = new RadioGroup("linkType"); m_linkType = new RadioGroup("linkType");
Option m_external = new Option( Option m_external = new Option(
Link.EXTERNAL_LINK, Link.EXTERNAL_LINK,
new Label(GlobalizationUtil.globalize( new Label(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.option_group.link_type.external"))); "cms.contenttyes.link.ui.option_group.link_type.external")));
m_external.setOnClick("enableUrlFields()"); m_external.setOnClick("enableUrlFields()");
Option m_internal = new Option( Option m_internal = new Option(
Link.INTERNAL_LINK, Link.INTERNAL_LINK,
new Label(GlobalizationUtil.globalize( new Label(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.option_group.link_type.internal"))); "cms.contenttyes.link.ui.option_group.link_type.internal")));
m_internal.setOnClick("enableItemFields()"); m_internal.setOnClick("enableItemFields()");
m_linkType.addOption(m_external); m_linkType.addOption(m_external);
@ -211,28 +216,28 @@ public class LinkPropertyForm extends FormSection
m_linkType.setOptionSelected(m_internal); m_linkType.setOptionSelected(m_internal);
m_linkType.addValidationListener(new NotNullValidationListener()); m_linkType.addValidationListener(new NotNullValidationListener());
add(new Label(GlobalizationUtil.globalize( add(new Label(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.option_group.link_type.label"))); "cms.contenttyes.link.ui.option_group.link_type.label")));
add(m_linkType); add(m_linkType);
/* External target */ /* External target */
Fieldset externalFieldset = new Fieldset(GlobalizationUtil.globalize( Fieldset externalFieldset = new Fieldset(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.target_uri")); "cms.contenttyes.link.ui.target_uri"));
externalFieldset.setClassAttr("externalLink autoHide"); externalFieldset.setClassAttr("externalLink autoHide");
m_targetURI = new TextField("targetURI"); m_targetURI = new TextField("targetURI");
m_targetURI.setOnFocus("toggle_link_fields(false)"); m_targetURI.setOnFocus("toggle_link_fields(false)");
m_targetURI.setHint(GlobalizationUtil.globalize( m_targetURI.setHint(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.target_uri_hint")); "cms.contenttyes.link.ui.target_uri_hint"));
externalFieldset.add(new Label(GlobalizationUtil.globalize( externalFieldset.add(new Label(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.target_uri"))); "cms.contenttyes.link.ui.target_uri")));
externalFieldset.add(m_targetURI); externalFieldset.add(m_targetURI);
add(externalFieldset); add(externalFieldset);
/* Internal target */ /* Internal target */
Fieldset internalFieldset = new Fieldset(GlobalizationUtil.globalize( Fieldset internalFieldset = new Fieldset(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.target_content_item")); "cms.contenttyes.link.ui.target_content_item"));
internalFieldset.setClassAttr("internalLink autoHide"); internalFieldset.setClassAttr("internalLink autoHide");
internalFieldset.add(new Label(GlobalizationUtil.globalize( internalFieldset.add(new Label(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.target_content_item") )); "cms.contenttyes.link.ui.target_content_item")));
m_itemSearch = new ItemSearchWidget(ITEM_SEARCH, m_contentType); m_itemSearch = new ItemSearchWidget(ITEM_SEARCH, m_contentType);
m_itemSearch.getSearchButton().setOnFocus("toggle_link_fields(true)"); m_itemSearch.getSearchButton().setOnFocus("toggle_link_fields(true)");
m_itemSearch.getClearButton().setOnFocus("toggle_link_fields(true)"); m_itemSearch.getClearButton().setOnFocus("toggle_link_fields(true)");
@ -240,13 +245,13 @@ public class LinkPropertyForm extends FormSection
/* Optional parameters for internal target */ /* Optional parameters for internal target */
internalFieldset.add(new Label(GlobalizationUtil.globalize( internalFieldset.add(new Label(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.target_parameters") )); "cms.contenttyes.link.ui.target_parameters")));
m_itemParams = new TextField("itemParams"); m_itemParams = new TextField("itemParams");
m_itemParams.setOnFocus("toggle_link_fields(true)"); m_itemParams.setOnFocus("toggle_link_fields(true)");
m_itemParams.setHint(GlobalizationUtil.globalize( m_itemParams.setHint(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.target_parameters_hint") ); "cms.contenttyes.link.ui.target_parameters_hint"));
internalFieldset.add(m_itemParams); internalFieldset.add(m_itemParams);
add(internalFieldset); add(internalFieldset);
// TODO: // TODO:
// Move this option to contentasset related link for backwards compatibility // Move this option to contentasset related link for backwards compatibility
@ -255,17 +260,17 @@ public class LinkPropertyForm extends FormSection
// cms_links to cms_related_links which shoud become ca_related_links // cms_links to cms_related_links which shoud become ca_related_links
/* Single option whether to open in new window, strongly discouraged!*/ /* Single option whether to open in new window, strongly discouraged!*/
Option m_selectWindow = new Option( Option m_selectWindow = new Option(
Link.TARGET_WINDOW, Link.TARGET_WINDOW,
new Label(GlobalizationUtil.globalize( new Label(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.option.new_window"))); "cms.contenttyes.link.ui.option.new_window")));
// "Open URL in new window"); // "Open URL in new window");
m_URIOption = new CheckboxGroup("openOption"); m_URIOption = new CheckboxGroup("openOption");
m_URIOption.addOption(m_selectWindow); m_URIOption.addOption(m_selectWindow);
add(m_URIOption, ColumnPanel.FULL_WIDTH); add(m_URIOption, ColumnPanel.FULL_WIDTH);
//add(new Label( //add(new Label(
add(new Embedded( add(new Embedded(
"<script language=\"javascript\">\n" "<script language=\"javascript\">\n"
+ "<!-- \n" + "<!-- \n"
+ "if (document.forms['linkEditForm'].linkType[0].checked) { \n" + "if (document.forms['linkEditForm'].linkType[0].checked) { \n"
+ " //toggle_link_fields(false); \n" + " //toggle_link_fields(false); \n"
@ -276,7 +281,7 @@ public class LinkPropertyForm extends FormSection
+ "} \n" + "} \n"
+ "// -->\n" + "// -->\n"
+ "</script>\n", + "</script>\n",
false), ColumnPanel.FULL_WIDTH); false), ColumnPanel.FULL_WIDTH);
} }
/** /**
@ -286,35 +291,37 @@ public class LinkPropertyForm extends FormSection
m_saveCancelSection = new SaveCancelSection(); m_saveCancelSection = new SaveCancelSection();
try { try {
m_saveCancelSection.getCancelButton().addPrintListener( m_saveCancelSection.getCancelButton().addPrintListener(
new PrintListener() { new PrintListener() {
@Override @Override
public void prepare(PrintEvent e) { public void prepare(PrintEvent e) {
Submit target = (Submit) e.getTarget(); Submit target = (Submit) e.getTarget();
if (m_linkModel.isSelected(e.getPageState())) { if (m_linkModel.isSelected(e.getPageState())) {
target.setButtonLabel(GlobalizationUtil.globalize( target.setButtonLabel(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.button_cancel")); "cms.contenttyes.link.ui.button_cancel"));
} else { } else {
target.setButtonLabel(GlobalizationUtil.globalize( target.setButtonLabel(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.button_reset")); "cms.contenttyes.link.ui.button_reset"));
}
} }
}); }
});
m_saveCancelSection.getSaveButton().addPrintListener( m_saveCancelSection.getSaveButton().addPrintListener(
new PrintListener() { new PrintListener() {
@Override @Override
public void prepare(PrintEvent e) { public void prepare(PrintEvent e) {
Submit target = (Submit) e.getTarget(); Submit target = (Submit) e.getTarget();
if (m_linkModel.isSelected(e.getPageState())) { if (m_linkModel.isSelected(e.getPageState())) {
target.setButtonLabel(GlobalizationUtil.globalize( target.setButtonLabel(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.button_save")); "cms.contenttyes.link.ui.button_save"));
} else { } else {
target.setButtonLabel(GlobalizationUtil.globalize( target.setButtonLabel(GlobalizationUtil.globalize(
"cms.contenttyes.link.ui.button_create")); "cms.contenttyes.link.ui.button_create"));
}
} }
}); }
});
} catch (TooManyListenersException e) { } catch (TooManyListenersException e) {
throw new UncheckedWrapperException("this cannot happen", e); throw new UncheckedWrapperException("this cannot happen", e);
} }
@ -323,6 +330,7 @@ public class LinkPropertyForm extends FormSection
/** /**
* Retrieves the saveCancelSection. * Retrieves the saveCancelSection.
*
* @return Save/Cencel section * @return Save/Cencel section
*/ */
public SaveCancelSection getSaveCancelSection() { public SaveCancelSection getSaveCancelSection() {
@ -340,11 +348,12 @@ public class LinkPropertyForm extends FormSection
* Submission listener. Handles cancel events. * Submission listener. Handles cancel events.
* *
* @param e the FormSectionEvent * @param e the FormSectionEvent
*
* @throws com.arsdigita.bebop.FormProcessException * @throws com.arsdigita.bebop.FormProcessException
*/ */
@Override @Override
public void submitted(FormSectionEvent e) public void submitted(FormSectionEvent e)
throws FormProcessException { throws FormProcessException {
if (m_saveCancelSection.getCancelButton().isSelected(e.getPageState())) { if (m_saveCancelSection.getCancelButton().isSelected(e.getPageState())) {
s_log.debug("cancel in submission listener"); s_log.debug("cancel in submission listener");
m_linkModel.clearSelection(e.getPageState()); m_linkModel.clearSelection(e.getPageState());
@ -354,15 +363,15 @@ public class LinkPropertyForm extends FormSection
} }
/** /**
* Validation listener. Ensures consistency of internal vs. external link * Validation listener. Ensures consistency of internal vs. external link data
* data
* *
* @param event the FormSectionEvent * @param event the FormSectionEvent
*
* @throws com.arsdigita.bebop.FormProcessException * @throws com.arsdigita.bebop.FormProcessException
*/ */
@Override @Override
public void validate(FormSectionEvent event) public void validate(FormSectionEvent event)
throws FormProcessException { throws FormProcessException {
PageState state = event.getPageState(); PageState state = event.getPageState();
FormData data = event.getFormData(); FormData data = event.getFormData();
@ -371,7 +380,7 @@ public class LinkPropertyForm extends FormSection
String externalURI = (String) m_targetURI.getValue(state); String externalURI = (String) m_targetURI.getValue(state);
if (externalURI == null || externalURI.length() == 0) { if (externalURI == null || externalURI.length() == 0) {
throw new FormProcessException( throw new FormProcessException(
"The URI field is required for an external link."); "The URI field is required for an external link.");
} }
String url = (String) m_targetURI.getValue(state); String url = (String) m_targetURI.getValue(state);
@ -389,7 +398,7 @@ public class LinkPropertyForm extends FormSection
// "http://servername" on the front // "http://servername" on the front
newURL = HTTP_PROTOCOL + Web.getConfig().getHost() newURL = HTTP_PROTOCOL + Web.getConfig().getHost()
+ url; + url;
} else if (!hasProtocol) { } else if (!hasProtocol) {
// There's no protocol. See if it would be ok if we // There's no protocol. See if it would be ok if we
// put one on the beginning // put one on the beginning
@ -398,8 +407,7 @@ public class LinkPropertyForm extends FormSection
} else { } else {
// No idea, just throw the error // No idea, just throw the error
throw new FormProcessException("URL is not valid: " + throw new FormProcessException("URL is not valid: " + ex.getMessage());
ex.getMessage());
} }
try { try {
@ -427,21 +435,20 @@ public class LinkPropertyForm extends FormSection
if (!localLink && !hasProtocol) { if (!localLink && !hasProtocol) {
m_targetURI.setValue(state, newURL); m_targetURI.setValue(state, newURL);
throw new FormProcessException( throw new FormProcessException(
"A valid URL starts with a protocol, eg http://"); "A valid URL starts with a protocol, eg http://");
} }
} }
} else if (Link.INTERNAL_LINK.equals((String) m_linkType.getValue( } else if (Link.INTERNAL_LINK.equals((String) m_linkType.getValue(
state))) { state))) {
// The link is internal, the item selected must be not null // The link is internal, the item selected must be not null
if (data.get(ITEM_SEARCH) == null) { if (data.get(ITEM_SEARCH) == null) {
throw new FormProcessException( throw new FormProcessException(
"Item selection is required for internal link."); "Item selection is required for internal link.");
} }
// Quasimodo // Quasimodo
// The target of the link must not be the same as the owner // The target of the link must not be the same as the owner
if(m_itemModel.getSelectedItem(state).getID().equals( if (m_itemModel.getSelectedItem(state).getID().equals(
((ContentItem) data.get(ITEM_SEARCH)).getID()) ((ContentItem) data.get(ITEM_SEARCH)).getID())) {
) {
throw new FormProcessException("Link target is the same as this object."); throw new FormProcessException("Link target is the same as this object.");
} }
} }
@ -451,6 +458,7 @@ public class LinkPropertyForm extends FormSection
* Get the current ContentItem * Get the current ContentItem
* *
* @param s the PageState * @param s the PageState
*
* @return the ContentItem * @return the ContentItem
*/ */
protected ContentItem getContentItem(PageState s) { protected ContentItem getContentItem(PageState s) {
@ -461,6 +469,7 @@ public class LinkPropertyForm extends FormSection
* Take care of basic Link creation steps * Take care of basic Link creation steps
* *
* @param s the PageState * @param s the PageState
*
* @return the newly-created Link * @return the newly-created Link
*/ */
protected Link createLink(PageState s) { protected Link createLink(PageState s) {
@ -474,6 +483,7 @@ public class LinkPropertyForm extends FormSection
* Init listener. For edit actions, fills the form with current data * Init listener. For edit actions, fills the form with current data
* *
* @param fse the FormSectionEvent * @param fse the FormSectionEvent
*
* @throws com.arsdigita.bebop.FormProcessException * @throws com.arsdigita.bebop.FormProcessException
*/ */
@Override @Override
@ -492,7 +502,7 @@ public class LinkPropertyForm extends FormSection
if ((link.getTargetURI() != null) if ((link.getTargetURI() != null)
&& link.getTargetURI().startsWith("&")) { && link.getTargetURI().startsWith("&")) {
m_itemParams.setValue(state, m_itemParams.setValue(state,
link.getTargetURI().substring(1)); link.getTargetURI().substring(1));
} else { } else {
m_targetURI.setValue(state, link.getTargetURI()); m_targetURI.setValue(state, link.getTargetURI());
} }
@ -526,6 +536,7 @@ public class LinkPropertyForm extends FormSection
* Process listener. Saves/creates the new or modified Link * Process listener. Saves/creates the new or modified Link
* *
* @param fse the FormSectionEvent * @param fse the FormSectionEvent
*
* @throws com.arsdigita.bebop.FormProcessException * @throws com.arsdigita.bebop.FormProcessException
*/ */
@Override @Override
@ -553,7 +564,7 @@ public class LinkPropertyForm extends FormSection
//call to set various properties of Link. //call to set various properties of Link.
setLinkProperties(link, fse); setLinkProperties(link, fse);
s_log.debug("Created Link with ID: " + link.getOID().toString() s_log.debug("Created Link with ID: " + link.getOID().toString()
+ "Title " + link.getTitle()); + "Title " + link.getTitle());
} }
// XXX Initialize the form // XXX Initialize the form
m_linkModel.clearSelection(state); m_linkModel.clearSelection(state);
@ -561,8 +572,9 @@ public class LinkPropertyForm extends FormSection
} }
/** /**
* Set various properties of the Link.Child clases can over-ride this method * Set various properties of the Link.Child clases can over-ride this method to add additional
* to add additional properties to Link. * properties to Link.
*
* @param link * @param link
* @param fse * @param fse
*/ */
@ -577,7 +589,7 @@ public class LinkPropertyForm extends FormSection
// Process internal and external urls // Process internal and external urls
if (Link.EXTERNAL_LINK.equals(m_linkType.getValue(state))) { if (Link.EXTERNAL_LINK.equals(m_linkType.getValue(state))) {
link.setTargetURI( link.setTargetURI(
(String) m_targetURI.getValue(state)); (String) m_targetURI.getValue(state));
link.setTargetItem(null); link.setTargetItem(null);
} else { } else {
// Internal // Internal
@ -585,7 +597,7 @@ public class LinkPropertyForm extends FormSection
link.setTargetURI(null); link.setTargetURI(null);
} else { } else {
link.setTargetURI(String.format("&%s", m_itemParams.getValue( link.setTargetURI(String.format("&%s", m_itemParams.getValue(
state))); state)));
} }
// Quasimodo: BEGIN // Quasimodo: BEGIN
@ -621,4 +633,5 @@ public class LinkPropertyForm extends FormSection
link.save(); link.save();
} }
} }

View File

@ -49,9 +49,9 @@ import java.math.BigDecimal;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
/** /**
* A form element which displays a select box of all content types available * A form element which displays a select box of all content types available under the given content
* under the given content section, and forwards to the item creation UI when * section, and forwards to the item creation UI when the user selects a content type to
* the user selects a content type to instantiate. * instantiate.
* *
* @author Stanislav Freidin (sfreidin@arsdigtia.com) * @author Stanislav Freidin (sfreidin@arsdigtia.com)
* @version $Revision: #12 $ $DateTime: 2004/08/17 23:15:09 $ * @version $Revision: #12 $ $DateTime: 2004/08/17 23:15:09 $
@ -59,10 +59,11 @@ import org.apache.log4j.Logger;
*/ */
public abstract class NewItemForm extends Form { public abstract class NewItemForm extends Form {
/** Internal logger instance to faciliate debugging. Enable logging output /**
* by editing /WEB-INF/conf/log4j.properties int hte runtime environment * Internal logger instance to faciliate debugging. Enable logging output by editing
* and set com.arsdigita.cms.ui.authoring.NewItemForm=DEBUG by uncommenting * /WEB-INF/conf/log4j.properties int hte runtime environment and set
* or adding the line. */ * com.arsdigita.cms.ui.authoring.NewItemForm=DEBUG by uncommenting or adding the line.
*/
private static final Logger s_log = Logger.getLogger(NewItemForm.class); private static final Logger s_log = Logger.getLogger(NewItemForm.class);
private final SingleSelect m_typeWidget; private final SingleSelect m_typeWidget;
@ -72,8 +73,7 @@ public abstract class NewItemForm extends Form {
public static final String TYPE_ID = "tid"; public static final String TYPE_ID = "tid";
/** /**
* Construct a new NewItemForm. It sets a vertical BoxPanel as the component * Construct a new NewItemForm. It sets a vertical BoxPanel as the component container.
* container.
* *
* @param name the name attribute of the form. * @param name the name attribute of the form.
*/ */
@ -88,18 +88,19 @@ public abstract class NewItemForm extends Form {
// create and add an "empty" component // create and add an "empty" component
m_emptyLabel = new Label(GlobalizationUtil m_emptyLabel = new Label(GlobalizationUtil
.globalize("cms.ui.authoring.no_types_registered"), .globalize("cms.ui.authoring.no_types_registered"),
false); false);
m_emptyLabel.setIdAttr("empty_label"); m_emptyLabel.setIdAttr("empty_label");
panel.add(m_emptyLabel); panel.add(m_emptyLabel);
m_createLabel = new Label(GlobalizationUtil m_createLabel = new Label(GlobalizationUtil
.globalize("cms.ui.authoring.create_new"), .globalize("cms.ui.authoring.create_new"),
false); false);
m_createLabel.setIdAttr("create_label"); m_createLabel.setIdAttr("create_label");
panel.add(m_createLabel); panel.add(m_createLabel);
m_typeWidget = new SingleSelect(new BigDecimalParameter(TYPE_ID)); m_typeWidget = new SingleSelect(new BigDecimalParameter(TYPE_ID),
OptionGroup.SortMode.ALPHABETICAL_ASCENDING);
try { try {
m_typeWidget.addPrintListener(new PrintListener() { m_typeWidget.addPrintListener(new PrintListener() {
@ -113,10 +114,8 @@ public abstract class NewItemForm extends Form {
ContentSection section = getContentSection(state); ContentSection section = getContentSection(state);
ContentType parentType = null; ContentType parentType = null;
ContentTypeCollection typesCollection = null; ContentTypeCollection typesCollection = null;
BigDecimal singleTypeID = (BigDecimal) BigDecimal singleTypeID = (BigDecimal) state.getValue(new BigDecimalParameter(
state.getValue(new ItemSearch.SINGLE_TYPE_PARAM));
BigDecimalParameter(
ItemSearch.SINGLE_TYPE_PARAM));
if (singleTypeID != null) { if (singleTypeID != null) {
try { try {
@ -141,7 +140,7 @@ public abstract class NewItemForm extends Form {
ContentType type = typesCollection.getContentType(); ContentType type = typesCollection.getContentType();
if (PermissionService if (PermissionService
.getDirectGrantedPermissions(type.getOID()) .getDirectGrantedPermissions(type.getOID())
.size() > 0) { .size() > 0) {
// chris gilbert - allow restriction of some types // chris gilbert - allow restriction of some types
// to certain users/groups. No interface to do // to certain users/groups. No interface to do
// this, but group could be created and permission // this, but group could be created and permission
@ -157,26 +156,25 @@ public abstract class NewItemForm extends Form {
if (party == null) { if (party == null) {
party = Kernel.getPublicUser(); party = Kernel.getPublicUser();
} }
PermissionDescriptor create = PermissionDescriptor create = new PermissionDescriptor(
new PermissionDescriptor( PrivilegeDescriptor
PrivilegeDescriptor .get(SecurityManager.CMS_NEW_ITEM),
.get(SecurityManager type,
.CMS_NEW_ITEM), party);
type,
party);
list = PermissionService.checkPermission(create); list = PermissionService.checkPermission(create);
} }
if (list) { if (list) {
// o.addOption(new Option(type.getID().toString(), type.getName())); // o.addOption(new Option(type.getID().toString(), type.getName()));
o.addOption( new Option(type.getID().toString(), o.addOption(new Option(type.getID().toString(),
new Label(type.getLabel())) ); new Label(type.getLabel())));
} }
} }
typesCollection.reset(); typesCollection.reset();
} }
} }
}); });
} catch (java.util.TooManyListenersException e) { } catch (java.util.TooManyListenersException e) {
throw new UncheckedWrapperException("Too many listeners: " + e.getMessage(), e); throw new UncheckedWrapperException("Too many listeners: " + e.getMessage(), e);
@ -185,7 +183,7 @@ public abstract class NewItemForm extends Form {
panel.add(m_typeWidget); panel.add(m_typeWidget);
m_submit = new Submit("new", GlobalizationUtil.globalize( m_submit = new Submit("new", GlobalizationUtil.globalize(
"cms.ui.authoring.go")); "cms.ui.authoring.go"));
panel.add(m_submit); panel.add(m_submit);
add(panel); add(panel);
@ -196,6 +194,7 @@ public abstract class NewItemForm extends Form {
/** /**
* *
* @param state * @param state
*
* @return * @return
*/ */
public BigDecimal getTypeID(PageState state) { public BigDecimal getTypeID(PageState state) {
@ -212,6 +211,7 @@ public abstract class NewItemForm extends Form {
/** /**
* Generate XML - show/hide labels/widgets * Generate XML - show/hide labels/widgets
*
* @param state * @param state
* @param parent * @param parent
*/ */
@ -233,4 +233,5 @@ public abstract class NewItemForm extends Form {
super.generateXML(state, parent); super.generateXML(state, parent);
} }
} }
} }

View File

@ -43,7 +43,7 @@ public class CheckboxGroup extends OptionGroup implements BebopConstants {
public CheckboxGroup(ArrayParameter param) { public CheckboxGroup(ArrayParameter param) {
super(param); super(param);
m_xmlElement = BEBOP_CHECKBOX; //m_xmlElement = BEBOP_CHECKBOX;
} }
/** /**
@ -60,4 +60,9 @@ public class CheckboxGroup extends OptionGroup implements BebopConstants {
protected String getElementTag() { protected String getElementTag() {
return BEBOP_CHECKBOXGROUP; return BEBOP_CHECKBOXGROUP;
} }
@Override
public String getOptionXMLElement() {
return BEBOP_CHECKBOX;
}
} }

View File

@ -133,8 +133,7 @@ public class Option extends DescriptiveComponent {
Assert.isUnlocked(this); Assert.isUnlocked(this);
Assert.exists(group); Assert.exists(group);
m_group = group; m_group = group;
m_isSelectOption = m_isSelectOption = BebopConstants.BEBOP_OPTION.equals(m_group.getOptionXMLElement());
BebopConstants.BEBOP_OPTION.equals(m_group.m_xmlElement);
} }
public final OptionGroup getGroup() { public final OptionGroup getGroup() {
@ -243,7 +242,7 @@ public class Option extends DescriptiveComponent {
*/ */
@Override @Override
public void generateXML(PageState s, Element e) { public void generateXML(PageState s, Element e) {
Element option = e.newChildElement(m_group.m_xmlElement, BEBOP_XML_NS); Element option = e.newChildElement(m_group.getOptionXMLElement(), BEBOP_XML_NS);
if ( ! m_isSelectOption ) { if ( ! m_isSelectOption ) {
option.addAttribute("name", getName()); option.addAttribute("name", getName());
} }

View File

@ -19,17 +19,23 @@
package com.arsdigita.bebop.form; package com.arsdigita.bebop.form;
import com.arsdigita.bebop.Form; import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.RequestLocal; import com.arsdigita.bebop.RequestLocal;
import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.ParameterData; import com.arsdigita.bebop.parameters.ParameterData;
import com.arsdigita.bebop.parameters.ParameterModel; import com.arsdigita.bebop.parameters.ParameterModel;
import com.arsdigita.bebop.parameters.ParameterModelWrapper; import com.arsdigita.bebop.parameters.ParameterModelWrapper;
import com.arsdigita.bebop.util.BebopConstants; import com.arsdigita.bebop.util.BebopConstants;
import com.arsdigita.globalization.GlobalizationHelper;
import com.arsdigita.util.Assert; import com.arsdigita.util.Assert;
import com.arsdigita.xml.Element; import com.arsdigita.xml.Element;
import java.text.Collator;
import java.util.Iterator; import java.util.Iterator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletRequestWrapper;
@ -45,71 +51,171 @@ import org.apache.log4j.Logger;
* @author Michael Pih * @author Michael Pih
* @version $Id: OptionGroup.java 738 2005-09-01 12:36:52Z sskracic $ * @version $Id: OptionGroup.java 738 2005-09-01 12:36:52Z sskracic $
*/ */
public abstract class OptionGroup extends Widget public abstract class OptionGroup extends Widget implements BebopConstants {
implements BebopConstants {
private static final Logger s_log = Logger.getLogger(OptionGroup.class); private static final Logger LOGGER = Logger.getLogger(OptionGroup.class);
/** /**
* The XML element to be used by individual options belonging to this group. This variable has * The XML element to be used by individual options belonging to this group. This variable has
* to be initialized by every subclass of OptionGroup. LEGACY: An abstract method would be the * to be initialized by every subclass of OptionGroup. LEGACY: An abstract method would be the
* better design, but changing it would break the API. * better design, but changing it would break the API.
*/ */
protected String m_xmlElement; //protected String m_xmlElement;
// this only needs to be an ArrayList for multiple selection option groups // this only needs to be an ArrayList for multiple selection option groups
private ArrayList m_selected; private List<String> m_selected;
private ArrayList m_options; private List<Option> m_options;
private Widget m_otherOption = null; private Widget m_otherOption = null;
private Form m_form = null; private Form m_form = null;
private boolean m_isDisabled = false; private boolean m_isDisabled = false;
private boolean m_isReadOnly = false; private boolean m_isReadOnly = false;
/**
* Sort Mode for options
*/
private OptionGroup.SortMode sortMode;
/**
* Exclude first option from sorting?
*/
private boolean excludeFirst;
public static final String OTHER_OPTION = "__other__"; public static final String OTHER_OPTION = "__other__";
// request-local copy of selected elements, options // request-local copy of selected elements, options
private RequestLocal m_requestOptions = new RequestLocal() { private RequestLocal m_requestOptions = new RequestLocal() {
@Override @Override
public Object initialValue(PageState ps) { public Object initialValue(final PageState state) {
return new ArrayList(); return new ArrayList<Option>();
} }
}; };
@Override
public final boolean isCompound() { public final boolean isCompound() {
return true; return true;
} }
// this is only used for single selection option groups // this is only used for single selection option groups
private final static String TOO_MANY_OPTIONS_SELECTED private final static String TOO_MANY_OPTIONS_SELECTED
= "Only one option may be selected by default on this option group."; = "Only one option may be selected by default on this option group.";
/** /**
* The ParameterModel for mutliple OptionGroups is always an array parameter * The ParameterModel for mutliple OptionGroups is always an array parameter
*
* @param model
*/ */
protected OptionGroup(ParameterModel model) { protected OptionGroup(final ParameterModel model) {
//super(model);
//m_options = new ArrayList<Option>();
//m_selected = new ArrayList<String>();
this(model, OptionGroup.SortMode.NO_SORT, false);
}
protected OptionGroup(final ParameterModel model,
final OptionGroup.SortMode sortMode) {
this(model, sortMode, false);
}
protected OptionGroup(final ParameterModel model,
final OptionGroup.SortMode sortMode,
final boolean excludeFirst) {
super(model); super(model);
m_options = new ArrayList(); m_options = new ArrayList<Option>();
m_selected = new ArrayList(); m_selected = new ArrayList<String>();
this.sortMode = sortMode;
this.excludeFirst = excludeFirst;
} }
/** /**
* Returns an Iterator of all the default Options in this group. * Returns an Iterator of all the default Options in this group.
*
* @return
*/ */
public Iterator getOptions() { public Iterator<Option> getOptions() {
return m_options.iterator(); return m_options.iterator();
} }
public enum SortMode {
NO_SORT,
ALPHABETICAL_ASCENDING,
ALPHABETICAL_DESENDING
}
public abstract String getOptionXMLElement();
/**
* This {@link Comparator} implementation is used to sort the list of options alphabetical. If
* the sorting is ascending or descending depends on the selected sort mode. The Comparator
* needs the {@link PageState} for retrieving the localised labels from the options.
*/
private class AlphabeticalSortComparator implements Comparator<Option> {
private final PageState state;
/**
* Constructor taking the current {@code PageState}.
*
* @param state
*/
public AlphabeticalSortComparator(final PageState state) {
this.state = state;
}
@Override
public int compare(final Option option1, final Option option2) {
String label1;
String label2;
//Check if the first option to compare has a inner label component. If it has
//store the localised text. Otherwise use the name of the option.
if (option1.getComponent() instanceof Label) {
final Label label = (Label) option1.getComponent();
label1 = label.getLabel(state);
} else {
label1 = option1.getName();
}
// Same for the second option
if (option2.getComponent() instanceof Label) {
final Label label = (Label) option2.getComponent();
label2 = label.getLabel(state);
} else {
label2 = option2.getName();
}
//We are using a Collator instance here instead of String#compare(String) because
//String#compare(String) is not local sensitive. For example in german a word starting
//with the letter 'Ö' should be handled like a word starting with the letter 'O'.
//Using String#compare(String) would put them at the end of the list.
//Depending on the sort mode we compare label1 with label2 (ascending) or label2 with
//label1 (descending).
final Collator collator = Collator
.getInstance(GlobalizationHelper.getNegotiatedLocale());
if (sortMode == SortMode.ALPHABETICAL_ASCENDING) {
return collator.compare(label1, label2);
} else if (sortMode == SortMode.ALPHABETICAL_DESENDING) {
return collator.compare(label2, label1);
} else {
return 0;
}
}
}
/** /**
* Returns an Iterator of all the default Options in this group, plus any request-specific * Returns an Iterator of all the default Options in this group, plus any request-specific
* options. * options.
*
* @param state
*
* @return
*/ */
public Iterator getOptions(PageState ps) { public Iterator<Option> getOptions(final PageState state) {
ArrayList allOptions = new ArrayList(); List<Option> allOptions = new ArrayList<Option>();
allOptions.addAll(m_options); allOptions.addAll(m_options);
ArrayList requestOptions = (ArrayList) m_requestOptions.get(ps); List<Option> requestOptions = (List<Option>) m_requestOptions.get(state);
for (Iterator i = requestOptions.iterator(); i.hasNext();) { for (Iterator<Option> iterator = requestOptions.iterator(); iterator.hasNext();) {
Object obj = i.next(); final Option option = iterator.next();
if (!allOptions.contains(obj)) { if (!allOptions.contains(option)) {
allOptions.add(obj); allOptions.add(option);
} }
} }
return allOptions.iterator(); return allOptions.iterator();
@ -117,74 +223,74 @@ public abstract class OptionGroup extends Widget
public void clearOptions() { public void clearOptions() {
Assert.isUnlocked(this); Assert.isUnlocked(this);
m_options = new ArrayList(); m_options = new ArrayList<Option>();
} }
/** /**
* Adds a new option. * Adds a new option.
* *
* @param opt The {@link Option} to be added. Note: the argument is modified and associated with * @param option The {@link Option} to be added. Note: the argument is modified and associated
* this OptionGroup, regardless of what its group was. * with this OptionGroup, regardless of what its group was.
*/ */
public void addOption(Option opt) { public void addOption(final Option option) {
addOption(opt, null, false); addOption(option, null, false);
} }
public void addOption(Option opt, PageState ps) { public void addOption(final Option option, final PageState state) {
addOption(opt, ps, false); addOption(option, state, false);
} }
/** /**
* Adds a new option.at the beginning of the list * Adds a new option.at the beginning of the list
* *
* @param opt The {@link Option} to be added. Note: the argument is modified and associated with * @param option The {@link Option} to be added. Note: the argument is modified and associated
* this OptionGroup, regardless of what its group was. * with this OptionGroup, regardless of what its group was.
*/ */
public void prependOption(Option opt) { public void prependOption(final Option option) {
addOption(opt, null, true); addOption(option, null, true);
} }
public void prependOption(Option opt, PageState ps) { public void prependOption(final Option option, final PageState state) {
addOption(opt, ps, true); addOption(option, state, true);
} }
public void removeOption(Option opt) { public void removeOption(final Option option) {
removeOption(opt, null); removeOption(option, null);
} }
/** /**
* Adds a new option for the scope of the current request, or to the page as a whole if there is * Adds a new option for the scope of the current request, or to the page as a whole if there is
* no current request. * no current request.
* *
* @param opt The {@link Option} to be added. Note: the argument is modified and associated * @param option The {@link Option} to be added. Note: the argument is modified and associated
* with this OptionGroup, regardless of what its group was. * with this OptionGroup, regardless of what its group was.
* @param ps the current page state. if ps is null, adds option to the default option list. * @param state the current page state. if ps is null, adds option to the default option list.
* @param prepend If true, prepend option to the list instead of appending it * @param prepend If true, prepend option to the list instead of appending it
*/ */
public void addOption(Option opt, PageState ps, boolean prepend) { public void addOption(final Option option, final PageState state, final boolean prepend) {
ArrayList list = m_options; List<Option> list = m_options;
if (ps == null) { if (state == null) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
} else { } else {
list = (ArrayList) m_requestOptions.get(ps); list = (List<Option>) m_requestOptions.get(state);
} }
opt.setGroup(this); option.setGroup(this);
if (prepend == true) { if (prepend == true) {
list.add(0, opt); list.add(0, option);
} else { } else {
list.add(opt); list.add(option);
} }
} }
public void removeOption(Option opt, PageState ps) { public void removeOption(final Option option, final PageState state) {
ArrayList list = m_options; List<Option> list = m_options;
if (ps == null) { if (state == null) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
} else { } else {
list = (ArrayList) m_requestOptions.get(ps); list = (List<Option>) m_requestOptions.get(state);
} }
list.remove(opt); list.remove(option);
} }
public void removeOption(String key) { public void removeOption(String key) {
@ -194,22 +300,22 @@ public abstract class OptionGroup extends Widget
/** /**
* Removes the first option whose key is isEqual to the key that is passed in. * Removes the first option whose key is isEqual to the key that is passed in.
*/ */
public void removeOption(String key, PageState ps) { public void removeOption(final String key, final PageState state) {
// This is not an entirely efficient technique. A more // This is not an entirely efficient technique. A more
// efficient solution is to switch to using a HashMap. // efficient solution is to switch to using a HashMap.
ArrayList list = m_options; List<Option> list = m_options;
if (ps == null) { if (state == null) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
} else { } else {
list = (ArrayList) m_requestOptions.get(ps); list = (List<Option>) m_requestOptions.get(state);
} }
Iterator i = list.iterator(); final Iterator<Option> iterator = list.iterator();
Option o = null; Option option;
while (i.hasNext()) { while (iterator.hasNext()) {
o = (Option) i.next(); option = iterator.next();
if (o.getValue().equals(key)) { if (option.getValue().equals(key)) {
list.remove(o); list.remove(option);
break; break;
} }
} }
@ -219,15 +325,15 @@ public abstract class OptionGroup extends Widget
/** /**
* Add an "Other (please specify)" type option to the widget * Add an "Other (please specify)" type option to the widget
* *
* @param hasOtherOption true is the widget has an "Other" option * @param label
* @param width The width, in characters, of the "Other" entry area * @param width The width, in characters, of the "Other" entry area
* @param height The height, in characters, of the "Other" entry area. If this is 1 then * @param height The height, in characters, of the "Other" entry area. If this is 1 then a
* a TextField is used. Otherwise a TextArea is used. * TextField is used. Otherwise a TextArea is used.
*/ */
public void addOtherOption(String label, int width, int height) { public void addOtherOption(final String label, final int width, final int height) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
Option otherOption = new Option(OTHER_OPTION, label); final Option otherOption = new Option(OTHER_OPTION, label);
addOption(otherOption); addOption(otherOption);
final ParameterModel model = getParameterModel(); final ParameterModel model = getParameterModel();
@ -276,14 +382,14 @@ public abstract class OptionGroup extends Widget
} }
} }
s_log.debug("createParameterData in OptionGroup"); LOGGER.debug("createParameterData in OptionGroup");
return super.createParameterData(new HttpServletRequestWrapper(request) { return super.createParameterData(new HttpServletRequestWrapper(request) {
@Override @Override
public String[] getParameterValues(String key) { public String[] getParameterValues(String key) {
if (s_log.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
s_log.debug("Getting values for " + key); LOGGER.debug("Getting values for " + key);
} }
if (model.getName().equals(key)) { if (model.getName().equals(key)) {
@ -307,12 +413,12 @@ public abstract class OptionGroup extends Widget
* *
* @param value the value of the option to be added to the by-default-selected set. * @param value the value of the option to be added to the by-default-selected set.
*/ */
public void setOptionSelected(String value) { public void setOptionSelected(final String value) {
Assert.isUnlocked(this); Assert.isUnlocked(this);
if (!isMultiple()) { if (!isMultiple()) {
// only one option may be selected // only one option may be selected
// to this selected list better be empty // to this selected list better be empty
Assert.isTrue(m_selected.size() == 0, TOO_MANY_OPTIONS_SELECTED); Assert.isTrue(m_selected.isEmpty(), TOO_MANY_OPTIONS_SELECTED);
m_selected.add(value); m_selected.add(value);
getParameterModel().setDefaultValue(value); getParameterModel().setDefaultValue(value);
} else { } else {
@ -332,9 +438,11 @@ public abstract class OptionGroup extends Widget
@Override @Override
public Object clone() throws CloneNotSupportedException { public Object clone() throws CloneNotSupportedException {
OptionGroup cloned = (OptionGroup) super.clone(); final OptionGroup cloned = (OptionGroup) super.clone();
cloned.m_options = (ArrayList) m_options.clone(); //cloned.m_options = m_options.clone();
cloned.m_selected = (ArrayList) m_selected.clone(); //cloned.m_selected = m_selected.clone();
cloned.m_options.addAll(m_options);
cloned.m_selected.addAll(m_selected);
return cloned; return cloned;
} }
@ -373,7 +481,7 @@ public abstract class OptionGroup extends Widget
} }
@Override @Override
public void setForm(Form form) { public void setForm(final Form form) {
m_form = form; m_form = form;
if (null != m_otherOption) { if (null != m_otherOption) {
m_otherOption.setForm(form); m_otherOption.setForm(form);
@ -387,14 +495,15 @@ public abstract class OptionGroup extends Widget
* <p> * <p>
* Generates DOM fragment: * Generates DOM fragment:
* <p> * <p>
* <pre><code>&lt;bebop:* name=... [onXXX=...]&gt; * <
* pre><code>&lt;bebop:* name=... [onXXX=...]&gt;
* &lt;bebop:option name=... [selected]&gt; option value &lt;/bebop:option%gt; * &lt;bebop:option name=... [selected]&gt; option value &lt;/bebop:option%gt;
* ... * ...
* &lt;/bebop:*select&gt;</code></pre> * &lt;/bebop:*select&gt;</code></pre>
*/ */
@Override @Override
public void generateWidget(PageState state, Element parent) { public void generateWidget(final PageState state, final Element parent) {
Element optionGroup = parent.newChildElement(getElementTag(), BEBOP_XML_NS); final Element optionGroup = parent.newChildElement(getElementTag(), BEBOP_XML_NS);
optionGroup.addAttribute("name", getName()); optionGroup.addAttribute("name", getName());
optionGroup.addAttribute("class", getName().replace(".", " ")); optionGroup.addAttribute("class", getName().replace(".", " "));
if (getLabel() != null) { if (getLabel() != null) {
@ -405,11 +514,35 @@ public abstract class OptionGroup extends Widget
} }
exportAttributes(optionGroup); exportAttributes(optionGroup);
for (Iterator i = getOptions(state); i.hasNext();) { //Build a list of all options we can operator on.
Option o = (Option) i.next(); final List<Option> options = new ArrayList<Option>();
o.generateXML(state, optionGroup); for (Iterator<Option> iterator = getOptions(state); iterator.hasNext();) {
options.add(iterator.next());
} }
//If the sort mode is not {@code NO_SORT}, sort the the list.
if (sortMode != SortMode.NO_SORT) {
//If exclude first is sest to true the first option should stay on the top.
//We simply remove the first option from our list and generate the XML for it here.
if (excludeFirst && !options.isEmpty()) {
final Option first = options.remove(0);
first.generateXML(state, optionGroup);
}
//Sort the list using our {@link AlphabeticalSortComparator}.
Collections.sort(options, new AlphabeticalSortComparator(state));
}
//Generate the XML for the options.
for (Option option : options) {
option.generateXML(state, optionGroup);
}
// for (Iterator<Option> iterator = getOptions(state); iterator.hasNext();) {
// Option option = iterator.next();
// option.generateXML(state, optionGroup);
// }
if (null != m_otherOption) { if (null != m_otherOption) {
m_otherOption.generateXML(state, optionGroup); m_otherOption.generateXML(state, optionGroup);
} }

View File

@ -57,7 +57,7 @@ public class RadioGroup extends OptionGroup implements BebopConstants {
public RadioGroup(ParameterModel model) { public RadioGroup(ParameterModel model) {
super(model); super(model);
m_xmlElement = BEBOP_RADIO; //m_xmlElement = BEBOP_RADIO;
} }
/** /**
@ -74,6 +74,11 @@ public class RadioGroup extends OptionGroup implements BebopConstants {
return BEBOP_RADIOGROUP; return BEBOP_RADIOGROUP;
} }
@Override
public String getOptionXMLElement() {
return BEBOP_RADIO;
}
/** /**
* Is this a multiple (and not single) selection option group? * Is this a multiple (and not single) selection option group?
* *

View File

@ -36,9 +36,20 @@ import com.arsdigita.bebop.util.BebopConstants;
* @version $Id: Select.java 738 2005-09-01 12:36:52Z sskracic $ */ * @version $Id: Select.java 738 2005-09-01 12:36:52Z sskracic $ */
public abstract class Select extends OptionGroup implements BebopConstants { public abstract class Select extends OptionGroup implements BebopConstants {
public Select(ParameterModel model) { public Select(final ParameterModel model) {
super(model); super(model);
m_xmlElement = BEBOP_OPTION; //m_xmlElement = BEBOP_OPTION;
}
public Select(final ParameterModel model,
final OptionGroup.SortMode sortMode) {
super(model, sortMode);
}
public Select(final ParameterModel model,
final OptionGroup.SortMode sortMode,
final boolean excludeFirst) {
super(model, sortMode, excludeFirst);
} }
/** /**
@ -68,4 +79,8 @@ public abstract class Select extends OptionGroup implements BebopConstants {
* @return The tag to be used for the top level DOM element * @return The tag to be used for the top level DOM element
* generated for this type of Widget. */ * generated for this type of Widget. */
protected abstract String getElementTag(); protected abstract String getElementTag();
public String getOptionXMLElement() {
return BEBOP_OPTION;
}
} }

View File

@ -22,53 +22,67 @@ import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.bebop.parameters.ParameterModel; import com.arsdigita.bebop.parameters.ParameterModel;
/** /**
* A class representing an HTML <code>SELECT</code> element with * A class representing an HTML <code>SELECT</code> element with a single selection.
* a single selection.
* *
* @author Karl Goldstein * @author Karl Goldstein
* @author Uday Mathur * @author Uday Mathur
* @author Rory Solomon * @author Rory Solomon
* @author Michael Pih * @author Michael Pih
* @author Christian Brechb&uuml;hler (christian@arsdigita.com) * @author Christian Brechb&uuml;hler (christian@arsdigita.com)
* @version $Id: SingleSelect.java 287 2005-02-22 00:29:02Z sskracic $ * @version $Id: SingleSelect.java 287 2005-02-22 00:29:02Z sskracic $
*/ */
public class SingleSelect extends Select { public class SingleSelect extends Select {
/** The XML tag. /**
* @return The tag to be used for the top level DOM element * The XML tag.
* generated for this type of Widget. *
* @return The tag to be used for the top level DOM element generated for this type of Widget.
*/ */
protected String getElementTag() { protected String getElementTag() {
return BEBOP_SELECT; return BEBOP_SELECT;
} }
/** /**
* Creates a new SingleSelect widget, using a StringParameter model * Creates a new SingleSelect widget, using a StringParameter model with the given parameter
* with the given parameter name. Since you can only have one * name. Since you can only have one item selected from a SingleSelect, the string parameter
* item selected from a SingleSelect, the string parameter returns * returns the value of the selected option.
* the value of the selected option. * <p>
* <p>This is equivalent to * This is equivalent to <code>SingleSelect(new StringParameter(name))</code>
* <code>SingleSelect(new StringParameter(name))</code> *
* @param name the name of the string parameter * @param name the name of the string parameter
*/ */
public SingleSelect(String name) { public SingleSelect(final String name) {
super(new StringParameter(name)); super(new StringParameter(name));
} }
/** /**
* Creates a new SingleSelect widget, using the given * Creates a new SingleSelect widget, using the given parameter model.
* parameter model. *
* @param model the parameter model * @param model the parameter model
*/ */
public SingleSelect(ParameterModel model) { public SingleSelect(final ParameterModel model) {
super(model); super(model);
} }
/** State that this is a single select public SingleSelect(final ParameterModel model,
* @return false final OptionGroup.SortMode sortMode) {
super(model, sortMode);
}
public SingleSelect(final ParameterModel model,
final OptionGroup.SortMode sortMode,
final boolean excludeFirst) {
super(model, sortMode, excludeFirst);
}
/**
* State that this is a single select
*
* @return false
*/ */
@Override @Override
public boolean isMultiple() { public boolean isMultiple() {
return false; return false;
} }
} }

View File

@ -41,6 +41,7 @@ import com.arsdigita.cms.ui.CMSDHTMLEditor;
import com.arsdigita.cms.ui.authoring.BasicPageForm; import com.arsdigita.cms.ui.authoring.BasicPageForm;
import com.arsdigita.globalization.GlobalizationHelper; import com.arsdigita.globalization.GlobalizationHelper;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import java.text.Collator;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.Locale; import java.util.Locale;
@ -51,13 +52,13 @@ import org.apache.log4j.Logger;
* @author Jens Pelzetter * @author Jens Pelzetter
*/ */
public class PublicationPropertyForm public class PublicationPropertyForm
extends BasicPageForm extends BasicPageForm
implements FormProcessListener, implements FormProcessListener,
FormInitListener, FormInitListener,
FormSubmissionListener { FormSubmissionListener {
private static final Logger s_log = Logger.getLogger( private static final Logger s_log = Logger.getLogger(
PublicationPropertyForm.class); PublicationPropertyForm.class);
private PublicationPropertiesStep m_step; private PublicationPropertiesStep m_step;
public static final String ID = "Publication_edit"; public static final String ID = "Publication_edit";
private final static PublicationsConfig config = new PublicationsConfig(); private final static PublicationsConfig config = new PublicationsConfig();
@ -83,19 +84,19 @@ public class PublicationPropertyForm
super.addWidgets(); super.addWidgets();
final ParameterModel yearOfPublicationParam = new IntegerParameter( final ParameterModel yearOfPublicationParam = new IntegerParameter(
Publication.YEAR_OF_PUBLICATION); Publication.YEAR_OF_PUBLICATION);
final TextField yearOfPublication = new TextField(yearOfPublicationParam); final TextField yearOfPublication = new TextField(yearOfPublicationParam);
yearOfPublication.setMaxLength(4); yearOfPublication.setMaxLength(4);
//yearOfPublication.addValidationListener(new NotNullValidationListener()); //yearOfPublication.addValidationListener(new NotNullValidationListener());
//yearOfPublication.addValidationListener(new NotEmptyValidationListener()); //yearOfPublication.addValidationListener(new NotEmptyValidationListener());
yearOfPublication.setLabel(PublicationGlobalizationUtil.globalize( yearOfPublication.setLabel(PublicationGlobalizationUtil.globalize(
"publications.ui.publication.year_of_publication")); "publications.ui.publication.year_of_publication"));
add(yearOfPublication); add(yearOfPublication);
final ParameterModel firstPublishedParam = new IntegerParameter(Publication.FIRST_PUBLISHED); final ParameterModel firstPublishedParam = new IntegerParameter(Publication.FIRST_PUBLISHED);
final TextField firstPublished = new TextField(firstPublishedParam); final TextField firstPublished = new TextField(firstPublishedParam);
firstPublished.setLabel(PublicationGlobalizationUtil.globalize( firstPublished.setLabel(PublicationGlobalizationUtil.globalize(
"publications.ui.publication.first_published")); "publications.ui.publication.first_published"));
add(firstPublished); add(firstPublished);
final ParameterModel langParam = new StringParameter(Publication.LANG); final ParameterModel langParam = new StringParameter(Publication.LANG);
final SingleSelect lang = new SingleSelect(langParam); final SingleSelect lang = new SingleSelect(langParam);
@ -105,8 +106,11 @@ public class PublicationPropertyForm
@Override @Override
public int compare(final Locale locale1, final Locale locale2) { public int compare(final Locale locale1, final Locale locale2) {
return locale1.getDisplayName(GlobalizationHelper.getNegotiatedLocale()).compareTo( final Locale negLocale = GlobalizationHelper.getNegotiatedLocale();
locale2.getDisplayName(GlobalizationHelper.getNegotiatedLocale())); final Collator collator = Collator.getInstance(negLocale);
return collator.compare(locale1.getDisplayName(negLocale),
locale2.getDisplayName(negLocale));
} }
}); });
@ -119,14 +123,14 @@ public class PublicationPropertyForm
public void prepare(final PrintEvent event) { public void prepare(final PrintEvent event) {
final Label target = (Label) event.getTarget(); final Label target = (Label) event.getTarget();
target.setLabel(currentLocale.getDisplayName(GlobalizationHelper. target.setLabel(currentLocale.getDisplayName(GlobalizationHelper.
getNegotiatedLocale())); getNegotiatedLocale()));
} }
}); });
lang.addOption(new Option(locale.toString(), optionLabel)); lang.addOption(new Option(locale.toString(), optionLabel));
} }
lang.setLabel(PublicationGlobalizationUtil.globalize( lang.setLabel(PublicationGlobalizationUtil.globalize(
"publications.ui.publication.language")); "publications.ui.publication.language"));
add(lang); add(lang);
ParameterModel abstractParam = new StringParameter(Publication.ABSTRACT); ParameterModel abstractParam = new StringParameter(Publication.ABSTRACT);
@ -139,7 +143,7 @@ public class PublicationPropertyForm
abstractArea.setCols(60); abstractArea.setCols(60);
abstractArea.setRows(18); abstractArea.setRows(18);
abstractArea.setLabel(PublicationGlobalizationUtil.globalize( abstractArea.setLabel(PublicationGlobalizationUtil.globalize(
"publications.ui.publication.abstract")); "publications.ui.publication.abstract"));
add(abstractArea); add(abstractArea);
ParameterModel miscParam = new StringParameter(Publication.MISC); ParameterModel miscParam = new StringParameter(Publication.MISC);
@ -150,7 +154,7 @@ public class PublicationPropertyForm
misc = new TextArea(miscParam); misc = new TextArea(miscParam);
} }
misc.setLabel(PublicationGlobalizationUtil.globalize( misc.setLabel(PublicationGlobalizationUtil.globalize(
"publications.ui.publication.misc")); "publications.ui.publication.misc"));
misc.setCols(60); misc.setCols(60);
misc.setRows(18); misc.setRows(18);
add(misc); add(misc);
@ -175,7 +179,7 @@ public class PublicationPropertyForm
Publication publication = (Publication) super.processBasicWidgets(fse); Publication publication = (Publication) super.processBasicWidgets(fse);
if ((publication != null) && getSaveCancelSection().getSaveButton(). if ((publication != null) && getSaveCancelSection().getSaveButton().
isSelected(fse.getPageState())) { isSelected(fse.getPageState())) {
//publication.setTitle((String) data.get(Publication.TITLE)); //publication.setTitle((String) data.get(Publication.TITLE));
publication.setYearOfPublication((Integer) data.get(Publication.YEAR_OF_PUBLICATION)); publication.setYearOfPublication((Integer) data.get(Publication.YEAR_OF_PUBLICATION));
publication.setYearFirstPublished((Integer) data.get(Publication.FIRST_PUBLISHED)); publication.setYearFirstPublished((Integer) data.get(Publication.FIRST_PUBLISHED));
@ -190,7 +194,7 @@ public class PublicationPropertyForm
@Override @Override
public void submitted(FormSectionEvent fse) throws FormProcessException { public void submitted(FormSectionEvent fse) throws FormProcessException {
if ((m_step != null) && getSaveCancelSection().getCancelButton(). if ((m_step != null) && getSaveCancelSection().getCancelButton().
isSelected(fse.getPageState())) { isSelected(fse.getPageState())) {
m_step.cancelStreamlinedCreation(fse.getPageState()); m_step.cancelStreamlinedCreation(fse.getPageState());
} }
} }