001 /*
002 * Apache License
003 * Version 2.0, January 2004
004 * http://www.apache.org/licenses/
005 *
006 * Copyright 2008-2010 by chenillekit.org
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 */
014
015 package org.chenillekit.tapestry.core.components;
016
017 import org.apache.tapestry5.BindingConstants;
018 import org.apache.tapestry5.ComponentResources;
019 import org.apache.tapestry5.EventConstants;
020 import org.apache.tapestry5.Link;
021 import org.apache.tapestry5.MarkupWriter;
022 import org.apache.tapestry5.annotations.Import;
023 import org.apache.tapestry5.annotations.Parameter;
024 import org.apache.tapestry5.ioc.Messages;
025 import org.apache.tapestry5.ioc.annotations.Inject;
026 import org.apache.tapestry5.runtime.Component;
027
028 import org.chenillekit.tapestry.core.internal.PagedSource;
029
030 /**
031 * Blatant copy and paste of {@link org.apache.tapestry5.corelib.components.GridPager} with modifications.
032 *
033 * @version $Id: Pager.java 668 2010-06-18 16:07:35Z homburgs $
034 */
035 @Import(stylesheet = {"Pager.css"})
036 public class Pager
037 {
038 /**
039 * The source of the data displayed by the PagedList (this is used to
040 * determine
041 * {@link PagedSource#getTotalRowCount() how many rows are available},
042 * which in turn determines the page count).
043 */
044 @Parameter
045 private PagedSource<?> source;
046
047 /**
048 * The number of rows displayed per page.
049 */
050 @Parameter
051 private int rowsPerPage;
052
053 /**
054 * The current page number (indexed from 1).
055 */
056 @Parameter
057 private int currentPage;
058
059 /**
060 * If this pager is in a custom position it must provide the id of the
061 * PagedLoop it is associated with.
062 */
063 @Parameter(defaultPrefix = BindingConstants.LITERAL, name = "for")
064 private String forId;
065
066 /**
067 * Number of pages before and after the current page in the range. The pager
068 * always displays links for 2 * range + 1 pages, unless that's more than
069 * the total number of available pages.
070 */
071 @Parameter("5")
072 private int range;
073
074 private int lastIndex;
075
076 private int maxPages;
077
078 @Inject
079 private ComponentResources resources;
080
081 @Inject
082 private Messages messages;
083
084 private Component pagedLoopComponent;
085
086 private PagedLoop pagedLoop;
087
088 void setupRender()
089 {
090 if (forId != null)
091 {
092 source = getPagedLoop().getPagedSource();
093 rowsPerPage = getPagedLoop().getRowsPerPage();
094 currentPage = getPagedLoop().getCurrentPage();
095 }
096 }
097
098 void beginRender(MarkupWriter writer)
099 {
100
101 int availableRows = source.getTotalRowCount();
102
103 maxPages = ((availableRows - 1) / rowsPerPage) + 1;
104
105 if (maxPages < 2)
106 return;
107
108 writer.element(resources.getContainer().getComponentResources().getElementName(), "class", "ck_paged_loop_pager");
109 writer.element("div", "class", "ck_paged_loop_pager");
110
111 lastIndex = 0;
112
113 for (int i = 1; i <= 2; i++)
114 writePageLink(writer, i);
115
116 int low = currentPage - range;
117 int high = currentPage + range;
118
119 if (low < 1)
120 {
121 low = 1;
122 high = 2 * range + 1;
123 }
124 else
125 {
126 if (high > maxPages)
127 {
128 high = maxPages;
129 low = high - 2 * range;
130 }
131 }
132
133 for (int i = low; i <= high; i++)
134 writePageLink(writer, i);
135
136 for (int i = maxPages - 1; i <= maxPages; i++)
137 writePageLink(writer, i);
138
139 writer.end();
140 writer.end();
141 }
142
143 void onAction(int newPage)
144 {
145 // TODO: Validate newPage in range
146 currentPage = newPage;
147 if (forId != null)
148 {
149 getPagedLoopComponent().getComponentResources().triggerEvent(
150 EventConstants.ACTION, new Integer[]{newPage},
151 null);
152 }
153 }
154
155 private Component getPagedLoopComponent()
156 {
157 if (forId != null && pagedLoopComponent == null)
158 pagedLoopComponent = resources.getPage().getComponentResources().getEmbeddedComponent(forId);
159
160 return pagedLoopComponent;
161 }
162
163 private PagedLoop getPagedLoop()
164 {
165 if (forId != null && pagedLoop == null)
166 pagedLoop = (PagedLoop) getPagedLoopComponent();
167
168 return pagedLoop;
169 }
170
171 private void writePageLink(MarkupWriter writer, int pageIndex)
172 {
173 if (pageIndex < 1 || pageIndex > maxPages)
174 return;
175
176 if (pageIndex <= lastIndex)
177 return;
178
179 if (pageIndex != lastIndex + 1)
180 writer.write(" ... "); // … is ellipsis
181
182 lastIndex = pageIndex;
183
184 if (pageIndex == currentPage)
185 {
186 writer.element("span", "class", "ck_paged_loop_current");
187 writer.write(Integer.toString(pageIndex));
188 writer.end();
189 return;
190 }
191
192 Link link = resources.createEventLink(EventConstants.ACTION, pageIndex);
193
194 writer.element("a", "href", link, "title", messages.format("goto-page", pageIndex));
195
196 writer.write(Integer.toString(pageIndex));
197 writer.end();
198 }
199 }