diff --git a/SystemTray.iml b/SystemTray.iml index f75d70c0..6be8b8f1 100755 --- a/SystemTray.iml +++ b/SystemTray.iml @@ -34,5 +34,7 @@ + + \ No newline at end of file diff --git a/src/dorkbox/systemTray/Checkbox.java b/src/dorkbox/systemTray/Checkbox.java index dbceedb9..8ab4846f 100644 --- a/src/dorkbox/systemTray/Checkbox.java +++ b/src/dorkbox/systemTray/Checkbox.java @@ -13,92 +13,104 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package dorkbox.systemTray; 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 */ +@SuppressWarnings("unused") public class Checkbox extends Entry { - private volatile boolean isChecked = false; - private volatile String text; - private volatile ActionListener callback; + private boolean isChecked = false; + private String text; + private ActionListener callback; - private volatile boolean enabled = true; - private volatile char mnemonicKey; + private boolean enabled = true; + private char mnemonicKey; public Checkbox() { this(null, null); } - public - Checkbox(final String text) { - this(text, null); - } - public Checkbox(final String text, final ActionListener callback) { this.text = text; 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 systemTray the system tray (which is the object that sits in the system tray) */ public synchronized - void bind(final MenuCheckboxHook hook, final Menu parent, final SystemTray systemTray) { - super.bind(hook, parent, systemTray); + void bind(final CheckboxPeer peer, final Menu parent, final SystemTray systemTray) { + super.bind(peer, parent, systemTray); - hook.setEnabled(this); - hook.setText(this); - hook.setCallback(this); - hook.setShortcut(this); - hook.setChecked(this); + peer.setEnabled(this); + peer.setText(this); + peer.setCallback(this); + peer.setShortcut(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 * * @param checked true to show the checkbox, false to hide it */ - public + public synchronized void setChecked(boolean checked) { this.isChecked = checked; - if (hook != null) { - ((MenuCheckboxHook) hook).setChecked(this); + if (peer != null) { + ((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 */ - public + public synchronized ActionListener getCallback() { 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. */ - public + public synchronized boolean getEnabled() { return this.enabled; } @@ -106,19 +118,19 @@ class Checkbox extends Entry { /** * Enables, or disables the entry. */ - public + public synchronized void setEnabled(final boolean enabled) { this.enabled = enabled; - if (hook != null) { - ((MenuCheckboxHook) hook).setEnabled(this); + if (peer != null) { + ((CheckboxPeer) peer).setEnabled(this); } } /** * @return the text label that the menu entry has assigned */ - public final + public synchronized String getText() { return text; } @@ -128,54 +140,41 @@ class Checkbox extends Entry { * * @param text the new text to set */ - public + public synchronized void setText(final String text) { this.text = text; - if (hook != null) { - ((MenuCheckboxHook) hook).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); + if (peer != null) { + ((CheckboxPeer) peer).setText(this); } } /** * 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. - * + *

* 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. */ - public + public synchronized char getShortcut() { 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. - * + *

* 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. * * @param key this is the key to set as the mnemonic */ - public + public synchronized void setShortcut(final char key) { this.mnemonicKey = key; - if (hook != null) { - ((MenuCheckboxHook) hook).setShortcut(this); + if (peer != null) { + ((CheckboxPeer) peer).setShortcut(this); } } } diff --git a/src/dorkbox/systemTray/Entry.java b/src/dorkbox/systemTray/Entry.java index 4176ff24..191a0223 100644 --- a/src/dorkbox/systemTray/Entry.java +++ b/src/dorkbox/systemTray/Entry.java @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package dorkbox.systemTray; 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 @@ -32,7 +31,7 @@ class Entry { private Menu parent; private SystemTray systemTray; - protected volatile EntryHook hook; + protected volatile EntryPeer peer; public Entry() { @@ -42,16 +41,16 @@ class Entry { // 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 systemTray the system tray (which is the object that sits in the system tray) */ 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.systemTray = systemTray; - this.hook = hook; + this.peer = peer; } // END methods for hooking into the system tray, menu's, and entries. @@ -78,12 +77,12 @@ class Entry { */ public synchronized void remove() { - if (hook != null) { - hook.remove(); + if (peer != null) { + peer.remove(); this.parent = null; this.systemTray = null; - hook = null; + peer = null; } } diff --git a/src/dorkbox/systemTray/Menu.java b/src/dorkbox/systemTray/Menu.java index 315f218f..7a22df36 100644 --- a/src/dorkbox/systemTray/Menu.java +++ b/src/dorkbox/systemTray/Menu.java @@ -24,8 +24,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import dorkbox.systemTray.util.MenuHook; -import dorkbox.systemTray.util.Status; +import dorkbox.systemTray.peer.MenuPeer; /** * 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") public class Menu extends MenuItem { - protected final List menuEntries = new ArrayList(); + final List menuEntries = new ArrayList(); public 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 systemTray the system tray (which is the object that sits in the system tray) */ public synchronized - void bind(final MenuHook hook, final Menu parent, final SystemTray systemTray) { - super.bind(hook, parent, systemTray); + void bind(final MenuPeer peer, final Menu parent, final SystemTray systemTray) { + super.bind(peer, parent, systemTray); - synchronized (menuEntries) { - for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) { - final Entry menuEntry = menuEntries.get(i); - hook.add(this, menuEntry, i); - } + for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) { + final Entry menuEntry = menuEntries.get(i); + peer.add(this, menuEntry, i); } } @@ -135,22 +132,20 @@ class Menu extends MenuItem { /** * Adds a menu entry, separator, or sub-menu to this menu. */ - public final + public synchronized T add(final T entry, int index) { - synchronized (menuEntries) { - if (index == -1) { - menuEntries.add(entry); - } else { - if (!menuEntries.isEmpty() && menuEntries.get(0) instanceof Status) { - // the "status" menu entry is ALWAYS first - index++; - } - menuEntries.add(index, entry); + if (index == -1) { + menuEntries.add(entry); + } else { + if (!menuEntries.isEmpty() && menuEntries.get(0) instanceof Status) { + // the "status" menu entry is ALWAYS first + index++; } + menuEntries.add(index, entry); } - if (hook != null) { - ((MenuHook) hook).add(this, entry, index); + if (peer != null) { + ((MenuPeer) peer).add(this, entry, index); } return entry; @@ -167,18 +162,16 @@ class Menu extends MenuItem { /** * Gets the last menu entry or sub-menu, ignoring status and separators */ - public final + public synchronized Entry getLast() { // Must be wrapped in a synchronized block for object visibility - synchronized (menuEntries) { - if (!menuEntries.isEmpty()) { - Entry entry; - for (int i = menuEntries.size()-1; i >= 0; i--) { - entry = menuEntries.get(i); + if (!menuEntries.isEmpty()) { + Entry entry; + for (int i = menuEntries.size()-1; i >= 0; i--) { + entry = menuEntries.get(i); - if (!(entry instanceof Separator || entry instanceof Status)) { - return entry; - } + if (!(entry instanceof Separator || entry instanceof Status)) { + return entry; } } } @@ -191,27 +184,25 @@ class Menu extends MenuItem { * * @param menuIndex the menu entry index to use to retrieve the menu entry. */ - public final + public synchronized Entry get(final int menuIndex) { if (menuIndex < 0) { return null; } // Must be wrapped in a synchronized block for object visibility - synchronized (menuEntries) { - if (!menuEntries.isEmpty()) { - int count = 0; - for (Entry entry : menuEntries) { - if (entry instanceof Separator || entry instanceof Status) { - continue; - } - - if (count == menuIndex) { - return entry; - } - - count++; + if (!menuEntries.isEmpty()) { + int count = 0; + for (Entry entry : menuEntries) { + if (entry instanceof Separator || entry instanceof Status) { + continue; } + + if (count == menuIndex) { + return entry; + } + + count++; } } @@ -223,19 +214,30 @@ class Menu extends MenuItem { * * @param entry This is the menu entry to remove */ - public final + public synchronized 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 // removed themselves from the menuEntries) if (entry != null) { - synchronized (menuEntries) { - for (Iterator iterator = menuEntries.iterator(); iterator.hasNext(); ) { - final Entry entry__ = iterator.next(); - if (entry__ == entry) { - iterator.remove(); - entry.remove(); - break; - } + for (Iterator iterator = menuEntries.iterator(); iterator.hasNext(); ) { + final Entry entry__ = iterator.next(); + if (entry__ == entry) { + 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)); } } } @@ -244,16 +246,14 @@ class Menu extends MenuItem { /** * This removes all menu entries from this menu */ - public final + public synchronized void removeAll() { - synchronized (menuEntries) { - // have to make copy because we are deleting all of them, and sub-menus remove themselves from parents - ArrayList menuEntriesCopy = new ArrayList(this.menuEntries); - for (Entry entry : menuEntriesCopy) { - entry.remove(); - } - menuEntries.clear(); + // have to make copy because we are deleting all of them, and sub-menus remove themselves from parents + ArrayList menuEntriesCopy = new ArrayList(this.menuEntries); + for (Entry entry : menuEntriesCopy) { + entry.remove(); } + menuEntries.clear(); } diff --git a/src/dorkbox/systemTray/MenuItem.java b/src/dorkbox/systemTray/MenuItem.java index d285ec06..eacdd79c 100644 --- a/src/dorkbox/systemTray/MenuItem.java +++ b/src/dorkbox/systemTray/MenuItem.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package dorkbox.systemTray; import java.awt.Image; @@ -22,8 +21,8 @@ import java.io.File; import java.io.InputStream; import java.net.URL; +import dorkbox.systemTray.peer.MenuItemPeer; import dorkbox.systemTray.util.ImageUtils; -import dorkbox.systemTray.util.MenuItemHook; /** * 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"}) public class MenuItem extends Entry { - private volatile String text; - private volatile File imageFile; - private volatile ActionListener callback; + private String text; + private File imageFile; + private ActionListener callback; // default enabled is always true - private volatile boolean enabled = true; - private volatile char mnemonicKey; + private boolean enabled = true; + private char mnemonicKey; public 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 systemTray the system tray (which is the object that sits in the system tray) */ public synchronized - void bind(final MenuItemHook hook, final Menu parent, final SystemTray systemTray) { - super.bind(hook, parent, systemTray); + void bind(final MenuItemPeer peer, final Menu parent, final SystemTray systemTray) { + super.bind(peer, parent, systemTray); - hook.setImage(this); - hook.setEnabled(this); - hook.setText(this); - hook.setCallback(this); - hook.setShortcut(this); + peer.setImage(this); + peer.setEnabled(this); + peer.setText(this); + peer.setCallback(this); + peer.setShortcut(this); } - private + private synchronized void setImage_(final File imageFile) { this.imageFile = imageFile; - if (hook != null) { - ((MenuItemHook) hook).setImage(this); + if (peer != null) { + ((MenuItemPeer) peer).setImage(this); } } @@ -142,7 +141,7 @@ class MenuItem extends Entry { *

* This file can also be a cached file, depending on how the image was assigned to this entry. */ - public + public synchronized File getImage() { return imageFile; } @@ -150,7 +149,7 @@ class MenuItem extends Entry { /** * Gets the callback assigned to this menu entry */ - public + public synchronized ActionListener getCallback() { return callback; } @@ -158,7 +157,7 @@ class MenuItem extends Entry { /** * @return true if this item is enabled, or false if it is disabled. */ - public + public synchronized boolean getEnabled() { return this.enabled; } @@ -166,19 +165,19 @@ class MenuItem extends Entry { /** * Enables, or disables the entry. */ - public + public synchronized void setEnabled(final boolean enabled) { this.enabled = enabled; - if (hook != null) { - ((MenuItemHook) hook).setEnabled(this); + if (peer != null) { + ((MenuItemPeer) peer).setEnabled(this); } } /** * @return the text label that the menu entry has assigned */ - public final + public synchronized String getText() { return text; } @@ -188,12 +187,12 @@ class MenuItem extends Entry { * * @param text the new text to set */ - public + public synchronized void setText(final String text) { this.text = text; - if (hook != null) { - ((MenuItemHook) hook).setText(this); + if (peer != null) { + ((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. */ - public + public synchronized 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. */ - public + public synchronized void setCallback(final ActionListener callback) { this.callback = callback; - if (hook != null) { - ((MenuItemHook) hook).setCallback(this); + if (peer != null) { + ((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 * of it will be underlined. */ - public + public synchronized char getShortcut() { return this.mnemonicKey; } @@ -352,19 +351,19 @@ class MenuItem extends Entry { * * @param key this is the key to set as the mnemonic */ - public + public synchronized void setShortcut(final char key) { this.mnemonicKey = key; - if (hook != null) { - ((MenuItemHook) hook).setShortcut(this); + if (peer != null) { + ((MenuItemPeer) peer).setShortcut(this); } } @Override public synchronized void remove() { - if (hook != null) { + if (peer != null) { setImage_(null); setText(null); setCallback(null); diff --git a/src/dorkbox/systemTray/Separator.java b/src/dorkbox/systemTray/Separator.java index c51f3e8e..f4f5e634 100644 --- a/src/dorkbox/systemTray/Separator.java +++ b/src/dorkbox/systemTray/Separator.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package dorkbox.systemTray; /** diff --git a/src/dorkbox/systemTray/util/Status.java b/src/dorkbox/systemTray/Status.java similarity index 74% rename from src/dorkbox/systemTray/util/Status.java rename to src/dorkbox/systemTray/Status.java index 5b5e9c56..3c44e730 100644 --- a/src/dorkbox/systemTray/util/Status.java +++ b/src/dorkbox/systemTray/Status.java @@ -13,12 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package dorkbox.systemTray; -package dorkbox.systemTray.util; - -import dorkbox.systemTray.Entry; -import dorkbox.systemTray.Menu; -import dorkbox.systemTray.SystemTray; +import dorkbox.systemTray.peer.StatusPeer; /** * 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 systemTray the system tray (which is the object that sits in the system tray) */ public synchronized - void bind(final MenuStatusHook hook, final Menu parent, final SystemTray systemTray) { - super.bind(hook, parent, systemTray); + void bind(final StatusPeer peer, final Menu parent, final SystemTray systemTray) { + super.bind(peer, parent, systemTray); - hook.setText(this); + peer.setText(this); } /** * @return the text label that the menu entry has assigned */ - public final + public synchronized String getText() { return text; } @@ -56,12 +53,12 @@ class Status extends Entry { * * @param text the new text to set */ - public + public synchronized void setText(final String text) { this.text = text; - if (hook != null) { - ((MenuStatusHook) hook).setText(this); + if (peer != null) { + ((StatusPeer) peer).setText(this); } } } diff --git a/src/dorkbox/systemTray/Tray.java b/src/dorkbox/systemTray/Tray.java index 2a8f1497..939b54c3 100644 --- a/src/dorkbox/systemTray/Tray.java +++ b/src/dorkbox/systemTray/Tray.java @@ -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; -import dorkbox.systemTray.util.Status; - -/** - * - */ public class Tray extends Menu { @@ -22,7 +32,7 @@ class Tray extends Menu { /** * Gets the 'status' string assigned to the system tray */ - public final + public synchronized String getStatus() { 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 */ - public final + public synchronized void setStatus(final String 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... - 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... - // also calls the hook to add it, so we don't need anything special - add(status, 0); - } + // also calls the hook to add it, so we don't need anything special + add(status, 0); } } } diff --git a/src/dorkbox/systemTray/nativeUI/AwtEntry.java b/src/dorkbox/systemTray/nativeUI/AwtEntry.java deleted file mode 100644 index 2e583f7c..00000000 --- a/src/dorkbox/systemTray/nativeUI/AwtEntry.java +++ /dev/null @@ -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(); -} diff --git a/src/dorkbox/systemTray/nativeUI/AwtMenu.java b/src/dorkbox/systemTray/nativeUI/AwtMenu.java index 5a0ce05e..d799d137 100644 --- a/src/dorkbox/systemTray/nativeUI/AwtMenu.java +++ b/src/dorkbox/systemTray/nativeUI/AwtMenu.java @@ -24,14 +24,14 @@ import dorkbox.systemTray.Entry; import dorkbox.systemTray.Menu; import dorkbox.systemTray.MenuItem; import dorkbox.systemTray.Separator; -import dorkbox.systemTray.util.MenuHook; -import dorkbox.systemTray.util.Status; +import dorkbox.systemTray.Status; +import dorkbox.systemTray.peer.MenuPeer; import dorkbox.systemTray.util.SystemTrayFixes; import dorkbox.util.SwingUtil; // this is a weird composite class, because it must be a Menu, but ALSO a Entry -- so it has both @SuppressWarnings("ForLoopReplaceableByForEach") -class AwtMenu implements MenuHook { +class AwtMenu implements MenuPeer { volatile java.awt.Menu _native; private final AwtMenu parent; diff --git a/src/dorkbox/systemTray/nativeUI/AwtMenuItem.java b/src/dorkbox/systemTray/nativeUI/AwtMenuItem.java index bbf1137d..c117ed86 100644 --- a/src/dorkbox/systemTray/nativeUI/AwtMenuItem.java +++ b/src/dorkbox/systemTray/nativeUI/AwtMenuItem.java @@ -21,11 +21,11 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import dorkbox.systemTray.SystemTray; -import dorkbox.systemTray.util.MenuItemHook; +import dorkbox.systemTray.peer.MenuItemPeer; import dorkbox.systemTray.util.SystemTrayFixes; import dorkbox.util.SwingUtil; -class AwtMenuItem implements MenuItemHook { +class AwtMenuItem implements MenuItemPeer { private final AwtMenu parent; private final MenuItem _native = new java.awt.MenuItem(); @@ -116,6 +116,7 @@ class AwtMenuItem implements MenuItemHook { }); } + @SuppressWarnings("Duplicates") @Override public void remove() { diff --git a/src/dorkbox/systemTray/nativeUI/AwtMenuItemCheckbox.java b/src/dorkbox/systemTray/nativeUI/AwtMenuItemCheckbox.java index 4d80f24f..7906674e 100644 --- a/src/dorkbox/systemTray/nativeUI/AwtMenuItemCheckbox.java +++ b/src/dorkbox/systemTray/nativeUI/AwtMenuItemCheckbox.java @@ -21,18 +21,17 @@ import java.awt.event.ActionListener; import dorkbox.systemTray.Checkbox; import dorkbox.systemTray.SystemTray; -import dorkbox.systemTray.util.MenuCheckboxHook; +import dorkbox.systemTray.peer.CheckboxPeer; import dorkbox.systemTray.util.SystemTrayFixes; import dorkbox.util.SwingUtil; -class AwtMenuItemCheckbox implements MenuCheckboxHook { +class AwtMenuItemCheckbox implements CheckboxPeer { private final AwtMenu parent; private final java.awt.CheckboxMenuItem _native = new java.awt.CheckboxMenuItem(); private volatile ActionListener swingCallback; - // this is ALWAYS called on the EDT. AwtMenuItemCheckbox(final AwtMenu parent) { this.parent = parent; diff --git a/src/dorkbox/systemTray/nativeUI/AwtMenuItemSeparator.java b/src/dorkbox/systemTray/nativeUI/AwtMenuItemSeparator.java index 141c9aff..dbee843b 100644 --- a/src/dorkbox/systemTray/nativeUI/AwtMenuItemSeparator.java +++ b/src/dorkbox/systemTray/nativeUI/AwtMenuItemSeparator.java @@ -17,10 +17,10 @@ package dorkbox.systemTray.nativeUI; import java.awt.MenuItem; -import dorkbox.systemTray.util.EntryHook; +import dorkbox.systemTray.peer.EntryPeer; import dorkbox.util.SwingUtil; -class AwtMenuItemSeparator implements EntryHook { +class AwtMenuItemSeparator implements EntryPeer { private final AwtMenu parent; private final MenuItem _native = new MenuItem("-"); diff --git a/src/dorkbox/systemTray/nativeUI/AwtMenuItemStatus.java b/src/dorkbox/systemTray/nativeUI/AwtMenuItemStatus.java index cda6c3bd..870f32fd 100644 --- a/src/dorkbox/systemTray/nativeUI/AwtMenuItemStatus.java +++ b/src/dorkbox/systemTray/nativeUI/AwtMenuItemStatus.java @@ -20,11 +20,11 @@ import static java.awt.Font.DIALOG; import java.awt.Font; import java.awt.MenuItem; -import dorkbox.systemTray.util.MenuStatusHook; -import dorkbox.systemTray.util.Status; +import dorkbox.systemTray.Status; +import dorkbox.systemTray.peer.StatusPeer; import dorkbox.util.SwingUtil; -class AwtMenuItemStatus implements MenuStatusHook { +class AwtMenuItemStatus implements StatusPeer { private final AwtMenu parent; private final MenuItem _native = new MenuItem(); diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenuBaseItem.java b/src/dorkbox/systemTray/nativeUI/GtkBaseMenuItem.java similarity index 97% rename from src/dorkbox/systemTray/nativeUI/GtkMenuBaseItem.java rename to src/dorkbox/systemTray/nativeUI/GtkBaseMenuItem.java index 5eadc349..4295d93b 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenuBaseItem.java +++ b/src/dorkbox/systemTray/nativeUI/GtkBaseMenuItem.java @@ -21,11 +21,11 @@ import com.sun.jna.Pointer; import dorkbox.systemTray.jna.linux.Gobject; import dorkbox.systemTray.jna.linux.Gtk; -import dorkbox.systemTray.util.EntryHook; +import dorkbox.systemTray.peer.EntryPeer; import dorkbox.systemTray.util.ImageUtils; abstract -class GtkMenuBaseItem implements EntryHook { +class GtkBaseMenuItem implements EntryPeer { 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 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 private volatile Pointer spacerImage; - GtkMenuBaseItem() { + GtkBaseMenuItem() { // cannot be done in a static initializer, because the tray icon size might not yet have been determined if (transparentIcon == null) { transparentIcon = ImageUtils.getTransparentImage(ImageUtils.ENTRY_SIZE); @@ -45,7 +45,6 @@ class GtkMenuBaseItem implements EntryHook { return hasLegitImage; } - public void setLegitImage(boolean isLegit) { hasLegitImage = isLegit; } diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenu.java b/src/dorkbox/systemTray/nativeUI/GtkMenu.java index ac18ba8e..80759526 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenu.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenu.java @@ -15,7 +15,6 @@ */ package dorkbox.systemTray.nativeUI; - import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -27,13 +26,13 @@ import dorkbox.systemTray.Entry; import dorkbox.systemTray.Menu; import dorkbox.systemTray.MenuItem; import dorkbox.systemTray.Separator; +import dorkbox.systemTray.Status; import dorkbox.systemTray.jna.linux.Gtk; -import dorkbox.systemTray.util.MenuHook; -import dorkbox.systemTray.util.Status; +import dorkbox.systemTray.peer.MenuPeer; -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 - private final List menuEntries = new LinkedList(); + private final List menuEntries = new LinkedList(); private final GtkMenu parent; 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; 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 { _nativeEntry = null; } @@ -66,7 +65,7 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook { } private - void add(final GtkMenuBaseItem item, final int index) { + void add(final GtkBaseMenuItem item, final int index) { if (index > 0) { menuEntries.add(index, item); } else { @@ -98,7 +97,7 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook { // have to remove all other menu entries synchronized (menuEntries) { 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); } @@ -136,13 +135,13 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook { // now add back other menu entries synchronized (menuEntries) { 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(); } 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 - final GtkMenuBaseItem menuEntry__ = menuEntries.get(i); + final GtkBaseMenuItem menuEntry__ = menuEntries.get(i); menuEntry__.onCreateMenu(_nativeMenu, hasImages); if (menuEntry__ instanceof GtkMenu) { @@ -173,10 +172,10 @@ class GtkMenu extends GtkMenuBaseItem implements MenuHook { synchronized (menuEntries) { // 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. - ArrayList menuEntriesCopy = new ArrayList(this.menuEntries); + ArrayList menuEntriesCopy = new ArrayList(this.menuEntries); for (int i = 0, menuEntriesSize = menuEntriesCopy.size(); i < menuEntriesSize; i++) { - final GtkMenuBaseItem menuEntry__ = menuEntriesCopy.get(i); + final GtkBaseMenuItem menuEntry__ = menuEntriesCopy.get(i); menuEntry__.remove(); } 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 public - void remove(final GtkMenuBaseItem item) { + void remove(final GtkBaseMenuItem item) { synchronized (menuEntries) { menuEntries.remove(item); } diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenuItem.java b/src/dorkbox/systemTray/nativeUI/GtkMenuItem.java index 242af590..b2aa08dc 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenuItem.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenuItem.java @@ -25,9 +25,9 @@ import dorkbox.systemTray.SystemTray; import dorkbox.systemTray.jna.linux.GCallback; import dorkbox.systemTray.jna.linux.Gobject; 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"}) private final NativeLong nativeLong; diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenuItemCheckbox.java b/src/dorkbox/systemTray/nativeUI/GtkMenuItemCheckbox.java index 4f5a7313..cf860e91 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenuItemCheckbox.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenuItemCheckbox.java @@ -26,10 +26,10 @@ import dorkbox.systemTray.SystemTray; import dorkbox.systemTray.jna.linux.GCallback; import dorkbox.systemTray.jna.linux.Gobject; import dorkbox.systemTray.jna.linux.Gtk; +import dorkbox.systemTray.peer.CheckboxPeer; 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; @SuppressWarnings({"FieldCanBeLocal", "unused"}) diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenuItemSeparator.java b/src/dorkbox/systemTray/nativeUI/GtkMenuItemSeparator.java index 1f190f4c..e3255989 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenuItemSeparator.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenuItemSeparator.java @@ -18,9 +18,9 @@ package dorkbox.systemTray.nativeUI; import com.sun.jna.Pointer; 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 Pointer _native = Gtk.gtk_separator_menu_item_new(); diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenuItemStatus.java b/src/dorkbox/systemTray/nativeUI/GtkMenuItemStatus.java index b51c02aa..ac46e0b9 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenuItemStatus.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenuItemStatus.java @@ -17,13 +17,13 @@ package dorkbox.systemTray.nativeUI; import com.sun.jna.Pointer; +import dorkbox.systemTray.Status; import dorkbox.systemTray.jna.linux.Gtk; -import dorkbox.systemTray.util.MenuStatusHook; -import dorkbox.systemTray.util.Status; +import dorkbox.systemTray.peer.StatusPeer; // 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 -class GtkMenuItemStatus extends GtkMenuBaseItem implements MenuStatusHook { +class GtkMenuItemStatus extends GtkBaseMenuItem implements StatusPeer { private final GtkMenu parent; private final Pointer _native = Gtk.gtk_image_menu_item_new_with_mnemonic(""); diff --git a/src/dorkbox/systemTray/nativeUI/NativeUI.java b/src/dorkbox/systemTray/nativeUI/NativeUI.java index a222030f..2c300af6 100644 --- a/src/dorkbox/systemTray/nativeUI/NativeUI.java +++ b/src/dorkbox/systemTray/nativeUI/NativeUI.java @@ -23,9 +23,8 @@ package dorkbox.systemTray.nativeUI; * the system (with the exception of Windows, whose native menu looks absolutely terrible). *

* 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). - * - MacOS cannot have images in their menu or sub-menu's -- only plain text is possible + * - 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 */ public -interface NativeUI -{} +interface NativeUI {} diff --git a/src/dorkbox/systemTray/nativeUI/_AppIndicatorNativeTray.java b/src/dorkbox/systemTray/nativeUI/_AppIndicatorNativeTray.java index fd8a73c7..16c55cab 100644 --- a/src/dorkbox/systemTray/nativeUI/_AppIndicatorNativeTray.java +++ b/src/dorkbox/systemTray/nativeUI/_AppIndicatorNativeTray.java @@ -157,13 +157,13 @@ class _AppIndicatorNativeTray extends Tray implements NativeUI { @Override public void setText(final MenuItem menuItem) { - // no op + // no op. } @Override public void setShortcut(final MenuItem menuItem) { - // no op + // no op. } @Override diff --git a/src/dorkbox/systemTray/nativeUI/_AwtTray.java b/src/dorkbox/systemTray/nativeUI/_AwtTray.java index f17398d5..6c4546a3 100644 --- a/src/dorkbox/systemTray/nativeUI/_AwtTray.java +++ b/src/dorkbox/systemTray/nativeUI/_AwtTray.java @@ -38,7 +38,7 @@ import dorkbox.util.SwingUtil; * 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 * - * 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"}) public @@ -157,7 +157,7 @@ class _AwtTray extends Tray implements NativeUI { @Override public void setText(final MenuItem menuItem) { - // no op + // no op. } @Override diff --git a/src/dorkbox/systemTray/peer/CheckboxPeer.java b/src/dorkbox/systemTray/peer/CheckboxPeer.java new file mode 100644 index 00000000..17ec353b --- /dev/null +++ b/src/dorkbox/systemTray/peer/CheckboxPeer.java @@ -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); +} diff --git a/src/dorkbox/systemTray/peer/EntryPeer.java b/src/dorkbox/systemTray/peer/EntryPeer.java new file mode 100644 index 00000000..eace91a0 --- /dev/null +++ b/src/dorkbox/systemTray/peer/EntryPeer.java @@ -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(); +} diff --git a/src/dorkbox/systemTray/peer/MenuItemPeer.java b/src/dorkbox/systemTray/peer/MenuItemPeer.java new file mode 100644 index 00000000..aa45c0dc --- /dev/null +++ b/src/dorkbox/systemTray/peer/MenuItemPeer.java @@ -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); +} diff --git a/src/dorkbox/systemTray/peer/MenuPeer.java b/src/dorkbox/systemTray/peer/MenuPeer.java new file mode 100644 index 00000000..05af5863 --- /dev/null +++ b/src/dorkbox/systemTray/peer/MenuPeer.java @@ -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); +} diff --git a/src/dorkbox/systemTray/peer/StatusPeer.java b/src/dorkbox/systemTray/peer/StatusPeer.java new file mode 100644 index 00000000..b8073d09 --- /dev/null +++ b/src/dorkbox/systemTray/peer/StatusPeer.java @@ -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); +} diff --git a/src/dorkbox/systemTray/swingUI/SwingMenu.java b/src/dorkbox/systemTray/swingUI/SwingMenu.java index abac76e1..fdd69127 100644 --- a/src/dorkbox/systemTray/swingUI/SwingMenu.java +++ b/src/dorkbox/systemTray/swingUI/SwingMenu.java @@ -15,7 +15,6 @@ */ package dorkbox.systemTray.swingUI; - import java.io.File; import javax.swing.ImageIcon; @@ -26,15 +25,14 @@ import dorkbox.systemTray.Entry; import dorkbox.systemTray.Menu; import dorkbox.systemTray.MenuItem; import dorkbox.systemTray.Separator; -import dorkbox.systemTray.SystemTray; -import dorkbox.systemTray.util.MenuHook; -import dorkbox.systemTray.util.Status; +import dorkbox.systemTray.Status; +import dorkbox.systemTray.peer.MenuPeer; import dorkbox.systemTray.util.SystemTrayFixes; 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) @SuppressWarnings("ForLoopReplaceableByForEach") -class SwingMenu implements MenuHook { +class SwingMenu implements MenuPeer { final JComponent _native; private final SwingMenu parent; @@ -89,12 +87,11 @@ class SwingMenu implements MenuHook { @Override public void setImage(final MenuItem menuItem) { - final File imageFile = menuItem.getImage(); - SwingUtil.invokeLater(new Runnable() { @Override public void run() { + File imageFile = menuItem.getImage(); if (imageFile != null) { ImageIcon origIcon = new ImageIcon(imageFile.getAbsolutePath()); ((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 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); - } - } } diff --git a/src/dorkbox/systemTray/swingUI/SwingMenuItem.java b/src/dorkbox/systemTray/swingUI/SwingMenuItem.java index ff32a9b7..ab5324f1 100644 --- a/src/dorkbox/systemTray/swingUI/SwingMenuItem.java +++ b/src/dorkbox/systemTray/swingUI/SwingMenuItem.java @@ -24,11 +24,11 @@ import javax.swing.JMenuItem; import dorkbox.systemTray.MenuItem; import dorkbox.systemTray.SystemTray; -import dorkbox.systemTray.util.MenuItemHook; +import dorkbox.systemTray.peer.MenuItemPeer; import dorkbox.systemTray.util.SystemTrayFixes; import dorkbox.util.SwingUtil; -class SwingMenuItem implements MenuItemHook { +class SwingMenuItem implements MenuItemPeer { private final SwingMenu parent; private final JMenuItem _native = new AdjustedJMenuItem(); @@ -44,12 +44,11 @@ class SwingMenuItem implements MenuItemHook { @Override public void setImage(final MenuItem menuItem) { - final File imageFile = menuItem.getImage(); - SwingUtil.invokeLater(new Runnable() { @Override public void run() { + File imageFile = menuItem.getImage(); if (imageFile != null) { ImageIcon origIcon = new ImageIcon(imageFile.getAbsolutePath()); _native.setIcon(origIcon); diff --git a/src/dorkbox/systemTray/swingUI/SwingMenuItemCheckbox.java b/src/dorkbox/systemTray/swingUI/SwingMenuItemCheckbox.java index 41c665c5..02744074 100644 --- a/src/dorkbox/systemTray/swingUI/SwingMenuItemCheckbox.java +++ b/src/dorkbox/systemTray/swingUI/SwingMenuItemCheckbox.java @@ -24,12 +24,12 @@ import javax.swing.JMenuItem; import dorkbox.systemTray.Checkbox; import dorkbox.systemTray.SystemTray; +import dorkbox.systemTray.peer.CheckboxPeer; import dorkbox.systemTray.util.ImageUtils; -import dorkbox.systemTray.util.MenuCheckboxHook; import dorkbox.systemTray.util.SystemTrayFixes; import dorkbox.util.SwingUtil; -class SwingMenuItemCheckbox implements MenuCheckboxHook { +class SwingMenuItemCheckbox implements CheckboxPeer { private final SwingMenu parent; private final JMenuItem _native = new AdjustedJMenuItem(); diff --git a/src/dorkbox/systemTray/swingUI/SwingMenuItemSeparator.java b/src/dorkbox/systemTray/swingUI/SwingMenuItemSeparator.java index cfe736d9..baabda4b 100644 --- a/src/dorkbox/systemTray/swingUI/SwingMenuItemSeparator.java +++ b/src/dorkbox/systemTray/swingUI/SwingMenuItemSeparator.java @@ -17,10 +17,10 @@ package dorkbox.systemTray.swingUI; import javax.swing.JSeparator; -import dorkbox.systemTray.util.EntryHook; +import dorkbox.systemTray.peer.EntryPeer; import dorkbox.util.SwingUtil; -class SwingMenuItemSeparator implements EntryHook { +class SwingMenuItemSeparator implements EntryPeer { private final SwingMenu parent; private final JSeparator _native = new JSeparator(JSeparator.HORIZONTAL); diff --git a/src/dorkbox/systemTray/swingUI/SwingMenuItemStatus.java b/src/dorkbox/systemTray/swingUI/SwingMenuItemStatus.java index 6cfd156f..6383389b 100644 --- a/src/dorkbox/systemTray/swingUI/SwingMenuItemStatus.java +++ b/src/dorkbox/systemTray/swingUI/SwingMenuItemStatus.java @@ -19,11 +19,11 @@ import java.awt.Font; import javax.swing.JMenuItem; -import dorkbox.systemTray.util.MenuStatusHook; -import dorkbox.systemTray.util.Status; +import dorkbox.systemTray.Status; +import dorkbox.systemTray.peer.StatusPeer; import dorkbox.util.SwingUtil; -class SwingMenuItemStatus implements MenuStatusHook { +class SwingMenuItemStatus implements StatusPeer { private final SwingMenu parent; private final JMenuItem _native = new AdjustedJMenuItem(); diff --git a/src/dorkbox/systemTray/swingUI/SwingUI.java b/src/dorkbox/systemTray/swingUI/SwingUI.java index 8a5876cc..9eead8df 100644 --- a/src/dorkbox/systemTray/swingUI/SwingUI.java +++ b/src/dorkbox/systemTray/swingUI/SwingUI.java @@ -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). *

* 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). - * - MacOS cannot have images in their menu or sub-menu's -- only plain text is possible + * - 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 */ public -interface SwingUI -{} +interface SwingUI {} diff --git a/src/dorkbox/systemTray/swingUI/TrayPopup.java b/src/dorkbox/systemTray/swingUI/TrayPopup.java index 3e9e2f52..237cf7a4 100644 --- a/src/dorkbox/systemTray/swingUI/TrayPopup.java +++ b/src/dorkbox/systemTray/swingUI/TrayPopup.java @@ -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 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 { private static final long serialVersionUID = 1L; diff --git a/src/dorkbox/systemTray/swingUI/_GtkStatusIconTray.java b/src/dorkbox/systemTray/swingUI/_GtkStatusIconTray.java index 2c819335..15eda9c4 100644 --- a/src/dorkbox/systemTray/swingUI/_GtkStatusIconTray.java +++ b/src/dorkbox/systemTray/swingUI/_GtkStatusIconTray.java @@ -41,15 +41,15 @@ import dorkbox.util.SwingUtil; *

* 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. + * + * 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") public class _GtkStatusIconTray extends Tray implements SwingUI { 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) private final List gtkCallbacks = new ArrayList(); diff --git a/src/dorkbox/systemTray/util/EntryHook.java b/src/dorkbox/systemTray/util/EntryHook.java deleted file mode 100644 index 98b35222..00000000 --- a/src/dorkbox/systemTray/util/EntryHook.java +++ /dev/null @@ -1,9 +0,0 @@ -package dorkbox.systemTray.util; - -/** - * - */ -public -interface EntryHook { - void remove(); -} diff --git a/src/dorkbox/systemTray/util/MenuBase.java b/src/dorkbox/systemTray/util/MenuBase.java deleted file mode 100644 index dfad421d..00000000 --- a/src/dorkbox/systemTray/util/MenuBase.java +++ /dev/null @@ -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 value = new AtomicReference(); -// -// 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 menuEntriesCopy = new ArrayList(MenuBase.this.menuEntries); -// for (Entry entry : menuEntriesCopy) { -// entry.remove(); -// } -// menuEntries.clear(); -// } -// } -// }); -// } -} diff --git a/src/dorkbox/systemTray/util/MenuCheckboxHook.java b/src/dorkbox/systemTray/util/MenuCheckboxHook.java deleted file mode 100644 index ccea5cc9..00000000 --- a/src/dorkbox/systemTray/util/MenuCheckboxHook.java +++ /dev/null @@ -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); -} diff --git a/src/dorkbox/systemTray/util/MenuHook.java b/src/dorkbox/systemTray/util/MenuHook.java deleted file mode 100644 index 9218dc17..00000000 --- a/src/dorkbox/systemTray/util/MenuHook.java +++ /dev/null @@ -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); -} diff --git a/src/dorkbox/systemTray/util/MenuItemHook.java b/src/dorkbox/systemTray/util/MenuItemHook.java deleted file mode 100644 index c7dd351f..00000000 --- a/src/dorkbox/systemTray/util/MenuItemHook.java +++ /dev/null @@ -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); -} diff --git a/src/dorkbox/systemTray/util/MenuStatusHook.java b/src/dorkbox/systemTray/util/MenuStatusHook.java deleted file mode 100644 index 6d6144b3..00000000 --- a/src/dorkbox/systemTray/util/MenuStatusHook.java +++ /dev/null @@ -1,9 +0,0 @@ -package dorkbox.systemTray.util; - -/** - * - */ -public -interface MenuStatusHook extends EntryHook { - void setText(Status menuItem); -} diff --git a/test/dorkbox/TestTray.java b/test/dorkbox/TestTray.java index 63d34e08..3de7c330 100644 --- a/test/dorkbox/TestTray.java +++ b/test/dorkbox/TestTray.java @@ -21,8 +21,9 @@ import java.awt.event.ActionListener; import java.net.URL; import dorkbox.systemTray.Checkbox; -import dorkbox.systemTray.Entry; import dorkbox.systemTray.Menu; +import dorkbox.systemTray.MenuItem; +import dorkbox.systemTray.Separator; import dorkbox.systemTray.SystemTray; /** @@ -51,7 +52,6 @@ class TestTray { } private SystemTray systemTray; - private ActionListener callbackGreen; private ActionListener callbackGray; public @@ -61,23 +61,32 @@ class TestTray { 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.setStatus("No Mail"); - callbackGreen = new ActionListener() { + callbackGray = new ActionListener() { @Override public 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.setImage(GREEN_TRAIN); @@ -86,76 +95,79 @@ class TestTray { entry.setText("Delete Mail"); // 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 public void actionPerformed(final ActionEvent e) { - final Entry entry = (Entry) e.getSource(); - 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); + System.err.println("Am i checked? " + ((Checkbox) e.getSource()).getChecked()); } }); + 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. -// submenu.addEntry("Add widget", GREEN_BUS, new Action() { +// submenu.add(new MenuItem("Hide tray", LT_GRAY_BUS, new ActionListener() { // @Override // 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); // progressBar.setValue(new Random().nextInt(101)); // 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 public void actionPerformed(final ActionEvent e) { systemTray.setEnabled(false); } - }); - submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() { + })); + submenu.add(new MenuItem("Remove menu", BLACK_FIRE, new ActionListener() { @Override public 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 public void actionPerformed(final ActionEvent e) { systemTray.shutdown(); //System.exit(0); not necessary if all non-daemon threads have stopped. } - }).setShortcut('q'); // case does not matter + })).setShortcut('q'); // case does not matter } } diff --git a/test/dorkbox/TestTrayJavaFX.java b/test/dorkbox/TestTrayJavaFX.java index 3f2d4061..a31c655e 100644 --- a/test/dorkbox/TestTrayJavaFX.java +++ b/test/dorkbox/TestTrayJavaFX.java @@ -19,8 +19,10 @@ package dorkbox; import java.awt.event.ActionListener; import java.net.URL; -import dorkbox.systemTray.Entry; +import dorkbox.systemTray.Checkbox; import dorkbox.systemTray.Menu; +import dorkbox.systemTray.MenuItem; +import dorkbox.systemTray.Separator; import dorkbox.systemTray.SystemTray; import javafx.application.Application; import javafx.application.Platform; @@ -95,11 +97,29 @@ class TestTrayJavaFX extends Application { systemTray.setImage(LT_GRAY_TRAIN); systemTray.setStatus("No Mail"); - callbackGreen = new ActionListener() { + callbackGray = new ActionListener() { @Override public 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.setImage(GREEN_TRAIN); @@ -108,69 +128,73 @@ class TestTrayJavaFX extends Application { entry.setText("Delete Mail"); // 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 public void actionPerformed(final java.awt.event.ActionEvent e) { - final Entry entry = (Entry) e.getSource(); - 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); + System.err.println("Am i checked? " + ((Checkbox) e.getSource()).getChecked()); } }); + 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. -// submenu.addEntry("Add widget", GREEN_BUS, new Action() { +// submenu.add(new MenuItem("Hide tray", LT_GRAY_BUS, new ActionListener() { // @Override // 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); // progressBar.setValue(new Random().nextInt(101)); // 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 public void actionPerformed(final java.awt.event.ActionEvent e) { systemTray.setEnabled(false); } - }); - submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() { + })); + submenu.add(new MenuItem("Remove menu", BLACK_FIRE, new ActionListener() { @Override public 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 public void actionPerformed(final java.awt.event.ActionEvent e) { @@ -178,6 +202,6 @@ class TestTrayJavaFX extends Application { Platform.exit(); // necessary to close javaFx //System.exit(0); not necessary if all non-daemon threads have stopped. } - }).setShortcut('q'); // case does not matter + })).setShortcut('q'); // case does not matter } } diff --git a/test/dorkbox/TestTraySwt.java b/test/dorkbox/TestTraySwt.java index c5d0ed16..d0d6949b 100644 --- a/test/dorkbox/TestTraySwt.java +++ b/test/dorkbox/TestTraySwt.java @@ -16,6 +16,7 @@ package dorkbox; +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; 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.Text; -import dorkbox.systemTray.Entry; +import dorkbox.systemTray.Checkbox; import dorkbox.systemTray.Menu; +import dorkbox.systemTray.MenuItem; +import dorkbox.systemTray.Separator; import dorkbox.systemTray.SystemTray; /** @@ -79,11 +82,29 @@ class TestTraySwt { systemTray.setImage(LT_GRAY_TRAIN); systemTray.setStatus("No Mail"); - callbackGreen = new ActionListener() { + callbackGray = new ActionListener() { @Override public - void actionPerformed(final java.awt.event.ActionEvent e) { - final Entry entry = (Entry) e.getSource(); + void actionPerformed(final ActionEvent e) { + 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.setImage(GREEN_TRAIN); @@ -92,84 +113,86 @@ class TestTraySwt { entry.setText("Delete Mail"); // 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 public - void actionPerformed(final java.awt.event.ActionEvent e) { - final Entry entry = (Entry) e.getSource(); - 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); + void actionPerformed(final ActionEvent e) { + System.err.println("Am i checked? " + ((Checkbox) e.getSource()).getChecked()); } }); + 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. -// submenu.addEntry("Add widget", GREEN_BUS, new Action() { +// submenu.add(new MenuItem("Hide tray", LT_GRAY_BUS, new ActionListener() { // @Override // 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); // progressBar.setValue(new Random().nextInt(101)); // 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 public - void actionPerformed(final java.awt.event.ActionEvent e) { + void actionPerformed(final ActionEvent e) { systemTray.setEnabled(false); } - }); - submenu.addEntry("Remove menu", BLACK_FIRE, new ActionListener() { + })); + submenu.add(new MenuItem("Remove menu", BLACK_FIRE, new ActionListener() { @Override public - void actionPerformed(final java.awt.event.ActionEvent e) { - submenu.remove(); + void actionPerformed(final ActionEvent e) { + MenuItem source = (MenuItem) e.getSource(); + source.getParent().remove(); } - }); + })); - systemTray.addEntry("Quit", new ActionListener() { + + systemTray.getMenu().add(new MenuItem("Quit", new ActionListener() { @Override public - void actionPerformed(final java.awt.event.ActionEvent e) { + void actionPerformed(final ActionEvent e) { systemTray.shutdown(); - + // necessary to shut down SWT display.asyncExec(new Runnable() { public void run() { shell.dispose(); } }); - //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();