001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.contrib.form;
016    
017    import org.apache.hivemind.ApplicationRuntimeException;
018    import org.apache.hivemind.HiveMind;
019    import org.apache.tapestry.AbstractComponent;
020    import org.apache.tapestry.IActionListener;
021    import org.apache.tapestry.IForm;
022    import org.apache.tapestry.IMarkupWriter;
023    import org.apache.tapestry.IRequestCycle;
024    import org.apache.tapestry.Tapestry;
025    import org.apache.tapestry.TapestryUtils;
026    import org.apache.tapestry.form.IFormComponent;
027    import org.apache.tapestry.listener.ListenerInvoker;
028    import org.apache.tapestry.services.DataSqueezer;
029    
030    /**
031     * A conditional element on a page which will render its wrapped elements zero or one times. This
032     * component is a variant of {@link org.apache.tapestry.components.Conditional}, but is designed
033     * for operation in a form. The component parameters are stored in hidden fields during rendering
034     * and are taken from those fields during the rewind, thus no StaleLink exceptions occur. [ <a
035     * href="../../../../../ComponentReference/contrib.FormConditional.html">Component Reference </a>]
036     * 
037     * @author Mindbridge
038     * @since 3.0
039     */
040    
041    public abstract class FormConditional extends AbstractComponent implements IFormComponent
042    {
043        protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
044        {
045            IForm form = TapestryUtils.getForm(cycle, this);
046    
047            boolean cycleRewinding = cycle.isRewinding();
048    
049            // If the cycle is rewinding, but not this particular form,
050            // then do nothing (don't even render the body).
051    
052            if (cycleRewinding && !form.isRewinding())
053                return;
054    
055            String name = form.getElementId(this);
056    
057            boolean condition = getCondition(cycle, form, name);
058    
059            getListenerInvoker().invokeListener(getListener(), this, cycle);
060    
061            // render the component body only if the condition is true
062            if (condition)
063            {
064                String element = getElement();
065    
066                boolean render = !cycleRewinding && HiveMind.isNonBlank(element);
067    
068                if (render)
069                {
070                    writer.begin(element);
071                    renderInformalParameters(writer, cycle);
072                }
073    
074                renderBody(writer, cycle);
075    
076                if (render)
077                    writer.end(element);
078            }
079        }
080    
081        private boolean getCondition(IRequestCycle cycle, IForm form, String name)
082        {
083            boolean condition;
084    
085            if (!cycle.isRewinding())
086            {
087                condition = getCondition();
088                writeValue(form, name, condition);
089            }
090            else
091            {
092                String submittedCondition = cycle.getParameter(name);
093                condition = convertValue(submittedCondition);
094            }
095    
096            if (isParameterBound("conditionValue"))
097                setConditionValue(condition);
098    
099            return condition;
100        }
101    
102        private void writeValue(IForm form, String name, boolean value)
103        {
104            String externalValue;
105    
106            try
107            {
108                externalValue = getDataSqueezer().squeeze(value ? Boolean.TRUE : Boolean.FALSE);
109            }
110            catch (Exception ex)
111            {
112                throw new ApplicationRuntimeException(Tapestry.format(
113                        "FormConditional.unable-to-convert-value",
114                        Boolean.toString(value)), this, null, ex);
115            }
116    
117            form.addHiddenValue(name, externalValue);
118        }
119    
120        private boolean convertValue(String value)
121        {
122            try
123            {
124                Boolean b = (Boolean) getDataSqueezer().unsqueeze(value);
125                return b.booleanValue();
126            }
127            catch (Exception ex)
128            {
129                throw new ApplicationRuntimeException(Tapestry.format(
130                        "FormConditional.unable-to-convert-string",
131                        value), this, null, ex);
132            }
133        }
134    
135        public abstract DataSqueezer getDataSqueezer();
136    
137        // Part of the FormElement interface.
138    
139        public boolean isDisabled()
140        {
141            return false;
142        }
143    
144        public abstract boolean getCondition();
145    
146        public abstract void setConditionValue(boolean value);
147    
148        public abstract String getElement();
149    
150        public abstract IActionListener getListener();
151    
152        /**
153         * Injected.
154         * 
155         * @since 4.0
156         */
157    
158        public abstract ListenerInvoker getListenerInvoker();
159    
160    }