/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.sys.document.web.renderers; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.sys.businessobject.SourceAccountingLine; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.document.AccountingDocument; import org.kuali.kfs.sys.document.datadictionary.AccountingLineGroupDefinition; import org.kuali.kfs.sys.document.datadictionary.AccountingLineViewActionDefinition; import org.kuali.kfs.sys.document.web.AccountingLineViewAction; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.kns.web.taglib.html.KNSFileTag; import org.kuali.rice.kns.web.taglib.html.KNSImageTag; /** * Renders the standard group header/import line */ public class GroupTitleLineRenderer implements Renderer, CellCountCurious { private int titleCellSpan = 4; private int cellCount = 1; private AccountingLineGroupDefinition accountingLineGroupDefinition; private AccountingDocument accountingDocument; private String lineCollectionProperty; private KNSFileTag scriptFileTag = new KNSFileTag(); private KNSFileTag noscriptFileTag = new KNSFileTag(); private KNSImageTag uploadButtonTag = new KNSImageTag(); private KNSImageTag cancelButtonTag = new KNSImageTag(); private boolean shouldUpload = true; private boolean canEdit = false; private boolean groupActionsRendered = false; /** * Constructs a ImportLineRenderer, setting defaults on the tags that will always exist */ public GroupTitleLineRenderer() { scriptFileTag.setSize("30"); noscriptFileTag.setSize("30"); noscriptFileTag.setStyle("font:10px;height:16px;"); uploadButtonTag.setSrc(SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString("externalizable.images.url") + "tinybutton-add1.gif"); uploadButtonTag.setStyleClass("tinybutton"); cancelButtonTag.setProperty("methodToCall.cancel"); cancelButtonTag.setSrc(SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString("externalizable.images.url") + "tinybutton-cancelimport.gif"); cancelButtonTag.setStyleClass("tinybutton"); } /** * @see org.kuali.kfs.sys.document.web.renderers.Renderer#clear() */ public void clear() { cellCount = 1; accountingLineGroupDefinition = null; titleCellSpan = 4; lineCollectionProperty = null; accountingDocument = null; shouldUpload = true; canEdit = false; // clean script file tag scriptFileTag.setPageContext(null); scriptFileTag.setParent(null); scriptFileTag.setProperty(null); // clean noscript file tag noscriptFileTag.setPageContext(null); noscriptFileTag.setParent(null); noscriptFileTag.setProperty(null); // clean upload button tag uploadButtonTag.setPageContext(null); uploadButtonTag.setParent(null); uploadButtonTag.setProperty(null); uploadButtonTag.setAlt(null); uploadButtonTag.setTitle(null); // clean cancel import tag cancelButtonTag.setPageContext(null); cancelButtonTag.setParent(null); cancelButtonTag.setAlt(null); cancelButtonTag.setTitle(null); cancelButtonTag.setOnclick(null); } /** * @see org.kuali.kfs.sys.document.web.renderers.Renderer#render(javax.servlet.jsp.PageContext, javax.servlet.jsp.tagext.Tag, * org.kuali.core.bo.BusinessObject) */ public void render(PageContext pageContext, Tag parentTag) throws JspException { try { pageContext.getOut().write(buildRowBeginning()); pageContext.getOut().write(buildTitleCell()); this.renderGroupLevelActions(pageContext, parentTag); pageContext.getOut().write(buildRowEnding()); } catch (IOException ioe) { throw new JspException("Difficulty in rendering import/group header line", ioe); } } /** * Builds a tag for the row beginning * * @returns the String with the HTML for the row opening */ protected String buildRowBeginning() { return "<tr>"; } /** * Builds the tag for the row beginning * * @returns the String with the HTML for the row beginning */ protected String buildRowEnding() { return "</tr>"; } protected void renderGroupLevelActions(PageContext pageContext, Tag parentTag) throws JspException { JspWriter out = pageContext.getOut(); try { out.write(this.buildGroupActionsBeginning()); this.renderGroupActions(pageContext, parentTag); this.renderUploadCell(pageContext, parentTag); out.write(this.buildGroupActionsColumnEnding()); } catch (IOException ioe) { throw new JspException("Difficulty rendering group level actions", ioe); } } /** * Builds a tag for the row beginning * * @returns the String with the HTML for the row opening */ protected String buildGroupActionsBeginning() { if (this.canUpload() || this.isGroupActionsRendered()) { StringBuilder groupActionsBeginning = new StringBuilder(); final int width = cellCount - titleCellSpan; groupActionsBeginning.append("<td "); groupActionsBeginning.append("colspan=\""); groupActionsBeginning.append(Integer.toString(width)); groupActionsBeginning.append("\" "); groupActionsBeginning.append("class=\"tab-subhead-import\" "); groupActionsBeginning.append("align=\"right\" "); groupActionsBeginning.append("nowrap=\"nowrap\" "); groupActionsBeginning.append("style=\"border-right: none;\""); groupActionsBeginning.append(">"); return groupActionsBeginning.toString(); } return StringUtils.EMPTY; } /** * Builds the tag for the row beginning * * @returns the String with the HTML for the row beginning */ protected String buildGroupActionsColumnEnding() { return this.canUpload() || this.isGroupActionsRendered() ? "</td>" : StringUtils.EMPTY; } /** * Builds the tags for the title cell of the import line * * @return the String with the HTML for the title cell */ protected String buildTitleCell() { StringBuilder titleCell = new StringBuilder(); int colSpan = (this.canUpload() || this.isGroupActionsRendered()) ? titleCellSpan : cellCount; titleCell.append("<td "); titleCell.append("colspan=\""); titleCell.append(colSpan); titleCell.append("\" "); titleCell.append("class=\"tab-subhead\" "); titleCell.append("style=\"border-right: none;\""); titleCell.append(">"); titleCell.append(buildGroupAnchor()); titleCell.append(accountingLineGroupDefinition.getGroupLabel()); titleCell.append("</td>"); return titleCell.toString(); } /** * Builds the unique anchor for this group * * @return the unique anchor for this group */ protected String buildGroupAnchor() { return "<a name=\"accounting" + getGroupInfix() + "Anchor\"></a>"; } protected void renderGroupActions(PageContext pageContext, Tag parentTag) throws JspException { List<? extends AccountingLineViewActionDefinition> accountingLineGroupActions = accountingLineGroupDefinition.getAccountingLineGroupActions(); if (!this.isGroupActionsRendered() || accountingLineGroupActions == null || accountingLineGroupActions.isEmpty()) { return; } List<AccountingLineViewAction> viewActions = new ArrayList<AccountingLineViewAction>(); for (AccountingLineViewActionDefinition action : accountingLineGroupActions) { String actionMethod = action.getActionMethod(); String actionLabel = action.getActionLabel(); String imageName = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString("externalizable.images.url") + action.getImageName(); AccountingLineViewAction viewAction = new AccountingLineViewAction(actionMethod, actionLabel, imageName); viewActions.add(viewAction); } if (!viewActions.isEmpty()) { ActionsRenderer actionsRenderer = new ActionsRenderer(); actionsRenderer.setTagBeginning(" "); actionsRenderer.setTagEnding(" "); actionsRenderer.setPostButtonSpacing(" "); actionsRenderer.setActions(viewActions); actionsRenderer.render(pageContext, parentTag); actionsRenderer.clear(); } } /** * A dumb way to get the group infix that tries to figure out if it's dealing with a source or target line * * @return the String "source" or "target" to populate the buildGroupAnchor */ protected String getGroupInfix() { Class accountingLineClass = accountingLineGroupDefinition.getAccountingLineClass(); return (accountingLineClass.isAssignableFrom(SourceAccountingLine.class) ? "source" : "target"); } /** * Oy, the big one...this one actually renders instead of returning the HTML in a String. This is because it's kind of complex * (and a likely target for future refactoring) * * @param pageContext the page contex to render to * @param parentTag the tag that is requesting all the rendering * @throws JspException thrown if something goes wrong */ protected void renderUploadCell(PageContext pageContext, Tag parentTag) throws JspException { JspWriter out = pageContext.getOut(); if (canUpload()) { try { String hideImport = getHideImportName(); String showImport = getShowImportName(); String showLink = getShowLinkName(); String uploadDiv = getUploadDivName(); out.write("\n<SCRIPT type=\"text/javascript\">\n"); out.write("<!--\n"); out.write("\tfunction " + hideImport + "(showLinkId, uploadDivId) {\n"); out.write("\t\tdocument.getElementById(showLinkId).style.display=\"inline\";\n"); out.write("\t\tdocument.getElementById(uploadDivId).style.display=\"none\";\n"); out.write("\t}\n"); out.write("\tfunction " + showImport + "(showLinkId, uploadDivId) {\n"); out.write("\t\tdocument.getElementById(showLinkId).style.display=\"none\";\n"); out.write("\t\tdocument.getElementById(uploadDivId).style.display=\"inline\";\n"); out.write("\t}\n"); out.write("\tdocument.write(\n"); out.write("\t\t'<a id=\"" + showLink + "\" href=\"#\" onclick=\"" + showImport + "(\\\'" + showLink + "\\\',\\\'" + uploadDiv + "\\\');return false;\">' +\n"); out.write("\t\t'<img src=\"" + SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString("externalizable.images.url") + "tinybutton-importlines.gif\" title=\"import file\" alt=\"import file\"' +\n"); out.write("\t\t'width=\"72\" border=\"0\">' +\n"); out.write("\t\t'</a>' +\n"); out.write("\t\t'<div id=\"" + uploadDiv + "\" style=\"display:none;\" >' +\n"); out.write("\t\t'"); scriptFileTag.setPageContext(pageContext); scriptFileTag.setParent(parentTag); String index = StringUtils.substringBetween(getLineCollectionProperty(), "[", "]"); if (StringUtils.isNotBlank(index) && getLineCollectionProperty().contains("transactionEntries")) { scriptFileTag.setProperty(StringUtils.substringBeforeLast(getLineCollectionProperty(), ".") + "." + accountingLineGroupDefinition.getImportedLinePropertyPrefix() + "File"); } else { scriptFileTag.setProperty(accountingLineGroupDefinition.getImportedLinePropertyPrefix() + "File"); } scriptFileTag.doStartTag(); scriptFileTag.doEndTag(); out.write("' +\n"); out.write("\t\t'"); uploadButtonTag.setPageContext(pageContext); uploadButtonTag.setParent(parentTag); uploadButtonTag.setProperty("methodToCall.upload" + StringUtils.capitalize(accountingLineGroupDefinition.getImportedLinePropertyPrefix()) + "Lines" + "." + getLineCollectionProperty()); uploadButtonTag.setAlt("insert " + accountingLineGroupDefinition.getGroupLabel() + " accounting lines"); uploadButtonTag.setTitle("insert " + accountingLineGroupDefinition.getGroupLabel() + " accounting lines"); uploadButtonTag.doStartTag(); uploadButtonTag.doEndTag(); out.write("' +\n"); out.write("\t\t'"); cancelButtonTag.setPageContext(pageContext); cancelButtonTag.setParent(parentTag); cancelButtonTag.setAlt("Cancel import of " + accountingLineGroupDefinition.getGroupLabel() + " accounting lines"); cancelButtonTag.setTitle("Cancel import of " + accountingLineGroupDefinition.getGroupLabel() + " accounting lines"); cancelButtonTag.setOnclick(getHideImportName() + "(\\\'" + showLink + "\\\',\\\'" + uploadDiv + "\\\');return false;"); cancelButtonTag.doStartTag(); cancelButtonTag.doEndTag(); out.write("' +\n"); out.write("\t'</div>');\n"); out.write("\t//-->\n"); out.write("</SCRIPT>\n"); out.write("<NOSCRIPT>\n"); out.write("\tImport " + accountingLineGroupDefinition.getGroupLabel() + " lines\n"); noscriptFileTag.setPageContext(pageContext); noscriptFileTag.setParent(parentTag); noscriptFileTag.setProperty(accountingLineGroupDefinition.getImportedLinePropertyPrefix() + "File"); noscriptFileTag.doStartTag(); noscriptFileTag.doEndTag(); uploadButtonTag.doStartTag(); uploadButtonTag.doEndTag(); out.write("</NOSCRIPT>\n"); } catch (IOException ioe) { throw new JspException("Difficulty rendering accounting lines import upload", ioe); } } } /** * @return the name of the line collection property, but in a form that is okay for javascript variable/function naming */ protected String getVariableFriendlyLineCollectionProperty() { return lineCollectionProperty.replaceAll("[^A-Za-z0-9]", "_"); } /** * @return the name of the hide import function */ protected String getHideImportName() { return "hide" + getVariableFriendlyLineCollectionProperty() + "Import"; } /** * @return the name of the show import function */ protected String getShowImportName() { return "show" + getVariableFriendlyLineCollectionProperty() + "Import"; } /** * @return the name of the show link element */ protected String getShowLinkName() { return lineCollectionProperty + "ShowLink"; } /** * @return the name of the upload div */ protected String getUploadDivName() { return "upload" + lineCollectionProperty + "Div"; } /** * Determines if an upload can proceed for the accounting line group * * @return true if upload is possible, false otherwise */ protected boolean canUpload() { return (canEdit && accountingDocument.getAccountingLineParser() != null && shouldUpload); } /** * Allows overriding of whether something can be uploaded - though this serves only to turn uploading more off, never more on * * @param allowUpload should we be allowed to upload? */ public void overrideCanUpload(boolean allowUpload) { this.shouldUpload = allowUpload; } /** * Gets the cellCount attribute. * * @return Returns the cellCount. */ public int getCellCount() { return cellCount; } /** * Sets the cellCount attribute value. * * @param cellCount The cellCount to set. */ public void setCellCount(int cellCount) { this.cellCount = cellCount; } /** * Gets the accountingDocument attribute. * * @return Returns the accountingDocument. */ public AccountingDocument getAccountingDocument() { return accountingDocument; } /** * Sets the accountingDocument attribute value. * * @param accountingDocument The accountingDocument to set. */ public void setAccountingDocument(AccountingDocument accountingDocument) { this.accountingDocument = accountingDocument; } /** * Gets the accountingLineGroupDefinition attribute. * * @return Returns the accountingLineGroupDefinition. */ public AccountingLineGroupDefinition getAccountingLineGroupDefinition() { return accountingLineGroupDefinition; } /** * Sets the accountingLineGroupDefinition attribute value. * * @param accountingLineGroupDefinition The accountingLineGroupDefinition to set. */ public void setAccountingLineGroupDefinition(AccountingLineGroupDefinition accountingLineGroupDefinition) { this.accountingLineGroupDefinition = accountingLineGroupDefinition; } /** * Gets the titleCellSpan attribute. * * @return Returns the titleCellSpan. */ public int getTitleCellSpan() { return titleCellSpan; } /** * Sets the titleCellSpan attribute value. * * @param titleCellSpan The titleCellSpan to set. */ public void setTitleCellSpan(int titleCellSpan) { this.titleCellSpan = titleCellSpan; } /** * Gets the lineCollectionProperty attribute. * * @return Returns the lineCollectionProperty. */ public String getLineCollectionProperty() { return lineCollectionProperty; } /** * Sets the lineCollectionProperty attribute value. * * @param lineCollectionProperty The lineCollectionProperty to set. */ public void setLineCollectionProperty(String lineCollectionProperty) { this.lineCollectionProperty = lineCollectionProperty; } /** * Gets the groupActionsRendered attribute. * * @return Returns the groupActionsRendered. */ public boolean isGroupActionsRendered() { return groupActionsRendered; } /** * Sets the groupActionsRendered attribute value. * * @param groupActionsRendered The groupActionsRendered to set. */ public void setGroupActionsRendered(boolean groupActionsRenderred) { this.groupActionsRendered = groupActionsRenderred; } /** * Sets the canEdit attribute value. * @param canEdit The canEdit to set. */ public void setCanEdit(boolean canEdit) { this.canEdit = canEdit; } }