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 }