• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / displaytag / 1753

12 Feb 2026 03:17AM UTC coverage: 77.321% (-0.01%) from 77.334%
1753

push

github

web-flow
Merge pull request #1102 from hazendaz/renovate/javax-support-logback-monorepo

Update dependency ch.qos.logback:logback-classic to v1.5.29 (javax-support)

1438 of 2003 branches covered (71.79%)

Branch coverage included in aggregate %.

4034 of 5074 relevant lines covered (79.5%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.62
/displaytag/src/main/java/org/displaytag/pagination/SmartListHelper.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2002-2026 Fabrizio Giustina, the Displaytag team
6
 */
7
package org.displaytag.pagination;
8

9
import java.text.MessageFormat;
10
import java.util.List;
11

12
import org.apache.commons.lang3.builder.ToStringBuilder;
13
import org.apache.commons.lang3.builder.ToStringStyle;
14
import org.displaytag.Messages;
15
import org.displaytag.model.Row;
16
import org.displaytag.properties.TableProperties;
17
import org.displaytag.util.Href;
18
import org.slf4j.Logger;
19
import org.slf4j.LoggerFactory;
20

21
/**
22
 * Utility class that chops up a List of objects into small bite size pieces that are more suitable for display.
23
 * <p>
24
 * This class is a stripped down version of the WebListHelper from Tim Dawson (tdawson@is.com)
25
 */
26
public class SmartListHelper {
27

28
    /**
29
     * logger.
30
     */
31
    private static Logger log = LoggerFactory.getLogger(SmartListHelper.class);
1✔
32

33
    /**
34
     * full list.
35
     */
36
    private List<Row> fullList;
37

38
    /**
39
     * sixe of the full list.
40
     */
41
    private int fullListSize;
42

43
    /**
44
     * number of items in a page.
45
     */
46
    private int pageSize;
47

48
    /**
49
     * number of pages.
50
     */
51
    private int pageCount;
52

53
    /** the list we hold is only part of the full dataset. */
54
    private boolean partialList;
55

56
    /**
57
     * index of current page.
58
     */
59
    private int currentPage;
60

61
    /**
62
     * TableProperties.
63
     */
64
    private TableProperties properties;
65

66
    /**
67
     * Creates a SmarListHelper instance that will help you chop up a list into bite size pieces that are suitable for
68
     * display.
69
     *
70
     * @param list
71
     *            List
72
     * @param fullSize
73
     *            size of the full list
74
     * @param itemsInPage
75
     *            number of items in a page (int &gt; 0)
76
     * @param tableProperties
77
     *            TableProperties
78
     * @param partialList
79
     *            the partial list
80
     */
81
    public SmartListHelper(final List<Row> list, final int fullSize, final int itemsInPage,
82
            final TableProperties tableProperties, final boolean partialList) {
1✔
83
        if (SmartListHelper.log.isDebugEnabled()) {
1!
84
            SmartListHelper.log.debug(Messages.getString("SmartListHelper.debug.instantiated", //$NON-NLS-1$
×
85
                    new Object[] { Integer.valueOf(list.size()), Integer.valueOf(itemsInPage),
×
86
                            Integer.valueOf(fullSize) }));
×
87
        }
88

89
        this.properties = tableProperties;
1✔
90
        this.pageSize = itemsInPage;
1✔
91
        this.fullList = list;
1✔
92
        this.fullListSize = fullSize;
1✔
93
        this.pageCount = this.computedPageCount();
1✔
94
        this.currentPage = 1;
1✔
95
        this.partialList = partialList;
1✔
96
    }
1✔
97

98
    /**
99
     * Constructor that can be used by subclasses. Subclasses that use this constructor must also override all the
100
     * public methods, since this constructor does nothing.
101
     */
102
    protected SmartListHelper() {
1✔
103
    }
1✔
104

105
    /**
106
     * Returns the computed number of pages it would take to show all the elements in the list given the pageSize we are
107
     * working with.
108
     *
109
     * @return int computed number of pages
110
     */
111
    protected int computedPageCount() {
112
        final int size = this.fullListSize;
1✔
113
        final int div = size / this.pageSize;
1✔
114
        return size % this.pageSize == 0 ? div : div + 1;
1✔
115
    }
116

117
    /**
118
     * Returns the index into the master list of the first object that should appear on the current page that the user
119
     * is viewing.
120
     *
121
     * @return int index of the first object that should appear on the current page
122
     */
123
    public int getFirstIndexForCurrentPage() {
124
        return this.getFirstIndexForPage(this.currentPage);
1✔
125
    }
126

127
    /**
128
     * Returns the index into the master list of the last object that should appear on the current page that the user is
129
     * viewing.
130
     *
131
     * @return int
132
     */
133
    protected int getLastIndexForCurrentPage() {
134
        return this.getLastIndexForPage(this.currentPage);
1✔
135
    }
136

137
    /**
138
     * Returns the index into the master list of the first object that should appear on the given page.
139
     *
140
     * @param pageNumber
141
     *            page number
142
     *
143
     * @return int index of the first object that should appear on the given page
144
     */
145
    protected int getFirstIndexForPage(final int pageNumber) {
146
        final int retval = (pageNumber - 1) * this.pageSize;
1✔
147
        return retval >= 0 ? retval : 0;
1!
148
    }
149

150
    /**
151
     * Returns the index into the master list of the last object that should appear on the given page.
152
     *
153
     * @param pageNumber
154
     *            page number
155
     *
156
     * @return int index of the last object that should appear on the given page
157
     */
158
    protected int getLastIndexForPage(final int pageNumber) {
159

160
        final int firstIndex = this.getFirstIndexForPage(pageNumber);
1✔
161
        final int pageIndex = this.pageSize - 1;
1✔
162
        final int lastIndex = this.fullListSize - 1;
1✔
163

164
        return Math.min(firstIndex + pageIndex, lastIndex);
1✔
165
    }
166

167
    /**
168
     * Returns a subsection of the list that contains just the elements that are supposed to be shown on the current
169
     * page the user is viewing.
170
     *
171
     * @return List subsection of the list that contains the elements that are supposed to be shown on the current page
172
     */
173
    public List<Row> getListForCurrentPage() {
174
        return this.getListForPage(this.currentPage);
1✔
175
    }
176

177
    /**
178
     * Returns a subsection of the list that contains just the elements that are supposed to be shown on the given page.
179
     *
180
     * @param pageNumber
181
     *            page number
182
     *
183
     * @return List subsection of the list that contains just the elements that are supposed to be shown on the given
184
     *         page
185
     */
186
    protected List<Row> getListForPage(final int pageNumber) {
187
        if (SmartListHelper.log.isDebugEnabled()) {
1!
188
            SmartListHelper.log.debug(Messages.getString("SmartListHelper.debug.sublist", //$NON-NLS-1$
×
189
                    new Object[] { Integer.valueOf(pageNumber) }));
×
190
        }
191

192
        int firstIndex = this.getFirstIndexForPage(pageNumber);
1✔
193
        int lastIndex = this.getLastIndexForPage(pageNumber);
1✔
194

195
        if (this.partialList) {
1✔
196
            firstIndex = 0;
1✔
197
            // use the min of pageSize or list size on the off chance they gave us more data than pageSize allows
198
            lastIndex = Math.min(this.pageSize - 1, this.fullList.size() - 1);
1✔
199
        }
200

201
        return this.fullList.subList(firstIndex, lastIndex + 1);
1✔
202
    }
203

204
    /**
205
     * Set's the page number that the user is viewing.
206
     *
207
     * @param pageNumber
208
     *            page number
209
     */
210
    public void setCurrentPage(final int pageNumber) {
211
        if (SmartListHelper.log.isDebugEnabled()) {
1!
212
            SmartListHelper.log.debug(Messages.getString("SmartListHelper.debug.currentpage", //$NON-NLS-1$
×
213
                    new Object[] { Integer.valueOf(pageNumber), Integer.valueOf(this.pageCount) }));
×
214
        }
215

216
        if (pageNumber < 1) {
1!
217
            // invalid page: better don't throw an exception, since this could easily happen
218
            // (list changed, user bookmarked the page)
219
            this.currentPage = 1;
×
220
        } else if (pageNumber != 1 && pageNumber > this.pageCount) {
1✔
221
            // invalid page: set to last page
222
            this.currentPage = this.pageCount;
1✔
223
        } else {
224
            this.currentPage = pageNumber;
1✔
225
        }
226
    }
1✔
227

228
    /**
229
     * Return the little summary message that lets the user know how many objects are in the list they are viewing, and
230
     * where in the list they are currently positioned. The message looks like: nnn [item(s)] found, displaying nnn to
231
     * nnn. [item(s)] is replaced by either itemName or itemNames depending on if it should be signular or plural.
232
     *
233
     * @return String
234
     */
235
    public String getSearchResultsSummary() {
236

237
        Object[] objs;
238
        String message;
239

240
        if (this.fullListSize == 0) {
1!
241
            objs = new Object[] { this.properties.getPagingItemsName() };
×
242
            message = this.properties.getPagingFoundNoItems();
×
243

244
        } else if (this.fullListSize == 1) {
1✔
245
            objs = new Object[] { this.properties.getPagingItemName() };
1✔
246
            message = this.properties.getPagingFoundOneItem();
1✔
247
        } else if (this.computedPageCount() == 1) {
1✔
248
            objs = new Object[] { Integer.valueOf(this.fullListSize), this.properties.getPagingItemsName(),
1✔
249
                    this.properties.getPagingItemsName() };
1✔
250
            message = this.properties.getPagingFoundAllItems();
1✔
251
        } else {
252
            objs = new Object[] { Integer.valueOf(this.fullListSize), this.properties.getPagingItemsName(),
1✔
253
                    Integer.valueOf(this.getFirstIndexForCurrentPage() + 1),
1✔
254
                    Integer.valueOf(this.getLastIndexForCurrentPage() + 1), Integer.valueOf(this.currentPage),
1✔
255
                    Integer.valueOf(this.pageCount) };
1✔
256
            message = this.properties.getPagingFoundSomeItems();
1✔
257
        }
258

259
        return new MessageFormat(message, this.properties.getLocale()).format(objs);
1✔
260
    }
261

262
    /**
263
     * Returns a string containing the nagivation bar that allows the user to move between pages within the list. The
264
     * urlFormatString should be a URL that looks like the following: somepage.page?page={0}
265
     *
266
     * @param baseHref
267
     *            Href used for links
268
     * @param pageParameter
269
     *            name for the page parameter
270
     *
271
     * @return String
272
     */
273
    public String getPageNavigationBar(final Href baseHref, final String pageParameter) {
274

275
        final int groupSize = this.properties.getPagingGroupSize();
1✔
276
        int startPage;
277
        int endPage;
278

279
        final Pagination pagination = new Pagination(baseHref, pageParameter, this.properties);
1✔
280
        pagination.setCurrent(Integer.valueOf(this.currentPage));
1✔
281

282
        // if no items are found still add pagination?
283
        if (this.pageCount == 0) {
1!
284
            pagination.addPage(1, true);
×
285
        }
286

287
        // center the selected page, but only if there are {groupSize} pages available after it, and check that the
288
        // result is not < 1
289
        startPage = Math.max(Math.min(this.currentPage - groupSize / 2, this.pageCount - (groupSize - 1)), 1);
1✔
290
        endPage = Math.min(startPage + groupSize - 1, this.pageCount);
1✔
291

292
        if (SmartListHelper.log.isDebugEnabled()) {
1!
293
            SmartListHelper.log.debug("Displaying pages from {} to {}", startPage, endPage);
×
294
        }
295

296
        if (this.currentPage != 1) {
1✔
297
            pagination.setFirst(Integer.valueOf(1));
1✔
298
            pagination.setPrevious(Integer.valueOf(this.currentPage - 1));
1✔
299
        }
300

301
        for (int j = startPage; j <= endPage; j++) {
1✔
302
            if (SmartListHelper.log.isDebugEnabled()) {
1!
303
                SmartListHelper.log.debug("adding page {}", j); //$NON-NLS-1$
×
304
            }
305
            pagination.addPage(j, j == this.currentPage);
1✔
306
        }
307

308
        if (this.currentPage != this.pageCount) {
1✔
309
            pagination.setNext(Integer.valueOf(this.currentPage + 1));
1✔
310
            pagination.setLast(Integer.valueOf(this.pageCount));
1✔
311
        }
312

313
        // format for previous/next banner
314
        String bannerFormat;
315

316
        if (pagination.isOnePage()) {
1✔
317
            bannerFormat = this.properties.getPagingBannerOnePage();
1✔
318
        } else if (pagination.isFirst()) {
1✔
319
            bannerFormat = this.properties.getPagingBannerFirst();
1✔
320
        } else if (pagination.isLast()) {
1✔
321
            bannerFormat = this.properties.getPagingBannerLast();
1✔
322
        } else {
323
            bannerFormat = this.properties.getPagingBannerFull();
1✔
324
        }
325

326
        return pagination.getFormattedBanner(this.properties.getPagingPageLink(),
1✔
327
                this.properties.getPagingPageSelected(), this.properties.getPagingPageSeparator(), bannerFormat);
1✔
328
    }
329

330
    /**
331
     * To string.
332
     *
333
     * @return the string
334
     *
335
     * @see java.lang.Object#toString()
336
     */
337
    @Override
338
    public String toString() {
339
        return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) //
1✔
340
                .append("fullList", this.fullList) //$NON-NLS-1$
1✔
341
                .append("fullListSize", this.fullListSize) //$NON-NLS-1$
1✔
342
                .append("pageSize", this.pageSize) //$NON-NLS-1$
1✔
343
                .append("pageCount", this.pageCount) //$NON-NLS-1$
1✔
344
                .append("properties", this.properties) //$NON-NLS-1$
1✔
345
                .append("currentPage", this.currentPage) //$NON-NLS-1$
1✔
346
                .append("partialList", this.partialList) //$NON-NLS-1$
1✔
347
                .toString();
1✔
348
    }
349
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc