|
|
1.1 ! root 1: #import "textundo.h" ! 2: ! 3: @implementation TypingTextChange ! 4: ! 5: /* ! 6: * A TypingTextChange object is created whenever and UndoText object wants ! 7: * to insert or delete characters from the keyboard. TypingTextChanges are ! 8: * not atomic like TextSelChanges. That is, no user events can come into the ! 9: * UndoText during a TextSelChange. In contrast, a TypingTextChange has to ! 10: * to wait for each keystroke until the change is completed. A typing change ! 11: * is complete when another change is initiated, or when the UndoText gets ! 12: * a keyDown: not adjacent to the current selection. ! 13: */ ! 14: ! 15: #define TYPING_OPERATION NXLocalStringFromTable("Operations", "Typing", NULL, "The operation of typing some text into the document.") ! 16: ! 17: - initView:aView ! 18: { ! 19: [super initView:aView name:TYPING_OPERATION]; ! 20: ! 21: insertionPoint = -1; ! 22: subsumingChange = nil; ! 23: firstKeyDown = YES; ! 24: finished = NO; ! 25: ! 26: return self; ! 27: } ! 28: ! 29: - saveBeforeChange ! 30: { ! 31: NXSelPt start, end; ! 32: ! 33: [super saveBeforeChange]; ! 34: ! 35: [textView getSel:&start :&end]; ! 36: insertionPoint = start.cp; ! 37: ! 38: return self; ! 39: } ! 40: ! 41: - saveAfterChange ! 42: { ! 43: /* Do nothing here. We'll take care of it in finishChange */ ! 44: ! 45: return self; ! 46: } ! 47: ! 48: /* ! 49: * The subsumeChange: hook is used to let the typing change know that it ! 50: * should end itself before the next change starts. However, if that change ! 51: * is a delete: and its adjacent to the insertion point, then it was ! 52: * a backspace and we don't want to terminate the typing change. ! 53: * ! 54: * In all the other cases, the new change can never be subsumed by the typing ! 55: * change, but it takes the opportunity to call endChange. ! 56: */ ! 57: - (BOOL)subsumeChange:change ! 58: { ! 59: if ([change isKindOf:[TypingTextChange class]]) { ! 60: [change subsumedBy:self]; ! 61: return YES; ! 62: } ! 63: ! 64: if ([change isKindOf:[DeleteTextChange class]] && [self canBeExtended]) { ! 65: return YES; ! 66: } ! 67: ! 68: return NO; ! 69: } ! 70: ! 71: /* ! 72: * This method is called by the ChangeManager when the user undoes this ! 73: * change or when this change doesn't subsume a newly started change. ! 74: */ ! 75: ! 76: - finishChange ! 77: { ! 78: if (!finished) { ! 79: [super saveAfterChange]; ! 80: [self setStart:insertionMin end:insertionMax]; ! 81: finished = YES; ! 82: } ! 83: return self; ! 84: } ! 85: ! 86: - subsumedBy:change ! 87: { ! 88: subsumingChange = change; ! 89: return self; ! 90: } ! 91: ! 92: /* ! 93: * A typing change can be extended by a new keystroke if the selection is ! 94: * adjacent to the insertion point maintained by the typing change. So, if ! 95: * the user deletes a character, clicks somewhere else and then deletes ! 96: * another character, two seperate change objects will be created. ! 97: */ ! 98: ! 99: - (BOOL)canBeExtended ! 100: { ! 101: NXSelPt start, end; ! 102: BOOL returnVal = NO; ! 103: ! 104: [textView getSel:&start :&end]; ! 105: if (start.cp == end.cp) { ! 106: if (start.cp == insertionPoint) { ! 107: return YES; ! 108: } ! 109: } else if (end.cp == insertionPoint) { ! 110: return YES; ! 111: } ! 112: ! 113: return returnVal; ! 114: } ! 115: ! 116: - deleteCharacter ! 117: { ! 118: NXSelPt start, end; ! 119: ! 120: if (subsumingChange != nil) ! 121: return [subsumingChange deleteCharacter]; ! 122: ! 123: if (firstKeyDown) { ! 124: [textView getSel:&start :&end]; ! 125: ! 126: insertionMin = insertionMax = start.cp; ! 127: ! 128: if (start.cp == end.cp) { ! 129: if (start.cp > 0) { ! 130: insertionPoint = start.cp - 1; ! 131: } else { ! 132: insertionPoint = 0; ! 133: } ! 134: } else { ! 135: insertionPoint = start.cp; ! 136: } ! 137: ! 138: firstKeyDown = NO; ! 139: } else { ! 140: if (insertionPoint > 0) { ! 141: insertionPoint--; ! 142: } ! 143: } ! 144: ! 145: if (insertionPoint < insertionMin) { ! 146: insertionMin = insertionPoint; ! 147: } ! 148: ! 149: return self; ! 150: } ! 151: ! 152: /* ! 153: * We don't do anything with the character (ch) right now, but a future ! 154: * implementation might want to save each character in a more efficient ! 155: * manner. ! 156: */ ! 157: ! 158: - addCharacter:(int)ch ! 159: { ! 160: NXSelPt start, end; ! 161: ! 162: if (subsumingChange != nil) ! 163: return [subsumingChange addCharacter:ch]; ! 164: ! 165: if (firstKeyDown) { ! 166: [textView getSel:&start :&end]; ! 167: ! 168: insertionMin = insertionMax = start.cp; ! 169: insertionPoint = start.cp; ! 170: firstKeyDown = NO; ! 171: } ! 172: ! 173: insertionPoint++; ! 174: ! 175: if (insertionPoint > insertionMax) { ! 176: insertionMax = insertionPoint; ! 177: } ! 178: ! 179: return self; ! 180: } ! 181: ! 182: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.