diff options
Diffstat (limited to 'projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java')
| -rw-r--r-- | projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java | 553 |
1 files changed, 247 insertions, 306 deletions
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java index 7350a39..81dc6e8 100644 --- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java @@ -23,323 +23,264 @@ import java.util.LinkedList; import java.util.List; /** -* NSNotificationQueue coalesces notifications to be -* posted to the NSNotificationCenter and can post them -* asynchronously. While calling postNotification on -* the notification center does not return until all -* receivers have been notified, calling enqueueNotification -* can return immediately. Use this class when you want -* to coalesce notifications or notify asynchronously, or -* both, which is the typical case. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 893 $ -*/ -public class NSNotificationQueue -{ - private static NSNotificationQueue defaultQueue = null; - - /** - * Posting style specifying that the notification should - * be posted on the next available event loop. - */ - public static final int PostASAP = 4; - - /** - * Posting style specifying that the notification should - * be posted on the next available idle loop. - */ - public static final int PostWhenIdle = 8; - - /** - * Posting style specifying that the notification should - * be posted immediately. The enqueue method will not - * return until all receivers have been notified. - */ - public static final int PostNow = 16; - - /** - * Used to indicate that this notification should not - * be coalesced with other notifications. - * Ignored if combined with other coalesce flags. - */ - public static final int NotificationNoCoalescing = 0; - - /** - * Used to indicate that this notification should - * be coalesced with other notifications with the - * same name. - * May be combined with NotificationCoalescingOnSender. - */ - public static final int NotificationCoalescingOnName = 1; - - /** - * Used to indicate that this notification should - * be coalesced with other notifications with the - * same object argument (which is typically the sender). - * May be combined with NotificationCoalescingOnName. - */ - public static final int NotificationCoalescingOnSender = 2; - - /** - * The ASAP queue, which should probably use a LinkedList. - */ - private List queue; - - /** - * The idle queue, which should probably use a LinkedList. - */ - private List idleQueue; - - /** - * The notification center we will be using. - */ - private NSNotificationCenter center; - - /** - * Our private ASAP notifier. - */ - private Notifier notifier; - - /** - * Our private idle notifier. - */ - private Notifier idleNotifier; - - /** - * Default constructor creates a new notification queue - * that uses the default notification center. - */ - public NSNotificationQueue() - { - this( NSNotificationCenter.defaultCenter() ); - } - - /** - * Creates a new notification queue that uses the - * specified notification center. - */ - public NSNotificationQueue( - NSNotificationCenter aCenter ) - { - queue = new LinkedList(); - idleQueue = new LinkedList(); - center = aCenter; - notifier = new Notifier( this, queue ); - idleNotifier = new Notifier( this, idleQueue ); - } - - /** - * Returns the system default queue, creating one - * if it has not yet been created. The system default - * queue uses the system default notification center. - */ - static public NSNotificationQueue defaultQueue() - { - if ( defaultQueue == null ) - { - defaultQueue = new NSNotificationQueue(); - } - return defaultQueue; - } - - /** - * Removes notifications from the queue that match - * the specified notification, considering the - * specified coalesce mask. - */ - public void dequeueMatchingNotifications( - NSNotification aNotification, - int aCoalesceMask) - { - if ( aCoalesceMask == NotificationNoCoalescing ) return; - dequeueFromQueue( aNotification, aCoalesceMask, queue ); - dequeueFromQueue( aNotification, aCoalesceMask, idleQueue ); - } - - private void dequeueFromQueue( - NSNotification aNotification, - int aCoalesceMask, - List aQueue ) - { - synchronized ( aQueue ) - { - int flag; - NSNotification notification; - Object name = aNotification.name(); - Object object = aNotification.object(); - Iterator it = aQueue.iterator(); - while ( it.hasNext() ) - { - flag = 0; - notification = (NSNotification) it.next(); - // if NotificationCoalescingOnName - if ( ( aCoalesceMask == 1 ) || ( aCoalesceMask == 3 ) ) - { - if ( name == null ) - { - if ( notification.name() != null ) - { - flag += NotificationCoalescingOnName; - } - } - else - { - // compare by value - if ( name.equals( notification.name() ) ) - { - flag += NotificationCoalescingOnName; - } - } - } - // if NotificationCoalescingOnSender - if ( aCoalesceMask >= 2 ) - { - // compare by reference - if ( object == notification.object() ) - { - flag += NotificationCoalescingOnSender; - } - } - - if ( flag == aCoalesceMask ) - { - it.remove(); - } - } - } - } - - /** - * Adds the notification to the queue to be run at - * the time specified by the posting style. The - * notification will be coalesced with other notifications - * that match the same name and object (sender) argument. - */ - public void enqueueNotification( - NSNotification aNotification, - int aPostingStyle) - { - enqueueNotificationWithCoalesceMaskForModes( - aNotification, aPostingStyle, - NotificationCoalescingOnName + NotificationCoalescingOnSender, - null ); - } - - /** - * Adds the notification to the queue to be run at - * the time specified by the posting style and coelesced - * as the specified mask indicates. - * aModeList is currently ignored and may be null. - */ - public void enqueueNotificationWithCoalesceMaskForModes( - NSNotification aNotification, - int aPostingStyle, - int aCoalesceMask, - List aModeList) - { - dequeueMatchingNotifications( aNotification, aCoalesceMask ); - - if ( aPostingStyle == PostNow ) - { - center.postNotification( aNotification ); - return; - } - - if ( aPostingStyle == PostASAP ) - { - synchronized ( queue ) - { - queue.add( aNotification ); - if ( ! notifier.willRun ) - { - // asap runs at the very first run loop ordering, plus one just in case - NSRunLoop.invokeLaterWithOrder( notifier, 1 ); - notifier.willRun = true; - } - } - return; - } - - if ( aPostingStyle == PostWhenIdle ) - { - synchronized ( idleQueue ) - { - idleQueue.add( aNotification ); - if ( ! idleNotifier.willRun ) - { - // when idle runs at the very last run loop ordering, minus one just in case - NSRunLoop.invokeLaterWithOrder( idleNotifier, Integer.MAX_VALUE - 1 ); - idleNotifier.willRun = true; - } - } - return; - } - - } - - private class Notifier implements Runnable - { - public boolean willRun; - - NSNotificationQueue parent; - List queue; - - public Notifier( - NSNotificationQueue aParent, List aQueue ) - { - willRun = false; - parent = aParent; - queue = aQueue; - } - - public void run() - { - Iterator it = new LinkedList( queue ).iterator(); - synchronized ( queue ) - { - queue.clear(); - } - willRun = false; - - // queue must already be cleared and willRun reset - // because this loop might queue more notifications - while ( it.hasNext() ) - { - parent.center.postNotification( - (NSNotification) it.next() ); - } - } - } + * NSNotificationQueue coalesces notifications to be posted to the + * NSNotificationCenter and can post them asynchronously. While calling + * postNotification on the notification center does not return until all + * receivers have been notified, calling enqueueNotification can return + * immediately. Use this class when you want to coalesce notifications or notify + * asynchronously, or both, which is the typical case. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 893 $ + */ +public class NSNotificationQueue { + private static NSNotificationQueue defaultQueue = null; + + /** + * Posting style specifying that the notification should be posted on the next + * available event loop. + */ + public static final int PostASAP = 4; + + /** + * Posting style specifying that the notification should be posted on the next + * available idle loop. + */ + public static final int PostWhenIdle = 8; + + /** + * Posting style specifying that the notification should be posted immediately. + * The enqueue method will not return until all receivers have been notified. + */ + public static final int PostNow = 16; + + /** + * Used to indicate that this notification should not be coalesced with other + * notifications. Ignored if combined with other coalesce flags. + */ + public static final int NotificationNoCoalescing = 0; + + /** + * Used to indicate that this notification should be coalesced with other + * notifications with the same name. May be combined with + * NotificationCoalescingOnSender. + */ + public static final int NotificationCoalescingOnName = 1; + + /** + * Used to indicate that this notification should be coalesced with other + * notifications with the same object argument (which is typically the sender). + * May be combined with NotificationCoalescingOnName. + */ + public static final int NotificationCoalescingOnSender = 2; + + /** + * The ASAP queue, which should probably use a LinkedList. + */ + private List queue; + + /** + * The idle queue, which should probably use a LinkedList. + */ + private List idleQueue; + + /** + * The notification center we will be using. + */ + private NSNotificationCenter center; + + /** + * Our private ASAP notifier. + */ + private Notifier notifier; + + /** + * Our private idle notifier. + */ + private Notifier idleNotifier; + + /** + * Default constructor creates a new notification queue that uses the default + * notification center. + */ + public NSNotificationQueue() { + this(NSNotificationCenter.defaultCenter()); + } + + /** + * Creates a new notification queue that uses the specified notification center. + */ + public NSNotificationQueue(NSNotificationCenter aCenter) { + queue = new LinkedList(); + idleQueue = new LinkedList(); + center = aCenter; + notifier = new Notifier(this, queue); + idleNotifier = new Notifier(this, idleQueue); + } + + /** + * Returns the system default queue, creating one if it has not yet been + * created. The system default queue uses the system default notification + * center. + */ + static public NSNotificationQueue defaultQueue() { + if (defaultQueue == null) { + defaultQueue = new NSNotificationQueue(); + } + return defaultQueue; + } + + /** + * Removes notifications from the queue that match the specified notification, + * considering the specified coalesce mask. + */ + public void dequeueMatchingNotifications(NSNotification aNotification, int aCoalesceMask) { + if (aCoalesceMask == NotificationNoCoalescing) + return; + dequeueFromQueue(aNotification, aCoalesceMask, queue); + dequeueFromQueue(aNotification, aCoalesceMask, idleQueue); + } + + private void dequeueFromQueue(NSNotification aNotification, int aCoalesceMask, List aQueue) { + synchronized (aQueue) { + int flag; + NSNotification notification; + Object name = aNotification.name(); + Object object = aNotification.object(); + Iterator it = aQueue.iterator(); + while (it.hasNext()) { + flag = 0; + notification = (NSNotification) it.next(); + // if NotificationCoalescingOnName + if ((aCoalesceMask == 1) || (aCoalesceMask == 3)) { + if (name == null) { + if (notification.name() != null) { + flag += NotificationCoalescingOnName; + } + } else { + // compare by value + if (name.equals(notification.name())) { + flag += NotificationCoalescingOnName; + } + } + } + // if NotificationCoalescingOnSender + if (aCoalesceMask >= 2) { + // compare by reference + if (object == notification.object()) { + flag += NotificationCoalescingOnSender; + } + } + + if (flag == aCoalesceMask) { + it.remove(); + } + } + } + } + + /** + * Adds the notification to the queue to be run at the time specified by the + * posting style. The notification will be coalesced with other notifications + * that match the same name and object (sender) argument. + */ + public void enqueueNotification(NSNotification aNotification, int aPostingStyle) { + enqueueNotificationWithCoalesceMaskForModes(aNotification, aPostingStyle, + NotificationCoalescingOnName + NotificationCoalescingOnSender, null); + } + + /** + * Adds the notification to the queue to be run at the time specified by the + * posting style and coelesced as the specified mask indicates. aModeList is + * currently ignored and may be null. + */ + public void enqueueNotificationWithCoalesceMaskForModes(NSNotification aNotification, int aPostingStyle, + int aCoalesceMask, List aModeList) { + dequeueMatchingNotifications(aNotification, aCoalesceMask); + + if (aPostingStyle == PostNow) { + center.postNotification(aNotification); + return; + } + + if (aPostingStyle == PostASAP) { + synchronized (queue) { + queue.add(aNotification); + if (!notifier.willRun) { + // asap runs at the very first run loop ordering, plus one just in case + NSRunLoop.invokeLaterWithOrder(notifier, 1); + notifier.willRun = true; + } + } + return; + } + + if (aPostingStyle == PostWhenIdle) { + synchronized (idleQueue) { + idleQueue.add(aNotification); + if (!idleNotifier.willRun) { + // when idle runs at the very last run loop ordering, minus one just in case + NSRunLoop.invokeLaterWithOrder(idleNotifier, Integer.MAX_VALUE - 1); + idleNotifier.willRun = true; + } + } + return; + } + + } + + private class Notifier implements Runnable { + public boolean willRun; + + NSNotificationQueue parent; + List queue; + + public Notifier(NSNotificationQueue aParent, List aQueue) { + willRun = false; + parent = aParent; + queue = aQueue; + } + + public void run() { + Iterator it = new LinkedList(queue).iterator(); + synchronized (queue) { + queue.clear(); + } + willRun = false; + + // queue must already be cleared and willRun reset + // because this loop might queue more notifications + while (it.hasNext()) { + parent.center.postNotification((NSNotification) it.next()); + } + } + } } /* - * $Log$ - * Revision 1.2 2006/02/16 13:15:00 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * $Log$ Revision 1.2 2006/02/16 13:15:00 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.6 2003/08/11 18:18:08 chochos - * improved encoding of strings, removed warnings + * Revision 1.6 2003/08/11 18:18:08 chochos improved encoding of strings, + * removed warnings * - * Revision 1.5 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.5 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.4 2001/11/01 15:49:26 mpowers - * With NSRunLoop, we can now correctly implement PostASAP and PostWhenIdle. + * Revision 1.4 2001/11/01 15:49:26 mpowers With NSRunLoop, we can now correctly + * implement PostASAP and PostWhenIdle. * - * Revision 1.3 2001/06/25 14:47:24 mpowers - * Fixed serious error where some notifications were not being posted at all. - * A simple change to Notifier class fixed the problem. Thanks to glista. + * Revision 1.3 2001/06/25 14:47:24 mpowers Fixed serious error where some + * notifications were not being posted at all. A simple change to Notifier class + * fixed the problem. Thanks to glista. * - * Revision 1.2 2001/02/26 15:53:22 mpowers - * Fine-tuning notification firing. + * Revision 1.2 2001/02/26 15:53:22 mpowers Fine-tuning notification firing. * Child display groups now update properly after parent save or invalidate. * - * Revision 1.1 2001/02/24 17:03:22 mpowers - * Implemented the notification queue, and changed editing context to use it. + * Revision 1.1 2001/02/24 17:03:22 mpowers Implemented the notification queue, + * and changed editing context to use it. * * */ - |
