This is eText.Undo.m in view mode; [Download] [Up]
{\rtf0\ansi{\fonttbl\f0\fmodern Courier;\f1\ftech Symbol;\f2\fmodern Ohlfs;} \margl40 \margr40 {\colortbl;\red0\green0\blue0;\red255\green0\blue0;} \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i0\ulnone\fs24\fc0\cf0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \i \b FILENAME \b0 : \b\i0 eText.Undo.m\ \b0 // \i \b SUMMARY \b0 : \b\i0 Implementation of the Undo subsystem of eText \b0 \ // \b\i CATEGORY \b0 : \i0 \b Undo \b0 \ // \b\i PROTOCOLS \b0 : \i0 \b Uses UndoManager \b0 \ // \b\i INTERFACE \b0 : \i0 \b None \b0 \ // \b\i AUTHOR \b0 : \b\i0 Rohit Khare, portions by Jeff Martin of Bozell. \b0 \ // \b\i COPYRIGHT \b0 : \f1\i0 Ó \f0\b 1993,94 California Institure of Technology, eText Project\ \b0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b\i Implementation Comments \b0\i0 \ // These methods deal with undoManager. We may have some real problems\ // intercepting the data flow between "user" methods and internal ones\ // (e.g. paste vs replaceSelWithRTF:)\ // Unlike Jeff's UndoText, we do ours with undo record grouping and\ // and without writing new replace... 'Action' methods. At least, we'll try...\ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b\i History \b0\i0 \ // 10/27/94: \b Changed handling of typing undos to attempt coalescing. \b0 \ // 10/17/94: \b Cleaned up for eText5. \b0 \ // 08/05/94: \b Completely Rearchitected for 5.0. RK \b0 \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Imported Interfaces \b0 \ //\ #import " \b eText.Undo.h \b0 "\ \ \b static \b0 \b int \b0 \b undoLastPos \b0 = -1;\ \b static \b0 \b int \b0 \b undoFirstPos \b0 = -1;\ \b static \b0 \b Stream \b0 * \b undoStream \b0 = NULL; // \i RK: Assumes only 1 Text is being edited \i0 \ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\b\fc0\cf0 static \b0 \b BOOL \b0 \b isTyping \b0 = \b NO \b0 ;\ #define \b DELETE_KEY \b0 (0x08)\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\b\fc0\cf0 \ NXTextFilterFunc \b0 \b oldTextFilter \b0 ; // \i keep the old text filter around \i0 \ \ \i @implementation eText(Undo)\ \i0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b eText Undo API\ \b0 //\ - \b undoSelChange \b0 :(const char *)actionName \{ // \i Call \b before \b0 transaction\ if(sp0.cp < 0) return \b nil \b0 ; \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\i0\fc0\cf0 \ [self \b registerLastTypingUndo \b0 ]; // \i Clear the queue... \i0 \ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 \ if(sp0.cp != spN.cp) \{\ \b undoStream \b0 = [[[Stream alloc] init] \b openMemory \b0 ];\ [self \b writeETF \b0 :[ \b undoStream \b0 stream] \b from \b0 : \b sp0 \b0 .cp \b to \b0 : \b spN \b0 .cp];\ \} else \{\ if(undoStream) [undoStream free];\ \b undoStream \b0 = \b NULL \b0 ;\ \}\ \ [undoManager \b setActionName \b0 : \b NXUniqueString \b0 (actionName ? actionName : "")];\ [undoManager \b beginUndoRecordGrouping \b0 ];\ return self;\ \}\ - \b undoParChange \b0 :(const char *)actionName \{ // \i Call \b before \b0 transaction\ \i0 int \b boP \b0 , \b eoP \b0 ;\ \ \i if(sp0.cp < 0) return \b nil \b0 ; \ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\i0\fc0\cf0 [self \b registerLastTypingUndo \b0 ]; // \i Clear the queue... \i0 \ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 \ \b undoStream \b0 = [[[Stream alloc] init] \b openMemory \b0 ];\ \b boP \b0 = [self \b positionFromLine \b0 :[self \b lineFromPosition \b0 : \b sp0 \b0 .cp]];\ \b eoP \b0 = [self \b positionFromLine \b0 :([self \b lineFromPosition \b0 : \b spN \b0 .cp] \b +1) \b0 ];\ if ( \b eoP \b0 \b < \b0 \b boP \b0 ) eoP = [self \b textLength \b0 ];\ [self \b writeETF \b0 :[ \b undoStream \b0 stream] \b from \b0 : \b boP \b0 \b to \b0 : \b eoP \b0 ];\ \ [undoManager \b setActionName \b0 : \b NXUniqueString \b0 (actionName ? actionName : "")];\ [undoManager \b beginUndoRecordGrouping \b0 ];\ return self;\ \}\ - \b undoAffectedRange \b0 :( \b int \b0 )from \b to \b0 :( \b int \b0 )to \{ // \i Call \b after \b0 transaction\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\i0\fc0\cf0 [[[undoManager setUndoTarget:self] freeUndoArgs] \ \b replaceSelWith \b0 : \b undoStream \b0 from: \b from \b0 to: \b to \b0 ];\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 [undoManager \b endUndoRecordGrouping \b0 ];\ \b undoStream \b0 = NULL;\ [self \b touch \b0 ];\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\fc0\cf0 return self;\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 \}\ \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Undo Stream Operations\ \b0 //\ \ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\fc0\cf0 - \b replaceSelWith \b0 : \i stream \i0 \b from \b0 :(int) \i from \i0 \b to \b0 :(int) \i to \i0 \{\ \fc1\cf1 [self \b setSel \b0 :from :to]; \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\b\fc0\cf0 \ \b0 [self \b undoSelChange \b0 :[undoManager \b currentActionName \b0 ]];\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\gray300\fc2\cf2 // Replace the given range with the rtf in the given stream\ \gray0\fc0\cf0 [stream \b rewind \b0 ]; \fc1\cf1 \ if(stream && [stream stream]) \ [self \b replaceSelWithRichText \b0 :[ \b stream \b0 stream]];\ else [self \b replaceSel \b0 : \b NULL \b0 ];\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\b\fc0\cf0 \b0\fc1\cf1 if (sp0.cp < 0) [self setSel:0:0];\ \b\fc0\cf0 [self undoAffectedRange:from to:spN.cp];\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\b0\fc0\cf0 return self;\ \}\ - \b replaceSel \b0 :(const char *) \i str \i0 \b from \b0 :(int) \i from \i0 \b to \b0 :(int) \i to \i0 \{\ \fc1\cf1 [self \b setSel \b0 :from :to]; \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\b\fc0\cf0 \ \b0 [self \b undoSelChange \b0 :[undoManager \b currentActionName \b0 ]];\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\gray300\fc2\cf2 // Replace the given range with the rtf in the given stream\ \gray0\fc1\cf1 if( \b str \b0 ) [self \b replaceSel \b0 : \b str \b0 ];\ else [self \b replaceSel \b0 : \b "" \b0 ];\ if (sp0.cp < 0) [self setSel:0:0];\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\b\fc0\cf0 [self undoAffectedRange:from to:spN.cp];\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\b0\fc0\cf0 return self;\ \}\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Selection Format Changes\ \b0 //\ - \b changeFont \b0 :sender \{\ id retval;\ \ [self \b touch \b0 ];\ if (sp0.cp == spN.cp) // \i If the font is at a caret, just go on. \i0 \ return [super \b changeFont \b0 :sender];\ \ [self \b undoSelChange \b0 :" \b Change Font \b0 "];\ if (![ \b sender \b0 \b respondsTo \b0 :@selector( \b convertFont \b0 :)])\ \b sender \b0 = [ \b FontManager \b0 new];\ retval = [super \b changeFont \b0 :sender];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ \ - \b pasteFont \b0 :sender \{\ id retval;\ [self \b undoSelChange \b0 :" \b Paste Font \b0 "];\ retval = [super \b pasteFont \b0 :sender];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ \ - \b underline \b0 :sender \{\ id retval;\ [self \b undoSelChange \b0 :" \b Underline \b0 "];\ retval = [super \b underline \b0 :sender];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ \ - \b subscript \b0 :sender \{\ id retval;\ \ [self \b undoSelChange \b0 :" \b Subscript \b0 "];\ retval = [super \b subscript \b0 :sender];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ - \b superscript \b0 :sender \{\ id retval;\ \ [self \b undoSelChange \b0 :" \b Superscript \b0 "];\ retval = [super \b superscript \b0 :sender];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ - \b unscript \b0 :sender \{\ id retval;\ [self \b undoSelChange \b0 :" \b Unscript \b0 "];\ retval = [super \b unscript \b0 :sender];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ \ - \b setSelFont \b0 :font \{\ id retval,newF;\ \ [self \b touch \b0 ];\ if ([font matrix] != NX_FLIPPEDMATRIX)\ newF = [Font newFont:[font name] size:[font pointSize]\ matrix:NX_FLIPPEDMATRIX];\ else newF = font;\ \ if (sp0.cp == spN.cp) // \i If the font is at a caret, just go on. \i0 \ return [super \b setSelFont \b0 :newF];\ \ [self \b undoSelChange \b0 :" \b Set Font \b0 "];\ retval = [super \b setSelFont \b0 :newF];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ - \b setSelFontSize \b0 :( \b float \b0 )size \{\ id retval;\ \ [self \b undoSelChange \b0 :" \b Set Font Size \b0 "];\ retval = [super \b setSelFontSize \b0 :size];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ - \b setSelFontFamily \b0 :(const char *)fontName \{\ id retval;\ \ [self \b undoSelChange \b0 :" \b Set Font Family \b0 "];\ retval = [super \b setSelFontFamily \b0 :fontName];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ \ - \b setSelGray \b0 :( \b float \b0 )value \{\ id retval;\ \ [self \b touch \b0 ];\ if (sp0.cp == spN.cp) // \i If the color is at a caret, just go on.\ \i0 return [super \b setSelGray \b0 :value];\ \ [self \b undoSelChange \b0 :" \b Set Text Gray \b0 "];\ retval = [super \b setSelGray \b0 :value];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ - \b setSelColor \b0 :( \b NXColor \b0 )color \{\ id retval;\ \ [self \b touch \b0 ];\ if (sp0.cp == spN.cp) // \i If the color is at a caret, just go on. \i0 \ return [super \b setSelColor \b0 :color];\ \ [self \b undoSelChange \b0 :" \b Set Text Color \b0 "];\ retval = [super \b setSelColor \b0 :color];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b Paragraph Changes\ \b0 //\ - \b pasteRuler \b0 :sender \{\ id retval;\ [self \b undoParChange \b0 :" \b Paste Ruler \b0 "];\ retval = [super \b pasteRuler \b0 :sender];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ - \b changeTabStopAt \b0 :( \b NXCoord \b0 )oldX \b to \b0 :( \b NXCoord \b0 )newX \{\ id retval;\ [self \b undoParChange \b0 :" \b Move Tab Stop \b0 "];\ retval = [super \b changeTabStopAt \b0 :oldX \b to \b0 :newX];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ - \b setSelProp \b0 :( \b NXParagraphProp \b0 )prop \b to \b0 :( \b NXCoord \b0 )val \{\ id retval;\ [self \b undoParChange \b0 :" \b Change Indentation \b0 "];\ retval = [super \b setSelProp \b0 :prop \b to \b0 :val];\ [self \b undoAffectedRange \b0 : \b sp0 \b0 .cp to: \b spN \b0 .cp];\ return retval;\ \}\ \ //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\ // \b UndoManager Delegate\ \b0 //\ - \b undoManagerWillUndo \b0 :sender \{ \ return [self \b registerLastTypingUndo \b0 ]; \}\ - \b registerLastTypingUndo \b0 \{\ if( \b isTyping \b0 ) \{\ if ((undoFirstPos != -1) &&(undoFirstPos != undoLastPos)) \{\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\fc1\cf1 \fc0\cf0 [[undoManager setUndoTarget:self] \ \b replaceSel:"" from: \b0 undoFirstPos \b to: \b0 undoLastPos \b ]; \b0 \ \} \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 \b \ [undoManager setActionName:"Typing"];\ [undoManager endUndoRecordGrouping];\ \b0 undoFirstPos = undoLastPos = -1;\ \}\ isTyping = NO;\ return self;\ \}\ \i \ @end\ \i0 \ char * \b undoFilterFunc \b0 (eText * \b self \b0 , unsigned char * \b text \b0 , int * \b len \b0 , int \b position \b0 )\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\fc0\cf0 \{\ int start = self->sp0.cp, end = self->spN.cp;\ id undoManager = self->undoManager;\ \ if(oldTextFilter) \b text \b0 = (unsigned char *)(* \b oldTextFilter \b0 )\ (self, text, len, position);\ \gray300\fc2\cf2 \ \gray0\fc0\cf0 if (isTyping && \b ! \b0 (( \b end == undoLastPos \b0 ) || ( \b start \b0 == \b undoFirstPos \b0 )))\{\ \gray300\fc2\cf2 // If we are typing, and this is not a contiguous extension of the last\ // typing, then close the previous group\ \gray0\fc0\cf0 [self \b registerLastTypingUndo \b0 ];\ isTyping = NO; \gray300\fc2\cf2 // This chains into the code immediately below \gray0\fc0\cf0 \ \}\ \gray300\fc2\cf2 // If we're not typing yet, get cranking\ \gray0\fc0\cf0 if (!isTyping) \{\ isTyping = YES;\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\b\fc0\cf0 [undoManager setActionName:"Typing"];\ [undoManager beginUndoRecordGrouping];\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\b0\fc0\cf0 \}\ \ \gray300\fc2\cf2 // This should never get called,since nuking one character already moves sp\ \gray0\fc1\cf1 //if ((start == end) && (text && (*text \b == DELETE_KEY \b0 )))\{\ \b // [self setSel:start-1 :end];\ \fc0\cf0 // start = self->sp0.cp, end = self->spN.cp;\ \b0\fc1\cf1 //\}\ \fc0\cf0 \gray300\fc2\cf2 // No matter what, we're about to nuke a section of text.\ // Note that we generate full RTF code for individual characters.\ // Jeff's old code avoided that by snapshotting the _entire_ document...\ \gray0\fc0\cf0 if \fc1\cf1 ( \b start != end \b0 ) \{\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 id stream = [[[Stream alloc] init] openMemory];\ [self \b writeETF \b0 :[stream \b stream \b0 ] \b from \b0 :start \b to \b0 :end];\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\fc0\cf0 [[[undoManager setUndoTarget:self] freeUndoArgs] \ \b replaceSelWith \b0 : \b stream \b0 from: \b start \b0 to: \b start \b0 ];\ \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\b\fc0\cf0 \ //[self replaceSel:""]; \b0\gray300\fc2\cf2 // could use objc_msgSendSuper() here\ \b\gray0\fc0\cf0 undoLastPos = start;\ undoFirstPos = start;\ \pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\b0\fc1\cf1 \}\ \ \gray300\fc2\cf2 // if it was a delete key, we're done; otherwise we have to undo\ // the subsequent \i addition \i0 of keystrokes \gray0\fc0\cf0 \ \fc1\cf1 if (text && (*text \b != \b0 \b DELETE_KEY \b0 )) \{\ \fc0\cf0 [[undoManager setUndoTarget:self] \ \b replaceSel:"" from:position to:((position + *len))]; \fc1\cf1 \ \fc0\cf0 undoLastPos = position + *len;\ \b0 if ( \b undoFirstPos \b0 == \b -1 \b0 ) \ \b undoFirstPos \b0 = \b position \b0 ;\ \fc1\cf1 \}\ \fc0\cf0 return ((char *)text);\ \} }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.