Code polish, documentation, cleanup for API changes

This commit is contained in:
nathan 2016-10-24 01:43:32 +02:00
parent daff5a8e48
commit 599dabf4ef
45 changed files with 638 additions and 957 deletions

View File

@ -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>

View File

@ -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);
} }
} }
} }

View File

@ -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;
} }
} }

View File

@ -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();
} }

View File

@ -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);

View File

@ -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;
/** /**

View File

@ -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);
} }
} }
} }

View File

@ -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);
}
} }
} }
} }

View File

@ -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();
}

View File

@ -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;

View File

@ -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() {

View File

@ -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;

View File

@ -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("-");

View File

@ -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();

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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;

View File

@ -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"})

View File

@ -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();

View File

@ -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("");

View File

@ -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 {}
{}

View File

@ -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

View File

@ -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

View 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);
}

View 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();
}

View 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);
}

View 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);
}

View 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);
}

View File

@ -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);
}
}
} }

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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 {}
{}

View File

@ -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;

View File

@ -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>();

View File

@ -1,9 +0,0 @@
package dorkbox.systemTray.util;
/**
*
*/
public
interface EntryHook {
void remove();
}

View File

@ -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();
// }
// }
// });
// }
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -1,9 +0,0 @@
package dorkbox.systemTray.util;
/**
*
*/
public
interface MenuStatusHook extends EntryHook {
void setText(Status menuItem);
}

View File

@ -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
} }
} }

View File

@ -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
} }
} }

View File

@ -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();