/* See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * Esri Inc. licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.esri.gpt.catalog.schema; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import com.esri.gpt.framework.jsf.MessageBroker; import com.esri.gpt.framework.util.Val; import com.esri.gpt.framework.xml.DomUtil; import java.util.List; import javax.faces.component.UIComponent; import javax.faces.component.UIGraphic; import javax.faces.component.UISelectBoolean; import javax.faces.component.UISelectItems; import javax.faces.component.html.HtmlGraphicImage; import javax.faces.component.html.HtmlInputHidden; import javax.faces.component.html.HtmlOutputLabel; import javax.faces.component.html.HtmlOutputText; import javax.faces.component.html.HtmlPanelGrid; import javax.faces.component.html.HtmlPanelGroup; import javax.faces.component.html.HtmlSelectBooleanCheckbox; import javax.faces.component.html.HtmlSelectOneRadio; import javax.faces.model.SelectItem; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Section component associated with a metadata schema. * <p/> * The component is configured from a node with a schema configuration * XML document. * <p/> * A section contains a label and a collection of parameters. The * parameters will appear within the user interface in the order in * which they appear within the schema configuration XML. * <p/> * Example: * <br/><section key="description"> * <br/></section> */ public class Section extends UiComponent { // class variables ============================================================= /** Mutually exclusive section = "exclusive" */ public static final String OBLIGATION_EXCLUSIVE = "exclusive"; /** Mandatory section = "mandatory" (this is the default) */ public static final String OBLIGATION_MANDATORY = "mandatory"; /** Optional section = "optional" */ public static final String OBLIGATION_OPTIONAL = "optional"; // instance variables ========================================================== private String _delete = ""; private Label _label; private String _obligation = Section.OBLIGATION_MANDATORY; private boolean _open = true; private Parameters _parameters; private Section _parent; private Sections _sections; private String _select = ""; private boolean _useSelectForDelete = false; private boolean _visibleOnDetails = true; private boolean _wasUnbound = false; // constructors ================================================================ /** Default constructor. */ public Section() { this(null); } /** * Construct by duplicating an existing object. * @param objectToDuplicate the object to duplicate */ public Section(Section objectToDuplicate) { super(objectToDuplicate); if (objectToDuplicate == null) { setParameters(new Parameters()); setSections(new Sections()); } else { setObligation(objectToDuplicate.getObligation()); setOpen(objectToDuplicate.getOpen()); setSelect(objectToDuplicate.getSelect()); setDelete(objectToDuplicate.getDelete()); setVisibleOnDetails(objectToDuplicate.getVisibleOnDetails()); setUseSelectForDelete(objectToDuplicate.getUseSelectForDelete()); if (objectToDuplicate.getLabel() != null) { setLabel(objectToDuplicate.getLabel().duplicate()); } setParameters(new Parameters(objectToDuplicate.getParameters())); setSections(new Sections(objectToDuplicate.getSections(),this)); } } // properties ================================================================== /** * Gets the XPath expression used to select nodes for deletion when an optional * section has not been filled (i.e. not checked within the editor). * @return the delete expression */ public String getDelete() { return _delete; } /** * Sets the XPath expression used to select nodes for deletion when an optional * section has not been filled (i.e. not checked within the editor). */ public void setDelete(String expression) { _delete = Val.chkStr(expression); } /** * Gets the mutually exclusive siblings associated with this section * @return the siblings (the collection includes this section if it is exclusive) */ private Sections getExclusiveSiblings(Schema schema) { Sections exclusive = new Sections(); Sections siblings = schema.getSections(); if (getParent() != null) { siblings = getParent().getSections(); } for (Section sibling: siblings.values()) { if (sibling.getObligation().equalsIgnoreCase(Section.OBLIGATION_EXCLUSIVE)) { exclusive.add(sibling); } } return exclusive; } /** * Gets the Faces ID for the section. * <br/>The Faces ID is based upon the section key. * <br/>All "." characters are replaced with "_". * @return the Faces ID */ public String getFacesId() { return getKey().replace('.','_'); } /** * Gets the label component. * @return the label component */ public Label getLabel() { return _label; } /** * Sets the label component. * @param label the label component */ public void setLabel(Label label) { _label = label; } /** * Gets the obligation for this section. * @return the obligation */ public String getObligation() { return _obligation; } /** * Sets the obligation for this section. * @param obligation the obligation */ public void setObligation(String obligation) { obligation = Val.chkStr(obligation); if (obligation.equalsIgnoreCase(Section.OBLIGATION_EXCLUSIVE)) { _obligation = Section.OBLIGATION_EXCLUSIVE; } else if (obligation.equalsIgnoreCase(Section.OBLIGATION_MANDATORY)) { _obligation = Section.OBLIGATION_MANDATORY; } else if (obligation.equalsIgnoreCase(Section.OBLIGATION_OPTIONAL)) { _obligation = Section.OBLIGATION_OPTIONAL; } else { _obligation = Section.OBLIGATION_MANDATORY; } } /** * Gets the open status. * @return true if the section is open */ public boolean getOpen() { return _open; } /** * Sets the open status. * @param open true if the section is open */ public void setOpen(boolean open) { _open = open; } /** * Gets the parameters for the schema. * @return the schema parameters */ public Parameters getParameters() { return _parameters; } /** * Sets the parameters for the schema. * @param parameters the schema parameters */ protected void setParameters(Parameters parameters) { _parameters = parameters; if (_parameters == null) _parameters = new Parameters(); } /** * Gets the parent section. * @return the parent section (null for a top level section) */ public Section getParent() { return _parent; } /** * Sets the parent section. */ protected void setParent(Section parent) { _parent = parent; } /** * Gets the sub-sections for this section. * @return the sub-sections */ public Sections getSections() { return _sections; } /** * Sets the sub-sections for this section. * @param sections the sub-sections */ protected void setSections(Sections sections) { _sections = sections; if (_sections == null) _sections = new Sections(); } /** * Gets the XPath selection expression for selecting the section. * @return the selection expression */ public String getSelect() { return _select; } /** * Sets the XPath selection expression for selecting the section. * @param expression the selection expression */ public void setSelect(String expression) { _select = Val.chkStr(expression); } /** * Gets the status indicating if the selection expression should * be used to select nodes for deletion when an optional * section has not been filled (i.e. not checked within the editor). * @return true if the selection expression should be used for deletion */ public boolean getUseSelectForDelete() { return _useSelectForDelete; } /** * Sets the status indicating if the selection expression should * be used to select nodes for deletion when an optional * section has not been filled (i.e. not checked within the editor). * @param useSelectForDelete true if the selection expression * should be used for deletion */ public void setUseSelectForDelete(boolean useSelectForDelete) { _useSelectForDelete = useSelectForDelete; } /** * Gets the status indicating if the section should be displayed on the * view details page. * @return true if the section should be displayed on the view details page */ public boolean getVisibleOnDetails() { return _visibleOnDetails; } /** * Sets the status indicating if the section should be displayed on the * view details page. * @param visible true if the section should be displayed on the view details page */ public void setVisibleOnDetails(boolean visible) { _visibleOnDetails = visible; } // methods ===================================================================== /** * Appends Faces display components for this section of the metadata details page. * @param schema the parent schema * @param context the UI context * @param parentComponent the parent component for this section */ public boolean appendDetailComponents(Schema schema, UiContext context, UIComponent parentComponent) { if (!getVisibleOnDetails()) return false; // initialize boolean bHadParameters = false; String sSectionId = getFacesId(); String sCheckboxId = sSectionId+"-chk"; String sRadioId = sSectionId+"-radio"; String sImgId = sSectionId+"-img"; String sBodyId = sSectionId+"-body"; String sParamsId = sSectionId+"-params"; boolean bIsExclusive = getObligation().equalsIgnoreCase(Section.OBLIGATION_EXCLUSIVE); boolean bIsOptional = getObligation().equalsIgnoreCase(Section.OBLIGATION_OPTIONAL); HtmlPanelGroup panel = new HtmlPanelGroup(); panel.setStyleClass("section"); MessageBroker msgBroker = context.extractMessageBroker(); // return if there is nothing to display if ((bIsExclusive || bIsOptional) && !getOpen()) { return false; } // determine the caption String sCaption = ""; if (getLabel() != null) { sCaption = msgBroker.retrieveMessage(getLabel().getResourceKey()); } if (sCaption.length() == 0) { sCaption = getKey(); } // make the header StringBuffer sbOnclick = new StringBuffer(); sbOnclick.append("mddOnSectionClicked('").append(sSectionId).append("')"); HtmlPanelGrid headerTable = new HtmlPanelGrid(); headerTable.setColumns(3); headerTable.setStyleClass("sectionHeader"); headerTable.setSummary(msgBroker.retrieveMessage("catalog.general.designOnly")); headerTable.setOnclick(sbOnclick.toString()); HtmlSelectBooleanCheckbox checkBox = new HtmlSelectBooleanCheckbox(); checkBox.setId(sCheckboxId); checkBox.setSelected(getOpen()); checkBox.setStyle("display:none;"); headerTable.getChildren().add(checkBox); HtmlGraphicImage img = new HtmlGraphicImage(); img.setId(sImgId); setGraphicUrl(img); headerTable.getChildren().add(img); HtmlOutputText caption = new HtmlOutputText(); caption.setValue(sCaption); caption.setStyleClass("sectionCaption"); headerTable.getChildren().add(caption); if (getLabel() != null) { panel.getChildren().add(headerTable); } else { panel.setStyleClass(""); } // make the section body boolean bContainerOnly = (getLabel() == null); String sBodyClass = "sectionBody"; if (bContainerOnly) sBodyClass= ""; HtmlPanelGrid sectionBody = new HtmlPanelGrid(); sectionBody.setId(sBodyId); sectionBody.setStyleClass(sBodyClass); setBodyDisplay(sectionBody); panel.getChildren().add(sectionBody); // make the table to hold section parameters, add all parameters HtmlPanelGrid parametersTable = new HtmlPanelGrid(); parametersTable.setId(sParamsId); parametersTable.setColumns(2); parametersTable.setStyleClass("parameters"); parametersTable.setSummary(msgBroker.retrieveMessage("catalog.general.designOnly")); boolean hasMap = false; for (Parameter parameter: getParameters().values()) { HtmlOutputText cmpLabel = null; UIComponent cmpValue = null; // check for a binary thumbnail if (parameter.getMeaningType().equalsIgnoreCase(Meaning.MEANINGTYPE_THUMBNAIL_URL)) { if (schema.getMeaning().getThumbnailUrl().length() == 0) { String uuid = Val.chkStr(context.extractHttpServletRequest().getParameter("uuid")); if ((uuid.length() > 0) && (schema.getMeaning().getThumbnailBinary().length() > 0)) { try { String thumbUrl = "/thumbnail?uuid="+URLEncoder.encode(uuid,"UTF-8"); parameter.getContent().getSingleValue().setValue(thumbUrl); } catch (UnsupportedEncodingException e) {} } } } boolean bDisplay = parameter.getVisible() && parameter.getVisibleOnDetails() && !parameter.getContent().isValueEmpty() && (parameter.getInput() != null); if ((parameter.getInput() instanceof InputMap)) { cmpValue = parameter.getInput().makeOutputComponent(context,this,parameter); if (cmpValue != null) { parametersTable.getChildren().add(cmpValue); hasMap = true; } } else if (bDisplay) { cmpValue = parameter.getInput().makeOutputComponent(context,this,parameter); if (cmpValue != null) { cmpLabel = new HtmlOutputText(); cmpLabel.setValue(msgBroker.retrieveMessage(parameter.getLabel().getResourceKey())); parametersTable.getChildren().add(cmpLabel); parametersTable.getChildren().add(cmpValue); } } } parametersTable.setColumnClasses(hasMap? ",parameterValue": "parameterLabel,parameterValue"); if (parametersTable.getChildCount() > 0) { bHadParameters = true; sectionBody.getChildren().add(parametersTable); } // append all sub-sections for (Section section: getSections().values()) { boolean bHadSubParams = section.appendDetailComponents(schema,context,sectionBody); if (bHadSubParams) bHadParameters = true; } if (!bHadParameters) panel.setRendered(false); if ((panel != null) && (panel.getChildCount() > 0) && panel.isRendered()) { parentComponent.getChildren().add(panel); } return bHadParameters; } /** * Appends Faces editing components for this section of the metadata editor * @param schema the parent schema * @param context the UI context * @param parentComponent the parent component for this section */ public void appendEditorComponents(Schema schema, UiContext context, UIComponent parentComponent) { //appendDetailComponents(schema,context,parentComponent); //if (true) return; // initialize String sSectionId = getFacesId(); String sCheckboxId = sSectionId+"-chk"; String sRadioId = sSectionId+"-radio"; String sImgId = sSectionId+"-img"; String sBodyId = sSectionId+"-body"; String sParamsId = sSectionId+"-params"; boolean bIsExclusive = getObligation().equalsIgnoreCase(Section.OBLIGATION_EXCLUSIVE); boolean bIsOptional = getObligation().equalsIgnoreCase(Section.OBLIGATION_OPTIONAL); HtmlPanelGroup panel = new HtmlPanelGroup(); panel.setStyleClass("section"); MessageBroker msgBroker = context.extractMessageBroker(); // determine the caption String sCaption = ""; if (getLabel() != null) { sCaption = msgBroker.retrieveMessage(getLabel().getResourceKey()); } if (sCaption.length() == 0) { sCaption = getKey(); } StringBuffer sbOnclick = new StringBuffer(); sbOnclick.append("mdeOnSectionClicked("); sbOnclick.append("this,").append(bIsOptional).append(",").append(bIsExclusive); sbOnclick.append(",'").append(sSectionId).append("')"); // add the caption if (bIsExclusive) { Sections exclusive = getExclusiveSiblings(schema); boolean bIsFirstExclusive = (exclusive.size() > 0) && (this == exclusive.values().iterator().next()); if (bIsFirstExclusive) { HtmlSelectOneRadio radio = new HtmlSelectOneRadio(); radio.setId(sRadioId); radio.setStyleClass("optionalSectionHeader"); radio.setOnclick(sbOnclick.toString()); ArrayList<SelectItem> radioItems = new ArrayList<SelectItem>(); UISelectItems uiItems = new UISelectItems(); uiItems.setValue(radioItems); radio.getChildren().add(uiItems); panel.getChildren().add(radio); int nIdx = 0; for (Section sibling: exclusive.values()) { String sItemLabel = ""; String sItemId = sibling.getFacesId(); if (sibling.getLabel() != null) { sItemLabel = msgBroker.retrieveMessage(sibling.getLabel().getResourceKey()); } if (sItemLabel.length() == 0) { sItemLabel = sibling.getKey(); } radioItems.add(new SelectItem(sItemId,sItemLabel)); if (sibling.getOpen()) { radio.setValue(sItemId); } nIdx++; } } } else if (bIsOptional) { HtmlPanelGroup captionPanel = new HtmlPanelGroup(); captionPanel.setStyleClass("optionalSectionHeader"); HtmlPanelGrid headerTable = new HtmlPanelGrid(); headerTable.setColumns(2); headerTable.setStyleClass("optionalSectionHeader"); headerTable.setSummary(msgBroker.retrieveMessage("catalog.general.designOnly")); HtmlSelectBooleanCheckbox checkBox = new HtmlSelectBooleanCheckbox(); checkBox.setId(sCheckboxId); checkBox.setSelected(getOpen()); checkBox.setOnclick(sbOnclick.toString()); headerTable.getChildren().add(checkBox); HtmlOutputLabel caption = new HtmlOutputLabel(); // even label has to have unique id (for GlassFish) caption.setId(sCheckboxId+"label"); caption.setFor(sCheckboxId); caption.setValue(sCaption); caption.setStyleClass("sectionCaption"); headerTable.getChildren().add(caption); panel.getChildren().add(headerTable); } else { HtmlPanelGrid headerTable = new HtmlPanelGrid(); headerTable.setColumns(3); headerTable.setStyleClass("mandatorySectionHeader"); headerTable.setSummary(msgBroker.retrieveMessage("catalog.general.designOnly")); headerTable.setOnclick(sbOnclick.toString()); HtmlSelectBooleanCheckbox checkBox = new HtmlSelectBooleanCheckbox(); checkBox.setId(sCheckboxId); checkBox.setSelected(getOpen()); //checkBox.setOnclick(sbOnclick.toString()); checkBox.setStyle("display:none;"); headerTable.getChildren().add(checkBox); HtmlGraphicImage img = new HtmlGraphicImage(); img.setId(sImgId); setGraphicUrl(img); headerTable.getChildren().add(img); HtmlOutputText caption = new HtmlOutputText(); caption.setValue(sCaption); caption.setStyleClass("sectionCaption"); headerTable.getChildren().add(caption); if (getLabel() != null) { panel.getChildren().add(headerTable); } else { panel.setStyleClass(""); } } // make the section body boolean bContainerOnly = (getLabel() == null); String sBodyClass = "sectionBody"; if (bContainerOnly) sBodyClass= ""; HtmlPanelGrid sectionBody = new HtmlPanelGrid(); sectionBody.setId(sBodyId); sectionBody.setStyleClass(sBodyClass); setBodyDisplay(sectionBody); panel.getChildren().add(sectionBody); // make the table to hold section parameters, add all parameters HtmlPanelGrid parametersTable = new HtmlPanelGrid(); parametersTable.setId(sParamsId); parametersTable.setColumns(2); parametersTable.setStyleClass("parameters"); parametersTable.setColumnClasses("parameterLabel,parameterInput"); parametersTable.setSummary(msgBroker.retrieveMessage("catalog.general.designOnly")); for (Parameter parameter: getParameters().values()) { if (parameter.getVisible()) { UIComponent cmpLabel = null; if (parameter.getLabel() != null) { cmpLabel = parameter.getLabel().makeEditorLabel(context,this,parameter); } if (cmpLabel == null) cmpLabel = new HtmlOutputText(); parametersTable.getChildren().add(cmpLabel); if (parameter.getInput() != null) { UIComponent cmp = parameter.getInput().makeInputComponent(context,this,parameter); if (cmp != null) parametersTable.getChildren().add(cmp); } } else { // non-visible hidden text if ((parameter.getInput() != null) && (parameter.getInput() instanceof InputText)) { HtmlInputHidden cmpLabel = new HtmlInputHidden(); cmpLabel.setId(parameter.getInput().getFacesId()+"-plcHldr"); HtmlInputHidden cmp = new HtmlInputHidden(); cmp.setId(parameter.getInput().getFacesId()); parameter.getInput().setComponentValue(context,cmp,parameter); parametersTable.getChildren().add(cmpLabel); parametersTable.getChildren().add(cmp); } } } if (parametersTable.getChildCount() > 0) { sectionBody.getChildren().add(parametersTable); } // append all sub-sections for (Section section: getSections().values()) { section.appendEditorComponents(schema,context,sectionBody); } if ((panel != null) && (panel.getChildCount() > 0) && panel.isRendered()) { parentComponent.getChildren().add(panel); } } /** * Configures the object based upon a node loaded from a * schema configuration XML. * <br/>The super.configure method should be invoked prior to any * sub-class configuration. * <p/> * The following attributes are configured: * <br/>key open obligation select delete visibleOnDetails * <p/> * The following child nodes are configured: * <br/>label parameter[] section[] * @param context the configuration context * @param node the configuration node * @param attributes the attributes of the configuration node */ @Override public void configure(CfgContext context, Node node, NamedNodeMap attributes) { super.configure(context,node,attributes); // configure attributes setOpen(Val.chkBool(DomUtil.getAttributeValue(attributes,"open"),true)); setObligation(DomUtil.getAttributeValue(attributes,"obligation")); setSelect(DomUtil.getAttributeValue(attributes,"select")); setDelete(DomUtil.getAttributeValue(attributes,"delete")); setUseSelectForDelete(Val.chkBool(DomUtil.getAttributeValue(attributes,"useSelectForDelete"),true)); if (getUseSelectForDelete() && (getDelete().length() == 0)) { setDelete(getSelect()); } setVisibleOnDetails(Val.chkBool(DomUtil.getAttributeValue(attributes,"visibleOnDetails"),true)); // configure the label component setLabel(context.getFactory().newLabel(context,DomUtil.findFirst(node,"label"))); // configure the parameter components Node[] aryParameters = DomUtil.findChildren(node,"parameter"); for (Node ndParameter: aryParameters) { getParameters().add(context.getFactory().newParameter(context,ndParameter)); } // configure the sub-section components Node[] arySections = DomUtil.findChildren(node,"section"); for (Node ndSection: arySections) { Section child = context.getFactory().newSection(context,ndSection); if (child != null) { child.setParent(this); getSections().add(child); } } getSections().checkExclusiveOpenStatus(); } /** * Produces a deep clone of the object. * <br/>The duplication constructor is invoked. * <br/>return new Section(this); */ public Section duplicate() { return new Section(this); } /** * Appends property information for the component to a StringBuffer. * <br/>The method is intended to support "FINEST" logging. * <br/>super.echo should be invoked prior appending any local information. * @param sb the StringBuffer to use when appending information */ @Override public void echo(StringBuffer sb) { super.echo(sb); sb.append(" open=\"").append(getOpen()).append("\""); sb.append(" obligation=\"").append(getObligation()).append("\""); //sb.append(" useSelectForDelete=\"").append(getUseSelectForDelete()).append("\""); sb.append(" visibleOnDetails=\"").append(getVisibleOnDetails()).append("\""); if (getSelect().length() > 0) { sb.append("\n select=\"").append(getSelect()).append("\""); } if (getDelete().length() > 0) { sb.append("\n delete=\"").append(getDelete()).append("\""); } if (getLabel() != null) sb.append("\n").append(getLabel()); if (getParameters().size() > 0) sb.append("\n").append(getParameters()); if (getSections().size() > 0) sb.append("\n").append(getSections()); } /** * Evaluates a section based upon the supplied metadata document. * <p/> * The default behavior is to invoke the "evaluate" method * for each parameter within the section as well as each sub-section. * @param schema the schema being evaluated * @param dom the metadata document * @param xpath an XPath object configured with an appropriate * Namespace context for the schema * @throws XPathExpressionException if an evaluation expression fails */ public void evaluate(Schema schema, Document dom, XPath xpath) throws XPathExpressionException { // determine if an optional section is present boolean bIsExclusive = getObligation().equalsIgnoreCase(Section.OBLIGATION_EXCLUSIVE); boolean bIsOptional = getObligation().equalsIgnoreCase(Section.OBLIGATION_OPTIONAL); if (bIsExclusive || bIsOptional) { setOpen(false); if (getSelect().length() > 0) { NodeList nl = (NodeList)xpath.evaluate(getSelect(),dom,XPathConstants.NODESET); setOpen(nl.getLength() > 0); } } // evaluate parameters and sub-sections for (Parameter parameter: getParameters().values()) { parameter.evaluate(schema,dom,xpath); } for (Section section: getSections().values()) { section.evaluate(schema,dom,xpath); } getSections().checkExclusiveOpenStatus(); } /** * Force a section open within the editor. * @param editorForm the Faces HtmlForm for the metadata editor */ public void forceOpen(UIComponent editorForm) { String sSectionId = getFacesId(); String sCheckboxId = sSectionId+"-chk"; String sRadioId = sSectionId+"-radio"; String sImgId = sSectionId+"-img"; String sBodyId = sSectionId+"-body"; boolean bIsExclusive = getObligation().equalsIgnoreCase(Section.OBLIGATION_EXCLUSIVE); boolean bIsOptional = getObligation().equalsIgnoreCase(Section.OBLIGATION_OPTIONAL); setOpen(true); UIComponent component = editorForm.findComponent(sCheckboxId); if ((component != null) && (component instanceof UISelectBoolean)) { UISelectBoolean checkbox = (UISelectBoolean)component; checkbox.setSelected(getOpen()); } if (!bIsExclusive && !bIsOptional) { component = editorForm.findComponent(sImgId); if ((component != null) && (component instanceof UIGraphic)) { setGraphicUrl((UIGraphic)component); } } component = editorForm.findComponent(sBodyId); if ((component != null) && (component instanceof HtmlPanelGrid)) { setBodyDisplay((HtmlPanelGrid)component); } if (getParent() != null) { getParent().forceOpen(editorForm); } } /** * Sets the display style for the grid holding the section content. * <br/>(open=display:block, closed=display:none) * @param grid the grid component */ private void setBodyDisplay(HtmlPanelGrid grid) { if (getOpen()) { grid.setStyle("display:block;"); } else { grid.setStyle("display:none;"); } } /** * Sets the url for the section graphic (open/closed). * @param graphic the graphic component */ private void setGraphicUrl(UIGraphic graphic) { if (getOpen()) { graphic.setUrl("/catalog/images/section_open.gif"); } else { graphic.setUrl("/catalog/images/section_closed.gif"); } } /** * Triggered on the save event from the metadata editor. * <p/> * The default behavior is to invoke the "unBind" method for * the each parameter as well as each sub-section. * @param schema the active schema * @param context the UI context * @param editorForm the Faces HtmlForm for the metadata editor * @throws SchemaException if an associated Faces UIComponent cannot be located */ public void unBind(Schema schema,UiContext context, UIComponent editorForm) throws SchemaException { _wasUnbound = true; String sSectionId = getFacesId(); String sCheckboxId = sSectionId+"-chk"; String sRadioId = sSectionId+"-radio"; String sImgId = sSectionId+"-img"; String sBodyId = sSectionId+"-body"; boolean bIsExclusive = getObligation().equalsIgnoreCase(Section.OBLIGATION_EXCLUSIVE); boolean bIsOptional = getObligation().equalsIgnoreCase(Section.OBLIGATION_OPTIONAL); UIComponent component; // determine whether or not this section is open if (bIsExclusive) { Sections exclusive = getExclusiveSiblings(schema); boolean bIsFirstExclusive = (exclusive.size() > 0) && (this == exclusive.values().iterator().next()); if (bIsFirstExclusive) { component = editorForm.findComponent(sRadioId); if ((component != null) && (component instanceof HtmlSelectOneRadio)) { HtmlSelectOneRadio radio = (HtmlSelectOneRadio)component; if ((radio.getValue() != null) && (radio.getValue() instanceof String)) { String sChosenId = Val.chkStr((String)radio.getValue()); for (Section sibling: exclusive.values()) { boolean bOpen = sChosenId.equals(sibling.getFacesId()); sibling.setOpen(bOpen); } } } } } else { component = editorForm.findComponent(sCheckboxId); if ((component != null) && (component instanceof UISelectBoolean)) { UISelectBoolean checkbox = (UISelectBoolean)component; setOpen(checkbox.isSelected()); } } // set the graphic for regular sections upon the open status if (!bIsExclusive && !bIsOptional) { component = editorForm.findComponent(sImgId); if ((component != null) && (component instanceof UIGraphic)) { setGraphicUrl((UIGraphic)component); } } // set the body display style based upon the open status component = editorForm.findComponent(sBodyId); if ((component != null) && (component instanceof HtmlPanelGrid)) { setBodyDisplay((HtmlPanelGrid)component); } // un-bind all parameters and sub-sections for (Parameter parameter: getParameters().values()) { parameter.unBind(context,editorForm); } for (Section section: getSections().values()) { section.unBind(schema,context,editorForm); } } /** * Updates the metadata document template based upon entered parameter value(s). * <p/> * The default behavior is to invoke the "update" method * for each parameter within the section as well as each sub-section. * @param dom the metadata document template for the schema * @param xpath an XPath object configured with an appropriate * Namespace context for the schema * @throws XPathExpressionException if an expression fails * @throws SchemaException if the update fails */ public void update(Document dom, XPath xpath) throws XPathExpressionException, SchemaException { // don't update if the section is optional and is not open within the editor boolean bProcessChildren = true; boolean bIsExclusive = getObligation().equalsIgnoreCase(Section.OBLIGATION_EXCLUSIVE); boolean bIsOptional = getObligation().equalsIgnoreCase(Section.OBLIGATION_OPTIONAL); if ((bIsExclusive || bIsOptional) && !getOpen()) { bProcessChildren = false; if (getDelete().length() > 0) { Content.deleteNodes(dom,xpath,getDelete()); } } // update parameters and sub-sections if (bProcessChildren) { for (Parameter parameter: getParameters().values()) { parameter.update(dom,xpath); } for (Section section: getSections().values()) { section.update(dom,xpath); } } } /** * Validates a section. * <p/> * The default behavior is to invoke the "validate" method * for each parameter within the section as well as each sub-section. * <p/> * Encountered errors should be appended to the * schema.getValidationErrors() collection. * <p/> * Parameter values associated with meaning should be used to populate * schema.getMeaning() values. * @param schema the schema being validated */ public void validate(Schema schema) { // don't validate if the section is optional and is not open within the editor boolean bProcessChildren = true; boolean bIsExclusive = getObligation().equalsIgnoreCase(Section.OBLIGATION_EXCLUSIVE); boolean bIsOptional = getObligation().equalsIgnoreCase(Section.OBLIGATION_OPTIONAL); if ((bIsExclusive || bIsOptional) && !getOpen()) { bProcessChildren = false; } // validate parameters and sub-sections if (bProcessChildren) { for (Parameter parameter: getParameters().values()) { parameter.validate(schema,this); } for (Section section: getSections().values()) { section.validate(schema); } } } /** * Selects all parameters conforming to the condiditions defined by predicate. * @param predicate predicate * @return list of selected parameters */ public List<Parameter> selectParameters(Predicate predicate) { return getParameters().selectParameters(predicate); } }