001: /**
002: * Copyright 2006 Webmedia Group Ltd.
003: *
004: * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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: **/package org.araneaframework.uilib.list;
016:
017: import java.io.Serializable;
018: import org.araneaframework.uilib.ConfigurationContext;
019: import org.araneaframework.uilib.util.ConfigurationContextUtil;
020:
021: /**
022: * This class incapsulates all the information and behavior connected with the moving through the list pages. That is
023: * it translates the moves through the pages and other user activities (like expanding the list) to the exact indexes
024: * in of list item range that is to be asked from the database. In addition it provides the renderer with enough
025: * information to show the list "sequence", e.g. the breaking of list into pages and blocks.
026: *
027: * @author <a href="mailto:ekabanov@webmedia.ee">Jevgeni Kabanov </a>
028: *
029: */
030: public class SequenceHelper implements Serializable {
031:
032: /**
033: * Default value of how many pages combine into one block for quick navigation.
034: */
035: public static final long DEFAULT_PAGES_ON_BLOCK = 10;
036:
037: /**
038: * Default value of how many items of the list will be displayed on one page.
039: */
040: public static final long DEFAULT_ITEMS_ON_PAGE = 10;
041:
042: /**
043: * Default value of how many items of the list will be displayed on one page.
044: */
045: public static final long FULL_ITEMS_ON_PAGE = Long.MAX_VALUE;
046:
047: /**
048: * Whether to preserve the list starting row when switching to showing full list and back.
049: */
050: public static final boolean DEFAULT_PRESERVE_STARTING_ROW = false;
051:
052: protected ConfigurationContext configuration;
053:
054: //Whether user has expanded the whole list.
055: private boolean allItemsShown = false;
056:
057: private long currentPage = 0;
058: private long totalItemCount;
059: private long itemsOnPage;
060: private long pagesOnBlock;
061:
062: private long firstItemIndex = 0;
063:
064: private long fullItemsOnPage = FULL_ITEMS_ON_PAGE;
065: private long defaultItemsOnPage = DEFAULT_ITEMS_ON_PAGE;
066: private long defaultPagesOnBlock = DEFAULT_PAGES_ON_BLOCK;
067: private boolean preserveStartingRow = DEFAULT_PRESERVE_STARTING_ROW;
068:
069: private long oldItemsOnPage;
070: private long oldFirstItemIndex;
071:
072: private boolean changed = true;
073:
074: /**
075: * Creates the class, setting all parameters to defaults.
076: */
077: public SequenceHelper(ConfigurationContext configuration) {
078: this .configuration = configuration;
079:
080: Long confDefaultItemsOnPage = ConfigurationContextUtil
081: .getDefaultListItemsOnPage(configuration);
082:
083: if (confDefaultItemsOnPage != null)
084: defaultItemsOnPage = confDefaultItemsOnPage.longValue();
085:
086: Long confFullItemsOnPage = (Long) configuration
087: .getEntry(ConfigurationContext.FULL_LIST_ITEMS_ON_PAGE);
088: if (confFullItemsOnPage != null)
089: fullItemsOnPage = confFullItemsOnPage.longValue();
090:
091: Long confDefaultPagesOnBlock = (Long) configuration
092: .getEntry(ConfigurationContext.DEFAULT_LIST_PAGES_ON_BLOCK);
093: if (confDefaultPagesOnBlock != null)
094: defaultPagesOnBlock = confDefaultPagesOnBlock.longValue();
095:
096: Boolean confPreserveStartingRow = (Boolean) configuration
097: .getEntry(ConfigurationContext.LIST_PRESERVE_STARTING_ROW);
098: if (confPreserveStartingRow != null)
099: preserveStartingRow = confPreserveStartingRow
100: .booleanValue();
101:
102: setItemsOnPage(defaultItemsOnPage);
103: setPagesOnBlock(defaultPagesOnBlock);
104:
105: totalItemCount = Long.MAX_VALUE;
106: }
107:
108: //*******************************************************************
109: // PUBLIC METHODS
110: //*******************************************************************
111:
112: /**
113: * Sets how many items will be displayed on one page.
114: */
115: public void setItemsOnPage(long itemsOnPage) {
116: this .itemsOnPage = itemsOnPage;
117: fireChange();
118: }
119:
120: /**
121: * Returns how many items will be displayed on one page.
122: */
123: public long getItemsOnPage() {
124: return this .itemsOnPage;
125: }
126:
127: /**
128: * Sets size of the block.
129: *
130: * @param pagesOnBlock
131: * number of pages combined into one block.
132: */
133: public void setPagesOnBlock(long pagesOnBlock) {
134: this .pagesOnBlock = pagesOnBlock;
135: fireChange();
136: }
137:
138: /**
139: * Sets the page which will be displayed. Page index is 0-based.
140: *
141: * @param currentPage
142: * index of the page.
143: */
144: public void setCurrentPage(long currentPage) {
145: if (currentPage < 0)
146: this .currentPage = 0;
147: else if (getPageCount() > 0 && currentPage >= getPageCount())
148: this .currentPage = getPageCount() - 1;
149: else
150: this .currentPage = currentPage;
151:
152: firstItemIndex = this .currentPage * itemsOnPage;
153:
154: fireChange();
155: }
156:
157: /**
158: * Sets how many items are there in the list.
159: *
160: * @param totalItemCount
161: * size of the list.
162: */
163: public void setTotalItemCount(long totalItemCount) {
164: this .totalItemCount = totalItemCount;
165: }
166:
167: /**
168: * Gets first item to be displayed on the current page.
169: *
170: * @return index of the first element from the list to be displayed.
171: */
172: public long getCurrentPageFirstItemIndex() {
173: return firstItemIndex;
174: }
175:
176: /**
177: * Gets last item to be displayed on the current page.
178: *
179: * @return index of the last element from the list to be displayed.
180: */
181: public long getCurrentPageLastItemIndex() {
182: long result = firstItemIndex + itemsOnPage - 1;
183: if (result >= totalItemCount)
184: result = totalItemCount - 1;
185: return result;
186: }
187:
188: /**
189: * Alters indexes to change page to the next one.
190: */
191: public void goToNextPage() {
192: setCurrentPage(currentPage + 1);
193: }
194:
195: /**
196: * Alters indexes to change page to the pervious one.
197: */
198: public void goToPreviousPage() {
199: setCurrentPage(currentPage - 1);
200: }
201:
202: /**
203: * Alters indexes to change block to the next one.
204: */
205: public void goToNextBlock() {
206: setCurrentPage(currentPage + pagesOnBlock);
207: }
208:
209: /**
210: * Alters indexes to change block to the previous one.
211: */
212: public void goToPreviousBlock() {
213: setCurrentPage(currentPage - pagesOnBlock);
214: }
215:
216: /**
217: * Alters indexes to change page to the first one. Page index is 0-based.
218: */
219: public void goToFirstPage() {
220: setCurrentPage(0);
221: }
222:
223: /**
224: * Alters indexes to change page to the last one.
225: */
226: public void goToLastPage() {
227: setCurrentPage(getPageCount() - 1);
228: }
229:
230: /**
231: * Alters indexes to change page.
232: *
233: * @param page
234: * 0-based index of the page to shift to.
235: */
236: public void goToPage(long page) {
237: setCurrentPage(page);
238: }
239:
240: public void validateSequence() {
241: if (currentPage >= getPageCount())
242: goToLastPage();
243: }
244:
245: /**
246: * Expands the list showing all items.
247: */
248: public void showFullPages() {
249: oldItemsOnPage = getItemsOnPage();
250: oldFirstItemIndex = firstItemIndex;
251:
252: setItemsOnPage(fullItemsOnPage);
253: setCurrentPage((long) Math.ceil((float) firstItemIndex
254: / (float) fullItemsOnPage));
255:
256: setAllItemsShown(true);
257:
258: if (preserveStartingRow)
259: firstItemIndex = oldFirstItemIndex;
260: }
261:
262: /**
263: * Collapses the list, showing only the current page.
264: */
265: public void showDefaultPages() {
266: long curFirstItemIndex = preserveStartingRow ? firstItemIndex
267: : oldFirstItemIndex;
268:
269: setItemsOnPage(oldItemsOnPage);
270: setCurrentPage((long) Math.ceil((float) curFirstItemIndex
271: / (float) itemsOnPage));
272:
273: setAllItemsShown(false);
274:
275: firstItemIndex = curFirstItemIndex;
276: }
277:
278: //*******************************************************************
279: // PROTECTED METHODS
280: //*******************************************************************
281:
282: protected void setAllItemsShown(boolean allItemsShown) {
283: this .allItemsShown = allItemsShown;
284: fireChange();
285: }
286:
287: /**
288: * @since 1.1
289: */
290: protected boolean getAllItemsShown() {
291: return this .allItemsShown;
292: }
293:
294: /**
295: * Gets how many pages are there in the list.
296: *
297: * @return number of pages.
298: */
299: protected long getPageCount() {
300: return (long) Math.ceil((double) this .totalItemCount
301: / (double) this .itemsOnPage);
302: }
303:
304: /**
305: * Gets the first page of the current block. Page index is 0-based.
306: *
307: * @return index of the page.
308: */
309: protected long getBlockFirstPage() {
310: long start = 0;
311: long end = 0;
312:
313: long tempPagesOnBlock = pagesOnBlock;
314:
315: if (tempPagesOnBlock > getPageCount()) {
316: tempPagesOnBlock = getPageCount();
317: }
318: long toStartCnt = tempPagesOnBlock / 2;
319: long toEndCnt = tempPagesOnBlock - 1 - toStartCnt;
320:
321: start = currentPage - toStartCnt;
322: end = currentPage + toEndCnt;
323: if (start < 0) {
324: end += (0 - start);
325: start = 0;
326: }
327: if (end >= getPageCount()) {
328: start -= end - getPageCount() + 1;
329: end = getPageCount() - 1;
330: }
331:
332: return start;
333: }
334:
335: /**
336: * Gets the last page of the current block. Page index is 0-based.
337: *
338: * @return index of the page.
339: */
340: protected long getBlockLastPage() {
341: long start = 0;
342: long end = 0;
343:
344: long tempPagesOnBlock = pagesOnBlock;
345:
346: if (tempPagesOnBlock > getPageCount()) {
347: tempPagesOnBlock = getPageCount();
348: }
349: long toStartCnt = tempPagesOnBlock / 2;
350: long toEndCnt = tempPagesOnBlock - 1 - toStartCnt;
351:
352: start = currentPage - toStartCnt;
353: end = currentPage + toEndCnt;
354: if (start <= 0) {
355: end += (0 - start);
356: start = 0;
357: }
358: if (end >= getPageCount()) {
359: start -= end - getPageCount() + 1;
360: end = getPageCount() - 1;
361: }
362:
363: return end;
364: }
365:
366: /**
367: * Returns whether the basic configuration that specifies which items are
368: * shown has changed since last call to this {@link SequenceHelper}'s {@link SequenceHelper#checkChanged()}
369: * method.
370: *
371: * @since 1.1
372: */
373: public boolean checkChanged() {
374: boolean result = changed;
375: changed = false;
376: return result;
377: }
378:
379: //*******************************************************************
380: // VIEW MODEL
381: //*******************************************************************
382:
383: /**
384: * Returns view model.
385: *
386: * @return view model.
387: */
388: public ViewModel getViewModel() {
389: return new ViewModel();
390: }
391:
392: /**
393: * View Model.
394: *
395: * @author <a href="mailto:ekabanov@webmedia.ee">Jevgeni Kabanov </a>
396: */
397: public class ViewModel implements Serializable {
398: private Long firstPage;
399: private Long lastPage;
400: private Long blockFirstPage;
401: private Long blockLastPage;
402: private Long currentPage;
403: private Long totalItemCount;
404: private Boolean allItemsShown;
405: private Long pageFirstItem;
406: private Long pageLastItem;
407: private Long itemsOnPage;
408:
409: /**
410: * Takes a snapshot of outer class state.
411: */
412: protected ViewModel() {
413: this .firstPage = new Long(0);
414: this .lastPage = new Long(
415: SequenceHelper.this .getPageCount() - 1);
416:
417: this .blockFirstPage = new Long(SequenceHelper.this
418: .getBlockFirstPage());
419: this .blockLastPage = new Long(SequenceHelper.this
420: .getBlockLastPage());
421:
422: this .currentPage = new Long(SequenceHelper.this .currentPage);
423: this .totalItemCount = new Long(
424: SequenceHelper.this .totalItemCount);
425:
426: this .allItemsShown = SequenceHelper.this .allItemsShown ? Boolean.TRUE
427: : Boolean.FALSE;
428:
429: this .pageFirstItem = new Long(SequenceHelper.this
430: .getCurrentPageFirstItemIndex() + 1);
431: this .pageLastItem = new Long(SequenceHelper.this
432: .getCurrentPageLastItemIndex() + 1);
433:
434: this .itemsOnPage = new Long(SequenceHelper.this .itemsOnPage);
435: }
436:
437: /**
438: * @return Returns the allItemsShown.
439: */
440: public Boolean getAllItemsShown() {
441: return allItemsShown;
442: }
443:
444: /**
445: * @return Returns the blockFirstPage.
446: */
447: public Long getBlockFirstPage() {
448: return blockFirstPage;
449: }
450:
451: /**
452: * @return Returns the blockLastPage.
453: */
454: public Long getBlockLastPage() {
455: return blockLastPage;
456: }
457:
458: /**
459: * @return Returns the currentPage.
460: */
461: public Long getCurrentPage() {
462: return currentPage;
463: }
464:
465: /**
466: * @return Returns the firstPage.
467: */
468: public Long getFirstPage() {
469: return firstPage;
470: }
471:
472: /**
473: * @return Returns the lastPage.
474: */
475: public Long getLastPage() {
476: return lastPage;
477: }
478:
479: /**
480: * @return Returns the pageFirstItem.
481: */
482: public Long getPageFirstItem() {
483: return pageFirstItem;
484: }
485:
486: /**
487: * @return Returns the pageLastItem.
488: */
489: public Long getPageLastItem() {
490: return pageLastItem;
491: }
492:
493: /**
494: * @return Returns the totalItemCount.
495: */
496: public Long getTotalItemCount() {
497: return totalItemCount;
498: }
499:
500: /**
501: * @return Returns the itemsOnPage.
502: */
503: public Long getItemsOnPage() {
504: return itemsOnPage;
505: }
506: }
507:
508: /**
509: * @since 1.1
510: */
511: protected void fireChange() {
512: changed = true;
513: }
514: }
|