001/* 002 * Copyright (c) 2014 Maxim Yunusov 003 * Licensed under the Apache License, Version 2.0 (the "License"); 004 * you may not use this file except in compliance with the License. 005 * You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software 010 * distributed under the License is distributed on an "AS IS" BASIS, 011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 * See the License for the specific language governing permissions and 013 * limitations under the License. 014 */ 015 016package org.maxur.perfmodel.backend.service.impl; 017 018import org.jvnet.hk2.annotations.Service; 019import org.maxur.perfmodel.backend.service.Application; 020import org.slf4j.Logger; 021import org.slf4j.LoggerFactory; 022 023import javax.inject.Named; 024import javax.swing.*; 025import java.awt.*; 026import java.io.IOException; 027import java.net.URI; 028import java.net.URL; 029 030import static java.awt.Desktop.Action.BROWSE; 031import static java.awt.Desktop.getDesktop; 032import static java.awt.Desktop.isDesktopSupported; 033import static java.awt.SystemTray.getSystemTray; 034import static java.lang.String.format; 035import static javax.swing.JOptionPane.showMessageDialog; 036import static javax.swing.SwingUtilities.invokeLater; 037import static org.maxur.perfmodel.backend.utils.OsUtils.isWindows; 038 039/** 040 * This class represents Performance Model Calculator Application 041 * It's GUI Implementation with Tray Icon 042 * 043 * @author Maxim 044 * @version 1.0 045 * @since <pre>24.10.2014</pre> 046 * <p> 047 * see http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/misc/TrayIconDemoProject/src/misc/TrayIconDemo.java 048 */ 049@Service 050public class TrayIconApplication extends Application { 051 052 private static final Logger LOGGER = LoggerFactory.getLogger(TrayIconApplication.class); 053 054 public static final String IMG_FAVICON_PATH = "/img/favicon.png"; 055 056 private TrayIcon trayIcon; 057 058 @SuppressWarnings("unused") 059 @Named("webapp.url") 060 private URI webappUri; 061 062 public TrayIconApplication() { 063 } 064 065 @Override 066 public boolean isApplicable() { 067 //Check the SystemTray support 068 return SystemTray.isSupported(); 069 } 070 071 @Override 072 protected void onInit() { 073 try { 074 final String className = isWindows() ? 075 "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" : 076 "javax.swing.plaf.metal.MetalLookAndFeel"; 077 UIManager.setLookAndFeel(className); 078 } catch (UnsupportedLookAndFeelException | IllegalAccessException 079 | InstantiationException | ClassNotFoundException ex 080 ) { 081 LOGGER.error("Tray application is not created", ex); 082 } 083 UIManager.put("swing.boldMetal", Boolean.FALSE); 084 } 085 086 @Override 087 protected void onStart() { 088 invokeLater(this::run); 089 } 090 091 private void run() { 092 trayIcon = new TrayIcon(createImage(IMG_FAVICON_PATH, "tray icon")); 093 trayIcon.setToolTip("Performance Model Calculator"); 094 trayIcon.setImageAutoSize(true); 095 trayIcon.setPopupMenu(createPopupMenu()); 096 trayIcon.addActionListener(e -> openBrowser()); 097 try { 098 getSystemTray().add(trayIcon); 099 } 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