1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.maxur.perfmodel.backend.service.impl;
17
18 import org.jvnet.hk2.annotations.Service;
19 import org.maxur.perfmodel.backend.service.Application;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 import javax.inject.Named;
24 import javax.swing.*;
25 import java.awt.*;
26 import java.io.IOException;
27 import java.net.URI;
28 import java.net.URL;
29
30 import static java.awt.Desktop.Action.BROWSE;
31 import static java.awt.Desktop.getDesktop;
32 import static java.awt.Desktop.isDesktopSupported;
33 import static java.awt.SystemTray.getSystemTray;
34 import static java.lang.String.format;
35 import static javax.swing.JOptionPane.showMessageDialog;
36 import static javax.swing.SwingUtilities.invokeLater;
37 import static org.maxur.perfmodel.backend.utils.OsUtils.isWindows;
38
39
40
41
42
43
44
45
46
47
48
49 @Service
50 public class TrayIconApplication extends Application {
51
52 private static final Logger LOGGER = LoggerFactory.getLogger(TrayIconApplication.class);
53
54 public static final String IMG_FAVICON_PATH = "/img/favicon.png";
55
56 private TrayIcon trayIcon;
57
58 @SuppressWarnings("unused")
59 @Named("webapp.url")
60 private URI webappUri;
61
62 public TrayIconApplication() {
63 }
64
65 @Override
66 public boolean isApplicable() {
67
68 return SystemTray.isSupported();
69 }
70
71 @Override
72 protected void onInit() {
73 try {
74 final String className = isWindows() ?
75 "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" :
76 "javax.swing.plaf.metal.MetalLookAndFeel";
77 UIManager.setLookAndFeel(className);
78 } catch (UnsupportedLookAndFeelException | IllegalAccessException
79 | InstantiationException | ClassNotFoundException ex
80 ) {
81 LOGGER.error("Tray application is not created", ex);
82 }
83 UIManager.put("swing.boldMetal", Boolean.FALSE);
84 }
85
86 @Override
87 protected void onStart() {
88 invokeLater(this::run);
89 }
90
91 private void run() {
92 trayIcon = new TrayIcon(createImage(IMG_FAVICON_PATH, "tray icon"));
93 trayIcon.setToolTip("Performance Model Calculator");
94 trayIcon.setImageAutoSize(true);
95 trayIcon.setPopupMenu(createPopupMenu());
96 trayIcon.addActionListener(e -> openBrowser());
97 try {
98 getSystemTray().add(trayIcon);
99 } catch (AWTException e) {
100 final String msg = "TrayIcon could not be added.";
101 LOGGER.error(msg);
102 throw new IllegalStateException(msg, e);
103 }
104 }
105
106 private PopupMenu createPopupMenu() {
107 final PopupMenu popup = new PopupMenu();
108
109 final MenuItem aboutItem = new MenuItem("About");
110 final MenuItem startClientItem = new MenuItem("Start Client");
111 final MenuItem manageServiceItem = new MenuItem("Stop Service");
112 final MenuItem exitItem = new MenuItem("Exit");
113
114 startClientItem.addActionListener(e -> openBrowser());
115
116 manageServiceItem.addActionListener(e -> {
117 if (webServer().isStarted()) {
118 webServer().stop();
119 } else {
120 webServer().restart();
121 }
122 final String label = webServer().isStarted() ? "Stop Service" : "Start Service";
123 manageServiceItem.setLabel(label);
124 final String message = webServer().isStarted() ? "Web Service was started" : "Web Service was stopped";
125 trayIcon.displayMessage("Performance Model Calculator",
126 message,
127 TrayIcon.MessageType.INFO);
128 startClientItem.setEnabled(webServer().isStarted());
129 });
130
131 aboutItem.addActionListener(e ->
132 showMessageDialog(null, "Performance Model Calculator. Version: " + version())
133 );
134
135 exitItem.addActionListener(e -> stop());
136
137 popup.add(aboutItem);
138 popup.add(startClientItem);
139 popup.add(manageServiceItem);
140 popup.addSeparator();
141 popup.add(exitItem);
142
143 return popup;
144 }
145
146 @Override
147 protected void onStop() {
148 getSystemTray().remove(trayIcon);
149 }
150
151 private static Image createImage(final String path, final String description) {
152 final URL imageURL = TrayIconApplication.class.getResource(path);
153 if (imageURL == null) {
154 final String msg = format("Resource '%s' is not found", IMG_FAVICON_PATH);
155 LOGGER.error(msg);
156 throw new IllegalStateException(msg);
157 }
158 return (new ImageIcon(imageURL, description)).getImage();
159 }
160
161 private void openBrowser() {
162 if (!isDesktopSupported()) {
163 LOGGER.error("Cannot open browser. Desktop is not supported");
164 return;
165 }
166 final Desktop desktop = getDesktop();
167 if (!desktop.isSupported(BROWSE)) {
168 LOGGER.error("Cannot open browser. Desktop is not supported browse action");
169 return;
170 }
171 try {
172 desktop.browse(webappUri);
173 } catch (IOException e) {
174 LOGGER.error("Cannot open browser", e);
175 }
176 }
177
178 }
179
180