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
032     * or one times. This component is a variant of
033     * {@link org.apache.tapestry.components.Conditional}, but is designed for
034     * operation in a form. The component parameters are stored in hidden fields
035     * during rendering and are taken from those fields during the rewind, thus no
036     * StaleLink exceptions occur. [ <a
037     * href="../../../../../ComponentReference/contrib.FormConditional.html">Component
038     * Reference </a>]
039     * 
040     * @author Mindbridge
041     * @since 3.0
042     */
043    
044    public abstract class FormConditional extends AbstractComponent implements
045            IFormComponent
046    {
047    
048        protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
049        {
050            IForm form = TapestryUtils.getForm(cycle, this);
051    
052            boolean cycleRewinding = cycle.isRewinding();
053    
054            // If the cycle is rewinding, but not this particular form,
055            // then do nothing (don't even render the body).
056    
057            if (cycleRewinding && !form.isRewinding()) return;
058    
059            String name = form.getElementId(this);
060    
061            boolean condition = getCondition(cycle, form, name);
062    
063            getListenerInvoker().invokeListener(getListener(), this, cycle);
064    
065            // render the component body only if the condition is true
066            if (condition)
067            {
068                String element = getElement();
069    
070                boolean render = !cycleRewinding && HiveMind.isNonBlank(element);
071    
072                if (render)
073                {
074                    writer.begin(element);
075                    renderInformalParameters(writer, cycle);
076                }
077    
078                renderBody(writer, cycle);
079    
080                if (render) writer.end(element);
081            }
082        }
083    
084        private boolean getCondition(IRequestCycle cycle, IForm form, String name)
085        {
086            boolean condition;
087    
088            if (!cycle.isRewinding())
089            {
090                condition = getCondition();
091                writeValue(form, name, condition);
092            }
093            else
094            {
095                String submittedCondition = cycle.getParameter(name);
096                condition = convertValue(submittedCondition);
097            }
098    
099            if (isParameterBound("conditionValue")) setConditionValue(condition);
100    
101            return condition;
102        }
103    
104        private void writeValue(IForm form, String name, boolean value)
105        {
106            String externalValue;
107    
108            try
109            {
110                externalValue = getDataSqueezer().squeeze(
111                        value ? Boolean.TRUE : Boolean.FALSE);
112            }
113            catch (Exception ex)
114            {
115                throw new ApplicationRuntimeException(Tapestry.format(
116                        "FormConditional.unable-to-convert-value", Boolean
117                                .toString(value)), this, null, ex);
118            }
119    
120            form.addHiddenValue(name, externalValue);
121        }
122    
123        private boolean convertValue(String value)
124        {
125            try
126            {
127                Boolean b = (Boolean) getDataSqueezer().unsqueeze(value);
128                return b.booleanValue();
129            }
130            catch (Exception ex)
131            {
132                throw new ApplicationRuntimeException(Tapestry.format(
133                        "FormConditional.unable-to-convert-string", value), this,
134                        null, ex);
135            }
136        }
137    
138        public abstract DataSqueezer getDataSqueezer();
139    
140        // Part of the FormElement interface.
141    
142        public boolean isDisabled()
143        {
144            return false;
145        }
146    
147        public abstract boolean getCondition();
148    
149        public abstract void setConditionValue(boolean value);
150    
151        public abstract String getElement();
152    
153        public abstract IActionListener getListener();
154    
155        /**
156         * Injected.
157         * 
158         * @since 4.0
159         */
160    
161        public abstract ListenerInvoker getListenerInvoker();
162    
163    }