Coverage Report - org.kuali.rice.kns.web.struts.form.KualiTableRenderFormMetadata
 
Classes in this File Line Coverage Branch Coverage Complexity
KualiTableRenderFormMetadata
0%
0/72
0%
0/20
1.8
KualiTableRenderFormMetadata$1
0%
0/24
0%
0/18
1.8
 
 1  
 /*
 2  
  * Copyright 2007 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.rice.kns.web.struts.form;
 17  
 
 18  
 import org.apache.commons.beanutils.BeanComparator;
 19  
 import org.apache.commons.beanutils.PropertyUtils;
 20  
 import org.apache.commons.lang.StringUtils;
 21  
 import org.kuali.rice.kew.exception.WorkflowException;
 22  
 import org.kuali.rice.kns.util.TableRenderUtil;
 23  
 
 24  
 import java.util.Collections;
 25  
 import java.util.Comparator;
 26  
 import java.util.Date;
 27  
 import java.util.List;
 28  
 
 29  
 /**
 30  
  * This class holds the metadata necessary to render a table when displaytag is not being used.
 31  
  */
 32  
 public class KualiTableRenderFormMetadata {
 33  
     private int viewedPageNumber;
 34  
     private int totalNumberOfPages;
 35  
     private int firstRowIndex;
 36  
     private int lastRowIndex;
 37  
     private int switchToPageNumber;
 38  
 
 39  
     /**
 40  
      * The number of rows that match the query criteria
 41  
      */
 42  
     private int resultsActualSize;
 43  
 
 44  
     /**
 45  
      * The number of rows that match the query criteria or
 46  
      *  the max results limit size (if applicable), whichever is less
 47  
      */
 48  
     private int resultsLimitedSize;
 49  
 
 50  
     /**
 51  
      * when the looked results screen was rendered, the index of the column that the results were sorted on.  -1 for unknown, index numbers
 52  
      * starting at 0
 53  
      */
 54  
     private int previouslySortedColumnIndex;
 55  
 
 56  
     /**
 57  
      * Comment for <code>columnToSortIndex</code>
 58  
      */
 59  
     private int columnToSortIndex;
 60  
 
 61  
     /**
 62  
      * If it is not feasible to use an index for lookup, as with mapped properties in an Map<String, String>, it may be necessary to store a string value
 63  
      */
 64  
     private String columnToSortName;
 65  
 
 66  
     /**
 67  
      * When the screen was last rendered, the column name on which it was previously sorted -- this is important for toggling between ascending and descending
 68  
      * sort orders
 69  
      */
 70  
     private String previouslySortedColumnName;
 71  
 
 72  
     private boolean sortDescending;
 73  
 
 74  0
     public KualiTableRenderFormMetadata() {
 75  0
         sortDescending = false;
 76  0
     }
 77  
 
 78  
     /**
 79  
      * Gets the columnToSortIndex attribute.
 80  
      * @return Returns the columnToSortIndex.
 81  
      */
 82  
     public int getColumnToSortIndex() {
 83  0
         return columnToSortIndex;
 84  
     }
 85  
 
 86  
     /**
 87  
      * Sets the columnToSortIndex attribute value.
 88  
      * @param columnToSortIndex The columnToSortIndex to set.
 89  
      */
 90  
     public void setColumnToSortIndex(int columnToSortIndex) {
 91  0
         this.columnToSortIndex = columnToSortIndex;
 92  0
     }
 93  
 
 94  
     /**
 95  
      * Gets the previouslySortedColumnIndex attribute.
 96  
      * @return Returns the previouslySortedColumnIndex.
 97  
      */
 98  
     public int getPreviouslySortedColumnIndex() {
 99  0
         return previouslySortedColumnIndex;
 100  
     }
 101  
 
 102  
     /**
 103  
      * Sets the previouslySortedColumnIndex attribute value.
 104  
      * @param previouslySortedColumnIndex The previouslySortedColumnIndex to set.
 105  
      */
 106  
     public void setPreviouslySortedColumnIndex(int previouslySortedColumnIndex) {
 107  0
         this.previouslySortedColumnIndex = previouslySortedColumnIndex;
 108  0
     }
 109  
 
 110  
     /**
 111  
      * Gets the resultsActualSize attribute.
 112  
      * @return Returns the resultsActualSize.
 113  
      */
 114  
     public int getResultsActualSize() {
 115  0
         return resultsActualSize;
 116  
     }
 117  
 
 118  
     /**
 119  
      * Sets the resultsActualSize attribute value.
 120  
      * @param resultsActualSize The resultsActualSize to set.
 121  
      */
 122  
     public void setResultsActualSize(int resultsActualSize) {
 123  0
         this.resultsActualSize = resultsActualSize;
 124  0
     }
 125  
 
 126  
     /**
 127  
      * Gets the resultsLimitedSize attribute.
 128  
      * @return Returns the resultsLimitedSize.
 129  
      */
 130  
     public int getResultsLimitedSize() {
 131  0
         return resultsLimitedSize;
 132  
     }
 133  
 
 134  
     /**
 135  
      * Sets the resultsLimitedSize attribute value.
 136  
      * @param resultsLimitedSize The resultsLimitedSize to set.
 137  
      */
 138  
     public void setResultsLimitedSize(int resultsLimitedSize) {
 139  0
         this.resultsLimitedSize = resultsLimitedSize;
 140  0
     }
 141  
 
 142  
     /**
 143  
      * Gets the switchToPageNumber attribute.
 144  
      * @return Returns the switchToPageNumber.
 145  
      */
 146  
     public int getSwitchToPageNumber() {
 147  0
         return switchToPageNumber;
 148  
     }
 149  
 
 150  
     /**
 151  
      * Sets the switchToPageNumber attribute value.
 152  
      * @param switchToPageNumber The switchToPageNumber to set.
 153  
      */
 154  
     public void setSwitchToPageNumber(int switchToPageNumber) {
 155  0
         this.switchToPageNumber = switchToPageNumber;
 156  0
     }
 157  
 
 158  
     /**
 159  
      * Gets the viewedPageNumber attribute.
 160  
      * @return Returns the viewedPageNumber.
 161  
      */
 162  
     public int getViewedPageNumber() {
 163  0
         return viewedPageNumber;
 164  
     }
 165  
 
 166  
     /**
 167  
      * Sets the viewedPageNumber attribute value.
 168  
      * @param viewedPageNumber The viewedPageNumber to set.
 169  
      */
 170  
     public void setViewedPageNumber(int viewedPageNumber) {
 171  0
         this.viewedPageNumber = viewedPageNumber;
 172  0
     }
 173  
 
 174  
     /**
 175  
      * Gets the totalNumberOfPages attribute.
 176  
      * @return Returns the totalNumberOfPages.
 177  
      */
 178  
     public int getTotalNumberOfPages() {
 179  0
         return totalNumberOfPages;
 180  
     }
 181  
 
 182  
     /**
 183  
      * Sets the totalNumberOfPages attribute value.
 184  
      * @param totalNumberOfPages The totalNumberOfPages to set.
 185  
      */
 186  
     public void setTotalNumberOfPages(int totalNumberOfPages) {
 187  0
         this.totalNumberOfPages = totalNumberOfPages;
 188  0
     }
 189  
 
 190  
     /**
 191  
      * Gets the firstRowIndex attribute.
 192  
      * @return Returns the firstRowIndex.
 193  
      */
 194  
     public int getFirstRowIndex() {
 195  0
         return firstRowIndex;
 196  
     }
 197  
 
 198  
     /**
 199  
      * Sets the firstRowIndex attribute value.
 200  
      * @param firstRowIndex The firstRowIndex to set.
 201  
      */
 202  
     public void setFirstRowIndex(int firstRowIndex) {
 203  0
         this.firstRowIndex = firstRowIndex;
 204  0
     }
 205  
 
 206  
     /**
 207  
      * Gets the lastRowIndex attribute.
 208  
      * @return Returns the lastRowIndex.
 209  
      */
 210  
     public int getLastRowIndex() {
 211  0
         return lastRowIndex;
 212  
     }
 213  
 
 214  
     /**
 215  
      * Sets the lastRowIndex attribute value.
 216  
      * @param lastRowIndex The lastRowIndex to set.
 217  
      */
 218  
     public void setLastRowIndex(int lastRowIndex) {
 219  0
         this.lastRowIndex = lastRowIndex;
 220  0
     }
 221  
 
 222  
     /**
 223  
      * Gets the sortDescending attribute.
 224  
      * @return Returns the sortDescending.
 225  
      */
 226  
     public boolean isSortDescending() {
 227  0
         return sortDescending;
 228  
     }
 229  
 
 230  
     /**
 231  
      * Sets the sortDescending attribute value.
 232  
      * @param sortDescending The sortDescending to set.
 233  
      */
 234  
     public void setSortDescending(boolean sortDescending) {
 235  0
         this.sortDescending = sortDescending;
 236  0
     }
 237  
 
 238  
         /**
 239  
          * @return the columnToSortName
 240  
          */
 241  
         public String getColumnToSortName() {
 242  0
                 return this.columnToSortName;
 243  
         }
 244  
 
 245  
         /**
 246  
          * @param columnToSortName the columnToSortName to set
 247  
          */
 248  
         public void setColumnToSortName(String columnToSortName) {
 249  0
                 this.columnToSortName = columnToSortName;
 250  0
         }
 251  
 
 252  
         /**
 253  
          * @return the previouslySortedColumnName
 254  
          */
 255  
         public String getPreviouslySortedColumnName() {
 256  0
                 return this.previouslySortedColumnName;
 257  
         }
 258  
 
 259  
         /**
 260  
          * @param previouslySortedColumnName the previouslySortedColumnName to set
 261  
          */
 262  
         public void setPreviouslySortedColumnName(String previouslySortedColumnName) {
 263  0
                 this.previouslySortedColumnName = previouslySortedColumnName;
 264  0
         }
 265  
 
 266  
 
 267  
     /**
 268  
      * Sets the paging form parameters to go to the first page of the list
 269  
      *
 270  
      * @param listSize size of table being rendered
 271  
      * @param maxRowsPerPage
 272  
      */
 273  
     public void jumpToFirstPage(int listSize, int maxRowsPerPage) {
 274  0
         jumpToPage(0, listSize, maxRowsPerPage);
 275  0
     }
 276  
 
 277  
     /**
 278  
      * Sets the paging form parameters to go to the last page of the list
 279  
      *
 280  
      * @param listSize size of table being rendered
 281  
      * @param maxRowsPerPage
 282  
      */
 283  
     public void jumpToLastPage(int listSize, int maxRowsPerPage) {
 284  0
         jumpToPage(TableRenderUtil.computeTotalNumberOfPages(listSize, maxRowsPerPage) - 1, listSize, maxRowsPerPage);
 285  0
     }
 286  
 
 287  
     /**
 288  
      * Sets the paging form parameters to go to the specified page of the list
 289  
      *
 290  
      * @param pageNumber first page is 0, must be non-negative.  If the list is not large enough to have the page specified, then
 291  
      *   this method will be equivalent to calling jumpToLastPage.
 292  
      * @param listSize size of table being rendered
 293  
      * @param maxRowsPerPage
 294  
      *
 295  
      * @see KualiTableRenderFormMetadata#jumpToLastPage(int, int)
 296  
      */
 297  
     public void jumpToPage(int pageNumber, int listSize, int maxRowsPerPage) {
 298  0
         int totalPages = TableRenderUtil.computeTotalNumberOfPages(listSize, maxRowsPerPage);
 299  0
         setTotalNumberOfPages(totalPages);
 300  0
         if (pageNumber >= totalPages) {
 301  0
             pageNumber = totalPages - 1;
 302  
         }
 303  0
         setViewedPageNumber(pageNumber);
 304  0
         setFirstRowIndex(TableRenderUtil.computeStartIndexForPage(pageNumber, listSize, maxRowsPerPage));
 305  0
         setLastRowIndex(TableRenderUtil.computeLastIndexForPage(pageNumber, listSize, maxRowsPerPage));
 306  0
     }
 307  
 
 308  
     /**
 309  
      * Sorts a list on the form according to the form metadata (sortColumName, previouslySortedColumnName)
 310  
      *
 311  
      * @param memberTableMetadata
 312  
      * @param items
 313  
      * @param maxRowsPerPage
 314  
      * @throws WorkflowException
 315  
      */
 316  
     public void sort(List<?> items, int maxRowsPerPage) {
 317  
 
 318  
             // Don't bother to sort null, empty or singleton lists
 319  0
             if (items == null || items.size() <= 1)
 320  0
                     return;
 321  
 
 322  0
         String columnToSortOn = getColumnToSortName();
 323  
 
 324  
         // Don't bother to sort if no column to sort on is provided
 325  0
         if (StringUtils.isEmpty(columnToSortOn))
 326  0
                 return;
 327  
 
 328  0
         String previouslySortedColumnName = getPreviouslySortedColumnName();
 329  
 
 330  
         // We know members isn't null or empty from the check above
 331  0
             Object firstItem = items.get(0);
 332  
             // Need to decide if the comparator is for a bean property or a mapped key on the qualififer attribute set
 333  0
             Comparator comparator = null;
 334  0
             Comparator subComparator = new Comparator<Object>() {
 335  
 
 336  
                     public int compare(Object o1, Object o2) {
 337  0
                             if (o1 == null)
 338  0
                                     return -1;
 339  0
                             if (o2 == null)
 340  0
                                     return 1;
 341  
 
 342  0
                             if (o1 instanceof java.util.Date && o2 instanceof java.util.Date) {
 343  0
                                     Date d1 = (Date)o1;
 344  0
                                     Date d2 = (Date)o2;
 345  0
                                     return d1.compareTo(d2);
 346  
                             }
 347  
 
 348  0
                             String s1 = o1.toString();
 349  0
                             String s2 = o2.toString();
 350  0
                             int n1=s1.length(), n2=s2.length();
 351  0
                             for (int i1=0, i2=0; i1<n1 && i2<n2; i1++, i2++) {
 352  0
                                     char c1 = s1.charAt(i1);
 353  0
                                     char c2 = s2.charAt(i2);
 354  0
                                     if (c1 != c2) {
 355  0
                                             c1 = Character.toUpperCase(c1);
 356  0
                                             c2 = Character.toUpperCase(c2);
 357  0
                                             if (c1 != c2) {
 358  0
                                                     c1 = Character.toLowerCase(c1);
 359  0
                                                     c2 = Character.toLowerCase(c2);
 360  0
                                                     if (c1 != c2) {
 361  0
                                                             return c1 - c2;
 362  
                                                     }
 363  
                                             }
 364  
                                     }
 365  
                             }
 366  0
                             return n1 - n2;
 367  
                     }
 368  
             };
 369  
             // If the columnName is a readable bean property on the first member, then it's safe to say we need a simple bean property comparator,
 370  
             // otherwise it's a mapped property -- syntax for BeanComparator is "name" and "name(key)", respectively
 371  0
             if (PropertyUtils.isReadable(firstItem, columnToSortOn))
 372  0
                     comparator = new BeanComparator(columnToSortOn, subComparator);
 373  
             else
 374  0
                     comparator = new BeanComparator(new StringBuilder().append("qualifierAsMap<String, String>(").append(columnToSortOn).append(")").toString(), subComparator);
 375  
 
 376  
 
 377  
         // If the user has decided to resort by the same column that the list is currently sorted by, then assume that s/he wants to reverse the order of the sort
 378  0
         if (!StringUtils.isEmpty(columnToSortOn) && !StringUtils.isEmpty(previouslySortedColumnName) && columnToSortOn.equals(previouslySortedColumnName)) {
 379  
             // we're already sorted on the same column that the user clicked on, so we reverse the list
 380  0
                 if (isSortDescending())
 381  0
                         comparator = Collections.reverseOrder(comparator);
 382  
 
 383  0
                 setSortDescending(!isSortDescending());
 384  
         } else {
 385  
                 // Track which column we're currently sorting, so that the above logic will work on the next sort
 386  0
                 setPreviouslySortedColumnName(columnToSortOn);
 387  0
                 setSortDescending(true);
 388  
         }
 389  
 
 390  0
         Collections.sort(items, comparator);
 391  
 
 392  0
                 jumpToFirstPage(items.size(), maxRowsPerPage);
 393  0
     }
 394  
 
 395  
 }