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 " ";
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 }