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#include "WOScriptedComponent.h" 23#include <NGObjWeb/WOTemplateBuilder.h> 24#include <NGScripting/NGScriptLanguage.h> 25#include "common.h" 26 27@interface NSObject(misc) 28- (void)applyStandardClasses; 29- (BOOL)isScriptFunction; 30 31- (id)callScriptFunction:(NSString *)_name withObject:(id)_arg0; 32- (id)evaluateScript:(NSString *)_script source:(NSString *)_s line:(int)_line; 33 34@end 35 36@interface WOComponent(UsedPrivates) 37- (id)initWithName:(NSString *)_cname 38 template:(WOTemplate *)_template 39 inContext:(WOContext *)_ctx; 40@end 41 42@interface WOComponentScript(UsedPrivates) 43- (id)initScriptWithComponent:(id)_comp; 44@end 45 46@implementation WOScriptedComponent 47 48static BOOL logScriptKVC = NO; 49static BOOL logScriptInit = NO; 50static BOOL logScriptDealloc = NO; 51 52+ (void)initialize { 53 static BOOL didInit = NO; 54 if (!didInit) { 55 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; 56 didInit = YES; 57 logScriptKVC = [ud boolForKey:@"WOLogScriptKVC"]; 58 logScriptInit = [ud boolForKey:@"WOLogScriptInit"]; 59 logScriptDealloc = [ud boolForKey:@"WOLogScriptDealloc"]; 60 } 61} 62 63- (id)initWithName:(NSString *)_cname 64 template:(WOTemplate *)_template 65 inContext:(WOContext *)_ctx 66{ 67 if ((self = [super initWithName:_cname template:_template inContext:_ctx])) { 68 self->script = [[_template componentScript] retain]; 69 70 self->language = 71 [[NGScriptLanguage languageWithName:[self->script language]] retain]; 72 if (self->language == nil) { 73 [self logWithFormat: 74 @"did not find engine for script language %@", 75 [self->script language]]; 76 RELEASE(self); 77 return nil; 78 } 79 80 if ((self->shadow = [self->language createShadowForMaster:self]) == nil) { 81 [self logWithFormat: 82 @"could not create shadow for component in language %@", 83 self->language]; 84 RELEASE(self); 85 return nil; 86 } 87 88 if ([self->shadow respondsToSelector:@selector(applyStandardClasses)]) 89 [(id)self->shadow applyStandardClasses]; 90 91 [self->script initScriptWithComponent:self]; 92 93 if (logScriptInit) 94 [self logWithFormat:@"created scripted component: %@", self]; 95 } 96 return self; 97} 98 99- (void)dealloc { 100 if (logScriptDealloc) 101 [self logWithFormat:@"will dealloc scripted component: %@", self]; 102 103 [self->shadow invalidateShadow]; /* ensure shadow is dead ;-) */ 104 RELEASE(self->shadow); 105 RELEASE(self->language); 106 RELEASE(self->script); 107 RELEASE(self->template); 108 [super dealloc]; 109} 110 111/* accessors */ 112 113- (void)setTemplate:(id)_template { 114 ASSIGN(self->template, _template); 115} 116- (WOElement *)_woComponentTemplate { 117 return self->template; 118} 119 120- (BOOL)isScriptedComponent { 121 return YES; 122} 123 124/* scripting */ 125 126- (id)evaluateScript:(NSString *)_script language:(NSString *)_lang 127 source:(NSString *)_src line:(unsigned)_line 128{ 129 return [self->shadow evaluateScript:_script source:_src line:_line]; 130} 131 132/* notification mapping */ 133 134- (void)awake { 135 [super awake]; 136 137 if ([self->shadow hasFunctionNamed:@"awake"]) 138 [self->shadow callScriptFunction:@"awake"]; 139} 140- (void)sleep { 141 if ([self->shadow hasFunctionNamed:@"sleep"]) 142 [self->shadow callScriptFunction:@"sleep"]; 143 144 //[self debugWithFormat:@"vars: %@", [self variableDictionary]]; 145 [super sleep]; 146} 147 148/* script properties */ 149 150- (BOOL)takeValue:(id)_value forJSPropertyNamed:(NSString *)_key { 151 NSAssert1(self->shadow, @"missing shadow for component %@", self); 152 [self->shadow setObject:_value forKey:_key]; 153 return YES; 154} 155- (id)valueForJSPropertyNamed:(NSString *)_key { 156 [self debugWithFormat:@"value for prop %@", _key]; 157 NSAssert1(self->shadow, @"missing shadow for component %@", self); 158 return [self->shadow objectForKey:_key]; 159} 160 161/* extra variables */ 162 163- (void)setObject:(id)_obj forKey:(NSString *)_key { 164 //[self debugWithFormat:@"setObject:%@ forKey:%@", _obj, _key]; 165 NSAssert1(self->shadow, @"missing shadow for component %@", self); 166 [self->shadow setObject:_obj forKey:_key]; 167} 168- (id)objectForKey:(NSString *)_key { 169 NSAssert1(self->shadow, @"missing shadow for component %@", self); 170 return [self->shadow objectForKey:_key]; 171} 172 173/* key-value coding */ 174 175- (void)takeValue:(id)_value forKey:(NSString *)_key { 176 NSString *funcName; 177 id func; 178 unsigned len; 179 unsigned char *buf; 180 181 len = [_key cStringLength]; 182 buf = malloc(len + 4); 183 [_key getCString:&(buf[3])]; 184 buf[0] = 's'; buf[1] = 'e'; buf[2] = 't'; 185 buf[len + 3] = '\0'; 186 if (len > 0) buf[3] = toupper(buf[3]); 187 funcName = [NSString stringWithCString:buf length:(len + 3)]; 188 free(buf); 189 190 if ((func = [self->shadow objectForKey:funcName])) { 191 if ([func isScriptFunction]) { 192 id result; 193 194 if (logScriptKVC) { 195 [self logWithFormat:@"KVC: for key %@ call %@(%@)", 196 _key, funcName, _value]; 197 } 198 199 result = [self->shadow callScriptFunction:funcName withObject:_value]; 200 } 201 else { 202 [self logWithFormat: 203 @"KVC: object stored at '%@' is not a function, " 204 @"could not set value for key %@ !", 205 funcName, _key]; 206 } 207 } 208 else { 209 if (logScriptKVC) { 210 [self logWithFormat:@"KVC: assign %@=%@ (no func '%@')", 211 _key, _value, funcName]; 212 } 213 214 [self->shadow setObject:_value forKey:_key]; 215 } 216} 217 218- (id)valueForKey:(NSString *)_key { 219 id obj; 220 221 //[self logWithFormat:@"script: valueForKey:%@", _key]; 222 223 if ((obj = [self->shadow objectForKey:_key])) { 224 if ([obj isScriptFunction]) { 225 if (logScriptKVC) { 226 [self logWithFormat:@"KVC: for key %@ call %@", 227 _key, _key]; 228 } 229 obj = [self->shadow callScriptFunction:_key]; 230 } 231 else { 232 if (logScriptKVC) { 233 [self logWithFormat:@"KVC: valueForKey(%@): %@", 234 _key, obj]; 235 } 236 } 237 return obj; 238 } 239 else { 240 if (logScriptKVC) { 241 [self logWithFormat:@"KVC: get value for key %@ from WOComponent", 242 _key]; 243 } 244 return [super valueForKey:_key]; 245 } 246} 247 248/* logging */ 249 250- (NSString *)loggingPrefix { 251 return [NSString stringWithFormat:@"script<%@>[0x%p]", [self name], self]; 252} 253 254@end /* WOScriptedComponent */ 255 256@implementation NSObject(ScriptFunc) 257 258- (BOOL)isScriptFunction { 259 return NO; 260} 261 262@end /* NSObject(ScriptFunc) */ 263