1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package davmail.ui.tray;
20
21 import davmail.BundleMessage;
22 import davmail.DavGateway;
23 import davmail.Settings;
24 import davmail.ui.AboutFrame;
25 import davmail.ui.SettingsFrame;
26 import org.apache.log4j.Level;
27 import org.apache.log4j.Logger;
28 import org.eclipse.swt.SWT;
29 import org.eclipse.swt.graphics.GC;
30 import org.eclipse.swt.graphics.Image;
31 import org.eclipse.swt.graphics.ImageData;
32 import org.eclipse.swt.graphics.PaletteData;
33 import org.eclipse.swt.widgets.Display;
34 import org.eclipse.swt.widgets.Menu;
35 import org.eclipse.swt.widgets.MenuItem;
36 import org.eclipse.swt.widgets.Shell;
37 import org.eclipse.swt.widgets.ToolTip;
38 import org.eclipse.swt.widgets.Tray;
39 import org.eclipse.swt.widgets.TrayItem;
40
41 import javax.imageio.ImageIO;
42 import javax.swing.*;
43 import java.awt.image.BufferedImage;
44 import java.io.ByteArrayInputStream;
45 import java.io.ByteArrayOutputStream;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.net.URL;
49 import java.util.ArrayList;
50
51
52
53
54 public class SwtGatewayTray implements DavGatewayTrayInterface {
55 private static final Logger LOGGER = Logger.getLogger(SwtGatewayTray.class);
56
57 private static final Object LOCK = new Object();
58
59 protected SwtGatewayTray() {
60 }
61
62 static SettingsFrame settingsFrame;
63 static AboutFrame aboutFrame;
64
65 private static TrayItem trayItem;
66 private static ArrayList<java.awt.Image> frameIcons;
67
68 private static Image image;
69 private static Image image2;
70 private static Image inactiveImage;
71 private static Display display;
72 private static Shell shell;
73 private boolean isActive = true;
74 private static boolean isReady = false;
75 private static Error error;
76 private boolean firstMessage = true;
77
78 public static void initDisplay() {
79 if (!isReady) {
80
81
82
83 Thread swtThread = new Thread("SWT") {
84 @Override
85 public void run() {
86 try {
87 display = Display.getDefault();
88 shell = new Shell(display);
89 synchronized (LOCK) {
90
91 isReady = true;
92 LOCK.notifyAll();
93 }
94
95
96 while (!shell.isDisposed()) {
97 if (!display.readAndDispatch()) {
98 display.sleep();
99 }
100 }
101
102 if (settingsFrame != null) {
103 settingsFrame.dispose();
104 }
105 if (aboutFrame != null) {
106 aboutFrame.dispose();
107 }
108 System.exit(0);
109 } catch (Throwable e) {
110 LOGGER.error("Error in SWT thread", e);
111 error = new Error(e);
112 }
113 }
114 };
115 swtThread.start();
116 while (true) {
117
118 try {
119 synchronized (LOCK) {
120 if (error != null) {
121 throw error;
122 }
123 if (isReady) {
124 break;
125 }
126 LOCK.wait(1000);
127 }
128 } catch (InterruptedException e) {
129 DavGatewayTray.error(new BundleMessage("LOG_ERROR_WAITING_FOR_SWT_INIT"), e);
130 Thread.currentThread().interrupt();
131 }
132 }
133 }
134 }
135
136
137
138
139
140
141 @Override
142 public java.util.List<java.awt.Image> getFrameIcons() {
143 return frameIcons;
144 }
145
146
147
148
149 public void switchIcon() {
150 isActive = true;
151 display.syncExec(() -> {
152 Image currentImage = trayItem.getImage();
153 if (currentImage != null && currentImage.equals(image)) {
154 trayItem.setImage(image2);
155 } else {
156 trayItem.setImage(image);
157 }
158 });
159
160 }
161
162
163
164
165 public void resetIcon() {
166 display.syncExec(() -> trayItem.setImage(image));
167 }
168
169
170
171
172 public void inactiveIcon() {
173 isActive = false;
174 display.syncExec(() -> trayItem.setImage(inactiveImage));
175 }
176
177
178
179
180
181
182 public boolean isActive() {
183 return isActive;
184 }
185
186
187
188
189
190
191
192 public void displayMessage(final String message, final Level level) {
193 if (trayItem != null) {
194 display.asyncExec(() -> {
195 int messageType = 0;
196 if (level.equals(Level.INFO)) {
197 messageType = SWT.ICON_INFORMATION;
198 } else if (level.equals(Level.WARN)) {
199 messageType = SWT.ICON_WARNING;
200 } else if (level.equals(Level.ERROR)) {
201 messageType = SWT.ICON_ERROR;
202 }
203 if (messageType != 0) {
204 final ToolTip toolTip = new ToolTip(shell, SWT.BALLOON | messageType);
205 toolTip.setText(BundleMessage.format("UI_DAVMAIL_GATEWAY"));
206 toolTip.setMessage(message);
207 trayItem.setToolTip(toolTip);
208
209 if (firstMessage) {
210 firstMessage = false;
211 try {
212 Thread.sleep(1000);
213 } catch (InterruptedException e) {
214 Thread.currentThread().interrupt();
215 }
216 }
217 toolTip.setVisible(true);
218 }
219 trayItem.setToolTipText(BundleMessage.format("UI_DAVMAIL_GATEWAY") + '\n' + message);
220 });
221 }
222 }
223
224
225
226
227
228
229
230
231 public static Image loadSwtImage(String fileName) {
232 Image result = null;
233 try {
234 ClassLoader classloader = DavGatewayTray.class.getClassLoader();
235 URL imageUrl = classloader.getResource(fileName);
236 if (imageUrl == null) {
237 throw new IOException("fileName");
238 }
239 try (InputStream inputStream = imageUrl.openStream()) {
240 result = new Image(display, inputStream);
241
242 }
243
244 } catch (IOException e) {
245 DavGatewayTray.warn(new BundleMessage("LOG_UNABLE_TO_LOAD_IMAGE"), e);
246 }
247 return result;
248 }
249
250
251
252
253
254
255
256
257
258 public static Image loadSwtImage(String fileName, int targetSize) {
259 int padding = 0;
260 Image result = null;
261 try {
262 ClassLoader classloader = DavGatewayTray.class.getClassLoader();
263 URL imageUrl = classloader.getResource(fileName);
264 if (imageUrl == null) {
265 throw new IOException(fileName);
266 }
267 BufferedImage bufferedImage;
268 if (Settings.getBooleanProperty("davmail.trayGrayscale", false)) {
269 bufferedImage = DavGatewayTray.convertGrayscale(ImageIO.read(imageUrl));
270 } else {
271 bufferedImage = ImageIO.read(imageUrl);
272 }
273 byte[] imageBytes;
274 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
275 ImageIO.write(bufferedImage, "png", os);
276 imageBytes = os.toByteArray();
277 }
278
279 try (InputStream inputStream = new ByteArrayInputStream(imageBytes)) {
280 Image loadedImage = new Image(display, inputStream);
281
282 ImageData resultImageData = new ImageData(targetSize, targetSize, 24, new PaletteData(0xff0000, 0x00ff00, 0x0000ff));
283
284 resultImageData.setAlpha(0, 0, 0);
285
286 result = new Image(display, resultImageData);
287
288
289 GC gc = new GC(result);
290 gc.setAntialias(SWT.ON);
291 gc.setInterpolation(SWT.HIGH);
292 gc.drawImage(loadedImage, 0, 0, loadedImage.getBounds().width, loadedImage.getBounds().height,
293 padding, padding, result.getBounds().width - padding, result.getBounds().height - padding);
294 gc.dispose();
295 loadedImage.dispose();
296 }
297
298 } catch (IOException e) {
299 DavGatewayTray.warn(new BundleMessage("LOG_UNABLE_TO_LOAD_IMAGE"), e);
300 }
301 return result;
302 }
303
304
305
306
307 public void init() {
308 try {
309
310 UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
311 } catch (Exception e) {
312 DavGatewayTray.warn(new BundleMessage("LOG_UNABLE_TO_SET_LOOK_AND_FEEL"));
313 }
314
315 initDisplay();
316
317 display.asyncExec(() -> {
318 try {
319 final Tray tray = display.getSystemTray();
320 if (tray != null) {
321
322 trayItem = new TrayItem(tray, SWT.NONE);
323 trayItem.setToolTipText(BundleMessage.format("UI_DAVMAIL_GATEWAY"));
324
325 frameIcons = new ArrayList<>();
326 frameIcons.add(DavGatewayTray.adjustTrayIcon(DavGatewayTray.loadImage(AwtGatewayTray.TRAY128_PNG)));
327 frameIcons.add(DavGatewayTray.adjustTrayIcon(DavGatewayTray.loadImage(AwtGatewayTray.TRAY_PNG)));
328
329 image = loadSwtImage("tray128.png", 128);
330 image2 = loadSwtImage("tray128active.png", 128);
331 inactiveImage = loadSwtImage("tray128inactive.png", 128);
332
333 trayItem.setImage(image);
334 trayItem.addDisposeListener(e -> {
335 if (image != null && !image.isDisposed()) {
336 image.dispose();
337 }
338 if (image2 != null && !image2.isDisposed()) {
339 image2.dispose();
340 }
341 if (inactiveImage != null && !inactiveImage.isDisposed()) {
342 inactiveImage.dispose();
343 }
344 });
345
346
347 final Menu popup = new Menu(shell, SWT.POP_UP);
348 trayItem.addListener(SWT.MenuDetect, event -> display.asyncExec(
349 () -> popup.setVisible(true)));
350
351 MenuItem aboutItem = new MenuItem(popup, SWT.PUSH);
352 aboutItem.setText(BundleMessage.format("UI_ABOUT"));
353 aboutItem.addListener(SWT.Selection, event -> SwingUtilities.invokeLater(
354 () -> {
355 if (aboutFrame == null) {
356 aboutFrame = new AboutFrame();
357 }
358 aboutFrame.update();
359 aboutFrame.setVisible(true);
360 aboutFrame.toFront();
361 aboutFrame.requestFocus();
362 }));
363
364
365 trayItem.addListener(SWT.DefaultSelection, event -> SwingUtilities.invokeLater(
366 () -> openSettingsFrame()));
367
368 MenuItem defaultItem = new MenuItem(popup, SWT.PUSH);
369 defaultItem.setText(BundleMessage.format("UI_SETTINGS"));
370 defaultItem.addListener(SWT.Selection, event -> SwingUtilities.invokeLater(
371 () -> openSettingsFrame()));
372
373 MenuItem exitItem = new MenuItem(popup, SWT.PUSH);
374 exitItem.setText(BundleMessage.format("UI_EXIT"));
375 exitItem.addListener(SWT.Selection, event -> DavGateway.stop());
376
377
378 if (Settings.isFirstStart()) {
379 SwingUtilities.invokeLater(() -> {
380
381 if (settingsFrame == null) {
382 settingsFrame = new SettingsFrame();
383 }
384 settingsFrame.setVisible(true);
385 settingsFrame.toFront();
386 settingsFrame.requestFocus();
387 });
388
389 }
390
391 }
392 } catch (Exception exc) {
393 DavGatewayTray.error(exc);
394 } catch (Error exc) {
395 error = exc;
396 throw exc;
397 }
398 });
399 }
400
401 private void openSettingsFrame() {
402
403 if (settingsFrame == null) {
404 settingsFrame = new SettingsFrame();
405 }
406 settingsFrame.reload();
407 settingsFrame.setVisible(true);
408 settingsFrame.toFront();
409 settingsFrame.requestFocus();
410 }
411
412 public void dispose() {
413 shell.dispose();
414 }
415
416 }