1
2
3
4
5
6 package io.github.olyutorskii.quetexj;
7
8 import java.awt.EventQueue;
9 import java.util.Objects;
10 import java.util.Queue;
11 import java.util.concurrent.ConcurrentLinkedQueue;
12 import java.util.logging.Formatter;
13 import java.util.logging.Handler;
14 import java.util.logging.Level;
15 import java.util.logging.LogRecord;
16 import java.util.logging.SimpleFormatter;
17 import javax.swing.text.BadLocationException;
18 import javax.swing.text.Document;
19 import javax.swing.text.PlainDocument;
20
21
22
23
24
25
26 public class SwingLogHandler extends Handler {
27
28 private final Document document;
29 private final Queue<String> msgQueue;
30 private final LogTransferTask transferTask;
31
32
33
34
35
36
37
38 public SwingLogHandler() {
39 this(new PlainDocument());
40 return;
41 }
42
43
44
45
46
47
48
49
50 public SwingLogHandler(Document document) {
51 super();
52
53 Objects.requireNonNull(document);
54 this.document = document;
55
56 this.msgQueue = new ConcurrentLinkedQueue<>();
57 this.transferTask =
58 new LogTransferTask(this.msgQueue);
59
60 Formatter formatter = new SimpleFormatter();
61 setFormatter(formatter);
62
63 return;
64 }
65
66
67
68
69
70
71
72
73
74 public Document getDocument() {
75 return this.document;
76 }
77
78
79
80
81
82
83
84
85 @Override
86 public synchronized void publish(LogRecord logRec) {
87 if (logRec == null) return;
88
89 if (!isLoggable(logRec)) {
90 return;
91 }
92
93 Formatter formatter = getFormatter();
94 String message = formatter.format(logRec);
95
96 publish(message);
97
98 return;
99 }
100
101
102
103
104
105
106
107
108 private void publish(String message) {
109 boolean offered = this.msgQueue.offer(message);
110 assert offered;
111
112 if (EventQueue.isDispatchThread()) {
113 this.transferTask.transferQueueToDoc();
114 } else {
115 EventQueue.invokeLater(this.transferTask);
116 }
117
118 return;
119 }
120
121
122
123
124 @Override
125 public void flush() {
126 return;
127 }
128
129
130
131
132
133
134 @Override
135 public void close() throws SecurityException {
136 setLevel(Level.OFF);
137 flush();
138 return;
139 }
140
141
142
143
144
145
146
147 private class LogTransferTask implements Runnable {
148
149 private final Queue<String> queue;
150 private final StringBuilder msgBuf;
151
152
153
154
155
156
157
158 LogTransferTask(Queue<String> queue) {
159 super();
160
161 this.queue = queue;
162 this.msgBuf = new StringBuilder();
163
164 return;
165 }
166
167
168
169
170
171 @Override
172 public void run() {
173 transferQueueToDoc();
174 return;
175 }
176
177
178
179
180 void transferQueueToDoc() {
181 int queueSize = this.queue.size();
182 if (queueSize == 1) {
183 String msg = this.queue.poll();
184 appendToDocument(msg);
185 return;
186 } else if (queueSize <= 0) {
187 return;
188 }
189
190 this.msgBuf.setLength(0);
191
192 while (!this.queue.isEmpty()) {
193 String msg = this.queue.poll();
194 if (msg == null) break;
195 this.msgBuf.append(msg);
196 }
197
198 appendToDocument(this.msgBuf);
199
200 return;
201 }
202
203
204
205
206
207
208
209
210 private void appendToDocument(CharSequence logMessage) {
211 if (logMessage == null) return;
212 if (logMessage.length() <= 0) return;
213
214 Document doc = getDocument();
215 String str = logMessage.toString();
216 int insertPt = doc.getLength();
217
218 try {
219 doc.insertString(insertPt, str, null);
220 } catch (BadLocationException e) {
221 assert false;
222 }
223
224 return;
225 }
226
227 }
228
229 }