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(" ... "); // &#8230; 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    }