WIP swing submenus
This commit is contained in:
parent
7509d7c960
commit
b354daab68
|
@ -17,17 +17,30 @@ package dorkbox.systemTray.swing;
|
|||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import dorkbox.systemTray.Menu;
|
||||
import dorkbox.systemTray.MenuEntry;
|
||||
import dorkbox.systemTray.SystemTray;
|
||||
import dorkbox.systemTray.SystemTrayMenuAction;
|
||||
import dorkbox.systemTray.util.ImageUtils;
|
||||
import dorkbox.util.SwingUtil;
|
||||
|
||||
// this is a weird composite class, because it must be a Menu, but ALSO a MenuEntry -- so it has both
|
||||
public
|
||||
class SwingMenu extends Menu {
|
||||
class SwingMenu extends Menu implements MenuEntry {
|
||||
|
||||
volatile SwingSystemTrayMenuPopup _native;
|
||||
volatile JComponent _native;
|
||||
|
||||
// this have to be volatile, because they can be changed from any thread
|
||||
private volatile String text;
|
||||
private volatile boolean hasLegitIcon = false;
|
||||
|
||||
/**
|
||||
* @param systemTray
|
||||
|
@ -43,7 +56,11 @@ class SwingMenu extends Menu {
|
|||
@Override
|
||||
public
|
||||
void run() {
|
||||
_native = new SwingSystemTrayMenuPopup();
|
||||
_native = new JMenu();
|
||||
|
||||
if (parent != null) {
|
||||
((SwingMenu) parent)._native.add(_native);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -92,9 +109,16 @@ class SwingMenu extends Menu {
|
|||
}
|
||||
else {
|
||||
// must always be called on the EDT
|
||||
menuEntry = new SwingMenuEntryItem(SwingMenu.this, callback);
|
||||
menuEntry.setText(menuText);
|
||||
menuEntry.setImage(imagePath);
|
||||
if (!menuText.equals("AAAAAAAA")) {
|
||||
menuEntry = new SwingMenuEntryItem(SwingMenu.this, callback);
|
||||
menuEntry.setText(menuText);
|
||||
menuEntry.setImage(imagePath);
|
||||
} else {
|
||||
menuEntry = new SwingMenu(getSystemTray(), SwingMenu.this);
|
||||
menuEntry.setText(menuText);
|
||||
menuEntry.setImage(imagePath);
|
||||
((SwingMenu) menuEntry).addMenuEntry("asdasdasd", null, null, null);
|
||||
}
|
||||
|
||||
menuEntries.add(menuEntry);
|
||||
}
|
||||
|
@ -102,4 +126,131 @@ class SwingMenu extends Menu {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// always called in the EDT
|
||||
void renderText(final String text) {
|
||||
((JMenuItem) _native).setText(text);
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
void setImage_(final File imageFile) {
|
||||
hasLegitIcon = imageFile != null;
|
||||
|
||||
SwingUtil.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
if (imageFile != null) {
|
||||
ImageIcon origIcon = new ImageIcon(imageFile.getAbsolutePath());
|
||||
((JMenuItem) _native).setIcon(origIcon);
|
||||
}
|
||||
else {
|
||||
((JMenuItem) _native).setIcon(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public
|
||||
String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
void setText(final String newText) {
|
||||
text = newText;
|
||||
SwingUtil.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
renderText(newText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
void setImage(final File imageFile) {
|
||||
if (imageFile == null) {
|
||||
setImage_(null);
|
||||
}
|
||||
else {
|
||||
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageFile));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
void setImage(final String imagePath) {
|
||||
if (imagePath == null) {
|
||||
setImage_(null);
|
||||
}
|
||||
else {
|
||||
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imagePath));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
void setImage(final URL imageUrl) {
|
||||
if (imageUrl == null) {
|
||||
setImage_(null);
|
||||
}
|
||||
else {
|
||||
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageUrl));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
void setImage(final String cacheName, final InputStream imageStream) {
|
||||
if (imageStream == null) {
|
||||
setImage_(null);
|
||||
}
|
||||
else {
|
||||
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, cacheName, imageStream));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
void setImage(final InputStream imageStream) {
|
||||
if (imageStream == null) {
|
||||
setImage_(null);
|
||||
}
|
||||
else {
|
||||
setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
boolean hasImage() {
|
||||
return hasLegitIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
void setCallback(final SystemTrayMenuAction callback) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
void remove() {
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
((SwingMenu) getParent())._native.remove(_native);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,24 +30,24 @@ abstract
|
|||
class SwingMenuEntry implements MenuEntry {
|
||||
private final int id = Menu.MENU_ID_COUNTER.getAndIncrement();
|
||||
|
||||
private final SwingMenu parentMenu;
|
||||
private final SwingMenu parent;
|
||||
final JComponent _native;
|
||||
|
||||
// this have to be volatile, because they can be changed from any thread
|
||||
private volatile String text;
|
||||
|
||||
// this is ALWAYS called on the EDT.
|
||||
SwingMenuEntry(final SwingMenu parentMenu, final JComponent menuItem) {
|
||||
this.parentMenu = parentMenu;
|
||||
SwingMenuEntry(final SwingMenu parent, final JComponent menuItem) {
|
||||
this.parent = parent;
|
||||
this._native = menuItem;
|
||||
|
||||
parentMenu._native.add(menuItem);
|
||||
parent._native.add(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
Menu getParent() {
|
||||
return parentMenu;
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,7 +143,7 @@ class SwingMenuEntry implements MenuEntry {
|
|||
public
|
||||
void run() {
|
||||
removePrivate();
|
||||
parentMenu._native.remove(_native);
|
||||
parent._native.remove(_native);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ class SwingMenuEntryItem extends SwingMenuEntry {
|
|||
private volatile SystemTrayMenuAction callback;
|
||||
|
||||
// this is ALWAYS called on the EDT.
|
||||
SwingMenuEntryItem(final SwingMenu parentMenu, final SystemTrayMenuAction callback) {
|
||||
super(parentMenu, new AdjustedJMenuItem());
|
||||
SwingMenuEntryItem(final SwingMenu parent, final SystemTrayMenuAction callback) {
|
||||
super(parent, new AdjustedJMenuItem());
|
||||
this.callback = callback;
|
||||
|
||||
|
||||
|
@ -86,6 +86,7 @@ class SwingMenuEntryItem extends SwingMenuEntry {
|
|||
((JMenuItem) _native).setText(text);
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
@Override
|
||||
void setImage_(final File imageFile) {
|
||||
hasLegitIcon = imageFile != null;
|
||||
|
|
|
@ -25,8 +25,8 @@ import dorkbox.systemTray.SystemTrayMenuAction;
|
|||
class SwingMenuEntrySpacer extends SwingMenuEntry implements MenuSpacer {
|
||||
|
||||
// this is ALWAYS called on the EDT.
|
||||
SwingMenuEntrySpacer(final SwingMenu parentMenu) {
|
||||
super(parentMenu, new JSeparator(JSeparator.HORIZONTAL));
|
||||
SwingMenuEntrySpacer(final SwingMenu parent) {
|
||||
super(parent, new JSeparator(JSeparator.HORIZONTAL));
|
||||
}
|
||||
|
||||
// called in the EDT thread
|
||||
|
|
|
@ -26,8 +26,8 @@ import dorkbox.systemTray.SystemTrayMenuAction;
|
|||
class SwingMenuEntryStatus extends SwingMenuEntry implements MenuStatus {
|
||||
|
||||
// this is ALWAYS called on the EDT.
|
||||
SwingMenuEntryStatus(final SwingMenu parentMenu, final String label) {
|
||||
super(parentMenu, new JMenuItem());
|
||||
SwingMenuEntryStatus(final SwingMenu parent, final String label) {
|
||||
super(parent, new JMenuItem());
|
||||
setText(label);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,8 +47,6 @@ class SwingSystemTray extends SwingMenu {
|
|||
volatile SystemTray tray;
|
||||
volatile TrayIcon trayIcon;
|
||||
|
||||
volatile boolean isActive = false;
|
||||
|
||||
/**
|
||||
* Creates a new system tray handler class.
|
||||
*/
|
||||
|
@ -56,6 +54,9 @@ class SwingSystemTray extends SwingMenu {
|
|||
SwingSystemTray(final dorkbox.systemTray.SystemTray systemTray) {
|
||||
super(systemTray, null);
|
||||
|
||||
// have to reassign our type...
|
||||
_native = new SwingSystemTrayMenuPopup();
|
||||
|
||||
ImageUtils.determineIconSize(dorkbox.systemTray.SystemTray.TYPE_SWING);
|
||||
|
||||
SwingUtil.invokeAndWait(new Runnable() {
|
||||
|
@ -143,10 +144,8 @@ class SwingSystemTray extends SwingMenu {
|
|||
final Image trayImage = new ImageIcon(iconFile.getAbsolutePath()).getImage();
|
||||
trayImage.flush();
|
||||
|
||||
if (!isActive) {
|
||||
if (trayIcon == null) {
|
||||
// here we init. everything
|
||||
isActive = true;
|
||||
|
||||
trayIcon = new TrayIcon(trayImage);
|
||||
|
||||
// appindicators DO NOT support anything other than PLAIN gtk-menus
|
||||
|
@ -185,7 +184,7 @@ class SwingSystemTray extends SwingMenu {
|
|||
|
||||
// voodoo to get this to popup to have the correct parent
|
||||
// from: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6285881
|
||||
_native.setInvoker(_native);
|
||||
((SwingSystemTrayMenuPopup) _native).setInvoker(_native);
|
||||
_native.setLocation(x, y);
|
||||
_native.setVisible(true);
|
||||
_native.setFocusable(true);
|
||||
|
@ -194,7 +193,7 @@ class SwingSystemTray extends SwingMenu {
|
|||
});
|
||||
|
||||
try {
|
||||
SwingSystemTray.this.tray.add(trayIcon);
|
||||
tray.add(trayIcon);
|
||||
} catch (AWTException e) {
|
||||
dorkbox.systemTray.SystemTray.logger.error("TrayIcon could not be added.", e);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ class SwingSystemTrayMenuPopup extends JPopupMenu {
|
|||
|
||||
private DelayTimer timer;
|
||||
|
||||
protected volatile Point previousLocation = null;
|
||||
protected volatile Point mouseClickLocation = null;
|
||||
|
||||
// protected boolean mouseStillOnMenu;
|
||||
// private JDialog hiddenDialog;
|
||||
|
@ -77,9 +77,9 @@ class SwingSystemTrayMenuPopup extends JPopupMenu {
|
|||
}
|
||||
|
||||
// has the mouse pointer moved > delta pixels from it's original location (when the tray icon was clicked)?
|
||||
else if (previousLocation != null &&
|
||||
location.x >= previousLocation.x - MOVEMENT_DELTA && location.x < previousLocation.x + MOVEMENT_DELTA &&
|
||||
location.y >= previousLocation.y - MOVEMENT_DELTA && location.y < previousLocation.y + MOVEMENT_DELTA) {
|
||||
else if (mouseClickLocation != null &&
|
||||
location.x >= mouseClickLocation.x - MOVEMENT_DELTA && location.x < mouseClickLocation.x + MOVEMENT_DELTA &&
|
||||
location.y >= mouseClickLocation.y - MOVEMENT_DELTA && location.y < mouseClickLocation.y + MOVEMENT_DELTA) {
|
||||
|
||||
// restart the timer
|
||||
SwingSystemTrayMenuPopup.this.timer.delay(POPUP_HIDE_DELAY);
|
||||
|
@ -125,10 +125,11 @@ class SwingSystemTrayMenuPopup extends JPopupMenu {
|
|||
@Override
|
||||
public
|
||||
void setVisible(boolean makeVisible) {
|
||||
// only allow java to close this popup if our timer closed it
|
||||
this.timer.cancel();
|
||||
|
||||
if (makeVisible) {
|
||||
previousLocation = MouseInfo.getPointerInfo().getLocation();
|
||||
mouseClickLocation = MouseInfo.getPointerInfo().getLocation();
|
||||
|
||||
// if the mouse isn't inside the popup in x seconds, close the popup
|
||||
this.timer.delay(POPUP_HIDE_DELAY);
|
||||
|
|
Loading…
Reference in New Issue