1package autotest.common.ui;
2
3import autotest.common.SimpleCallback;
4
5import com.google.gwt.event.dom.client.ClickEvent;
6import com.google.gwt.event.dom.client.ClickHandler;
7import com.google.gwt.user.client.ui.Anchor;
8import com.google.gwt.user.client.ui.Composite;
9import com.google.gwt.user.client.ui.FlowPanel;
10import com.google.gwt.user.client.ui.HorizontalPanel;
11import com.google.gwt.user.client.ui.Label;
12import com.google.gwt.user.client.ui.Panel;
13
14import java.util.ArrayList;
15import java.util.List;
16
17/**
18 * A widget to faciliate pagination of tables.  Shows currently displayed rows,
19 * total row count, and buttons for moving among pages.
20 */
21public class Paginator extends Composite {
22    static class LinkWithDisable extends Composite {
23        protected Panel panel = new FlowPanel();
24        protected Label label;
25        protected Anchor link;
26
27        public LinkWithDisable(String text) {
28            label = new Label(text);
29            link = new Anchor(text);
30            panel.add(link);
31            panel.add(label);
32            link.setStyleName("paginator-link");
33            label.setStyleName("paginator-link");
34            setEnabled(false); // default to not enabled
35            initWidget(panel);
36        }
37
38        public void setEnabled(boolean enabled) {
39            link.setVisible(enabled);
40            label.setVisible(!enabled);
41        }
42
43        public void addClickHandler(ClickHandler handler) {
44            link.addClickHandler(handler);
45        }
46    }
47
48    protected int resultsPerPage, numTotalResults;
49    protected List<SimpleCallback> callbacks = new ArrayList<SimpleCallback>();
50    protected int currentStart = 0;
51
52    protected HorizontalPanel mainPanel = new HorizontalPanel();
53    protected LinkWithDisable nextControl, prevControl,
54                              firstControl, lastControl;
55    protected Label statusLabel = new Label();
56
57    public Paginator() {
58        prevControl = new LinkWithDisable("< Previous");
59        prevControl.addClickHandler(new ClickHandler() {
60            public void onClick(ClickEvent event) {
61                currentStart -= Paginator.this.resultsPerPage;
62                notifyCallbacks();
63            }
64        });
65        nextControl = new LinkWithDisable("Next >");
66        nextControl.addClickHandler(new ClickHandler() {
67            public void onClick(ClickEvent event) {
68                currentStart += Paginator.this.resultsPerPage;
69                notifyCallbacks();
70            }
71        });
72        firstControl = new LinkWithDisable("<< First");
73        firstControl.addClickHandler(new ClickHandler() {
74            public void onClick(ClickEvent event) {
75                currentStart = 0;
76                notifyCallbacks();
77            }
78        });
79        lastControl = new LinkWithDisable("Last >>");
80        lastControl.addClickHandler(new ClickHandler() {
81            public void onClick(ClickEvent event) {
82                currentStart = getLastPageStart();
83                notifyCallbacks();
84            }
85        });
86
87        statusLabel.setWidth("10em");
88        statusLabel.setHorizontalAlignment(Label.ALIGN_CENTER);
89
90        mainPanel.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE);
91        mainPanel.add(firstControl);
92        mainPanel.add(prevControl);
93        mainPanel.add(statusLabel);
94        mainPanel.add(nextControl);
95        mainPanel.add(lastControl);
96
97        initWidget(mainPanel);
98    }
99
100    /**
101     * Get the current starting row index.
102     */
103    public int getStart() {
104        return currentStart;
105    }
106
107    /**
108     * Get the current ending row index (one past the last currently displayed
109     * row).
110     */
111    public int getEnd() {
112        int end = currentStart + resultsPerPage;
113        if (end < numTotalResults)
114            return end;
115        return numTotalResults;
116    }
117
118    /**
119     * Get the size of each page.
120     */
121    public int getResultsPerPage() {
122        return resultsPerPage;
123    }
124
125    /**
126     * Set the size of a page.
127     */
128    public void setResultsPerPage(int resultsPerPage) {
129        this.resultsPerPage = resultsPerPage;
130    }
131
132    /**
133     * Set the total number of results in the current working set.
134     */
135    public void setNumTotalResults(int numResults) {
136        this.numTotalResults = numResults;
137        if (currentStart >= numResults)
138            currentStart = getLastPageStart();
139    }
140
141    /**
142     * Set the current starting index.
143     */
144    public void setStart(int start) {
145        this.currentStart = start;
146    }
147
148    protected int getLastPageStart() {
149        // compute start of last page using truncation
150        return ((numTotalResults - 1) / resultsPerPage) * resultsPerPage;
151    }
152
153    public void update() {
154        boolean prevEnabled = !(currentStart == 0);
155        boolean nextEnabled = currentStart + resultsPerPage < numTotalResults;
156        firstControl.setEnabled(prevEnabled);
157        prevControl.setEnabled(prevEnabled);
158        nextControl.setEnabled(nextEnabled);
159        lastControl.setEnabled(nextEnabled);
160        int displayStart = getStart() + 1;
161        if(numTotalResults == 0)
162            displayStart = 0;
163        statusLabel.setText(displayStart + "-" + getEnd() +
164                            " of " + numTotalResults);
165    }
166
167    public void addCallback(SimpleCallback callback) {
168        callbacks.add(callback);
169    }
170
171    public void removeCallback(SimpleCallback callback) {
172        callbacks.remove(callback);
173    }
174
175    protected void notifyCallbacks() {
176        for (SimpleCallback callback : callbacks) {
177            callback.doCallback(this);
178        }
179    }
180}
181