1/* 2 Copyright (C) 2000-2005 SKYRIX Software AG 3 4 This file is part of SOPE. 5 6 SOPE is free software; you can redistribute it and/or modify it under 7 the terms of the GNU Lesser General Public License as published by the 8 Free Software Foundation; either version 2, or (at your option) any 9 later version. 10 11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 14 License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with SOPE; see the file COPYING. If not, write to the 18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 19 02111-1307, USA. 20*/ 21 22/* 23 WESwitch { selection | selections }; 24 WECase { key | keys }; 25 WEDefaultCase {}; 26 27 Warning: The DefaultCase must appear at the last position!!! 28*/ 29 30/* 31 example: 32 33 // wod: 34 Switch: WESwitch { selection = selection; }; 35 FirstCase: WECase { key = "first"; }; 36 SecondCase: WECase { keys = ("second", "third"); }; 37 DefaultCase: WEDefaultCase {}; 38 39 // html: 40 <#Switch> 41 <#FirstCase>content of first case</#FirstCase> 42 <#SecondCase>content of second case</#SecondCase> 43 <#DefaultCase>content of default case</#SecondCase> 44 </#Switch> 45 46*/ 47#include <NGObjWeb/WODynamicElement.h> 48 49@class WOAssociation; 50 51@interface WESwitch : WODynamicElement 52{ 53@protected 54 WOAssociation *selection; // string -> single switch 55 WOAssociation *selections; // array -> multi switch 56 WOElement *template; 57} 58@end 59 60@interface WECase : WODynamicElement 61{ 62 WOAssociation *key; // string -> unique identifier 63 WOAssociation *keys; // array of unique identifiers 64 65 WOAssociation *defaultCase; // emulates a WEDefaultCase DEPRECATED!!! 66 67 WOElement *template; 68} 69@end 70 71@interface WEDefaultCase : WODynamicElement 72{ 73 WOElement *template; 74} 75@end 76 77#include "common.h" 78 79#if DEBUG 80static NSString *WESwitch_DefaultCaseFound = @"WESwitch_DefaultCaseFound"; 81#endif 82static NSString *WESwitch_CaseDidMatch = @"WESwitch_CaseDidMatch"; 83static NSString *WESwitchSelection = @"WESwitchSelection"; 84static NSString *WESwitchSelections = @"WESwitchSelections"; 85static NSString *WESwitchDict = @"WESwitchDict"; 86 87@implementation WESwitch 88 89- (id)initWithName:(NSString *)_name 90 associations:(NSDictionary *)_config 91 template:(WOElement *)_subs 92{ 93 if ((self = [super initWithName:_name associations:_config template:_subs])) { 94 self->selection = WOExtGetProperty(_config, @"selection"); 95 self->selections = WOExtGetProperty(_config, @"selections"); 96 97 self->template = [_subs retain]; 98 } 99 return self; 100} 101 102- (void)dealloc { 103 [self->template release]; 104 [self->selection release]; 105 [self->selections release]; 106 [super dealloc]; 107} 108 109/* processing requests */ 110 111- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx { 112 WOComponent *cmp = nil; 113 NSArray *array = nil; 114 NSString *k = nil; 115 unsigned i, cnt; 116 BOOL doLazy = YES; 117 118 119 cmp = [_ctx component]; 120 array = [self->selections valueInComponent:cmp]; 121 k = [self->selection valueInComponent:cmp]; 122 cnt = [array count]; 123 124 if (_req == nil) { 125 [self->template takeValuesFromRequest:_req inContext:_ctx]; 126 } 127 else if (k) { 128 [_ctx setObject:k forKey:WESwitchSelection]; 129 [self->template takeValuesFromRequest:_req inContext:_ctx]; 130 [_ctx removeObjectForKey:WESwitchSelection]; 131 } 132 else if (doLazy) { 133 for (i = 0; i < cnt; i++) { 134 [_ctx setObject:[array objectAtIndex:i] forKey:WESwitchSelection]; 135 [self->template takeValuesFromRequest:_req inContext:_ctx]; 136 } 137 if (cnt == 0) { 138 [_ctx setObject:array forKey:WESwitchSelections]; 139 [self->template takeValuesFromRequest:_req inContext:_ctx]; 140 [_ctx removeObjectForKey:WESwitchSelections]; 141 } 142 [_ctx removeObjectForKey:WESwitchSelection]; 143 } 144 else if (cnt > 0) { 145 NSLog(@"Warning(%s):This case is not implemented!!!", __PRETTY_FUNCTION__); 146 [self->template takeValuesFromRequest:_req inContext:_ctx]; 147 } 148 149#if DEBUG 150 else { 151 [cmp logWithFormat: 152 @"Warning! WESwitch: Neither 'selection' nor 'selections' set!!!"]; 153 } 154#endif 155 156 [_ctx removeObjectForKey:WESwitch_CaseDidMatch]; 157} 158 159- (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx { 160 return [self->template invokeActionForRequest:_request inContext:_ctx]; 161} 162 163/* generating response */ 164 165- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { 166 WOComponent *cmp = nil; 167 NSArray *array = nil; 168 NSString *k = nil; 169 unsigned i, cnt; 170 BOOL doLazy = YES; 171 172 173 cmp = [_ctx component]; 174 array = [self->selections valueInComponent:cmp]; 175 k = [self->selection valueInComponent:cmp]; 176 cnt = [array count]; 177 178 if (_response == nil) { 179 [self->template appendToResponse:_response inContext:_ctx]; 180 } 181 else if (k) { 182 [_ctx setObject:k forKey:WESwitchSelection]; 183 [self->template appendToResponse:_response inContext:_ctx]; 184 [_ctx removeObjectForKey:WESwitchSelection]; 185 } 186 else if (doLazy) { 187 for (i=0; i<cnt; i++) { 188 [_ctx setObject:[array objectAtIndex:i] forKey:WESwitchSelection]; 189 [self->template appendToResponse:_response inContext:_ctx]; 190 } 191 if (cnt == 0) { 192 [_ctx setObject:array forKey:WESwitchSelections]; 193 [self->template appendToResponse:_response inContext:_ctx]; 194 [_ctx removeObjectForKey:WESwitchSelections]; 195 } 196 [_ctx removeObjectForKey:WESwitchSelection]; 197 } 198 else if (cnt > 0) { 199 NSMutableDictionary *dict = nil; 200 201 // get subcontent of WECases 202 [_ctx setObject:array forKey:WESwitchSelections]; 203 [self->template appendToResponse:_response inContext:_ctx]; 204 205 dict = [_ctx objectForKey:WESwitchDict]; 206 207 // append subcontent 208 if (dict) { 209 for (i=0; i<cnt; i++) { 210 NSString *k = [array objectAtIndex:i]; 211 NSData *c = [dict objectForKey:k]; // subcontent of WECase 212 213 if (c) 214 [_response appendContentData:c]; 215 } 216 } 217 218 [_ctx removeObjectForKey:WESwitchDict]; 219 [_ctx removeObjectForKey:WESwitchSelections]; 220 } 221 222#if DEBUG 223 else { 224 [cmp logWithFormat: 225 @"Warning! WESwitch: Neither 'selection' nor 'selections' set!!!"]; 226 } 227#endif 228 229 [_ctx removeObjectForKey:WESwitch_CaseDidMatch]; 230} 231 232@end /* WESwitch */ 233 234@implementation WECase 235 236- (id)initWithName:(NSString *)_name 237 associations:(NSDictionary *)_config 238 template:(WOElement *)_t 239{ 240 if ((self = [super initWithName:_name associations:_config template:_t])) { 241 self->key = WOExtGetProperty(_config, @"key"); 242 self->keys = WOExtGetProperty(_config, @"keys"); 243 244 // DEPRECATED!!! 245 self->defaultCase = WOExtGetProperty(_config, @"default"); 246 247 self->template = [_t retain]; 248 } 249 return self; 250} 251 252- (void)dealloc { 253 [self->template release]; 254 [self->key release]; 255 [self->keys release]; 256 [self->defaultCase release]; 257 [super dealloc]; 258} 259 260/* processing requests */ 261 262- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx { 263 NSArray *selections = nil; 264 NSString *selection = nil; 265 NSString *k = nil; 266 NSArray *ks = nil; 267 268 k = [self->key stringValueInComponent:[_ctx component]]; 269 ks = [self->keys valueInComponent:[_ctx component]]; 270 271 selections = [_ctx objectForKey:WESwitchSelections]; 272 selection = [_ctx objectForKey:WESwitchSelection]; 273 274 if ([self->defaultCase boolValueInComponent:[_ctx component]]) { 275 if ([_ctx objectForKey:WESwitch_CaseDidMatch] == nil) 276 [self->template takeValuesFromRequest:_req inContext:_ctx]; 277 return; 278 } 279 280 if ((k == nil) && (ks == nil)) { 281#if DEBUG 282 [[_ctx component] logWithFormat: 283 @"Warning! WECase: Neither 'key' nor 'keys' set!!!"]; 284#endif 285 return; 286 } 287 if ((k != nil) && (ks != nil)) { 288#if DEBUG 289 [[_ctx component] logWithFormat: 290 @"Warning! WECase: Both, 'key' and 'keys' are set!!!"]; 291#endif 292 return; 293 } 294 295 if (_req == nil) { 296 [self->template takeValuesFromRequest:nil inContext:_ctx]; 297 } 298 if (selection) { 299 if (k && [k isEqualToString:selection]) { 300 [self->template takeValuesFromRequest:_req inContext:_ctx]; 301 [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch]; 302 } 303 else if (ks && [ks containsObject:selection]) { 304 [self->template takeValuesFromRequest:_req inContext:_ctx]; 305 [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch]; 306 } 307 } 308 else if (selections && [selections count] > 0) { 309 NSLog(@"Warning(%s): This case is not implemented!", __PRETTY_FUNCTION__); 310 [self->template takeValuesFromRequest:_req inContext:_ctx]; 311 } 312} 313 314- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx { 315 return [self->template invokeActionForRequest:_req inContext:_ctx]; 316} 317 318/* generating response */ 319 320- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { 321 NSArray *selections = nil; 322 NSString *selection = nil; 323 NSString *k = nil; 324 NSArray *ks = nil; 325 326 k = [self->key stringValueInComponent:[_ctx component]]; 327 ks = [self->keys valueInComponent:[_ctx component]]; 328 329 selections = [_ctx objectForKey:WESwitchSelections]; 330 selection = [_ctx objectForKey:WESwitchSelection]; 331 332 if ([self->defaultCase boolValueInComponent:[_ctx component]]) { 333 if ([_ctx objectForKey:WESwitch_CaseDidMatch] == nil) 334 [self->template appendToResponse:_response inContext:_ctx]; 335 return; 336 } 337 338 if ((k == nil) && (ks == nil)) { 339#if DEBUG 340 [[_ctx component] warnWithFormat: 341 @"WECase: Neither 'key' nor 'keys' set!!!"]; 342#endif 343 return; 344 } 345 if ((k != nil) && (ks != nil)) { 346#if DEBUG 347 [[_ctx component] warnWithFormat: 348 @"WECase: Both, 'key' and 'keys' are set!!!"]; 349#endif 350 return; 351 } 352 353 if (_response == nil) { 354 [self->template appendToResponse:nil inContext:_ctx]; 355 } 356 if (selection) { 357 if (k && [k isEqualToString:selection]) { 358 [self->template appendToResponse:_response inContext:_ctx]; 359 [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch]; 360 } 361 else if (ks && [ks containsObject:selection]) { 362 [self->template appendToResponse:_response inContext:_ctx]; 363 [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch]; 364 } 365 } 366 else if (selections && [selections count] > 0) { 367 if ([selections containsObject:k]) { 368 static NSData *emptyData = nil; 369 NSMutableDictionary *dict = nil; 370 NSData *oldContent = nil; 371 372 if (emptyData == nil) 373 emptyData = [[NSData alloc] init]; 374 375 // get subcontent dictionary 376 dict = [_ctx objectForKey:WESwitchDict]; 377 if (dict == nil) 378 dict = [NSMutableDictionary dictionaryWithCapacity:[selections count]]; 379 380 // set new content 381 oldContent = [_response content]; 382 RETAIN(oldContent); 383 [_response setContent:emptyData]; 384 385 // append template to new content 386 [self->template appendToResponse:_response inContext:_ctx]; 387 388 // save new content in dict 389 if ([_response content]) 390 [dict setObject:[_response content] forKey:k]; 391 [_ctx setObject:dict forKey:WESwitchDict]; 392 393 // restore old content 394 [_response setContent:oldContent]; 395 [oldContent release]; oldContent = nil; 396 397 // TODO: use NSNumber here? 398 [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch]; 399 } 400 } 401} 402 403@end /* WECase */ 404 405@implementation WEDefaultCase 406 407- (id)initWithName:(NSString *)_name 408 associations:(NSDictionary *)_config 409 template:(WOElement *)_t 410{ 411 if ((self = [super initWithName:_name associations:_config template:_t])) { 412 self->template = [_t retain]; 413 } 414 return self; 415} 416 417- (void)dealloc { 418 [self->template release]; 419 [super dealloc]; 420} 421 422/* processing requests */ 423 424- (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx { 425 if (([_ctx objectForKey:WESwitch_CaseDidMatch] == nil)) 426 [self->template takeValuesFromRequest:_req inContext:_ctx]; 427} 428 429- (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx { 430 return [self->template invokeActionForRequest:_req inContext:_ctx]; 431} 432 433/* generating response */ 434 435- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { 436 if (([_ctx objectForKey:WESwitch_CaseDidMatch] == nil)) 437 [self->template appendToResponse:_response inContext:_ctx]; 438 439#if DEBUG 440 [_ctx setObject:@"Yes" forKey:WESwitch_DefaultCaseFound]; 441#endif 442} 443 444@end /* WEDefaultCase */ 445