home *** CD-ROM | disk | FTP | other *** search
- /* TurboTFCell.m
- *
- * TurboTFCell is a subclass of TextFieldCell which supports
- * a) length-watching on a string -- maxLength [length of 0
- * indicates that length-watching is not active]
- * b) auto-jumping to nextText if the maximum is reached
- * c) acceptsReturn will cause the Return character to be
- * interpreted literally rather than as a signal to end editing
- *
- *
- * You may freely copy, distribute, and reuse the code in this example.
- * NeXT disclaims any warranty of any kind, expressed or implied, as to its
- * fitness for any particular use.
- *
- * Written by: Sharon Zakhour
- * Created: Oct/91
- */
-
- #import "TurboTFCell.h"
-
- @implementation TurboTFCell
-
- /* In order for the length watching (and auto-jumping since that is
- * determined by length) to work properly, the character and text
- * filters need to know the identity of the cell they are working with.
- */
- static id theCell = NULL;
-
- - init
- {
- return [self initTextCell:""];
- }
-
- - initTextCell: (const char*) aString
- {
- [super initTextCell:aString];
-
- // Initialize these to the default TextField behavior
- originalText = NULL;
- customTextFilter = (NXTextFilterFunc)lengthFilter;
- [self setAutoJump: NO forLength: 0];
- [self setAcceptsReturn: NO];
- return self;
- }
-
- - free
- {
- if (originalText)
- free(originalText);
- originalText = NULL;
- return[super free];
- }
-
- /* The primary reason I've overridden select: and edit: (below) is to set
- * the local static variable "theCell" to self. The filter functions must know
- * about the current cell in order to query it for information on length,
- * autojumping, etc. The only way that a cell becomes active are
- * through one of these methods.
- */
- - select:(const NXRect *)aRect inView:controlView editor:textObj delegate:anObject start:(int)selStart length:(int)selLength
- {
- /* do what the superclass would do */
- [super select:aRect inView:controlView editor:textObj
- delegate:anObject start:selStart length:selLength];
-
- theCell = self;
- if (maxLength && originalText)
- strcpy(originalText, [self stringValue]);
-
- [textObj setTextFilter:(NXTextFilterFunc)customTextFilter];
- [textObj setCharFilter:autoJumpCharFilter];
- return self;
- }
-
- /* The primary reason I've overridden edit: and select: (above) is to set
- * the local static variable "theCell" to self. The filter functions must know
- * about the current cell in order to query it for information on length,
- * autojumping, etc. The only way that a cell becomes active are
- * through one of these methods.
- */
- - edit:(const NXRect *)aRect inView:controlView editor:textObj delegate:anObject event:(NXEvent *)theEvent
- {
- /* do what the superclass would do */
- [super edit:aRect inView:controlView editor:textObj
- delegate:anObject event:theEvent];
-
- theCell = self;
- if (maxLength && originalText)
- strcpy(originalText, [self stringValue]);
-
- [textObj setTextFilter:(NXTextFilterFunc)customTextFilter];
- [textObj setCharFilter:autoJumpCharFilter];
- return self;
- }
-
- - setMaxLength: (int) length
- {
- if (originalText)
- {
- free(originalText);
- originalText = NULL;
- }
- maxLength = length;
- if (length)
- originalText = (char *)malloc(maxLength);
- return self;
- }
-
- - (int) maxLength;
- {
- return maxLength;
- }
-
- - setAutoJump: (BOOL) flag forLength: (int)length
- {
- autoJump = flag;
- [self setMaxLength: length];
- return self;
- }
-
- - (BOOL) autoJump
- {
- return autoJump;
- }
-
- - setAcceptsReturn: (BOOL) flag
- {
- acceptsReturn = flag;
- return self;
- }
-
- - (BOOL) acceptsReturn
- {
- return acceptsReturn;
- }
-
- - setOriginalText: (char *)aString
- {
- if (originalText)
- strcpy(originalText, aString);
- return self;
- }
-
- - (char *)originalText
- {
- return originalText;
- }
-
- - setCustomFilter: (NXTextFilterFunc) aFilter;
- {
- customTextFilter = (NXTextFilterFunc)aFilter;
- return self;
- }
-
- - (NXTextFilterFunc) customTextFilter
- {
- return (NXTextFilterFunc) customTextFilter;
- }
-
-
- /* Run the given string through the Cell's text filter to
- * see if it passes muster.
- */
- - (BOOL) checkString: (char *)aString
- {
- int i, len;
- char *cp;
- id textObj;
- void *fooPtr;
-
- if (customTextFilter == (NXTextFilterFunc)nil)
- return YES;
-
- textObj = [[[self controlView] window] getFieldEditor :YES for: self];
- for (i = 0, cp = aString; i < strlen(aString); i++, cp++)
- {
- len = 1;
- // fooPtr will eliminate a compiler warning about "unused value"
- fooPtr = (void*)(*(NXTextFilterFunc)customTextFilter)((id)textObj,
- (unsigned char *)cp, (int *)&len, (int)i);
- if (len == 0)
- return NO;
- }
- return YES;
- }
-
- // This is the default text filter. If another has been installed via the setCustomFilter:
- // method, then this one will not get called.
- char *lengthFilter(id textObj, char *inputText, int *inputLength, int position)
- {
- int maxLength;
- BOOL autoJump;
-
- maxLength = [theCell maxLength];
- autoJump = [theCell autoJump];
-
- if (maxLength && !autoJump && [textObj textLength] > maxLength)
- {
- *inputLength = 0;
- return "";
- }
-
- return inputText;
- }
-
- // This could easily be extended to include letters with diacritics.
- // See Chapter 6 Summary for KeyInfo for a full listing of keyboard
- // event information.
- #define IS_VALID_ASCII(ch) ((ch) >= ' ' && (ch) <= '~')
-
- unsigned short autoJumpCharFilter(unsigned short charCode, int flags, unsigned
- short charSet)
- {
- NXSelPt start, end;
- NXEvent *event, fakeEvent;
- id textObj;
- int curLength, maxLength;
- BOOL autoJump, acceptsReturn;
-
- maxLength = [theCell maxLength];
- autoJump = [theCell autoJump];
- acceptsReturn = [theCell acceptsReturn];
-
- event = [NXApp currentEvent];
- textObj = [[[theCell controlView] window] getFieldEditor :YES for: theCell];
- curLength = [textObj textLength] +1;
-
- /* Anything that's highlighted is going to get clobbered, so let's adjust */
- [textObj getSel: &start : &end];
- if (start.cp != end.cp)
- curLength -= end.cp - start.cp;
-
- // Currently acceptsReturn doesn't work very well with maxLength because
- // it counts newlines which you probably don't want. If you want something
- // more sophisticated then you'll have to parse the runs!
- if (acceptsReturn && charCode == NX_CR)
- return NXEditorFilter(charCode, flags, charSet);
-
- // Watch out for interpreted rather than real keystrokes -- let them
- // through even though we have reached our maximum length.
- if (autoJump && maxLength && curLength > maxLength &&
- IS_VALID_ASCII(charCode))
- {
- fakeEvent = *event;
- fakeEvent.time++;
- DPSPostEvent(&fakeEvent, YES);
- return NX_TAB;
- }
- return NXFieldFilter(charCode, flags, charSet);
- }
-
- @end
-