1 package com.trendmicro.grid.acl.client.util;
2
3 import static java.lang.System.out;
4 import java.text.NumberFormat;
5
6
7
8
9
10
11
12 public class ProgressIndicator implements Runnable {
13
14 static final String ANIMATION_CHARS = "/-\\|";
15 static final char CARRIAGE_RETURN = '\r';
16 static final long FRAME_DELAY = 150;
17
18 int animationIndex;
19
20 volatile String prefix, message = "";
21
22 volatile boolean stopped;
23 volatile double progress;
24 NumberFormat progressFormatter = NumberFormat.getInstance();
25
26 StringBuilder buffer;
27
28 public ProgressIndicator(String prefix) {
29 this.prefix = prefix;
30
31 progressFormatter.setGroupingUsed(false);
32 progressFormatter.setMinimumFractionDigits(2);
33 }
34
35 @Override
36 public void run() {
37 try {
38 while (!Thread.currentThread().isInterrupted() && !isClosed()) {
39 println();
40
41 try {
42 synchronized (this) {
43 wait(FRAME_DELAY);
44 }
45 } catch (InterruptedException e) {
46 Thread.currentThread().interrupt();
47 progress = -1;
48 break;
49 }
50 }
51
52 println();
53 } finally {
54 stopped = true;
55 synchronized (this) {
56 notifyAll();
57 }
58 }
59 }
60
61 private synchronized void println() {
62 if (buffer == null) {
63 if (!isClosed())
64 buffer = new StringBuilder(128);
65 else
66 return;
67 } else {
68 buffer.setLength(0);
69 buffer.append(CARRIAGE_RETURN);
70 }
71
72 buffer.append(prefix);
73
74 if (!isClosed()) {
75 buffer.append(' ').append(message).append(" [").append(ANIMATION_CHARS.charAt(animationIndex)).append(']');
76 animationIndex++;
77 if (animationIndex >= ANIMATION_CHARS.length())
78 animationIndex = 0;
79
80 if (progress > 0) {
81 buffer.append(' ');
82 buffer.append(progressFormatter.format(Math.round(progress * 10000) / 100D));
83 buffer.append('%');
84 }
85 } else {
86 for (int len = String.valueOf(message).length() + 4 + 8; len >= 0; len--)
87 buffer.append(' ');
88 }
89
90 synchronized (out) {
91 out.print(buffer.toString());
92
93 if (isClosed()) {
94 out.println();
95 buffer = null;
96 }
97 }
98 }
99
100 public synchronized void println(String line) {
101 synchronized (out) {
102 if (buffer == null)
103 out.println(line);
104 else {
105 out.print('\r');
106 out.println(line);
107 }
108 }
109 }
110
111 public void setMessage(String message) {
112 this.message = message;
113 }
114
115 public void setProgress(double processed, double total) {
116 if (!isClosed())
117 progress = total == 0 ? 0 : processed / total;
118 }
119
120 public void append(String message) {
121 prefix += message;
122 }
123
124 public boolean isClosed() {
125 return progress == -1;
126 }
127
128 public synchronized void close() {
129 progress = -1;
130 notifyAll();
131
132 try {
133 int maxWait = 20;
134 while (!stopped && maxWait-- > 0) wait(100);
135 } catch (InterruptedException ignored) {
136 Thread.currentThread().interrupt();
137 }
138 }
139 }