1 /***
2 * Copyright (c) 2003 held jointly by the individual authors.
3 *
4 * This library is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 2.1 of the License, or (at your option)
7 * any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 * > http://www.gnu.org/copyleft/lesser.html >
18 * http://www.opensource.org/licenses/lgpl-license.php
19 */
20 package net.mlw.vlh.web.tag;
21
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.regex.Pattern;
27
28 import javax.servlet.http.HttpServletRequest;
29 import javax.servlet.jsp.JspException;
30
31 import net.mlw.vlh.ValueList;
32 import net.mlw.vlh.ValueListInfo;
33 import net.mlw.vlh.web.ValueListConfigBean;
34 import net.mlw.vlh.web.util.DisplayHelper;
35 import net.mlw.vlh.web.util.JspUtils;
36
37 import org.springframework.context.MessageSource;
38 import org.springframework.context.NoSuchMessageException;
39
40 /***
41 * Generate buttons to navigate through pages of data using i18n
42 * (internationalization). The following keys are required to be define in
43 * message sources.
44 *
45 * <p>
46 * If you like to, you can add your properties file in your locale and add this
47 * lines of code in your language:
48 * </p>
49 * Summary info:
50 * <ol>
51 * <code>
52 * <li>paging.text.totalRow={0} Total </li>
53 * <li>paging.text.pageFromTotal= <b>{0}</b> of {1} page(s) </li>
54 * </code>
55 * </ol>
56 * Paging info:
57 * <ol>
58 * <li>paging.first(off), paging.first(on)</li>
59 * <li>paging.previous(off), paging.previous(on)</li>
60 * <li>paging.forward(off), paging.forward(on)</li>
61 * <li>paging.last(off), paging.last(on)</li>
62 * <li>paging.delim</li>
63 * <li>paging.text.totalRow</li>
64 * <li>paging.text.pageFromTotal</li>
65 * </ol>
66 * Focus info:
67 * <ol>
68 * <li>paging.focus(on), paging.focus(off), paging.focus(disabled),
69 * paging.focus(error)</li>
70 * </ol>
71 * Items per page info:
72 * <ol>
73 * <code>
74 * <li>paging.itemsPerPage.label = Items Per Page:</li>
75 * <li>paging.itemsPerPage.title = Number of items per page.</li>
76 * <li>paging.itemsPerPage.button = Set</li>
77 * </code>
78 * </ol>
79 * @todo Document this tag. AAA separate summary to differnt tag, find better
80 * pictures for paging.focus
81 * @author Matthew L. Wilson, Andrej Zachar
82 * @version $Revision: 1.38 $ $Date: 2005/11/23 15:02:16 $
83 */
84 public class DefaultPagingTag extends ConfigurableTag
85 {
86
87 /***
88 * Pattern for ...border=...
89 */
90 private static final Pattern BORDER_ATTRIBUTE_PATTERN = Pattern.compile("//b(border//s*=//s*//\"?\'?)", Pattern.CASE_INSENSITIVE);
91
92 /***
93 * Pattern for ...cellspacing=...
94 */
95 private static final Pattern CELLSPACING_ATTRIBUTE_PATTERN = Pattern.compile("//b(cellspacing//s*=//s*//\"?\'?)",
96 Pattern.CASE_INSENSITIVE);
97
98 /***
99 * Pattern for ...cellpadding=...
100 */
101 private static final Pattern CELLPADDING_ATTRIBUTE_PATTERN = Pattern.compile("//b(cellpadding//s*=//s*//\"?\'?)",
102 Pattern.CASE_INSENSITIVE);
103
104 private static final String PAGING_TAG_STYLE = "PagingTag";
105
106 private static final String SUMMARY_STYLE = "Summary";
107
108 private static final String ITEMS_PER_PAGE_STYLE = "ItemsPerPage";
109
110 private static final String INPUT_BOX_STYLE = ITEMS_PER_PAGE_STYLE + "InputBox";
111
112 private static final String LABEL_STYLE = ITEMS_PER_PAGE_STYLE + "Label";
113
114 private static final String SUBMIT_BUTTON_STYLE = ITEMS_PER_PAGE_STYLE + "SubmitButton";
115
116 private static final String PAGING_STYLE = "Paging";
117
118
119
120 private int pages = 0;
121
122 private boolean showSummary = false;
123
124 private boolean showItemsPerPage = false;
125
126 private boolean generateItemsPerPageForm = true;
127
128
129
130 private int currentPage = 0;
131
132 private int maxPage = 0;
133
134 private Map parameters;
135
136 private ValueListSpaceTag rootTag;
137
138 private DisplayHelper displayHelper;
139
140 private MessageSource messageSource;
141
142 private Locale currentLocale;
143
144 protected ValueListConfigBean getConfig()
145 {
146 return rootTag.getConfig();
147 }
148
149 protected ValueList getValueList()
150 {
151 return rootTag.getValueList();
152 }
153
154 protected ValueListInfo getValueListInfo()
155 {
156 return rootTag.getValueList().getValueListInfo();
157 }
158
159 protected TableInfo getTableInfo()
160 {
161 return rootTag.getTableInfo();
162 }
163
164 protected Locale getLocale()
165 {
166 return this.currentLocale;
167 }
168
169 protected void init(HttpServletRequest request) throws JspException
170 {
171 this.rootTag = (ValueListSpaceTag) JspUtils.getParent(this, ValueListSpaceTag.class);
172 ValueListConfigBean config = rootTag.getConfig();
173 this.displayHelper = config.getDisplayHelper();
174 this.messageSource = config.getMessageSource();
175 this.currentLocale = config.getLocaleResolver().resolveLocale(request);
176 }
177
178 /***
179 * @see javax.servlet.jsp.tagext.TagSupport#doStartTag()
180 */
181 public int doStartTag() throws JspException
182 {
183
184 init((HttpServletRequest) pageContext.getRequest());
185
186 Locale locale = getLocale();
187
188 TableInfo tableInfo = getTableInfo();
189 ValueListInfo valueListInfo = getValueListInfo();
190
191
192 parameters = new HashMap(tableInfo.getParameters());
193 parameters.put(ValueListInfo.SORT_COLUMN + tableInfo.getId(), valueListInfo.getSortingColumn());
194 parameters.put(ValueListInfo.SORT_DIRECTION + tableInfo.getId(), valueListInfo.getSortingDirection());
195
196 int page = valueListInfo.getPagingPage();
197 int numberOfPages = valueListInfo.getTotalNumberOfPages();
198
199 this.currentPage = page - (pages / 2);
200 if (this.currentPage < 1)
201 {
202 this.currentPage = 1;
203 }
204
205 this.maxPage = (this.currentPage - 1) + pages;
206 if (this.maxPage > numberOfPages)
207 {
208 this.currentPage -= (this.maxPage - numberOfPages);
209 this.maxPage = numberOfPages;
210 }
211 if (this.maxPage < 2)
212 {
213 this.maxPage = 0;
214 }
215 if (this.currentPage < 1)
216 {
217 this.currentPage = 1;
218 }
219
220 StringBuffer sb = new StringBuffer();
221
222 final String stylePrefix = getConfig().getStylePrefix();
223 final String pagingTagStyle = stylePrefix + PAGING_TAG_STYLE + " " + PAGING_TAG_STYLE;
224 final String summaryStyle = stylePrefix + SUMMARY_STYLE + " " + SUMMARY_STYLE;
225 final String itemsPerPageStyle = stylePrefix + ITEMS_PER_PAGE_STYLE + " " + ITEMS_PER_PAGE_STYLE;
226 final String pagingStyle = stylePrefix + PAGING_STYLE + " " + PAGING_STYLE;
227
228 sb.append("<table class='").append(pagingTagStyle).append("'");
229
230 String attributes = getAttributes();
231 if (attributes != null)
232 {
233 if (!BORDER_ATTRIBUTE_PATTERN.matcher(attributes).find())
234 {
235 sb.append(" border=0");
236 }
237 if (!CELLSPACING_ATTRIBUTE_PATTERN.matcher(attributes).find())
238 {
239 sb.append(" cellspacing=0");
240 }
241 if (!CELLPADDING_ATTRIBUTE_PATTERN.matcher(attributes).find())
242 {
243 sb.append(" cellpadding=0");
244 }
245 sb.append(" ").append(attributes);
246 }
247
248 sb.append(">");
249 sb.append("\n <tr class='").append(pagingTagStyle).append("'>");
250
251 if (showSummary)
252 {
253 sb.append("\n <td class='").append(summaryStyle).append("'>");
254 renderSumary(sb);
255 sb.append("</td>");
256 if (showItemsPerPage)
257 {
258 HashMap itemsPerPageParameters = new HashMap(parameters);
259 sb.append("\n <td class='").append(itemsPerPageStyle).append("'>");
260 renderItemsPerPage(sb, itemsPerPageParameters);
261 sb.append("</td>");
262 }
263 sb.append("\n <td class='").append(pagingStyle).append("'>");
264 sb.append("<table border='0' cellspacing='0' cellpadding='0' class='").append(pagingStyle).append("'>");
265 sb.append("\n <tr class='").append(pagingStyle).append("'>");
266
267 }
268
269 parameters.put(ValueListInfo.PAGING_NUMBER_PER + tableInfo.getId(), String.valueOf(valueListInfo.getPagingNumberPer()));
270
271 renderFocusControl(sb);
272
273 String value;
274
275 if (page > 1)
276 {
277 parameters.put(ValueListInfo.PAGING_PAGE + tableInfo.getId(), "1");
278
279 value = getMessage("paging.first(on)", null, locale);
280
281 sb.append("\n <td>");
282 renderPagingLink(sb, parameters, value);
283 sb.append("</td>");
284
285 String delim = getMessage("paging.delim", null, "", locale);
286
287 if (value.length() > 0 && delim.length() > 0)
288 {
289 sb.append("\n <td>").append(delim).append("</td>");
290 }
291
292 parameters.put(ValueListInfo.PAGING_PAGE + tableInfo.getId(), String.valueOf(page - 1));
293
294 value = getMessage("paging.previous(on)", null, locale);
295
296 sb.append("\n <td>");
297 renderPagingLink(sb, parameters, value);
298 sb.append("</td>");
299
300 if (value.length() > 0 && delim.length() > 0)
301 {
302 sb.append("\n <td>").append(delim).append("</td>");
303 }
304 }
305 else
306 {
307 sb.append("\n <td>").append(getMessage("paging.first(off)", null, locale)).append("</td>");
308 sb.append("\n <td>").append(getMessage("paging.previous(off)", null, locale)).append("</td>");
309 }
310
311 JspUtils.write(pageContext, sb.toString());
312 pageContext.setAttribute("page" + tableInfo.getId(), new Integer(this.currentPage));
313
314 return EVAL_BODY_BUFFERED;
315 }
316
317 /***
318 * Try to resolve the message. Treat as an error if the message can't be found.
319 * @param code the code to lookup up, such as 'calculator.noRateSet'
320 * @param args Array of arguments that will be filled in for params within
321 * the message (params look like "{0}", "{1,date}", "{2,time}" within a message),
322 * or null if none.
323 * @param locale the Locale in which to do the lookup
324 * @return the resolved message
325 * @throws NoSuchMessageException if the message wasn't found
326 * @see <a href="http://java.sun.com/j2se/1.3/docs/api/java/text/MessageFormat.html">java.text.MessageFormat</a>
327 */
328 protected String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException, JspException
329 {
330 return displayHelper.help(pageContext, messageSource.getMessage(code, args, locale));
331 }
332
333 /***
334 * Try to resolve the message. Return default message if no message was found.
335 * @param code the code to lookup up, such as 'calculator.noRateSet'. Users of
336 * this class are encouraged to base message names on the relevant fully
337 * qualified class name, thus avoiding conflict and ensuring maximum clarity.
338 * @param args array of arguments that will be filled in for params within
339 * the message (params look like "{0}", "{1,date}", "{2,time}" within a message),
340 * or null if none.
341 * @param locale the Locale in which to do the lookup
342 * @param defaultMessage String to return if the lookup fails
343 * @return the resolved message if the lookup was successful;
344 * otherwise the default message passed as a parameter
345 * @see <a href="http://java.sun.com/j2se/1.3/docs/api/java/text/MessageFormat.html">java.text.MessageFormat</a>
346 */
347 protected String getMessage(String code, Object[] args, String defaultMessage, Locale locale) throws NoSuchMessageException,
348 JspException
349 {
350 return displayHelper.help(pageContext, messageSource.getMessage(code, args, defaultMessage, locale));
351 }
352
353 /***
354 *
355 * @param sb
356 * @param itemsPerPageParameters
357 * @throws NoSuchMessageException
358 * @throws JspException
359 * @todo DO IT WIHTOUT JAVASCRIPT!
360 */
361 protected void renderItemsPerPage(StringBuffer sb, HashMap itemsPerPageParameters) throws NoSuchMessageException, JspException
362 {
363 Locale locale = getLocale();
364 ValueListInfo valueListInfo = getValueListInfo();
365 TableInfo tableInfo = getTableInfo();
366
367 itemsPerPageParameters.remove(ValueListInfo.PAGING_NUMBER_PER + tableInfo.getId());
368 itemsPerPageParameters.put(ValueListInfo.PAGING_PAGE + tableInfo.getId(), String.valueOf(valueListInfo.getPagingPage()));
369
370 if (valueListInfo.isFocusEnabled())
371 {
372 itemsPerPageParameters.put(ValueListInfo.DO_FOCUS + tableInfo.getId(), valueListInfo.isDoFocusAgain() ? "true" : "false");
373 if (valueListInfo.getFocusProperty() != null)
374 {
375 itemsPerPageParameters.put(ValueListInfo.FOCUS_PROPERTY + tableInfo.getId(), valueListInfo.getFocusProperty());
376 }
377 if (valueListInfo.getFocusValue() != null)
378 {
379 itemsPerPageParameters.put(ValueListInfo.FOCUS_VALUE + tableInfo.getId(), valueListInfo.getFocusValue());
380 }
381 }
382
383 String propertyName = ValueListInfo.PAGING_NUMBER_PER + tableInfo.getId();
384
385 String delim = getMessage("paging.delim", null, "", locale);
386 sb.append(delim);
387
388 final String stylePrefix = getConfig().getStylePrefix();
389 final String commonStyle = stylePrefix + ITEMS_PER_PAGE_STYLE + " " + ITEMS_PER_PAGE_STYLE;
390 final String labelStyle = stylePrefix + LABEL_STYLE + " " + LABEL_STYLE;
391 final String inputBoxStyle = stylePrefix + INPUT_BOX_STYLE + " " + INPUT_BOX_STYLE;
392 final String submitButtonStyle = stylePrefix + SUBMIT_BUTTON_STYLE + " " + SUBMIT_BUTTON_STYLE;
393
394 if (isGenerateItemsPerPageForm())
395 {
396 sb.append("<form action='#' onsubmit='return false;' class='").append(commonStyle).append("'>");
397 }
398
399 sb.append("<table border='0' cellspacing='0' cellpadding='0' class='").append(commonStyle).append("'>");
400
401 sb.append("\n <tr class='").append(commonStyle).append("'>");
402
403 Map labelAttrs = new HashMap();
404 labelAttrs.put("class", labelStyle);
405
406 sb.append("\n <td nowrap='true' class='").append(labelStyle).append("'>");
407 renderPerPageLabel(sb, labelAttrs, getMessage("paging.itemsPerPage.label", null, locale));
408 sb.append("</td>");
409
410 Map inputBoxAttrs = new HashMap();
411 inputBoxAttrs.put("id", propertyName);
412 inputBoxAttrs.put("name", propertyName);
413 inputBoxAttrs.put("class", inputBoxStyle);
414 inputBoxAttrs.put("title", getMessage("paging.itemsPerPage.title", null, locale));
415 inputBoxAttrs.put("value", new Integer(valueListInfo.getPagingNumberPer()));
416
417 sb.append("\n <td class='").append(inputBoxStyle).append("'>");
418 renderPerPageInputBox(sb, inputBoxAttrs);
419 sb.append("</td>");
420
421 Map submitButtonAttrs = new HashMap();
422 submitButtonAttrs.put("class", submitButtonStyle);
423 submitButtonAttrs.put("value", getMessage("paging.itemsPerPage.button", null, locale));
424 submitButtonAttrs.put("onclick", "window.location.href = \"" + tableInfo.getUrl()
425 + getConfig().getLinkEncoder().encode(pageContext, itemsPerPageParameters) + propertyName + "=\" + document.getElementById(\""
426 + propertyName + "\").value;");
427
428 sb.append("\n <td class='").append(submitButtonStyle).append("'>");
429 renderPerPageSubmitButton(sb, submitButtonAttrs);
430 sb.append("</td>");
431
432 sb.append("\n </tr>");
433 sb.append("\n </table>");
434
435 if (isGenerateItemsPerPageForm())
436 {
437 sb.append("</form>");
438 }
439 }
440
441 /***
442 * Render label for items per page input box. Subclasses can overide or extend the method to provide different behaviour.
443 *
444 * @param sb StringBuffer to render into
445 * @param attributes
446 * @param text
447 */
448 protected void renderPerPageLabel(StringBuffer sb, Map attributes, String text)
449 {
450 renderBodyTag(sb, "label", attributes, text);
451 }
452
453 /***
454 * Render input box for items per page. Subclasses can overide or extend the method to provide different behaviour.
455 *
456 * @param sb StringBuffer to tender into
457 * @param attributes Attributes for rendering a tag
458 */
459 protected void renderPerPageInputBox(StringBuffer sb, Map attributes)
460 {
461 attributes.put("type", "text");
462 renderSimpleTag(sb, "input", attributes);
463 }
464
465 /***
466 * Render submit button for items per page input box. Subclasses can overide or extend the method to provide different behaviour.
467 *
468 * @param sb
469 * @param attributes
470 */
471 protected void renderPerPageSubmitButton(StringBuffer sb, Map attributes)
472 {
473 if (!attributes.containsKey("type"))
474 {
475 attributes.put("type", "button");
476 }
477 renderSimpleTag(sb, "input", attributes);
478 }
479
480 private static void renderSimpleTag(StringBuffer sb, String name, Map attributes)
481 {
482 sb.append("<").append(name);
483 if (attributes != null)
484 {
485 Iterator i = attributes.entrySet().iterator();
486 while (i.hasNext())
487 {
488 Map.Entry entry = (Map.Entry) i.next();
489 sb.append(" ").append(entry.getKey()).append("='").append(entry.getValue()).append("'");
490 }
491 }
492 sb.append(">");
493 }
494
495 private static void renderBodyTag(StringBuffer sb, String name, Map attributes, String content)
496 {
497 renderSimpleTag(sb, name, attributes);
498 if (content != null)
499 {
500 sb.append(content);
501 }
502 sb.append("</").append(name).append(">");
503 }
504
505 /***
506 * @param sb
507 * @throws JspException
508 * @throws NoSuchMessageException
509 */
510 protected void renderSumary(StringBuffer sb) throws NoSuchMessageException, JspException
511 {
512 Locale locale = getLocale();
513 ValueListInfo valueListInfo = getValueListInfo();
514 sb.append(getMessage("paging.text.totalRow", new Object[]
515 { new Integer(valueListInfo.getTotalNumberOfEntries()) }, locale));
516 sb.append(getMessage("paging.text.pageFromTotal", new Object[]
517 { new Integer(valueListInfo.getPagingPage()), new Integer(valueListInfo.getTotalNumberOfPages()) }, locale));
518 }
519
520 /***
521 *
522 * @param sb
523 * @throws JspException
524 */
525 protected void renderFocusControl(StringBuffer sb) throws JspException
526 {
527
528 Locale locale = getLocale();
529 ValueListInfo valueListInfo = getValueListInfo();
530 TableInfo tableInfo = getTableInfo();
531
532 String value;
533
534 if (valueListInfo.isFocusEnabled())
535 {
536 parameters.put(ValueListInfo.FOCUS_PROPERTY + tableInfo.getId(), valueListInfo.getFocusProperty());
537
538 if (valueListInfo.getFocusValue() != null)
539 {
540 parameters.put(ValueListInfo.FOCUS_VALUE + tableInfo.getId(), valueListInfo.getFocusValue());
541 }
542
543 HashMap focusParameters = new HashMap(parameters);
544 if (valueListInfo.getFocusStatus() != ValueListInfo.FOCUS_TOO_MANY_ITEMS)
545 {
546 focusParameters.put(ValueListInfo.DO_FOCUS + tableInfo.getId(), valueListInfo.isDoFocusAgain() ? "false" : "true");
547
548 value = getMessage(valueListInfo.isDoFocusAgain() ? "paging.focus(off)" : "paging.focus(on)", null, locale);
549
550 sb.append("\n <td>");
551 renderPagingLink(sb, parameters, value);
552 sb.append("</td>");
553
554 String delim = getMessage("paging.delim", null, "", locale);
555 if (value.length() > 0 && delim.length() > 0)
556 {
557 sb.append("\n <td>").append(delim).append("</td>");
558 }
559 }
560 else
561 {
562 if (valueListInfo.isFocusEnabled())
563 {
564 sb.append("\n <td>").append(getMessage("paging.focus(error)", null, locale)).append("</td>");
565 }
566 }
567
568 }
569 else
570 {
571 sb.append("\n <td>").append(getMessage("paging.focus(disabled)", null, locale)).append("</td>");
572 }
573 }
574
575 /***
576 * @see javax.servlet.jsp.tagext.IterationTag#doAfterBody()
577 */
578 public int doAfterBody() throws JspException
579 {
580
581
582
583 if (this.currentPage <= this.maxPage)
584 {
585
586 TableInfo tableInfo = getTableInfo();
587
588 String label = null;
589
590 if (getBodyContent() != null)
591 {
592 label = getBodyContent().getString();
593 if (label != null)
594 {
595 label = label.trim();
596 }
597 getBodyContent().clearBody();
598 }
599
600 if (label == null || label.length() == 0)
601 {
602 return SKIP_BODY;
603 }
604
605 StringBuffer sb = new StringBuffer();
606
607 renderContent(sb, label);
608
609 JspUtils.writePrevious(pageContext, sb.toString());
610
611 pageContext.setAttribute("page" + tableInfo.getId(), new Integer(++this.currentPage));
612
613 return EVAL_BODY_AGAIN;
614
615 }
616 else
617 {
618 return SKIP_BODY;
619 }
620 }
621
622 /***
623 *
624 * @param sb
625 * @param label
626 */
627 private void renderContent(StringBuffer sb, String label)
628 {
629 ValueListInfo valueListInfo = getValueListInfo();
630 TableInfo tableInfo = getTableInfo();
631 if (this.currentPage == valueListInfo.getPagingPage())
632 {
633 sb.append("\n <th>").append(label).append("</th>");
634 }
635 else
636 {
637 parameters.put(ValueListInfo.PAGING_PAGE + tableInfo.getId(), String.valueOf(this.currentPage));
638
639 sb.append("\n <td>");
640 renderPagingLink(sb, parameters, label);
641 sb.append("</td>");
642 }
643 }
644
645 /***
646 * @see javax.servlet.jsp.tagext.TagSupport#doEndTag()
647 */
648 public int doEndTag() throws JspException
649 {
650 StringBuffer sb = new StringBuffer();
651
652 Locale locale = getLocale();
653
654 String delim = getMessage("paging.delim", null, locale);
655
656 ValueListInfo valueListInfo = getValueListInfo();
657 TableInfo tableInfo = getTableInfo();
658
659 int page = valueListInfo.getPagingPage();
660 int numberOfPages = valueListInfo.getTotalNumberOfPages();
661
662 if (getBodyContent() == null || getBodyContent().getString() == null || getBodyContent().getString().trim().length() == 0)
663 {
664 while (this.currentPage <= this.maxPage)
665 {
666 renderContent(sb, String.valueOf(this.currentPage));
667 this.currentPage++;
668 }
669 }
670
671 if (page < numberOfPages)
672 {
673
674 parameters.put(ValueListInfo.PAGING_PAGE + tableInfo.getId(), String.valueOf(page + 1));
675
676 String value = getMessage("paging.forward(on)", null, locale);
677
678 sb.append("\n <td>");
679 renderPagingLink(sb, parameters, value);
680 sb.append("</td>");
681
682 if (value.length() > 0 && delim.length() > 0)
683 {
684 sb.append("\n <td>").append(delim).append("</td>");
685 }
686
687 parameters.put(ValueListInfo.PAGING_PAGE + tableInfo.getId(), String.valueOf(numberOfPages));
688
689 value = getMessage("paging.last(on)", null, locale);
690
691 sb.append("\n <td>");
692 renderPagingLink(sb, parameters, value);
693 sb.append("</td>");
694 }
695 else
696 {
697 sb.append("\n <td>").append(getMessage("paging.forward(off)", null, locale)).append("</td>");
698 sb.append("\n <td>").append(getMessage("paging.last(off)", null, locale)).append("</td>");
699 }
700
701 sb.append("\n </tr>");
702 sb.append("\n </table>");
703
704 if (showSummary)
705 {
706 sb.append("</td>");
707 sb.append("\n </tr>");
708 sb.append("\n</table>");
709 }
710 JspUtils.write(pageContext, sb.toString());
711
712 release();
713
714 return EVAL_PAGE;
715 }
716
717 /***
718 * Renders <code><a></code> tag for control buttons. Subclasses can overide or extend the method to provide different behaviour.
719 *
720 * @param sb StringBuffer to render into
721 * @param parameters Map of parameters
722 * @param value Label
723 */
724 protected void renderPagingLink(StringBuffer sb, Map parameters, String value)
725 {
726 TableInfo tableInfo = getTableInfo();
727 sb.append("<a href=\"").append(tableInfo.getUrl());
728 sb.append(rootTag.getConfig().getLinkEncoder().encode(pageContext, parameters));
729 sb.append("\">").append(value).append("</a>");
730 }
731
732 /***
733 * @return Returns the pages.
734 */
735 public int getPages()
736 {
737 return this.pages;
738 }
739
740 /***
741 * @param pages The pages to set.
742 */
743 public void setPages(int pages)
744 {
745 this.pages = pages;
746 }
747
748 /***
749 *
750 * @return showSummary
751 */
752 public boolean isShowSummary()
753 {
754 return showSummary;
755 }
756
757 /***
758 * @param showSummary The showSummary to set.
759 */
760 public void setShowSummary(boolean showSummary)
761 {
762 this.showSummary = showSummary;
763 }
764
765 /***
766 *
767 * @return showItemsPerPage
768 */
769 public boolean isShowItemsPerPage()
770 {
771 return showItemsPerPage;
772 }
773
774 /***
775 * Enable or disable generating form for number of items per page.
776 * @param showItemsPerPage
777 */
778 public void setShowItemsPerPage(boolean showItemsPerPage)
779 {
780 this.showItemsPerPage = showItemsPerPage;
781 }
782
783 /***
784 * @return Returns the generateItemsPerPageForm.
785 */
786 public boolean isGenerateItemsPerPageForm()
787 {
788 return generateItemsPerPageForm;
789 }
790
791 /***
792 * Enable or disable generating of HTML form tag wrapping input box "items per page".
793 *
794 * @param generateItemsPerPageForm The generateItemsPerPageForm to set.
795 */
796 /***
797 *
798 * @param nestedForm
799 */
800 public void setGenerateItemsPerPageForm(boolean nestedForm)
801 {
802 this.generateItemsPerPageForm = nestedForm;
803 }
804
805 private void reset()
806 {
807 this.rootTag = null;
808 this.currentPage = 0;
809 this.generateItemsPerPageForm = true;
810 this.maxPage = 0;
811 this.pages = 0;
812 this.parameters = null;
813 this.showItemsPerPage = false;
814 this.showSummary = false;
815 this.displayHelper = null;
816 this.messageSource = null;
817 this.currentLocale = null;
818 }
819
820 /***
821 * Called on a Tag handler to release state.
822 * The page compiler guarantees that JSP page implementation
823 * objects will invoke this method on all tag handlers,
824 * but there may be multiple invocations on doStartTag and doEndTag in between.
825 *
826 * @see javax.servlet.jsp.tagext.Tag#release()
827 */
828 public void release()
829 {
830 super.release();
831 reset();
832 }
833 }