This is GeneralFormCell.m in view mode; [Download] [Up]
/*------------------------------------------------------------------- Copyright 1991, 1992 Don McGregor The implementation of a subclass that adds new types of error checking to a FormCell class. 9/2/91 Don McGregor 3/19/92: cleaned up some code, made things more compact, attemped to do a custom inspector for IB without success. Made changes to -init to make it work better with GeneralForm in a custom IB palette. 3/21/92 Screw it. Rewrote it extensively to get rid of the stuff that requires an int to be set that switches between modes. Now it works off a SEL that corresponds to a method name, which makes it all a lot more extensible. Backward compatible with the old way, so long as an initial qualifier function is not set.IB inspector for the Cell now works. Stupid bug was throwing me off. You may freely use this code in any way you wish. however, you may not charge any money for the use of it. No warranty of any kind, etc, etc. -------------------------------------------------------------------*/ #import "GeneralFormCell.h" #import "GeneralFormCellInspector.h" #import <strings.h> #import <stdio.h> #import <stdlib.h> //A psuedo-class variable. This won't be inherited by subclasses, //but will be shared among all instances of this class. It's //terminated with a null char as a sentinel. //See comments for NXBrowser delegate methods static char *typeList[] = {"anyType:", "isDouble:", "posDouble:", "nonNegDouble:", "isFloat:", "posFloat:", "nonNegFloat:", "isInt:", "posInt:", "nonNegInt:", "isDate:", "isSSN:", "\0"}; @implementation GeneralFormCell - init { /*------------------------------------------------------------------- Does some initialization work on a few things to get a "standard" look and feel. Sets the entry type to be anyType:, which accepts all input. -------------------------------------------------------------------*/ [super init]; [self setTitleAlignment:NX_RIGHTALIGNED]; [self setBezeled:YES]; [self setEntryQual:"anyType:"]; return self; } -(BOOL)isEntryAcceptable:(const char *)aString { /*------------------------------------------------------------------- Override of the FormCell method. this is a reworking of the way that NeXT went about it. They relied on using a case statement and defined constants to dispatch to the correct entry field checker. that really doesn't scale too well; you need to keep track of what constants have already been used and so on. Blech. This uses the SEL that points to the entry checking method. Some magic with pointers to functions and prototypes; see methodFor: method in Object docs. -------------------------------------------------------------------*/ typedef BOOL (*entryCheck)(id, SEL, NXAtom); int entryType; entryCheck entryCheckingFcn; //get ptr to fcn that does the checking entryCheckingFcn = (entryCheck)[self methodFor:entryQual]; if([self respondsTo:entryQual]) { return entryCheckingFcn(self, entryQual, aString); } //Fallback. It might be that the programmer is trying to //use the old method, which involves setting an integer. //This is here for backward compatability. //If no entry qualifier is set, we look at the //entryType field next. entryType = [super entryType]; if((entryType >=0) && (entryType <= 7)) return [super isEntryAcceptable:aString]; //Oughta never get here. If it does, the programmer screwed up //by specifiying a non-existent entry Qualifier. In effect, this //is an NX_ANYTYPE return YES; } -(BOOL)anyType:(const char *)aString { /*------------------------------------------------------------------- Returns YES, always. Any type of field is acceptable. -------------------------------------------------------------------*/ return YES; } -(BOOL)isDouble:(const char *)aString { /*------------------------------------------------------------------- Checks for a double type entry. Works by sending messages to super that use the old data checking routines. -------------------------------------------------------------------*/ [self setEntryType:NX_DOUBLETYPE]; return [super isEntryAcceptable:aString]; } -(BOOL)posDouble:(const char *)aString { /*------------------------------------------------------------------- Checks for a positive double type entry. Works by sending messages to super that use the old data checking routines. -------------------------------------------------------------------*/ [self setEntryType:NX_POSDOUBLETYPE]; return [super isEntryAcceptable:aString]; } -(BOOL)nonNegDouble:(const char *)aString { /*------------------------------------------------------------------- Checks for a non-negative double, that is any double greater than or equal to zero. --------------------------------------------------------------------*/ double theNumber; //If it is a double type, make sure it's greater than zero. //If it's not, we know to return false. if(([self isDouble:aString]) == YES) { theNumber = atof(aString); if(theNumber >= 0.0) return YES; } return NO; } -(BOOL)isFloat:(const char *)aString { /*------------------------------------------------------------------- Checks for a float type entry. Works by sending messages to super that use the old data checking routines. -------------------------------------------------------------------*/ [self setEntryType:NX_FLOATTYPE]; return [super isEntryAcceptable:aString]; } -(BOOL)posFloat:(const char *)aString { /*------------------------------------------------------------------- Checks for a positive float type entry. Works by sending messages to super that use the old data checking routines. -------------------------------------------------------------------*/ [self setEntryType:NX_POSFLOATTYPE]; return [super isEntryAcceptable:aString]; } -(BOOL)nonNegFloat:(const char *)aString { /*------------------------------------------------------------------- Checks for a non-neg float type entry. -------------------------------------------------------------------*/ float theNumber; //If it is a float type, make sure it's greater than zero. //If it's not, we know to return false. if(([self isFloat:aString]) == YES) { theNumber = atof(aString); if(theNumber >= 0.0) return YES; } return NO; } -(BOOL)isInt:(const char*)aString { /*------------------------------------------------------------------- A boolean check to see if the string parses into an int. This is more restrictive than just a "number." -------------------------------------------------------------------*/ [self setEntryType:NX_INTTYPE]; return [super isEntryAcceptable:aString]; } -(BOOL)posInt:(const char *)aString { /*------------------------------------------------------------------- Checks for a positive float type entry. Works by sending messages to super that use the old data checking routines. -------------------------------------------------------------------*/ [self setEntryType:NX_POSINTTYPE]; return [super isEntryAcceptable:aString]; } -(BOOL)nonNegInt:(const char *)aString { /*------------------------------------------------------------------- Similar to the above, but this checks for the possiblity of a non-negative integer. -------------------------------------------------------------------*/ int theNumber; //If it is an int type, make sure it's greater than zero. //If it's not, we know to return false. if([self isInt:aString] == YES) { theNumber = atoi(aString); if(theNumber >= 0) return YES; } return NO; } -(BOOL)isDate:(const char *)aString { /*------------------------------------------------------------------- Checks the string passed to see if it is something like a date, eg mo/day/yr. Only very modest checking is implemented here, and this could be much improved. We don't check to see if a date is valid for a possible month (2/31/92 would pass, for example.) -------------------------------------------------------------------*/ int day = -1, month = -1, year = -1; BOOL okInput = YES; sscanf(aString, "%d/%d/%d", &month, &day, &year); if((day <= 0) || (day > 31)) okInput = NO; if((month <= 0) || (month > 12)) okInput = NO; if(year <= 0) okInput = NO; return okInput; } -(BOOL)isSSN:(const char*)aString { /*------------------------------------------------------------------- Checks to see if the input is an SSN of the form nnn-nn-nnnn. the first number should be between zero and 999, the second between zero and 99, the third between zero and 9999. SSA may put more restrictions on the numbers, but I don't know about them. The field lengths should also be appropriate; eg, 1-1-1 should not be allowed, but 001-01-0001 should be. -------------------------------------------------------------------*/ int number1 = -1, number2 = -1, number3 = -1; BOOL okInput = YES; sscanf(aString, "%d-%d-%d", &number1, &number2, &number3); //Check to see if the numbers are within //reasonable bounds. if((number1 < 0) || (number1 > 999)) okInput = NO; if((number2 < 0) || (number2 > 99)) okInput = NO; if((number3 < 0) || (number3 > 9999)) okInput = NO; //check on lengths of the fields if(strlen(aString) != 11) okInput = NO; if(okInput) //Put in this check to prevent past end of array errors { if((aString[3] != '-') || (aString[6] != '-')) okInput = NO; } return okInput; } -(BOOL)isNumber:(const char*)aString { /*------------------------------------------------------------------- A boolean check to see if the string parses into a number, any number--double, integer, postive, negative, whatever. -------------------------------------------------------------------*/ int itsType; BOOL result; itsType = [self entryType]; [self setEntryType:NX_DOUBLETYPE]; result = [super isEntryAcceptable:aString]; [self setEntryType:itsType]; return result; } -setEntryQual:(NXAtom)aString; { /*------------------------------------------------------------------- sets the entry qualifying method to be the method who's string is passed. -------------------------------------------------------------------*/ SEL filterSEL; filterSEL = sel_getUid((STR)aString); if([self respondsTo:filterSEL]) entryQual = filterSEL; else [self error:"attempt to set invalid entry qualifier; no such method as %s exists\n", aString]; return self; } -(STR)currentQualName { /*------------------------------------------------------------------- Returns the string name for the method of the current entry qualifying method. -------------------------------------------------------------------*/ return sel_getName(entryQual); } -(const char *)inspectorName { /*----------------------------------------------------------------- Returns the name of the Cell's inspector for IB. -----------------------------------------------------------------*/ return "GeneralFormCellInspector"; } -(int)browser:sender fillMatrix:matrix inColumn:(int)column { /*------------------------------------------------------------------- Delegate method to fill the browser in the IB inspector with the names of the valid qualifiers. -------------------------------------------------------------------*/ int i, j=0; id browserCell; while(*typeList[j]) { [matrix addRow]; i = [[matrix cellList] count]; browserCell = [matrix cellAt:(i-1) :0]; [browserCell setStringValue:typeList[j]]; [browserCell setLeaf:YES]; [browserCell setLoaded:YES]; j++; } return j; } -(BOOL)browser:sender columnIsValid:(int)column { /*------------------------------------------------------------------- More delegate methods for the NXBrowser in the IB inspector. -------------------------------------------------------------------*/ return YES; } -write:typedStream { /*------------------------------------------------------------------- Archiving stuff. -------------------------------------------------------------------*/ [super write:typedStream]; NXWriteType(typedStream,":", &entryQual); return self; } -read:typedStream { [super read:typedStream]; NXReadType(typedStream,":", &entryQual); return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.