00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import "CPArray.j"
00024 @import "CPDictionary.j"
00025 @import "CPNotification.j"
00026 @import "CPException.j"
00027
00028
00029 var CPNotificationDefaultCenter = nil;
00030
00035 @implementation CPNotificationCenter : CPObject
00036 {
00037 CPMutableDictionary _namedRegistries;
00038 _CPNotificationRegistry _unnamedRegistry;
00039 }
00040
00044 + (CPNotifcationCenter)defaultCenter
00045 {
00046 if (!CPNotificationDefaultCenter)
00047 CPNotificationDefaultCenter = [[CPNotificationCenter alloc] init];
00048
00049 return CPNotificationDefaultCenter;
00050 }
00051
00052 - (id)init
00053 {
00054 self = [super init];
00055
00056 if (self)
00057 {
00058 _namedRegistries = [CPDictionary dictionary];
00059 _unnamedRegistry = [[_CPNotificationRegistry alloc] init];
00060 }
00061 return self;
00062 }
00063
00072 - (void)addObserver:(id)anObserver selector:(SEL)aSelector name:(CPString)aNotificationName object:(id)anObject
00073 {
00074 var registry,
00075 observer = [[_CPNotificationObserver alloc] initWithObserver:anObserver selector:aSelector];
00076
00077 if (aNotificationName == nil)
00078 registry = _unnamedRegistry;
00079
00080 else if (!(registry = [_namedRegistries objectForKey:aNotificationName]))
00081 {
00082 registry = [[_CPNotificationRegistry alloc] init];
00083 [_namedRegistries setObject:registry forKey:aNotificationName];
00084 }
00085
00086 [registry addObserver:observer object:anObject];
00087 }
00088
00093 - (void)removeObserver:(id)anObserver
00094 {
00095 var name = nil,
00096 names = [_namedRegistries keyEnumerator];
00097
00098 while (name = [names nextObject])
00099 [[_namedRegistries objectForKey:name] removeObserver:anObserver object:nil];
00100
00101 [_unnamedRegistry removeObserver:anObserver object:nil];
00102 }
00103
00110 - (void)removeObserver:(id)anObserver name:(CPString)aNotificationName object:(id)anObject
00111 {
00112 if (aNotificationName == nil)
00113 {
00114 var name = nil,
00115 names = [_namedRegistries keyEnumerator];
00116
00117 while (name = [names nextObject])
00118 [[_namedRegistries objectForKey:name] removeObserver:anObserver object:anObject];
00119
00120 [_unnamedRegistry removeObserver:anObserver object:anObject];
00121 }
00122 else
00123 [[_namedRegistries objectForKey:aNotificationName] removeObserver:anObserver object:anObject];
00124 }
00125
00131 - (void)postNotification:(CPNotification)aNotification
00132 {
00133 if (!aNotification)
00134 [CPException raise:CPInvalidArgumentException reason:"postNotification: does not except 'nil' notifications"];
00135
00136 _CPNotificationCenterPostNotification(self, aNotification);
00137 }
00138
00145 - (void)postNotificationName:(CPString)aNotificationName object:(id)anObject userInfo:(CPDictionary)aUserInfo
00146 {
00147 _CPNotificationCenterPostNotification(self, [[CPNotification alloc] initWithName:aNotificationName object:anObject userInfo:aUserInfo]);
00148 }
00149
00155 - (void)postNotificationName:(CPString)aNotificationName object:(id)anObject
00156 {
00157 _CPNotificationCenterPostNotification(self, [[CPNotification alloc] initWithName:aNotificationName object:anObject userInfo:nil]);
00158 }
00159
00160 @end
00161
00162 var _CPNotificationCenterPostNotification = function( self, aNotification)
00163 {
00164 [self._unnamedRegistry postNotification:aNotification];
00165 [[self._namedRegistries objectForKey:[aNotification name]] postNotification:aNotification];
00166 }
00167
00168
00169
00170
00171
00172 @implementation _CPNotificationRegistry : CPObject
00173 {
00174 CPDictionary _objectObservers;
00175 BOOL _observerRemoval;
00176 CPArray _postingObservers;
00177 }
00178
00179 - (id)init
00180 {
00181 if (self)
00182 _objectObservers = [CPDictionary dictionary];
00183
00184 return self;
00185 }
00186
00187 -(void)addObserver:(_CPNotificationObserver)anObserver object:(id)anObject
00188 {
00189
00190
00191 if (!anObject)
00192 anObject = [CPNull null];
00193
00194
00195 var observers = [_objectObservers objectForKey:[anObject hash]];
00196
00197 if (!observers)
00198 {
00199 observers = [];
00200 [_objectObservers setObject:observers forKey:[anObject hash]];
00201 }
00202
00203 if (observers == _postingObservers)
00204 _postingObservers = [observers copy];
00205
00206
00207 observers.push(anObserver);
00208 }
00209
00210 -(void)removeObserver:(id)anObserver object:(id)anObject
00211 {
00212 var removedKeys = [];
00213
00214
00215 if (anObject == nil)
00216 {
00217 var key = nil,
00218 keys = [_objectObservers keyEnumerator];
00219
00220
00221 while (key = [keys nextObject])
00222 {
00223 var observers = [_objectObservers objectForKey:key],
00224 count = observers ? observers.length : 0;
00225
00226 while (count--)
00227 if ([observers[count] observer] == anObserver)
00228 {
00229 _observerRemoval = YES;
00230 if (observers == _postingObservers)
00231 _postingObservers = [observers copy];
00232
00233 observers.splice(count, 1);
00234 }
00235
00236 if (!observers || observers.length == 0)
00237 removedKeys.push(key);
00238 }
00239 }
00240 else
00241 {
00242 var key = [anObject hash],
00243 observers = [_objectObservers objectForKey:key];
00244 count = observers ? observers.length : 0;
00245
00246 while (count--)
00247 if ([observers[count] observer] == anObserver)
00248 {
00249 _observerRemoval = YES;
00250 if (observers == _postingObservers)
00251 _postingObservers = [observers copy];
00252
00253 observers.splice(count, 1)
00254 }
00255
00256 if (!observers || observers.length == 0)
00257 removedKeys.push(key);
00258 }
00259
00260 var count = removedKeys.length;
00261
00262 while (count--)
00263 [_objectObservers removeObjectForKey:removedKeys[count]];
00264 }
00265
00266 - (void)postNotification:(CPNotification)aNotification
00267 {
00268
00269
00270
00271
00272
00273
00274
00275
00276 var object = [aNotification object];
00277
00278 if (object != nil && (_postingObservers = [_objectObservers objectForKey:[object hash]]))
00279 {
00280 var observers = _postingObservers,
00281 count = observers.length;
00282
00283 _observerRemoval = NO;
00284 while (count--)
00285 {
00286 var observer = _postingObservers[count];
00287
00288
00289
00290 if (!_observerRemoval || [observers indexOfObjectIdenticalTo:observer] != CPNotFound)
00291 [observer postNotification:aNotification];
00292
00293 }
00294 }
00295
00296
00297 _postingObservers = [_objectObservers objectForKey:[[CPNull null] hash]];
00298
00299 if (!_postingObservers)
00300 return;
00301
00302 var observers = _postingObservers,
00303 count = observers.length;
00304
00305 _observerRemoval = NO;
00306 while (count--)
00307 {
00308 var observer = _postingObservers[count];
00309
00310
00311
00312 if (!_observerRemoval || [observers indexOfObjectIdenticalTo:observer] != CPNotFound)
00313 [observer postNotification:aNotification];
00314 }
00315
00316 _postingObservers = nil;
00317 }
00318
00319 - (unsigned)count
00320 {
00321 return [_objectObservers count];
00322 }
00323
00324 @end
00325
00326
00327 @implementation _CPNotificationObserver : CPObject
00328 {
00329 id _observer;
00330 SEL _selector;
00331 }
00332
00333 - (id)initWithObserver:(id)anObserver selector:(SEL)aSelector
00334 {
00335 if (self)
00336 {
00337 _observer = anObserver;
00338 _selector = aSelector;
00339 }
00340
00341 return self;
00342 }
00343
00344 - (id)observer
00345 {
00346 return _observer;
00347 }
00348
00349 -(void)postNotification:(CPNotification)aNotification
00350 {
00351 [_observer performSelector:_selector withObject:aNotification];
00352 }
00353
00354 @end