forked from dorkbox/SystemTray
Code polish, documentation, cleanup for API changes
This commit is contained in:
parent
daff5a8e48
commit
599dabf4ef
@ -34,5 +34,7 @@
|
|||||||
<orderEntry type="module" module-name="JavaLauncher-Util" />
|
<orderEntry type="module" module-name="JavaLauncher-Util" />
|
||||||
<orderEntry type="library" name="jna" level="application" />
|
<orderEntry type="library" name="jna" level="application" />
|
||||||
<orderEntry type="library" name="SWT" level="project" />
|
<orderEntry type="library" name="SWT" level="project" />
|
||||||
|
<orderEntry type="library" name="asm" level="application" />
|
||||||
|
<orderEntry type="library" name="javassist" level="application" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
@ -13,92 +13,104 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package dorkbox.systemTray;
|
package dorkbox.systemTray;
|
||||||
|
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
import dorkbox.systemTray.util.MenuCheckboxHook;
|
import dorkbox.systemTray.peer.CheckboxPeer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents a common menu-checkbox entry, that is cross platform in nature
|
* This represents a common menu-checkbox entry, that is cross platform in nature
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public
|
public
|
||||||
class Checkbox extends Entry {
|
class Checkbox extends Entry {
|
||||||
private volatile boolean isChecked = false;
|
private boolean isChecked = false;
|
||||||
private volatile String text;
|
private String text;
|
||||||
private volatile ActionListener callback;
|
private ActionListener callback;
|
||||||
|
|
||||||
private volatile boolean enabled = true;
|
private boolean enabled = true;
|
||||||
private volatile char mnemonicKey;
|
private char mnemonicKey;
|
||||||
|
|
||||||
public
|
public
|
||||||
Checkbox() {
|
Checkbox() {
|
||||||
this(null, null);
|
this(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
|
||||||
Checkbox(final String text) {
|
|
||||||
this(text, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
public
|
||||||
Checkbox(final String text, final ActionListener callback) {
|
Checkbox(final String text, final ActionListener callback) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
Checkbox(final String text) {
|
||||||
|
this(text, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param hook the platform specific implementation for all actions for this type
|
* @param peer the platform specific implementation for all actions for this type
|
||||||
* @param parent the parent of this menu, null if the parent is the system tray
|
* @param parent the parent of this menu, null if the parent is the system tray
|
||||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||||
*/
|
*/
|
||||||
public synchronized
|
public synchronized
|
||||||
void bind(final MenuCheckboxHook hook, final Menu parent, final SystemTray systemTray) {
|
void bind(final CheckboxPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||||
super.bind(hook, parent, systemTray);
|
super.bind(peer, parent, systemTray);
|
||||||
|
|
||||||
hook.setEnabled(this);
|
peer.setEnabled(this);
|
||||||
hook.setText(this);
|
peer.setText(this);
|
||||||
hook.setCallback(this);
|
peer.setCallback(this);
|
||||||
hook.setShortcut(this);
|
peer.setShortcut(this);
|
||||||
hook.setChecked(this);
|
peer.setChecked(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this checkbox is selected, false if not.
|
||||||
|
*/
|
||||||
|
public synchronized
|
||||||
|
boolean getChecked() {
|
||||||
|
return isChecked;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the checked status for this entry
|
* Sets the checked status for this entry
|
||||||
*
|
*
|
||||||
* @param checked true to show the checkbox, false to hide it
|
* @param checked true to show the checkbox, false to hide it
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
void setChecked(boolean checked) {
|
void setChecked(boolean checked) {
|
||||||
this.isChecked = checked;
|
this.isChecked = checked;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuCheckboxHook) hook).setChecked(this);
|
((CheckboxPeer) peer).setChecked(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if this checkbox is selected, false if not.
|
|
||||||
*/
|
|
||||||
public final
|
|
||||||
boolean getChecked() {
|
|
||||||
return isChecked;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the callback assigned to this menu entry
|
* Gets the callback assigned to this menu entry
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
ActionListener getCallback() {
|
ActionListener getCallback() {
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a callback for a menu entry. This is the action that occurs when one clicks the menu entry
|
||||||
|
*
|
||||||
|
* @param callback the callback to set. If null, the callback is safely removed.
|
||||||
|
*/
|
||||||
|
public synchronized
|
||||||
|
void setCallback(final ActionListener callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
if (peer != null) {
|
||||||
|
((CheckboxPeer) peer).setCallback(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if this item is enabled, or false if it is disabled.
|
* @return true if this item is enabled, or false if it is disabled.
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
boolean getEnabled() {
|
boolean getEnabled() {
|
||||||
return this.enabled;
|
return this.enabled;
|
||||||
}
|
}
|
||||||
@ -106,19 +118,19 @@ class Checkbox extends Entry {
|
|||||||
/**
|
/**
|
||||||
* Enables, or disables the entry.
|
* Enables, or disables the entry.
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
void setEnabled(final boolean enabled) {
|
void setEnabled(final boolean enabled) {
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuCheckboxHook) hook).setEnabled(this);
|
((CheckboxPeer) peer).setEnabled(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the text label that the menu entry has assigned
|
* @return the text label that the menu entry has assigned
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
String getText() {
|
String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@ -128,54 +140,41 @@ class Checkbox extends Entry {
|
|||||||
*
|
*
|
||||||
* @param text the new text to set
|
* @param text the new text to set
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
void setText(final String text) {
|
void setText(final String text) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuCheckboxHook) hook).setText(this);
|
((CheckboxPeer) peer).setText(this);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a callback for a menu entry. This is the action that occurs when one clicks the menu entry
|
|
||||||
*
|
|
||||||
* @param callback the callback to set. If null, the callback is safely removed.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setCallback(final ActionListener callback) {
|
|
||||||
this.callback = callback;
|
|
||||||
if (hook != null) {
|
|
||||||
((MenuCheckboxHook) hook).setCallback(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the shortcut key for this menu entry (Mnemonic) which is what menu entry uses to be "selected" via the keyboard while the
|
* Gets the shortcut key for this menu entry (Mnemonic) which is what menu entry uses to be "selected" via the keyboard while the
|
||||||
* menu is displayed.
|
* menu is displayed.
|
||||||
*
|
* <p>
|
||||||
* Mnemonics are case-insensitive, and if the character defined by the mnemonic is found within the text, the first occurrence
|
* Mnemonics are case-insensitive, and if the character defined by the mnemonic is found within the text, the first occurrence
|
||||||
* of it will be underlined.
|
* of it will be underlined.
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
char getShortcut() {
|
char getShortcut() {
|
||||||
return this.mnemonicKey;
|
return this.mnemonicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a menu entry shortcut key (Mnemonic) so that menu entry can be "selected" via the keyboard while the menu is displayed.
|
* Sets a menu entry shortcut key (Mnemonic) so that menu entry can be "selected" via the keyboard while the menu is displayed.
|
||||||
*
|
* <p>
|
||||||
* Mnemonics are case-insensitive, and if the character defined by the mnemonic is found within the text, the first occurrence
|
* Mnemonics are case-insensitive, and if the character defined by the mnemonic is found within the text, the first occurrence
|
||||||
* of it will be underlined.
|
* of it will be underlined.
|
||||||
*
|
*
|
||||||
* @param key this is the key to set as the mnemonic
|
* @param key this is the key to set as the mnemonic
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
void setShortcut(final char key) {
|
void setShortcut(final char key) {
|
||||||
this.mnemonicKey = key;
|
this.mnemonicKey = key;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuCheckboxHook) hook).setShortcut(this);
|
((CheckboxPeer) peer).setShortcut(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,11 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package dorkbox.systemTray;
|
package dorkbox.systemTray;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import dorkbox.systemTray.util.EntryHook;
|
import dorkbox.systemTray.peer.EntryPeer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents a common menu-entry, that is cross platform in nature
|
* This represents a common menu-entry, that is cross platform in nature
|
||||||
@ -32,7 +31,7 @@ class Entry {
|
|||||||
private Menu parent;
|
private Menu parent;
|
||||||
private SystemTray systemTray;
|
private SystemTray systemTray;
|
||||||
|
|
||||||
protected volatile EntryHook hook;
|
protected volatile EntryPeer peer;
|
||||||
|
|
||||||
public
|
public
|
||||||
Entry() {
|
Entry() {
|
||||||
@ -42,16 +41,16 @@ class Entry {
|
|||||||
// called internally when an entry/menu is attached
|
// called internally when an entry/menu is attached
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param hook the platform specific implementation for all actions for this type
|
* @param peer the platform specific implementation for all actions for this type
|
||||||
* @param parent the parent of this menu, null if the parent is the system tray
|
* @param parent the parent of this menu, null if the parent is the system tray
|
||||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||||
*/
|
*/
|
||||||
public synchronized
|
public synchronized
|
||||||
void bind(final EntryHook hook, final Menu parent, final SystemTray systemTray) {
|
void bind(final EntryPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.systemTray = systemTray;
|
this.systemTray = systemTray;
|
||||||
|
|
||||||
this.hook = hook;
|
this.peer = peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// END methods for hooking into the system tray, menu's, and entries.
|
// END methods for hooking into the system tray, menu's, and entries.
|
||||||
@ -78,12 +77,12 @@ class Entry {
|
|||||||
*/
|
*/
|
||||||
public synchronized
|
public synchronized
|
||||||
void remove() {
|
void remove() {
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
hook.remove();
|
peer.remove();
|
||||||
|
|
||||||
this.parent = null;
|
this.parent = null;
|
||||||
this.systemTray = null;
|
this.systemTray = null;
|
||||||
hook = null;
|
peer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import dorkbox.systemTray.util.MenuHook;
|
import dorkbox.systemTray.peer.MenuPeer;
|
||||||
import dorkbox.systemTray.util.Status;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a cross-platform menu that is displayed by the tray-icon or as a sub-menu
|
* Represents a cross-platform menu that is displayed by the tray-icon or as a sub-menu
|
||||||
@ -33,7 +32,7 @@ import dorkbox.systemTray.util.Status;
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public
|
public
|
||||||
class Menu extends MenuItem {
|
class Menu extends MenuItem {
|
||||||
protected final List<Entry> menuEntries = new ArrayList<Entry>();
|
final List<Entry> menuEntries = new ArrayList<Entry>();
|
||||||
|
|
||||||
public
|
public
|
||||||
Menu() {
|
Menu() {
|
||||||
@ -100,19 +99,17 @@ class Menu extends MenuItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param hook the platform specific implementation for all actions for this type
|
* @param peer the platform specific implementation for all actions for this type
|
||||||
* @param parent the parent of this menu, null if the parent is the system tray
|
* @param parent the parent of this menu, null if the parent is the system tray
|
||||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||||
*/
|
*/
|
||||||
public synchronized
|
public synchronized
|
||||||
void bind(final MenuHook hook, final Menu parent, final SystemTray systemTray) {
|
void bind(final MenuPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||||
super.bind(hook, parent, systemTray);
|
super.bind(peer, parent, systemTray);
|
||||||
|
|
||||||
synchronized (menuEntries) {
|
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
final Entry menuEntry = menuEntries.get(i);
|
||||||
final Entry menuEntry = menuEntries.get(i);
|
peer.add(this, menuEntry, i);
|
||||||
hook.add(this, menuEntry, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,22 +132,20 @@ class Menu extends MenuItem {
|
|||||||
/**
|
/**
|
||||||
* Adds a menu entry, separator, or sub-menu to this menu.
|
* Adds a menu entry, separator, or sub-menu to this menu.
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
<T extends Entry> T add(final T entry, int index) {
|
<T extends Entry> T add(final T entry, int index) {
|
||||||
synchronized (menuEntries) {
|
if (index == -1) {
|
||||||
if (index == -1) {
|
menuEntries.add(entry);
|
||||||
menuEntries.add(entry);
|
} else {
|
||||||
} else {
|
if (!menuEntries.isEmpty() && menuEntries.get(0) instanceof Status) {
|
||||||
if (!menuEntries.isEmpty() && menuEntries.get(0) instanceof Status) {
|
// the "status" menu entry is ALWAYS first
|
||||||
// the "status" menu entry is ALWAYS first
|
index++;
|
||||||
index++;
|
|
||||||
}
|
|
||||||
menuEntries.add(index, entry);
|
|
||||||
}
|
}
|
||||||
|
menuEntries.add(index, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuHook) hook).add(this, entry, index);
|
((MenuPeer) peer).add(this, entry, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@ -167,18 +162,16 @@ class Menu extends MenuItem {
|
|||||||
/**
|
/**
|
||||||
* Gets the last menu entry or sub-menu, ignoring status and separators
|
* Gets the last menu entry or sub-menu, ignoring status and separators
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
Entry getLast() {
|
Entry getLast() {
|
||||||
// Must be wrapped in a synchronized block for object visibility
|
// Must be wrapped in a synchronized block for object visibility
|
||||||
synchronized (menuEntries) {
|
if (!menuEntries.isEmpty()) {
|
||||||
if (!menuEntries.isEmpty()) {
|
Entry entry;
|
||||||
Entry entry;
|
for (int i = menuEntries.size()-1; i >= 0; i--) {
|
||||||
for (int i = menuEntries.size()-1; i >= 0; i--) {
|
entry = menuEntries.get(i);
|
||||||
entry = menuEntries.get(i);
|
|
||||||
|
|
||||||
if (!(entry instanceof Separator || entry instanceof Status)) {
|
if (!(entry instanceof Separator || entry instanceof Status)) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,27 +184,25 @@ class Menu extends MenuItem {
|
|||||||
*
|
*
|
||||||
* @param menuIndex the menu entry index to use to retrieve the menu entry.
|
* @param menuIndex the menu entry index to use to retrieve the menu entry.
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
Entry get(final int menuIndex) {
|
Entry get(final int menuIndex) {
|
||||||
if (menuIndex < 0) {
|
if (menuIndex < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be wrapped in a synchronized block for object visibility
|
// Must be wrapped in a synchronized block for object visibility
|
||||||
synchronized (menuEntries) {
|
if (!menuEntries.isEmpty()) {
|
||||||
if (!menuEntries.isEmpty()) {
|
int count = 0;
|
||||||
int count = 0;
|
for (Entry entry : menuEntries) {
|
||||||
for (Entry entry : menuEntries) {
|
if (entry instanceof Separator || entry instanceof Status) {
|
||||||
if (entry instanceof Separator || entry instanceof Status) {
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == menuIndex) {
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (count == menuIndex) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,19 +214,30 @@ class Menu extends MenuItem {
|
|||||||
*
|
*
|
||||||
* @param entry This is the menu entry to remove
|
* @param entry This is the menu entry to remove
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
void remove(final Entry entry) {
|
void remove(final Entry entry) {
|
||||||
// null is passed in when a sub-menu is removing itself from us (because they have already called "remove" and have also
|
// null is passed in when a sub-menu is removing itself from us (because they have already called "remove" and have also
|
||||||
// removed themselves from the menuEntries)
|
// removed themselves from the menuEntries)
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
synchronized (menuEntries) {
|
for (Iterator<Entry> iterator = menuEntries.iterator(); iterator.hasNext(); ) {
|
||||||
for (Iterator<Entry> iterator = menuEntries.iterator(); iterator.hasNext(); ) {
|
final Entry entry__ = iterator.next();
|
||||||
final Entry entry__ = iterator.next();
|
if (entry__ == entry) {
|
||||||
if (entry__ == entry) {
|
iterator.remove();
|
||||||
iterator.remove();
|
entry.remove();
|
||||||
entry.remove();
|
break;
|
||||||
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 dorkbox.systemTray.Separator) {
|
||||||
|
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 dorkbox.systemTray.Separator) {
|
||||||
|
remove(menuEntries.get(menuEntries.size() - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,16 +246,14 @@ class Menu extends MenuItem {
|
|||||||
/**
|
/**
|
||||||
* This removes all menu entries from this menu
|
* This removes all menu entries from this menu
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
void removeAll() {
|
void removeAll() {
|
||||||
synchronized (menuEntries) {
|
// have to make copy because we are deleting all of them, and sub-menus remove themselves from parents
|
||||||
// have to make copy because we are deleting all of them, and sub-menus remove themselves from parents
|
ArrayList<Entry> menuEntriesCopy = new ArrayList<Entry>(this.menuEntries);
|
||||||
ArrayList<Entry> menuEntriesCopy = new ArrayList<Entry>(this.menuEntries);
|
for (Entry entry : menuEntriesCopy) {
|
||||||
for (Entry entry : menuEntriesCopy) {
|
entry.remove();
|
||||||
entry.remove();
|
|
||||||
}
|
|
||||||
menuEntries.clear();
|
|
||||||
}
|
}
|
||||||
|
menuEntries.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package dorkbox.systemTray;
|
package dorkbox.systemTray;
|
||||||
|
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
@ -22,8 +21,8 @@ import java.io.File;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.peer.MenuItemPeer;
|
||||||
import dorkbox.systemTray.util.ImageUtils;
|
import dorkbox.systemTray.util.ImageUtils;
|
||||||
import dorkbox.systemTray.util.MenuItemHook;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents a common menu-entry, that is cross platform in nature
|
* This represents a common menu-entry, that is cross platform in nature
|
||||||
@ -31,13 +30,13 @@ import dorkbox.systemTray.util.MenuItemHook;
|
|||||||
@SuppressWarnings({"unused", "SameParameterValue", "WeakerAccess"})
|
@SuppressWarnings({"unused", "SameParameterValue", "WeakerAccess"})
|
||||||
public
|
public
|
||||||
class MenuItem extends Entry {
|
class MenuItem extends Entry {
|
||||||
private volatile String text;
|
private String text;
|
||||||
private volatile File imageFile;
|
private File imageFile;
|
||||||
private volatile ActionListener callback;
|
private ActionListener callback;
|
||||||
|
|
||||||
// default enabled is always true
|
// default enabled is always true
|
||||||
private volatile boolean enabled = true;
|
private boolean enabled = true;
|
||||||
private volatile char mnemonicKey;
|
private char mnemonicKey;
|
||||||
|
|
||||||
public
|
public
|
||||||
MenuItem() {
|
MenuItem() {
|
||||||
@ -113,27 +112,27 @@ class MenuItem extends Entry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param hook the platform specific implementation for all actions for this type
|
* @param peer the platform specific implementation for all actions for this type
|
||||||
* @param parent the parent of this menu, null if the parent is the system tray
|
* @param parent the parent of this menu, null if the parent is the system tray
|
||||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||||
*/
|
*/
|
||||||
public synchronized
|
public synchronized
|
||||||
void bind(final MenuItemHook hook, final Menu parent, final SystemTray systemTray) {
|
void bind(final MenuItemPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||||
super.bind(hook, parent, systemTray);
|
super.bind(peer, parent, systemTray);
|
||||||
|
|
||||||
hook.setImage(this);
|
peer.setImage(this);
|
||||||
hook.setEnabled(this);
|
peer.setEnabled(this);
|
||||||
hook.setText(this);
|
peer.setText(this);
|
||||||
hook.setCallback(this);
|
peer.setCallback(this);
|
||||||
hook.setShortcut(this);
|
peer.setShortcut(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
private synchronized
|
||||||
void setImage_(final File imageFile) {
|
void setImage_(final File imageFile) {
|
||||||
this.imageFile = imageFile;
|
this.imageFile = imageFile;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuItemHook) hook).setImage(this);
|
((MenuItemPeer) peer).setImage(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +141,7 @@ class MenuItem extends Entry {
|
|||||||
* <p>
|
* <p>
|
||||||
* This file can also be a cached file, depending on how the image was assigned to this entry.
|
* This file can also be a cached file, depending on how the image was assigned to this entry.
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
File getImage() {
|
File getImage() {
|
||||||
return imageFile;
|
return imageFile;
|
||||||
}
|
}
|
||||||
@ -150,7 +149,7 @@ class MenuItem extends Entry {
|
|||||||
/**
|
/**
|
||||||
* Gets the callback assigned to this menu entry
|
* Gets the callback assigned to this menu entry
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
ActionListener getCallback() {
|
ActionListener getCallback() {
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
@ -158,7 +157,7 @@ class MenuItem extends Entry {
|
|||||||
/**
|
/**
|
||||||
* @return true if this item is enabled, or false if it is disabled.
|
* @return true if this item is enabled, or false if it is disabled.
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
boolean getEnabled() {
|
boolean getEnabled() {
|
||||||
return this.enabled;
|
return this.enabled;
|
||||||
}
|
}
|
||||||
@ -166,19 +165,19 @@ class MenuItem extends Entry {
|
|||||||
/**
|
/**
|
||||||
* Enables, or disables the entry.
|
* Enables, or disables the entry.
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
void setEnabled(final boolean enabled) {
|
void setEnabled(final boolean enabled) {
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuItemHook) hook).setEnabled(this);
|
((MenuItemPeer) peer).setEnabled(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the text label that the menu entry has assigned
|
* @return the text label that the menu entry has assigned
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
String getText() {
|
String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@ -188,12 +187,12 @@ class MenuItem extends Entry {
|
|||||||
*
|
*
|
||||||
* @param text the new text to set
|
* @param text the new text to set
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
void setText(final String text) {
|
void setText(final String text) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuItemHook) hook).setText(this);
|
((MenuItemPeer) peer).setText(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +314,7 @@ class MenuItem extends Entry {
|
|||||||
/**
|
/**
|
||||||
* @return true if this menu entry has an image assigned to it, or is just text.
|
* @return true if this menu entry has an image assigned to it, or is just text.
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
boolean hasImage() {return imageFile != null;}
|
boolean hasImage() {return imageFile != null;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -323,12 +322,12 @@ class MenuItem extends Entry {
|
|||||||
*
|
*
|
||||||
* @param callback the callback to set. If null, the callback is safely removed.
|
* @param callback the callback to set. If null, the callback is safely removed.
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
void setCallback(final ActionListener callback) {
|
void setCallback(final ActionListener callback) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuItemHook) hook).setCallback(this);
|
((MenuItemPeer) peer).setCallback(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +338,7 @@ class MenuItem extends Entry {
|
|||||||
* Mnemonics are case-insensitive, and if the character defined by the mnemonic is found within the text, the first occurrence
|
* Mnemonics are case-insensitive, and if the character defined by the mnemonic is found within the text, the first occurrence
|
||||||
* of it will be underlined.
|
* of it will be underlined.
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
char getShortcut() {
|
char getShortcut() {
|
||||||
return this.mnemonicKey;
|
return this.mnemonicKey;
|
||||||
}
|
}
|
||||||
@ -352,19 +351,19 @@ class MenuItem extends Entry {
|
|||||||
*
|
*
|
||||||
* @param key this is the key to set as the mnemonic
|
* @param key this is the key to set as the mnemonic
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
void setShortcut(final char key) {
|
void setShortcut(final char key) {
|
||||||
this.mnemonicKey = key;
|
this.mnemonicKey = key;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuItemHook) hook).setShortcut(this);
|
((MenuItemPeer) peer).setShortcut(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
void remove() {
|
void remove() {
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
setImage_(null);
|
setImage_(null);
|
||||||
setText(null);
|
setText(null);
|
||||||
setCallback(null);
|
setCallback(null);
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package dorkbox.systemTray;
|
package dorkbox.systemTray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,12 +13,9 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
package dorkbox.systemTray;
|
||||||
|
|
||||||
package dorkbox.systemTray.util;
|
import dorkbox.systemTray.peer.StatusPeer;
|
||||||
|
|
||||||
import dorkbox.systemTray.Entry;
|
|
||||||
import dorkbox.systemTray.Menu;
|
|
||||||
import dorkbox.systemTray.SystemTray;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents a common menu-status entry, that is cross platform in nature
|
* This represents a common menu-status entry, that is cross platform in nature
|
||||||
@ -32,21 +29,21 @@ class Status extends Entry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param hook the platform specific implementation for all actions for this type
|
* @param peer the platform specific implementation for all actions for this type
|
||||||
* @param parent the parent of this menu, null if the parent is the system tray
|
* @param parent the parent of this menu, null if the parent is the system tray
|
||||||
* @param systemTray the system tray (which is the object that sits in the system tray)
|
* @param systemTray the system tray (which is the object that sits in the system tray)
|
||||||
*/
|
*/
|
||||||
public synchronized
|
public synchronized
|
||||||
void bind(final MenuStatusHook hook, final Menu parent, final SystemTray systemTray) {
|
void bind(final StatusPeer peer, final Menu parent, final SystemTray systemTray) {
|
||||||
super.bind(hook, parent, systemTray);
|
super.bind(peer, parent, systemTray);
|
||||||
|
|
||||||
hook.setText(this);
|
peer.setText(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the text label that the menu entry has assigned
|
* @return the text label that the menu entry has assigned
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
String getText() {
|
String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@ -56,12 +53,12 @@ class Status extends Entry {
|
|||||||
*
|
*
|
||||||
* @param text the new text to set
|
* @param text the new text to set
|
||||||
*/
|
*/
|
||||||
public
|
public synchronized
|
||||||
void setText(final String text) {
|
void setText(final String text) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
|
||||||
if (hook != null) {
|
if (peer != null) {
|
||||||
((MenuStatusHook) hook).setText(this);
|
((StatusPeer) peer).setText(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
package dorkbox.systemTray;
|
package dorkbox.systemTray;
|
||||||
|
|
||||||
import dorkbox.systemTray.util.Status;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public
|
public
|
||||||
class Tray extends Menu {
|
class Tray extends Menu {
|
||||||
|
|
||||||
@ -22,7 +32,7 @@ class Tray extends Menu {
|
|||||||
/**
|
/**
|
||||||
* Gets the 'status' string assigned to the system tray
|
* Gets the 'status' string assigned to the system tray
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
String getStatus() {
|
String getStatus() {
|
||||||
return statusText;
|
return statusText;
|
||||||
}
|
}
|
||||||
@ -32,37 +42,35 @@ class Tray extends Menu {
|
|||||||
*
|
*
|
||||||
* @param statusText the text you want displayed, null if you want to remove the 'status' string
|
* @param statusText the text you want displayed, null if you want to remove the 'status' string
|
||||||
*/
|
*/
|
||||||
public final
|
public synchronized
|
||||||
void setStatus(final String statusText) {
|
void setStatus(final String statusText) {
|
||||||
this.statusText = statusText;
|
this.statusText = statusText;
|
||||||
|
|
||||||
synchronized (menuEntries) {
|
// status is ALWAYS at 0 index...
|
||||||
|
Entry menuEntry = null;
|
||||||
|
if (!menuEntries.isEmpty()) {
|
||||||
|
menuEntry = menuEntries.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menuEntry instanceof Status) {
|
||||||
|
// set the text or delete...
|
||||||
|
|
||||||
|
if (statusText == null) {
|
||||||
|
// delete
|
||||||
|
remove(menuEntry);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// set text
|
||||||
|
((Status) menuEntry).setText(statusText);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// create a new one
|
||||||
|
Status status = new Status();
|
||||||
|
status.setText(statusText);
|
||||||
|
|
||||||
// status is ALWAYS at 0 index...
|
// status is ALWAYS at 0 index...
|
||||||
Entry menuEntry = null;
|
// also calls the hook to add it, so we don't need anything special
|
||||||
if (!menuEntries.isEmpty()) {
|
add(status, 0);
|
||||||
menuEntry = menuEntries.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (menuEntry instanceof Status) {
|
|
||||||
// set the text or delete...
|
|
||||||
|
|
||||||
if (statusText == null) {
|
|
||||||
// delete
|
|
||||||
remove(menuEntry);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// set text
|
|
||||||
((Status) menuEntry).setText(statusText);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// create a new one
|
|
||||||
Status status = new Status();
|
|
||||||
status.setText(statusText);
|
|
||||||
|
|
||||||
// status is ALWAYS at 0 index...
|
|
||||||
// also calls the hook to add it, so we don't need anything special
|
|
||||||
add(status, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.systemTray.nativeUI;
|
|
||||||
|
|
||||||
import java.awt.MenuItem;
|
|
||||||
import java.awt.MenuShortcut;
|
|
||||||
import java.awt.PopupMenu;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
import dorkbox.systemTray.Entry;
|
|
||||||
import dorkbox.systemTray.swingUI.SwingUI;
|
|
||||||
import dorkbox.systemTray.util.SystemTrayFixes;
|
|
||||||
import dorkbox.util.SwingUtil;
|
|
||||||
|
|
||||||
abstract
|
|
||||||
class AwtEntry extends Entry implements SwingUI {
|
|
||||||
private final AwtMenu parent;
|
|
||||||
final MenuItem _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.
|
|
||||||
AwtEntry(final AwtMenu parent, final MenuItem menuItem) {
|
|
||||||
this.parent = parent;
|
|
||||||
this._native = menuItem;
|
|
||||||
|
|
||||||
parent._native.add(menuItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
// public
|
|
||||||
// Menu getParent() {
|
|
||||||
// return parent;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* must always be called in the EDT thread
|
|
||||||
*/
|
|
||||||
abstract
|
|
||||||
void renderText(final String text);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not always called on the EDT thread
|
|
||||||
*/
|
|
||||||
abstract
|
|
||||||
void setImage_(final File imageFile);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables, or disables the sub-menu entry.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setEnabled(final boolean enabled) {
|
|
||||||
_native.setEnabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void setShortcut(final char key) {
|
|
||||||
if (!(_native instanceof PopupMenu)) {
|
|
||||||
// yikes...
|
|
||||||
final int vKey = SystemTrayFixes.getVirtualKey(key);
|
|
||||||
|
|
||||||
SwingUtil.invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
_native.setShortcut(new MenuShortcut(vKey));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
String getText() {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void setText(final String newText) {
|
|
||||||
this.text = newText;
|
|
||||||
|
|
||||||
SwingUtil.invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
renderText(newText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
|
||||||
void setImage(final File imageFile) {
|
|
||||||
if (imageFile == null) {
|
|
||||||
setImage_(null);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageFile));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final
|
|
||||||
void setImage(final String imagePath) {
|
|
||||||
if (imagePath == null) {
|
|
||||||
setImage_(null);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imagePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final
|
|
||||||
void setImage(final URL imageUrl) {
|
|
||||||
if (imageUrl == null) {
|
|
||||||
setImage_(null);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageUrl));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final
|
|
||||||
void setImage(final String cacheName, final InputStream imageStream) {
|
|
||||||
if (imageStream == null) {
|
|
||||||
setImage_(null);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, cacheName, imageStream));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final
|
|
||||||
void setImage(final InputStream imageStream) {
|
|
||||||
if (imageStream == null) {
|
|
||||||
setImage_(null);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// setImage_(ImageUtils.resizeAndCache(ImageUtils.ENTRY_SIZE, imageStream));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final
|
|
||||||
void remove() {
|
|
||||||
SwingUtil.invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
removePrivate();
|
|
||||||
parent._native.remove(_native);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// called when this item is removed. Necessary to cleanup/remove itself
|
|
||||||
abstract
|
|
||||||
void removePrivate();
|
|
||||||
}
|
|
@ -24,14 +24,14 @@ import dorkbox.systemTray.Entry;
|
|||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.MenuItem;
|
import dorkbox.systemTray.MenuItem;
|
||||||
import dorkbox.systemTray.Separator;
|
import dorkbox.systemTray.Separator;
|
||||||
import dorkbox.systemTray.util.MenuHook;
|
import dorkbox.systemTray.Status;
|
||||||
import dorkbox.systemTray.util.Status;
|
import dorkbox.systemTray.peer.MenuPeer;
|
||||||
import dorkbox.systemTray.util.SystemTrayFixes;
|
import dorkbox.systemTray.util.SystemTrayFixes;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
// this is a weird composite class, because it must be a Menu, but ALSO a Entry -- so it has both
|
// this is a weird composite class, because it must be a Menu, but ALSO a Entry -- so it has both
|
||||||
@SuppressWarnings("ForLoopReplaceableByForEach")
|
@SuppressWarnings("ForLoopReplaceableByForEach")
|
||||||
class AwtMenu implements MenuHook {
|
class AwtMenu implements MenuPeer {
|
||||||
|
|
||||||
volatile java.awt.Menu _native;
|
volatile java.awt.Menu _native;
|
||||||
private final AwtMenu parent;
|
private final AwtMenu parent;
|
||||||
|
@ -21,11 +21,11 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
import dorkbox.systemTray.util.MenuItemHook;
|
import dorkbox.systemTray.peer.MenuItemPeer;
|
||||||
import dorkbox.systemTray.util.SystemTrayFixes;
|
import dorkbox.systemTray.util.SystemTrayFixes;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
class AwtMenuItem implements MenuItemHook {
|
class AwtMenuItem implements MenuItemPeer {
|
||||||
|
|
||||||
private final AwtMenu parent;
|
private final AwtMenu parent;
|
||||||
private final MenuItem _native = new java.awt.MenuItem();
|
private final MenuItem _native = new java.awt.MenuItem();
|
||||||
@ -116,6 +116,7 @@ class AwtMenuItem implements MenuItemHook {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void remove() {
|
void remove() {
|
||||||
|
@ -21,18 +21,17 @@ import java.awt.event.ActionListener;
|
|||||||
|
|
||||||
import dorkbox.systemTray.Checkbox;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
import dorkbox.systemTray.util.MenuCheckboxHook;
|
import dorkbox.systemTray.peer.CheckboxPeer;
|
||||||
import dorkbox.systemTray.util.SystemTrayFixes;
|
import dorkbox.systemTray.util.SystemTrayFixes;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
class AwtMenuItemCheckbox implements MenuCheckboxHook {
|
class AwtMenuItemCheckbox implements CheckboxPeer {
|
||||||
|
|
||||||
private final AwtMenu parent;
|
private final AwtMenu parent;
|
||||||
private final java.awt.CheckboxMenuItem _native = new java.awt.CheckboxMenuItem();
|
private final java.awt.CheckboxMenuItem _native = new java.awt.CheckboxMenuItem();
|
||||||
|
|
||||||
private volatile ActionListener swingCallback;
|
private volatile ActionListener swingCallback;
|
||||||
|
|
||||||
|
|
||||||
// this is ALWAYS called on the EDT.
|
// this is ALWAYS called on the EDT.
|
||||||
AwtMenuItemCheckbox(final AwtMenu parent) {
|
AwtMenuItemCheckbox(final AwtMenu parent) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
@ -17,10 +17,10 @@ package dorkbox.systemTray.nativeUI;
|
|||||||
|
|
||||||
import java.awt.MenuItem;
|
import java.awt.MenuItem;
|
||||||
|
|
||||||
import dorkbox.systemTray.util.EntryHook;
|
import dorkbox.systemTray.peer.EntryPeer;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
class AwtMenuItemSeparator implements EntryHook {
|
class AwtMenuItemSeparator implements EntryPeer {
|
||||||
|
|
||||||
private final AwtMenu parent;
|
private final AwtMenu parent;
|
||||||
private final MenuItem _native = new MenuItem("-");
|
private final MenuItem _native = new MenuItem("-");
|
||||||
|
@ -20,11 +20,11 @@ import static java.awt.Font.DIALOG;
|
|||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.MenuItem;
|
import java.awt.MenuItem;
|
||||||
|
|
||||||
import dorkbox.systemTray.util.MenuStatusHook;
|
import dorkbox.systemTray.Status;
|
||||||
import dorkbox.systemTray.util.Status;
|
import dorkbox.systemTray.peer.StatusPeer;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
class AwtMenuItemStatus implements MenuStatusHook {
|
class AwtMenuItemStatus implements StatusPeer {
|
||||||
|
|
||||||
private final AwtMenu parent;
|
private final AwtMenu parent;
|
||||||
private final MenuItem _native = new MenuItem();
|
private final MenuItem _native = new MenuItem();
|
||||||
|
@ -21,11 +21,11 @@ import com.sun.jna.Pointer;
|
|||||||
|
|
||||||
import dorkbox.systemTray.jna.linux.Gobject;
|
import dorkbox.systemTray.jna.linux.Gobject;
|
||||||
import dorkbox.systemTray.jna.linux.Gtk;
|
import dorkbox.systemTray.jna.linux.Gtk;
|
||||||
import dorkbox.systemTray.util.EntryHook;
|
import dorkbox.systemTray.peer.EntryPeer;
|
||||||
import dorkbox.systemTray.util.ImageUtils;
|
import dorkbox.systemTray.util.ImageUtils;
|
||||||
|
|
||||||
abstract
|
abstract
|
||||||
class GtkMenuBaseItem implements EntryHook {
|
class GtkBaseMenuItem implements EntryPeer {
|
||||||
private static File transparentIcon = null;
|
private static File transparentIcon = null;
|
||||||
// these are necessary BECAUSE GTK menus look funky as hell when there are some menu entries WITH icons and some WITHOUT
|
// these are necessary BECAUSE GTK menus look funky as hell when there are some menu entries WITH icons and some WITHOUT
|
||||||
private volatile boolean hasLegitImage = true;
|
private volatile boolean hasLegitImage = true;
|
||||||
@ -33,7 +33,7 @@ class GtkMenuBaseItem implements EntryHook {
|
|||||||
// these have to be volatile, because they can be changed from any thread
|
// these have to be volatile, because they can be changed from any thread
|
||||||
private volatile Pointer spacerImage;
|
private volatile Pointer spacerImage;
|
||||||
|
|
||||||
GtkMenuBaseItem() {
|
GtkBaseMenuItem() {
|
||||||
// cannot be done in a static initializer, because the tray icon size might not yet have been determined
|
// cannot be done in a static initializer, because the tray icon size might not yet have been determined
|
||||||
if (transparentIcon == null) {
|
if (transparentIcon == null) {
|
||||||
transparentIcon = ImageUtils.getTransparentImage(ImageUtils.ENTRY_SIZE);
|
transparentIcon = ImageUtils.getTransparentImage(ImageUtils.ENTRY_SIZE);
|
||||||
@ -45,7 +45,6 @@ class GtkMenuBaseItem implements EntryHook {
|
|||||||
return hasLegitImage;
|
return hasLegitImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
|
||||||
void setLegitImage(boolean isLegit) {
|
void setLegitImage(boolean isLegit) {
|
||||||
hasLegitImage = isLegit;
|
hasLegitImage = isLegit;
|
||||||
}
|
}
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.systemTray.nativeUI;
|
package dorkbox.systemTray.nativeUI;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -27,13 +26,13 @@ import dorkbox.systemTray.Entry;
|
|||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.MenuItem;
|
import dorkbox.systemTray.MenuItem;
|
||||||
import dorkbox.systemTray.Separator;
|
import dorkbox.systemTray.Separator;
|
||||||
|
import dorkbox.systemTray.Status;
|
||||||
import dorkbox.systemTray.jna.linux.Gtk;
|
import dorkbox.systemTray.jna.linux.Gtk;
|
||||||
import dorkbox.systemTray.util.MenuHook;
|
import dorkbox.systemTray.peer.MenuPeer;
|
||||||
import dorkbox.systemTray.util.Status;
|
|
||||||
|
|
||||||
class GtkMenu extends GtkMenuBaseItem implements MenuHook {
|
class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||||
// this is a list (that mirrors the actual list) BECAUSE we have to create/delete the entire menu in GTK every time something is changed
|
// this is a list (that mirrors the actual list) BECAUSE we have to create/delete the entire menu in GTK every time something is changed
|
||||||
private final List<GtkMenuBaseItem> menuEntries = new LinkedList<GtkMenuBaseItem>();
|
private final List<GtkBaseMenuItem> menuEntries = new LinkedList<GtkBaseMenuItem>();
|
||||||
|
|
||||||
private final GtkMenu parent;
|
private final GtkMenu parent;
|
||||||
volatile Pointer _nativeMenu; // must ONLY be created at the end of delete!
|
volatile Pointer _nativeMenu; // must ONLY be created at the end of delete!
|
||||||
@ -55,7 +54,7 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook {
|
|||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
_nativeEntry = Gtk.gtk_image_menu_item_new_with_mnemonic(""); // is what is added to the parent menu
|
_nativeEntry = Gtk.gtk_image_menu_item_new_with_mnemonic(""); // is what is added to the parent menu (so images work)
|
||||||
} else {
|
} else {
|
||||||
_nativeEntry = null;
|
_nativeEntry = null;
|
||||||
}
|
}
|
||||||
@ -66,7 +65,7 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
void add(final GtkMenuBaseItem item, final int index) {
|
void add(final GtkBaseMenuItem item, final int index) {
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
menuEntries.add(index, item);
|
menuEntries.add(index, item);
|
||||||
} else {
|
} else {
|
||||||
@ -98,7 +97,7 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook {
|
|||||||
// have to remove all other menu entries
|
// have to remove all other menu entries
|
||||||
synchronized (menuEntries) {
|
synchronized (menuEntries) {
|
||||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||||
final GtkMenuBaseItem menuEntry__ = menuEntries.get(i);
|
final GtkBaseMenuItem menuEntry__ = menuEntries.get(i);
|
||||||
menuEntry__.onDeleteMenu(_nativeMenu);
|
menuEntry__.onDeleteMenu(_nativeMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,13 +135,13 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook {
|
|||||||
// now add back other menu entries
|
// now add back other menu entries
|
||||||
synchronized (menuEntries) {
|
synchronized (menuEntries) {
|
||||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||||
final GtkMenuBaseItem menuEntry__ = menuEntries.get(i);
|
final GtkBaseMenuItem menuEntry__ = menuEntries.get(i);
|
||||||
hasImages |= menuEntry__.hasImage();
|
hasImages |= menuEntry__.hasImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||||
// the menu entry looks FUNKY when there are a mis-match of entries WITH and WITHOUT images
|
// the menu entry looks FUNKY when there are a mis-match of entries WITH and WITHOUT images
|
||||||
final GtkMenuBaseItem menuEntry__ = menuEntries.get(i);
|
final GtkBaseMenuItem menuEntry__ = menuEntries.get(i);
|
||||||
menuEntry__.onCreateMenu(_nativeMenu, hasImages);
|
menuEntry__.onCreateMenu(_nativeMenu, hasImages);
|
||||||
|
|
||||||
if (menuEntry__ instanceof GtkMenu) {
|
if (menuEntry__ instanceof GtkMenu) {
|
||||||
@ -173,10 +172,10 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook {
|
|||||||
synchronized (menuEntries) {
|
synchronized (menuEntries) {
|
||||||
// a copy is made because sub-menus remove themselves from parents when .remove() is called. If we don't
|
// a copy is made because sub-menus remove themselves from parents when .remove() is called. If we don't
|
||||||
// do this, errors will be had because indices don't line up anymore.
|
// do this, errors will be had because indices don't line up anymore.
|
||||||
ArrayList<GtkMenuBaseItem> menuEntriesCopy = new ArrayList<GtkMenuBaseItem>(this.menuEntries);
|
ArrayList<GtkBaseMenuItem> menuEntriesCopy = new ArrayList<GtkBaseMenuItem>(this.menuEntries);
|
||||||
|
|
||||||
for (int i = 0, menuEntriesSize = menuEntriesCopy.size(); i < menuEntriesSize; i++) {
|
for (int i = 0, menuEntriesSize = menuEntriesCopy.size(); i < menuEntriesSize; i++) {
|
||||||
final GtkMenuBaseItem menuEntry__ = menuEntriesCopy.get(i);
|
final GtkBaseMenuItem menuEntry__ = menuEntriesCopy.get(i);
|
||||||
menuEntry__.remove();
|
menuEntry__.remove();
|
||||||
}
|
}
|
||||||
this.menuEntries.clear();
|
this.menuEntries.clear();
|
||||||
@ -354,7 +353,7 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook {
|
|||||||
|
|
||||||
// called when a child removes itself from the parent menu. Does not work for sub-menus
|
// called when a child removes itself from the parent menu. Does not work for sub-menus
|
||||||
public
|
public
|
||||||
void remove(final GtkMenuBaseItem item) {
|
void remove(final GtkBaseMenuItem item) {
|
||||||
synchronized (menuEntries) {
|
synchronized (menuEntries) {
|
||||||
menuEntries.remove(item);
|
menuEntries.remove(item);
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@ import dorkbox.systemTray.SystemTray;
|
|||||||
import dorkbox.systemTray.jna.linux.GCallback;
|
import dorkbox.systemTray.jna.linux.GCallback;
|
||||||
import dorkbox.systemTray.jna.linux.Gobject;
|
import dorkbox.systemTray.jna.linux.Gobject;
|
||||||
import dorkbox.systemTray.jna.linux.Gtk;
|
import dorkbox.systemTray.jna.linux.Gtk;
|
||||||
import dorkbox.systemTray.util.MenuItemHook;
|
import dorkbox.systemTray.peer.MenuItemPeer;
|
||||||
|
|
||||||
class GtkMenuItem extends GtkMenuBaseItem implements MenuItemHook, GCallback {
|
class GtkMenuItem extends GtkBaseMenuItem implements MenuItemPeer, GCallback {
|
||||||
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||||
private final NativeLong nativeLong;
|
private final NativeLong nativeLong;
|
||||||
|
|
||||||
|
@ -26,10 +26,10 @@ import dorkbox.systemTray.SystemTray;
|
|||||||
import dorkbox.systemTray.jna.linux.GCallback;
|
import dorkbox.systemTray.jna.linux.GCallback;
|
||||||
import dorkbox.systemTray.jna.linux.Gobject;
|
import dorkbox.systemTray.jna.linux.Gobject;
|
||||||
import dorkbox.systemTray.jna.linux.Gtk;
|
import dorkbox.systemTray.jna.linux.Gtk;
|
||||||
|
import dorkbox.systemTray.peer.CheckboxPeer;
|
||||||
import dorkbox.systemTray.util.ImageUtils;
|
import dorkbox.systemTray.util.ImageUtils;
|
||||||
import dorkbox.systemTray.util.MenuCheckboxHook;
|
|
||||||
|
|
||||||
class GtkMenuItemCheckbox extends GtkMenuBaseItem implements MenuCheckboxHook, GCallback {
|
class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCallback {
|
||||||
private static File transparentIcon = null;
|
private static File transparentIcon = null;
|
||||||
|
|
||||||
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||||
|
@ -18,9 +18,9 @@ package dorkbox.systemTray.nativeUI;
|
|||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
import dorkbox.systemTray.jna.linux.Gtk;
|
import dorkbox.systemTray.jna.linux.Gtk;
|
||||||
import dorkbox.systemTray.util.EntryHook;
|
import dorkbox.systemTray.peer.EntryPeer;
|
||||||
|
|
||||||
class GtkMenuItemSeparator extends GtkMenuBaseItem implements EntryHook {
|
class GtkMenuItemSeparator extends GtkBaseMenuItem implements EntryPeer {
|
||||||
|
|
||||||
private final GtkMenu parent;
|
private final GtkMenu parent;
|
||||||
private final Pointer _native = Gtk.gtk_separator_menu_item_new();
|
private final Pointer _native = Gtk.gtk_separator_menu_item_new();
|
||||||
|
@ -17,13 +17,13 @@ package dorkbox.systemTray.nativeUI;
|
|||||||
|
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.Status;
|
||||||
import dorkbox.systemTray.jna.linux.Gtk;
|
import dorkbox.systemTray.jna.linux.Gtk;
|
||||||
import dorkbox.systemTray.util.MenuStatusHook;
|
import dorkbox.systemTray.peer.StatusPeer;
|
||||||
import dorkbox.systemTray.util.Status;
|
|
||||||
|
|
||||||
// you might wonder WHY this extends MenuEntryItem -- the reason is that an AppIndicator "status" will be offset from everyone else,
|
// you might wonder WHY this extends MenuEntryItem -- the reason is that an AppIndicator "status" will be offset from everyone else,
|
||||||
// where a GtkStatusIconTray + SwingUI will have everything lined up. (with or without icons). This is to normalize how it looks
|
// where a GtkStatusIconTray + SwingUI will have everything lined up. (with or without icons). This is to normalize how it looks
|
||||||
class GtkMenuItemStatus extends GtkMenuBaseItem implements MenuStatusHook {
|
class GtkMenuItemStatus extends GtkBaseMenuItem implements StatusPeer {
|
||||||
|
|
||||||
private final GtkMenu parent;
|
private final GtkMenu parent;
|
||||||
private final Pointer _native = Gtk.gtk_image_menu_item_new_with_mnemonic("");
|
private final Pointer _native = Gtk.gtk_image_menu_item_new_with_mnemonic("");
|
||||||
|
@ -23,9 +23,8 @@ package dorkbox.systemTray.nativeUI;
|
|||||||
* the system (with the exception of Windows, whose native menu looks absolutely terrible).
|
* the system (with the exception of Windows, whose native menu looks absolutely terrible).
|
||||||
* <p>
|
* <p>
|
||||||
* Noticeable differences that are limitations for the NativeUI only:
|
* Noticeable differences that are limitations for the NativeUI only:
|
||||||
* - AppIndicator Status entries must be plain text (they are not bold as they are everywhere else).
|
* - AppIndicator Status entries must be plain text (they are not bold as they are everywhere else).
|
||||||
* - MacOS cannot have images in their menu or sub-menu's -- only plain text is possible
|
* - MacOS cannot have images in their menu or sub-menu's -- only plain text is possible
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
interface NativeUI
|
interface NativeUI {}
|
||||||
{}
|
|
||||||
|
@ -157,13 +157,13 @@ class _AppIndicatorNativeTray extends Tray implements NativeUI {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setText(final MenuItem menuItem) {
|
void setText(final MenuItem menuItem) {
|
||||||
// no op
|
// no op.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setShortcut(final MenuItem menuItem) {
|
void setShortcut(final MenuItem menuItem) {
|
||||||
// no op
|
// no op.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -38,7 +38,7 @@ import dorkbox.util.SwingUtil;
|
|||||||
* http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6453521
|
* http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6453521
|
||||||
* https://stackoverflow.com/questions/331407/java-trayicon-using-image-with-transparent-background/3882028#3882028
|
* https://stackoverflow.com/questions/331407/java-trayicon-using-image-with-transparent-background/3882028#3882028
|
||||||
*
|
*
|
||||||
* Also, on linux, this WILL NOT CLOSE properly -- there is a frame handle that keeps the JVM open
|
* Also, on linux, this WILL NOT CLOSE properly -- there is a frame handle that keeps the JVM open. MacOS does not have this problem.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter", "WeakerAccess"})
|
@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter", "WeakerAccess"})
|
||||||
public
|
public
|
||||||
@ -157,7 +157,7 @@ class _AwtTray extends Tray implements NativeUI {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setText(final MenuItem menuItem) {
|
void setText(final MenuItem menuItem) {
|
||||||
// no op
|
// no op.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
35
src/dorkbox/systemTray/peer/CheckboxPeer.java
Normal file
35
src/dorkbox/systemTray/peer/CheckboxPeer.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.systemTray.peer;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.Checkbox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal component used to bind the API to the implementation
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
interface CheckboxPeer extends EntryPeer {
|
||||||
|
|
||||||
|
void setEnabled(Checkbox menuItem);
|
||||||
|
|
||||||
|
void setText(Checkbox menuItem);
|
||||||
|
|
||||||
|
void setCallback(Checkbox menuItem);
|
||||||
|
|
||||||
|
void setShortcut(Checkbox menuItem);
|
||||||
|
|
||||||
|
void setChecked(Checkbox checkbox);
|
||||||
|
}
|
24
src/dorkbox/systemTray/peer/EntryPeer.java
Normal file
24
src/dorkbox/systemTray/peer/EntryPeer.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.systemTray.peer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal component used to bind the API to the implementation
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
interface EntryPeer {
|
||||||
|
void remove();
|
||||||
|
}
|
34
src/dorkbox/systemTray/peer/MenuItemPeer.java
Normal file
34
src/dorkbox/systemTray/peer/MenuItemPeer.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.systemTray.peer;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.MenuItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal component used to bind the API to the implementation
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
interface MenuItemPeer extends EntryPeer {
|
||||||
|
void setImage(MenuItem menuItem);
|
||||||
|
|
||||||
|
void setEnabled(MenuItem menuItem);
|
||||||
|
|
||||||
|
void setText(MenuItem menuItem);
|
||||||
|
|
||||||
|
void setCallback(MenuItem menuItem);
|
||||||
|
|
||||||
|
void setShortcut(MenuItem menuItem);
|
||||||
|
}
|
27
src/dorkbox/systemTray/peer/MenuPeer.java
Normal file
27
src/dorkbox/systemTray/peer/MenuPeer.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.systemTray.peer;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.Entry;
|
||||||
|
import dorkbox.systemTray.Menu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal component used to bind the API to the implementation
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
interface MenuPeer extends MenuItemPeer {
|
||||||
|
void add(Menu parentMenu, Entry entry, int index);
|
||||||
|
}
|
26
src/dorkbox/systemTray/peer/StatusPeer.java
Normal file
26
src/dorkbox/systemTray/peer/StatusPeer.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.systemTray.peer;
|
||||||
|
|
||||||
|
import dorkbox.systemTray.Status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal component used to bind the API to the implementation
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
interface StatusPeer extends EntryPeer {
|
||||||
|
void setText(Status menuItem);
|
||||||
|
}
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.systemTray.swingUI;
|
package dorkbox.systemTray.swingUI;
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
@ -26,15 +25,14 @@ import dorkbox.systemTray.Entry;
|
|||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
import dorkbox.systemTray.MenuItem;
|
import dorkbox.systemTray.MenuItem;
|
||||||
import dorkbox.systemTray.Separator;
|
import dorkbox.systemTray.Separator;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.Status;
|
||||||
import dorkbox.systemTray.util.MenuHook;
|
import dorkbox.systemTray.peer.MenuPeer;
|
||||||
import dorkbox.systemTray.util.Status;
|
|
||||||
import dorkbox.systemTray.util.SystemTrayFixes;
|
import dorkbox.systemTray.util.SystemTrayFixes;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
// this is a weird composite class, because it must be a Menu, but ALSO a Entry -- so it has both (and duplicate code)
|
// this is a weird composite class, because it must be a Menu, but ALSO a Entry -- so it has both (and duplicate code)
|
||||||
@SuppressWarnings("ForLoopReplaceableByForEach")
|
@SuppressWarnings("ForLoopReplaceableByForEach")
|
||||||
class SwingMenu implements MenuHook {
|
class SwingMenu implements MenuPeer {
|
||||||
|
|
||||||
final JComponent _native;
|
final JComponent _native;
|
||||||
private final SwingMenu parent;
|
private final SwingMenu parent;
|
||||||
@ -89,12 +87,11 @@ class SwingMenu implements MenuHook {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setImage(final MenuItem menuItem) {
|
void setImage(final MenuItem menuItem) {
|
||||||
final File imageFile = menuItem.getImage();
|
|
||||||
|
|
||||||
SwingUtil.invokeLater(new Runnable() {
|
SwingUtil.invokeLater(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
|
File imageFile = menuItem.getImage();
|
||||||
if (imageFile != null) {
|
if (imageFile != null) {
|
||||||
ImageIcon origIcon = new ImageIcon(imageFile.getAbsolutePath());
|
ImageIcon origIcon = new ImageIcon(imageFile.getAbsolutePath());
|
||||||
((AdjustedJMenu) _native).setIcon(origIcon);
|
((AdjustedJMenu) _native).setIcon(origIcon);
|
||||||
@ -179,41 +176,4 @@ class SwingMenu implements MenuHook {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// NOT ALWAYS CALLED ON EDT
|
|
||||||
protected
|
|
||||||
void remove__(final Object menuEntry) {
|
|
||||||
try {
|
|
||||||
// synchronized (menuEntries) {
|
|
||||||
// // null is passed in when a sub-menu is removing itself from us (because they have already called "remove" and have also
|
|
||||||
// // removed themselves from the menuEntries)
|
|
||||||
// if (menuEntry != null) {
|
|
||||||
// for (Iterator<Entry> iterator = menuEntries.iterator(); iterator.hasNext(); ) {
|
|
||||||
// final Entry entry = iterator.next();
|
|
||||||
// if (entry == menuEntry) {
|
|
||||||
// iterator.remove();
|
|
||||||
// entry.remove();
|
|
||||||
// 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 dorkbox.systemTray.Separator) {
|
|
||||||
// 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 dorkbox.systemTray.Separator) {
|
|
||||||
// remove(menuEntries.get(menuEntries.size() - 1));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
} catch (Exception e) {
|
|
||||||
SystemTray.logger.error("Error removing entry from menu.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,11 @@ import javax.swing.JMenuItem;
|
|||||||
|
|
||||||
import dorkbox.systemTray.MenuItem;
|
import dorkbox.systemTray.MenuItem;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
import dorkbox.systemTray.util.MenuItemHook;
|
import dorkbox.systemTray.peer.MenuItemPeer;
|
||||||
import dorkbox.systemTray.util.SystemTrayFixes;
|
import dorkbox.systemTray.util.SystemTrayFixes;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
class SwingMenuItem implements MenuItemHook {
|
class SwingMenuItem implements MenuItemPeer {
|
||||||
|
|
||||||
private final SwingMenu parent;
|
private final SwingMenu parent;
|
||||||
private final JMenuItem _native = new AdjustedJMenuItem();
|
private final JMenuItem _native = new AdjustedJMenuItem();
|
||||||
@ -44,12 +44,11 @@ class SwingMenuItem implements MenuItemHook {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setImage(final MenuItem menuItem) {
|
void setImage(final MenuItem menuItem) {
|
||||||
final File imageFile = menuItem.getImage();
|
|
||||||
|
|
||||||
SwingUtil.invokeLater(new Runnable() {
|
SwingUtil.invokeLater(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
|
File imageFile = menuItem.getImage();
|
||||||
if (imageFile != null) {
|
if (imageFile != null) {
|
||||||
ImageIcon origIcon = new ImageIcon(imageFile.getAbsolutePath());
|
ImageIcon origIcon = new ImageIcon(imageFile.getAbsolutePath());
|
||||||
_native.setIcon(origIcon);
|
_native.setIcon(origIcon);
|
||||||
|
@ -24,12 +24,12 @@ import javax.swing.JMenuItem;
|
|||||||
|
|
||||||
import dorkbox.systemTray.Checkbox;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
|
import dorkbox.systemTray.peer.CheckboxPeer;
|
||||||
import dorkbox.systemTray.util.ImageUtils;
|
import dorkbox.systemTray.util.ImageUtils;
|
||||||
import dorkbox.systemTray.util.MenuCheckboxHook;
|
|
||||||
import dorkbox.systemTray.util.SystemTrayFixes;
|
import dorkbox.systemTray.util.SystemTrayFixes;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
class SwingMenuItemCheckbox implements MenuCheckboxHook {
|
class SwingMenuItemCheckbox implements CheckboxPeer {
|
||||||
|
|
||||||
private final SwingMenu parent;
|
private final SwingMenu parent;
|
||||||
private final JMenuItem _native = new AdjustedJMenuItem();
|
private final JMenuItem _native = new AdjustedJMenuItem();
|
||||||
|
@ -17,10 +17,10 @@ package dorkbox.systemTray.swingUI;
|
|||||||
|
|
||||||
import javax.swing.JSeparator;
|
import javax.swing.JSeparator;
|
||||||
|
|
||||||
import dorkbox.systemTray.util.EntryHook;
|
import dorkbox.systemTray.peer.EntryPeer;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
class SwingMenuItemSeparator implements EntryHook {
|
class SwingMenuItemSeparator implements EntryPeer {
|
||||||
|
|
||||||
private final SwingMenu parent;
|
private final SwingMenu parent;
|
||||||
private final JSeparator _native = new JSeparator(JSeparator.HORIZONTAL);
|
private final JSeparator _native = new JSeparator(JSeparator.HORIZONTAL);
|
||||||
|
@ -19,11 +19,11 @@ import java.awt.Font;
|
|||||||
|
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
|
||||||
import dorkbox.systemTray.util.MenuStatusHook;
|
import dorkbox.systemTray.Status;
|
||||||
import dorkbox.systemTray.util.Status;
|
import dorkbox.systemTray.peer.StatusPeer;
|
||||||
import dorkbox.util.SwingUtil;
|
import dorkbox.util.SwingUtil;
|
||||||
|
|
||||||
class SwingMenuItemStatus implements MenuStatusHook {
|
class SwingMenuItemStatus implements StatusPeer {
|
||||||
|
|
||||||
private final SwingMenu parent;
|
private final SwingMenu parent;
|
||||||
private final JMenuItem _native = new AdjustedJMenuItem();
|
private final JMenuItem _native = new AdjustedJMenuItem();
|
||||||
|
@ -22,9 +22,8 @@ package dorkbox.systemTray.swingUI;
|
|||||||
* one loses the native L&F of the system (with the exception of Windows, whose native menu looks absolutely terrible).
|
* one loses the native L&F of the system (with the exception of Windows, whose native menu looks absolutely terrible).
|
||||||
* <p>
|
* <p>
|
||||||
* Noticeable differences that are limitations for the NativeUI only:
|
* Noticeable differences that are limitations for the NativeUI only:
|
||||||
* - AppIndicator Status entries must be plain text (they are not bold as they are everywhere else).
|
* - AppIndicator Status entries must be plain text (they are not bold as they are everywhere else).
|
||||||
* - MacOS cannot have images in their menu or sub-menu's -- only plain text is possible
|
* - MacOS cannot have images in their menu or sub-menu's -- only plain text is possible
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
interface SwingUI
|
interface SwingUI {}
|
||||||
{}
|
|
||||||
|
@ -40,7 +40,7 @@ import dorkbox.util.ScreenUtil;
|
|||||||
/**
|
/**
|
||||||
* This custom popup is required if we want to be able to show images on the menu,
|
* This custom popup is required if we want to be able to show images on the menu,
|
||||||
*
|
*
|
||||||
* This is our "golden standard" since we have 100% control over it.
|
* This is our "golden standard" since we have 100% control over it on all platforms
|
||||||
*/
|
*/
|
||||||
class TrayPopup extends JPopupMenu {
|
class TrayPopup extends JPopupMenu {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ -41,15 +41,15 @@ import dorkbox.util.SwingUtil;
|
|||||||
* <p/>
|
* <p/>
|
||||||
* This is the "old" way to do it, and does not work with some desktop environments. This is a hybrid class, because we want to show the
|
* This is the "old" way to do it, and does not work with some desktop environments. This is a hybrid class, because we want to show the
|
||||||
* swing menu popup INSTEAD of GTK menu popups. The "golden standard" is our swing menu popup, since we have 100% control over it.
|
* swing menu popup INSTEAD of GTK menu popups. The "golden standard" is our swing menu popup, since we have 100% control over it.
|
||||||
|
*
|
||||||
|
* http://code.metager.de/source/xref/gnome/Platform/gtk%2B/gtk/deprecated/gtkstatusicon.c
|
||||||
|
* https://github.com/djdeath/glib/blob/master/gobject/gobject.c
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("Duplicates")
|
@SuppressWarnings("Duplicates")
|
||||||
public
|
public
|
||||||
class _GtkStatusIconTray extends Tray implements SwingUI {
|
class _GtkStatusIconTray extends Tray implements SwingUI {
|
||||||
private volatile Pointer trayIcon;
|
private volatile Pointer trayIcon;
|
||||||
|
|
||||||
// http://code.metager.de/source/xref/gnome/Platform/gtk%2B/gtk/deprecated/gtkstatusicon.c
|
|
||||||
// https://github.com/djdeath/glib/blob/master/gobject/gobject.c
|
|
||||||
|
|
||||||
// have to save these in a field to prevent GC on the objects (since they go out-of-scope from java)
|
// have to save these in a field to prevent GC on the objects (since they go out-of-scope from java)
|
||||||
private final List<Object> gtkCallbacks = new ArrayList<Object>();
|
private final List<Object> gtkCallbacks = new ArrayList<Object>();
|
||||||
|
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
package dorkbox.systemTray.util;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
interface EntryHook {
|
|
||||||
void remove();
|
|
||||||
}
|
|
@ -1,243 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.systemTray.util;
|
|
||||||
|
|
||||||
|
|
||||||
import dorkbox.systemTray.Menu;
|
|
||||||
|
|
||||||
// this is a weird composite class, because it must be a Menu, but ALSO a Entry -- so it has both
|
|
||||||
@SuppressWarnings("ForLoopReplaceableByForEach")
|
|
||||||
public abstract
|
|
||||||
class MenuBase extends Menu {
|
|
||||||
// /**
|
|
||||||
// * Called in the EDT/GTK dispatch threads
|
|
||||||
// *
|
|
||||||
// * @param systemTray the system tray (which is the object that sits in the system tray)
|
|
||||||
// * @param parent the parent of this menu, null if the parent is the system tray
|
|
||||||
// */
|
|
||||||
// public
|
|
||||||
// MenuBase(final SystemTray systemTray, final Menu parent) {
|
|
||||||
// setSystemTray(systemTray);
|
|
||||||
// setParent(parent);
|
|
||||||
// }
|
|
||||||
|
|
||||||
protected abstract
|
|
||||||
void dispatch(final Runnable runnable);
|
|
||||||
|
|
||||||
protected abstract
|
|
||||||
void dispatchAndWait(final Runnable runnable);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will add a new menu entry
|
|
||||||
* NOT ALWAYS CALLED ON DISPATCH
|
|
||||||
*/
|
|
||||||
// protected abstract
|
|
||||||
// Entry addEntry_(final String menuText, final File imagePath, final ActionListener callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will add a new checkbox menu entry
|
|
||||||
* NOT ALWAYS CALLED ON DISPATCH
|
|
||||||
*/
|
|
||||||
// protected abstract
|
|
||||||
// Checkbox addCheckbox_(final String menuText, final ActionListener callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will add a new sub-menu entry
|
|
||||||
* NOT ALWAYS CALLED ON DISPATCH
|
|
||||||
*/
|
|
||||||
// protected abstract
|
|
||||||
// Menu addMenu_(final String menuText, final File imagePath);
|
|
||||||
|
|
||||||
|
|
||||||
// // public here so that Swing/Gtk/AppIndicator can override this
|
|
||||||
// protected abstract
|
|
||||||
// void setImage_(final File imageFile);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: buggy. The menu will **sometimes** stop responding to the "enter" key after this. Mnemonics still work however.
|
|
||||||
// public
|
|
||||||
// Entry addWidget(final JComponent widget) {
|
|
||||||
// if (widget == null) {
|
|
||||||
// throw new NullPointerException("Widget cannot be null");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final AtomicReference<Entry> value = new AtomicReference<Entry>();
|
|
||||||
//
|
|
||||||
// dispatchAndWait(new Runnable() {
|
|
||||||
// @Override
|
|
||||||
// public
|
|
||||||
// void run() {
|
|
||||||
// synchronized (menuEntries) {
|
|
||||||
// // must always be called on the EDT
|
|
||||||
// Entry entry = new EntryWidget(MenuImpl.this, widget);
|
|
||||||
// value.set(entry);
|
|
||||||
// menuEntries.add(entry);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// return value.get();
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// public final
|
|
||||||
// Entry get(final String menuText) {
|
|
||||||
// if (menuText == null || menuText.isEmpty()) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Must be wrapped in a synchronized block for object visibility
|
|
||||||
// synchronized (menuEntries) {
|
|
||||||
// for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
|
||||||
// final Entry entry = menuEntries.get(i);
|
|
||||||
//
|
|
||||||
// if (entry instanceof Separator || entry instanceof Status) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//// String text = entry.getText();
|
|
||||||
//
|
|
||||||
// // text can be null
|
|
||||||
//// if (menuText.equals(text)) {
|
|
||||||
//// return entry;
|
|
||||||
//// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * This removes a menu entry from the dropdown menu.
|
|
||||||
// *
|
|
||||||
// * @param entry This is the menu entry to remove
|
|
||||||
// */
|
|
||||||
// @Override
|
|
||||||
// public final
|
|
||||||
// void remove(final Entry entry) {
|
|
||||||
// if (entry == null) {
|
|
||||||
// throw new NullPointerException("No menu entry exists for entry");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// dispatchAndWait(new Runnable() {
|
|
||||||
// @Override
|
|
||||||
// public
|
|
||||||
// void run() {
|
|
||||||
// remove__(entry);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * This removes a sub-menu entry from the dropdown menu.
|
|
||||||
// *
|
|
||||||
// * @param menu This is the menu entry to remove
|
|
||||||
// */
|
|
||||||
// @Override
|
|
||||||
// public final
|
|
||||||
// void remove(final Menu menu) {
|
|
||||||
// final Menu parent = getParent();
|
|
||||||
// if (parent == null) {
|
|
||||||
// // we are the system tray menu, so we just remove from ourselves
|
|
||||||
// dispatchAndWait(new Runnable() {
|
|
||||||
// @Override
|
|
||||||
// public
|
|
||||||
// void run() {
|
|
||||||
// remove__(menu);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// final Menu _this = this;
|
|
||||||
// // we are a submenu
|
|
||||||
// dispatchAndWait(new Runnable() {
|
|
||||||
// @Override
|
|
||||||
// public
|
|
||||||
// void run() {
|
|
||||||
// ((MenuBase) parent).remove__(_this);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * This removes a menu entry or sub-menu (via the text label) from the dropdown menu.
|
|
||||||
// *
|
|
||||||
// * @param menuText This is the label for the menu entry or sub-menu to remove
|
|
||||||
// */
|
|
||||||
// public final
|
|
||||||
// void remove(final String menuText) {
|
|
||||||
// dispatchAndWait(new Runnable() {
|
|
||||||
// @Override
|
|
||||||
// public
|
|
||||||
// void run() {
|
|
||||||
// synchronized (menuEntries) {
|
|
||||||
// Entry entry = get(menuText);
|
|
||||||
//
|
|
||||||
// if (entry != null) {
|
|
||||||
// remove(entry);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public final
|
|
||||||
// void removeAll() {
|
|
||||||
// dispatch(new Runnable() {
|
|
||||||
// @Override
|
|
||||||
// public
|
|
||||||
// void run() {
|
|
||||||
// synchronized (menuEntries) {
|
|
||||||
// // have to make copy because we are deleting all of them, and sub-menus remove themselves from parents
|
|
||||||
// ArrayList<Entry> menuEntriesCopy = new ArrayList<Entry>(MenuBase.this.menuEntries);
|
|
||||||
// for (Entry entry : menuEntriesCopy) {
|
|
||||||
// entry.remove();
|
|
||||||
// }
|
|
||||||
// menuEntries.clear();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package dorkbox.systemTray.util;
|
|
||||||
|
|
||||||
import dorkbox.systemTray.Checkbox;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
interface MenuCheckboxHook extends EntryHook {
|
|
||||||
|
|
||||||
void setEnabled(Checkbox menuItem);
|
|
||||||
|
|
||||||
void setText(Checkbox menuItem);
|
|
||||||
|
|
||||||
void setCallback(Checkbox menuItem);
|
|
||||||
|
|
||||||
void setShortcut(Checkbox menuItem);
|
|
||||||
|
|
||||||
void setChecked(Checkbox checkbox);
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
package dorkbox.systemTray.util;
|
|
||||||
|
|
||||||
import dorkbox.systemTray.Entry;
|
|
||||||
import dorkbox.systemTray.Menu;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
interface MenuHook extends MenuItemHook {
|
|
||||||
void add(Menu parentMenu, Entry entry, int index);
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package dorkbox.systemTray.util;
|
|
||||||
|
|
||||||
import dorkbox.systemTray.MenuItem;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
interface MenuItemHook extends EntryHook {
|
|
||||||
void setImage(MenuItem menuItem);
|
|
||||||
|
|
||||||
void setEnabled(MenuItem menuItem);
|
|
||||||
|
|
||||||
void setText(MenuItem menuItem);
|
|
||||||
|
|
||||||
void setCallback(MenuItem menuItem);
|
|
||||||
|
|
||||||
void setShortcut(MenuItem menuItem);
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package dorkbox.systemTray.util;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
interface MenuStatusHook extends EntryHook {
|
|
||||||
void setText(Status menuItem);
|
|
||||||
}
|
|
@ -21,8 +21,9 @@ import java.awt.event.ActionListener;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import dorkbox.systemTray.Checkbox;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.Entry;
|
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
|
import dorkbox.systemTray.MenuItem;
|
||||||
|
import dorkbox.systemTray.Separator;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +52,6 @@ class TestTray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SystemTray systemTray;
|
private SystemTray systemTray;
|
||||||
private ActionListener callbackGreen;
|
|
||||||
private ActionListener callbackGray;
|
private ActionListener callbackGray;
|
||||||
|
|
||||||
public
|
public
|
||||||
@ -61,23 +61,32 @@ class TestTray {
|
|||||||
throw new RuntimeException("Unable to load SystemTray!");
|
throw new RuntimeException("Unable to load SystemTray!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// final JPopupMenu popupMenu = new JPopupMenu();
|
|
||||||
// JMenu submenu2 = new JMenu("SubMenu1");
|
|
||||||
// submenu2.add("asdf");
|
|
||||||
// submenu2.add("asdf");
|
|
||||||
//
|
|
||||||
// // Add submenu to popup menu
|
|
||||||
// popupMenu.add(submenu2);
|
|
||||||
|
|
||||||
|
|
||||||
systemTray.setImage(LT_GRAY_TRAIN);
|
systemTray.setImage(LT_GRAY_TRAIN);
|
||||||
systemTray.setStatus("No Mail");
|
systemTray.setStatus("No Mail");
|
||||||
|
|
||||||
callbackGreen = new ActionListener() {
|
callbackGray = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
final Entry entry = (Entry) e.getSource();
|
final MenuItem entry = (MenuItem) e.getSource();
|
||||||
|
systemTray.setStatus(null);
|
||||||
|
systemTray.setImage(BLACK_TRAIN);
|
||||||
|
|
||||||
|
entry.setCallback(null);
|
||||||
|
// systemTray.setStatus("Mail Empty");
|
||||||
|
systemTray.getMenu().remove(entry);
|
||||||
|
System.err.println("POW");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Menu mainMenu = systemTray.getMenu();
|
||||||
|
|
||||||
|
MenuItem greenEntry = new MenuItem("Green Mail", new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void actionPerformed(final ActionEvent e) {
|
||||||
|
final MenuItem entry = (MenuItem) e.getSource();
|
||||||
systemTray.setStatus("Some Mail!");
|
systemTray.setStatus("Some Mail!");
|
||||||
systemTray.setImage(GREEN_TRAIN);
|
systemTray.setImage(GREEN_TRAIN);
|
||||||
|
|
||||||
@ -86,76 +95,79 @@ class TestTray {
|
|||||||
entry.setText("Delete Mail");
|
entry.setText("Delete Mail");
|
||||||
// systemTray.remove(menuEntry);
|
// systemTray.remove(menuEntry);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
greenEntry.setImage(GREEN_MAIL);
|
||||||
|
// case does not matter
|
||||||
|
greenEntry.setShortcut('G');
|
||||||
|
mainMenu.add(greenEntry);
|
||||||
|
|
||||||
callbackGray = new ActionListener() {
|
|
||||||
|
Checkbox checkbox = new Checkbox("Euro € Mail", new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
final Entry entry = (Entry) e.getSource();
|
System.err.println("Am i checked? " + ((Checkbox) e.getSource()).getChecked());
|
||||||
systemTray.setStatus(null);
|
|
||||||
systemTray.setImage(BLACK_TRAIN);
|
|
||||||
|
|
||||||
entry.setCallback(null);
|
|
||||||
// systemTray.setStatus("Mail Empty");
|
|
||||||
systemTray.remove(entry);
|
|
||||||
System.err.println("POW");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Entry menuEntry = this.systemTray.addEntry("Green Mail", GREEN_MAIL, callbackGreen);
|
|
||||||
// case does not matter
|
|
||||||
menuEntry.setShortcut('G');
|
|
||||||
|
|
||||||
final Checkbox menuCheckbox = this.systemTray.addCheckbox("Euro € Mail", callbackGreen);
|
|
||||||
// case does not matter
|
|
||||||
// menuCheckbox.setShortcut('€');
|
|
||||||
|
|
||||||
this.systemTray.addSeparator();
|
|
||||||
|
|
||||||
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
|
|
||||||
submenu.setShortcut('t');
|
|
||||||
submenu.addEntry("Disable menu", BLACK_BUS, new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void actionPerformed(final ActionEvent e) {
|
|
||||||
submenu.setEnabled(false);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
checkbox.setShortcut('€');
|
||||||
|
mainMenu.add(checkbox);
|
||||||
|
|
||||||
|
mainMenu.add(new Separator());
|
||||||
|
|
||||||
|
|
||||||
|
Menu submenu = new Menu("Options", BLUE_CAMPING);
|
||||||
|
submenu.setShortcut('t');
|
||||||
|
mainMenu.add(submenu);
|
||||||
|
|
||||||
|
MenuItem disableMenu = new MenuItem("Disable menu", BLACK_BUS, new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void actionPerformed(final ActionEvent e) {
|
||||||
|
MenuItem source = (MenuItem) e.getSource();
|
||||||
|
source.getParent().setEnabled(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
submenu.add(disableMenu);
|
||||||
|
|
||||||
|
|
||||||
// TODO: buggy. The menu will **sometimes** stop responding to the "enter" key after this. Mnemonics still work however.
|
// TODO: buggy. The menu will **sometimes** stop responding to the "enter" key after this. Mnemonics still work however.
|
||||||
// submenu.addEntry("Add widget", GREEN_BUS, new Action() {
|
// submenu.add(new MenuItem("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
||||||
// @Override
|
// @Override
|
||||||
// public
|
// public
|
||||||
// void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
// void actionPerformed(final ActionEvent e) {
|
||||||
|
// MenuItem source = (MenuItem) e.getSource();
|
||||||
// JProgressBar progressBar = new JProgressBar(0, 100);
|
// JProgressBar progressBar = new JProgressBar(0, 100);
|
||||||
// progressBar.setValue(new Random().nextInt(101));
|
// progressBar.setValue(new Random().nextInt(101));
|
||||||
// progressBar.setStringPainted(true);
|
// progressBar.setStringPainted(true);
|
||||||
// systemTray.addWidget(progressBar);
|
// source.getSystemTray().add(progressBar);
|
||||||
// }
|
// }
|
||||||
// });
|
// }));
|
||||||
submenu.addEntry("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
|
||||||
|
|
||||||
|
submenu.add(new MenuItem("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
systemTray.setEnabled(false);
|
systemTray.setEnabled(false);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() {
|
submenu.add(new MenuItem("Remove menu", BLACK_FIRE, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
submenu.remove();
|
MenuItem source = (MenuItem) e.getSource();
|
||||||
|
source.getParent().remove();
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
|
|
||||||
systemTray.addEntry("Quit", new ActionListener() {
|
systemTray.getMenu().add(new MenuItem("Quit", new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
systemTray.shutdown();
|
systemTray.shutdown();
|
||||||
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
||||||
}
|
}
|
||||||
}).setShortcut('q'); // case does not matter
|
})).setShortcut('q'); // case does not matter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,10 @@ package dorkbox;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
|
import dorkbox.systemTray.MenuItem;
|
||||||
|
import dorkbox.systemTray.Separator;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
@ -95,11 +97,29 @@ class TestTrayJavaFX extends Application {
|
|||||||
systemTray.setImage(LT_GRAY_TRAIN);
|
systemTray.setImage(LT_GRAY_TRAIN);
|
||||||
systemTray.setStatus("No Mail");
|
systemTray.setStatus("No Mail");
|
||||||
|
|
||||||
callbackGreen = new ActionListener() {
|
callbackGray = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
final Entry entry = (Entry) e.getSource();
|
final MenuItem entry = (MenuItem) e.getSource();
|
||||||
|
systemTray.setStatus(null);
|
||||||
|
systemTray.setImage(BLACK_TRAIN);
|
||||||
|
|
||||||
|
entry.setCallback(null);
|
||||||
|
// systemTray.setStatus("Mail Empty");
|
||||||
|
systemTray.getMenu().remove(entry);
|
||||||
|
System.err.println("POW");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Menu mainMenu = systemTray.getMenu();
|
||||||
|
|
||||||
|
MenuItem greenEntry = new MenuItem("Green Mail", new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
|
final MenuItem entry = (MenuItem) e.getSource();
|
||||||
systemTray.setStatus("Some Mail!");
|
systemTray.setStatus("Some Mail!");
|
||||||
systemTray.setImage(GREEN_TRAIN);
|
systemTray.setImage(GREEN_TRAIN);
|
||||||
|
|
||||||
@ -108,69 +128,73 @@ class TestTrayJavaFX extends Application {
|
|||||||
entry.setText("Delete Mail");
|
entry.setText("Delete Mail");
|
||||||
// systemTray.remove(menuEntry);
|
// systemTray.remove(menuEntry);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
greenEntry.setImage(GREEN_MAIL);
|
||||||
|
// case does not matter
|
||||||
|
greenEntry.setShortcut('G');
|
||||||
|
mainMenu.add(greenEntry);
|
||||||
|
|
||||||
callbackGray = new ActionListener() {
|
|
||||||
|
Checkbox checkbox = new Checkbox("Euro € Mail", new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
final Entry entry = (Entry) e.getSource();
|
System.err.println("Am i checked? " + ((Checkbox) e.getSource()).getChecked());
|
||||||
systemTray.setStatus(null);
|
|
||||||
systemTray.setImage(BLACK_TRAIN);
|
|
||||||
|
|
||||||
entry.setCallback(null);
|
|
||||||
// systemTray.setStatus("Mail Empty");
|
|
||||||
systemTray.remove(entry);
|
|
||||||
System.err.println("POW");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Entry menuEntry = this.systemTray.addEntry("Green Mail", GREEN_MAIL, callbackGreen);
|
|
||||||
// case does not matter
|
|
||||||
menuEntry.setShortcut('G');
|
|
||||||
|
|
||||||
menuEntry = this.systemTray.addEntry("Euro € Mail", GREEN_MAIL, callbackGreen);
|
|
||||||
// case does not matter
|
|
||||||
menuEntry.setShortcut('€');
|
|
||||||
|
|
||||||
this.systemTray.addSeparator();
|
|
||||||
|
|
||||||
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
|
|
||||||
submenu.setShortcut('t');
|
|
||||||
submenu.addEntry("Disable menu", BLACK_BUS, new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
|
||||||
submenu.setEnabled(false);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
checkbox.setShortcut('€');
|
||||||
|
mainMenu.add(checkbox);
|
||||||
|
|
||||||
|
mainMenu.add(new Separator());
|
||||||
|
|
||||||
|
|
||||||
|
Menu submenu = new Menu("Options", BLUE_CAMPING);
|
||||||
|
submenu.setShortcut('t');
|
||||||
|
mainMenu.add(submenu);
|
||||||
|
|
||||||
|
MenuItem disableMenu = new MenuItem("Disable menu", BLACK_BUS, new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
|
MenuItem source = (MenuItem) e.getSource();
|
||||||
|
source.getParent().setEnabled(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
submenu.add(disableMenu);
|
||||||
|
|
||||||
|
|
||||||
// TODO: buggy. The menu will **sometimes** stop responding to the "enter" key after this. Mnemonics still work however.
|
// TODO: buggy. The menu will **sometimes** stop responding to the "enter" key after this. Mnemonics still work however.
|
||||||
// submenu.addEntry("Add widget", GREEN_BUS, new Action() {
|
// submenu.add(new MenuItem("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
||||||
// @Override
|
// @Override
|
||||||
// public
|
// public
|
||||||
// void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
// void actionPerformed(final ActionEvent e) {
|
||||||
|
// MenuItem source = (MenuItem) e.getSource();
|
||||||
// JProgressBar progressBar = new JProgressBar(0, 100);
|
// JProgressBar progressBar = new JProgressBar(0, 100);
|
||||||
// progressBar.setValue(new Random().nextInt(101));
|
// progressBar.setValue(new Random().nextInt(101));
|
||||||
// progressBar.setStringPainted(true);
|
// progressBar.setStringPainted(true);
|
||||||
// systemTray.addWidget(progressBar);
|
// source.getSystemTray().add(progressBar);
|
||||||
// }
|
// }
|
||||||
// });
|
// }));
|
||||||
submenu.addEntry("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
|
||||||
|
|
||||||
|
submenu.add(new MenuItem("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
systemTray.setEnabled(false);
|
systemTray.setEnabled(false);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() {
|
submenu.add(new MenuItem("Remove menu", BLACK_FIRE, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
submenu.remove();
|
MenuItem source = (MenuItem) e.getSource();
|
||||||
|
source.getParent().remove();
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
systemTray.addEntry("Quit", new ActionListener() {
|
|
||||||
|
systemTray.getMenu().add(new MenuItem("Quit", new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final java.awt.event.ActionEvent e) {
|
||||||
@ -178,6 +202,6 @@ class TestTrayJavaFX extends Application {
|
|||||||
Platform.exit(); // necessary to close javaFx
|
Platform.exit(); // necessary to close javaFx
|
||||||
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
||||||
}
|
}
|
||||||
}).setShortcut('q'); // case does not matter
|
})).setShortcut('q'); // case does not matter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package dorkbox;
|
package dorkbox;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
@ -24,8 +25,10 @@ import org.eclipse.swt.widgets.Display;
|
|||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
|
|
||||||
import dorkbox.systemTray.Entry;
|
import dorkbox.systemTray.Checkbox;
|
||||||
import dorkbox.systemTray.Menu;
|
import dorkbox.systemTray.Menu;
|
||||||
|
import dorkbox.systemTray.MenuItem;
|
||||||
|
import dorkbox.systemTray.Separator;
|
||||||
import dorkbox.systemTray.SystemTray;
|
import dorkbox.systemTray.SystemTray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,11 +82,29 @@ class TestTraySwt {
|
|||||||
systemTray.setImage(LT_GRAY_TRAIN);
|
systemTray.setImage(LT_GRAY_TRAIN);
|
||||||
systemTray.setStatus("No Mail");
|
systemTray.setStatus("No Mail");
|
||||||
|
|
||||||
callbackGreen = new ActionListener() {
|
callbackGray = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
final Entry entry = (Entry) e.getSource();
|
final MenuItem entry = (MenuItem) e.getSource();
|
||||||
|
systemTray.setStatus(null);
|
||||||
|
systemTray.setImage(BLACK_TRAIN);
|
||||||
|
|
||||||
|
entry.setCallback(null);
|
||||||
|
// systemTray.setStatus("Mail Empty");
|
||||||
|
systemTray.getMenu().remove(entry);
|
||||||
|
System.err.println("POW");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Menu mainMenu = systemTray.getMenu();
|
||||||
|
|
||||||
|
MenuItem greenEntry = new MenuItem("Green Mail", new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void actionPerformed(final ActionEvent e) {
|
||||||
|
final MenuItem entry = (MenuItem) e.getSource();
|
||||||
systemTray.setStatus("Some Mail!");
|
systemTray.setStatus("Some Mail!");
|
||||||
systemTray.setImage(GREEN_TRAIN);
|
systemTray.setImage(GREEN_TRAIN);
|
||||||
|
|
||||||
@ -92,84 +113,86 @@ class TestTraySwt {
|
|||||||
entry.setText("Delete Mail");
|
entry.setText("Delete Mail");
|
||||||
// systemTray.remove(menuEntry);
|
// systemTray.remove(menuEntry);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
greenEntry.setImage(GREEN_MAIL);
|
||||||
|
// case does not matter
|
||||||
|
greenEntry.setShortcut('G');
|
||||||
|
mainMenu.add(greenEntry);
|
||||||
|
|
||||||
callbackGray = new ActionListener() {
|
|
||||||
|
Checkbox checkbox = new Checkbox("Euro € Mail", new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
final Entry entry = (Entry) e.getSource();
|
System.err.println("Am i checked? " + ((Checkbox) e.getSource()).getChecked());
|
||||||
systemTray.setStatus(null);
|
|
||||||
systemTray.setImage(BLACK_TRAIN);
|
|
||||||
|
|
||||||
entry.setCallback(null);
|
|
||||||
// systemTray.setStatus("Mail Empty");
|
|
||||||
systemTray.remove(entry);
|
|
||||||
System.err.println("POW");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Entry menuEntry = this.systemTray.addEntry("Green Mail", GREEN_MAIL, callbackGreen);
|
|
||||||
// case does not matter
|
|
||||||
menuEntry.setShortcut('G');
|
|
||||||
|
|
||||||
menuEntry = this.systemTray.addEntry("Euro € Mail", GREEN_MAIL, callbackGreen);
|
|
||||||
// case does not matter
|
|
||||||
menuEntry.setShortcut('€');
|
|
||||||
|
|
||||||
this.systemTray.addSeparator();
|
|
||||||
|
|
||||||
final Menu submenu = this.systemTray.addMenu("Options", BLUE_CAMPING);
|
|
||||||
submenu.setShortcut('t');
|
|
||||||
submenu.addEntry("Disable menu", BLACK_BUS, new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
|
||||||
submenu.setEnabled(false);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
checkbox.setShortcut('€');
|
||||||
|
mainMenu.add(checkbox);
|
||||||
|
|
||||||
|
mainMenu.add(new Separator());
|
||||||
|
|
||||||
|
|
||||||
|
Menu submenu = new Menu("Options", BLUE_CAMPING);
|
||||||
|
submenu.setShortcut('t');
|
||||||
|
mainMenu.add(submenu);
|
||||||
|
|
||||||
|
MenuItem disableMenu = new MenuItem("Disable menu", BLACK_BUS, new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void actionPerformed(final ActionEvent e) {
|
||||||
|
MenuItem source = (MenuItem) e.getSource();
|
||||||
|
source.getParent().setEnabled(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
submenu.add(disableMenu);
|
||||||
|
|
||||||
|
|
||||||
// TODO: buggy. The menu will **sometimes** stop responding to the "enter" key after this. Mnemonics still work however.
|
// TODO: buggy. The menu will **sometimes** stop responding to the "enter" key after this. Mnemonics still work however.
|
||||||
// submenu.addEntry("Add widget", GREEN_BUS, new Action() {
|
// submenu.add(new MenuItem("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
||||||
// @Override
|
// @Override
|
||||||
// public
|
// public
|
||||||
// void onClick(final SystemTray systemTray, final Menu parent, final Entry entry) {
|
// void actionPerformed(final ActionEvent e) {
|
||||||
|
// MenuItem source = (MenuItem) e.getSource();
|
||||||
// JProgressBar progressBar = new JProgressBar(0, 100);
|
// JProgressBar progressBar = new JProgressBar(0, 100);
|
||||||
// progressBar.setValue(new Random().nextInt(101));
|
// progressBar.setValue(new Random().nextInt(101));
|
||||||
// progressBar.setStringPainted(true);
|
// progressBar.setStringPainted(true);
|
||||||
// systemTray.addWidget(progressBar);
|
// source.getSystemTray().add(progressBar);
|
||||||
// }
|
// }
|
||||||
// });
|
// }));
|
||||||
submenu.addEntry("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
|
||||||
|
|
||||||
|
submenu.add(new MenuItem("Hide tray", LT_GRAY_BUS, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
systemTray.setEnabled(false);
|
systemTray.setEnabled(false);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() {
|
submenu.add(new MenuItem("Remove menu", BLACK_FIRE, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
submenu.remove();
|
MenuItem source = (MenuItem) e.getSource();
|
||||||
|
source.getParent().remove();
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
systemTray.addEntry("Quit", new ActionListener() {
|
|
||||||
|
systemTray.getMenu().add(new MenuItem("Quit", new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void actionPerformed(final java.awt.event.ActionEvent e) {
|
void actionPerformed(final ActionEvent e) {
|
||||||
systemTray.shutdown();
|
systemTray.shutdown();
|
||||||
|
// necessary to shut down SWT
|
||||||
display.asyncExec(new Runnable() {
|
display.asyncExec(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
shell.dispose();
|
shell.dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
//System.exit(0); not necessary if all non-daemon threads have stopped.
|
||||||
}
|
}
|
||||||
}).setShortcut('q'); // case does not matter
|
})).setShortcut('q'); // case does not matter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
shell.pack();
|
shell.pack();
|
||||||
|
Loading…
Reference in New Issue
Block a user