- Add "Save file as" menu that forces browser to download file instead of opening...
[pithos] / src / gr / ebs / gss / client / ProgressBar.java
1 /*
2  * Copyright 2008, 2009 Electronic Business Systems Ltd.
3  *
4  * This file is part of GSS.
5  *
6  * GSS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 package gr.ebs.gss.client;
20
21 import com.google.gwt.user.client.ui.FlexTable;
22 import com.google.gwt.user.client.ui.Grid;
23 import com.google.gwt.user.client.ui.Label;
24 import com.google.gwt.user.client.ui.VerticalPanel;
25
26 /**
27  * <P>
28  * A simple progress bar that uses table elements to show progress and with a
29  * basic time remaining calculation built in.
30  * <P>
31  * You can optionally display some text above the progress bar and/or display
32  * time remaining underneath the progress bar. To control the display of those
33  * features, set the options in the constructor as shown in the following usage
34  * example:
35  *
36  * <PRE>
37  * final ProgressBar progressBar = new ProgressBar(20, ProgressBar.SHOW_TIME_REMAINING + ProgressBar.SHOW_TEXT);
38  * progressBar.setText(&quot;Doing something...&quot;);
39  * RootPanel.get().add(progressBar);
40  * Timer t = new Timer() {
41  *
42  *      public void run() {
43  *              int progress = progressBar.getProgress() + 4;
44  *              if (progress &gt; 100)
45  *                      cancel();
46  *              progressBar.setProgress(progress);
47  *      }
48  * };
49  * t.scheduleRepeating(1000);
50  * </PRE>
51  * <P>
52  * How the time remaining is displayed can be controlled by setting the relevant
53  * messages using the language of your choice.
54  * <P>
55  * The default setting for the messages are as follows:
56  *
57  * <PRE>
58  * setSecondsMessage(&quot;Time remaining: {0} Seconds&quot;);
59  * setMinutesMessage(&quot;Time remaining: {0} Minutes&quot;);
60  * setHoursMessage(&quot;Time remaining: {0} Hours&quot;);
61  * </PRE>
62  * <P>
63  * To reset the time remaining/set the start time, simply set the progress to
64  * zero.
65  * <P>
66  * Some basic CSS styling is available to control the text, border around the
67  * progress bar itself and the colour of the progress bar elements.
68  *
69  * <PRE>
70  * .progressbar-text {
71  *     font-weight: bold;
72  * }
73  * .progressbar-remaining {
74  *     font-size: 12px;
75  *     font-style: italic;
76  * }
77  * .progressbar-outer {
78  *     border: 1px solid black;
79  * }
80  * .progressbar-inner {
81  *     border: 1px solid black;
82  *     margin: 1px;
83  * }
84  * .progressbar-bar {
85  *     width: 5px;
86  *     height: 15px;
87  *     margin: 1px;
88  * }
89  * .progressbar-fullbar {
90  *     background: blue;
91  * }
92  * .progressbar-blankbar {
93  *     background: #eee;
94  * }
95  *</PRE>
96  * <P>
97  * You can take advantage of the default style by adding the following to the
98  * head of your HTML page.
99  * <P>
100  * &lt;link rel="stylesheet" type="text/css" href="style/gwl-progressBar.css">
101  * <P>
102  * This style sheet also has two additional styles which you can use by adding
103  * the stye name to the widget. You can use either one of these, or use both
104  * combined.
105  *
106  * <PRE>
107  * ProgressBar progressBar = new ProgressBar(20);
108  * progressBar.addStyleName(&quot;progressbar-solid&quot;);
109  * progressBar.addStyleName(&quot;progressbar-noborder&quot;);
110  * </PRE>
111  *
112  * @author Bjarne Matzen - Bjarne[dot]Matzen[at]gmail[dot]com
113  */
114
115 public class ProgressBar extends VerticalPanel {
116
117         /**
118          * Option to show text label above progress bar
119          */
120         public static final int SHOW_TEXT = 2;
121
122         /**
123          * Option to show time remaining
124          */
125         public static final int SHOW_TIME_REMAINING = 1;
126
127         /**
128          * The time the progress bar was started
129          */
130         private long startTime = System.currentTimeMillis();
131
132         /**
133          * The number of bar elements to show
134          */
135         private int elements = 20;
136
137         /**
138          * Time element text
139          */
140         private String secondsMessage = "Estimated time remaining: {0} Seconds";
141
142         private String minutesMessage = "Estimated time remaining: {0} Minutes";
143
144         private String hoursMessage = "Estimated time remaining: {0} Hours";
145
146         /**
147          * Current progress (as a percentage)
148          */
149         private int progress = 0;
150
151         /**
152          * This is the frame around the progress bar
153          */
154         private FlexTable barFrame = new FlexTable();
155
156         /**
157          * This is the grid used to show the elements
158          */
159         private Grid elementGrid;
160
161         /**
162          * This is the current text label below the progress bar
163          */
164         private Label remainLabel = new Label();
165
166         /**
167          * This is the current text label above the progress bar
168          */
169         private Label textLabel = new Label();
170
171         /**
172          * internal flags for options
173          */
174         private boolean showRemaining = false;
175
176         private boolean showText = false;
177
178         /**
179          * Base constructor for this widget
180          *
181          * @param elements The number of elements (bars) to show on the progress bar
182          * @param options The display options for the progress bar
183          */
184         public ProgressBar(int elements, int options) {
185                 // Read the options and set convenience variables
186                 if ((options & SHOW_TIME_REMAINING) == SHOW_TIME_REMAINING)
187                         showRemaining = true;
188                 if ((options & SHOW_TEXT) == SHOW_TEXT)
189                         showText = true;
190
191                 // Set element count
192                 this.elements = elements;
193
194                 // Styling
195                 remainLabel.setStyleName("progressbar-remaining");
196                 textLabel.setStyleName("progressbar-text");
197
198                 // Initialize the progress elements
199                 elementGrid = new Grid(1, elements);
200                 elementGrid.setStyleName("progressbar-inner");
201                 elementGrid.setCellPadding(0);
202                 elementGrid.setCellSpacing(0);
203
204                 for (int loop = 0; loop < elements; loop++) {
205                         Grid elm = new Grid(1, 1);
206                         // elm.setHTML(0, 0, "&nbsp;");
207                         elm.setHTML(0, 0, "");
208                         elm.setStyleName("progressbar-blankbar");
209                         elm.addStyleName("progressbar-bar");
210                         elementGrid.setWidget(0, loop, elm);
211                 }
212
213                 // Create the container around the elements
214                 Grid containerGrid = new Grid(1, 1);
215                 containerGrid.setCellPadding(0);
216                 containerGrid.setCellSpacing(0);
217                 containerGrid.setWidget(0, 0, elementGrid);
218                 containerGrid.setStyleName("progressbar-outer");
219                 // containerGrid.setBorderWidth(1);
220
221                 // Set up the surrounding flex table based on the options
222                 int row = 0;
223                 if (showText)
224                         barFrame.setWidget(row++, 0, textLabel);
225                 barFrame.setWidget(row++, 0, containerGrid);
226                 if (showRemaining)
227                         barFrame.setWidget(row++, 0, remainLabel);
228
229                 barFrame.setWidth("100%");
230
231                 // Add the frame to the panel
232                 this.add(barFrame);
233
234                 // Initialize progress bar
235                 setProgress(0);
236         }
237
238         /**
239          * Constructor without options
240          *
241          * @param elements The number of elements (bars) to show on the progress bar
242          */
243         public ProgressBar(int elements) {
244                 this(elements, 0);
245         }
246
247         /**
248          * Set the current progress as a percentage
249          *
250          * @param percentage Set current percentage for the progress bar
251          */
252         public void setProgress(int percentage) {
253                 // Make sure we are error-tolerant
254                 if (percentage > 100)
255                         percentage = 100;
256                 if (percentage < 0)
257                         percentage = 0;
258
259                 // Set the internal variable
260                 progress = percentage;
261
262                 // Update the elements in the progress grid to
263                 // reflect the status
264                 int completed = elements * percentage / 100;
265                 for (int loop = 0; loop < elements; loop++) {
266                         Grid elm = (Grid) elementGrid.getWidget(0, loop);
267                         if (loop < completed) {
268                                 elm.setStyleName("progressbar-fullbar");
269                                 elm.addStyleName("progressbar-bar");
270                         } else {
271                                 elm.setStyleName("progressbar-blankbar");
272                                 elm.addStyleName("progressbar-bar");
273                         }
274                 }
275
276                 if (percentage > 0) {
277                         // Calculate the new time remaining
278                         long soFar = (System.currentTimeMillis() - startTime) / 1000;
279                         long remaining = soFar * (100 - percentage) / percentage;
280                         // Select the best UOM
281                         String remainText = secondsMessage;
282                         if (remaining > 120) {
283                                 remaining = remaining / 60;
284                                 remainText = minutesMessage;
285                                 if (remaining > 120) {
286                                         remaining = remaining / 60;
287                                         remainText = hoursMessage;
288                                 }
289                         }
290                         // Locate the position to insert out time remaining
291                         int pos = remainText.indexOf("{0}");
292                         if (pos >= 0) {
293                                 String trail = "";
294                                 if (pos + 3 < remainText.length())
295                                         trail = remainText.substring(pos + 3);
296                                 remainText = remainText.substring(0, pos) + remaining + trail;
297                         }
298                         // Set the label
299                         remainLabel.setText(remainText);
300                 } else
301                         // If progress is 0, reset the start time
302                         startTime = System.currentTimeMillis();
303         }
304
305         /**
306          * Get the current progress as a percentage
307          *
308          * @return Current percentage for the progress bar
309          */
310         public int getProgress() {
311                 return progress;
312         }
313
314         /**
315          * Get the text displayed above the progress bar
316          *
317          * @return the text
318          */
319         public String getText() {
320                 return textLabel.getText();
321         }
322
323         /**
324          * Set the text displayed above the progress bar
325          *
326          * @param text the text to set
327          */
328         public void setText(String text) {
329                 textLabel.setText(text);
330         }
331
332         /**
333          * Get the message used to format the time remaining text for hours
334          *
335          * @return the hours message
336          */
337         public String getHoursMessage() {
338                 return hoursMessage;
339         }
340
341         /**
342          * Set the message used to format the time remaining text below the progress
343          * bar. There are 3 messages used for hours, minutes and seconds
344          * respectively. The message must contain a placeholder for the value. The
345          * placeholder must be {0}. For example, the following is a valid message:
346          * "Hours remaining: {0}"
347          *
348          * @param hoursMessage the hours message to set
349          */
350         public void setHoursMessage(String hoursMessage) {
351                 this.hoursMessage = hoursMessage;
352         }
353
354         /**
355          * Get the message used to format the time remaining text for minutes
356          *
357          * @return the minutesMessage
358          */
359         public String getMinutesMessage() {
360                 return minutesMessage;
361         }
362
363         /**
364          * Set the message used to format the time remaining text below the progress
365          * bar. There are 3 messages used for hours, minutes and seconds
366          * respectively. The message must contain a placeholder for the value. The
367          * placeholder must be {0}. For example, the following is a valid message:
368          * "Minutes remaining: {0}"
369          *
370          * @param minutesMessage the minutes message to set
371          */
372         public void setMinutesMessage(String minutesMessage) {
373                 this.minutesMessage = minutesMessage;
374         }
375
376         /**
377          * Get the message used to format the time remaining text for seconds
378          *
379          * @return the secondsMessage
380          */
381         public String getSecondsMessage() {
382                 return secondsMessage;
383         }
384
385         /**
386          * Set the message used to format the time remaining text below the progress
387          * bar. There are 3 messages used for hours, minutes and seconds
388          * respectively. The message must contain a placeholder for the value. The
389          * placeholder must be {0}. For example, the following is a valid message:
390          * "Seconds remaining: {0}"
391          *
392          * @param secondsMessage the secondsMessage to set
393          */
394         public void setSecondsMessage(String secondsMessage) {
395                 this.secondsMessage = secondsMessage;
396         }
397
398 }