001    /*
002     * Copyright 2001,2004 The Apache Software Foundation.
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     */
016    
017    package org.apache.commons.scaffold.util;
018    
019    
020    import java.util.Map;
021    
022    import org.apache.commons.scaffold.text.ConvertUtils;
023    
024    
025    /**
026     * Scroller tracks the coordinates needed to manage
027     * flipping through a result list using
028     * LIMIT and OFFSET clauses (or the equivalent).
029     *
030     * Scrolls through entries using a range (10 to 20 of 50)
031     * but does not support paging per se goto page 3 (or entry 30)),
032     * though that would be an easy enhancement.
033     *
034     * @author James Klicman <james@jsptags.com>
035     * @author Ted Husted
036     * @author WXXI Public Broadcasting Council
037     * @author OK State DEQ
038     * @version $Revision: 155464 $ $Date: 2005-02-26 13:26:54 +0000 (Sat, 26 Feb 2005) $
039     */
040    public class Scroller {
041    
042    
043      public Scroller(int entries, int from, int limit, int count) {
044         calculate(entries,from,limit,count);
045      }
046    
047    
048      public Scroller() {
049      }
050    
051    
052      /**
053       * The maximum to return with a scrolling list.
054       */
055      public static final int SCROLL_ROWS = 20;
056    
057    
058    // ---------------------------------------------------------------- Properties
059    
060    
061      /**
062       * The default starting point [1].
063       * The value is for the convenience of SQL, which is one-based.
064       */
065      public static int FROM = 1;
066    
067    
068      /**
069       * The starting point for the current query [FROM].
070       */
071      protected int from = FROM;
072    
073    
074      /**
075       * Set from.
076       * @param from The new from value.
077       */
078      public void setFrom(int from) {
079        this.from = from;
080      }
081    
082    
083      /**
084       * Return from.
085       * @return The form value.
086       */
087      public int getFrom() {
088        return(this.from);
089      }
090    
091    
092      /**
093       * The ending point for the current query [1].
094       */
095      protected int thru = 1;
096    
097    
098      /**
099       * Set thru.
100       * @param thru The new thru value.
101       */
102      public void setThru(int thru) {
103        this.thru = thru;
104      }
105    
106    
107      /**
108       * Return thru.
109       * @return The form value.
110       */
111      public int getThru() {
112        return(this.thru);
113      }
114    
115    
116      /**
117       * The starting point to use for a "backward" query.
118       */
119      protected int prev = 1;
120    
121    
122      /**
123       * Set prev.
124       * @param prev The new prev value.
125       */
126      public void setPrev(int prev) {
127        this.prev = prev;
128      }
129    
130    
131      /**
132       * Return prev.
133       * @return The prev value.
134       */
135      public int getPrev() {
136        return(this.prev);
137      }
138    
139    
140      /**
141       * The starting point to use with a "forward" query.
142       * This should always be a valid value.
143       *
144       */
145      protected int next = 1;
146    
147    
148      /**
149       * Set next.
150       * @param next The new next value.
151       */
152      public void setNext(int next) {
153        this.next = next;
154      }
155    
156    
157      /**
158       * Return next.
159       * @return The next value.
160       */
161      public int getNext() {
162        return(this.next);
163      }
164    
165    
166      /**
167       * The maximum number of entries to fetch at a time
168       * [Integer.MAX_VALUE].
169       */
170      protected int limit = Integer.MAX_VALUE;
171    
172    
173      /**
174       * Set limit.
175       * @param limit The new limit value.
176       */
177      public void setLimit(int limit) {
178        this.limit = limit;
179      }
180    
181    
182      /**
183       * Return limit.
184       * @return The limit value.
185       */
186      public int getLimit() {
187        return(this.limit);
188      }
189    
190    
191      /**
192       * The actual number of entries to fetch (eg length or limit).
193       */
194      protected int entries = 0;
195    
196    
197      /**
198       * Set entries
199       * @param entries The new entries value.
200       */
201      public void setEntries(int entries) {
202        this.entries = entries;
203      }
204    
205    
206      /**
207       * Return entries.
208       * @return The entries value.
209       */
210      public int getEntries() {
211        return(this.entries);
212      }
213    
214    
215      /**
216       * The maximum number of entries available  (the SQL count).
217       *
218       */
219      protected int count = 0;
220    
221    
222      /**
223       * Set count
224       * @param count The new count value.
225       */
226      public void setCount(int count) {
227        this.count = count;
228      }
229    
230    
231      /**
232       * Return count.
233       * @return The count value.
234       */
235      public int getCount() {
236        return(this.count);
237      }
238    
239    
240      /**
241       * Field for the parameters property [java.util.HashMap].
242       */
243      protected Map parameters = new java.util.HashMap();
244    
245    
246      /**
247       * Set parameters
248       * @param parameters The new parameters value.
249       */
250      public void setParameters(Map parameters) {
251        this.parameters = parameters;
252      }
253    
254    
255      /**
256       * Return parameters.
257       * @return The parameters value.
258       */
259      public Map getParameters() {
260        return(this.parameters);
261      }
262    
263    
264      /**
265       * Set a parameter
266       * @param key The parameter name
267       * @param value The parameter value
268       */
269      public void putParameter(String key, String value) {
270        getParameters().put(key,value);
271      }
272    
273    
274      /**
275       * Set a parameter
276       * @param key The parameter name
277       * @param value The parameter value
278       */
279      public boolean isParameters() {
280        return (!getParameters().isEmpty());
281      }
282    
283    
284      /**
285       * Return parameters as a query string for use with a URI.
286       * @return query string
287       */
288      public String getQueryString(String uri) {
289    
290          return ConvertUtils.addParams(uri,getParameters());
291    
292      }
293    
294    
295      /**
296       * Return parameters as a series of hidden HTML fields.
297       * @return parameters as a series of hidden HTML fields.
298       */
299      public String getHiddenFields() {
300    
301          return ConvertUtils.renderHiddenFields(getParameters());
302    
303      }
304    
305    
306    // ------------------------------------------------------------ Public Methods
307    
308    
309      /**
310       * The database offset for the current query [0].
311       *
312       * Convenience method to return one less than from
313       *
314       * @return The offset for this query
315       */
316      public int getOffset() {
317        int from = getFrom();
318        return(--from);
319      }
320    
321    
322      /**
323       * Return page number for given entry.
324       * @return The number of pages
325       */
326      public int getPage(int thru) {
327    
328        int limit = getLimit();
329    
330        if ((0==thru) || (0==limit)) return 1;
331    
332        double page = (thru / limit) + (thru % limit == 0 ? 0 : 1);
333    
334        return new Double(page).intValue();
335      }
336    
337    
338      /**
339       * Return current page number
340       * @return The number of pages
341       */
342      public int getPage() {
343    
344          return getPage(getThru());
345      }
346    
347    
348      /**
349       * Return number of pages.
350       * @return The number of pages
351       */
352      public int getPages() {
353    
354          return getPage(getCount());
355      }
356    
357    
358      /**
359       * Return first entry for given page.
360       * @return first entry for given page
361       */
362      public int getOffsetForPage(int page) {
363    
364          int limit = getLimit();
365    
366          return ((page*limit)-limit)+1;
367      }
368    
369    
370      /**
371       * Calculate the new property values
372       * using a bean that has already had count and limit set.
373       *
374       * @param from The first absolute row
375       */
376      public void calculate() {
377    
378         int from = getFrom();
379         int limit = getLimit();
380         int entries = getEntries();
381         int count = getCount();
382    
383         // Calculate "next" relative to starting point; or wrap to beginning.
384         int thru = (from + entries) - 1 ; if (thru < 1) thru = 1;
385    
386         // Calculate "previous" relative to starting point, but don't go negative
387         int prev = from - limit; if (prev < 1) prev = 1;
388    
389         // Calculate "next" relative to starting point; or wrap to beginning.
390         int next = from + entries; if (next > count) next = 1;
391    
392         setPrev(prev);
393         setNext(next);
394         setThru(thru);
395      }
396    
397    
398    
399      /**
400       * Calculate the new property values
401       * using a bean that has already had count and limit set.
402       *
403       * @param from The first absolute row
404       */
405      public void calculate(int entries) {
406    
407         setEntries(entries);
408         calculate();
409      }
410    
411    
412      /**
413       * Calculate the new property values.
414       *
415       * @param entries The number of matches in this set
416       * @param from The first absolute row in this set
417       * @param count How many rows in the complete set
418       * @param limit The maximum rows in a subset page
419       */
420      public void calculate(int entries, int from, int count, int limit) {
421    
422         if ((from<1) || (from>count)) from = 1;
423    
424         setLimit(limit);
425         setCount(count);
426         setFrom(from);
427         calculate(entries);
428      }
429    
430    } // end Scroller