|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.