Skip to content

Commit bd9eeaf

Browse files
committed
add consoleProgressBar
bump version
1 parent b1003bc commit bd9eeaf

File tree

8 files changed

+680
-3
lines changed

8 files changed

+680
-3
lines changed

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<modelVersion>4.0.0</modelVersion>
1212
<artifactId>cli-utils</artifactId>
13-
<version>0.2.5</version>
13+
<version>0.2.6</version>
1414
<name>CliUtils</name>
1515
<packaging>jar</packaging>
1616

@@ -20,6 +20,11 @@
2020
<artifactId>commons-cli</artifactId>
2121
<version>1.4</version>
2222
</dependency>
23+
<dependency>
24+
<groupId>info.unterrainer.commons</groupId>
25+
<artifactId>datastructures</artifactId>
26+
<version>0.1.2</version>
27+
</dependency>
2328
</dependencies>
2429

2530
</project>
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
package info.unterrainer.commons.cliutils.consoleprogressbar;
2+
3+
import java.io.PrintStream;
4+
import java.util.Optional;
5+
6+
import info.unterrainer.commons.cliutils.consoleprogressbar.drawablecomponents.DrawableComponent;
7+
import info.unterrainer.commons.cliutils.consoleprogressbar.drawablecomponents.ProgressBar;
8+
import info.unterrainer.commons.cliutils.consoleprogressbar.drawablecomponents.SimpleInsertBar;
9+
import info.unterrainer.commons.datastructures.Fader;
10+
import lombok.AccessLevel;
11+
import lombok.Builder;
12+
import lombok.Getter;
13+
import lombok.NoArgsConstructor;
14+
import lombok.Setter;
15+
import lombok.experimental.Accessors;
16+
17+
/**
18+
* This class enables your console-applications to draw a progress-bar.
19+
* <p>
20+
* You may specify if your console supports control-characters (like
21+
* standard-out) or not (like the Eclipse console-implementation (before Mars
22+
* (4.5)) or a pipe to a file) if you'd like to use one of the two standard
23+
* {@link DrawableComponent} implementations.<br/>
24+
* You also may implement your own {@link DrawableComponent} and use that in
25+
* your applications.
26+
* <p>
27+
* Default values are:
28+
* <table>
29+
* <tr>
30+
* <td><b>width</b></td>
31+
* <td>50</td>
32+
* </tr>
33+
* <tr>
34+
* <td><b>minValue</b></td>
35+
* <td>0.0d</td>
36+
* </tr>
37+
* <tr>
38+
* <td><b>maxValue</b></td>
39+
* <td>1.0d</td>
40+
* </tr>
41+
* <tr>
42+
* <td><b>controlCharacterSupport</b></td>
43+
* <td>true</td>
44+
* </tr>
45+
* </table>
46+
*/
47+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
48+
@Accessors(chain = true)
49+
public class ConsoleProgressBar {
50+
51+
@Getter
52+
private Fader fader;
53+
private double minValue;
54+
private double maxValue;
55+
56+
@Getter
57+
@Setter
58+
private boolean controlCharacterSupport;
59+
60+
@Getter
61+
@Setter
62+
private int width;
63+
64+
@Getter
65+
private boolean drawInitialized = false;
66+
private int lastNumberOfCharactersDrawn;
67+
@Getter
68+
private DrawableComponent component;
69+
70+
@Builder
71+
public ConsoleProgressBar(final Integer width, final Double minValue, final Double maxValue,
72+
final Boolean controlCharacterSupport, final DrawableComponent component) {
73+
74+
this.minValue = Optional.ofNullable(minValue).orElse(0.0d);
75+
this.maxValue = Optional.ofNullable(maxValue).orElse(1.0d);
76+
this.width = Optional.ofNullable(width).orElse(50);
77+
this.controlCharacterSupport = Optional.ofNullable(controlCharacterSupport).orElse(true);
78+
79+
if (component == null) {
80+
if (this.controlCharacterSupport)
81+
this.component = ProgressBar.builder().build();
82+
else
83+
this.component = SimpleInsertBar.builder().build();
84+
} else
85+
this.component = component;
86+
}
87+
88+
private void checkFader() {
89+
if (fader == null)
90+
fader = new Fader(minValue, maxValue);
91+
}
92+
93+
/**
94+
* Updates the bar to a given value.
95+
*
96+
* @param v the value to set the bar to
97+
* @return the console progress bar
98+
*/
99+
public ConsoleProgressBar updateValue(final double v) {
100+
checkFader();
101+
fader.setValue(v);
102+
return this;
103+
}
104+
105+
/**
106+
* Updates the bar by a given value.
107+
*
108+
* @param v the value
109+
* @return the console progress bar
110+
*/
111+
public ConsoleProgressBar updateValueBy(final double v) {
112+
checkFader();
113+
fader.setValue(fader.getValue() + v);
114+
return this;
115+
}
116+
117+
/**
118+
* Updates the bar to a given percentage.
119+
*
120+
* @param p the percentage to set the bar to
121+
* @return the console progress bar
122+
*/
123+
public ConsoleProgressBar updatePercentage(final double p) {
124+
checkFader();
125+
fader.setPercentage(p);
126+
return this;
127+
}
128+
129+
/**
130+
* Updates the bar by a given percentage.
131+
*
132+
* @param p the percentage
133+
* @return the console progress bar
134+
*/
135+
public ConsoleProgressBar updatePercentageBy(final double p) {
136+
checkFader();
137+
fader.setPercentage(fader.getPercentage() + p);
138+
return this;
139+
}
140+
141+
/**
142+
* Resets the bar to its minimum value.
143+
*
144+
* @return the console progress bar
145+
*/
146+
public ConsoleProgressBar reset() {
147+
checkFader();
148+
fader.setValue(fader.getMinimalValue());
149+
return this;
150+
}
151+
152+
/**
153+
* Sets the bar to its maximum value.
154+
*
155+
* @return the console progress bar
156+
*/
157+
public ConsoleProgressBar complete() {
158+
checkFader();
159+
fader.setValue(fader.getMaximalValue());
160+
return this;
161+
}
162+
163+
/**
164+
* Decides if a redraw is necessary.
165+
* <p>
166+
* This is the case if the last drawn value differs from the current one or if
167+
* the component hasn't been drawn yet at all.
168+
*
169+
* @return a boolean value
170+
*/
171+
public boolean isRedrawNecessary() {
172+
return !drawInitialized || (int) (fader.getPercentage() * width) != lastNumberOfCharactersDrawn;
173+
}
174+
175+
/**
176+
* Redraws the draw-able component of this progress bar by calling
177+
* {@link #remove(PrintStream)} and then {@link #draw(PrintStream)}.
178+
* <p>
179+
* Please call this as frequent as possible.<br>
180+
* The real remove-draw call will only be issued if there really has been a
181+
* change in the graphical representation of the bar.
182+
*
183+
* @param ps the print-stream to draw to
184+
* @return the console progress bar
185+
*/
186+
public ConsoleProgressBar redraw(final PrintStream ps) {
187+
if (ps != null) {
188+
checkFader();
189+
int fullNumber = (int) (fader.getPercentage() * width);
190+
191+
if (isRedrawNecessary()) {
192+
if (drawInitialized)
193+
component.remove(ps, width, lastNumberOfCharactersDrawn);
194+
component.draw(ps, fader, width, drawInitialized, fullNumber, lastNumberOfCharactersDrawn);
195+
drawInitialized = true;
196+
lastNumberOfCharactersDrawn = fullNumber;
197+
}
198+
}
199+
return this;
200+
}
201+
202+
/**
203+
* This method will draw the component. It will not remove the component first
204+
* and it will draw at any circumstances.<br>
205+
* If you want to re-draw it (update its values visually) consider calling
206+
* redraw instead.
207+
*
208+
* @param ps the print-stream to draw to
209+
* @return the console progress bar
210+
*/
211+
public ConsoleProgressBar draw(final PrintStream ps) {
212+
if (ps != null) {
213+
checkFader();
214+
int fullNumber = (int) (fader.getPercentage() * width);
215+
component.draw(ps, fader, width, drawInitialized, fullNumber, lastNumberOfCharactersDrawn);
216+
drawInitialized = true;
217+
lastNumberOfCharactersDrawn = fullNumber;
218+
ps.flush();
219+
}
220+
return this;
221+
}
222+
223+
/**
224+
* This method removes the component from the print-stream if possible.
225+
* <p>
226+
* If you use a component that cannot do so, e.g. components designed for
227+
* consoles with no control-character support, then this call will do nothing.
228+
*
229+
* @param ps the print-stream to draw to
230+
* @return the console progress bar
231+
*/
232+
public ConsoleProgressBar remove(final PrintStream ps) {
233+
if (ps != null) {
234+
checkFader();
235+
if (drawInitialized) {
236+
component.remove(ps, width, lastNumberOfCharactersDrawn);
237+
ps.flush();
238+
}
239+
}
240+
return this;
241+
}
242+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package info.unterrainer.commons.cliutils.consoleprogressbar.drawablecomponents;
2+
3+
import java.io.PrintStream;
4+
5+
import info.unterrainer.commons.datastructures.Fader;
6+
7+
public interface DrawableComponent {
8+
9+
/**
10+
* Draws the graphical component of the progress bar.<br/>
11+
* No need to flush the stream after writing. This is done after calling this
12+
* method.
13+
*
14+
* @param ps the print-stream to draw to
15+
* @param fader the fader that holds all exact values regarding the
16+
* bar
17+
* @param width the width of the bar in characters
18+
* @param drawInitialized false, if this is the first call to the draw-method,
19+
* true otherwise
20+
* @param value the number of characters that have the status 'filled'
21+
* @param lastValue the number of character drawn by the last call to draw
22+
*/
23+
void draw(PrintStream ps, Fader fader, int width, boolean drawInitialized, int value, int lastValue);
24+
25+
/**
26+
* Removes the graphical component of the progress bar from the output
27+
* stream.<br/>
28+
* No need to flush the stream after writing. This is done after calling this
29+
* method.
30+
*
31+
* @param ps the print-stream to draw to
32+
* @param width the width of the bar in characters
33+
* @param lastValue the number of character drawn by the last call to draw
34+
*/
35+
void remove(PrintStream ps, int width, int lastValue);
36+
}

0 commit comments

Comments
 (0)