/*! @header ECXMLControlDefaultRule @abstract Module of Encore @availability OS X, GNUstep @copyright 2004, 2005, 2006 Oliver Langer Author: Oliver Langer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA <pre> ------------------------------------------------------------------------- Modification history 27.11.05 ola initial version 22.08.06 ola license changed ------------------------------------------------------------------------- </pre> */ #include <Encore/ECMemory.h> #include <Encore/ECXMLControlDefaultRule.h> @implementation ECXMLControlSetAttributeRule - init { self = [super init]; self->setterLookupUtil = [[ECXMLControlSetterLookupUtil alloc] init]; return self; } - (void) dealloc { if( nil != self->setterLookupUtil ) { [self->setterLookupUtil release]; } [super dealloc]; } - (BOOL) mayActOn: (ECXMLControlContext *) aContext { return [[[aContext event] eventId] isEqual: [ECXMLControlEvent eventId_addAttribute]]; } - (BOOL) actOn: (ECXMLControlContext *) aContext { id userObject; BOOL ignoreSubsequentRules = NO; NSAssert( [[[aContext event] eventId] isEqual: [ECXMLControlEvent eventId_addAttribute]], @"ECXMLControlSetAttributeRule::actOn: Expected an addAttribute event!" ); // fetch user object at top position userObject = [[aContext state] userObjectAtTopPosition]; if( nil == userObject ) { return NO; } EC_AUTORELEASEPOOL_BEGIN SEL methodToCall = [self->setterLookupUtil lookupMethodForAttributeName: [[aContext event] attributeName] ofObject: userObject]; if( NULL != methodToCall ) { [userObject performSelector: methodToCall withObject: [[aContext event] attributeValue]]; ignoreSubsequentRules = YES; } EC_AUTORELEASEPOOL_END return ignoreSubsequentRules; } @end // ------------------------------------- ECXMLControlLinkObjectRule @implementation ECXMLControlLinkObjectRule - init { self = [super init]; self->setterLookupUtil = [[ECXMLControlSetterLookupUtil alloc] init]; return self; } - (void) dealloc { if( nil != self->setterLookupUtil ) { [self->setterLookupUtil release]; } [super dealloc]; } - (BOOL) actOn: (ECXMLControlContext *) aContext { BOOL elementRemovedFromStack = NO; NSAssert( [[[aContext event] eventId] isEqual: [ECXMLControlEvent eventId_elementEnded]], @"ECXMLControlLinkObjectRule::actOn: Expected an END ELEMENT event!" ); EC_AUTORELEASEPOOL_BEGIN if( [[aContext state] countStackObjects] > 1 ) { /* * For the current top user object there exists a (potential) parent * object -> so remove it from the stack and add (link) it to the parent * object */ id oldTopUserObject = [[[aContext state] popUserObject] autorelease]; SEL methodToCall; elementRemovedFromStack = YES; /** * Look up for a related setter method of the current (new) top object. * Call it, if existent */ methodToCall = [self->setterLookupUtil lookupMethodForAttributeName: [[aContext event] elementName] ofObject: [[aContext state] userObjectAtTopPosition]]; if( NULL != methodToCall ) { [[[aContext state] userObjectAtTopPosition] performSelector: methodToCall withObject: oldTopUserObject]; } } EC_AUTORELEASEPOOL_END return elementRemovedFromStack; } - (BOOL) mayActOn: (ECXMLControlContext *) aContext { return [[[aContext event] eventId] isEqual: [ECXMLControlEvent eventId_elementEnded]]; } @end // ------------------------------------- ECXMLControlSetterLookupUtil @implementation ECXMLControlSetterLookupUtil - init { self = [super init]; self->namesForSetterMethods = [[NSMutableArray alloc] init]; /* * The following format strings must contain "%@%@", where the * first substitution string will be replaced by the first letter of * the attribute name, which may be in lower or in upper case. The remaining * substition string will be replaced by the remaining characters of the * attribute name */ [self addMethodNameSchema: @"set%@%@:"]; [self addMethodNameSchema: @"add%@%@:"]; return self; } - (void) dealloc { if( nil != self->namesForSetterMethods ) { [self->namesForSetterMethods release]; } [super dealloc]; } - addMethodNameSchema: (NSString *) aMethodNameSchema { [self->namesForSetterMethods addObject: aMethodNameSchema]; return self; } - (SEL) lookupMethodForAttributeName: (NSString *) anAttributeName ofObject: (id) aTargetObject { SEL toReturn = NULL; EC_AUTORELEASEPOOL_BEGIN SEL methodToCall; int i; NSString *firstCharacter = [anAttributeName substringToIndex: 1]; NSString *remainingChars = [anAttributeName substringFromIndex: 1]; for( i = 0; i < [self->namesForSetterMethods count]; i++ ) { NSString *methodName; // try with the first character as uppercase character methodName = [[[NSString alloc] initWithFormat: [self->namesForSetterMethods objectAtIndex: i], [firstCharacter uppercaseString], remainingChars] autorelease]; methodToCall = NSSelectorFromString( methodName ); if( NULL != methodToCall ) { if( [aTargetObject respondsToSelector: methodToCall] ) { // method found toReturn = methodToCall; break; } } // try with the first character as lowercase character methodName = [[[NSString alloc] initWithFormat: [self->namesForSetterMethods objectAtIndex: i], [firstCharacter lowercaseString], remainingChars] autorelease]; methodToCall = NSSelectorFromString( methodName ); if( NULL != methodToCall ) { if( [aTargetObject respondsToSelector: methodToCall] ) { // method found toReturn = methodToCall; break; } } } EC_AUTORELEASEPOOL_END return toReturn; } @end