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