home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.0 / NeXTSTEP3.0.iso / NextDeveloper / Examples / AppKit / Draw / textUndo.subproj / UndoText.m < prev    next >
Text File  |  1992-02-09  |  12KB  |  454 lines

  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 eliminat2fany 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 fun2gn 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_OPE2hON];
  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 change2i  id retval;
  287.  
  288.     change = [[WholeTextChange alloc] initView:self name:PASTE_RULER_OPERATION];
  289.  
  290.     [change startChange];
  291.         retval = [super pasteRuler:sender];
  292.     [change endChange];
  293.  
  294.     return retval;
  295. }
  296.  
  297. - subscript:sender
  298. {
  299.     id change;
  300.     id retval;
  301.  
  302.     change = [[TextSelChange alloc] initView:self name:SUBSCRIPT_OPERATION];
  303.     [change startChange];
  304.         retval = [super subscript:sender];
  305.     [change endChange];
  306.  
  307.     return retval;
  308. }
  309.  
  310. - superscript:sender
  311. {
  312.     id change;
  313.     id retval;
  314.  
  315.     change = [[TextSelChange alloc] initView:self name:SUPERSCRIPT_OPERATION];
  316.     [change startChange];
  317.         retval = [super superscript:sender];
  318.     [change endChange];
  319.  
  320.     return retval;
  321. }
  322.  
  323. - underline:sender
  324. {
  325.     id change;
  326.     id retval;
  327.  
  328.     change = [[TextSelChange alloc] initView:self name:UNDERLINE_OPERATION];
  329.     [change startChange];
  330.         retval = [super underline:sender];
  331.     [change endChange];
  332.  
  333.     return retval;
  334. }
  335.  
  336. - unscript:sender
  337. {
  338.     id change;
  339.     id retval;
  340.  
  341.     change = [[TextSelChange alloc] initView:self name:UNSCRIPT_OPERATION];
  342.     [change startChange];
  343.         retval = [super unscript:sender];
  344.     [change endChange];
  345.  
  346.     return retval;
  347. }
  348.  
  349. - changeFont:sender
  350. {
  351.     id change;
  352.     id retval;
  353.  
  354.     change = [[TextSelChange alloc] initView:self name:FONT_OPERATION];
  355.     [change startChange];
  356.         retval = [super changeFont:sender];
  357.     [change endChange];
  358.  
  359.     return retval;
  360. }
  361.  
  362. - changeTabStopAt:(NXCoord)oldX to:(NXCoord)newX
  363. {
  364.     id change;
  365.     id retval;
  366.  
  367.     change = [[WholeTextChange alloc] initView:self name:TAB_MOVE_OPERATION];
  368.  
  369.     [change startChange];
  370.         retval = [super changeTabStopAt:oldX to:newX];
  371.     [change endChange];
  372.  
  373.     return retval;
  374. }
  375.  
  376. - setSelProp:(NXParagraphProp)prop to:(NXCoord)val
  377. {
  378.     id change;
  379.     id retval;
  380.     const char *name;
  381.  
  382.     switch(prop) {
  383.       case NX_LEFTALIGN :
  384.     name = ALIGN_LEFT_OPERATION;
  385.     break;
  386.       case NX_RIGHTALIGN :
  387.     name = ALIGN_RIGHT_OPERATION;
  388.     break;
  389.       case NX_CENTERALIGN :
  390.     name = CENTER_OPERATION;
  391.     break;
  392.       case NX_JUSTALIGN :
  393.     name = JUSTIFY_OPERATION;
  394.     break;
  395.       case NX_FIRSTINDENT :
  396.     name = FIRST_INDENT_OPERATION;
  397.     break;
  398.       case NX_INDENT :
  399.     name = INDENT_OPERATION;
  400.     break;
  401.       case NX_ADDTAB :
  402.     name = NEW_TAB_OPERATION;
  403.     break;
  404.       case NX_REMOVETAB :
  405.     name = DELETE_TAB_OPERATION;
  406.     bre2p      case NX_LEFTMARGIN :
  407.     name = LEFT_MARGIN_OPERATION;
  408.     break;
  409.       case NX_RIGHTMARGIN :
  410.     name = RIGHT_MARGIN_OPERATION;
  411.     break;
  412.       default :
  413.     name = PARAGRAPH_OPERATION;
  414.     break;
  415.     }
  416.  
  417.     change = [[WholeTextChange alloc] initView:self name:name];
  418.  
  419.     [change startChange];
  420.         retval = [super setSelProp:prop to:val];
  421.     [change endChange];
  422.  
  423.     return retval;
  424. }
  425.  
  426. - replaceSel:(char *)str
  427. {
  428.     id change;
  429.     id retval;
  430.     NXSelPt oldStart, oldEnd;
  431.     NXSelPt newStart, newEnd;
  432.  
  433.     change = [[TextSelChange alloc] initView:self name:REPLACE_OPERATION];
  434.     [change startChange];
  435.     [super getSel:&oldStart :&oldEnd];
  436.     retval = [super replaceSel:str];
  437.     [super getSel:&newStart :&newEnd];
  438.     [super setSel:oldStart.cp :newEnd.cp];
  439.     [change endChange];
  440.     [super setSel:newStart.cp :newEnd.cp];
  441.  
  442.     return retval;
  443. }
  444.  
  445. - getSelBeforeKeydown:(int *)start :(int *)end
  446. {
  447.     *start = startBeforeKeydown;
  448.     *end = endBeforeKeydown;
  449.  
  450.     return self;
  451. }
  452.  
  453. @end
  454.