This is OATextFieldCell.m in view mode; [Download] [Up]
// OATextFieldCell:TextFieldCell
//
// COPYRIGHT 1994 BY M. ONYSCHUK AND ASSOCIATES INC.
// ALL RIGHTS RESERVED.
#import "OATextFieldCell.h"
#import "OATextFieldFormatter.h"
#import <appkit/Font.h>
#import <appkit/Text.h>
#import <appkit/color.h>
#import <appkit/NXCType.h>
#import <appkit/publicWraps.h>
#import <defaults/defaults.h>
#include <libc.h>
#define CLASS_VERSION 1
#define DF_NAME "OATextField"
#define DF_COLOR_OPTIONAL "OptionalFieldColor"
#define COLOR_OPTIONAL "0.53 0.66 1.0"
#define DF_COLOR_MANDATORY "MandatoryFieldColor"
#define COLOR_MANDATORY "1.0 0.6 0.6"
#define DF_FONT "Font"
#define FONT "Courier 12.0"
@interface OATextFieldCell (Private)
// Factory methods
+ (OATextFieldCell *)currentCell;
+ setCurrentCell:(OATextFieldCell *)aCell;
// Instance methods
- (void)_setBackgroundColorFromDefaultsDatabase;
- (void)_setFontFromDefaultsDatabase;
- (void)_setStringValueByRemovingWhitespace;
- (void)_setStringValueFromCaseMapping;
@end
@implementation OATextFieldCell (Private)
// Factory methods
static OATextFieldCell *currentCell = nil;
+ (OATextFieldCell *)currentCell
{
return currentCell;
}
+ setCurrentCell:(OATextFieldCell *)aCell
{
currentCell = aCell;
return self;
}
// Instance methods
static NXColor
colorFromRGBString(const char *aString)
{
if (aString) {
float r, g, b;
sscanf(aString, "%f %f %f", &r, &g, &b);
return NXConvertRGBAToColor(r, g, b, NX_NOALPHA);
} else {
return NX_COLORCLEAR;
}
}
static Font *
fontFromFontString(const char *aString)
{
if (aString) {
char name[80];
float size;
if (sscanf(aString, "%[^ \t]%f", name, &size) == 2) {
return[Font newFont:name size:size];
} else {
return nil;
}
} else {
return nil;
}
}
- (void)_setBackgroundColorFromDefaultsDatabase
{
const char *value = [self stringValue];
unsigned int length = (value) ? strlen(value) : 0;
// if the field is empty, and the defaults database
// specifies a color for the mandatory flag setting, then
// set the background color to the color specified...
if (length == 0) {
const char *df;
if ([self isMandatory]) {
df = NXGetDefaultValue(DF_NAME, DF_COLOR_MANDATORY);
} else {
df = NXGetDefaultValue(DF_NAME, DF_COLOR_OPTIONAL);
}
if (df) {
[self setBackgroundColor:colorFromRGBString(df)];
}
}
}
- (void)_setFontFromDefaultsDatabase
{
const char *df;
if ((df = NXGetDefaultValue(DF_NAME, DF_FONT)) != NULL) {
Font *font;
if ((font = fontFromFontString(df)) != nil) {
[self setFont:font];
}
}
}
- (void)_setStringValueByRemovingWhitespace
{
const char *value = [self stringValue];
unsigned int length = (value) ? strlen(value) : 0;
if (isSettingValue) {
return;
}
isSettingValue = YES;
if (length > 0) {
int i, j;
char *copy = NXCopyStringBufferFromZone(value, [self zone]);
if (removeLeadingWhitespace) {
for (i = 0; NXIsSpace(copy[i]); i++) {
}
if (i > 0) {
for (j = 0; i < length; i++, j++) {
copy[j] = copy[i];
}
copy[j] = copy[i];
}
}
if (removeTrailingWhitespace) {
for (j = strlen(copy); j && NXIsSpace(copy[j-1]); j--) {
}
copy[j] = '\0';
}
[self setStringValueNoCopy:copy];
}
isSettingValue = NO;
}
- (void)_setStringValueFromCaseMapping
{
const char *value = [self stringValue];
unsigned int length = (value) ? strlen(value) : 0;
if (isSettingValue) {
return;
}
isSettingValue = YES;
if (length > 0) {
switch (caseMapping) {
case MAP_TO_UPPER:
{
int index = length;
char *copy = NXCopyStringBufferFromZone(value,[self zone]);
while (index--) {
copy[index] = NXToUpper(copy[index]);
}
[self setStringValueNoCopy:copy];
}
break;
case MAP_TO_LOWER:
{
int index = length;
char *copy = NXCopyStringBufferFromZone(value,[self zone]);
while (index--) {
copy[index] = NXToLower(copy[index]);
}
[self setStringValueNoCopy:copy];
}
break;
case MAP_TO_PROPER:
{
int index = length;
char *copy = NXCopyStringBufferFromZone(value,[self zone]);
while (index--) {
if ((index == 0) || NXIsSpace(copy[index - 1])) {
copy[index] = NXToUpper(copy[index]);
} else {
copy[index] = NXToLower(copy[index]);
}
}
[self setStringValueNoCopy:copy];
}
break;
case MAP_TO_STUDLY:
{
// YeAH! StUDlY CapS
int index = length;
char *copy = NXCopyStringBufferFromZone(value,[self zone]);
while (index--) {
if (random()&01) {
copy[index] = NXToUpper(copy[index]);
} else {
copy[index] = NXToLower(copy[index]);
}
}
[self setStringValueNoCopy:copy];
}
break;
case MAP_TO_NONE:
break;
}
}
isSettingValue = NO;
}
@end
@implementation OATextFieldCell
+ initialize
// Initializes the receiver, sets the class version, and registers
// several default values.
{
static NXDefaultsVector defaults = {
{DF_COLOR_OPTIONAL, NULL},
{DF_COLOR_MANDATORY, NULL},
{DF_FONT, NULL},
{NULL}
};
NXRegisterDefaults(DF_NAME, defaults);
[self setVersion:CLASS_VERSION];
return self;
}
// Instance methods
static char emptyText[1] = {'\0'};
static char outputText[80] = {'\0'};
char *
OAFilterFun(id textObj,
unsigned char *inputText,
int *inputLength,
int position)
{
OATextFieldCell *cell = [OATextFieldCell currentCell];
OACharacterFiltering filtering = [cell characterFiltering];
const char *exceptions = [cell filteringExceptions];
BOOL checksMaximumLength = [cell doesCheckMaximumLength];
int maximumLength = [cell maximumLength];
OATextFieldFormatter *formatter = [cell textFieldFormatter];
if (inputText == NULL) {
// if the input is NULL, then return...
*inputLength = 0;
return emptyText;
}
if (NXIsCntrl(inputText[0])) {
outputText[0] = inputText[0];
outputText[1] = '\0';
return outputText;
}
if (checksMaximumLength && (position >= maximumLength)) {
// if the imput is too long then beep and return...
NXBeep();
*inputLength = 0;
return emptyText;
}
if ((filtering == ALLOW_ALL) ||
(filtering == ALLOW_LETTERS && NXIsAlpha(inputText[0])) ||
(filtering == ALLOW_NUMBERS && NXIsDigit(inputText[0])) ||
(filtering == ALLOW_ALPHANUMERIC && NXIsAlNum(inputText[0])) ||
(exceptions && index(exceptions, inputText[0]))) {
// if the input passes filter presets, then if the
// cell has a custom formatter, apply it here...
if (formatter) {
const char *formatterOutput;
[formatter filterSubstring:inputText
ofSize:*inputLength
at:position];
formatterOutput = [formatter output];
if (formatterOutput) {
*inputLength = strlen(formatterOutput);
return formatterOutput;
} else {
*inputLength = 0;
return emptyText;
}
} else {
strncpy(outputText, inputText, *inputLength);
return outputText;
}
} else {
// Beep to signal an input error...
NXBeep();
*inputLength = 0;
return emptyText;
}
}
- initTextCell:(const char *)stringValue
{
[super initTextCell:stringValue];
oldTextFilter = (NXTextFilterFunc)nil;
[self _setStringValueFromCaseMapping];
[self _setStringValueByRemovingWhitespace];
[self _setFontFromDefaultsDatabase];
[self _setBackgroundColorFromDefaultsDatabase];
return self;
}
- free
{
if (filteringExceptions) {
NXZoneFree([self zone], filteringExceptions);
filteringExceptions = NULL;
}
return[super free];
}
- select:(const NXRect *)aRect
inView:controlView
editor:textObj
delegate:anObject
start:(int)selStart
length:(int)selLength
{
[self setBackgroundColor:NX_COLORWHITE];
[super select:aRect
inView:controlView
editor:textObj
delegate:anObject
start:selStart
length:selLength];
oldTextFilter = [textObj textFilter];
[textObj setTextFilter:(NXTextFilterFunc)OAFilterFun];
[OATextFieldCell setCurrentCell:self];
return self;
}
- (BOOL)isEntryAcceptable:(const char *)value
{
unsigned int length = (value) ? strlen(value) : 0;
int ivalue = atoi(value);
// perform field length check...
if ((length == 0) && [self isNullable]) {
return YES;
}
if ([self doesCheckMinimumLength] &&
(length < [self minimumLength])) {
NXBeep();
return NO;
} else {
goto BEGIN_CHECK_VALUES; // GOTO
}
if ([self doesCheckMaximumLength] &&
(length > [self maximumLength])) {
NXBeep();
return NO;
}
BEGIN_CHECK_VALUES:
// begin value check...
if ([self doesCheckMinimumValue] &&
(ivalue < [self minimumValue])) {
NXBeep();
return NO;
}
if ([self doesCheckMaximumValue] &&
(ivalue > [self maximumValue])) {
NXBeep();
return NO;
}
// after preliminary checks, perform custom formatting and
// validation defined by the formatter...
if (formatter) {
if ([formatter formatString:[self stringValue]] == YES) {
// this is a bit bass-ackwards by my reasoning, but it is
// the way the text delegate indicates that an error in input
// has occurred...
NXBeep();
return NO;
} else {
[self setStringValue:[formatter output]];
return YES;
}
}
return YES;
}
- edit:(const NXRect *)aRect
inView:controlView
editor:textObj
delegate:anObject
event:(NXEvent *)theEvent
{
[self setBackgroundColor:NX_COLORWHITE];
[super edit:aRect
inView:controlView
editor:textObj
delegate:anObject
event:theEvent];
oldTextFilter = [textObj textFilter];
[textObj setTextFilter:(NXTextFilterFunc)OAFilterFun];
[OATextFieldCell setCurrentCell:self];
return self;
}
- endEditing:anObject
{
[self _setStringValueFromCaseMapping];
[self _setStringValueByRemovingWhitespace];
[self _setBackgroundColorFromDefaultsDatabase];
[anObject setTextFilter:(NXTextFilterFunc)oldTextFilter];
[OATextFieldCell setCurrentCell:nil];
return [super endEditing:anObject];
}
- (OACaseMapping)caseMapping
{
return caseMapping;
}
- setCaseMapping:(OACaseMapping)aValue
{
caseMapping = aValue;
[self _setStringValueFromCaseMapping];
return self;
}
- (OACharacterFiltering)characterFiltering
{
return characterFiltering;
}
- setCharacterFiltering:(OACharacterFiltering)aValue
{
characterFiltering = aValue;
return self;
}
- (const char *)filteringExceptions
{
return filteringExceptions;
}
- setFilteringExceptions:(const char *)aValue
{
NXZone *z = [self zone];
if (filteringExceptions) {
NXZoneFree(z, filteringExceptions);
}
filteringExceptions = (aValue) ?
NXCopyStringBufferFromZone(aValue,z) : NULL;
return self;
}
- (BOOL)doesRemoveLeadingWhitespace
{
return removeLeadingWhitespace;
}
- setRemovesLeadingWhitespace:(BOOL)aValue
{
removeLeadingWhitespace = aValue;
[self _setStringValueByRemovingWhitespace];
return self;
}
- (BOOL)doesRemoveTrailingWhitespace
{
return removeTrailingWhitespace;
}
- setRemovesTrailingWhitespace:(BOOL)aValue
{
removeTrailingWhitespace = aValue;
[self _setStringValueByRemovingWhitespace];
return self;
}
- (int)minimumLength
{
return minimumLength;
}
- setMinimumLength:(int)aValue
{
minimumLength = aValue;
return self;
}
- (BOOL)doesCheckMinimumLength
{
return checkMinimumLength;
}
- setChecksMinimumLength:(BOOL)aValue
{
checkMinimumLength = aValue;
return self;
}
- (int)maximumLength
{
return maximumLength;
}
- setMaximumLength:(int)aValue
{
maximumLength = aValue;
return self;
}
- (BOOL)doesCheckMaximumLength
{
return checkMaximumLength;
}
- setChecksMaximumLength:(BOOL)aValue
{
checkMaximumLength = aValue;
return self;
}
- (BOOL)isNullable
{
return isNullable;
}
- setNullable:(BOOL)aValue
{
isNullable = aValue;
return self;
}
- (BOOL)isMandatory
{
return isMandatory;
}
- setMandatory:(BOOL)aValue
{
isMandatory = aValue;
[self _setBackgroundColorFromDefaultsDatabase];
return self;
}
- (int)minimumValue
{
return minimumValue;
}
- setMinimumValue:(int)aValue
{
minimumValue = aValue;
return self;
}
- (BOOL)doesCheckMinimumValue
{
return checkMinimumValue;
}
- setChecksMinimumValue:(BOOL)aValue
{
checkMinimumValue = aValue;
return self;
}
- (int)maximumValue
{
return maximumValue;
}
- setMaximumValue:(int)aValue
{
maximumValue = aValue;
return self;
}
- (BOOL)doesCheckMaximumValue
{
return checkMaximumValue;
}
- setChecksMaximumValue:(BOOL)aValue
{
checkMaximumValue = aValue;
return self;
}
- (OATextFieldFormatter *)textFieldFormatter
{
return formatter;
}
- setTextFieldFormatter:(OATextFieldFormatter *)aValue
{
return [self setTextFieldFormatterNoCopy:[aValue copy]];
}
- setTextFieldFormatterNoCopy:(OATextFieldFormatter *)aValue
{
if (formatter != aValue) {
[formatter free];
}
formatter = aValue;
[formatter setTextFieldCell:self];
return self;
}
- read:(NXTypedStream *)aStream
{
[super read:aStream];
NXReadType(aStream,@encode(OACaseMapping), &caseMapping);
NXReadType(aStream,@encode(OACharacterFiltering), &characterFiltering);
NXReadType(aStream,@encode(char*), &filteringExceptions);
NXReadType(aStream,@encode(BOOL), &removeLeadingWhitespace);
NXReadType(aStream,@encode(BOOL), &removeTrailingWhitespace);
NXReadType(aStream,@encode(int), &minimumLength);
NXReadType(aStream,@encode(int), &maximumLength);
NXReadType(aStream,@encode(BOOL), &checkMinimumLength);
NXReadType(aStream,@encode(BOOL), &checkMaximumLength);
NXReadType(aStream,@encode(BOOL), &isNullable);
NXReadType(aStream,@encode(BOOL), &isMandatory);
NXReadType(aStream,@encode(int), &minimumValue);
NXReadType(aStream,@encode(int), &maximumValue);
NXReadType(aStream,@encode(BOOL), &checkMinimumValue);
NXReadType(aStream,@encode(BOOL), &checkMaximumValue);
formatter = NXReadObject(aStream);
return self;
}
- write:(NXTypedStream *)aStream
{
[super write:aStream];
NXWriteType(aStream,@encode(OACaseMapping), &caseMapping);
NXWriteType(aStream,@encode(OACharacterFiltering), &characterFiltering);
NXWriteType(aStream,@encode(char*), &filteringExceptions);
NXWriteType(aStream,@encode(BOOL), &removeLeadingWhitespace);
NXWriteType(aStream,@encode(BOOL), &removeTrailingWhitespace);
NXWriteType(aStream,@encode(int), &minimumLength);
NXWriteType(aStream,@encode(int), &maximumLength);
NXWriteType(aStream,@encode(BOOL), &checkMinimumLength);
NXWriteType(aStream,@encode(BOOL), &checkMaximumLength);
NXWriteType(aStream,@encode(BOOL), &isNullable);
NXWriteType(aStream,@encode(BOOL), &isMandatory);
NXWriteType(aStream,@encode(int), &minimumValue);
NXWriteType(aStream,@encode(int), &maximumValue);
NXWriteType(aStream,@encode(BOOL), &checkMinimumValue);
NXWriteType(aStream,@encode(BOOL), &checkMaximumValue);
NXWriteObject(aStream,formatter);
return self;
}
- copyFromZone:(NXZone *)aZone
{
OATextFieldCell *copy = [super copyFromZone:aZone];
copy->filteringExceptions = (filteringExceptions) ?
NXCopyStringBufferFromZone(filteringExceptions, aZone) : NULL;
copy->formatter = [formatter copyFromZone:aZone];
return copy;
}
- awake
{
id ret = [super awake];
[self _setStringValueFromCaseMapping];
[self _setStringValueByRemovingWhitespace];
[self _setFontFromDefaultsDatabase];
[self _setBackgroundColorFromDefaultsDatabase];
[self setTextFieldFormatterNoCopy:formatter];
return ret;
}
- awakeFromNib
{
return [self awake];
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.