diff options
| author | Benjamin Culkin <scorpress@gmail.com> | 2024-05-19 17:56:33 -0400 |
|---|---|---|
| committer | Benjamin Culkin <scorpress@gmail.com> | 2024-05-19 17:56:33 -0400 |
| commit | aedc34d55462a75e329bbf342251ff6504cd117e (patch) | |
| tree | bcc8f1f2352582717b484df302aeea6696b8f000 /projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java | |
Initial import from SVN
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 | 345 |
1 files changed, 345 insertions, 0 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 new file mode 100644 index 0000000..7350a39 --- /dev/null +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSNotificationQueue.java @@ -0,0 +1,345 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2001 Intersect Software Corporation + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, see http://www.gnu.org +*/ + +package net.wotonomy.foundation; + +import java.util.Iterator; +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() ); + } + } + } + +} + +/* + * $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.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.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. + * 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. + * + * + */ + |
