|
|
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.