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.validation;
018
019import org.apache.wicket.core.util.string.CssUtils;
020import org.apache.wicket.feedback.ContainerFeedbackMessageFilter;
021import org.apache.wicket.feedback.FeedbackCollector;
022import org.apache.wicket.feedback.IFeedback;
023import org.apache.wicket.feedback.IFeedbackMessageFilter;
024import org.apache.wicket.markup.ComponentTag;
025import org.apache.wicket.markup.html.WebMarkupContainer;
026import org.apache.wicket.markup.html.border.Border;
027import org.apache.wicket.markup.html.form.Form;
028
029/**
030 * A border that can be placed around a form component to indicate when the bordered child/children
031 * has a validation error. A child of the border named "errorIndicator" will be shown and hidden
032 * depending on whether the child has an error. A typical error indicator might be a little red
033 * asterisk.
034 * <p>
035 * <strong>Note: </strong> Since this border checks its children do not use
036 * TransparentWebMarkupContainer and add the children directly into the border
037 * 
038 * @author Jonathan Locke
039 * @author Eelco Hillenius
040 */
041public class FormComponentFeedbackBorder extends Border implements IFeedback
042{
043        private static final long serialVersionUID = 1L;
044
045        private static final String ERROR_CSS_CLASS_KEY = CssUtils
046                .key(FormComponentFeedbackBorder.class, "error");
047
048        /** Visible property cache. */
049        private boolean visible;
050
051        /**
052         * Error indicator that will be shown whenever there is an error-level message for the
053         * collecting component.
054         */
055        private final class ErrorIndicator extends WebMarkupContainer
056        {
057                private static final long serialVersionUID = 1L;
058
059                /**
060                 * Construct.
061                 * 
062                 * @param id
063                 *            component id
064                 */
065                public ErrorIndicator(String id)
066                {
067                        super(id);
068                }
069
070                /**
071                 * @see org.apache.wicket.Component#isVisible()
072                 */
073                @Override
074                public boolean isVisible()
075                {
076                        return visible;
077                }
078
079                @Override
080                protected void onComponentTag(ComponentTag tag)
081                {
082                        super.onComponentTag(tag);
083                        tag.put("class", getString(ERROR_CSS_CLASS_KEY));
084                }
085        }
086
087        /**
088         * Constructor.
089         * 
090         * @param id
091         *            See Component
092         */
093        public FormComponentFeedbackBorder(final String id)
094        {
095                super(id);
096                addToBorder(new ErrorIndicator("errorIndicator"));
097        }
098
099        /**
100         * Update the 'visible' flag to indicate the existence (or lack thereof) of feedback messages
101         */
102        @Override
103        protected void onBeforeRender()
104        {
105                super.onBeforeRender();
106                // Get the messages for the current page
107                visible = new FeedbackCollector(getPage()).collect(getMessagesFilter()).size() > 0;
108        }
109
110        /**
111         * @return Let subclass specify some other filter
112         */
113        protected IFeedbackMessageFilter getMessagesFilter()
114        {
115                return new ContainerFeedbackMessageFilter(this);
116        }
117}