Save This Page
Home » displaytag-1.1.1-src » org » displaytag » render » [javadoc | source]
    1   /**
    2    * Licensed under the Artistic License; you may not use this file
    3    * except in compliance with the License.
    4    * You may obtain a copy of the License at
    5    *
    6    *      http://displaytag.sourceforge.net/license.html
    7    *
    8    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
    9    * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   10    * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   11    */
   12   package org.displaytag.render;
   13   
   14   import java.io.IOException;
   15   import java.text.MessageFormat;
   16   import java.util.Iterator;
   17   import java.util.Map;
   18   
   19   import javax.servlet.jsp.JspException;
   20   import javax.servlet.jsp.JspWriter;
   21   
   22   import org.apache.commons.logging.Log;
   23   import org.apache.commons.logging.LogFactory;
   24   import org.displaytag.exception.DecoratorException;
   25   import org.displaytag.exception.ObjectLookupException;
   26   import org.displaytag.exception.WrappedRuntimeException;
   27   import org.displaytag.model.Column;
   28   import org.displaytag.model.HeaderCell;
   29   import org.displaytag.model.Row;
   30   import org.displaytag.model.TableModel;
   31   import org.displaytag.pagination.PaginatedList;
   32   import org.displaytag.pagination.SmartListHelper;
   33   import org.displaytag.properties.MediaTypeEnum;
   34   import org.displaytag.properties.SortOrderEnum;
   35   import org.displaytag.properties.TableProperties;
   36   import org.displaytag.tags.CaptionTag;
   37   import org.displaytag.tags.TableTagParameters;
   38   import org.displaytag.util.Anchor;
   39   import org.displaytag.util.Href;
   40   import org.displaytag.util.HtmlAttributeMap;
   41   import org.displaytag.util.ParamEncoder;
   42   import org.displaytag.util.TagConstants;
   43   
   44   
   45   /**
   46    * A table writer that formats a table in HTML and writes it to a JSP page.
   47    * @author Fabrizio Giustina
   48    * @author Jorge L. Barroso
   49    * @version $Id$
   50    * @see org.displaytag.render.TableWriterTemplate
   51    * @since 1.1
   52    */
   53   public class HtmlTableWriter extends TableWriterAdapter
   54   {
   55   
   56       /**
   57        * Logger.
   58        */
   59       private static Log log = LogFactory.getLog(HtmlTableWriter.class);
   60   
   61       /**
   62        * <code>TableModel</code>
   63        */
   64       private TableModel tableModel;
   65   
   66       /**
   67        * <code>TableProperties</code>
   68        */
   69       private TableProperties properties;
   70   
   71       /**
   72        * Output destination.
   73        */
   74       private JspWriter out;
   75   
   76       /**
   77        * The param encoder used to generate unique parameter names. Initialized at the first use of encodeParameter().
   78        */
   79       private ParamEncoder paramEncoder;
   80   
   81       /**
   82        * base href used for links.
   83        */
   84       private Href baseHref;
   85   
   86       /**
   87        * add export links.
   88        */
   89       private boolean export;
   90   
   91       private CaptionTag captionTag;
   92   
   93       /**
   94        * The paginated list containing the external pagination and sort parameters The presence of this paginated list is
   95        * what determines if external pagination and sorting is used or not.
   96        */
   97       private PaginatedList paginatedList;
   98   
   99       /**
  100        * Used by various functions when the person wants to do paging.
  101        */
  102       private SmartListHelper listHelper;
  103   
  104       /**
  105        * page size.
  106        */
  107       private int pagesize;
  108   
  109       private HtmlAttributeMap attributeMap;
  110   
  111       /**
  112        * Unique table id.
  113        */
  114       private String uid;
  115   
  116       /**
  117        * This table writer uses a <code>TableTag</code> and a <code>JspWriter</code> to do its work.
  118        * @param tableTag <code>TableTag</code> instance called back by this writer.
  119        * @param out The output destination.
  120        */
  121       public HtmlTableWriter(
  122           TableModel tableModel,
  123           TableProperties tableProperties,
  124           Href baseHref,
  125           boolean export,
  126           JspWriter out,
  127           CaptionTag captionTag,
  128           PaginatedList paginatedList,
  129           SmartListHelper listHelper,
  130           int pagesize,
  131           HtmlAttributeMap attributeMap,
  132           String uid)
  133       {
  134           this.tableModel = tableModel;
  135           this.properties = tableProperties;
  136           this.baseHref = baseHref;
  137           this.export = export;
  138           this.out = out;
  139           this.captionTag = captionTag;
  140           this.paginatedList = paginatedList;
  141           this.listHelper = listHelper;
  142           this.pagesize = pagesize;
  143           this.attributeMap = attributeMap;
  144           this.uid = uid;
  145       }
  146   
  147       /**
  148        * Writes a banner containing search result and paging navigation above an HTML table to a JSP page.
  149        * @see org.displaytag.render.TableWriterTemplate#writeTopBanner(org.displaytag.model.TableModel)
  150        */
  151       protected void writeTopBanner(TableModel model)
  152       {
  153           writeSearchResultAndNavigation();
  154       }
  155   
  156       /**
  157        * Writes an HTML table's opening tags to a JSP page.
  158        * @see org.displaytag.render.TableWriterTemplate#writeTableOpener(org.displaytag.model.TableModel)
  159        */
  160       protected void writeTableOpener(TableModel model)
  161       {
  162           this.write(getOpenTag());
  163       }
  164   
  165       /**
  166        * Writes an HTML table's caption to a JSP page.
  167        * @see org.displaytag.render.TableWriterTemplate#writeCaption(org.displaytag.model.TableModel)
  168        */
  169       protected void writeCaption(TableModel model)
  170       {
  171           this.write(captionTag.getOpenTag() + model.getCaption() + captionTag.getCloseTag());
  172       }
  173   
  174       /**
  175        * Writes an HTML table's footer to a JSP page; HTML requires tfoot to appear before tbody.
  176        * @see org.displaytag.render.TableWriterTemplate#writeFooter(org.displaytag.model.TableModel)
  177        */
  178       protected void writePreBodyFooter(TableModel model)
  179       {
  180           this.write(TagConstants.TAG_TFOOTER_OPEN);
  181           this.write(model.getFooter());
  182           this.write(TagConstants.TAG_TFOOTER_CLOSE);
  183       }
  184   
  185       /**
  186        * Writes the start of an HTML table's body to a JSP page.
  187        * @see org.displaytag.render.TableWriterTemplate#writeTableBodyOpener(org.displaytag.model.TableModel)
  188        */
  189       protected void writeTableBodyOpener(TableModel model)
  190       {
  191           this.write(TagConstants.TAG_TBODY_OPEN);
  192   
  193       }
  194   
  195       /**
  196        * Writes the end of an HTML table's body to a JSP page.
  197        * @see org.displaytag.render.TableWriterTemplate#writeTableBodyCloser(org.displaytag.model.TableModel)
  198        */
  199       protected void writeTableBodyCloser(TableModel model)
  200       {
  201           this.write(TagConstants.TAG_TBODY_CLOSE);
  202       }
  203   
  204       /**
  205        * Writes the closing structure of an HTML table to a JSP page.
  206        * @see org.displaytag.render.TableWriterTemplate#writeTableCloser(org.displaytag.model.TableModel)
  207        */
  208       protected void writeTableCloser(TableModel model)
  209       {
  210           this.write(TagConstants.TAG_OPENCLOSING);
  211           this.write(TagConstants.TABLE_TAG_NAME);
  212           this.write(TagConstants.TAG_CLOSE);
  213       }
  214   
  215       /**
  216        * Writes a banner containing search result, paging navigation, and export links below an HTML table to a JSP page.
  217        * @see org.displaytag.render.TableWriterTemplate#writeBottomBanner(org.displaytag.model.TableModel)
  218        */
  219       protected void writeBottomBanner(TableModel model)
  220       {
  221           writeNavigationAndExportLinks();
  222       }
  223   
  224       /**
  225        * @see org.displaytag.render.TableWriterTemplate#writeDecoratedTableFinish(org.displaytag.model.TableModel)
  226        */
  227       protected void writeDecoratedTableFinish(TableModel model)
  228       {
  229           model.getTableDecorator().finish();
  230       }
  231   
  232       /**
  233        * @see org.displaytag.render.TableWriterTemplate#writeDecoratedRowStart(org.displaytag.model.TableModel)
  234        */
  235       protected void writeDecoratedRowStart(TableModel model)
  236       {
  237           this.write(model.getTableDecorator().startRow());
  238       }
  239   
  240       /**
  241        * Writes an HTML table's row-opening tag to a JSP page.
  242        * @see org.displaytag.render.TableWriterTemplate#writeRowOpener(org.displaytag.model.Row)
  243        */
  244       protected void writeRowOpener(Row row)
  245       {
  246           this.write(row.getOpenTag());
  247       }
  248   
  249       /**
  250        * Writes an HTML table's column-opening tag to a JSP page.
  251        * @see org.displaytag.render.TableWriterTemplate#writeColumnOpener(org.displaytag.model.Column)
  252        */
  253       protected void writeColumnOpener(Column column) throws ObjectLookupException, DecoratorException
  254       {
  255           this.write(column.getOpenTag());
  256       }
  257   
  258       /**
  259        * Writes an HTML table's column-closing tag to a JSP page.
  260        * @see org.displaytag.render.TableWriterTemplate#writeColumnCloser(org.displaytag.model.Column)
  261        */
  262       protected void writeColumnCloser(Column column)
  263       {
  264           this.write(column.getCloseTag());
  265       }
  266   
  267       /**
  268        * Writes to a JSP page an HTML table row that has no columns.
  269        * @see org.displaytag.render.TableWriterTemplate#writeRowWithNoColumns(java.lang.String)
  270        */
  271       protected void writeRowWithNoColumns(String rowValue)
  272       {
  273           this.write(TagConstants.TAG_TD_OPEN);
  274           this.write(rowValue);
  275           this.write(TagConstants.TAG_TD_CLOSE);
  276       }
  277   
  278       /**
  279        * Writes an HTML table's row-closing tag to a JSP page.
  280        * @see org.displaytag.render.TableWriterTemplate#writeRowCloser(org.displaytag.model.Row)
  281        */
  282       protected void writeRowCloser(Row row)
  283       {
  284           this.write(row.getCloseTag());
  285       }
  286   
  287       /**
  288        * @see org.displaytag.render.TableWriterTemplate#writeDecoratedRowFinish(org.displaytag.model.TableModel)
  289        */
  290       protected void writeDecoratedRowFinish(TableModel model)
  291       {
  292           this.write(model.getTableDecorator().finishRow());
  293       }
  294   
  295       /**
  296        * Writes an HTML message to a JSP page explaining that the table model contains no data.
  297        * @see org.displaytag.render.TableWriterTemplate#writeEmptyListMessage(java.lang.String)
  298        */
  299       protected void writeEmptyListMessage(String emptyListMessage)
  300       {
  301           this.write(emptyListMessage);
  302       }
  303   
  304       /**
  305        * Writes a HTML table column value to a JSP page.
  306        * @see org.displaytag.render.TableWriterTemplate#writeColumnValue(java.lang.String,org.displaytag.model.Column)
  307        */
  308       protected void writeColumnValue(Object value, Column column)
  309       {
  310           this.write(value);
  311       }
  312   
  313       /**
  314        * Writes an HTML message to a JSP page explaining that the row contains no data.
  315        * @see org.displaytag.render.TableWriterTemplate#writeEmptyListRowMessage(java.lang.String)
  316        */
  317       protected void writeEmptyListRowMessage(String message)
  318       {
  319           this.write(message);
  320       }
  321   
  322       /**
  323        * Writes an HTML table's column header to a JSP page.
  324        * @see org.displaytag.render.TableWriterTemplate#writeTableHeader(org.displaytag.model.TableModel)
  325        */
  326       protected void writeTableHeader(TableModel model)
  327       {
  328   
  329           if (log.isDebugEnabled())
  330           {
  331               log.debug("[" + tableModel.getId() + "] getTableHeader called");
  332           }
  333   
  334           // open thead
  335           write(TagConstants.TAG_THEAD_OPEN);
  336   
  337           // open tr
  338           write(TagConstants.TAG_TR_OPEN);
  339   
  340           // no columns?
  341           if (this.tableModel.isEmpty())
  342           {
  343               write(TagConstants.TAG_TH_OPEN);
  344               write(TagConstants.TAG_TH_CLOSE);
  345           }
  346   
  347           // iterator on columns for header
  348           Iterator iterator = this.tableModel.getHeaderCellList().iterator();
  349   
  350           while (iterator.hasNext())
  351           {
  352               // get the header cell
  353               HeaderCell headerCell = (HeaderCell) iterator.next();
  354   
  355               if (headerCell.getSortable())
  356               {
  357                   String cssSortable = this.properties.getCssSortable();
  358                   headerCell.addHeaderClass(cssSortable);
  359               }
  360   
  361               // if sorted add styles
  362               if (headerCell.isAlreadySorted())
  363               {
  364                   // sorted css class
  365                   headerCell.addHeaderClass(this.properties.getCssSorted());
  366   
  367                   // sort order css class
  368                   headerCell.addHeaderClass(this.properties.getCssOrder(this.tableModel.isSortOrderAscending()));
  369               }
  370   
  371               // append th with html attributes
  372               write(headerCell.getHeaderOpenTag());
  373   
  374               // title
  375               String header = headerCell.getTitle();
  376   
  377               // column is sortable, create link
  378               if (headerCell.getSortable())
  379               {
  380                   // creates the link for sorting
  381                   Anchor anchor = new Anchor(getSortingHref(headerCell), header);
  382   
  383                   // append to buffer
  384                   header = anchor.toString();
  385               }
  386   
  387               write(header);
  388               write(headerCell.getHeaderCloseTag());
  389           }
  390   
  391           // close tr
  392           write(TagConstants.TAG_TR_CLOSE);
  393   
  394           // close thead
  395           write(TagConstants.TAG_THEAD_CLOSE);
  396   
  397           if (log.isDebugEnabled())
  398           {
  399               log.debug("[" + tableModel.getId() + "] getTableHeader end");
  400           }
  401       }
  402   
  403       /**
  404        * Generates the link to be added to a column header for sorting.
  405        * @param headerCell header cell the link should be added to
  406        * @return Href for sorting
  407        */
  408       private Href getSortingHref(HeaderCell headerCell)
  409       {
  410           // costruct Href from base href, preserving parameters
  411           Href href = (Href) this.baseHref.clone();
  412   
  413           if (this.paginatedList == null)
  414           {
  415               // add column number as link parameter
  416               if (!this.tableModel.isLocalSort() && (headerCell.getSortName() != null))
  417               {
  418                   href.addParameter(encodeParameter(TableTagParameters.PARAMETER_SORT), headerCell.getSortName());
  419                   href.addParameter(encodeParameter(TableTagParameters.PARAMETER_SORTUSINGNAME), "1");
  420               }
  421               else
  422               {
  423                   href.addParameter(encodeParameter(TableTagParameters.PARAMETER_SORT), headerCell.getColumnNumber());
  424               }
  425   
  426               boolean nowOrderAscending = true;
  427   
  428               if (headerCell.getDefaultSortOrder() != null)
  429               {
  430                   boolean sortAscending = SortOrderEnum.ASCENDING.equals(headerCell.getDefaultSortOrder());
  431                   nowOrderAscending = headerCell.isAlreadySorted()
  432                       ? !this.tableModel.isSortOrderAscending()
  433                       : sortAscending;
  434               }
  435               else
  436               {
  437                   nowOrderAscending = !(headerCell.isAlreadySorted() && this.tableModel.isSortOrderAscending());
  438               }
  439   
  440               int sortOrderParam = nowOrderAscending ? SortOrderEnum.ASCENDING.getCode() : SortOrderEnum.DESCENDING
  441                   .getCode();
  442               href.addParameter(encodeParameter(TableTagParameters.PARAMETER_ORDER), sortOrderParam);
  443   
  444               // If user want to sort the full table I need to reset the page number.
  445               // or if we aren't sorting locally we need to reset the page as well.
  446               if (this.tableModel.isSortFullTable() || !this.tableModel.isLocalSort())
  447               {
  448                   href.addParameter(encodeParameter(TableTagParameters.PARAMETER_PAGE), 1);
  449               }
  450           }
  451           else
  452           {
  453               if (properties.getPaginationSkipPageNumberInSort())
  454               {
  455                   href.removeParameter(properties.getPaginationPageNumberParam());
  456               }
  457   
  458               String sortProperty = headerCell.getSortProperty();
  459               if (sortProperty == null)
  460               {
  461                   sortProperty = headerCell.getBeanPropertyName();
  462               }
  463   
  464               href.addParameter(properties.getPaginationSortParam(), sortProperty);
  465               String dirParam;
  466               if (headerCell.isAlreadySorted())
  467               {
  468                   dirParam = tableModel.isSortOrderAscending() ? properties.getPaginationDescValue() : properties
  469                       .getPaginationAscValue();
  470               }
  471               else
  472               {
  473                   dirParam = properties.getPaginationAscValue();
  474               }
  475               href.addParameter(properties.getPaginationSortDirectionParam(), dirParam);
  476               if (paginatedList.getSearchId() != null)
  477               {
  478                   href.addParameter(properties.getPaginationSearchIdParam(), paginatedList.getSearchId());
  479               }
  480           }
  481   
  482           return href;
  483       }
  484   
  485       /**
  486        * encode a parameter name to be unique in the page using ParamEncoder.
  487        * @param parameterName parameter name to encode
  488        * @return String encoded parameter name
  489        */
  490       private String encodeParameter(String parameterName)
  491       {
  492           // paramEncoder has been already instantiated?
  493           if (this.paramEncoder == null)
  494           {
  495               // use the id attribute to get the unique identifier
  496               this.paramEncoder = new ParamEncoder(this.tableModel.getId());
  497           }
  498   
  499           return this.paramEncoder.encodeParameterName(parameterName);
  500       }
  501   
  502       /**
  503        * Generates table footer with links for export commands.
  504        */
  505       public void writeNavigationAndExportLinks()
  506       {
  507           // Put the page stuff there if it needs to be there...
  508           if (this.properties.getAddPagingBannerBottom())
  509           {
  510               writeSearchResultAndNavigation();
  511           }
  512   
  513           // add export links (only if the table is not empty)
  514           if (this.export && this.tableModel.getRowListPage().size() != 0)
  515           {
  516               writeExportLinks();
  517           }
  518       }
  519   
  520       /**
  521        * generates the search result and navigation bar.
  522        */
  523       public void writeSearchResultAndNavigation()
  524       {
  525           if ((this.paginatedList == null && this.pagesize != 0 && this.listHelper != null)
  526               || (this.paginatedList != null))
  527           {
  528               // create a new href
  529               Href navigationHref = (Href) this.baseHref.clone();
  530   
  531               write(this.listHelper.getSearchResultsSummary());
  532   
  533               String pageParameter;
  534               if (paginatedList == null)
  535               {
  536                   pageParameter = encodeParameter(TableTagParameters.PARAMETER_PAGE);
  537               }
  538               else
  539               {
  540                   pageParameter = properties.getPaginationPageNumberParam();
  541                   if ((paginatedList.getSearchId() != null)
  542                       && (!navigationHref.getParameterMap().containsKey(properties.getPaginationSearchIdParam())))
  543                   {
  544                       navigationHref.addParameter(properties.getPaginationSearchIdParam(), paginatedList.getSearchId());
  545                   }
  546               }
  547               write(this.listHelper.getPageNavigationBar(navigationHref, pageParameter));
  548           }
  549       }
  550   
  551       /**
  552        * Writes the formatted export links section.
  553        */
  554       private void writeExportLinks()
  555       {
  556           // Figure out what formats they want to export, make up a little string
  557           Href exportHref = (Href) this.baseHref.clone();
  558   
  559           StringBuffer buffer = new StringBuffer(200);
  560           Iterator iterator = MediaTypeEnum.iterator();
  561   
  562           while (iterator.hasNext())
  563           {
  564               MediaTypeEnum currentExportType = (MediaTypeEnum) iterator.next();
  565   
  566               if (this.properties.getAddExport(currentExportType))
  567               {
  568   
  569                   if (buffer.length() > 0)
  570                   {
  571                       buffer.append(this.properties.getExportBannerSeparator());
  572                   }
  573   
  574                   exportHref.addParameter(encodeParameter(TableTagParameters.PARAMETER_EXPORTTYPE), currentExportType
  575                       .getCode());
  576   
  577                   // export marker
  578                   exportHref.addParameter(TableTagParameters.PARAMETER_EXPORTING, "1");
  579   
  580                   Anchor anchor = new Anchor(exportHref, this.properties.getExportLabel(currentExportType));
  581                   buffer.append(anchor.toString());
  582               }
  583           }
  584   
  585           String[] exportOptions = {buffer.toString()};
  586           write(MessageFormat.format(this.properties.getExportBanner(), exportOptions));
  587       }
  588   
  589       /**
  590        * create the open tag containing all the attributes.
  591        * @return open tag string: <code>%lt;table attribute="value" ... ></code>
  592        */
  593       public String getOpenTag()
  594       {
  595   
  596           if (this.uid != null && attributeMap.get(TagConstants.ATTRIBUTE_ID) == null)
  597           {
  598               // we need to clone the attribute map in order to "fix" the html id when using only the "uid" attribute
  599               Map localAttributeMap = (Map) attributeMap.clone();
  600               localAttributeMap.put(TagConstants.ATTRIBUTE_ID, this.uid);
  601   
  602               StringBuffer buffer = new StringBuffer();
  603               buffer.append(TagConstants.TAG_OPEN).append(TagConstants.TABLE_TAG_NAME);
  604               buffer.append(localAttributeMap);
  605               buffer.append(TagConstants.TAG_CLOSE);
  606   
  607               return buffer.toString();
  608   
  609           }
  610   
  611           // fast, no clone
  612           StringBuffer buffer = new StringBuffer();
  613   
  614           buffer.append(TagConstants.TAG_OPEN).append(TagConstants.TABLE_TAG_NAME);
  615           buffer.append(attributeMap);
  616           buffer.append(TagConstants.TAG_CLOSE);
  617   
  618           return buffer.toString();
  619       }
  620   
  621       /**
  622        * Utility method.
  623        * @param string String
  624        */
  625       public void write(String string)
  626       {
  627           if (string != null)
  628           {
  629               try
  630               {
  631                   out.write(string);
  632               }
  633               catch (IOException e)
  634               {
  635                   throw new WrappedRuntimeException(getClass(), e);
  636               }
  637           }
  638   
  639       }
  640   
  641       public void writeTable(TableModel model, String id) throws JspException
  642       {
  643           super.writeTable(model, id);
  644       }
  645   
  646       /**
  647        * Utility method.
  648        * @param string String
  649        */
  650       public void write(Object string)
  651       {
  652           if (string != null)
  653           {
  654               try
  655               {
  656                   out.write(string.toString());
  657               }
  658               catch (IOException e)
  659               {
  660                   throw new WrappedRuntimeException(getClass(), e);
  661               }
  662           }
  663   
  664       }
  665   
  666   }

Save This Page
Home » displaytag-1.1.1-src » org » displaytag » render » [javadoc | source]