1 /**
2 * Copyright 2005-2016 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.kns.util.TableRenderUtil;
22
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.Date;
26 import java.util.List;
27
28 /**
29 * This class holds the metadata necessary to render a table when displaytag is not being used.
30 *
31 * @deprecated KNS Struts deprecated, use KRAD and the Spring MVC framework.
32 */
33 @Deprecated
34 public class KualiTableRenderFormMetadata {
35 private int viewedPageNumber;
36 private int totalNumberOfPages;
37 private int firstRowIndex;
38 private int lastRowIndex;
39 private int switchToPageNumber;
40
41 /**
42 * The number of rows that match the query criteria
43 */
44 private int resultsActualSize;
45
46 /**
47 * The number of rows that match the query criteria or
48 * the max results limit size (if applicable), whichever is less
49 */
50 private int resultsLimitedSize;
51
52 /**
53 * when the looked results screen was rendered, the index of the column that the results were sorted on. -1 for unknown, index numbers
54 * starting at 0
55 */
56 private int previouslySortedColumnIndex;
57
58 /**
59 * Comment for <code>columnToSortIndex</code>
60 */
61 private int columnToSortIndex;
62
63 /**
64 * 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
65 */
66 private String columnToSortName;
67
68 /**
69 * When the screen was last rendered, the column name on which it was previously sorted -- this is important for toggling between ascending and descending
70 * sort orders
71 */
72 private String previouslySortedColumnName;
73
74 private boolean sortDescending;
75
76 public KualiTableRenderFormMetadata() {
77 sortDescending = false;
78 }
79
80 /**
81 * Gets the columnToSortIndex attribute.
82 * @return Returns the columnToSortIndex.
83 */
84 public int getColumnToSortIndex() {
85 return columnToSortIndex;
86 }
87
88 /**
89 * Sets the columnToSortIndex attribute value.
90 * @param columnToSortIndex The columnToSortIndex to set.
91 */
92 public void setColumnToSortIndex(int columnToSortIndex) {
93 this.columnToSortIndex = columnToSortIndex;
94 }
95
96 /**
97 * Gets the previouslySortedColumnIndex attribute.
98 * @return Returns the previouslySortedColumnIndex.
99 */
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 }