View Javadoc
1   /*
2    * Copyright 2008 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.sys.document.web.renderers;
17  
18  import java.io.IOException;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import javax.servlet.jsp.JspException;
23  import javax.servlet.jsp.JspWriter;
24  import javax.servlet.jsp.PageContext;
25  import javax.servlet.jsp.tagext.Tag;
26  
27  import org.apache.commons.lang.StringUtils;
28  import org.kuali.ole.sys.OLEConstants;
29  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
30  import org.kuali.ole.sys.context.SpringContext;
31  import org.kuali.ole.sys.document.AccountingDocument;
32  import org.kuali.ole.sys.document.datadictionary.AccountingLineGroupDefinition;
33  import org.kuali.ole.sys.document.datadictionary.AccountingLineViewActionDefinition;
34  import org.kuali.ole.sys.document.web.AccountingLineViewAction;
35  import org.kuali.rice.core.api.config.property.ConfigurationService;
36  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
37  import org.kuali.rice.kns.web.taglib.html.KNSFileTag;
38  import org.kuali.rice.kns.web.taglib.html.KNSImageTag;
39  import org.kuali.rice.krad.util.GlobalVariables;
40  
41  /**
42   * Renders the standard group header/import line
43   */
44  public class GroupTitleLineRenderer implements Renderer, CellCountCurious {
45      private int titleCellSpan = 4;
46      private int cellCount = 1;
47      private AccountingLineGroupDefinition accountingLineGroupDefinition;
48      private AccountingDocument accountingDocument;
49      private String lineCollectionProperty;
50      private KNSFileTag scriptFileTag = new KNSFileTag();
51      private KNSFileTag noscriptFileTag = new KNSFileTag();
52      private KNSImageTag uploadButtonTag = new KNSImageTag();
53      private KNSImageTag cancelButtonTag = new KNSImageTag();
54      private boolean shouldUpload = true;
55      private boolean canEdit = false;
56  
57      private boolean groupActionsRendered = false;
58  
59      /**
60       * Constructs a ImportLineRenderer, setting defaults on the tags that will always exist
61       */
62      public GroupTitleLineRenderer() {
63          scriptFileTag.setSize("30");
64          noscriptFileTag.setSize("30");
65          noscriptFileTag.setStyle("font:10px;height:16px;");
66          uploadButtonTag.setSrc(SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString("externalizable.images.url") + "tinybutton-add1.gif");
67          uploadButtonTag.setStyleClass("tinybutton");
68          cancelButtonTag.setProperty("methodToCall.cancel");
69          cancelButtonTag.setSrc(SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString("externalizable.images.url") + "tinybutton-cancelimport.gif");
70          cancelButtonTag.setStyleClass("tinybutton");
71      }
72  
73      /**
74       * @see org.kuali.ole.sys.document.web.renderers.Renderer#clear()
75       */
76      @Override
77      public void clear() {
78          cellCount = 1;
79          accountingLineGroupDefinition = null;
80          titleCellSpan = 4;
81          lineCollectionProperty = null;
82          accountingDocument = null;
83          shouldUpload = true;
84          canEdit = false;
85  
86          // clean script file tag
87          scriptFileTag.setPageContext(null);
88          scriptFileTag.setParent(null);
89          scriptFileTag.setProperty(null);
90  
91          // clean noscript file tag
92          noscriptFileTag.setPageContext(null);
93          noscriptFileTag.setParent(null);
94          noscriptFileTag.setProperty(null);
95  
96          // clean upload button tag
97          uploadButtonTag.setPageContext(null);
98          uploadButtonTag.setParent(null);
99          uploadButtonTag.setProperty(null);
100         uploadButtonTag.setAlt(null);
101         uploadButtonTag.setTitle(null);
102 
103         // clean cancel import tag
104         cancelButtonTag.setPageContext(null);
105         cancelButtonTag.setParent(null);
106         cancelButtonTag.setAlt(null);
107         cancelButtonTag.setTitle(null);
108         cancelButtonTag.setOnclick(null);
109     }
110 
111     /**
112      * @see org.kuali.ole.sys.document.web.renderers.Renderer#render(javax.servlet.jsp.PageContext, javax.servlet.jsp.tagext.Tag,
113      *      org.kuali.core.bo.BusinessObject)
114      */
115     @Override
116     public void render(PageContext pageContext, Tag parentTag) throws JspException {
117         try {
118             pageContext.getOut().write(buildRowBeginning());
119 
120             pageContext.getOut().write(buildTitleCell());
121             this.renderGroupLevelActions(pageContext, parentTag);
122 
123             pageContext.getOut().write(buildRowEnding());
124         }
125         catch (IOException ioe) {
126             throw new JspException("Difficulty in rendering import/group header line", ioe);
127         }
128     }
129 
130     /**
131      * Builds a tag for the row beginning
132      *
133      * @returns the String with the HTML for the row opening
134      */
135     protected String buildRowBeginning() {
136         return "<tr>";
137     }
138 
139     /**
140      * Builds the tag for the row beginning
141      *
142      * @returns the String with the HTML for the row beginning
143      */
144     protected String buildRowEnding() {
145         return "</tr>";
146     }
147 
148     protected void renderGroupLevelActions(PageContext pageContext, Tag parentTag) throws JspException {
149         JspWriter out = pageContext.getOut();
150 
151         try {
152             out.write(this.buildGroupActionsBeginning());
153 
154             this.renderGroupActions(pageContext, parentTag);
155             String nameSpaceCode = OLEConstants.Account.ACCOUNT_NAMESPACE;
156 
157             boolean hasPermission = KimApiServiceLocator.getPermissionService().hasPermission(
158                     GlobalVariables.getUserSession().getPerson().getPrincipalId(), nameSpaceCode,
159                     OLEConstants.Account.UPLOAD_BUDGET);
160 
161             if(hasPermission) {
162             this.renderUploadCell(pageContext, parentTag);
163             }
164 
165             out.write(this.buildGroupActionsColumnEnding());
166         }
167         catch (IOException ioe) {
168             throw new JspException("Difficulty rendering group level actions", ioe);
169         }
170     }
171 
172     /**
173      * Builds a tag for the row beginning
174      *
175      * @returns the String with the HTML for the row opening
176      */
177     protected String buildGroupActionsBeginning() {
178         if (this.canUpload() || this.isGroupActionsRendered()) {
179             StringBuilder groupActionsBeginning = new StringBuilder();
180             final int width = cellCount - titleCellSpan;
181 
182             groupActionsBeginning.append("<td ");
183             groupActionsBeginning.append("colspan=\"");
184             groupActionsBeginning.append(Integer.toString(width));
185             groupActionsBeginning.append("\" ");
186 
187             groupActionsBeginning.append("class=\"tab-subhead-import\" ");
188             groupActionsBeginning.append("align=\"right\" ");
189             groupActionsBeginning.append("nowrap=\"nowrap\" ");
190             groupActionsBeginning.append("style=\"border-right: none;\"");
191             groupActionsBeginning.append(">");
192 
193             return groupActionsBeginning.toString();
194         }
195 
196         return StringUtils.EMPTY;
197     }
198 
199     /**
200      * Builds the tag for the row beginning
201      *
202      * @returns the String with the HTML for the row beginning
203      */
204     protected String buildGroupActionsColumnEnding() {
205         return this.canUpload() || this.isGroupActionsRendered() ? "</td>" : StringUtils.EMPTY;
206     }
207 
208     /**
209      * Builds the tags for the title cell of the import line
210      *
211      * @return the String with the HTML for the title cell
212      */
213     protected String buildTitleCell() {
214         StringBuilder titleCell = new StringBuilder();
215         int colSpan = (this.canUpload() || this.isGroupActionsRendered()) ? titleCellSpan : cellCount;
216 
217         titleCell.append("<td ");
218 
219         titleCell.append("colspan=\"");
220         titleCell.append(colSpan);
221         titleCell.append("\" ");
222 
223         titleCell.append("class=\"tab-subhead\" ");
224 
225         titleCell.append("style=\"border-right: none;\"");
226 
227         titleCell.append(">");
228 
229         titleCell.append(buildGroupAnchor());
230 
231         titleCell.append(accountingLineGroupDefinition.getGroupLabel());
232 
233         titleCell.append("</td>");
234 
235         return titleCell.toString();
236     }
237 
238     /**
239      * Builds the unique anchor for this group
240      *
241      * @return the unique anchor for this group
242      */
243     protected String buildGroupAnchor() {
244         return "<a name=\"accounting" + getGroupInfix() + "Anchor\"></a>";
245     }
246 
247     protected void renderGroupActions(PageContext pageContext, Tag parentTag) throws JspException {
248         List<? extends AccountingLineViewActionDefinition> accountingLineGroupActions = accountingLineGroupDefinition.getAccountingLineGroupActions();
249         if (!this.isGroupActionsRendered() || accountingLineGroupActions == null || accountingLineGroupActions.isEmpty()) {
250             return;
251         }
252 
253         List<AccountingLineViewAction> viewActions = new ArrayList<AccountingLineViewAction>();
254         for (AccountingLineViewActionDefinition action : accountingLineGroupActions) {
255             String actionMethod = action.getActionMethod();
256             String actionLabel = action.getActionLabel();
257             String imageName = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString("externalizable.images.url") + action.getImageName();
258 
259             AccountingLineViewAction viewAction = new AccountingLineViewAction(actionMethod, actionLabel, imageName);
260             viewActions.add(viewAction);
261         }
262 
263         if (!viewActions.isEmpty()) {
264             ActionsRenderer actionsRenderer = new ActionsRenderer();
265             actionsRenderer.setTagBeginning(" ");
266             actionsRenderer.setTagEnding(" ");
267             actionsRenderer.setPostButtonSpacing(" ");
268             actionsRenderer.setActions(viewActions);
269             actionsRenderer.render(pageContext, parentTag);
270             actionsRenderer.clear();
271         }
272     }
273 
274     /**
275      * A dumb way to get the group infix that tries to figure out if it's dealing with a source or target line
276      *
277      * @return the String "source" or "target" to populate the buildGroupAnchor
278      */
279     protected String getGroupInfix() {
280         Class accountingLineClass = accountingLineGroupDefinition.getAccountingLineClass();
281         return (accountingLineClass.isAssignableFrom(SourceAccountingLine.class) ? "source" : "target");
282     }
283 
284     /**
285      * Oy, the big one...this one actually renders instead of returning the HTML in a String. This is because it's kind of complex
286      * (and a likely target for future refactoring)
287      *
288      * @param pageContext the page contex to render to
289      * @param parentTag the tag that is requesting all the rendering
290      * @throws JspException thrown if something goes wrong
291      */
292     protected void renderUploadCell(PageContext pageContext, Tag parentTag) throws JspException {
293         JspWriter out = pageContext.getOut();
294 
295         if (canUpload()) {
296             try {
297                 String hideImport = getHideImportName();
298                 String showImport = getShowImportName();
299                 String showLink = getShowLinkName();
300                 String uploadDiv = getUploadDivName();
301 
302                 out.write("\n<SCRIPT type=\"text/javascript\">\n");
303                 out.write("<!--\n");
304                 out.write("\tfunction " + hideImport + "() {\n");
305                 out.write("\t\tdocument.getElementById(\"" + showLink + "\").style.display=\"inline\";\n");
306                 out.write("\t\tdocument.getElementById(\"" + uploadDiv + "\").style.display=\"none\";\n");
307                 out.write("\t}\n");
308                 out.write("\tfunction " + showImport + "() {\n");
309                 out.write("\t\tdocument.getElementById(\"" + showLink + "\").style.display=\"none\";\n");
310                 out.write("\t\tdocument.getElementById(\"" + uploadDiv + "\").style.display=\"inline\";\n");
311                 out.write("\t}\n");
312                 out.write("\tdocument.write(\n");
313                 out.write("\t\t'<a id=\"" + showLink + "\" href=\"#\" onclick=\"" + showImport + "();return false;\">' +\n");
314                 out.write("\t\t'<img src=\"" + SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString("externalizable.images.url") + "tinybutton-importlines.gif\" title=\"import file\" alt=\"import file\"' +\n");
315                 out.write("\t\t'width=\"72\" border=\"0\">' +\n");
316                 out.write("\t\t'</a>' +\n");
317                 out.write("\t\t'<div id=\"" + uploadDiv + "\" style=\"display:none;\" >' +\n");
318 
319                 out.write("\t\t'");
320 
321                 scriptFileTag.setPageContext(pageContext);
322                 scriptFileTag.setParent(parentTag);
323                 scriptFileTag.setProperty(accountingLineGroupDefinition.getImportedLinePropertyPrefix() + "File");
324                 scriptFileTag.doStartTag();
325                 scriptFileTag.doEndTag();
326 
327                 out.write("' +\n");
328                 out.write("\t\t'");
329 
330                 uploadButtonTag.setPageContext(pageContext);
331                 uploadButtonTag.setParent(parentTag);
332                 uploadButtonTag.setProperty("methodToCall.upload" + StringUtils.capitalize(accountingLineGroupDefinition.getImportedLinePropertyPrefix()) + "Lines");
333                 uploadButtonTag.setAlt("insert " + accountingLineGroupDefinition.getGroupLabel() + " accounting lines");
334                 uploadButtonTag.setTitle("insert " + accountingLineGroupDefinition.getGroupLabel() + " accounting lines");
335                 uploadButtonTag.doStartTag();
336                 uploadButtonTag.doEndTag();
337 
338                 out.write("' +\n");
339 
340                 out.write("\t\t'");
341 
342                 cancelButtonTag.setPageContext(pageContext);
343                 cancelButtonTag.setParent(parentTag);
344                 cancelButtonTag.setAlt("Cancel import of " + accountingLineGroupDefinition.getGroupLabel() + " accounting lines");
345                 cancelButtonTag.setTitle("Cancel import of " + accountingLineGroupDefinition.getGroupLabel() + " accounting lines");
346                 cancelButtonTag.setOnclick(getHideImportName() + "();return false;");
347                 cancelButtonTag.doStartTag();
348                 cancelButtonTag.doEndTag();
349 
350                 out.write("' +\n");
351 
352                 out.write("\t'</div>');\n");
353                 out.write("\t//-->\n");
354                 out.write("</SCRIPT>\n");
355                 out.write("<NOSCRIPT>\n");
356                 out.write("\tImport " + accountingLineGroupDefinition.getGroupLabel() + " lines\n");
357 
358                 noscriptFileTag.setPageContext(pageContext);
359                 noscriptFileTag.setParent(parentTag);
360                 noscriptFileTag.setProperty(accountingLineGroupDefinition.getImportedLinePropertyPrefix() + "File");
361                 noscriptFileTag.doStartTag();
362                 noscriptFileTag.doEndTag();
363 
364                 uploadButtonTag.doStartTag();
365                 uploadButtonTag.doEndTag();
366 
367                 out.write("</NOSCRIPT>\n");
368             }
369             catch (IOException ioe) {
370                 throw new JspException("Difficulty rendering accounting lines import upload", ioe);
371             }
372         }
373     }
374 
375     /**
376      * @return the name of the line collection property, but in a form that is okay for javascript variable/function naming
377      */
378     protected String getVariableFriendlyLineCollectionProperty() {
379         return lineCollectionProperty.replaceAll("[^A-Za-z0-9]", "_");
380     }
381 
382     /**
383      * @return the name of the hide import function
384      */
385     protected String getHideImportName() {
386         return "hide" + getVariableFriendlyLineCollectionProperty() + "Import";
387     }
388 
389     /**
390      * @return the name of the show import function
391      */
392     protected String getShowImportName() {
393         return "show" + getVariableFriendlyLineCollectionProperty() + "Import";
394     }
395 
396     /**
397      * @return the name of the show link element
398      */
399     protected String getShowLinkName() {
400         return lineCollectionProperty + "ShowLink";
401     }
402 
403     /**
404      * @return the name of the upload div
405      */
406     protected String getUploadDivName() {
407         return "upload" + lineCollectionProperty + "Div";
408     }
409 
410     /**
411      * Determines if an upload can proceed for the accounting line group
412      *
413      * @return true if upload is possible, false otherwise
414      */
415     protected boolean canUpload() {
416         return (canEdit && accountingDocument.getAccountingLineParser() != null && shouldUpload);
417     }
418 
419     /**
420      * Allows overriding of whether something can be uploaded - though this serves only to turn uploading more off, never more on
421      *
422      * @param allowUpload should we be allowed to upload?
423      */
424     public void overrideCanUpload(boolean allowUpload) {
425         this.shouldUpload = allowUpload;
426     }
427 
428     /**
429      * Gets the cellCount attribute.
430      *
431      * @return Returns the cellCount.
432      */
433     public int getCellCount() {
434         return cellCount;
435     }
436 
437     /**
438      * Sets the cellCount attribute value.
439      *
440      * @param cellCount The cellCount to set.
441      */
442     @Override
443     public void setCellCount(int cellCount) {
444         this.cellCount = cellCount;
445     }
446 
447     /**
448      * Gets the accountingDocument attribute.
449      *
450      * @return Returns the accountingDocument.
451      */
452     public AccountingDocument getAccountingDocument() {
453         return accountingDocument;
454     }
455 
456     /**
457      * Sets the accountingDocument attribute value.
458      *
459      * @param accountingDocument The accountingDocument to set.
460      */
461     public void setAccountingDocument(AccountingDocument accountingDocument) {
462         this.accountingDocument = accountingDocument;
463     }
464 
465     /**
466      * Gets the accountingLineGroupDefinition attribute.
467      *
468      * @return Returns the accountingLineGroupDefinition.
469      */
470     public AccountingLineGroupDefinition getAccountingLineGroupDefinition() {
471         return accountingLineGroupDefinition;
472     }
473 
474     /**
475      * Sets the accountingLineGroupDefinition attribute value.
476      *
477      * @param accountingLineGroupDefinition The accountingLineGroupDefinition to set.
478      */
479     public void setAccountingLineGroupDefinition(AccountingLineGroupDefinition accountingLineGroupDefinition) {
480         this.accountingLineGroupDefinition = accountingLineGroupDefinition;
481     }
482 
483     /**
484      * Gets the titleCellSpan attribute.
485      *
486      * @return Returns the titleCellSpan.
487      */
488     public int getTitleCellSpan() {
489         return titleCellSpan;
490     }
491 
492     /**
493      * Sets the titleCellSpan attribute value.
494      *
495      * @param titleCellSpan The titleCellSpan to set.
496      */
497     public void setTitleCellSpan(int titleCellSpan) {
498         this.titleCellSpan = titleCellSpan;
499     }
500 
501     /**
502      * Gets the lineCollectionProperty attribute.
503      *
504      * @return Returns the lineCollectionProperty.
505      */
506     public String getLineCollectionProperty() {
507         return lineCollectionProperty;
508     }
509 
510     /**
511      * Sets the lineCollectionProperty attribute value.
512      *
513      * @param lineCollectionProperty The lineCollectionProperty to set.
514      */
515     public void setLineCollectionProperty(String lineCollectionProperty) {
516         this.lineCollectionProperty = lineCollectionProperty;
517     }
518 
519     /**
520      * Gets the groupActionsRendered attribute.
521      *
522      * @return Returns the groupActionsRendered.
523      */
524     public boolean isGroupActionsRendered() {
525         return groupActionsRendered;
526     }
527 
528     /**
529      * Sets the groupActionsRendered attribute value.
530      *
531      * @param groupActionsRendered The groupActionsRendered to set.
532      */
533     public void setGroupActionsRendered(boolean groupActionsRenderred) {
534         this.groupActionsRendered = groupActionsRenderred;
535     }
536 
537     /**
538      * Sets the canEdit attribute value.
539      * @param canEdit The canEdit to set.
540      */
541     public void setCanEdit(boolean canEdit) {
542         this.canEdit = canEdit;
543     }
544 
545 }