// // $Id$ // // MCPClassDescription.m // MCPKit // // Created by Serge Cohen (serge.cohen@m4x.org) on 09/08/04. // Copyright (c) 2004 Serge Cohen. All rights reserved. // // Forked by the Sequel Pro team (sequelpro.com), April 2009 // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // More info at // More info at #import "MCPClassDescription.h" #import "MCPClassDescription+Private.h" #import "MCPEntrepriseNotifications.h" #import "MCPModel.h" #import "MCPAttribute.h" #import "MCPRelation.h" @implementation MCPClassDescription #pragma mark Class methods + (void) initialize { if (self = [MCPClassDescription class]) { [self setVersion:010101]; // Major.Minor.Revision -> MaMiRe } return; } #pragma mark Life cycle - (id) initInModel:(MCPModel *) iModel withName:(NSString *) iName { self = [super init]; if (self) { model = iModel; [self setName:iName]; attributes = [[NSMutableArray alloc] init]; relations = [[NSMutableArray alloc] init]; incomings = [[NSMutableArray alloc] init]; representedClass = nil; // NSLog(@"MAKING a new object : %@", self); } return self; } - (void) dealloc { // NSArray *theRelations; // unsigned int i; [name release]; [externalName release]; [attributes release]; while ([relations count]) { [(MCPRelation *)[relations objectAtIndex:0] invalidateRelation]; } [relations release]; while ([incomings count]) { [(MCPRelation *)[incomings objectAtIndex:0] invalidateRelation]; } [incomings release]; [super dealloc]; } #pragma mark NSCoding protocol - (id) initWithCoder:(NSCoder *) decoder { self = [super init]; if ((self) && ([decoder allowsKeyedCoding])) { model = [decoder decodeObjectForKey:@"MCPmodel"]; // NSLog(@"in MCPClassDescription initWithCoder, model = %@ (pointer = %p)", model, model); [self setName:[decoder decodeObjectForKey:@"MCPname"]]; [self setExternalName:[decoder decodeObjectForKey:@"MCPexternalName"]]; [self setAttributes:[decoder decodeObjectForKey:@"MCPattributes"]]; // [self setRelations:[decoder decodeObjectForKey:@"MCPrelations"]]; relations = [[NSMutableArray alloc] init]; incomings = [[NSMutableArray alloc] init]; representedClass = nil; [decoder decodeObjectForKey:@"MCPrelations"]; // The relation get linked properly while initted. } else { NSLog(@"For some reason, unable to decode MCPClassDescription from the coder!!!"); } return self; } - (void) encodeWithCoder:(NSCoder *) encoder { if (! [encoder allowsKeyedCoding]) { NSLog(@"In MCPClassDescription -encodeWithCoder : Unable to encode to a non-keyed encoder!!, will not perform encoding!!"); return; } // [encoder encodeObject:[self model] forKey:@"MCPmodel"]; [encoder encodeConditionalObject:[self model] forKey:@"MCPmodel"]; [encoder encodeObject:[self name] forKey:@"MCPname"]; [encoder encodeObject:[self externalName] forKey:@"MCPexternalName"]; [encoder encodeObject:[self attributes] forKey:@"MCPattributes"]; [encoder encodeObject:[self relations] forKey:@"MCPrelations"]; [encoder encodeObject:@"1.1.1" forKey:@"MCPversion"]; return; } #pragma mark Making new attributes and relations - (MCPAttribute *) addNewAttributeWithName:(NSString *) iName inPosition:(int) index { MCPAttribute *theAttribute = [[MCPAttribute alloc] initForClassDescription:self withName:iName]; // [self addAttribute:theAttribute]; [self insertObject:theAttribute inAttributesAtIndex:(index < 0) ? ([self countOfAttributes] + index + 1) : index]; [theAttribute release]; return theAttribute; } - (MCPRelation *) addNewRelationTo:(MCPClassDescription *) iTo name:(NSString *) iName inPostion:(int) index { MCPRelation *theRelation = [[MCPRelation alloc] initWithName:iName from:self to:iTo]; [theRelation release]; return theRelation; } #pragma mark Setters - (void) setName:(NSString *) iName { if (iName != name) { [name release]; name = [iName retain]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPModelChangedNotification object:model]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPClassDescriptionChangedNotification object:self]; representedClass = nil; } } - (void) setExternalName:(NSString *) iExternalName { if (iExternalName != externalName) { [externalName release]; externalName = [iExternalName retain]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPModelChangedNotification object:model]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPClassDescriptionChangedNotification object:self]; } } - (void) insertObject:(MCPAttribute *) iAttribute inAttributesAtIndex:(unsigned int) index { [attributes insertObject:iAttribute atIndex:index]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPModelChangedNotification object:model]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPClassDescriptionChangedNotification object:self]; } - (void) removeObjectFromAttributesAtIndex:(unsigned int) index { [attributes removeObjectAtIndex:index]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPModelChangedNotification object:model]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPClassDescriptionChangedNotification object:self]; } - (void) insertObject:(MCPRelation *) iRelation inRelationsAtIndex:(unsigned int) index { [relations insertObject:iRelation atIndex:index]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPModelChangedNotification object:model]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPClassDescriptionChangedNotification object:self]; } - (void) removeObjectFromRelationsAtIndex:(unsigned int) index { [relations removeObjectAtIndex:index]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPModelChangedNotification object:model]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPClassDescriptionChangedNotification object:self]; } #pragma mark Getters - (MCPModel *) model { return model; } - (NSString *) name { return name; } - (NSString *) externalName { return externalName; } - (NSArray *) attributes { return [NSArray arrayWithArray:attributes]; } - (unsigned int) countOfAttributes { return [attributes count]; } - (MCPAttribute *) objectInAttributesAtIndex:(unsigned int) index { return (MCPAttribute *)((NSNotFound != index) ? [attributes objectAtIndex:index] : nil); } - (unsigned int) indexOfAttribute:(id) iAttribute { return [attributes indexOfObject:iAttribute]; } - (NSArray *) relations { return [NSArray arrayWithArray:relations]; } - (unsigned int) countOfRelations { return [relations count]; } - (MCPRelation *) objectInRelationsAtIndex:(unsigned int) index { return (MCPRelation *)((NSNotFound != index) ? [relations objectAtIndex:index] : nil); } - (unsigned int) indexOfRelation:(id) iRelation { return [relations indexOfObject:iRelation]; } - (Class) representedClass { if (representedClass) { return representedClass; } representedClass = NSClassFromString(name); return representedClass; } #pragma mark Some general methods: - (BOOL) isEqual:(id) iObject // Equal to another class description if they have the same name. // Equal to a string if the string is equal to the className of the class description. { if ([iObject isKindOfClass:[MCPClassDescription class]]) { return [name isEqualToString:[(MCPClassDescription *)iObject name]]; } if ([iObject isKindOfClass:[NSString class]]) { return [name isEqualToString:(NSString *)iObject]; } return NO; } /* - (NSString *) description { return [NSString stringWithFormat:@"", [self name], self]; } - (NSString *) descriptionWithLocale:(NSDictionary *) locale { return [self description]; } */ #pragma mark Output for logging - (NSString *) descriptionWithLocale:(NSDictionary *) locale { NSMutableString *theOutput = [NSMutableString string]; unsigned i; [theOutput appendFormat:@"MCPClassDescription for class : %@ (table : %@)\n", [self name], [self externalName]]; for (i=0; [attributes count] != i; ++i) { MCPAttribute *theAttribute = (MCPAttribute *) [attributes objectAtIndex:i]; [theOutput appendFormat:@"attribute %u, name = %@, column = %@. Allows null : %c\n", i, [theAttribute name], [theAttribute externalName], ([theAttribute allowsNull] ? 'Y' : 'N')]; } return theOutput; } #pragma mark For debugging the retain counting - (id) retain { [super retain]; return self; } - (void) release { [super release]; return; } @end @implementation MCPClassDescription (Private) #pragma mark Setters - (void) setAttributes:(NSArray *) iAttributes { if (iAttributes != attributes) { [attributes release]; attributes = [[NSMutableArray alloc] initWithArray:iAttributes]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPModelChangedNotification object:model]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPClassDescriptionChangedNotification object:self]; } } - (void) setRelations:(NSArray *) iRelations { if (iRelations != relations) { [relations release]; relations = [[NSMutableArray alloc] initWithArray:iRelations]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPModelChangedNotification object:model]; [[NSNotificationCenter defaultCenter] postNotificationName:MCPClassDescriptionChangedNotification object:self]; } } - (void) insertObject:(MCPRelation *) iRelation inIncomingsAtIndex:(unsigned int) index { if ([iRelation destination] == self) { [incomings insertObject:iRelation atIndex:index]; } else { NSLog(@"in -[MCPClassDescription+Private insertObject:inIncomingsAtIndex:]. ERRROR : self is NOT the destination of the relation"); } } - (void) removeObjectFromIncomingsAtIndex:(unsigned int) index { [incomings removeObjectAtIndex:index]; } #pragma mark Getters - (NSArray *) incomings { return [NSArray arrayWithArray:incomings]; } - (unsigned int) countOfIncomings { return [incomings count]; } - (MCPRelation *) objectInIncomingsAtIndex:(unsigned int) index { return (MCPRelation *)[incomings objectAtIndex:index]; } - (unsigned int) indexOfIncoming:(id) iRelation { return [incomings indexOfObject:iRelation]; } @end