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 if (bufferedImage.getWidth() != targetSize || bufferedImage.getHeight() != targetSize) {
274 bufferedImage = DavGatewayTray.scaleImage(bufferedImage, targetSize);
275 }
276 byte[] imageBytes;
277 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
278 ImageIO.write(bufferedImage, "png", os);
279 imageBytes = os.toByteArray();
280 }
281
282 try (InputStream inputStream = new ByteArrayInputStream(imageBytes)) {
283 Image loadedImage = new Image(display, inputStream);
284
285 ImageData resultImageData = new ImageData(targetSize, targetSize, 24, new PaletteData(0xff0000, 0x00ff00, 0x0000ff));
286
287 resultImageData.setAlpha(0, 0, 0);
288
289 result = new Image(display, resultImageData);
290
291
292 GC gc = new GC(result);
293 gc.setAntialias(SWT.ON);
294 gc.setInterpolation(SWT.HIGH);
295 gc.drawImage(loadedImage, 0, 0, loadedImage.getBounds().width, loadedImage.getBounds().height,
296 padding, padding, result.getBounds().width - padding, result.getBounds().height - padding);
297 gc.dispose();
298 loadedImage.dispose();
299 }
300
301 } catch (IOException e) {
302 DavGatewayTray.warn(new BundleMessage("LOG_UNABLE_TO_LOAD_IMAGE"), e);
303 }
304 return result;
305 }
306
307 protected static void setDefaultIconImage(Image image) {
308 SwtGatewayTray.image = image;
309 }
310
311 protected static void setActiveIconImage(Image image) {
312 SwtGatewayTray.image2 = image;
313 }
314
315 protected static void setInactiveIconImage(Image image) {
316 SwtGatewayTray.inactiveImage = image;
317 }
318
319
320
321
322 public void init() {
323 try {
324
325 UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
326 } catch (Exception e) {
327 DavGatewayTray.warn(new BundleMessage("LOG_UNABLE_TO_SET_LOOK_AND_FEEL"));
328 }
329
330 initDisplay();
331
332 display.asyncExec(() -> {
333 try {
334 final Tray tray = display.getSystemTray();
335 if (tray != null) {
336
337 trayItem = new TrayItem(tray, SWT.NONE);
338 trayItem.setToolTipText(BundleMessage.format("UI_DAVMAIL_GATEWAY"));
339
340 frameIcons = new ArrayList<>();
341 frameIcons.add(DavGatewayTray.adjustTrayIcon(DavGatewayTray.loadImage(AwtGatewayTray.TRAY128_PNG)));
342 frameIcons.add(DavGatewayTray.adjustTrayIcon(DavGatewayTray.loadImage(AwtGatewayTray.TRAY_PNG)));
343
344
345 int trayIconSize = 24;
346 if (Settings.isWindows()) {
347 trayIconSize = 16;
348 }
349
350 SwtGatewayTray.setDefaultIconImage(loadSwtImage("tray128.png", trayIconSize));
351 SwtGatewayTray.setActiveIconImage(loadSwtImage("tray128active.png", trayIconSize));
352 SwtGatewayTray.setInactiveIconImage(loadSwtImage("tray128inactive.png", trayIconSize));
353
354 trayItem.setImage(image);
355 trayItem.addDisposeListener(e -> {
356 if (image != null && !image.isDisposed()) {
357 image.dispose();
358 }
359 if (image2 != null && !image2.isDisposed()) {
360 image2.dispose();
361 }
362 if (inactiveImage != null && !inactiveImage.isDisposed()) {
363 inactiveImage.dispose();
364 }
365 });
366
367
368 final Menu popup = new Menu(shell, SWT.POP_UP);
369 trayItem.addListener(SWT.MenuDetect, event -> display.asyncExec(
370 () -> popup.setVisible(true)));
371
372 MenuItem aboutItem = new MenuItem(popup, SWT.PUSH);
373 aboutItem.setText(BundleMessage.format("UI_ABOUT"));
374 aboutItem.addListener(SWT.Selection, event -> SwingUtilities.invokeLater(
375 () -> {
376 if (aboutFrame == null) {
377 aboutFrame = new AboutFrame();
378 }
379 aboutFrame.update();
380 aboutFrame.setVisible(true);
381 aboutFrame.toFront();
382 aboutFrame.requestFocus();
383 }));
384
385
386 trayItem.addListener(SWT.DefaultSelection, event -> SwingUtilities.invokeLater(
387 this::openSettingsFrame));
388
389 MenuItem defaultItem = new MenuItem(popup, SWT.PUSH);
390 defaultItem.setText(BundleMessage.format("UI_SETTINGS"));
391 defaultItem.addListener(SWT.Selection, event -> SwingUtilities.invokeLater(
392 this::openSettingsFrame));
393
394 MenuItem exitItem = new MenuItem(popup, SWT.PUSH);
395 exitItem.setText(BundleMessage.format("UI_EXIT"));
396 exitItem.addListener(SWT.Selection, event -> DavGateway.stop());
397
398
399 if (Settings.isFirstStart()) {
400 SwingUtilities.invokeLater(() -> {
401
402 if (settingsFrame == null) {
403 settingsFrame = new SettingsFrame();
404 }
405 settingsFrame.setVisible(true);
406 settingsFrame.toFront();
407 settingsFrame.requestFocus();
408 });
409
410 }
411
412 }
413 } catch (Exception exc) {
414 DavGatewayTray.error(exc);
415 } catch (Error exc) {
416 error = exc;
417 throw exc;
418 }
419 });
420 }
421
422 private void openSettingsFrame() {
423
424 if (settingsFrame == null) {
425 settingsFrame = new SettingsFrame();
426 }
427 settingsFrame.reload();
428 settingsFrame.setVisible(true);
429 settingsFrame.toFront();
430 settingsFrame.requestFocus();
431 }
432
433 public void dispose() {
434 shell.dispose();
435 }
436
437 }