001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.markup.html.form;
018
019import java.text.SimpleDateFormat;
020
021import org.apache.wicket.Component;
022import org.apache.wicket.model.IModel;
023import org.apache.wicket.model.IObjectClassAwareModel;
024import org.apache.wicket.util.string.Strings;
025
026/**
027 * Abstract base class for TextArea and TextField.
028 * 
029 * @author Jonathan Locke
030 * 
031 * @param <T>
032 *            The model object type
033 */
034public abstract class AbstractTextComponent<T> extends FormComponent<T>
035{
036        // Flag for the type resolving. FLAG_RESERVED1-3 are taken by form component
037        private static final int TYPE_RESOLVED = Component.FLAG_RESERVED4;
038
039        /**
040         * 
041         */
042        private static final long serialVersionUID = 1L;
043
044        /**
045         * Text components that implement this interface are know to be able to provide a pattern for
046         * formatting output and parsing input. This can be used by for instance date picker components
047         * which are based on JavaScript and need some knowledge as to how to communicate properly via
048         * request parameters.
049         */
050        public interface ITextFormatProvider
051        {
052                /**
053                 * Gets the pattern for printing output and parsing input.
054                 * 
055                 * @return The text pattern
056                 * @see SimpleDateFormat
057                 */
058                String getTextFormat();
059        }
060
061        /**
062         * @see org.apache.wicket.Component#Component(String)
063         */
064        public AbstractTextComponent(String id)
065        {
066                this(id, null);
067        }
068
069        /**
070         * @param id
071         * @param model
072         * @see org.apache.wicket.Component#Component(String, IModel)
073         */
074        public AbstractTextComponent(final String id, final IModel<T> model)
075        {
076                super(id, model);
077                setConvertEmptyInputStringToNull(true);
078        }
079
080        /**
081         * Should the bound object become <code>null</code> when the input is empty?
082         * 
083         * @return <code>true</code> when the value will be set to <code>null</code> when the input is
084         *         empty.
085         */
086        public final boolean getConvertEmptyInputStringToNull()
087        {
088                return getFlag(FLAG_CONVERT_EMPTY_INPUT_STRING_TO_NULL);
089        }
090
091        /**
092         * TextFields return an empty string even if the user didn't type anything in them. To be able
093         * to work nicely with validation, this method returns false.
094         * 
095         * @see org.apache.wicket.markup.html.form.FormComponent#isInputNullable()
096         */
097        @Override
098        public boolean isInputNullable()
099        {
100                return false;
101        }
102
103        /**
104         * Convert the input respecting the flag convertEmptyInputStringToNull. Subclasses that override
105         * this method should test this flag also.
106         * 
107         * @see org.apache.wicket.markup.html.form.FormComponent#convertInput()
108         */
109        @Override
110        public void convertInput()
111        {
112                // Stateless forms don't have to be rendered first, convertInput could be called before
113                // onBeforeRender calling resolve type here again to check if the type is correctly set.
114                resolveType();
115                String[] value = getInputAsArray();
116                String tmp = value != null && value.length > 0 ? value[0] : null;
117                if (getConvertEmptyInputStringToNull() && Strings.isEmpty(tmp))
118                {
119                        setConvertedInput(null);
120                }
121                else
122                {
123                        super.convertInput();
124                }
125        }
126
127        /**
128         * If the type is not set try to guess it if the model supports it.
129         * 
130         * @see org.apache.wicket.Component#onBeforeRender()
131         */
132        @Override
133        protected void onBeforeRender()
134        {
135                super.onBeforeRender();
136                resolveType();
137        }
138
139        /**
140         * 
141         */
142        private void resolveType()
143        {
144                if (!getFlag(TYPE_RESOLVED) && getType() == null)
145                {
146                        Class<?> type = getModelType(getDefaultModel());
147                        setType(type);
148                        setFlag(TYPE_RESOLVED, true);
149                }
150        }
151
152        /**
153         * 
154         * @param model
155         * @return the type of the model object or <code>null</code>
156         */
157        private Class<?> getModelType(IModel<?> model)
158        {
159                if (model instanceof IObjectClassAwareModel)
160                {
161                        Class<?> objectClass = ((IObjectClassAwareModel<?>)model).getObjectClass();
162                        return objectClass;
163                }
164                else
165                {
166                        return null;
167                }
168        }
169
170        /**
171         * Should the bound object become <code>null</code> when the input is empty?
172         * 
173         * @param flag
174         *            the value to set this flag.
175         * @return this
176         */
177        public final FormComponent<T> setConvertEmptyInputStringToNull(boolean flag)
178        {
179                setFlag(FLAG_CONVERT_EMPTY_INPUT_STRING_TO_NULL, flag);
180                return this;
181        };
182}