001    /* 
002        Licensed to the Apache Software Foundation (ASF) under one
003        or more contributor license agreements.  See the NOTICE file
004        distributed with this work for additional information
005        regarding copyright ownership.  The ASF licenses this file
006        to you under the Apache License, Version 2.0 (the
007        "License"); you may not use this file except in compliance
008        with the License.  You may obtain a copy of the License at
009    
010           http://www.apache.org/licenses/LICENSE-2.0
011    
012        Unless required by applicable law or agreed to in writing,
013        software distributed under the License is distributed on an
014        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015        KIND, either express or implied.  See the License for the
016        specific language governing permissions and limitations
017        under the License.  
018     */
019    package org.apache.wiki.tags;
020    
021    import java.io.IOException;
022    
023    import javax.servlet.jsp.jstl.fmt.LocaleSupport;
024    
025    import org.apache.wiki.util.TextUtil;
026    
027    
028    /**
029     *  Calculate pagination string. Used for page-info and search results
030     *
031     *  <P><B>Attributes</B></P>
032     *  <UL>
033     *    <LI> start - start item of the page to be highlighted
034     *    <LI> total - total number of items
035     *    <LI> pagesize - total number of items per page
036     *    <LI> maxlinks - number of page links to be generated
037     *    <LI> fmtkey - pagination prefix of the i18n resource keys. Following keys are used:
038     *    <br>fmtkey="info.pagination"
039     *      <UL>
040     *        <LI> info.pagination.first=<span class="first">First</span>
041     *        <LI> info.pagination.last=<span class="last">Last</span>
042     *        <LI> info.pagination.previous=<span class="prev">Previous</span>
043     *        <LI> info.pagination.next=<span class="next">Next</span>
044     *        <LI> info.pagination.all=<span class="all">all</span>
045     *        <LI> info.pagination.total=&nbsp;(Total items: {0} ) 
046     *        <LI> info.pagination.show.title=Show items from {0} to {1}
047     *        <LI> info.pagination.showall.title=Show all items
048     *      </UL>
049     *  </UL>
050     *  <P>Following optional attributes can be parameterized with '%s' (item count)</P>
051     *  <UL>
052     *    <LI> href - href of each page link. (optional)
053     *    <LI> onclick - onclick of each page link. (optional)
054     *  </UL>
055     *
056     *  @since 2.5.109
057     */
058    public class SetPaginationTag
059        extends WikiTagBase
060    {
061        private static final long serialVersionUID = 0L;
062        private static final int ALLITEMS = -1;
063    
064        private int m_start;
065        private int m_total;
066        private int m_pagesize;
067        private int m_maxlinks;
068        private String m_fmtkey;
069        private String m_href;
070        private String m_onclick;
071    
072        public void initTag()
073        {
074            super.initTag();
075            m_start = 0;
076            m_total = 0;
077            m_pagesize = 20;
078            m_maxlinks = 9;
079            m_fmtkey = null;
080            m_href = null;
081            m_onclick = null;
082        }
083    
084        public void setStart(int arg)
085        {
086            m_start = arg;
087        }
088    
089        public void setTotal(int arg)
090        {
091            m_total = arg;
092        }
093    
094        public void setPagesize(int arg)
095        {
096            m_pagesize = arg;
097        }
098    
099        public void setMaxlinks(int arg)
100        {
101            m_maxlinks = arg;
102            if( m_maxlinks % 2 == 0 ) m_maxlinks--; /* must be odd */
103        }
104    
105        public void setFmtkey(String arg)
106        {
107            m_fmtkey = arg;
108        }
109    
110        public void setHref(String arg)
111        {
112            m_href = arg;
113        }
114    
115        public void setOnclick(String arg)
116        {
117            m_onclick = arg;
118        }
119    
120    
121        // 0 20 40 60
122        // 0 20 40 60 80 next last
123        // first previous 20 40 *60* 80 100 next last
124        // fist previous 40 60 80 100 120
125        public int doWikiStartTag()
126            throws IOException
127        {
128            if( m_total <= m_pagesize ) return SKIP_BODY;
129    
130            StringBuffer pagination = new StringBuffer();
131    
132            if( m_start > m_total ) m_start = m_total;
133            if( m_start < ALLITEMS ) m_start = 0;
134    
135            int maxs = m_pagesize * m_maxlinks;
136            int mids = m_pagesize * ( m_maxlinks / 2 );
137    
138            pagination.append( "<div class='pagination'>");
139    
140            pagination.append( LocaleSupport.getLocalizedMessage(pageContext, m_fmtkey )+ " " );
141    
142            int cursor = 0;
143            int cursormax = m_total;
144    
145            if( m_total > maxs )   //need to calculate real window ends
146            {
147              if( m_start > mids ) cursor = m_start - mids;
148              if( (cursor + maxs) > m_total )
149                cursor = ( ( 1 + m_total/m_pagesize ) * m_pagesize ) - maxs ;
150    
151              cursormax = cursor + maxs;
152            }
153    
154    
155            if( ( m_start == ALLITEMS ) || (cursor > 0) )
156            {
157                appendLink ( pagination, 0, m_fmtkey + ".first" );
158            }
159    
160    
161            if( (m_start != ALLITEMS ) && (m_start-m_pagesize >= 0) )
162            {
163                appendLink( pagination, m_start-m_pagesize, m_fmtkey + ".previous" );
164            }
165    
166            if( m_start != ALLITEMS )
167            {
168              while( cursor < cursormax )
169              {
170                if( cursor == m_start )
171                {
172                  pagination.append( "<span class='cursor'>" );
173                  pagination.append( 1 + cursor/m_pagesize );
174                  pagination.append( "</span>" );
175                }
176                else
177                {
178                  appendLink( pagination, cursor, 1+cursor/m_pagesize );
179                }
180                cursor += m_pagesize;
181              }
182            }
183    
184    
185            if( (m_start != ALLITEMS ) && (m_start + m_pagesize < m_total) )
186            {
187                appendLink( pagination, m_start+m_pagesize, m_fmtkey + ".next" );
188    
189            if( (m_start == ALLITEMS ) || (cursormax < m_total) )
190              appendLink ( pagination, ( (m_total/m_pagesize) * m_pagesize ), m_fmtkey + ".last" );
191            }
192    
193            if( m_start == ALLITEMS )
194            {
195              pagination.append( "<span class='cursor'>" );
196              pagination.append( LocaleSupport.getLocalizedMessage(pageContext, m_fmtkey + ".all" ) );
197              pagination.append( "</span>&nbsp;&nbsp;" );
198            }
199            else
200            {
201              appendLink ( pagination, ALLITEMS, m_fmtkey + ".all" );
202            }
203    
204            //(Total items: " + m_total + ")" );
205            pagination.append( LocaleSupport.getLocalizedMessage(pageContext, m_fmtkey + ".total",
206                               new Object[]{ m_total } ) );
207    
208            pagination.append( "</div>" );
209    
210    
211            /* +++ processing done +++ */
212    
213            String p = pagination.toString();
214    
215            pageContext.getOut().println( p );
216    
217            pageContext.setAttribute( "pagination", p ); /* and cache for later use in page context */
218    
219            return SKIP_BODY;
220        }
221    
222    
223        /**
224         * Generate pagination links <a href='' title='' onclick=''>text</a>
225         * for pagination blocks starting a page.
226         * Uses m_href and m_onclick as attribute patterns
227         * '%s' in the patterns are replaced with page offset
228         *
229         * @param sb  : stringbuffer to write output to
230         * @param page : start of page block
231         * @param onclick : link text
232         *
233         **/
234        private void appendLink( StringBuffer sb, int page, String fmttextkey )
235        {
236            appendLink2( sb, page, LocaleSupport.getLocalizedMessage( pageContext, fmttextkey ) );
237        }
238        private void appendLink( StringBuffer sb, int page, int paginationblock )
239        {
240            appendLink2( sb, page, Integer.toString( paginationblock ) );
241        }
242        private void appendLink2( StringBuffer sb, int page, String text )
243        {
244            sb.append( "<a title=\"" );
245            if( page == ALLITEMS )
246            {
247                sb.append( LocaleSupport.getLocalizedMessage( pageContext, m_fmtkey + ".showall.title" ) );
248            }
249            else
250            {
251                sb.append( LocaleSupport.getLocalizedMessage( pageContext, m_fmtkey + ".show.title",
252                           new Object[]{ page + 1, page + m_pagesize } ) );
253            }
254            sb.append( "\" " );
255    
256            if( m_href != null )
257            {
258                sb.append( "href=\"" );
259                sb.append( TextUtil.replaceString( m_href, "%s", Integer.toString( page ) ) );
260                sb.append( "\" " );
261            }
262    
263            if( m_onclick != null )
264            {
265                sb.append( "onclick=\"" );
266                sb.append( TextUtil.replaceString( m_onclick, "%s", Integer.toString( page ) ) );
267                sb.append( "\" " );
268            }
269    
270            sb.append( ">" );
271            sb.append( text );
272            sb.append( "</a>" );
273        }
274    
275    }