Annotation of Examples/AppKit/Draw/textUndo.subproj/UndoText.m, revision 1.1

1.1     ! root        1: #import "textundo.h"
        !             2: 
        !             3: @interface UndoText(PrivateMethods)
        !             4: 
        !             5: - getSelBeforeKeydown:(int *)start :(int *)end;
        !             6: 
        !             7: @end
        !             8: 
        !             9: #define FONT_OPERATION NXLocalStringFromTable("Operations", "Font", NULL, "The user action of changing the font of a bunch of selected graphical entities.")
        !            10: #define CUT_OPERATION NXLocalStringFromTable("Operations", "Cut", NULL, "The operation of cutting some graphical entities out of the document and putting them on the Pasteboard.")
        !            11: #define TEXT_COLOR_OPERATION NXLocalStringFromTable("Operations", "Text Color", NULL, "The operation of changing the color of some text.")
        !            12: #define TEXT_GRAY_OPERATION NXLocalStringFromTable("TextOperations", "Text Gray", NULL, "The operation of changing the gray of some text.")
        !            13: #define SET_FONT_OPERATION NXLocalStringFromTable("TextOperations", "Set Font", NULL, "The operation of changing the font of some text.")
        !            14: #define FONT_SIZE_OPERATION NXLocalStringFromTable("TextOperations", "Font Size", NULL, "The operation of changing the size of some text.")
        !            15: #define PASTE_FONT_OPERATION NXLocalStringFromTable("TextOperations", "Paste Font", NULL, "The operation of setting the font of some text based on the copy/paste font mechanism.")
        !            16: #define PASTE_RULER_OPERATION NXLocalStringFromTable("TextOperations", "Paste Ruler", NULL, "The operation of setting the paragraph properties of some text based on the copy/paste ruler mechanism.")
        !            17: #define SUBSCRIPT_OPERATION NXLocalStringFromTable("TextOperations", "Subscript", NULL, "The operation of subscripting some text.")
        !            18: #define SUPERSCRIPT_OPERATION NXLocalStringFromTable("TextOperations", "Superscript", NULL, "The operation of superscripting some text.")
        !            19: #define UNDERLINE_OPERATION NXLocalStringFromTable("TextOperations", "Underline", NULL, "The operation of underlining some text.")
        !            20: #define UNSCRIPT_OPERATION NXLocalStringFromTable("TextOperations", "Unscript", NULL, "The operation of eliminating any super or subscripting of some text.")
        !            21: #define TAB_MOVE_OPERATION NXLocalStringFromTable("TextOperations", "Tab Move", NULL, "The operation of changing the tab stops in some text.")
        !            22: #define ALIGN_LEFT_OPERATION NXLocalStringFromTable("TextOperations", "Align Left", NULL, "The operation of aligning a paragraph to the left.")
        !            23: #define ALIGN_RIGHT_OPERATION NXLocalStringFromTable("TextOperations", "Align Right", NULL, "The operation of aligning a paragraph to the right.")
        !            24: #define CENTER_OPERATION NXLocalStringFromTable("TextOperations", "Center", NULL, "The operation of centering some text.")
        !            25: #define JUSTIFY_OPERATION NXLocalStringFromTable("TextOperations", "Justify", NULL, "The operation of left and right justifying some text.")
        !            26: #define FIRST_INDENT_OPERATION NXLocalStringFromTable("TextOperations", "First Indent", NULL, "The operation of changing the first indent of some text.")
        !            27: #define INDENT_OPERATION NXLocalStringFromTable("TextOperations", "Indent", NULL, "The operation of changing the indentation of some text.")
        !            28: #define NEW_TAB_OPERATION NXLocalStringFromTable("TextOperations", "New Tab", NULL, "The operation of adding a tab stop to some text.")
        !            29: #define DELETE_TAB_OPERATION NXLocalStringFromTable("TextOperations", "Delete Tab", NULL, "The operation of deleting a tab stop in some text.")
        !            30: #define LEFT_MARGIN_OPERATION NXLocalStringFromTable("TextOperations", "Left Margin", NULL, "The operation of changing the left margin on some text.")
        !            31: #define RIGHT_MARGIN_OPERATION NXLocalStringFromTable("TextOperations", "Right Margin", NULL, "The operation of changing the right margin on some text.")
        !            32: #define PARAGRAPH_OPERATION NXLocalStringFromTable("TextOperations", "Paragraph Change", NULL, "The operation of changing some general paragraph properties of some text.")
        !            33: #define REPLACE_OPERATION NXLocalStringFromTable("TextOperations", "Replace", NULL, "The operation of replace a run of text.")
        !            34: 
        !            35: @implementation UndoText
        !            36: 
        !            37: /*
        !            38:  * This subclass of Text overrides methods that allow the user to change the
        !            39:  * information stored in a Text object. Before one of these changes, a Change
        !            40:  * object is created to record what is about to happen. The change object is
        !            41:  * given control (to record the current state of the text) before and after
        !            42:  * the change actually happens.
        !            43:  *
        !            44:  * Keystroke changes are handled by a special filter function which looks at
        !            45:  * the characters as they are entered. This class is plug compatible with
        !            46:  * the Text class. If you use an UndoText in the presence of a ChangeManager,
        !            47:  * the undo mechanism will work automatically.
        !            48:  */
        !            49: 
        !            50: #define DELETE_KEY (0x08)
        !            51: 
        !            52: static char *undoFilterFunc(UndoText *self, unsigned char *text,
        !            53:                            int *len, int position)
        !            54: {
        !            55:     id change;
        !            56:     unsigned char *p;
        !            57:     int chars;
        !            58: 
        !            59:     if (self->oldTextFilter) {
        !            60:        text = (unsigned char *) (*self->oldTextFilter)(self, text,
        !            61:                                                        len, position);
        !            62:     }
        !            63: 
        !            64:     change = [[TypingTextChange alloc] initView:self];
        !            65:     [change startChange];
        !            66:        for (p = text, chars = *len; chars; ++p, --chars) {
        !            67:            if (*p == DELETE_KEY) {
        !            68:                [change deleteCharacter];
        !            69:            } else {
        !            70:                [change addCharacter:(int) *p];
        !            71:            }
        !            72:        }
        !            73:     [change endChange];
        !            74: 
        !            75:     return ((char *)text);
        !            76: }
        !            77: 
        !            78: static BOOL selIsEmpty(UndoText *self)
        !            79: {    
        !            80:     return (self->sp0.cp == self->spN.cp);
        !            81: }
        !            82: 
        !            83: - initFrame:(const NXRect *)frameRect
        !            84: {
        !            85:     [super initFrame:frameRect];
        !            86:     oldTextFilter = [self textFilter];
        !            87:     [super setTextFilter:&undoFilterFunc];
        !            88: 
        !            89:     return self;
        !            90: }
        !            91: 
        !            92: /*
        !            93:  * This is a utility method that deletes the current selection without
        !            94:  * creating a Change object. This is primarily used by TextSelections so
        !            95:  * that they can quietly remove themselves.
        !            96:  */
        !            97: 
        !            98: - eraseSelection
        !            99: {
        !           100:     [super delete:self];
        !           101:     return self;
        !           102: }
        !           103: 
        !           104: /*
        !           105:  * We need to provide access to the clickCount because the behavior of
        !           106:  * delete: changes when clickCount > 1. This has to do with the smart
        !           107:  * deletion of words. TextSelections get and set the clickCount.
        !           108:  */
        !           109: 
        !           110: - (int)clickCount
        !           111: {
        !           112:     return clickCount;
        !           113: }
        !           114: 
        !           115: - setClickCount:(int)count
        !           116: {
        !           117:     clickCount = count;
        !           118:     return self;
        !           119: }
        !           120: 
        !           121: /*
        !           122:  * The text object will change the selection after the keyDown: but before
        !           123:  * the filter function gets control. We simply preserve the original selection
        !           124:  * for later use.
        !           125:  */
        !           126: 
        !           127: - keyDown:(NXEvent *)event
        !           128: {
        !           129:     NXSelPt start, end;
        !           130: 
        !           131:     [self getSel:&start :&end];
        !           132: 
        !           133:     startBeforeKeydown = start.cp;
        !           134:     endBeforeKeydown = end.cp;
        !           135: 
        !           136:     return [super keyDown:event];
        !           137: }
        !           138: 
        !           139: - setTextFilter:(NXTextFilterFunc)aFunc
        !           140: {
        !           141:     oldTextFilter = aFunc;
        !           142:     return self;
        !           143: }
        !           144: 
        !           145: /* Methods that create change objects */
        !           146: 
        !           147: - clear:sender
        !           148: {
        !           149:     return [self delete:sender];
        !           150: }
        !           151: 
        !           152: - cut:sender
        !           153: {
        !           154:     id change;
        !           155:     id retval;
        !           156: 
        !           157:     change = [[TextSelChange alloc] initView:self name:CUT_OPERATION];
        !           158: 
        !           159:     [change startChange];
        !           160:         retval = [super cut:sender];
        !           161:     [change endChange];
        !           162: 
        !           163:     return retval;
        !           164: }
        !           165: 
        !           166: - delete:sender
        !           167: {
        !           168:     id change;
        !           169:     id retval = nil;
        !           170: 
        !           171:     if (!selIsEmpty(self)) {
        !           172:        change = [[DeleteTextChange alloc] initView:self];
        !           173:        [change startChange];
        !           174:            retval = [super delete:sender];
        !           175:        [change endChange];
        !           176:     }
        !           177: 
        !           178:     return retval;
        !           179: }
        !           180: 
        !           181: static id pasteboard = nil;
        !           182: 
        !           183: - paste:sender
        !           184: {
        !           185:     id change;
        !           186:     id retval;
        !           187:     BOOL canPaste;
        !           188:     const NXAtom *types;
        !           189: 
        !           190:     if (pasteboard == nil) {
        !           191:        pasteboard = [Pasteboard new];
        !           192:     }
        !           193: 
        !           194:     for (canPaste = NO, types = [pasteboard types]; *types; types++) {
        !           195:        if(*types == NXAsciiPboardType || *types == NXRTFPboardType) {
        !           196:            canPaste = YES;
        !           197:            break;
        !           198:        }
        !           199:     }
        !           200:     
        !           201:     if (canPaste) {
        !           202:        change = [[PasteTextChange alloc] initView:self];
        !           203:        [change startChange];
        !           204:             retval = [super paste:sender];
        !           205:        [change endChange];
        !           206:     } else {
        !           207:        retval = nil;
        !           208:     }
        !           209: 
        !           210:     return retval;
        !           211: }
        !           212: 
        !           213: - setSelGray:(float)value
        !           214: {
        !           215:     id change;
        !           216:     id retval;
        !           217: 
        !           218:     change = [[TextSelColorChange alloc] initView:self name:TEXT_GRAY_OPERATION];
        !           219:     [change startChange];
        !           220:         retval = [super setSelGray:value];
        !           221:     [change endChange];
        !           222: 
        !           223:     return retval;
        !           224: }
        !           225: 
        !           226: - setSelColor:(NXColor)color
        !           227: {
        !           228:     id change;
        !           229:     id retval;
        !           230: 
        !           231:     change = [[TextSelColorChange alloc] initView:self name:TEXT_COLOR_OPERATION];
        !           232:     [change startChange];
        !           233:         retval = [super setSelColor:color];
        !           234:     [change endChange];
        !           235: 
        !           236:     return retval;
        !           237: }
        !           238: 
        !           239: - setSelFont:fontId
        !           240: {
        !           241:     id change;
        !           242:     id retval;
        !           243: 
        !           244:     change = [[TextSelChange alloc] initView:self name:SET_FONT_OPERATION];
        !           245:     [change startChange];
        !           246:         retval = [super setSelFont:fontId];
        !           247:     [change endChange];
        !           248: 
        !           249:     return retval;
        !           250: }
        !           251: 
        !           252: - setSelFontSize:(float)size
        !           253: {
        !           254:     id change;
        !           255:     id retval;
        !           256: 
        !           257:     change = [[TextSelChange alloc] initView:self name:FONT_SIZE_OPERATION];
        !           258:     [change startChange];
        !           259:         retval = [super setSelFontSize:size];
        !           260:     [change endChange];
        !           261: 
        !           262:     return retval;
        !           263: }
        !           264: 
        !           265: - setSelFontFamily:(const char *)fontName
        !           266: {
        !           267:     return [super setSelFontFamily:fontName];
        !           268: }
        !           269: 
        !           270: - pasteFont:sender
        !           271: {
        !           272:     id change;
        !           273:     id retval;
        !           274: 
        !           275:     change = [[WholeTextChange alloc] initView:self name:PASTE_FONT_OPERATION];
        !           276: 
        !           277:     [change startChange];
        !           278:         retval = [super pasteFont:sender];
        !           279:     [change endChange];
        !           280: 
        !           281:     return retval;
        !           282: }
        !           283: 
        !           284: - pasteRuler:sender
        !           285: {
        !           286:     id change;
        !           287:     id retval;
        !           288: 
        !           289:     change = [[WholeTextChange alloc] initView:self name:PASTE_RULER_OPERATION];
        !           290: 
        !           291:     [change startChange];
        !           292:         retval = [super pasteRuler:sender];
        !           293:     [change endChange];
        !           294: 
        !           295:     return retval;
        !           296: }
        !           297: 
        !           298: - subscript:sender
        !           299: {
        !           300:     id change;
        !           301:     id retval;
        !           302: 
        !           303:     change = [[TextSelChange alloc] initView:self name:SUBSCRIPT_OPERATION];
        !           304:     [change startChange];
        !           305:         retval = [super subscript:sender];
        !           306:     [change endChange];
        !           307: 
        !           308:     return retval;
        !           309: }
        !           310: 
        !           311: - superscript:sender
        !           312: {
        !           313:     id change;
        !           314:     id retval;
        !           315: 
        !           316:     change = [[TextSelChange alloc] initView:self name:SUPERSCRIPT_OPERATION];
        !           317:     [change startChange];
        !           318:         retval = [super superscript:sender];
        !           319:     [change endChange];
        !           320: 
        !           321:     return retval;
        !           322: }
        !           323: 
        !           324: - underline:sender
        !           325: {
        !           326:     id change;
        !           327:     id retval;
        !           328: 
        !           329:     change = [[TextSelChange alloc] initView:self name:UNDERLINE_OPERATION];
        !           330:     [change startChange];
        !           331:         retval = [super underline:sender];
        !           332:     [change endChange];
        !           333: 
        !           334:     return retval;
        !           335: }
        !           336: 
        !           337: - unscript:sender
        !           338: {
        !           339:     id change;
        !           340:     id retval;
        !           341: 
        !           342:     change = [[TextSelChange alloc] initView:self name:UNSCRIPT_OPERATION];
        !           343:     [change startChange];
        !           344:         retval = [super unscript:sender];
        !           345:     [change endChange];
        !           346: 
        !           347:     return retval;
        !           348: }
        !           349: 
        !           350: - changeFont:sender
        !           351: {
        !           352:     id change;
        !           353:     id retval;
        !           354: 
        !           355:     change = [[TextSelChange alloc] initView:self name:FONT_OPERATION];
        !           356:     [change startChange];
        !           357:         retval = [super changeFont:sender];
        !           358:     [change endChange];
        !           359: 
        !           360:     return retval;
        !           361: }
        !           362: 
        !           363: - changeTabStopAt:(NXCoord)oldX to:(NXCoord)newX
        !           364: {
        !           365:     id change;
        !           366:     id retval;
        !           367: 
        !           368:     change = [[WholeTextChange alloc] initView:self name:TAB_MOVE_OPERATION];
        !           369: 
        !           370:     [change startChange];
        !           371:         retval = [super changeTabStopAt:oldX to:newX];
        !           372:     [change endChange];
        !           373: 
        !           374:     return retval;
        !           375: }
        !           376: 
        !           377: - setSelProp:(NXParagraphProp)prop to:(NXCoord)val
        !           378: {
        !           379:     id change;
        !           380:     id retval;
        !           381:     const char *name;
        !           382: 
        !           383:     switch(prop) {
        !           384:       case NX_LEFTALIGN :
        !           385:        name = ALIGN_LEFT_OPERATION;
        !           386:        break;
        !           387:       case NX_RIGHTALIGN :
        !           388:        name = ALIGN_RIGHT_OPERATION;
        !           389:        break;
        !           390:       case NX_CENTERALIGN :
        !           391:        name = CENTER_OPERATION;
        !           392:        break;
        !           393:       case NX_JUSTALIGN :
        !           394:        name = JUSTIFY_OPERATION;
        !           395:        break;
        !           396:       case NX_FIRSTINDENT :
        !           397:        name = FIRST_INDENT_OPERATION;
        !           398:        break;
        !           399:       case NX_INDENT :
        !           400:        name = INDENT_OPERATION;
        !           401:        break;
        !           402:       case NX_ADDTAB :
        !           403:        name = NEW_TAB_OPERATION;
        !           404:        break;
        !           405:       case NX_REMOVETAB :
        !           406:        name = DELETE_TAB_OPERATION;
        !           407:        break;
        !           408:       case NX_LEFTMARGIN :
        !           409:        name = LEFT_MARGIN_OPERATION;
        !           410:        break;
        !           411:       case NX_RIGHTMARGIN :
        !           412:        name = RIGHT_MARGIN_OPERATION;
        !           413:        break;
        !           414:       default :
        !           415:        name = PARAGRAPH_OPERATION;
        !           416:        break;
        !           417:     }
        !           418: 
        !           419:     change = [[WholeTextChange alloc] initView:self name:name];
        !           420: 
        !           421:     [change startChange];
        !           422:         retval = [super setSelProp:prop to:val];
        !           423:     [change endChange];
        !           424: 
        !           425:     return retval;
        !           426: }
        !           427: 
        !           428: - replaceSel:(char *)str
        !           429: {
        !           430:     id change;
        !           431:     id retval;
        !           432:     NXSelPt oldStart, oldEnd;
        !           433:     NXSelPt newStart, newEnd;
        !           434: 
        !           435:     change = [[TextSelChange alloc] initView:self name:REPLACE_OPERATION];
        !           436:     [change startChange];
        !           437:        [super getSel:&oldStart :&oldEnd];
        !           438:        retval = [super replaceSel:str];
        !           439:        [super getSel:&newStart :&newEnd];
        !           440:        [super setSel:oldStart.cp :newEnd.cp];
        !           441:     [change endChange];
        !           442:     [super setSel:newStart.cp :newEnd.cp];
        !           443: 
        !           444:     return retval;
        !           445: }
        !           446: 
        !           447: - getSelBeforeKeydown:(int *)start :(int *)end
        !           448: {
        !           449:     *start = startBeforeKeydown;
        !           450:     *end = endBeforeKeydown;
        !           451: 
        !           452:     return self;
        !           453: }
        !           454: 
        !           455: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.