001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kns.web.struts.form; 017 018import org.apache.commons.beanutils.BeanComparator; 019import org.apache.commons.beanutils.PropertyUtils; 020import org.apache.commons.lang.StringUtils; 021import org.kuali.rice.kns.util.TableRenderUtil; 022 023import java.util.Collections; 024import java.util.Comparator; 025import java.util.Date; 026import java.util.List; 027 028/** 029 * This class holds the metadata necessary to render a table when displaytag is not being used. 030 * 031 * @deprecated KNS Struts deprecated, use KRAD and the Spring MVC framework. 032 */ 033@Deprecated 034public class KualiTableRenderFormMetadata { 035 private int viewedPageNumber; 036 private int totalNumberOfPages; 037 private int firstRowIndex; 038 private int lastRowIndex; 039 private int switchToPageNumber; 040 041 /** 042 * The number of rows that match the query criteria 043 */ 044 private int resultsActualSize; 045 046 /** 047 * The number of rows that match the query criteria or 048 * the max results limit size (if applicable), whichever is less 049 */ 050 private int resultsLimitedSize; 051 052 /** 053 * when the looked results screen was rendered, the index of the column that the results were sorted on. -1 for unknown, index numbers 054 * starting at 0 055 */ 056 private int previouslySortedColumnIndex; 057 058 /** 059 * Comment for <code>columnToSortIndex</code> 060 */ 061 private int columnToSortIndex; 062 063 /** 064 * 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 065 */ 066 private String columnToSortName; 067 068 /** 069 * When the screen was last rendered, the column name on which it was previously sorted -- this is important for toggling between ascending and descending 070 * sort orders 071 */ 072 private String previouslySortedColumnName; 073 074 private boolean sortDescending; 075 076 public KualiTableRenderFormMetadata() { 077 sortDescending = false; 078 } 079 080 /** 081 * Gets the columnToSortIndex attribute. 082 * @return Returns the columnToSortIndex. 083 */ 084 public int getColumnToSortIndex() { 085 return columnToSortIndex; 086 } 087 088 /** 089 * Sets the columnToSortIndex attribute value. 090 * @param columnToSortIndex The columnToSortIndex to set. 091 */ 092 public void setColumnToSortIndex(int columnToSortIndex) { 093 this.columnToSortIndex = columnToSortIndex; 094 } 095 096 /** 097 * Gets the previouslySortedColumnIndex attribute. 098 * @return Returns the previouslySortedColumnIndex. 099 */ 100 public int getPreviouslySortedColumnIndex() { 101 return previouslySortedColumnIndex; 102 } 103 104 /** 105 * Sets the previouslySortedColumnIndex attribute value. 106 * @param previouslySortedColumnIndex The previouslySortedColumnIndex to set. 107 */ 108 public void setPreviouslySortedColumnIndex(int previouslySortedColumnIndex) { 109 this.previouslySortedColumnIndex = previouslySortedColumnIndex; 110 } 111 112 /** 113 * Gets the resultsActualSize attribute. 114 * @return Returns the resultsActualSize. 115 */ 116 public int getResultsActualSize() { 117 return resultsActualSize; 118 } 119 120 /** 121 * Sets the resultsActualSize attribute value. 122 * @param resultsActualSize The resultsActualSize to set. 123 */ 124 public void setResultsActualSize(int resultsActualSize) { 125 this.resultsActualSize = resultsActualSize; 126 } 127 128 /** 129 * Gets the resultsLimitedSize attribute. 130 * @return Returns the resultsLimitedSize. 131 */ 132 public int getResultsLimitedSize() { 133 return resultsLimitedSize; 134 } 135 136 /** 137 * Sets the resultsLimitedSize attribute value. 138 * @param resultsLimitedSize The resultsLimitedSize to set. 139 */ 140 public void setResultsLimitedSize(int resultsLimitedSize) { 141 this.resultsLimitedSize = resultsLimitedSize; 142 } 143 144 /** 145 * Gets the switchToPageNumber attribute. 146 * @return Returns the switchToPageNumber. 147 */ 148 public int getSwitchToPageNumber() { 149 return switchToPageNumber; 150 } 151 152 /** 153 * Sets the switchToPageNumber attribute value. 154 * @param switchToPageNumber The switchToPageNumber to set. 155 */ 156 public void setSwitchToPageNumber(int switchToPageNumber) { 157 this.switchToPageNumber = switchToPageNumber; 158 } 159 160 /** 161 * Gets the viewedPageNumber attribute. 162 * @return Returns the viewedPageNumber. 163 */ 164 public int getViewedPageNumber() { 165 return viewedPageNumber; 166 } 167 168 /** 169 * Sets the viewedPageNumber attribute value. 170 * @param viewedPageNumber The viewedPageNumber to set. 171 */ 172 public void setViewedPageNumber(int viewedPageNumber) { 173 this.viewedPageNumber = viewedPageNumber; 174 } 175 176 /** 177 * Gets the totalNumberOfPages attribute. 178 * @return Returns the totalNumberOfPages. 179 */ 180 public int getTotalNumberOfPages() { 181 return totalNumberOfPages; 182 } 183 184 /** 185 * Sets the totalNumberOfPages attribute value. 186 * @param totalNumberOfPages The totalNumberOfPages to set. 187 */ 188 public void setTotalNumberOfPages(int totalNumberOfPages) { 189 this.totalNumberOfPages = totalNumberOfPages; 190 } 191 192 /** 193 * Gets the firstRowIndex attribute. 194 * @return Returns the firstRowIndex. 195 */ 196 public int getFirstRowIndex() { 197 return firstRowIndex; 198 } 199 200 /** 201 * Sets the firstRowIndex attribute value. 202 * @param firstRowIndex The firstRowIndex to set. 203 */ 204 public void setFirstRowIndex(int firstRowIndex) { 205 this.firstRowIndex = firstRowIndex; 206 } 207 208 /** 209 * Gets the lastRowIndex attribute. 210 * @return Returns the lastRowIndex. 211 */ 212 public int getLastRowIndex() { 213 return lastRowIndex; 214 } 215 216 /** 217 * Sets the lastRowIndex attribute value. 218 * @param lastRowIndex The lastRowIndex to set. 219 */ 220 public void setLastRowIndex(int lastRowIndex) { 221 this.lastRowIndex = lastRowIndex; 222 } 223 224 /** 225 * Gets the sortDescending attribute. 226 * @return Returns the sortDescending. 227 */ 228 public boolean isSortDescending() { 229 return sortDescending; 230 } 231 232 /** 233 * Sets the sortDescending attribute value. 234 * @param sortDescending The sortDescending to set. 235 */ 236 public void setSortDescending(boolean sortDescending) { 237 this.sortDescending = sortDescending; 238 } 239 240 /** 241 * @return the columnToSortName 242 */ 243 public String getColumnToSortName() { 244 return this.columnToSortName; 245 } 246 247 /** 248 * @param columnToSortName the columnToSortName to set 249 */ 250 public void setColumnToSortName(String columnToSortName) { 251 this.columnToSortName = columnToSortName; 252 } 253 254 /** 255 * @return the previouslySortedColumnName 256 */ 257 public String getPreviouslySortedColumnName() { 258 return this.previouslySortedColumnName; 259 } 260 261 /** 262 * @param previouslySortedColumnName the previouslySortedColumnName to set 263 */ 264 public void setPreviouslySortedColumnName(String previouslySortedColumnName) { 265 this.previouslySortedColumnName = previouslySortedColumnName; 266 } 267 268 269 /** 270 * Sets the paging form parameters to go to the first page of the list 271 * 272 * @param listSize size of table being rendered 273 * @param maxRowsPerPage 274 */ 275 public void jumpToFirstPage(int listSize, int maxRowsPerPage) { 276 jumpToPage(0, listSize, maxRowsPerPage); 277 } 278 279 /** 280 * Sets the paging form parameters to go to the last page of the list 281 * 282 * @param listSize size of table being rendered 283 * @param maxRowsPerPage 284 */ 285 public void jumpToLastPage(int listSize, int maxRowsPerPage) { 286 jumpToPage(TableRenderUtil.computeTotalNumberOfPages(listSize, maxRowsPerPage) - 1, listSize, maxRowsPerPage); 287 } 288 289 /** 290 * Sets the paging form parameters to go to the specified page of the list 291 * 292 * @param pageNumber first page is 0, must be non-negative. If the list is not large enough to have the page specified, then 293 * this method will be equivalent to calling jumpToLastPage. 294 * @param listSize size of table being rendered 295 * @param maxRowsPerPage 296 * 297 * @see KualiTableRenderFormMetadata#jumpToLastPage(int, int) 298 */ 299 public void jumpToPage(int pageNumber, int listSize, int maxRowsPerPage) { 300 int totalPages = TableRenderUtil.computeTotalNumberOfPages(listSize, maxRowsPerPage); 301 setTotalNumberOfPages(totalPages); 302 if (pageNumber >= totalPages) { 303 pageNumber = totalPages - 1; 304 } 305 setViewedPageNumber(pageNumber); 306 setFirstRowIndex(TableRenderUtil.computeStartIndexForPage(pageNumber, listSize, maxRowsPerPage)); 307 setLastRowIndex(TableRenderUtil.computeLastIndexForPage(pageNumber, listSize, maxRowsPerPage)); 308 } 309 310 /** 311 * Sorts a list on the form according to the form metadata (sortColumName, previouslySortedColumnName) 312 * 313 * @param memberTableMetadata 314 * @param items 315 * @param maxRowsPerPage 316 * @throws org.kuali.rice.kew.api.exception.WorkflowException 317 */ 318 public void sort(List<?> items, int maxRowsPerPage) { 319 320 // Don't bother to sort null, empty or singleton lists 321 if (items == null || items.size() <= 1) 322 return; 323 324 String columnToSortOn = getColumnToSortName(); 325 326 // Don't bother to sort if no column to sort on is provided 327 if (StringUtils.isEmpty(columnToSortOn)) 328 return; 329 330 String previouslySortedColumnName = getPreviouslySortedColumnName(); 331 332 // We know members isn't null or empty from the check above 333 Object firstItem = items.get(0); 334 // Need to decide if the comparator is for a bean property or a mapped key on the qualififer attribute set 335 Comparator comparator = null; 336 Comparator subComparator = new Comparator<Object>() { 337 338 public int compare(Object o1, Object o2) { 339 if (o1 == null) 340 return -1; 341 if (o2 == null) 342 return 1; 343 344 if (o1 instanceof java.util.Date && o2 instanceof java.util.Date) { 345 Date d1 = (Date)o1; 346 Date d2 = (Date)o2; 347 return d1.compareTo(d2); 348 } 349 350 String s1 = o1.toString(); 351 String s2 = o2.toString(); 352 int n1=s1.length(), n2=s2.length(); 353 for (int i1=0, i2=0; i1<n1 && i2<n2; i1++, i2++) { 354 char c1 = s1.charAt(i1); 355 char c2 = s2.charAt(i2); 356 if (c1 != c2) { 357 c1 = Character.toUpperCase(c1); 358 c2 = Character.toUpperCase(c2); 359 if (c1 != c2) { 360 c1 = Character.toLowerCase(c1); 361 c2 = Character.toLowerCase(c2); 362 if (c1 != c2) { 363 return c1 - c2; 364 } 365 } 366 } 367 } 368 return n1 - n2; 369 } 370 }; 371 // 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, 372 // otherwise it's a mapped property -- syntax for BeanComparator is "name" and "name(key)", respectively 373 if (PropertyUtils.isReadable(firstItem, columnToSortOn)) 374 comparator = new BeanComparator(columnToSortOn, subComparator); 375 else 376 comparator = new BeanComparator(new StringBuilder().append("qualifierAsMap(").append(columnToSortOn).append(")").toString(), subComparator); 377 378 379 // 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 380 if (!StringUtils.isEmpty(columnToSortOn) && !StringUtils.isEmpty(previouslySortedColumnName) && columnToSortOn.equals(previouslySortedColumnName)) { 381 // we're already sorted on the same column that the user clicked on, so we reverse the list 382 if (isSortDescending()) 383 comparator = Collections.reverseOrder(comparator); 384 385 setSortDescending(!isSortDescending()); 386 } else { 387 // Track which column we're currently sorting, so that the above logic will work on the next sort 388 setPreviouslySortedColumnName(columnToSortOn); 389 setSortDescending(true); 390 } 391 392 //if the user is just going between pages no need to sort 393 if (getSwitchToPageNumber() == getViewedPageNumber()) { 394 Collections.sort(items, comparator); 395 } 396 397 jumpToFirstPage(items.size(), maxRowsPerPage); 398 } 399 400}