001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.sys.document.web.renderers;
017    
018    import java.io.IOException;
019    
020    import javax.servlet.jsp.JspException;
021    import javax.servlet.jsp.JspWriter;
022    import javax.servlet.jsp.PageContext;
023    import javax.servlet.jsp.tagext.Tag;
024    
025    import org.apache.commons.lang.StringUtils;
026    import org.apache.struts.taglib.html.HiddenTag;
027    import org.kuali.kfs.sys.KFSConstants;
028    import org.kuali.kfs.sys.context.SpringContext;
029    import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
030    import org.kuali.rice.kns.service.KualiConfigurationService;
031    import org.kuali.rice.kns.web.ui.Field;
032    import org.kuali.rice.core.util.KeyLabelPair;
033    import org.springframework.web.util.HtmlUtils;
034    
035    /**
036     * Renderer which displays a read only field
037     */
038    public class ReadOnlyRenderer extends FieldRendererBase {
039        private boolean shouldRenderInquiry = true;
040        
041        /**
042         * @see org.kuali.kfs.sys.document.web.renderers.Renderer#render(javax.servlet.jsp.PageContext, javax.servlet.jsp.tagext.Tag)
043         */
044        public void render(PageContext pageContext, Tag parentTag) throws JspException {
045            JspWriter out = pageContext.getOut();
046    
047            try {
048                String value = discoverRenderValue();
049                out.write(buildBeginSpan());
050                
051                if (!StringUtils.isEmpty(value)) {
052                    if (shouldRenderInquiryLink()) {
053                        out.write(buildBeginInquiryLink());
054                    }                
055                    out.write(value);                
056                    if (shouldRenderInquiryLink()) {
057                        out.write(buildEndInquiryLink());
058                    }                                
059                } else {
060                    out.write(buildNonBreakingSpace());
061                }
062                
063                out.write(buildEndSpan());
064            }
065            catch (IOException ioe) {
066                throw new JspException("Difficulty rendering read only field", ioe);
067            }
068        }
069    
070        /**
071         * Clears the persisting tag.
072         * @see org.kuali.kfs.sys.document.web.renderers.FieldRendererBase#clear()
073         */
074        @Override
075        public void clear() {
076            super.clear();
077        }
078    
079        /**
080         * Generates the HTML for the opening span tag to wrap the displayed value
081         * @param propertyPrefix the property path from the form the business object being rendered
082         * @return the HTML for the opening span 
083         */
084        protected String buildBeginSpan() {
085            StringBuilder beginSpan = new StringBuilder();        
086            beginSpan.append("<span id=\"");
087            beginSpan.append(getFieldName());
088            beginSpan.append(".div\">");        
089            return beginSpan.toString();
090        }
091        
092        /**
093         * Generates the HTML for the closing span tag to wrap the displayed value
094         * @return the HTML for the closing span
095         */
096        protected String buildEndSpan() {
097            return "</span>";
098        }
099        
100        /**
101         * Builds the opening anchor tag to make the displayed read only value open up an inquiry screen
102         * @return the HTML for the opening inquiry anchor tag
103         */
104        protected String buildBeginInquiryLink() {
105            StringBuilder beginInquiryLink = new StringBuilder();
106            
107            if (getField().getInquiryURL() instanceof AnchorHtmlData) {
108                AnchorHtmlData htmlData = (AnchorHtmlData) getField().getInquiryURL();
109                beginInquiryLink.append("<a href=\"");
110                beginInquiryLink.append(SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.APPLICATION_URL_KEY));
111                beginInquiryLink.append("/kr/");
112                beginInquiryLink.append(htmlData.getHref());
113                beginInquiryLink.append("\" title=\"");
114                beginInquiryLink.append(htmlData.getTitle());
115                beginInquiryLink.append("\" target=\"blank\">");
116                
117            }
118            
119            return beginInquiryLink.toString();
120        }
121        
122        /**
123         * Builds the closing anchor tag for the inquiry link
124         * @return the HTML for the closing inquiry anchor tag
125         */
126        protected String buildEndInquiryLink() {
127            if (getField().getInquiryURL() instanceof AnchorHtmlData) {
128                return "</a>";
129            }
130            return "";
131        }
132        
133        /**
134         * Determines if this read only field should attempt to display the inquiry link around the rendered value
135         * @return true if the inquiry link should be rendered, false otherwise
136         */
137        protected boolean shouldRenderInquiryLink() {
138            return getField().getInquiryURL() != null && !StringUtils.isBlank(((AnchorHtmlData)getField().getInquiryURL()).getHref()) && isInquirableValue(getField().getPropertyValue())  && shouldRenderInquiry;
139        }
140        
141        /**
142         * Determines if the given property value is worthy of having an inquiry for it
143         * @param propertyValue the value of the property to potentially render an inquiry for
144         * @return true if the value is inquirable; false otherwise
145         */
146        protected boolean isInquirableValue(String propertyValue) {
147            return !StringUtils.isBlank(propertyValue) && !propertyValue.matches("^-*$");
148        }
149        
150        /**
151         * Sets the shouldRenderInquiry attribute value.
152         * @param shouldRenderInquiry The shouldRenderInquiry to set.
153         */
154        public void setShouldRenderInquiry(boolean shouldRenderInquiry) {
155            this.shouldRenderInquiry = shouldRenderInquiry;
156        }
157    
158        /**
159         * Dropdowns are typically fields with codes, which may be close to meaningless, with more explanative labels.  Therefore,
160         * fields which are drop downs should display the label instead
161         * @return the label for the chosen key on the field if possible; otherwise, an empty String
162         */
163        protected String getValueForDropDown() {
164            for (Object keyLabelPairAsObject : getField().getFieldValidValues()) {
165                final KeyLabelPair keyLabelPair = (KeyLabelPair)keyLabelPairAsObject;
166                if (getField().getPropertyValue().equalsIgnoreCase(keyLabelPair.getKey().toString())) {
167                    return keyLabelPair.getLabel();
168                }
169            }
170            return null;
171        }
172        
173        /**
174         * An algorithm to discover the actual read only value to render.  If this is a drop down, it finds the renderable value for the drop down;
175         * if the value is unavailable, it searches for the property in unconverted values
176         * @return the value to display
177         */
178        protected String discoverRenderValue() {
179            String value = getField().getPropertyValue();
180            if (getField().getFieldType().equals(Field.DROPDOWN) && !StringUtils.isEmpty(value)) {
181                value = getValueForDropDown();
182            }
183            
184            return value;
185        }
186        
187        /**
188         * @return the HTML for a non-breaking space, so the box isn't all empty
189         */
190        protected String buildNonBreakingSpace() {
191            return "&nbsp;";
192        }
193    
194        /**
195         * Nope, no quick finder here
196         * @see org.kuali.kfs.sys.document.web.renderers.FieldRenderer#renderQuickfinder()
197         */
198        public boolean renderQuickfinder() {
199            return false;
200        }
201    
202        /**
203         * @see org.kuali.kfs.sys.document.web.renderers.FieldRendererBase#closeNoWrapSpan(javax.servlet.jsp.PageContext, javax.servlet.jsp.tagext.Tag)
204         */
205        @Override
206        public void closeNoWrapSpan(PageContext pageContext, Tag parentTag) throws JspException {
207            // do nothing - read onlys don't need "no wrap"
208        }
209    
210        /**
211         * @see org.kuali.kfs.sys.document.web.renderers.FieldRendererBase#openNoWrapSpan(javax.servlet.jsp.PageContext, javax.servlet.jsp.tagext.Tag)
212         */
213        @Override
214        public void openNoWrapSpan(PageContext pageContext, Tag parentTag) throws JspException {
215            // do nothing - read onlys don't need "no wrap"
216        }
217        
218    }