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

New tray popup implementation #124

Merged
merged 1 commit into from
Dec 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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