Added setEnabled() for menu+entries, misc bug fixes for windows

This commit is contained in:
nathan 2016-10-03 23:12:00 +02:00
parent ad8cd3709c
commit 7e2834c0cb
12 changed files with 281 additions and 54 deletions

View File

@ -20,7 +20,6 @@ import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import dorkbox.systemTray.util.ImageUtils;
@ -33,7 +32,7 @@ public abstract
class Menu {
public static final AtomicInteger MENU_ID_COUNTER = new AtomicInteger();
private final int id = Menu.MENU_ID_COUNTER.getAndIncrement();
// TODO: enable/disable entries and menus?
protected final java.util.List<MenuEntry> menuEntries = new ArrayList<MenuEntry>();
private final SystemTray systemTray;
@ -92,6 +91,12 @@ class Menu {
protected abstract
Menu addMenu_(final String menuText, final File imagePath);
/*
* Called when this menu is removed from it's parent menu
*/
protected abstract
void removePrivate();
/*
* Necessary to guarantee all updates occur on the dispatch thread
*/
@ -104,6 +109,13 @@ class Menu {
protected abstract
void dispatchAndWait(Runnable runnable);
/**
* Enables, or disables the sub-menu entry.
*/
public abstract
void setEnabled(final boolean enabled);
/**
* Gets the menu entry for a specified text
*
@ -353,9 +365,6 @@ class Menu {
}
/**
* This removes a menu entry from the dropdown menu.
*
@ -367,9 +376,6 @@ class Menu {
throw new NullPointerException("No menu entry exists for menuEntry");
}
// have to wait for the value
final AtomicBoolean hasValue = new AtomicBoolean(false);
dispatchAndWait(new Runnable() {
@Override
public
@ -383,7 +389,6 @@ class Menu {
// this will also reset the menu
menuEntry.remove();
hasValue.set(true);
break;
}
}
@ -406,10 +411,6 @@ class Menu {
}
}
});
if (!hasValue.get()) {
throw new NullPointerException("Menu entry '" + menuEntry.getText() + "'not found in list while trying to remove it.");
}
}
/**
@ -417,17 +418,51 @@ class Menu {
*
* @param menu This is the menu entry to remove
*/
@SuppressWarnings("Duplicates")
public
void remove(final Menu menu) {
if (menu == null) {
throw new NullPointerException("No menu entry exists for menuEntry");
}
dispatchAndWait(new Runnable() {
@SuppressWarnings("Duplicates")
@Override
public
void run() {
try {
synchronized (menuEntries) {
for (Iterator<MenuEntry> iterator = menuEntries.iterator(); iterator.hasNext(); ) {
final MenuEntry entry = iterator.next();
if (entry == menu) {
iterator.remove();
// this will also reset the menu
menu.removePrivate();
break;
}
}
// now check to see if a spacer is at the top/bottom of the list (and remove it if so. This is a recursive function.
if (!menuEntries.isEmpty()) {
if (menuEntries.get(0) instanceof MenuSpacer) {
remove(menuEntries.get(0));
}
}
// now check to see if a spacer is at the top/bottom of the list (and remove it if so. This is a recursive function.
if (!menuEntries.isEmpty()) {
if (menuEntries.get(menuEntries.size()-1) instanceof MenuSpacer) {
remove(menuEntries.get(menuEntries.size() - 1));
}
}
}
} catch (Exception e) {
SystemTray.logger.error("Error removing menu entry from list.", e);
}
}
});
}
/**
* This removes a menu entry or sub-menu (via the text label) from the dropdown menu.
*
@ -435,9 +470,6 @@ class Menu {
*/
public
void remove(final String menuText) {
// have to wait for the value
final AtomicBoolean hasValue = new AtomicBoolean(true);
dispatchAndWait(new Runnable() {
@Override
public
@ -445,18 +477,11 @@ class Menu {
synchronized (menuEntries) {
MenuEntry menuEntry = get(menuText);
if (menuEntry == null) {
hasValue.set(false);
}
else {
if (menuEntry != null) {
remove(menuEntry);
}
}
}
});
if (!hasValue.get()) {
throw new NullPointerException("No menu entry exists for string '" + menuText + "'");
}
}
}

View File

@ -31,6 +31,11 @@ interface MenuEntry {
*/
Menu getParent();
/**
* Enables, or disables the entry.
*/
void setEnabled(final boolean enabled);
/**
* @return the text label that the menu entry has assigned
*/

View File

@ -104,7 +104,7 @@ class SystemTray extends Menu {
* <p>
* This is an advanced feature, and it is recommended to leave at 0.
*/
public static int FORCE_TRAY_TYPE = 0;
public static int FORCE_TRAY_TYPE = 3;
@Property
/**
@ -812,6 +812,14 @@ class SystemTray extends Menu {
return null;
}
/**
* @return the attached menu to this system tray
*/
public
Menu getMenu() {
return systemTrayMenu;
}
/**
* Adds a spacer to the dropdown menu. When menu entries are removed, any menu spacer that ends up at the top/bottom of the drop-down
* menu, will also be removed. For example:
@ -825,34 +833,73 @@ class SystemTray extends Menu {
* Entry3 (deleted)
*/
public
void addMenuSpacer() {
systemTrayMenu.addMenuSpacer();
void addSeparator() {
systemTrayMenu.addSeparator();
}
// NO OP.
@Override
protected
MenuEntry addEntry_(final String menuText, final File imagePath, final SystemTrayMenuAction callback) {
return null;
}
// NO OP.
@Override
protected
Menu addMenu_(final String menuText, final File imagePath) {
return null;
}
// NO OP.
@Override
public
void setEnabled(final boolean enabled) {
}
// NO OP.
@Override
protected
void dispatch(final Runnable runnable) {
}
// NO OP.
@Override
protected
void dispatchAndWait(final Runnable runnable) {
}
// NO OP.
protected
void removePrivate() {
}
/**
* Gets the menu entry for a specified text
*
* @param menuText the menu entry text to use to find the menu entry. The first result found is returned
*/
public final
MenuEntry getMenuEntry(final String menuText) {
return systemTrayMenu.getMenuEntry(menuText);
MenuEntry get(final String menuText) {
return systemTrayMenu.get(menuText);
}
/**
* Gets the first menu entry, ignoring status and spacers
*/
public final
MenuEntry getFirstMenuEntry() {
return systemTrayMenu.getFirstMenuEntry();
MenuEntry getFirst() {
return systemTrayMenu.getFirst();
}
/**
* Gets the last menu entry, ignoring status and spacers
*/
public final
MenuEntry getLastMenuEntry() {
return systemTrayMenu.getLastMenuEntry();
MenuEntry getLast() {
return systemTrayMenu.getLast();
}
/**
@ -861,10 +908,14 @@ class SystemTray extends Menu {
* @param menuIndex the menu entry index to use to retrieve the menu entry.
*/
public final
MenuEntry getMenuEntry(final int menuIndex) {
return systemTrayMenu.getMenuEntry(menuIndex);
MenuEntry get(final int menuIndex) {
return systemTrayMenu.get(menuIndex);
}
/**
* Adds a menu entry to the tray icon with text (no image)
*
@ -872,8 +923,8 @@ class SystemTray extends Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public final
void addMenuEntry(String menuText, SystemTrayMenuAction callback) {
addMenuEntry(menuText, (String) null, callback);
MenuEntry addEntry(String menuText, SystemTrayMenuAction callback) {
return addEntry(menuText, (String) null, callback);
}
/**
@ -884,8 +935,8 @@ class SystemTray extends Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public final
void addMenuEntry(String menuText, String imagePath, SystemTrayMenuAction callback) {
systemTrayMenu.addMenuEntry(menuText, imagePath, callback);
MenuEntry addEntry(String menuText, String imagePath, SystemTrayMenuAction callback) {
return systemTrayMenu.addEntry(menuText, imagePath, callback);
}
/**
@ -896,8 +947,8 @@ class SystemTray extends Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public final
void addMenuEntry(String menuText, URL imageUrl, SystemTrayMenuAction callback) {
systemTrayMenu.addMenuEntry(menuText, imageUrl, callback);
MenuEntry addEntry(String menuText, URL imageUrl, SystemTrayMenuAction callback) {
return systemTrayMenu.addEntry(menuText, imageUrl, callback);
}
/**
@ -909,8 +960,8 @@ class SystemTray extends Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public
void addMenuEntry(String menuText, String cacheName, InputStream imageStream, SystemTrayMenuAction callback) {
systemTrayMenu.addMenuEntry(menuText, cacheName, imageStream, callback);
MenuEntry addEntry(String menuText, String cacheName, InputStream imageStream, SystemTrayMenuAction callback) {
return systemTrayMenu.addEntry(menuText, cacheName, imageStream, callback);
}
/**
@ -921,18 +972,80 @@ class SystemTray extends Menu {
* @param callback callback that will be executed when this menu entry is clicked
*/
public final
void addMenuEntry(String menuText, InputStream imageStream, SystemTrayMenuAction callback) {
systemTrayMenu.addMenuEntry(menuText, imageStream, callback);
MenuEntry addEntry(String menuText, InputStream imageStream, SystemTrayMenuAction callback) {
return systemTrayMenu.addEntry(menuText, imageStream, callback);
}
/**
* Adds a sub-menu entry with text (no image)
*
* @param menuText string of the text you want to appear
*/
public
Menu addMenu(String menuText) {
return addMenu(menuText, (String) null);
}
/**
* Adds a sub-menu entry with text + image
*
* @param menuText string of the text you want to appear
* @param imagePath the image (full path required) to use. If null, no image will be used
*/
public
Menu addMenu(String menuText, String imagePath) {
return systemTrayMenu.addMenu(menuText, imagePath);
}
/**
* Adds a sub-menu entry with text + image
*
* @param menuText string of the text you want to appear
* @param imageUrl the URL of the image to use. If null, no image will be used
*/
public
Menu addMenu(String menuText, URL imageUrl) {
return systemTrayMenu.addMenu(menuText, imageUrl);
}
/**
* Adds a sub-menu entry with text + image
*
* @param menuText string of the text you want to appear
* @param cacheName @param cacheName the name to use for lookup in the cache for the imageStream
* @param imageStream the InputStream of the image to use. If null, no image will be used
*/
public
Menu addMenu(String menuText, String cacheName, InputStream imageStream) {
return systemTrayMenu.addMenu(menuText, cacheName, imageStream);
}
/**
* Adds a sub-menu entry with text + image
*
* @param menuText string of the text you want to appear
* @param imageStream the InputStream of the image to use. If null, no image will be used
*/
public
Menu addMenu(String menuText, InputStream imageStream) {
return systemTrayMenu.addMenu(menuText, imageStream);
}
/**
* This removes a menu entry from the dropdown menu.
*
* @param menuEntry This is the menu entry to remove
*/
public final
void removeMenuEntry(final MenuEntry menuEntry) {
systemTrayMenu.removeMenuEntry(menuEntry);
void remove(final MenuEntry menuEntry) {
systemTrayMenu.remove(menuEntry);
}
@ -942,8 +1055,8 @@ class SystemTray extends Menu {
* @param menuText This is the label for the menu entry to remove
*/
public final
void removeMenuEntry(final String menuText) {
systemTrayMenu.removeMenuEntry(menuText);
void remove(final String menuText) {
systemTrayMenu.remove(menuText);
}
}

View File

@ -67,6 +67,18 @@ class GtkEntry implements MenuEntry {
abstract
void setImage_(final File imageFile);
/**
* Enables, or disables the sub-menu entry.
*/
@Override
public
void setEnabled(final boolean enabled) {
if (enabled) {
Gtk.gtk_widget_set_sensitive(_native, Gtk.TRUE);
} else {
Gtk.gtk_widget_set_sensitive(_native, Gtk.FALSE);
}
}
@Override
public

View File

@ -57,6 +57,10 @@ class GtkEntrySeparator extends GtkEntry implements MenuSpacer {
@Override
public
void setCallback(final SystemTrayMenuAction callback) {
}
@Override
public
void setEnabled(final boolean enabled) {
}
}

View File

@ -53,4 +53,9 @@ class GtkEntryStatus extends GtkEntryItem {
public
void setCallback(final SystemTrayMenuAction callback) {
}
@Override
public
void setEnabled(final boolean enabled) {
}
}

View File

@ -105,6 +105,19 @@ class GtkMenu extends Menu implements MenuEntry {
});
}
/**
* Enables, or disables the sub-menu entry.
*/
@Override
public
void setEnabled(final boolean enabled) {
if (enabled) {
Gtk.gtk_widget_set_sensitive(menuEntry._native, Gtk.TRUE);
} else {
Gtk.gtk_widget_set_sensitive(menuEntry._native, Gtk.FALSE);
}
}
@Override
public
void addSeparator() {

View File

@ -59,6 +59,14 @@ class SwingEntry implements MenuEntry {
abstract
void setImage_(final File imageFile);
/**
* Enables, or disables the sub-menu entry.
*/
@Override
public
void setEnabled(final boolean enabled) {
_native.setEnabled(enabled);
}
@Override
public

View File

@ -58,11 +58,11 @@ class SwingMenu extends Menu implements MenuEntry {
public
void run() {
if (parent != null) {
if (!OS.isLinux()) {
_native = new AdjustedJMenu(null);
if (OS.isLinux()) {
_native = new AdjustedJMenu((SwingSystemTrayLinuxMenuPopup)((SwingMenu) systemTray.getMenu())._native);
}
else {
_native = new AdjustedJMenu((SwingSystemTrayLinuxMenuPopup)((SwingMenu) systemTray.getMenu())._native);
_native = new AdjustedJMenu(null);
}
((SwingMenu) parent)._native.add(_native);
@ -108,6 +108,15 @@ class SwingMenu extends Menu implements MenuEntry {
});
}
/**
* Enables, or disables the sub-menu entry.
*/
@Override
public
void setEnabled(final boolean enabled) {
_native.setEnabled(enabled);
}
/**
* Will add a new menu entry, or update one if it already exists
*/
@ -303,8 +312,27 @@ class SwingMenu extends Menu implements MenuEntry {
@Override
public
void run() {
((SwingMenu) getParent())._native.remove(_native);
_native.setVisible(false);
if (_native instanceof SwingSystemTrayMenuPopup) {
((SwingSystemTrayMenuPopup) _native).close();
}
else if (_native instanceof SwingSystemTrayLinuxMenuPopup) {
((SwingSystemTrayLinuxMenuPopup) _native).close();
}
SwingMenu parent = (SwingMenu) getParent();
if (parent != null) {
parent._native.remove(_native);
}
}
});
}
/*
* Called when this menu is removed from it's parent menu
*/
protected
void removePrivate() {
remove();
}
}

View File

@ -80,6 +80,8 @@ class SwingSystemTray extends SwingMenu {
}
menuEntries.clear();
}
remove();
}
});
}

View File

@ -156,4 +156,9 @@ class SwingSystemTrayLinuxMenuPopup extends JPopupMenu {
// restart the timer
SwingSystemTrayLinuxMenuPopup.this.timer.delay(POPUP_HIDE_DELAY);
}
public
void close() {
this.timer.cancel();
}
}

View File

@ -46,6 +46,7 @@ class SwingSystemTrayMenuPopup extends JPopupMenu {
this.hiddenDialog = new JDialog((Frame)null);
this.hiddenDialog.setEnabled(false);
this.hiddenDialog.setUndecorated(true);
this.hiddenDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
this.hiddenDialog.setSize(1, 1);
@ -68,4 +69,10 @@ class SwingSystemTrayMenuPopup extends JPopupMenu {
super.setVisible(makeVisible);
}
public
void close() {
this.hiddenDialog.setVisible(false);
this.hiddenDialog.dispatchEvent(new WindowEvent(this.hiddenDialog, WindowEvent.WINDOW_CLOSING));
}
}