home *** CD-ROM | disk | FTP | other *** search
- #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
-