Skip to content
This repository has been archived by the owner on Dec 10, 2018. It is now read-only.

Commit

Permalink
Merge pull request #124 from tresf/trayfix
Browse files Browse the repository at this point in the history
New tray popup implementation
  • Loading branch information
tresf committed Dec 21, 2015
2 parents ff25a82 + fbd3201 commit 36f331b
Show file tree
Hide file tree
Showing 6 changed files with 357 additions and 534 deletions.
144 changes: 144 additions & 0 deletions src/org/jdesktop/swinghelper/tray/JXTrayIcon.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Copyright 2008 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

package org.jdesktop.swinghelper.tray;

import javax.swing.*;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.PopupMenuEvent;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class JXTrayIcon extends TrayIcon {
private JPopupMenu menu;
private static JDialog dialog;
static {
dialog = new JDialog((Frame) null);
dialog.setUndecorated(true);
dialog.setAlwaysOnTop(true);
}

private static PopupMenuListener popupListener = new PopupMenuListener() {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
}

public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
dialog.setVisible(false);
}

public void popupMenuCanceled(PopupMenuEvent e) {
dialog.setVisible(false);
}
};


public JXTrayIcon(Image image) {
super(image);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
showJPopupMenu(e);
}

public void mouseReleased(MouseEvent e) {
showJPopupMenu(e);
}
});
}

protected void showJPopupMenu(MouseEvent e) {
if (menu != null) {
Dimension size = menu.getPreferredSize();
showJPopupMenu(e.getX(), e.getY() - size.height);
}
}

protected void showJPopupMenu(int x, int y) {
dialog.setLocation(x, y);
dialog.setVisible(true);
menu.show(dialog.getContentPane(), 0, 0);
// popup works only for focused windows
dialog.toFront();
}

public JPopupMenu getJPopupMenu() {
return menu;
}

public void setJPopupMenu(JPopupMenu menu) {
if (this.menu != null) {
this.menu.removePopupMenuListener(popupListener);
}
this.menu = menu;
menu.addPopupMenuListener(popupListener);
}

private static void createGui() {
JXTrayIcon tray = new JXTrayIcon(createImage());
tray.setJPopupMenu(createJPopupMenu());
try {
SystemTray.getSystemTray().add(tray);
} catch (AWTException e) {
e.printStackTrace();
}
}

public static void main(String[] args) throws Exception {

UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGui();
}
});
}

static Image createImage() {
BufferedImage i = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) i.getGraphics();
g2.setColor(Color.RED);
g2.fill(new Ellipse2D.Float(0, 0, i.getWidth(), i.getHeight()));
g2.dispose();
return i;
}

static JPopupMenu createJPopupMenu() {
final JPopupMenu m = new JPopupMenu();
m.add(new JMenuItem("Item 1"));
m.add(new JMenuItem("Item 2"));
JMenu submenu = new JMenu("Submenu");
submenu.add(new JMenuItem("item 1"));
submenu.add(new JMenuItem("item 2"));
submenu.add(new JMenuItem("item 3"));
m.add(submenu);
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
m.add(exitItem);
return m;
}
}
105 changes: 53 additions & 52 deletions src/qz/common/TrayManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.jdesktop.swinghelper.tray.JXTrayIcon;
import qz.auth.Certificate;
import qz.deploy.DeployUtilities;
import qz.deploy.WindowsDeploy;
Expand Down Expand Up @@ -58,11 +59,7 @@ public class TrayManager {
// The cached icons
private final IconCache iconCache;

// Time in millis before the popup menu disappears
final int POPUP_TIMEOUT = 2000;

// Custom swing pop-up menu
AutoHidePopupTray tray;
JXTrayIcon tray;

private ConfirmDialog confirmDialog;
private GatewayDialog gatewayDialog;
Expand Down Expand Up @@ -105,15 +102,27 @@ public TrayManager() {
shortcutCreator = DeployUtilities.getSystemShortcutCreator();
shortcutCreator.setShortcutName(Constants.ABOUT_TITLE);

// Initialize a custom Swing system tray that hides after a timeout
tray = new AutoHidePopupTray(POPUP_TIMEOUT);
tray.setToolTipText(name);
SystemUtilities.setSystemLookAndFeel();

if (SystemTray.isSupported()) {
// Accommodate some OS-specific tray bugs
tray = SystemUtilities.isLinux() ? new ModernTrayIcon() : new JXTrayIcon(new ImageIcon(new byte[1]).getImage());

// Iterates over all images denoted by IconCache.getTypes() and caches them
iconCache = new IconCache(tray.getIconSize());
tray.setImage(iconCache.getImage(IconCache.Icon.DANGER_ICON));
// Iterates over all images denoted by IconCache.getTypes() and caches them
iconCache = new IconCache(tray.getSize());
tray.setImage(iconCache.getImage(IconCache.Icon.DANGER_ICON));
tray.setToolTip(name);

try {
SystemTray.getSystemTray().add(tray);
} catch (AWTException awt) {
trayLogger.log(Level.SEVERE, "Could not attach tray", awt);
}
} else {
iconCache = new IconCache();
}

// Linux spcecific tasks
// OS-specific tasks
if (SystemUtilities.isLinux()) {
// Fix the tray icon to look proper on Ubuntu
UbuntuUtilities.fixTrayIcons(iconCache);
Expand All @@ -131,32 +140,7 @@ public TrayManager() {
// The ok/cancel dialog
confirmDialog = new ConfirmDialog(null, "Please Confirm", iconCache);

addMenuItems(tray);
//tray.displayMessage(name, name + " is running.", Level.INFO);

if (tray.getTrayIcon()!=null){
tray.getTrayIcon().addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
tray.setVisible(false);
aboutListener.actionPerformed(new ActionEvent(e.getSource(),e.getID(),null));
}
}

@Override
public void mousePressed(MouseEvent e) {}

@Override
public void mouseReleased(MouseEvent e) {}

@Override
public void mouseEntered(MouseEvent e) {}

@Override
public void mouseExited(MouseEvent e) {}
});
}
addMenuItems();
}

/**
Expand All @@ -176,7 +160,9 @@ public void run() {
/**
* Builds the swing pop-up menu with the specified items
*/
private void addMenuItems(JPopupMenu popup) {
private void addMenuItems() {
JPopupMenu popup = new JPopupMenu();

JMenu advancedMenu = new JMenu("Advanced");
advancedMenu.setMnemonic(KeyEvent.VK_A);
advancedMenu.setIcon(iconCache.getIcon(IconCache.Icon.SETTINGS_ICON));
Expand Down Expand Up @@ -253,6 +239,8 @@ private void addMenuItems(JPopupMenu popup) {
popup.add(startupItem);
popup.add(separator);
popup.add(exitItem);

tray.setJPopupMenu(popup);
}


Expand Down Expand Up @@ -391,21 +379,21 @@ private void shortcutToggle(ActionEvent e, DeployUtilities.ToggleType toggleType
// Remove shortcut entry
if (confirmDialog.prompt("Remove " + name + " from " + toggleType + "?")) {
if (!shortcutCreator.removeShortcut(toggleType)) {
tray.displayMessage(name, "Error removing " + toggleType + " entry", Level.SEVERE);
tray.displayMessage(name, "Error removing " + toggleType + " entry", TrayIcon.MessageType.ERROR);
checkBoxState = true; // Set our checkbox back to true
} else {
tray.displayMessage(name, "Successfully removed " + toggleType + " entry", Level.INFO);
tray.displayMessage(name, "Successfully removed " + toggleType + " entry", TrayIcon.MessageType.INFO);
}
} else {
checkBoxState = true; // Set our checkbox back to true
}
} else {
// Add shortcut entry
if (!shortcutCreator.createShortcut(toggleType)) {
tray.displayMessage(name, "Error creating " + toggleType + " entry", Level.SEVERE);
tray.displayMessage(name, "Error creating " + toggleType + " entry", TrayIcon.MessageType.ERROR);
checkBoxState = false; // Set our checkbox back to false
} else {
tray.displayMessage(name, "Successfully added " + toggleType + " entry", Level.INFO);
tray.displayMessage(name, "Successfully added " + toggleType + " entry", TrayIcon.MessageType.INFO);
}
}

Expand All @@ -418,7 +406,7 @@ private void shortcutToggle(ActionEvent e, DeployUtilities.ToggleType toggleType
* Displays a basic error dialog.
*/
private void showErrorDialog(String message) {
JOptionPane.showMessageDialog(tray, message, name, JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(null, message, name, JOptionPane.ERROR_MESSAGE);
}

public boolean showGatewayDialog(final Certificate cert) {
Expand Down Expand Up @@ -522,15 +510,15 @@ public static String getPorts(Server server) {
* Thread safe method for setting an info status message
*/
public void displayInfoMessage(String text) {
displayMessage(name, text, Level.INFO);
displayMessage(name, text, TrayIcon.MessageType.INFO);
}

/**
* Thread safe method for setting a fine status message. Fine messages are suppressed unless "Show all
* notifications" is checked.
*/
public void displayFineMessage(String text) {
displayMessage(name, text, Level.FINE);
displayMessage(name, text, TrayIcon.MessageType.NONE);
}

/**
Expand All @@ -544,7 +532,7 @@ public void setDefaultIcon() {
* Thread safe method for setting the error status message
*/
public void displayErrorMessage(String text) {
displayMessage(name, text, Level.SEVERE);
displayMessage(name, text, TrayIcon.MessageType.ERROR);
}

/**
Expand All @@ -558,7 +546,7 @@ public void setDangerIcon() {
* Thread safe method for setting the warning status message
*/
public void displayWarningMessage(String text) {
displayMessage(name, text, Level.WARNING);
displayMessage(name, text, TrayIcon.MessageType.WARNING);
}


Expand All @@ -577,7 +565,7 @@ private void setIcon(final IconCache.Icon i) {
SwingUtilities.invokeLater(new Thread(new Runnable() {
@Override
public void run() {
tray.setIcon(iconCache.getIcon(i));
tray.setImage(iconCache.getImage(i));
}
}));
}
Expand All @@ -590,21 +578,34 @@ public void run() {
* @param text The text body of the tray message
* @param level The message type: Level.INFO, .WARN, .SEVERE
*/
private void displayMessage(final String caption, final String text, final Level level) {
private void displayMessage(final String caption, final String text, final TrayIcon.MessageType level) {
if (tray != null) {
SwingUtilities.invokeLater(new Thread(new Runnable() {
@Override
public void run() {
boolean showAllNotifications = prefs.getBoolean(notificationsKey, false);
if (showAllNotifications || (level == Level.INFO || level == Level.SEVERE)) {
if (showAllNotifications || (level == TrayIcon.MessageType.INFO || level == TrayIcon.MessageType.ERROR)) {
tray.displayMessage(caption, text, level);
}
trayLogger.log(level, "Tray Message: " + text);
trayLogger.log(convertLevel(level), "Tray Message: " + text);
}
}));
}
}

public static Level convertLevel(TrayIcon.MessageType level) {
switch (level) {
case NONE:
return Level.FINE;
case ERROR:
return Level.SEVERE;
case WARNING:
return Level.WARNING;
default:
return Level.INFO;
}
}

public void addLogHandler(Logger logger) {
if (logHandler == null) {
try {
Expand Down
Loading

0 comments on commit 36f331b

Please sign in to comment.