/****************************************************************************
* Copyright (C) 2012 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file is part of the Open eCard App.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License version 3.0 as published by the Free Software Foundation
* and appearing in the file LICENSE.GPL included in the packaging of
* this file. Please review the following information to ensure the
* GNU General Public License version 3.0 requirements will be met:
* http://www.gnu.org/copyleft/gpl.html.
*
* Other Usage
* Alternatively, this file may be used in accordance with the terms
* and conditions contained in a signed written agreement between
* you and ecsec GmbH.
*
***************************************************************************/
package org.openecard.richclient.gui;
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import org.openecard.addon.AddonManager;
import org.openecard.common.I18n;
import org.openecard.gui.graphics.GraphicsUtil;
import org.openecard.gui.graphics.OecLogoBgWhite;
import org.openecard.recognition.CardRecognition;
import org.openecard.richclient.RichClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class creates a tray icon on systems that do have a system tray.
* Otherwise a normal window will be shown.
*
* @author Moritz Horsch <horsch@cdc.informatik.tu-darmstadt.de>
* @author Johannes Schmölz <johannes.schmoelz@ecsec.de>
*/
public class AppTray {
private static final Logger logger = LoggerFactory.getLogger(AppTray.class);
private static final String ICON_LOADER = "loader";
private static final String ICON_LOGO = "logo";
private final I18n lang = I18n.getTranslation("richclient");
private SystemTray tray;
private TrayIcon trayIcon;
private Status status;
private JFrame frame;
private JLabel label;
private RichClient client;
private Boolean isLinux = null;
private Boolean isKde = null;
private boolean trayAvailable;
/**
* Constructor of AppTray class.
*
* @param client RichClient
*/
public AppTray(RichClient client) {
this.client = client;
}
/**
* Starts the setup process.
* A loading icon is displayed.
*/
public void beginSetup() {
if (SystemTray.isSupported()) {
setupTrayIcon();
} else {
setupFrame();
}
}
/**
* Finishes the setup process.
* The loading icon is replaced with the eCard logo.
*
* @param rec
* @param manager
*/
public void endSetup(CardRecognition rec, AddonManager manager) {
if (trayAvailable) {
trayIcon.setImage(getTrayIconImage(ICON_LOGO));
trayIcon.setToolTip(lang.translationForKey("tray.title"));
} else {
label.setIcon(new ImageIcon(GraphicsUtil.createImage(OecLogoBgWhite.class, 256, 256)));
}
status = new Status(this, rec, manager);
}
/**
* Returns the current status.
*
* @return current status
*/
public Status status() {
return status;
}
/**
* Removes the tray icon from the tray and terminates the application.
*/
public void shutdown() {
if (trayAvailable) {
trayIcon.displayMessage("Open eCard App", lang.translationForKey("tray.message.shutdown"), TrayIcon.MessageType.INFO);
client.teardown();
tray.remove(trayIcon);
} else {
client.teardown();
}
System.exit(0);
}
private void setupTrayIcon() {
trayAvailable = true;
tray = SystemTray.getSystemTray();
trayIcon = new TrayIcon(getTrayIconImage(ICON_LOADER), lang.translationForKey("tray.message.loading"), null);
trayIcon.setImageAutoSize(true);
trayIcon.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (status != null) {
status.showInfo(new Point(e.getX(), e.getY()));
}
}
});
try {
tray.add(trayIcon);
} catch (AWTException ex) {
logger.error("TrayIcon could not be added to the system tray.", ex);
// tray and trayIcon are not needed anymore
tray = null;
trayIcon = null;
setupFrame();
}
}
private Image getTrayIconImage(String name) {
Dimension dim = tray.getTrayIconSize();
if (isLinux()) {
if (isKde()) {
return getImageKde(name, dim);
} else {
return getImageLinux(name, dim);
}
} else if (isMacOSX()) {
return getImageMacOSX(name, dim);
} else {
return getImageDefault(name, dim);
}
}
private Image getImageKde(String name, Dimension dim) {
if (name.equals(ICON_LOADER)) {
switch(dim.width) {
case 24:
return GuiUtils.getImage("loader_icon_linux_kde_24.gif");
default:
return GuiUtils.getImage("loader_icon_linux_default_256.gif");
}
} else {
// KDE uses tray icon images with the size of 24 x 24 pixels, but only 22 x 22 pixels are shown. The images
// are not scaled, but simply get cropped on the right side and the bottom by 2 pixels. If a smaller image
// is used (e.g. 22 x 22 pixels), it will be first scaled to 24 x 24 pixels and then it will be cropped.
// So an image must be used which is 24 x 24 pixels in size and can be cropped by 2 pixels without loosing
// any information.
// Attention: This may change in future version of KDE!
return GraphicsUtil.createImage(OecLogoBgWhite.class, dim.width - 2, dim.height - 2, dim.width, dim.height, 0, 0);
}
}
private Image getImageLinux(String name, Dimension dim) {
if (name.equals(ICON_LOADER)) {
return GuiUtils.getImage("loader_icon_linux_default_256.gif");
} else {
return GraphicsUtil.createImage(OecLogoBgWhite.class, dim.width, dim.height);
}
}
private Image getImageMacOSX(String name, Dimension dim) {
return GraphicsUtil.createImage(OecLogoBgWhite.class, dim.width - 2, dim.height - 2, dim.width, dim.height, 1, 1);
}
private Image getImageDefault(String name, Dimension dim) {
if (name.equals(ICON_LOADER)) {
return GuiUtils.getImage("loader_icon_default_256.gif");
} else {
return GraphicsUtil.createImage(OecLogoBgWhite.class, dim.width, dim.height);
}
}
private boolean isMacOSX() {
return System.getProperty("os.name").contains("OS X");
}
private boolean isLinux() {
if (isLinux == null) {
String os = System.getProperty("os.name").toLowerCase();
isLinux = os.indexOf("nux") >= 0;
}
return isLinux;
}
private boolean isKde() {
if (isKde == null) {
// KDE_FULL_SESSION contains true when KDE is running
// The spec says (http://techbase.kde.org/KDE_System_Administration/Environment_Variables#KDE_FULL_SESSION)
// If you plan on using this variable to detect a running KDE session, check if the value is not empty
// instead of seeing if it equals true. The value might be changed in the future to include KDE version.
String kdeSession = System.getenv("KDE_FULL_SESSION");
if (kdeSession != null && ! kdeSession.isEmpty()) {
isKde = true;
} else {
isKde = false;
}
}
return isKde;
}
private void setupFrame() {
trayAvailable = false;
frame = new JFrame(lang.translationForKey("tray.title"));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setIconImage(GraphicsUtil.createImage(OecLogoBgWhite.class, 256, 256));
label = new JLabel(GuiUtils.getImageIcon("loader_icon_default_64.gif"));
label.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
status.showInfo(e.getLocationOnScreen());
}
});
ImageIcon logo = new ImageIcon(GraphicsUtil.createImage(OecLogoBgWhite.class, 256, 256));
Container c = frame.getContentPane();
c.setPreferredSize(new Dimension(logo.getIconWidth(), logo.getIconHeight()));
c.setBackground(Color.white);
c.add(label);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}