This is TypingTextChange.m in view mode; [Download] [Up]
#import "textundo.h" @implementation TypingTextChange /* * A TypingTextChange object is created whenever and UndoText object wants * to insert or delete characters from the keyboard. TypingTextChanges are * not atomic like TextSelChanges. That is, no user events can come into the * UndoText during a TextSelChange. In contrast, a TypingTextChange has to * to wait for each keystroke until the change is completed. A typing change * is complete when another change is initiated, or when the UndoText gets * a keyDown: not adjacent to the current selection. */ #define TYPING_OPERATION NXLocalStringFromTable("Operations", "Typing", NULL, "The operation of typing some text into the document.") - initView:aView { [super initView:aView name:TYPING_OPERATION]; insertionPoint = -1; subsumingChange = nil; firstKeyDown = YES; finished = NO; return self; } - saveBeforeChange { NXSelPt start, end; [super saveBeforeChange]; [textView getSel:&start :&end]; insertionPoint = start.cp; return self; } - saveAfterChange { /* Do nothing here. We'll take care of it in finishChange */ return self; } /* * The subsumeChange: hook is used to let the typing change know that it * should end itself before the next change starts. However, if that change * is a delete: and its adjacent to the insertion point, then it was * a backspace and we don't want to terminate the typing change. * * In all the other cases, the new change can never be subsumed by the typing * change, but it takes the opportunity to call endChange. */ - (BOOL)subsumeChange:change { if ([change isKindOf:[TypingTextChange class]]) { [change subsumedBy:self]; return YES; } if ([change isKindOf:[DeleteTextChange class]] && [self canBeExtended]) { return YES; } return NO; } /* * This method is called by the ChangeManager when the user undoes this * change or when this change doesn't subsume a newly started change. */ - finishChange { if (!finished) { [super saveAfterChange]; [self setStart:insertionMin end:insertionMax]; finished = YES; } return self; } - subsumedBy:change { subsumingChange = change; return self; } /* * A typing change can be extended by a new keystroke if the selection is * adjacent to the insertion point maintained by the typing change. So, if * the user deletes a character, clicks somewhere else and then deletes * another character, two seperate change objects will be created. */ - (BOOL)canBeExtended { NXSelPt start, end; BOOL returnVal = NO; [textView getSel:&start :&end]; if (start.cp == end.cp) { if (start.cp == insertionPoint) { return YES; } } else if (end.cp == insertionPoint) { return YES; } return returnVal; } - deleteCharacter { NXSelPt start, end; if (subsumingChange != nil) return [subsumingChange deleteCharacter]; if (firstKeyDown) { [textView getSel:&start :&end]; insertionMin = insertionMax = start.cp; if (start.cp == end.cp) { if (start.cp > 0) { insertionPoint = start.cp - 1; } else { insertionPoint = 0; } } else { insertionPoint = start.cp; } firstKeyDown = NO; } else { if (insertionPoint > 0) { insertionPoint--; } } if (insertionPoint < insertionMin) { insertionMin = insertionPoint; } return self; } /* * We don't do anything with the character (ch) right now, but a future * implementation might want to save each character in a more efficient * manner. */ - addCharacter:(int)ch { NXSelPt start, end; if (subsumingChange != nil) return [subsumingChange addCharacter:ch]; if (firstKeyDown) { [textView getSel:&start :&end]; insertionMin = insertionMax = start.cp; insertionPoint = start.cp; firstKeyDown = NO; } insertionPoint++; if (insertionPoint > insertionMax) { insertionMax = insertionPoint; } return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.