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