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 "CPException.j"
00026 @import "CPNotification.j"
00027 @import "CPNull.j"
00028
00029
00030 var CPNotificationDefaultCenter = nil;
00031
00045 @implementation CPNotificationCenter : CPObject
00046 {
00047 CPMutableDictionary _namedRegistries;
00048 _CPNotificationRegistry _unnamedRegistry;
00049 }
00050
00054 + (CPNotificationCenter)defaultCenter
00055 {
00056 if (!CPNotificationDefaultCenter)
00057 CPNotificationDefaultCenter = [[CPNotificationCenter alloc] init];
00058
00059 return CPNotificationDefaultCenter;
00060 }
00061
00062 - (id)init
00063 {
00064 self = [super init];
00065
00066 if (self)
00067 {
00068 _namedRegistries = [CPDictionary dictionary];
00069 _unnamedRegistry = [[_CPNotificationRegistry alloc] init];
00070 }
00071 return self;
00072 }
00073
00082 - (void)addObserver:(id)anObserver selector:(SEL)aSelector name:(CPString)aNotificationName object:(id)anObject
00083 {
00084 var registry,
00085 observer = [[_CPNotificationObserver alloc] initWithObserver:anObserver selector:aSelector];
00086
00087 if (aNotificationName == nil)
00088 registry = _unnamedRegistry;
00089
00090 else if (!(registry = [_namedRegistries objectForKey:aNotificationName]))
00091 {
00092 registry = [[_CPNotificationRegistry alloc] init];
00093 [_namedRegistries setObject:registry forKey:aNotificationName];
00094 }
00095
00096 [registry addObserver:observer object:anObject];
00097 }
00098
00103 - (void)removeObserver:(id)anObserver
00104 {
00105 var name = nil,
00106 names = [_namedRegistries keyEnumerator];
00107
00108 while (name = [names nextObject])
00109 [[_namedRegistries objectForKey:name] removeObserver:anObserver object:nil];
00110
00111 [_unnamedRegistry removeObserver:anObserver object:nil];
00112 }
00113
00120 - (void)removeObserver:(id)anObserver name:(CPString)aNotificationName object:(id)anObject
00121 {
00122 if (aNotificationName == nil)
00123 {
00124 var name = nil,
00125 names = [_namedRegistries keyEnumerator];
00126
00127 while (name = [names nextObject])
00128 [[_namedRegistries objectForKey:name] removeObserver:anObserver object:anObject];
00129
00130 [_unnamedRegistry removeObserver:anObserver object:anObject];
00131 }
00132 else
00133 [[_namedRegistries objectForKey:aNotificationName] removeObserver:anObserver object:anObject];
00134 }
00135
00141 - (void)postNotification:(CPNotification)aNotification
00142 {
00143 if (!aNotification)
00144 [CPException raise:CPInvalidArgumentException reason:"postNotification: does not except 'nil' notifications"];
00145
00146 _CPNotificationCenterPostNotification(self, aNotification);
00147 }
00148
00155 - (void)postNotificationName:(CPString)aNotificationName object:(id)anObject userInfo:(CPDictionary)aUserInfo
00156 {
00157 _CPNotificationCenterPostNotification(self, [[CPNotification alloc] initWithName:aNotificationName object:anObject userInfo:aUserInfo]);
00158 }
00159
00165 - (void)postNotificationName:(CPString)aNotificationName object:(id)anObject
00166 {
00167 _CPNotificationCenterPostNotification(self, [[CPNotification alloc] initWithName:aNotificationName object:anObject userInfo:nil]);
00168 }
00169
00170 @end
00171
00172 var _CPNotificationCenterPostNotification = function( self, aNotification)
00173 {
00174 [self._unnamedRegistry postNotification:aNotification];
00175 [[self._namedRegistries objectForKey:[aNotification name]] postNotification:aNotification];
00176 }
00177
00178
00179
00180
00181
00182 @implementation _CPNotificationRegistry : CPObject
00183 {
00184 CPDictionary _objectObservers;
00185 BOOL _observerRemovalCount;
00186 }
00187
00188 - (id)init
00189 {
00190 self = [super init];
00191
00192 if (self)
00193 {
00194 _observerRemovalCount = 0;
00195 _objectObservers = [CPDictionary dictionary];
00196 }
00197
00198 return self;
00199 }
00200
00201 -(void)addObserver:(_CPNotificationObserver)anObserver object:(id)anObject
00202 {
00203
00204
00205 if (!anObject)
00206 anObject = [CPNull null];
00207
00208
00209 var observers = [_objectObservers objectForKey:[anObject UID]];
00210
00211 if (!observers)
00212 {
00213 observers = [];
00214 [_objectObservers setObject:observers forKey:[anObject UID]];
00215 }
00216
00217
00218 observers.push(anObserver);
00219 }
00220
00221 -(void)removeObserver:(id)anObserver object:(id)anObject
00222 {
00223 var removedKeys = [];
00224
00225
00226 if (anObject == nil)
00227 {
00228 var key = nil,
00229 keys = [_objectObservers keyEnumerator];
00230
00231
00232 while (key = [keys nextObject])
00233 {
00234 var observers = [_objectObservers objectForKey:key],
00235 count = observers ? observers.length : 0;
00236
00237 while (count--)
00238 if ([observers[count] observer] == anObserver)
00239 {
00240 ++_observerRemovalCount;
00241 observers.splice(count, 1);
00242 }
00243
00244 if (!observers || observers.length == 0)
00245 removedKeys.push(key);
00246 }
00247 }
00248 else
00249 {
00250 var key = [anObject UID],
00251 observers = [_objectObservers objectForKey:key];
00252 count = observers ? observers.length : 0;
00253
00254 while (count--)
00255 if ([observers[count] observer] == anObserver)
00256 {
00257 ++_observerRemovalCount;
00258 observers.splice(count, 1)
00259 }
00260
00261 if (!observers || observers.length == 0)
00262 removedKeys.push(key);
00263 }
00264
00265 var count = removedKeys.length;
00266
00267 while (count--)
00268 [_objectObservers removeObjectForKey:removedKeys[count]];
00269 }
00270
00271 - (void)postNotification:(CPNotification)aNotification
00272 {
00273
00274
00275
00276
00277
00278
00279
00280
00281 var observerRemovalCount = _observerRemovalCount,
00282 object = [aNotification object],
00283 observers = nil;
00284
00285 if (object != nil && (observers = [[_objectObservers objectForKey:[object UID]] copy]))
00286 {
00287 var currentObservers = observers,
00288 count = observers.length;
00289
00290 while (count--)
00291 {
00292 var observer = observers[count];
00293
00294
00295
00296 if ((observerRemovalCount === _observerRemovalCount) || [currentObservers indexOfObjectIdenticalTo:observer] !== CPNotFound)
00297 [observer postNotification:aNotification];
00298 }
00299 }
00300
00301
00302 observers = [[_objectObservers objectForKey:[[CPNull null] UID]] copy];
00303
00304 if (!observers)
00305 return;
00306
00307 var observerRemovalCount = _observerRemovalCount,
00308 count = observers.length,
00309 currentObservers = observers;
00310
00311 while (count--)
00312 {
00313 var observer = observers[count];
00314
00315
00316
00317 if ((observerRemovalCount === _observerRemovalCount) || [currentObservers indexOfObjectIdenticalTo:observer] !== CPNotFound)
00318 [observer postNotification:aNotification];
00319 }
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